001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.InputProcessor;
004import com.badlogic.gdx.utils.IntArray;
005
006/**
007 * This wraps an InputProcessor, storing all key events and allowing them to be processed one at a time using next() or
008 * all at once using drain(). To have an effect, it needs to be registered by calling Input.setInputProcessor(SquidKey).
009 * <br>
010 * It does not perform the blocking functionality of the now-removed Swing SquidKey implementation, because this is
011 * meant to run in an event-driven libGDX game and should not step on the toes of libGDX's input handling. To block game
012 * logic until an event has been received, check hasNext() in the game's render() method and effectively "block" by not
013 * running game logic if hasNext() returns false. You can get an event if hasNext() returns true by calling next().
014 *
015 * @author Eben Howard - http://squidpony.com - howard@squidpony.com
016 * @author Nathan Sweet
017 * @author Tommy Ettinger
018 * */
019public class SquidKey implements InputProcessor {
020    private static final int KEY_DOWN = 0;
021    private static final int KEY_UP = 1;
022    private static final int KEY_TYPED = 2;
023
024    private InputProcessor processor;
025    private final IntArray queue = new IntArray();
026    private final IntArray processingQueue = new IntArray();
027    private boolean ignoreInput;
028
029    /**
030     * Constructs a SquidKey with no InputProcessor; for this to do anything, setProcessor() must be called.
031     */
032    public SquidKey () {
033    }
034
035    /**
036     * Constructs a SquidKey with the given InputProcessor.
037     * @param processor An InputProcessor that will handle keyDown(), keyUp(), and keyTyped() events
038     */
039    public SquidKey (InputProcessor processor) {
040        this.processor = processor;
041    }
042
043    /**
044     * Constructs a SquidKey with the given InputProcessor.
045     * @param processor An InputProcessor that will handle keyDown(), keyUp(), and keyTyped() events
046     * @param ignoreInput the starting value for the ignore status; true to ignore input, false to process it.
047     */
048    public SquidKey (InputProcessor processor, boolean ignoreInput) {
049        this.processor = processor;
050        this.ignoreInput = ignoreInput;
051    }
052
053    /**
054     * Sets the InputProcessor that this object will use to make sense of Key events.
055     * @param processor An InputProcessor that will handle keyDown(), keyUp(), and keyTyped() events
056     */
057    public void setProcessor (InputProcessor processor) {
058        this.processor = processor;
059    }
060
061    /**
062     * Gets this object's InputProcessor.
063     * @return this object's InputProcessor
064     */
065    public InputProcessor getProcessor () {
066        return processor;
067    }
068
069    /**
070     * Get the status for whether this should ignore input right now or not. True means this object will ignore and not
071     * queue keypresses, false means it should process them normally. Useful to pause processing or delegate it to
072     * another object temporarily.
073     * @return true if this object currently ignores input, false otherwise.
074     */
075    public boolean getIgnoreInput() {
076        return ignoreInput;
077    }
078
079    /**
080     * Set the status for whether this should ignore input right now or not. True means this object will ignore and not
081     * queue keypresses, false means it should process them normally. Useful to pause processing or delegate it to
082     * another object temporarily.
083     * @param ignoreInput true if this should object should ignore and not queue input, false otherwise.
084     */
085    public void setIgnoreInput(boolean ignoreInput) {
086        this.ignoreInput = ignoreInput;
087    }
088
089    /**
090     * Processes all events queued up, passing them to this object's InputProcessor.
091     */
092    public void drain () {
093        IntArray q = processingQueue;
094        if (processor == null) {
095            queue.clear();
096            return;
097        }
098        q.addAll(queue);
099        queue.clear();
100
101        for (int i = 0, n = q.size; i < n; ) {
102            switch (q.get(i++)) {
103                case KEY_DOWN:
104                    processor.keyDown(q.get(i++));
105                    break;
106                case KEY_UP:
107                    processor.keyUp(q.get(i++));
108                    break;
109                case KEY_TYPED:
110                    processor.keyTyped((char) q.get(i++));
111                    break;
112            }
113        }
114        q.clear();
115    }
116
117    /**
118     * Returns true if at least one event is queued.
119     * @return true if there is an event queued, false otherwise.
120     */
121    public boolean hasNext()
122    {
123        return queue.size >= 2;
124    }
125
126    /**
127     * Processes the first event queued up, passing it to this object's InputProcessor.
128     */
129    public void next() {
130        IntArray q = processingQueue;
131        if (processor == null || queue.size < 2) {
132            queue.clear();
133            return;
134        }
135        q.addAll(queue, 0, 2);
136        queue.removeRange(0, 1);
137
138        if (q.size >= 2) {
139            int e = q.get(0), n = q.get(1);
140            switch (e) {
141                case KEY_DOWN:
142                    processor.keyDown(n);
143                    break;
144                case KEY_UP:
145                    processor.keyUp(n);
146                    break;
147                case KEY_TYPED:
148                    processor.keyTyped((char) n);
149                    break;
150            }
151        }
152        q.clear();
153    }
154
155    /**
156     * Empties the backing queue of data.
157     */
158    public void flush()
159    {
160        queue.clear();
161    }
162
163    @Override
164        public boolean keyDown (int keycode) {
165        if(ignoreInput) return false;
166        queue.add(KEY_DOWN);
167        queue.add(keycode);
168        return false;
169    }
170
171    @Override
172        public boolean keyUp (int keycode) {
173        if(ignoreInput) return false;
174        queue.add(KEY_UP);
175        queue.add(keycode);
176        return false;
177    }
178
179    @Override
180        public boolean keyTyped (char character) {
181        if(ignoreInput) return false;
182        queue.add(KEY_TYPED);
183        queue.add(character);
184        return false;
185    }
186
187    @Override
188        public boolean touchDown (int screenX, int screenY, int pointer, int button) {
189        return false;
190    }
191
192    @Override
193        public boolean touchUp (int screenX, int screenY, int pointer, int button) {
194        return false;
195    }
196
197    @Override
198        public boolean touchDragged (int screenX, int screenY, int pointer) {
199        return false;
200    }
201
202    @Override
203        public boolean mouseMoved (int screenX, int screenY) {
204        return false;
205    }
206
207    @Override
208        public boolean scrolled (int amount) {
209        return false;
210    }
211
212}