001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.*;
004import com.badlogic.gdx.files.FileHandle;
005import com.badlogic.gdx.utils.IntIntMap;
006import com.badlogic.gdx.utils.TimeUtils;
007import squidpony.squidmath.IntIntOrderedMap;
008import squidpony.squidmath.IntVLA;
009
010/**
011 * This input processing class can handle mouse and keyboard input, using a squidpony.squidgrid.gui.gdx.SquidMouse for
012 * Mouse input and a user implementation of the SquidInput.KeyHandler interface to react to keys represented as chars
013 * and the modifiers those keys were pressed with, any of alt, ctrl, and/or shift. Not all keys are representable by
014 * default in unicode, so symbolic representations are stored in constants in this class, and are passed to
015 * {@link KeyHandler#handle(char, boolean, boolean, boolean)} as chars like DOWN_ARROW or its value, '\u2193'. Shift
016 * modifies the input as it would on a QWERTY keyboard, and the exact mapping is documented in
017 * {@link #fromCode(int, boolean)} as well. This class handles mouse input immediately, but stores keypresses in a
018 * queue, storing all key events and allowing them to be processed one at a time using {@link #next()} or all at once
019 * using {@link #drain()}. To have an effect, it needs to be registered by calling
020 * {@link Input#setInputProcessor(InputProcessor)}. Note that calling {@link #hasNext()} does more than just check if
021 * there are events that can be processed; because hasNext() is expected to be called frequently, it is also the point
022 * where this class checks if a key is being held and so the next event should occur. Holding a key only causes the
023 * keyDown() method of InputListener to be called once, so this uses hasNext() to see if there should be a next event
024 * coming from a held key.
025 * <br>
026 * This also allows some key remapping, including remapping so a key pressed with modifiers like Ctrl and Shift could
027 * act like '?' (which could be used by expert players to avoid accidentally opening a help menu they don't need), and
028 * that would free up '?' for some other use that could also be remapped. The remap() methods do much of this, often
029 * with help from {@link #combineModifiers(char, boolean, boolean, boolean)}, while the unmap() methods allow removal of
030 * any no-longer-wanted remappings.
031 * <br>
032 * It does not perform the blocking functionality of earlier SquidKey implementations, because this is meant to run
033 * in an event-driven libGDX game and should not step on the toes of libGDX's input handling. To block game logic
034 * until an event has been received, check hasNext() in the game's render() method and effectively "block" by not
035 * running game logic if hasNext() returns false. You can process an event if hasNext() returns true by calling 
036 * {@link #next()}. Mouse inputs do not affect hasNext(), and next() will process only key pressed events. Also, see
037 * above about the extra behavior of hasNext regarding held keys.
038 *
039 * @author Eben Howard - http://squidpony.com - howard@squidpony.com
040 * @author Nathan Sweet
041 * @author Tommy Ettinger
042 * */
043public class SquidInput extends InputAdapter {
044    /**
045     * A single-method interface used to process "typed" characters, special characters produced by unusual keys, and
046     * modifiers that can affect them. SquidInput has numerous static char values that are expected to be passed
047     * to handle() in place of the special keys (such as arrow keys) that do not have a standard char value.
048     */
049    public interface KeyHandler{
050        /**
051         * The only method you need to implement yourself in KeyHandler, this should react to keys such as
052         * 'a' (produced by pressing the A key while not holding Shift), 'E' (produced by pressing the E key while
053         * holding Shift), and '\u2190' (left arrow in unicode, also available as a constant in SquidInput, produced by
054         * pressing the left arrow key even though that key does not have a default unicode representation). Capital
055         * letters will be capitalized when they are passed to this, but they may or may not have the shift argument as
056         * true depending on how this method was called. Symbols that may be produced by holding Shift and pressing a
057         * number or a symbol key can vary between keyboards (some may require Shift to be held down, others may not).
058         * <br>
059         * This can react to the input in whatever way you find appropriate for your game.
060         * @param key a char of the "typed" representation of the key, such as 'a' or 'E', or if there is no Unicode
061         *            character for the key, an appropriate alternate character as documented in SquidInput.fromKey()
062         * @param alt true if the Alt modifier was being held while this key was entered, false otherwise.
063         * @param ctrl true if the Ctrl modifier was being held while this key was entered, false otherwise.
064         * @param shift true if the Shift modifier was being held while this key was entered, false otherwise.
065         */
066        void handle(char key, boolean alt, boolean ctrl, boolean shift);
067    }
068
069    protected KeyHandler keyAction;
070    protected boolean numpadDirections = true, ignoreInput;
071    protected SquidMouse mouse;
072    protected final IntVLA queue = new IntVLA();
073    protected long lastKeyTime = -1000000L;
074    protected IntIntOrderedMap heldCodes = new IntIntOrderedMap(64, 0.25f);
075    protected long repeatGapMillis = 220L;
076    public final IntIntMap mapping = new IntIntMap(128, 0.25f);
077    /**
078     * Constructs a new SquidInput that does not respond to keyboard or mouse input. These can be set later by calling
079     * setKeyHandler() to allow keyboard handling or setMouse() to allow mouse handling on a grid.
080     * <br>
081     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
082     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
083     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
084     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
085     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
086     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
087     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
088     * sent between users even if they play different games). If you really want a custom filename, or to load the
089     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
090     * SquidInput after construction.
091     */
092    public SquidInput() {
093        this(null, null, false);
094    }
095
096    /**
097     * Constructs a new SquidInput that does not respond to keyboard input, but does take mouse input and passes mouse
098     * events along to the given SquidMouse. The SquidMouse, even though it is an InputProcessor on its own, should not
099     * be registered by calling Input.setInputProcessor(SquidMouse), and instead this object should be registered by
100     * calling Input.setInputProcessor(SquidInput). The keyboard and mouse handling can be changed later by calling
101     * setKeyHandler() to allow keyboard handling or setMouse() to change mouse handling.
102     * <br>
103     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
104     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
105     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
106     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
107     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
108     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
109     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
110     * sent between users even if they play different games). If you really want a custom filename, or to load the
111     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
112     * SquidInput after construction.
113     * @param mouse a SquidMouse instance that will be used for handling mouse input.
114     */
115    public SquidInput(SquidMouse mouse) {
116        this(null, mouse, false);
117    }
118
119    /**
120     * Constructs a new SquidInput that does not respond to mouse input, but does take keyboard input and sends keyboard
121     * events through some processing before calling keyHandler.handle() on keypresses that can sensibly be processed.
122     * Modifier keys do not go through the same processing but are checked for their current state when the key is
123     * pressed, and the states of alt, ctrl, and shift are passed to keyHandler.handle() as well.
124     * You can use setMouse() to allow mouse handling or change the KeyHandler with setKeyHandler().
125     * <br>
126     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
127     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
128     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
129     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
130     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
131     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
132     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
133     * sent between users even if they play different games). If you really want a custom filename, or to load the
134     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
135     * SquidInput after construction.
136     * @param keyHandler must implement the SquidInput.KeyHandler interface so it can handle() key input.
137     */
138    public SquidInput(KeyHandler keyHandler) {
139        this(keyHandler, null, false);
140    }
141    /**
142     * Constructs a new SquidInput that does not respond to mouse input, but does take keyboard input and sends keyboard
143     * events through some processing before calling keyHandler.handle() on keypresses that can sensibly be processed.
144     * Modifier keys do not go through the same processing but are checked for their current state when the key is
145     * pressed, and the states of alt, ctrl, and shift are passed to keyHandler.handle() as well.
146     * You can use setMouse() to allow mouse handling or change the KeyHandler with setKeyHandler().
147     * <br>
148     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
149     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
150     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
151     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
152     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
153     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
154     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
155     * sent between users even if they play different games). If you really want a custom filename, or to load the
156     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
157     * SquidInput after construction.
158     * @param keyHandler must implement the SquidInput.KeyHandler interface so it can handle() key input.
159     * @param ignoreInput true if this should ignore input initially, false if it should process input normally.
160     */
161    public SquidInput(KeyHandler keyHandler, boolean ignoreInput) {
162        this(keyHandler, null, ignoreInput);
163    }
164    /**
165     * Constructs a new SquidInput that responds to mouse and keyboard input when given a SquidMouse and a
166     * SquidInput.KeyHandler implementation. It sends keyboard events through some processing before calling
167     * keyHandler.handle() on keypresses that can sensibly be processed. Modifier keys do not go through the same
168     * processing but are checked for their current state when the key is pressed, and the states of alt, ctrl, and
169     * shift are passed to keyHandler.handle() as well. The SquidMouse, even though it is an
170     * InputProcessor on its own, should not be registered by calling Input.setInputProcessor(SquidMouse), and instead
171     * this object should be registered by calling Input.setInputProcessor(SquidInput). You can use setKeyHandler() or
172     * setMouse() to change keyboard or mouse handling.
173     * <br>
174     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
175     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
176     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
177     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
178     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
179     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
180     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
181     * sent between users even if they play different games). If you really want a custom filename, or to load the
182     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
183     * SquidInput after construction.
184     * @param keyHandler must implement the SquidInput.KeyHandler interface so it can handle() key input.
185     * @param mouse a SquidMouse instance that will be used for handling mouse input.
186     */
187    public SquidInput(KeyHandler keyHandler, SquidMouse mouse) {
188        this(keyHandler, mouse, false);
189    }
190
191    /**
192     * Constructs a new SquidInput that responds to mouse and keyboard input when given a SquidMouse and a
193     * SquidInput.KeyHandler implementation, and can be put in an initial state where it ignores input until told
194     * otherwise via setIgnoreInput(boolean). It sends keyboard events through some processing before calling
195     * keyHandler.handle() on keypresses that can sensibly be processed. Modifier keys do not go through the same
196     * processing but are checked for their current state when the key is pressed, and the states of alt, ctrl, and
197     * shift are passed to keyHandler.handle() as well. The SquidMouse, even though it is an
198     * InputProcessor on its own, should not be registered by calling Input.setInputProcessor(SquidMouse), and instead
199     * this object should be registered by calling Input.setInputProcessor(SquidInput). You can use setKeyHandler() or
200     * setMouse() to change keyboard or mouse handling.
201     * <br>
202     * All SquidInput constructors must be called after the {@link ApplicationListener#create()} method has started, and
203     * cannot be called in an ApplicationListener's constructor or in initialization at the class level. This is because
204     * all constructors attempt to load a file, if it exists, with {@code Gdx.files.local("keymap.preferences")}, and
205     * {@code Gdx.files} is only available starting in create(). This file, keymap.preferences, is meant to contain any
206     * key remappings specified by the user, and its contents should be produced by {@link #keyMappingToString()} when
207     * any key mappings change and are saved. You can use your own filename, but keymap.preferences is the standard one
208     * and these can be exchanged between games (so common remappings for users of DVORAK or AZERTY keyboards can be
209     * sent between users even if they play different games). If you really want a custom filename, or to load the
210     * keymap from a larger user profile, you can give the contents to {@link #keyMappingFromString(String)} on a
211     * SquidInput after construction.
212     * @param keyHandler must implement the SquidInput.KeyHandler interface so it can handle() key input.
213     * @param mouse a SquidMouse instance that will be used for handling mouse input.
214     * @param ignoreInput true if this should ignore input initially, false if it should process input normally.
215     */
216    public SquidInput(KeyHandler keyHandler, SquidMouse mouse, boolean ignoreInput) {
217        keyAction = keyHandler;
218        this.mouse = mouse;
219        this.ignoreInput = ignoreInput;
220        FileHandle prefFile;
221        if(Gdx.files.isLocalStorageAvailable() && (prefFile = Gdx.files.local("keymap.preferences")).exists())
222        {
223            keyMappingFromString(prefFile.readString("UTF8"));
224        }
225    }
226
227    public void setKeyHandler(KeyHandler keyHandler)
228    {
229        keyAction = keyHandler;
230    }
231    public void setMouse(SquidMouse mouse)
232    {
233        this.mouse = mouse;
234    }
235
236    public boolean isUsingNumpadDirections() {
237        return numpadDirections;
238    }
239
240    public void setUsingNumpadDirections(boolean using) {
241        numpadDirections = using;
242    }
243
244    public KeyHandler getKeyHandler() {
245        return keyAction;
246    }
247
248    public SquidMouse getMouse() {
249        return mouse;
250    }
251
252    /**
253     * Get the status for whether this should ignore input right now or not. True means this object will ignore and not
254     * queue input, false means it should process them normally. Useful to pause processing or delegate it to
255     * another object temporarily.
256     * @return true if this object currently ignores input, false otherwise.
257     */
258    public boolean getIgnoreInput() {
259        return ignoreInput;
260    }
261
262    /**
263     * Set the status for whether this should ignore input right now or not. True means this object will ignore and not
264     * queue input, false means it should process them normally. Useful to pause processing or delegate it to
265     * another object temporarily.
266     * @param ignoreInput true if this should object should ignore and not queue input, false otherwise.
267     */
268    public void setIgnoreInput(boolean ignoreInput) {
269        this.ignoreInput = ignoreInput;
270    }
271
272    /**
273     * Remaps a char that could be input and processed by {@link KeyHandler#handle(char, boolean, boolean, boolean)}
274     * (possibly with some pressed modifiers) to another char with possible modifiers. When the first key/modifier mix
275     * is received, it will be translated to the second group in this method.
276     * @param pressedChar a source char that might be used in handling, like 'q', 'A', '7', '(', or {@link #UP_ARROW}.
277     * @param pressedAlt true if alt is part of the source combined keypress, false otherwise
278     * @param pressedCtrl true if ctrl is part of the source combined keypress, false otherwise
279     * @param pressedShift true if shift is part of the source combined keypress, false otherwise
280     * @param targetChar a target char that might be used in handling, like 'q', 'A', '7', '(', or {@link #UP_ARROW}.
281     * @param targetAlt true if alt is part of the target combined keypress, false otherwise
282     * @param targetCtrl true if ctrl is part of the target combined keypress, false otherwise
283     * @param targetShift true if shift is part of the target combined keypress, false otherwise
284     * @return this for chaining
285     */
286    public SquidInput remap(char pressedChar, boolean pressedAlt, boolean pressedCtrl, boolean pressedShift,
287                            char targetChar, boolean targetAlt, boolean targetCtrl, boolean targetShift)
288    {
289        mapping.put(combineModifiers(pressedChar, pressedAlt, pressedCtrl, pressedShift),
290                combineModifiers(targetChar, targetAlt, targetCtrl, targetShift));
291        return this;
292    }
293
294    /**
295     * Remaps a keypress combination, which is a char and several potential modifiers, to another keypress combination.
296     * When the {@code pressed} combination is received, it will be translated to {@code target} in this method.
297     * @see #combineModifiers(char, boolean, boolean, boolean) combineModifiers is usually used to make pressed and target
298     * @param pressed an int for the source keypress, probably produced by {@link #combineModifiers(char, boolean, boolean, boolean)}
299     * @param target an int for the target keypress, probably produced by {@link #combineModifiers(char, boolean, boolean, boolean)}
300     * @return this for chaining
301     */
302    public SquidInput remap(int pressed, int target)
303    {
304        mapping.put(pressed, target);
305        return this;
306    }
307    /**
308     * Remaps many keypress combinations, each of which is a char and several potential modifiers, to other keypress
309     * combinations. When the first of a pair of combinations is received, it will be translated to the second
310     * combination of the pair.
311     * @see #combineModifiers(char, boolean, boolean, boolean) combineModifiers is usually used to make the contents of pairs
312     * @param pairs an int array alternating source and target keypresses, each probably produced by {@link #combineModifiers(char, boolean, boolean, boolean)}
313     * @return this for chaining
314     */
315    public SquidInput remap(int[] pairs)
316    {
317        int len;
318        if(pairs == null || (len = pairs.length) <= 1)
319            return this;
320        for (int i = 0; i < len - 1; i++) {
321            mapping.put(pairs[i], pairs[++i]);
322        }
323        return this;
324    }
325
326    /**
327     * Removes a keypress combination from the mapping by specifying the char and any modifiers that are part of the
328     * keypress combination. This combination will no longer be remapped, but the original handling will be the same.
329     * @param pressedChar a char that might be used in handling, like 'q', 'A', '7', '(', or {@link #UP_ARROW}.
330     * @param pressedAlt true if alt is part of the combined keypress, false otherwise
331     * @param pressedCtrl true if ctrl is part of the combined keypress, false otherwise
332     * @param pressedShift true if shift is part of the combined keypress, false otherwise
333     * @return this for chaining
334     */
335    public SquidInput unmap(char pressedChar, boolean pressedAlt, boolean pressedCtrl, boolean pressedShift){
336        mapping.remove(combineModifiers(pressedChar, pressedAlt,pressedCtrl,pressedShift), 0);
337        return this;
338    }
339    /**
340     * Removes a keypress combination from the mapping by specifying the keypress combination as an int. This
341     * combination will no longer be remapped, but the original handling will be the same.
342     * @see #combineModifiers(char, boolean, boolean, boolean) combineModifiers is usually used to make pressed
343     * @param pressed an int for the source keypress, probably produced by {@link #combineModifiers(char, boolean, boolean, boolean)}
344     * @return this for chaining
345     */
346    public SquidInput unmap(int pressed)
347    {
348        mapping.remove(pressed, 0);
349        return this;
350    }
351
352    /**
353     * Removes any remappings to key bindings that were in use in this SquidInput.
354     * @return this for chaining
355     */
356    public SquidInput clearMapping()
357    {
358        mapping.clear();
359        return this;
360    }
361    /**
362     * Combines the key (as it would be given to {@link KeyHandler#handle(char, boolean, boolean, boolean)}) with the
363     * three booleans for the alt, ctrl, and shift modifier keys, returning an int that can be used with the internal
364     * queue of ints or the public {@link #mapping} of received inputs to actual inputs the program can process.
365     * @param key a char that might be used in handling, like 'q', 'A', '7', '(', or {@link #UP_ARROW}.
366     * @param alt true if alt is part of this combined keypress, false otherwise
367     * @param ctrl true if ctrl is part of this combined keypress, false otherwise
368     * @param shift true if shift is part of this combined keypress, false otherwise
369     * @return an int that contains the information to represent the key with any modifiers as one value
370     */
371    public static int combineModifiers(char key, boolean alt, boolean ctrl, boolean shift) {
372        int c = alt ? (key | 0x10000) : key;
373        c |= ctrl ? 0x20000 : 0;
374        c |= shift ? 0x40000 : 0;
375        return c;
376    }
377
378    /**
379     * Gets the current key remapping as a String, which can be saved in a file and read back with
380     * {@link #keyMappingFromString(String)}. Because that method is automatically called by SquidInput's constructor
381     * and tries to load a file named "keymap.preferences" in the local folder, it is recommended that you save
382     * user-remapped keys to that file, but only if the user has actively changed them (that file could exist from an
383     * earlier run and you don't want to affect it unless the user made some change). This will allow input with any of
384     * Shift, Alt, and Ctl modifiers in any script supported by the Unicode Basic Multilingual Plane (the first 65536
385     * chars of Unicode).
386     * @return a String that stores four chars per remapping.
387     */
388    public String keyMappingToString()
389    {
390        char[] cs = new char[mapping.size << 2];
391        int i = 0;
392        for(IntIntMap.Entry ent : mapping)
393        {
394            cs[i++] = (char)(ent.key);
395            cs[i++] = (char)((ent.key>>>16) + 64);
396            cs[i++] = (char)(ent.value);
397            cs[i++] = (char)((ent.value>>>16) + 64);
398        }
399        return String.valueOf(cs);
400    }
401
402    /**
403     * Reads in a String (almost certainly produced by {@link #keyMappingToString()}) to set the current key remapping.
404     * This is automatically called if a file named "keymap.preferences" is present in the local folder, receiving the
405     * contents of that file as a parameter, so games that want to save a user's preferences should try to save that
406     * file if possible (this also allows one file to be reused across multiple computers or installations by copying
407     * it). This will allow input with any of Shift, Alt, and Ctl modifiers in any script supported by the Unicode Basic
408     * Multilingual Plane (the first 65536 chars of Unicode). You may want to call {@link #clearMapping()} before
409     * calling this if you have already set the mapping and want the String's contents to be used as the only mapping.
410     * @param keymap a String that was probably produced by {@link #keyMappingToString()}
411     * @return this for chaining
412     */
413    public SquidInput keyMappingFromString(String keymap)
414    {
415        int len, k, v;
416        if(keymap == null || (len = keymap.length()) < 4)
417            return this;
418        for (int i = 0; i < len - 3; i++) {
419            k = keymap.charAt(i);
420            k |= (keymap.charAt(++i) - 64) << 16;
421            v = keymap.charAt(++i);
422            v |= (keymap.charAt(++i) - 64) << 16;
423            mapping.put(k, v);
424        }
425        return this;
426    }
427
428    /**
429     * Processes all events queued up, passing them through this object's key processing and then to keyHandler. Mouse
430     * events are not queued and are processed when they come in.
431     */
432    public void drain () {
433        IntVLA qu = queue;
434
435        if (keyAction == null || qu.size <= 0) {
436            qu.clear();
437            return;
438        }
439
440        for (int i = 0, n = qu.size, t; i < n; ) {
441            t = qu.get(i++);
442            t = mapping.get(t, t);
443            keyAction.handle((char)t, (t & 0x10000) != 0, (t & 0x20000) != 0, (t & 0x40000) != 0);
444        }
445
446        qu.clear();
447    }
448
449    /**
450     * Gets the amount of milliseconds of holding a key this requires to count as a key repeat. The default is 220. 
451     * @return how long a key needs to be held before this will count it as a key repeat, as a long in milliseconds
452     */
453    public long getRepeatGap() {
454        return repeatGapMillis;
455    }
456
457    /**
458     * Sets the amount of milliseconds of holding a key this requires to count as a key repeat. The default is 220.
459     * @param time how long a key needs to be held before this will count it as a key repeat, as a positive long in milliseconds
460     */
461    public void setRepeatGap(long time) {
462        repeatGapMillis = time;
463    }
464
465    /**
466     * Returns true if at least one event is queued, but also will call {@link #keyDown(int)} if a key is being held but
467     * there is a failure to process the repeated event. The conditions this checks:
468     * <ul>
469     *     <li>Is a key is currently being held?</li>
470     *     <li>Are no modifier keys being held (shift, control, alt)? (without this check, the modifier key counts as a
471     *     repeat of the key it modifies, which is probably never the intended behavior)</li>
472     *     <li>Has {@link #keyDown(int)} already been called at least once?</li>
473     *     <li>Have there been at least {@link #getRepeatGap()} milliseconds between the last key being received and this call?</li>
474     * </ul>
475     * If all of these conditions are true, keyDown() is called again with the last key it had received, and if this has
476     * an effect (the key can be handled), then generally an event should be queued, so this will have a next event and
477     * should return true. You can change the amount of time required to hold a key to cause key repeats with
478     * {@link #setRepeatGap(long)}, but the default of 220 ms is usually suitable. Too low of a value can cause normal
479     * key presses to be counted twice or more, and too high of a value may delay an expected key repeat.
480     * @return true if there is an event queued, false otherwise
481     */
482    public boolean hasNext()
483    {
484        if( 
485                Gdx.input.isKeyPressed(Input.Keys.ANY_KEY)
486                && !Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT)
487                && !Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT)
488                && !Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT)
489                && !Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)
490                && !Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT)
491                && !Gdx.input.isKeyPressed(Input.Keys.ALT_RIGHT)
492                && !heldCodes.isEmpty()
493                && TimeUtils.timeSinceMillis(lastKeyTime) > repeatGapMillis // defaults to 220 ms
494                )
495        {
496            keyDown(heldCodes.lastKey());
497        }
498        return queue.size > 0;
499    }
500
501    /**
502     * Processes the first key event queued up, passing it to this object's InputProcessor. Mouse events are not
503     * queued and are processed when they come in.
504     */
505    public void next() {
506        IntVLA qu = queue;
507        if (keyAction == null) {
508            qu.clear(); // Accidentally captured a keypress when keys aren't meant to be handled
509            return;
510        }
511        if (qu.isEmpty()) {
512            return;
513        }
514//        
515//        for (int i = 0; i < qu.size; i++) {
516//            System.out.print((char)qu.get(i));
517//        }
518//        System.out.println();
519//        
520        int t = qu.removeIndex(0);
521        t = mapping.get(t, t);
522        keyAction.handle((char)t, (t & 0x10000) != 0, (t & 0x20000) != 0, (t & 0x40000) != 0);
523        
524    }
525
526    /**
527     * Empties the backing queue of data.
528     */
529    public void flush()
530    {
531        queue.clear();
532    }
533
534    @Override
535    public boolean keyDown (int keycode) {
536        if (ignoreInput || keyAction == null) {
537            return false;
538        }
539        heldCodes.put(keycode, (int)(lastKeyTime = TimeUtils.millis()));
540        boolean shift = Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT);
541        int c = fromCode(keycode, shift);
542        if(c != '\0') {
543            c |= (Gdx.input.isKeyPressed(Input.Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Input.Keys.ALT_RIGHT))
544                    ? 0x10000 : 0;
545            c |= (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT))
546                    ? 0x20000 : 0;
547            c |= (shift)
548                    ? 0x40000 : 0;
549            //if(queue.isEmpty()) 
550            queue.add(c);
551            //else 
552            //    queue.set(0, c);
553        }
554        return false;
555    }
556    @Override
557        public boolean keyUp (int keycode) {
558        heldCodes.remove(keycode);
559        if(heldCodes.isEmpty())
560            queue.clear();
561        return false;
562    }
563
564    @Override
565        public boolean keyTyped (char character) {
566        return false;
567    }
568
569    @Override
570        public boolean touchDown (int screenX, int screenY, int pointer, int button) {
571        if(ignoreInput || mouse == null) return false;
572        return mouse.touchDown(screenX, screenY, pointer, button);
573    }
574
575    @Override
576        public boolean touchUp (int screenX, int screenY, int pointer, int button) {
577        if(ignoreInput || mouse == null) return false;
578        return mouse.touchUp(screenX, screenY, pointer, button);
579    }
580
581    @Override
582        public boolean touchDragged (int screenX, int screenY, int pointer) {
583        if(ignoreInput || mouse == null) return false;
584        return mouse.touchDragged(screenX, screenY, pointer);
585    }
586
587    @Override
588        public boolean mouseMoved (int screenX, int screenY) {
589        if(ignoreInput || mouse == null) return false;
590        return mouse.mouseMoved(screenX, screenY);
591    }
592
593    @Override
594        public boolean scrolled (int amount) {
595        if(ignoreInput || mouse == null) return false;
596        return mouse.scrolled(amount);
597    }
598
599    /**
600     * Maps keycodes to unicode chars, sometimes depending on whether the Shift key is held.
601     *
602     * It is strongly recommended that you refer to key combinations regarding non-alphabet keys by using, for example,
603     * Ctrl-Shift-; instead of Ctrl-:, that is to use the unshifted key with Shift instead of assuming that all
604     * keyboards will use the QWERTY layout. Pressing shift while pressing just about any representable symbol will map
605     * to the shifted version as if on a QWERTY keyboard, and if you don't have a QWERTY keyboard, the mappings are
606     * documented in full below.
607     *
608     * Keys 'a' to 'z' report 'A' to 'Z' when shift is held. Non-ASCII-Latin characters do not have this behavior, since
609     * most keyboards would be unable to send keys for a particular language and A-Z are very common. You can still
610     * allow a response to, e.g. 'ä' and 'Ä' separately by checking for whether Shift was pressed in conjunction with
611     * 'ä' on a keyboard with that key, which can be useful when users can configure their own keyboard layouts.
612     *
613     * Top row numbers map as follows:
614     *
615     * {@literal '1' to '!', '2' to '@', '3' to '#', '4' to '$', '5' to '%',}
616     * {@literal '6' to '^', '7' to '&amp;', '8' to '*', '9' to '(', '0' to ')'}
617     *
618     * Numpad numbers will report a SquidInput constant such as UP_LEFT_ARROW for Numpad 7, but only if numpadDirections
619     * is true; otherwise they send the number (here, 7). Numpad 0 sends VERTICAL_ARROW or 0.
620     *
621     * Most symbol keys are mapped to a single unicode char as a constant in SquidInput and disregard Shift. The
622     * constant is usually the same as the name of the char; possible exceptions are Backspace (on PC) or Delete (on
623     * Mac) mapping to BACKSPACE, Delete (on PC) mapping to FORWARD_DELETE, Esc mapping to ESCAPE, and Enter (on PC) or
624     * Return (on Mac) mapping to ENTER.
625     *
626     * {@literal ':', '*', '#', '@'}, and space keys, if present, always map to themselves, regardless of Shift.
627     *
628     * Other characters map as follows when Shift is held, as they would on a QWERTY keyboard:
629     * <ul>
630     * <li>{@code ','} to {@code '<'}</li>
631     * <li>{@code '.'} to {@code '>'}</li>
632     * <li>{@code '/'} to {@code '?'}</li>
633     * <li>{@code ';'} to {@code ':'}</li>
634     * <li>{@code '\''} to {@code '"'}</li>
635     * <li>{@code '['} to <code>'{'</code></li>
636     * <li>{@code ']'} to <code>'}'</code></li>
637     * <li>{@code '|'} to {@code '\\'}</li>
638     * <li>{@code '-'} to {@code '_'}</li>
639     * <li>{@code '+'} to {@code '='}</li>
640     * <li>{@code '`'} to {@code '~'} (note, this key produces no event on the GWT backend)</li>
641     * </ul>
642     * @param keycode a keycode as passed by LibGDX
643     * @param shift true if Shift key is being held.
644     * @return a char appropriate to the given keycode; often uses shift to capitalize or change a char, but not for keys like the arrow keys that normally don't produce chars
645     */
646    public char fromCode(int keycode, boolean shift)
647    {
648        switch (keycode) {
649            case Input.Keys.HOME:
650                return HOME;
651            case Input.Keys.FORWARD_DEL:
652                return FORWARD_DELETE;
653            case Input.Keys.ESCAPE:
654                return ESCAPE;
655            case Input.Keys.END:
656                return END;
657
658            case Input.Keys.UP:
659                return UP_ARROW;
660            case Input.Keys.DOWN:
661                return DOWN_ARROW;
662            case Input.Keys.LEFT:
663                return LEFT_ARROW;
664            case Input.Keys.RIGHT:
665                return RIGHT_ARROW;
666            case Input.Keys.CENTER:
667                return CENTER_ARROW;
668
669            case Input.Keys.NUM_0:
670                return (shift) ? ')' : '0';
671            case Input.Keys.NUM_1:
672                return (shift) ? '!' : '1';
673            case Input.Keys.NUM_2:
674                return (shift) ? '@' : '2';
675            case Input.Keys.NUM_3:
676                return (shift) ? '#' : '3';
677            case Input.Keys.NUM_4:
678                return (shift) ? '$' : '4';
679            case Input.Keys.NUM_5:
680                return (shift) ? '%' : '5';
681            case Input.Keys.NUM_6:
682                return (shift) ? '^' : '6';
683            case Input.Keys.NUM_7:
684                return (shift) ? '&' : '7';
685            case Input.Keys.NUM_8:
686                return (shift) ? '*' : '8';
687            case Input.Keys.NUM_9:
688                return (shift) ? '(' : '9';
689            case Input.Keys.NUMPAD_0:
690                return (numpadDirections) ? VERTICAL_ARROW : '0';
691            case Input.Keys.NUMPAD_1:
692                return (numpadDirections) ? DOWN_LEFT_ARROW : '1';
693            case Input.Keys.NUMPAD_2:
694                return (numpadDirections) ? DOWN_ARROW : '2';
695            case Input.Keys.NUMPAD_3:
696                return (numpadDirections) ? DOWN_RIGHT_ARROW : '3';
697            case Input.Keys.NUMPAD_4:
698                return (numpadDirections) ? LEFT_ARROW : '4';
699            case Input.Keys.NUMPAD_5:
700                return (numpadDirections) ? CENTER_ARROW : '5';
701            case Input.Keys.NUMPAD_6:
702                return (numpadDirections) ? RIGHT_ARROW : '6';
703            case Input.Keys.NUMPAD_7:
704                return (numpadDirections) ? UP_LEFT_ARROW : '7';
705            case Input.Keys.NUMPAD_8:
706                return (numpadDirections) ? UP_ARROW : '8';
707            case Input.Keys.NUMPAD_9:
708                return (numpadDirections) ? UP_RIGHT_ARROW : '9';
709            case Input.Keys.COLON:
710                return ':';
711            case Input.Keys.STAR:
712                return '*';
713            case Input.Keys.POUND:
714                return '#';
715            case Input.Keys.A:
716                return (shift) ? 'A' : 'a';
717            case Input.Keys.B:
718                return (shift) ? 'B' : 'b';
719            case Input.Keys.C:
720                return (shift) ? 'C' : 'c';
721            case Input.Keys.D:
722                return (shift) ? 'D' : 'd';
723            case Input.Keys.E:
724                return (shift) ? 'E' : 'e';
725            case Input.Keys.F:
726                return (shift) ? 'F' : 'f';
727            case Input.Keys.G:
728                return (shift) ? 'G' : 'g';
729            case Input.Keys.H:
730                return (shift) ? 'H' : 'h';
731            case Input.Keys.I:
732                return (shift) ? 'I' : 'i';
733            case Input.Keys.J:
734                return (shift) ? 'J' : 'j';
735            case Input.Keys.K:
736                return (shift) ? 'K' : 'k';
737            case Input.Keys.L:
738                return (shift) ? 'L' : 'l';
739            case Input.Keys.M:
740                return (shift) ? 'M' : 'm';
741            case Input.Keys.N:
742                return (shift) ? 'N' : 'n';
743            case Input.Keys.O:
744                return (shift) ? 'O' : 'o';
745            case Input.Keys.P:
746                return (shift) ? 'P' : 'p';
747            case Input.Keys.Q:
748                return (shift) ? 'Q' : 'q';
749            case Input.Keys.R:
750                return (shift) ? 'R' : 'r';
751            case Input.Keys.S:
752                return (shift) ? 'S' : 's';
753            case Input.Keys.T:
754                return (shift) ? 'T' : 't';
755            case Input.Keys.U:
756                return (shift) ? 'U' : 'u';
757            case Input.Keys.V:
758                return (shift) ? 'V' : 'v';
759            case Input.Keys.W:
760                return (shift) ? 'W' : 'w';
761            case Input.Keys.X:
762                return (shift) ? 'X' : 'x';
763            case Input.Keys.Y:
764                return (shift) ? 'Y' : 'y';
765            case Input.Keys.Z:
766                return (shift) ? 'Z' : 'z';
767            case Input.Keys.COMMA:
768                return (shift) ? '<' : ',';
769            case Input.Keys.PERIOD:
770                return (shift) ? '>' :'.';
771            case Input.Keys.TAB:
772                return TAB;
773            case Input.Keys.SPACE:
774                return ' ';
775            case Input.Keys.ENTER:
776                return ENTER;
777            case Input.Keys.BACKSPACE:
778                return BACKSPACE; // also DEL
779            case Input.Keys.GRAVE:
780                return (shift) ? '~' : '`';
781            case Input.Keys.MINUS:
782                return (shift) ? '_' : '-';
783            case Input.Keys.EQUALS:
784                return (shift) ? '+' :'=';
785            case Input.Keys.LEFT_BRACKET:
786                return (shift) ? '{' :'[';
787            case Input.Keys.RIGHT_BRACKET:
788                return (shift) ? '}' :']';
789            case Input.Keys.BACKSLASH:
790                return (shift) ? '|' :'\\';
791            case Input.Keys.SEMICOLON:
792                return (shift) ? ':' :';';
793            case Input.Keys.APOSTROPHE:
794                return (shift) ? '"' :'\'';
795            case Input.Keys.SLASH:
796                return (shift) ? '?' :'/';
797            case Input.Keys.AT:
798                return '@';
799            case Input.Keys.PAGE_UP:
800                return PAGE_UP;
801            case Input.Keys.PAGE_DOWN:
802                return PAGE_DOWN;
803            case Input.Keys.BUTTON_A:
804                return GAMEPAD_A;
805            case Input.Keys.BUTTON_B:
806                return GAMEPAD_B;
807            case Input.Keys.BUTTON_C:
808                return GAMEPAD_C;
809            case Input.Keys.BUTTON_X:
810                return GAMEPAD_X;
811            case Input.Keys.BUTTON_Y:
812                return GAMEPAD_Y;
813            case Input.Keys.BUTTON_Z:
814                return GAMEPAD_Z;
815            case Input.Keys.BUTTON_L1:
816                return GAMEPAD_L1;
817            case Input.Keys.BUTTON_R1:
818                return GAMEPAD_R1;
819            case Input.Keys.BUTTON_L2:
820                return GAMEPAD_L2;
821            case Input.Keys.BUTTON_R2:
822                return GAMEPAD_R2;
823            case Input.Keys.BUTTON_THUMBL:
824                return GAMEPAD_LEFT_THUMB;
825            case Input.Keys.BUTTON_THUMBR:
826                return GAMEPAD_RIGHT_THUMB;
827            case Input.Keys.BUTTON_START:
828                return GAMEPAD_START;
829            case Input.Keys.BUTTON_SELECT:
830                return GAMEPAD_SELECT;
831            case Input.Keys.INSERT:
832                return INSERT;
833
834            case Input.Keys.F1:
835                return F1;
836            case Input.Keys.F2:
837                return F2;
838            case Input.Keys.F3:
839                return F3;
840            case Input.Keys.F4:
841                return F4;
842            case Input.Keys.F5:
843                return F5;
844            case Input.Keys.F6:
845                return F6;
846            case Input.Keys.F7:
847                return F7;
848            case Input.Keys.F8:
849                return F8;
850            case Input.Keys.F9:
851                return F9;
852            case Input.Keys.F10:
853                return F10;
854            case Input.Keys.F11:
855                return F11;
856            case Input.Keys.F12:
857                return F12;
858            default:
859                return '\0';
860        }
861
862    }
863
864    /**
865     * Left arrow key. If numpadDirections is enabled, this will also be sent by Numpad 4.
866     */
867    public static final char LEFT_ARROW = '\u2190';
868    /**
869     * Up arrow key. If numpadDirections is enabled, this will also be sent by Numpad 8.
870     */
871    public static final char UP_ARROW = '\u2191';
872    /**
873     * Down arrow key. If numpadDirections is enabled, this will also be sent by Numpad 6.
874     */
875    public static final char RIGHT_ARROW = '\u2192';
876    /**
877     * Down arrow key. If numpadDirections is enabled, this will also be sent by Numpad 2.
878     */
879    public static final char DOWN_ARROW = '\u2193';
880    /**
881     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 1.
882     */
883    public static final char DOWN_LEFT_ARROW = '\u2199';
884    /**
885     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 3.
886     */
887    public static final char DOWN_RIGHT_ARROW = '\u2198';
888    /**
889     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 9.
890     */
891    public static final char UP_RIGHT_ARROW = '\u2197';
892    /**
893     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 7.
894     */
895    public static final char UP_LEFT_ARROW = '\u2196';
896    /**
897     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 5.
898     */
899    public static final char CENTER_ARROW = '\u21BA';
900    /**
901     * Not typically a dedicated key, but if numpadDirections is enabled, this will be sent by Numpad 0.
902     *
903     * Intended for games that might need up a jump or crouch button on the numpad that supplants movement.
904     */
905    public static final char VERTICAL_ARROW = '\u2195';
906    /**
907     * Enter key, also called Return key. Used to start a new line of text or confirm entries in forms.
908     */
909    public static final char ENTER = '\u21B5';
910    /**
911     * Tab key. Used for entering horizontal spacing, such as indentation, but also often to cycle between menu items.
912     */
913    public static final char TAB = '\u21B9';
914    /**
915     * Backspace key on most PC keyboards; Delete key on Mac keyboards. Used to delete the previous character.
916     */
917    public static final char BACKSPACE = '\u2280';
918    /**
919     * Delete key on most PC keyboards; no equivalent on some (all?) Mac keyboards. Used to delete the next character.
920     *
921     * Not present on some laptop keyboards and some (all?) Mac keyboards.
922     */
923    public static final char FORWARD_DELETE = '\u2281';
924    /**
925     * Insert key. Not recommended for common use because it could affect other application behavior.
926     *
927     * Not present on some laptop keyboards.
928     */
929    public static final char INSERT = '\u2208';
930    /**
931     * Page Down key.
932     *
933     * Not present on some laptop keyboards.
934     */
935    public static final char PAGE_DOWN = '\u22A4';
936    /**
937     * Page Up key.
938     *
939     * Not present on some laptop keyboards.
940     */
941    public static final char PAGE_UP = '\u22A5';
942    /**
943     * Home key (commonly used for moving a cursor to start of line).
944     *
945     * Not present on some laptop keyboards.
946     */
947    public static final char HOME = '\u2302';
948    /**
949     * End key (commonly used for moving a cursor to end of line).
950     *
951     * Not present on some laptop keyboards.
952     */
953    public static final char END = '\u2623';
954    /**
955     * Esc or Escape key
956     */
957    public static final char ESCAPE = '\u2620';
958
959    /**
960     * Function key F1
961     */
962    public static final char F1 = '\u2460';
963    /**
964     * Function key F2
965     */
966    public static final char F2 = '\u2461';
967    /**
968     * Function key F3
969     */
970    public static final char F3 = '\u2462';
971    /**
972     * Function key F4
973     */
974    public static final char F4 = '\u2463';
975    /**
976     * Function key F5
977     */
978    public static final char F5 = '\u2464';
979    /**
980     * Function key F6
981     */
982    public static final char F6 = '\u2465';
983    /**
984     * Function key F7
985     */
986    public static final char F7 = '\u2466';
987    /**
988     * Function key F8
989     */
990    public static final char F8 = '\u2467';
991    /**
992     * Function key F9
993     */
994    public static final char F9 = '\u2468';
995    /**
996     * Function key F10
997     */
998    public static final char F10 = '\u2469';
999    /**
1000     * Function key F11
1001     */
1002    public static final char F11 = '\u246A';
1003    /**
1004     * Function key F12
1005     */
1006    public static final char F12 = '\u246B';
1007
1008    /**
1009     * Gamepad A button.
1010     */
1011    public static final char GAMEPAD_A = '\u24b6';
1012    /**
1013     * Gamepad B button.
1014     */
1015    public static final char GAMEPAD_B = '\u24b7';
1016    /**
1017     * Gamepad C button.
1018     */
1019    public static final char GAMEPAD_C = '\u24b8';
1020    /**
1021     * Gamepad X button.
1022     */
1023    public static final char GAMEPAD_X = '\u24cd';
1024    /**
1025     * Gamepad Y button.
1026     */
1027    public static final char GAMEPAD_Y = '\u24ce';
1028    /**
1029     * Gamepad Z button.
1030     */
1031    public static final char GAMEPAD_Z = '\u24cf';
1032
1033    /**
1034     * Gamepad L1 button.
1035     */
1036    public static final char GAMEPAD_L1 = '\u24c1';
1037    /**
1038     * Gamepad L2 button.
1039     */
1040    public static final char GAMEPAD_L2 = '\u24db';
1041    /**
1042     * Gamepad R1 button.
1043     */
1044    public static final char GAMEPAD_R1 = '\u24c7';
1045    /**
1046     * Gamepad R2 button.
1047     */
1048    public static final char GAMEPAD_R2 = '\u24e1';
1049    /**
1050     * Gamepad Left Thumb button.
1051     */
1052    public static final char GAMEPAD_LEFT_THUMB = '\u24a7';
1053    /**
1054     * Gamepad Right Thumb button.
1055     */
1056    public static final char GAMEPAD_RIGHT_THUMB = '\u24ad';
1057    /**
1058     * Gamepad Start button.
1059     */
1060    public static final char GAMEPAD_START = '\u2713';
1061    /**
1062     * Gamepad Select button.
1063     */
1064    public static final char GAMEPAD_SELECT = '\u261C';
1065
1066
1067}