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 *
010 * It does not perform the blocking functionality of the non-GDX SquidKey implementation, because this is meant to run
011 * in an event-driven libGDX game and should not step on the toes of libGDX's input handling. To block game logic
012 * 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    static private final int KEY_DOWN = 0;
021    static private final int KEY_UP = 1;
022    static private 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 = false;
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
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        synchronized (this) {
095            if (processor == null) {
096                queue.clear();
097                return;
098            }
099            q.addAll(queue);
100            queue.clear();
101        }
102        for (int i = 0, n = q.size; i < n;) {
103            switch (q.get(i++)) {
104                case KEY_DOWN:
105                    processor.keyDown(q.get(i++));
106                    break;
107                case KEY_UP:
108                    processor.keyUp(q.get(i++));
109                    break;
110                case KEY_TYPED:
111                    processor.keyTyped((char)q.get(i++));
112                    break;
113            }
114        }
115        q.clear();
116    }
117
118    /**
119     * Returns true if at least one event is queued.
120     * @return true if there is an event queued, false otherwise.
121     */
122    public boolean hasNext()
123    {
124        return queue.size >= 2;
125    }
126
127    /**
128     * Processes the first event queued up, passing it to this object's InputProcessor.
129     */
130    public void next()
131    {
132        IntArray q = processingQueue;
133        synchronized (this) {
134            if (processor == null || queue.size < 2) {
135                queue.clear();
136                return;
137            }
138            q.addAll(queue, 0, 2);
139            queue.removeRange(0, 1);
140        }
141        if(q.size >= 2)
142        {
143            int e = q.get(0), n = q.get(1);
144            switch (e) {
145                case KEY_DOWN:
146                    processor.keyDown(n);
147                    break;
148                case KEY_UP:
149                    processor.keyUp(n);
150                    break;
151                case KEY_TYPED:
152                    processor.keyTyped((char)n);
153                    break;
154            }
155        }
156        q.clear();
157    }
158
159    /**
160     * Empties the backing queue of data.
161     */
162    public void flush()
163    {
164        queue.clear();
165    }
166
167    @Override
168        public synchronized boolean keyDown (int keycode) {
169        if(ignoreInput) return false;
170        queue.add(KEY_DOWN);
171        queue.add(keycode);
172        return false;
173    }
174
175    @Override
176        public synchronized boolean keyUp (int keycode) {
177        if(ignoreInput) return false;
178        queue.add(KEY_UP);
179        queue.add(keycode);
180        return false;
181    }
182
183    @Override
184        public synchronized boolean keyTyped (char character) {
185        if(ignoreInput) return false;
186        queue.add(KEY_TYPED);
187        queue.add(character);
188        return false;
189    }
190
191    @Override
192        public synchronized boolean touchDown (int screenX, int screenY, int pointer, int button) {
193        return false;
194    }
195
196    @Override
197        public synchronized boolean touchUp (int screenX, int screenY, int pointer, int button) {
198        return false;
199    }
200
201    @Override
202        public synchronized boolean touchDragged (int screenX, int screenY, int pointer) {
203        return false;
204    }
205
206    @Override
207        public synchronized boolean mouseMoved (int screenX, int screenY) {
208        return false;
209    }
210
211    @Override
212        public synchronized boolean scrolled (int amount) {
213        return false;
214    }
215
216}