View Javadoc
1   package org.newdawn.slick;
2   
3   import java.io.IOException;
4   import java.io.OutputStream;
5   import java.util.ArrayList;
6   import java.util.Arrays;
7   import java.util.HashSet;
8   import java.util.List;
9   import java.util.Set;
10  
11  import org.lwjgl.LWJGLException;
12  import org.lwjgl.input.Controller;
13  import org.lwjgl.input.Controllers;
14  import org.lwjgl.input.Keyboard;
15  import org.lwjgl.input.Mouse;
16  import org.lwjgl.opengl.Display;
17  import org.newdawn.slick.util.Log;
18  
19  /**
20   * A wrapper for all keyboard, mouse and controller input.
21   *
22   * @author kevin
23   */
24  public final class Input {
25      /** The controller index to pass to check all controllers. */
26      private static final int ANY_CONTROLLER = -1;
27  
28      /** The maximum number of buttons on controllers. */
29      private static final int MAX_BUTTONS = 100;
30  
31      /** */
32      public static final int KEY_ESCAPE          = 0x01;
33      /** */
34      public static final int KEY_1               = 0x02;
35      /** */
36      public static final int KEY_2               = 0x03;
37      /** */
38      public static final int KEY_3               = 0x04;
39      /** */
40      public static final int KEY_4               = 0x05;
41      /** */
42      public static final int KEY_5               = 0x06;
43      /** */
44      public static final int KEY_6               = 0x07;
45      /** */
46      public static final int KEY_7               = 0x08;
47      /** */
48      public static final int KEY_8               = 0x09;
49      /** */
50      public static final int KEY_9               = 0x0A;
51      /** */
52      public static final int KEY_0               = 0x0B;
53      /** */
54      public static final int KEY_MINUS           = 0x0C; /* - on main keyboard. */
55      /** */
56      private static final int KEY_EQUALS          = 0x0D;
57      /** */
58      public static final int KEY_BACK            = 0x0E; /* backspace. */
59      /** */
60      public static final int KEY_TAB             = 0x0F;
61      /** */
62      public static final int KEY_Q               = 0x10;
63      /** */
64      public static final int KEY_W               = 0x11;
65      /** */
66      public static final int KEY_E               = 0x12;
67      /** */
68      public static final int KEY_R               = 0x13;
69      /** */
70      public static final int KEY_T               = 0x14;
71      /** */
72      public static final int KEY_Y               = 0x15;
73      /** */
74      public static final int KEY_U               = 0x16;
75      /** */
76      public static final int KEY_I               = 0x17;
77      /** */
78      public static final int KEY_O               = 0x18;
79      /** */
80      public static final int KEY_P               = 0x19;
81      /** */
82      public static final int KEY_LBRACKET        = 0x1A;
83      /** */
84      public static final int KEY_RBRACKET        = 0x1B;
85      /** */
86      public static final int KEY_RETURN          = 0x1C; /* Enter on main keyboard */
87      /** */
88      public static final int KEY_ENTER           = 0x1C; /* Enter on main keyboard */
89      /** */
90      public static final int KEY_LCONTROL        = 0x1D;
91      /** */
92      public static final int KEY_A               = 0x1E;
93      /** */
94      public static final int KEY_S               = 0x1F;
95      /** */
96      public static final int KEY_D               = 0x20;
97      /** */
98      public static final int KEY_F               = 0x21;
99      /** */
100     public static final int KEY_G               = 0x22;
101     /** */
102     public static final int KEY_H               = 0x23;
103     /** */
104     public static final int KEY_J               = 0x24;
105     /** */
106     public static final int KEY_K               = 0x25;
107     /** */
108     public static final int KEY_L               = 0x26;
109     /** */
110     public static final int KEY_SEMICOLON       = 0x27;
111     /** */
112     public static final int KEY_APOSTROPHE      = 0x28;
113     /** */
114     public static final int KEY_GRAVE           = 0x29; /* accent grave */
115     /** */
116     public static final int KEY_LSHIFT          = 0x2A;
117     /** */
118     public static final int KEY_BACKSLASH       = 0x2B;
119     /** */
120     public static final int KEY_Z               = 0x2C;
121     /** */
122     public static final int KEY_X               = 0x2D;
123     /** */
124     public static final int KEY_C               = 0x2E;
125     /** */
126     public static final int KEY_V               = 0x2F;
127     /** */
128     public static final int KEY_B               = 0x30;
129     /** */
130     public static final int KEY_N               = 0x31;
131     /** */
132     public static final int KEY_M               = 0x32;
133     /** */
134     public static final int KEY_COMMA           = 0x33;
135     /** */
136     public static final int KEY_PERIOD          = 0x34; /* . on main keyboard */
137     /** */
138     public static final int KEY_SLASH           = 0x35; /* / on main keyboard */
139     /** */
140     public static final int KEY_RSHIFT          = 0x36;
141     /** */
142     public static final int KEY_MULTIPLY        = 0x37; /* * on numeric keypad */
143     /** */
144     private static final int KEY_LMENU           = 0x38; /* left Alt */
145     /** */
146     public static final int KEY_SPACE           = 0x39;
147     /** */
148     public static final int KEY_CAPITAL         = 0x3A;
149     /** */
150     public static final int KEY_F1              = 0x3B;
151     /** */
152     public static final int KEY_F2              = 0x3C;
153     /** */
154     public static final int KEY_F3              = 0x3D;
155     /** */
156     public static final int KEY_F4              = 0x3E;
157     /** */
158     public static final int KEY_F5              = 0x3F;
159     /** */
160     public static final int KEY_F6              = 0x40;
161     /** */
162     public static final int KEY_F7              = 0x41;
163     /** */
164     public static final int KEY_F8              = 0x42;
165     /** */
166     public static final int KEY_F9              = 0x43;
167     /** */
168     public static final int KEY_F10             = 0x44;
169     /** */
170     public static final int KEY_NUMLOCK         = 0x45;
171     /** */
172     public static final int KEY_SCROLL          = 0x46; /* Scroll Lock */
173     /** */
174     public static final int KEY_NUMPAD7         = 0x47;
175     /** */
176     public static final int KEY_NUMPAD8         = 0x48;
177     /** */
178     public static final int KEY_NUMPAD9         = 0x49;
179     /** */
180     public static final int KEY_SUBTRACT        = 0x4A; /* - on numeric keypad */
181     /** */
182     public static final int KEY_NUMPAD4         = 0x4B;
183     /** */
184     public static final int KEY_NUMPAD5         = 0x4C;
185     /** */
186     public static final int KEY_NUMPAD6         = 0x4D;
187     /** */
188     public static final int KEY_ADD             = 0x4E; /* + on numeric keypad */
189     /** */
190     public static final int KEY_NUMPAD1         = 0x4F;
191     /** */
192     public static final int KEY_NUMPAD2         = 0x50;
193     /** */
194     public static final int KEY_NUMPAD3         = 0x51;
195     /** */
196     public static final int KEY_NUMPAD0         = 0x52;
197     /** */
198     public static final int KEY_DECIMAL         = 0x53; /* . on numeric keypad */
199     /** */
200     public static final int KEY_F11             = 0x57;
201     /** */
202     public static final int KEY_F12             = 0x58;
203     /** */
204     public static final int KEY_F13             = 0x64; /*                     (NEC PC98) */
205     /** */
206     public static final int KEY_F14             = 0x65; /*                     (NEC PC98) */
207     /** */
208     public static final int KEY_F15             = 0x66; /*                     (NEC PC98) */
209     /** */
210     public static final int KEY_KANA            = 0x70; /* (Japanese keyboard)            */
211     /** */
212     public static final int KEY_CONVERT         = 0x79; /* (Japanese keyboard)            */
213     /** */
214     public static final int KEY_NOCONVERT       = 0x7B; /* (Japanese keyboard)            */
215     /** */
216     public static final int KEY_YEN             = 0x7D; /* (Japanese keyboard)            */
217     /** */
218     public static final int KEY_NUMPADEQUALS    = 0x8D; /* = on numeric keypad (NEC PC98) */
219     /** */
220     public static final int KEY_CIRCUMFLEX      = 0x90; /* (Japanese keyboard)            */
221     /** */
222     public static final int KEY_AT              = 0x91; /*                     (NEC PC98) */
223     /** */
224     public static final int KEY_COLON           = 0x92; /*                     (NEC PC98) */
225     /** */
226     public static final int KEY_UNDERLINE       = 0x93; /*                     (NEC PC98) */
227     /** */
228     public static final int KEY_KANJI           = 0x94; /* (Japanese keyboard)            */
229     /** */
230     public static final int KEY_STOP            = 0x95; /*                     (NEC PC98) */
231     /** */
232     public static final int KEY_AX              = 0x96; /*                     (Japan AX) */
233     /** */
234     public static final int KEY_UNLABELED       = 0x97; /*                        (J3100) */
235     /** */
236     public static final int KEY_NUMPADENTER     = 0x9C; /* Enter on numeric keypad */
237     /** */
238     public static final int KEY_RCONTROL        = 0x9D;
239     /** */
240     public static final int KEY_NUMPADCOMMA     = 0xB3; /* , on numeric keypad (NEC PC98) */
241     /** */
242     public static final int KEY_DIVIDE          = 0xB5; /* / on numeric keypad */
243     /** */
244     public static final int KEY_SYSRQ           = 0xB7;
245     /** */
246     private static final int KEY_RMENU           = 0xB8; /* right Alt */
247     /** */
248     public static final int KEY_PAUSE           = 0xC5; /* Pause */
249     /** */
250     public static final int KEY_HOME            = 0xC7; /* Home on arrow keypad */
251     /** */
252     public static final int KEY_UP              = 0xC8; /* UpArrow on arrow keypad */
253     /** */
254     public static final int KEY_PRIOR           = 0xC9; /* PgUp on arrow keypad */
255     /** */
256     public static final int KEY_LEFT            = 0xCB; /* LeftArrow on arrow keypad */
257     /** */
258     public static final int KEY_RIGHT           = 0xCD; /* RightArrow on arrow keypad */
259     /** */
260     public static final int KEY_END             = 0xCF; /* End on arrow keypad */
261     /** */
262     public static final int KEY_DOWN            = 0xD0; /* DownArrow on arrow keypad */
263     /** */
264     public static final int KEY_NEXT            = 0xD1; /* PgDn on arrow keypad */
265     /** */
266     public static final int KEY_INSERT          = 0xD2; /* Insert on arrow keypad */
267     /** */
268     public static final int KEY_DELETE          = 0xD3; /* Delete on arrow keypad */
269     /** */
270     public static final int KEY_LWIN            = 0xDB; /* Left Windows key */
271     /** */
272     public static final int KEY_RWIN            = 0xDC; /* Right Windows key */
273     /** */
274     public static final int KEY_APPS            = 0xDD; /* AppMenu key */
275     /** */
276     public static final int KEY_POWER           = 0xDE;
277     /** */
278     public static final int KEY_SLEEP           = 0xDF;
279 
280     /** A helper for left ALT. */
281     public static final int KEY_LALT = KEY_LMENU;
282     /** A helper for right ALT. */
283     public static final int KEY_RALT = KEY_RMENU;
284 
285     /** Control index. */
286     private static final int LEFT = 0;
287     /** Control index. */
288     private static final int RIGHT = 1;
289     /** Control index. */
290     private static final int UP = 2;
291     /** Control index. */
292     private static final int DOWN = 3;
293     /** Control index. */
294     private static final int BUTTON1 = 4;
295     /** Control index. */
296     public static final int BUTTON2 = 5;
297     /** Control index. */
298     public static final int BUTTON3 = 6;
299     /** Control index. */
300     public static final int BUTTON4 = 7;
301     /** Control index. */
302     public static final int BUTTON5 = 8;
303     /** Control index. */
304     public static final int BUTTON6 = 9;
305     /** Control index. */
306     public static final int BUTTON7 = 10;
307     /** Control index. */
308     public static final int BUTTON8 = 11;
309     /** Control index. */
310     public static final int BUTTON9 = 12;
311     /** Control index. */
312     public static final int BUTTON10 = 13;
313 
314     /** The left mouse button indicator. */
315     public static final int MOUSE_LEFT_BUTTON = 0;
316     /** The right mouse button indicator. */
317     public static final int MOUSE_RIGHT_BUTTON = 1;
318     /** The middle mouse button indicator. */
319     public static final int MOUSE_MIDDLE_BUTTON = 2;
320 
321     /** True if the controllers system has been initialised. */
322     private static boolean controllersInited = false;
323     /** The list of controllers. */
324     private static final List<Controller> controllers = new ArrayList<>();
325 
326     /** The last recorded mouse x position. */
327     private int lastMouseX;
328     /** The last recorded mouse y position. */
329     private int lastMouseY;
330     /** THe state of the mouse buttons. */
331     private final boolean[] mousePressed = new boolean[10];
332     /** THe state of the controller buttons. */
333     private final boolean[][] controllerPressed = new boolean[100][MAX_BUTTONS];
334 
335     /** The character values representing the pressed keys. */
336     private final char[] keys = new char[1024];
337     /** True if the key has been pressed since last queries. */
338     private final boolean[] pressed = new boolean[1024];
339     /** The time since the next key repeat to be fired for the key. */
340     private final long[] nextRepeat = new long[1024];
341 
342     /** The control states from the controllers. */
343     private final boolean[][] controls = new boolean[10][MAX_BUTTONS+10];
344     /** True if the event has been consumed. */
345     private boolean consumed = false;
346     /** A list of listeners to be notified of input events. */
347     private final Set<ControlledInputReceiver> allListeners = new HashSet<>();
348     /** The listeners to notify of key events. */
349     private final List<KeyListener> keyListeners = new ArrayList<>();
350     /** The listener to add. */
351     private final List<KeyListener> keyListenersToAdd = new ArrayList<>();
352     /** The listeners to notify of mouse events. */
353     private final List<MouseListener> mouseListeners = new ArrayList<>();
354     /** The listener to add. */
355     private final List<MouseListener> mouseListenersToAdd = new ArrayList<>();
356     /** The listener to nofiy of controller events. */
357     private final List<ControllerListener> controllerListeners = new ArrayList<>();
358     /** The current value of the wheel. */
359     @SuppressWarnings("unused")
360     private int wheel;
361     /** The height of the display. */
362     private int height;
363 
364     /** True if the display is active. */
365     private boolean displayActive = true;
366 
367     /** True if key repeat is enabled. */
368     private boolean keyRepeat;
369     /** The initial delay for key repeat starts. */
370     private int keyRepeatInitial;
371     /** The interval of key repeat. */
372     private int keyRepeatInterval;
373 
374     /** True if the input is currently paused. */
375     private boolean paused;
376     /** The scale to apply to screen coordinates. */
377     private float scaleX = 1;
378     /** The scale to apply to screen coordinates. */
379     private float scaleY = 1;
380     /** The offset to apply to screen coordinates. */
381     private float xoffset = 0;
382     /** The offset to apply to screen coordinates. */
383     private float yoffset = 0;
384 
385     /** The delay before determining a single or double click. */
386     private int doubleClickDelay = 250;
387     /** The timer running out for a single click. */
388     private long doubleClickTimeout = 0;
389 
390     /** The clicked x position. */
391     @SuppressWarnings("unused")
392     private int clickX;
393     /** The clicked y position. */
394     @SuppressWarnings("unused")
395     private int clickY;
396     /** The clicked button. */
397     private int clickButton;
398 
399     /** The x position location the mouse was pressed. */
400     private int pressedX = -1;
401 
402     /** The x position location the mouse was pressed. */
403     private int pressedY = -1;
404 
405     /** The pixel distance the mouse can move to accept a mouse click. */
406     private int mouseClickTolerance = 5;
407 
408     /**
409      * Disables support for controllers. This means the jinput JAR and native libs
410      * are not required.
411      */
412     public static void disableControllers() {
413        controllersInited = true;
414     }
415 
416     /**
417      * Create a new input with the height of the screen.
418      *
419      * @param height The height of the screen
420      */
421     public Input(int height) {
422         init(height);
423     }
424 
425     /**
426      * Set the double click interval, the time between the first
427      * and second clicks that should be interpreted as a
428      * double click.
429      *
430      * @param delay The delay between clicks
431      */
432     public void setDoubleClickInterval(int delay) {
433         doubleClickDelay = delay;
434     }
435 
436     /**
437      * Set the pixel distance the mouse can move to accept a mouse click.
438      * Default is 5.
439      *
440      * @param mouseClickTolerance The number of pixels.
441      */
442     public void setMouseClickTolerance (int mouseClickTolerance) {
443         this.mouseClickTolerance = mouseClickTolerance;
444     }
445 
446     /**
447      * Set the scaling to apply to screen coordinates.
448      *
449      * @param scaleX The scaling to apply to the horizontal axis
450      * @param scaleY The scaling to apply to the vertical axis
451      */
452     void setScale(float scaleX, float scaleY) {
453         this.scaleX = scaleX;
454         this.scaleY = scaleY;
455     }
456 
457     /**
458      * Set the offset to apply to the screen coordinates.
459      *
460      * @param xoffset The offset on the x-axis
461      * @param yoffset The offset on the y-axis
462      */
463     void setOffset(float xoffset, float yoffset) {
464         this.xoffset = xoffset;
465         this.yoffset = yoffset;
466     }
467 
468     /**
469      * Reset the transformation being applied to the input to the default.
470      */
471     public void resetInputTransform() {
472         setOffset(0, 0);
473         setScale(1, 1);
474     }
475 
476     /**
477      * Add a listener to be notified of input events.
478      *
479      * @param listener The listener to be notified
480      */
481     public void addListener(InputListener listener) {
482         addKeyListener(listener);
483         addMouseListener(listener);
484         addControllerListener(listener);
485     }
486 
487     /**
488      * Add a key listener to be notified of key input events.
489      *
490      * @param listener The listener to be notified
491      */
492     void addKeyListener(KeyListener listener) {
493         keyListenersToAdd.add(listener);
494     }
495 
496     /**
497      * Add a key listener to be notified of key input events.
498      *
499      * @param listener The listener to be notified
500      */
501     private void addKeyListenerImpl(KeyListener listener) {
502         if (keyListeners.contains(listener)) {
503             return;
504         }
505         keyListeners.add(listener);
506         allListeners.add(listener);
507     }
508 
509     /**
510      * Add a mouse listener to be notified of mouse input events.
511      *
512      * @param listener The listener to be notified
513      */
514     void addMouseListener(MouseListener listener) {
515         mouseListenersToAdd.add(listener);
516     }
517 
518     /**
519      * Add a mouse listener to be notified of mouse input events.
520      *
521      * @param listener The listener to be notified
522      */
523     private void addMouseListenerImpl(MouseListener listener) {
524         if (mouseListeners.contains(listener)) {
525             return;
526         }
527         mouseListeners.add(listener);
528         allListeners.add(listener);
529     }
530 
531     /**
532      * Add a controller listener to be notified of controller input events.
533      *
534      * @param listener The listener to be notified
535      */
536     void addControllerListener(ControllerListener listener) {
537         if (controllerListeners.contains(listener)) {
538             return;
539         }
540         controllerListeners.add(listener);
541         allListeners.add(listener);
542     }
543 
544     /**
545      * Remove all the listeners from this input.
546      */
547     public void removeAllListeners() {
548         removeAllKeyListeners();
549         removeAllMouseListeners();
550         removeAllControllerListeners();
551     }
552 
553     /**
554      * Remove all the key listeners from this input.
555      */
556     void removeAllKeyListeners() {
557         allListeners.removeAll(keyListeners);
558         keyListeners.clear();
559     }
560 
561     /**
562      * Remove all the mouse listeners from this input.
563      */
564     void removeAllMouseListeners() {
565         allListeners.removeAll(mouseListeners);
566         mouseListeners.clear();
567     }
568 
569     /**
570      * Remove all the controller listeners from this input.
571      */
572     void removeAllControllerListeners() {
573         allListeners.removeAll(controllerListeners);
574         controllerListeners.clear();
575     }
576 
577     /**
578      * Add a listener to be notified of input events. This listener
579      * will get events before others that are currently registered
580      *
581      * @param listener The listener to be notified
582      */
583     public void addPrimaryListener(InputListener listener) {
584         removeListener(listener);
585 
586         keyListeners.add(0, listener);
587         mouseListeners.add(0, listener);
588         controllerListeners.add(0, listener);
589 
590         allListeners.add(listener);
591     }
592 
593     /**
594      * Remove a listener that will no longer be notified.
595      *
596      * @param listener The listen to be removed
597      */
598     void removeListener(InputListener listener) {
599         removeKeyListener(listener);
600         removeMouseListener(listener);
601         removeControllerListener(listener);
602     }
603 
604     /**
605      * Remove a key listener that will no longer be notified.
606      *
607      * @param listener The listen to be removed
608      */
609     void removeKeyListener(KeyListener listener) {
610         keyListeners.remove(listener);
611         allListeners.remove(listener);
612     }
613 
614     /**
615      * Remove a controller listener that will no longer be notified.
616      *
617      * @param listener The listen to be removed
618      */
619     void removeControllerListener(ControllerListener listener) {
620         controllerListeners.remove(listener);
621         allListeners.remove(listener);
622     }
623 
624     /**
625      * Remove a mouse listener that will no longer be notified.
626      *
627      * @param listener The listen to be removed
628      */
629     void removeMouseListener(MouseListener listener) {
630         mouseListeners.remove(listener);
631         allListeners.remove(listener);
632     }
633 
634     /**
635      * Initialise the input system.
636      *
637      * @param height The height of the window
638      */
639     void init(int height) {
640         this.height = height;
641         lastMouseX = getMouseX();
642         lastMouseY = getMouseY();
643     }
644 
645     /**
646      * Get the character representation of the key identified by the specified code.
647      *
648      * @param code The key code of the key to retrieve the name of
649      * @return The name or character representation of the key requested
650      */
651     public static String getKeyName(int code) {
652         return Keyboard.getKeyName(code);
653     }
654 
655     /**
656      * Check if a particular key has been pressed since this method
657      * was last called for the specified key.
658      *
659      * @param code The key code of the key to check
660      * @return True if the key has been pressed
661      */
662     public boolean isKeyPressed(int code) {
663         if (pressed[code]) {
664             pressed[code] = false;
665             return true;
666         }
667 
668         return false;
669     }
670 
671     /**
672      * Check if a mouse button has been pressed since last call.
673      *
674      * @param button The button to check
675      * @return True if the button has been pressed since last call
676      */
677     public boolean isMousePressed(int button) {
678         if (mousePressed[button]) {
679             mousePressed[button] = false;
680             return true;
681         }
682 
683         return false;
684     }
685 
686     /**
687      * Check if a controller button has been pressed since last
688      * time.
689      *
690      * @param button The button to check for (note that this includes directional controls first)
691      * @return True if the button has been pressed since last time
692      */
693     public boolean isControlPressed(int button) {
694         return isControlPressed(button, 0);
695     }
696 
697     /**
698      * Check if a controller button has been pressed since last
699      * time.
700      *
701      * @param controller The index of the controller to check
702      * @param button The button to check for (note that this includes directional controls first)
703      * @return True if the button has been pressed since last time
704      */
705     boolean isControlPressed(int button, int controller) {
706         if (controllerPressed[controller][button]) {
707             controllerPressed[controller][button] = false;
708             return true;
709         }
710 
711         return false;
712     }
713 
714     /**
715      * Clear the state for isControlPressed method. This will reset all
716      * controls to not pressed.
717      */
718     void clearControlPressedRecord() {
719         for (int i=0;i<controllers.size();i++) {
720             Arrays.fill(controllerPressed[i], false);
721         }
722     }
723 
724     /**
725      * Clear the state for the <code>isKeyPressed</code> method. This will
726      * resort in all keys returning that they haven't been pressed, until
727      * they are pressed again
728      */
729     void clearKeyPressedRecord() {
730         Arrays.fill(pressed, false);
731     }
732 
733     /**
734      * Clear the state for the <code>isMousePressed</code> method. This will
735      * resort in all mouse buttons returning that they haven't been pressed, until
736      * they are pressed again.
737      */
738     void clearMousePressedRecord() {
739         Arrays.fill(mousePressed, false);
740     }
741 
742     /**
743      * Check if a particular key is down.
744      *
745      * @param code The key code of the key to check
746      * @return True if the key is down
747      */
748     public boolean isKeyDown(int code) {
749         return Keyboard.isKeyDown(code);
750     }
751 
752     /**
753      * Get the absolute x position of the mouse cursor within the container.
754      *
755      * @return The absolute x position of the mouse cursor
756      */
757     public int getAbsoluteMouseX() {
758         return Mouse.getX();
759     }
760 
761     /**
762      * Get the absolute y position of the mouse cursor within the container.
763      *
764      * @return The absolute y position of the mouse cursor
765      */
766     public int getAbsoluteMouseY() {
767         return height - Mouse.getY() - 1;
768     }
769 
770     /**
771      * Get the x position of the mouse cursor.
772      *
773      * @return The x position of the mouse cursor
774      */
775     int getMouseX() {
776         return (int) ((Mouse.getX() * scaleX)+xoffset);
777     }
778 
779     /**
780      * Get the y position of the mouse cursor.
781      *
782      * @return The y position of the mouse cursor
783      */
784     int getMouseY() {
785         return (int) (((height-Mouse.getY() - 1) * scaleY)+yoffset);
786     }
787 
788     /**
789      * Check if a given mouse button is down.
790      *
791      * @param button The index of the button to check (starting at 0)
792      * @return True if the mouse button is down
793      */
794     public boolean isMouseButtonDown(int button) {
795         return Mouse.isButtonDown(button);
796     }
797 
798     /**
799      * Check if any mouse button is down.
800      *
801      * @return True if any mouse button is down
802      */
803     private boolean anyMouseDown() {
804         for (int i=0;i<3;i++) {
805             if (Mouse.isButtonDown(i)) {
806                 return true;
807             }
808         }
809 
810         return false;
811     }
812 
813     /**
814      * Get a count of the number of controllers available.
815      *
816      * @return The number of controllers available
817      */
818     int getControllerCount() {
819         try {
820             initControllers();
821         } catch (SlickException e) {
822             throw new RuntimeException("Failed to initialise controllers");
823         }
824 
825         return controllers.size();
826     }
827 
828     /**
829      * Get the number of axis that are available on a given controller.
830      *
831      * @param controller The index of the controller to check
832      * @return The number of axis available on the controller
833      */
834     public int getAxisCount(int controller) {
835         return controllers.get(controller).getAxisCount();
836     }
837 
838     /**
839      * Get the value of the axis with the given index.
840      *
841      * @param controller The index of the controller to check
842      * @param axis The index of the axis to read
843      * @return The axis value at time of reading
844      */
845     public float getAxisValue(int controller, int axis) {
846         return controllers.get(controller).getAxisValue(axis);
847     }
848 
849     /**
850      * Get the name of the axis with the given index.
851      *
852      * @param controller The index of the controller to check
853      * @param axis The index of the axis to read
854      * @return The name of the specified axis
855      */
856     public String getAxisName(int controller, int axis) {
857         return controllers.get(controller).getAxisName(axis);
858     }
859 
860     /**
861      * Check if the controller has the left direction pressed.
862      *
863      * @param controller The index of the controller to check
864      * @return True if the controller is pressed to the left
865      */
866     boolean isControllerLeft(int controller) {
867         if (controller >= getControllerCount()) {
868             return false;
869         }
870 
871         if (controller == ANY_CONTROLLER) {
872             for (int i=0;i<controllers.size();i++) {
873                 if (isControllerLeft(i)) {
874                     return true;
875                 }
876             }
877 
878             return false;
879         }
880 
881         return controllers.get(controller).getXAxisValue() < -0.5f
882                 || controllers.get(controller).getPovX() < -0.5f;
883     }
884 
885     /**
886      * Check if the controller has the right direction pressed.
887      *
888      * @param controller The index of the controller to check
889      * @return True if the controller is pressed to the right
890      */
891     boolean isControllerRight(int controller) {
892         if (controller >= getControllerCount()) {
893             return false;
894         }
895 
896         if (controller == ANY_CONTROLLER) {
897             for (int i=0;i<controllers.size();i++) {
898                 if (isControllerRight(i)) {
899                     return true;
900                 }
901             }
902 
903             return false;
904         }
905 
906         return controllers.get(controller).getXAxisValue() > 0.5f
907                    || controllers.get(controller).getPovX() > 0.5f;
908     }
909 
910     /**
911      * Check if the controller has the up direction pressed.
912      *
913      * @param controller The index of the controller to check
914      * @return True if the controller is pressed to the up
915      */
916     boolean isControllerUp(int controller) {
917         if (controller >= getControllerCount()) {
918             return false;
919         }
920 
921         if (controller == ANY_CONTROLLER) {
922             for (int i=0;i<controllers.size();i++) {
923                 if (isControllerUp(i)) {
924                     return true;
925                 }
926             }
927 
928             return false;
929         }
930         return controllers.get(controller).getYAxisValue() < -0.5f
931                    || controllers.get(controller).getPovY() < -0.5f;
932     }
933 
934     /**
935      * Check if the controller has the down direction pressed.
936      *
937      * @param controller The index of the controller to check
938      * @return True if the controller is pressed to the down
939      */
940     boolean isControllerDown(int controller) {
941         if (controller >= getControllerCount()) {
942             return false;
943         }
944 
945         if (controller == ANY_CONTROLLER) {
946             for (int i=0;i<controllers.size();i++) {
947                 if (isControllerDown(i)) {
948                     return true;
949                 }
950             }
951 
952             return false;
953         }
954 
955         return controllers.get(controller).getYAxisValue() > 0.5f
956                || controllers.get(controller).getPovY() > 0.5f;
957 
958     }
959 
960     /**
961      * Check if controller button is pressed.
962      *
963      * @param controller The index of the controller to check
964      * @param index The index of the button to check
965      * @return True if the button is pressed
966      */
967     boolean isButtonPressed(int index, int controller) {
968         if (controller >= getControllerCount()) {
969             return false;
970         }
971 
972         if (controller == ANY_CONTROLLER) {
973             for (int i=0;i<controllers.size();i++) {
974                 if (isButtonPressed(index, i)) {
975                     return true;
976                 }
977             }
978 
979             return false;
980         }
981 
982         return controllers.get(controller).isButtonPressed(index);
983     }
984 
985     /**
986      * Check if button 1 is pressed.
987      *
988      * @param controller The index of the controller to check
989      * @return True if the button is pressed
990      */
991     public boolean isButton1Pressed(int controller) {
992         return isButtonPressed(0, controller);
993     }
994 
995     /**
996      * Check if button 2 is pressed.
997      *
998      * @param controller The index of the controller to check
999      * @return True if the button is pressed
1000      */
1001     public boolean isButton2Pressed(int controller) {
1002         return isButtonPressed(1, controller);
1003     }
1004 
1005     /**
1006      * Check if button 3 is pressed.
1007      *
1008      * @param controller The index of the controller to check
1009      * @return True if the button is pressed
1010      */
1011     public boolean isButton3Pressed(int controller) {
1012         return isButtonPressed(2, controller);
1013     }
1014 
1015     /**
1016      * Initialise the controllers system.
1017      *
1018      * @throws org.newdawn.slick.SlickException Indicates a failure to use the hardware
1019      */
1020     public void initControllers() throws SlickException {
1021         if (controllersInited) {
1022             return;
1023         }
1024 
1025         controllersInited = true;
1026         try {
1027             Controllers.create();
1028             int count = Controllers.getControllerCount();
1029 
1030             for (int i = 0; i < count; i++) {
1031                 Controller controller = Controllers.getController(i);
1032 
1033                 if ((controller.getButtonCount() >= 3) && (controller.getButtonCount() < MAX_BUTTONS)) {
1034                     controllers.add(controller);
1035                 }
1036             }
1037 
1038             Log.info("Found "+controllers.size()+" controllers");
1039             for (int i=0;i<controllers.size();i++) {
1040                 Log.info(i+" : "+ controllers.get(i).getName());
1041             }
1042         } catch (LWJGLException e) {
1043             if (e.getCause() instanceof ClassNotFoundException) {
1044                 throw new SlickException(
1045                         "Unable to create controller - no jinput found - add jinput.jar to your classpath");
1046             }
1047             throw new SlickException("Unable to create controllers");
1048         } catch (NoClassDefFoundError e) {
1049             // forget it, no jinput available
1050         }
1051     }
1052 
1053     /**
1054      * Notification from an event handle that an event has been consumed.
1055      */
1056     public void consumeEvent() {
1057         consumed = true;
1058     }
1059 
1060     /**
1061      * A null stream to clear out those horrid errors.
1062      *
1063      * @author kevin
1064      */
1065     @SuppressWarnings("unused")
1066     private final class NullOutputStream extends OutputStream {
1067         /**
1068          * @see java.io.OutputStream#write(int)
1069          */
1070         @Override
1071         public void write(int b) throws IOException {
1072             // null implementation
1073         }
1074 
1075     }
1076 
1077     /**
1078      * Hook to allow us to translate any key character into special key
1079      * codes for easier use.
1080      *
1081      * @param key The original key code
1082      * @param c The character that was fired
1083      * @return The key code to fire
1084      */
1085     private int resolveEventKey(int key, char c) {
1086         // BUG with LWJGL - equals comes back with keycode = 0
1087         // See: http://slick.javaunlimited.net/viewtopic.php?t=617
1088         if ((c == 61) || (key == 0)) {
1089             return KEY_EQUALS;
1090         }
1091 
1092         return key;
1093     }
1094 
1095     /**
1096      * Notification that the mouse has been pressed and hence we
1097      * should consider what we're doing with double clicking.
1098      *
1099      * @param button The button pressed/released
1100      * @param x The location of the mouse
1101      * @param y The location of the mouse
1102      */
1103     void considerDoubleClick(int button, int x, int y) {
1104         if (doubleClickTimeout == 0) {
1105             clickX = x;
1106             clickY = y;
1107             clickButton = button;
1108             doubleClickTimeout = System.currentTimeMillis() + doubleClickDelay;
1109             fireMouseClicked(button, x, y, 1);
1110         } else {
1111             if (clickButton == button) {
1112                 if ((System.currentTimeMillis() < doubleClickTimeout)) {
1113                     fireMouseClicked(button, x, y, 2);
1114                     doubleClickTimeout = 0;
1115                 }
1116             }
1117         }
1118     }
1119 
1120     /**
1121      * Poll the state of the input.
1122      *
1123      * @param width The width of the game view
1124      * @param height The height of the game view
1125      */
1126     public void poll(int width, int height) {
1127         if (paused) {
1128             clearControlPressedRecord();
1129             clearKeyPressedRecord();
1130             clearMousePressedRecord();
1131 
1132             while (Keyboard.next()) {}
1133             while (Mouse.next()) {}
1134             return;
1135         }
1136 
1137         if (!Display.isActive()) {
1138             clearControlPressedRecord();
1139             clearKeyPressedRecord();
1140             clearMousePressedRecord();
1141         }
1142 
1143         // add any listeners requested since last time
1144         keyListenersToAdd.forEach(this::addKeyListenerImpl);
1145         keyListenersToAdd.clear();
1146         mouseListenersToAdd.forEach(this::addMouseListenerImpl);
1147         mouseListenersToAdd.clear();
1148 
1149         if (doubleClickTimeout != 0) {
1150             if (System.currentTimeMillis() > doubleClickTimeout) {
1151                 doubleClickTimeout = 0;
1152             }
1153         }
1154 
1155         this.height = height;
1156 
1157         for (ControlledInputReceiver listener : allListeners) {
1158             listener.inputStarted();
1159         }
1160 
1161         while (Keyboard.next()) {
1162             if (Keyboard.getEventKeyState()) {
1163                 int eventKey = resolveEventKey(Keyboard.getEventKey(), Keyboard.getEventCharacter());
1164 
1165                 keys[eventKey] = Keyboard.getEventCharacter();
1166                 pressed[eventKey] = true;
1167                 nextRepeat[eventKey] = System.currentTimeMillis() + keyRepeatInitial;
1168 
1169                 consumed = false;
1170                 for (KeyListener listener : keyListeners) {
1171                     if (listener.isAcceptingInput()) {
1172                         listener.keyPressed(eventKey, Keyboard.getEventCharacter());
1173                         if (consumed) {
1174                             break;
1175                         }
1176                     }
1177                 }
1178             } else {
1179                 int eventKey = resolveEventKey(Keyboard.getEventKey(), Keyboard.getEventCharacter());
1180                 nextRepeat[eventKey] = 0;
1181 
1182                 consumed = false;
1183                 for (KeyListener listener : keyListeners) {
1184                     if (listener.isAcceptingInput()) {
1185                         listener.keyReleased(eventKey, keys[eventKey]);
1186                         if (consumed) {
1187                             break;
1188                         }
1189                     }
1190                 }
1191             }
1192         }
1193 
1194         while (Mouse.next()) {
1195             if (Mouse.getEventButton() >= 0) {
1196                 if (Mouse.getEventButtonState()) {
1197                     consumed = false;
1198                     mousePressed[Mouse.getEventButton()] = true;
1199 
1200                     pressedX = (int) (xoffset + (Mouse.getEventX() * scaleX));
1201                     pressedY =  (int) (yoffset + ((height-Mouse.getEventY()) * scaleY));
1202 
1203                     for (MouseListener listener : mouseListeners) {
1204                         if (listener.isAcceptingInput()) {
1205                             listener.mousePressed(Mouse.getEventButton(), pressedX, pressedY);
1206                             if (consumed) {
1207                                 break;
1208                             }
1209                         }
1210                     }
1211                 } else {
1212                     consumed = false;
1213                     mousePressed[Mouse.getEventButton()] = false;
1214 
1215                     int releasedX = (int) (xoffset + (Mouse.getEventX() * scaleX));
1216                     int releasedY = (int) (yoffset + ((height-Mouse.getEventY()) * scaleY));
1217                     if ((pressedX != -1) &&
1218                         (pressedY != -1) &&
1219                         (Math.abs(pressedX - releasedX) < mouseClickTolerance) &&
1220                         (Math.abs(pressedY - releasedY) < mouseClickTolerance)) {
1221                         considerDoubleClick(Mouse.getEventButton(), releasedX, releasedY);
1222                         pressedX = pressedY = -1;
1223                     }
1224 
1225                     for (MouseListener listener : mouseListeners) {
1226                         if (listener.isAcceptingInput()) {
1227                             listener.mouseReleased(Mouse.getEventButton(), releasedX, releasedY);
1228                             if (consumed) {
1229                                 break;
1230                             }
1231                         }
1232                     }
1233                 }
1234             } else {
1235                 if (Mouse.isGrabbed() && displayActive) {
1236                     if ((Mouse.getEventDX() != 0) || (Mouse.getEventDY() != 0)) {
1237                         consumed = false;
1238                         for (MouseListener listener : mouseListeners) {
1239                             if (listener.isAcceptingInput()) {
1240                                 if (anyMouseDown()) {
1241                                     listener.mouseDragged(0, 0, Mouse.getEventDX(), -Mouse.getEventDY());
1242                                 } else {
1243                                     listener.mouseMoved(0, 0, Mouse.getEventDX(), -Mouse.getEventDY());
1244                                 }
1245 
1246                                 if (consumed) {
1247                                     break;
1248                                 }
1249                             }
1250                         }
1251                     }
1252                 }
1253 
1254                 int dwheel = Mouse.getEventDWheel();
1255                 wheel += dwheel;
1256                 if (dwheel != 0) {
1257                     consumed = false;
1258                     for (MouseListener listener : mouseListeners) {
1259                         if (listener.isAcceptingInput()) {
1260                             listener.mouseWheelMoved(dwheel);
1261                             if (consumed) {
1262                                 break;
1263                             }
1264                         }
1265                     }
1266                 }
1267             }
1268         }
1269 
1270         if (!displayActive || Mouse.isGrabbed()) {
1271             lastMouseX = getMouseX();
1272             lastMouseY = getMouseY();
1273         } else {
1274             if ((lastMouseX != getMouseX()) || (lastMouseY != getMouseY())) {
1275                 consumed = false;
1276                 for (MouseListener listener : mouseListeners) {
1277                     if (listener.isAcceptingInput()) {
1278                         if (anyMouseDown()) {
1279                             listener.mouseDragged(lastMouseX, lastMouseY, getMouseX(), getMouseY());
1280                         } else {
1281                             listener.mouseMoved(lastMouseX, lastMouseY, getMouseX(), getMouseY());
1282                         }
1283                         if (consumed) {
1284                             break;
1285                         }
1286                     }
1287                 }
1288                 lastMouseX = getMouseX();
1289                 lastMouseY = getMouseY();
1290             }
1291         }
1292 
1293         if (controllersInited) {
1294             for (int i=0;i<getControllerCount();i++) {
1295                 int count = controllers.get(i).getButtonCount()+3;
1296                 count = Math.min(count, 24);
1297                 for (int c=0;c<=count;c++) {
1298                     if (controls[i][c] && !isControlDwn(c, i)) {
1299                         controls[i][c] = false;
1300                         fireControlRelease(c, i);
1301                     } else if (!controls[i][c] && isControlDwn(c, i)) {
1302                         controllerPressed[i][c] = true;
1303                         controls[i][c] = true;
1304                         fireControlPress(c, i);
1305                     }
1306                 }
1307             }
1308         }
1309 
1310         if (keyRepeat) {
1311             for (int i=0;i<1024;i++) {
1312                 if (pressed[i] && (nextRepeat[i] != 0)) {
1313                     if (System.currentTimeMillis() > nextRepeat[i]) {
1314                         nextRepeat[i] = System.currentTimeMillis() + keyRepeatInterval;
1315                         consumed = false;
1316                         for (KeyListener listener : keyListeners) {
1317                             if (listener.isAcceptingInput()) {
1318                                 listener.keyPressed(i, keys[i]);
1319                                 if (consumed) {
1320                                     break;
1321                                 }
1322                             }
1323                         }
1324                     }
1325                 }
1326             }
1327         }
1328 
1329 
1330         for (ControlledInputReceiver listener : allListeners) {
1331             listener.inputEnded();
1332         }
1333 
1334         if (Display.isCreated()) {
1335             displayActive = Display.isActive();
1336         }
1337     }
1338 
1339     /**
1340      * Enable key repeat for this input context. This will cause keyPressed to get called repeatedly
1341      * at a set interval while the key is pressed.
1342      *
1343      * @param initial The interval before key repeating starts after a key press
1344      * @param interval The interval between key repeats in ms
1345      * @deprecated
1346      */
1347     public void enableKeyRepeat(int initial, int interval) {
1348         Keyboard.enableRepeatEvents(true);
1349     }
1350 
1351     /**
1352      * Enable key repeat for this input context. Uses the system settings for repeat
1353      * interval configuration.
1354      */
1355     public void enableKeyRepeat() {
1356         Keyboard.enableRepeatEvents(true);
1357     }
1358 
1359     /**
1360      * Disable key repeat for this input context.
1361      */
1362     public void disableKeyRepeat() {
1363         Keyboard.enableRepeatEvents(false);
1364     }
1365 
1366     /**
1367      * Check if key repeat is enabled.
1368      *
1369      * @return True if key repeat is enabled
1370      */
1371     public boolean isKeyRepeatEnabled() {
1372         return Keyboard.areRepeatEventsEnabled();
1373     }
1374 
1375     /**
1376      * Fire an event indicating that a control has been pressed.
1377      *
1378      * @param index The index of the control pressed
1379      * @param controllerIndex The index of the controller on which the control was pressed
1380      */
1381     private void fireControlPress(int index, int controllerIndex) {
1382         consumed = false;
1383         for (ControllerListener listener : controllerListeners) {
1384             if (listener.isAcceptingInput()) {
1385                 switch (index) {
1386                     case LEFT:
1387                         listener.controllerLeftPressed(controllerIndex);
1388                         break;
1389                     case RIGHT:
1390                         listener.controllerRightPressed(controllerIndex);
1391                         break;
1392                     case UP:
1393                         listener.controllerUpPressed(controllerIndex);
1394                         break;
1395                     case DOWN:
1396                         listener.controllerDownPressed(controllerIndex);
1397                         break;
1398                     default:
1399                         // assume button pressed
1400                         listener.controllerButtonPressed(controllerIndex, (index - BUTTON1) + 1);
1401                         break;
1402                 }
1403                 if (consumed) {
1404                     break;
1405                 }
1406             }
1407         }
1408     }
1409 
1410     /**
1411      * Fire an event indicating that a control has been released.
1412      *
1413      * @param index The index of the control released
1414      * @param controllerIndex The index of the controller on which the control was released
1415      */
1416     private void fireControlRelease(int index, int controllerIndex) {
1417         consumed = false;
1418         for (ControllerListener listener : controllerListeners) {
1419             if (listener.isAcceptingInput()) {
1420                 switch (index) {
1421                     case LEFT:
1422                         listener.controllerLeftReleased(controllerIndex);
1423                         break;
1424                     case RIGHT:
1425                         listener.controllerRightReleased(controllerIndex);
1426                         break;
1427                     case UP:
1428                         listener.controllerUpReleased(controllerIndex);
1429                         break;
1430                     case DOWN:
1431                         listener.controllerDownReleased(controllerIndex);
1432                         break;
1433                     default:
1434                         // assume button release
1435                         listener.controllerButtonReleased(controllerIndex, (index - BUTTON1) + 1);
1436                         break;
1437                 }
1438                 if (consumed) {
1439                     break;
1440                 }
1441             }
1442         }
1443     }
1444 
1445     /**
1446      * Check if a particular control is currently pressed.
1447      *
1448      * @param index The index of the control
1449      * @param controllerIndex The index of the control to which the control belongs
1450      * @return True if the control is pressed
1451      */
1452     private boolean isControlDwn(int index, int controllerIndex) {
1453         switch (index) {
1454         case LEFT:
1455             return isControllerLeft(controllerIndex);
1456         case RIGHT:
1457             return isControllerRight(controllerIndex);
1458         case UP:
1459             return isControllerUp(controllerIndex);
1460         case DOWN:
1461             return isControllerDown(controllerIndex);
1462         }
1463 
1464         if (index >= BUTTON1) {
1465             return isButtonPressed((index-BUTTON1), controllerIndex);
1466         }
1467 
1468         throw new RuntimeException("Unknown control index");
1469     }
1470 
1471 
1472     /**
1473      * Pauses the polling and sending of input events.
1474      */
1475     public void pause() {
1476         paused = true;
1477 
1478         // Reset all polling arrays
1479         clearKeyPressedRecord();
1480         clearMousePressedRecord();
1481         clearControlPressedRecord();
1482     }
1483 
1484     /**
1485      * Resumes the polling and sending of input events.
1486      */
1487     public void resume() {
1488         paused = false;
1489     }
1490 
1491     /**
1492      * Notify listeners that the mouse button has been clicked.
1493      *
1494      * @param button The button that has been clicked
1495      * @param x The location at which the button was clicked
1496      * @param y The location at which the button was clicked
1497      * @param clickCount The number of times the button was clicked (single or double click)
1498      */
1499     private void fireMouseClicked(int button, int x, int y, int clickCount) {
1500         consumed = false;
1501         for (MouseListener listener : mouseListeners) {
1502             if (listener.isAcceptingInput()) {
1503                 listener.mouseClicked(button, x, y, clickCount);
1504                 if (consumed) {
1505                     break;
1506                 }
1507             }
1508         }
1509     }
1510 }