Keyboard.java
package swingtree.input;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* This is a simple Singleton class representing the current state of the keyboard.
* <b>It is not a keyboard shortcut implementation</b> but merely a fast API to check if
* a certain key on the keyboard has been pressed...
* The keyboard class <b>can not be used to hook up lambda callbacks</b>, but merely ought
* to serve as <b>a common way to query the current state of the keyboard</b>!
*/
public class Keyboard
{
private final static Keyboard INSTANCE = new Keyboard();
/**
* Exposes the singleton instance of the {@link Keyboard} class.
*
* @return The singleton instance of the {@link Keyboard} class.
*/
public static Keyboard get() { return INSTANCE; }
/**
* This enum represents all the keys on the keyboard which can be queried for their current state.
* This is a mapping of the {@link KeyEvent} constants to a more readable and type safe enum.
*/
public enum Key
{
NONE(KeyEvent.VK_UNDEFINED),
ENTER(KeyEvent.VK_ENTER), BACK_SPACE(KeyEvent.VK_BACK_SPACE), TAB(KeyEvent.VK_TAB),
CANCEL(KeyEvent.VK_CANCEL), CLEAR(KeyEvent.VK_CLEAR), SHIFT(KeyEvent.VK_SHIFT),
CONTROL(KeyEvent.VK_CONTROL), ALT(KeyEvent.VK_ALT), PAUSE(KeyEvent.VK_PAUSE), CAPS_LOCK(KeyEvent.VK_CAPS_LOCK),
ESCAPE(KeyEvent.VK_ESCAPE), SPACE(KeyEvent.VK_SPACE), PAGE_UP(KeyEvent.VK_PAGE_UP), PAGE_DOWN(KeyEvent.VK_PAGE_DOWN),
END(KeyEvent.VK_END), HOME(KeyEvent.VK_HOME), LEFT(KeyEvent.VK_LEFT), UP(KeyEvent.VK_UP),
RIGHT(KeyEvent.VK_RIGHT), DOWN(KeyEvent.VK_DOWN), COMMA(KeyEvent.VK_COMMA), MINUS(KeyEvent.VK_MINUS),
PERIOD(KeyEvent.VK_PERIOD), SLASH(KeyEvent.VK_SLASH),
ZERO(KeyEvent.VK_0), ONE(KeyEvent.VK_1), TWO(KeyEvent.VK_2), THREE(KeyEvent.VK_3), FOUR(KeyEvent.VK_4),
FIVE(KeyEvent.VK_5), SIX(KeyEvent.VK_6), SEVEN(KeyEvent.VK_7), EIGHT(KeyEvent.VK_8), NINE(KeyEvent.VK_9),
SEMICOLON(KeyEvent.VK_SEMICOLON),
EQUALS(KeyEvent.VK_EQUALS),
A(KeyEvent.VK_A), B(KeyEvent.VK_B), C(KeyEvent.VK_C), D(KeyEvent.VK_D), E(KeyEvent.VK_E), F(KeyEvent.VK_F),
G(KeyEvent.VK_G), H(KeyEvent.VK_H), I(KeyEvent.VK_I), J(KeyEvent.VK_J), K(KeyEvent.VK_K), L(KeyEvent.VK_L),
M(KeyEvent.VK_M), N(KeyEvent.VK_N), O(KeyEvent.VK_O), P(KeyEvent.VK_P), Q(KeyEvent.VK_Q), R(KeyEvent.VK_R),
S(KeyEvent.VK_S), T(KeyEvent.VK_T), U(KeyEvent.VK_U), V(KeyEvent.VK_V), W(KeyEvent.VK_W), X(KeyEvent.VK_X),
Y(KeyEvent.VK_Y), Z(KeyEvent.VK_Z),
OPEN_BRACKET(KeyEvent.VK_OPEN_BRACKET),
BACK_SLASH(KeyEvent.VK_BACK_SLASH),
CLOSE_BRACKET(KeyEvent.VK_CLOSE_BRACKET),
NUMPAD_0(KeyEvent.VK_NUMPAD0), NUMPAD_1(KeyEvent.VK_NUMPAD1), NUMPAD_2(KeyEvent.VK_NUMPAD2),
NUMPAD_3(KeyEvent.VK_NUMPAD3), NUMPAD_4(KeyEvent.VK_NUMPAD4), NUMPAD_5(KeyEvent.VK_NUMPAD5),
NUMPAD_6(KeyEvent.VK_NUMPAD6), NUMPAD_7(KeyEvent.VK_NUMPAD7), NUMPAD_8(KeyEvent.VK_NUMPAD8),
NUMPAD_9(KeyEvent.VK_NUMPAD9),
MULTIPLY(KeyEvent.VK_MULTIPLY), ADD(KeyEvent.VK_ADD), SEPARATOR(KeyEvent.VK_SEPARATOR),
SUBTRACT(KeyEvent.VK_SUBTRACT), DECIMAL(KeyEvent.VK_DECIMAL), DIVIDE(KeyEvent.VK_DIVIDE),
DELETE(KeyEvent.VK_DELETE), NUM_LOCK(KeyEvent.VK_NUM_LOCK), SCROLL_LOCK(KeyEvent.VK_SCROLL_LOCK),
F1(KeyEvent.VK_F1), F2(KeyEvent.VK_F2), F3(KeyEvent.VK_F3), F4(KeyEvent.VK_F4), F5(KeyEvent.VK_F5),
F6(KeyEvent.VK_F6), F7(KeyEvent.VK_F7), F8(KeyEvent.VK_F8), F9(KeyEvent.VK_F9), F10(KeyEvent.VK_F10),
F11(KeyEvent.VK_F11), F12(KeyEvent.VK_F12), F13(KeyEvent.VK_F13), F14(KeyEvent.VK_F14), F15(KeyEvent.VK_F15),
F16(KeyEvent.VK_F16), F17(KeyEvent.VK_F17), F18(KeyEvent.VK_F18), F19(KeyEvent.VK_F19), F20(KeyEvent.VK_F20),
F21(KeyEvent.VK_F21), F22(KeyEvent.VK_F22), F23(KeyEvent.VK_F23), F24(KeyEvent.VK_F24),
PRINTSCREEN(KeyEvent.VK_PRINTSCREEN),
INSERT(KeyEvent.VK_INSERT),
HELP(KeyEvent.VK_HELP), META(KeyEvent.VK_META), BACK_QUOTE(KeyEvent.VK_BACK_QUOTE),
QUOTE(KeyEvent.VK_QUOTE);
public final int code;
Key( int keyCode ) { this.code = keyCode; }
/**
* This method checks if this key is currently pressed on the keyboard
* by checking if it is in a list of currently pressed keys.
*
* @return The truth value determining if this key is currently pressed on the keyboard.
*/
public boolean isPressed() {
return Keyboard.get().isPressed(this);
}
}
private final List<Key> _pressed = new ArrayList<>();
/**
* This method checks if the supplied {@link Key} is currently pressed on the keyboard.
*
* @param key An instance of the {@link Key} enum representing a keyboard key.
* @return The truth value determining if the specified {@link Key} type is currently pressed by the user.
* @throws NullPointerException If the supplied {@link Key} is null,
* use {@link Key#NONE} instead to check if no key is currently pressed.
*/
public boolean isPressed( Key key ) {
Objects.requireNonNull(key);
synchronized ( this ) {
if ( key == Key.NONE )
return _pressed.isEmpty();
return _pressed.contains(key);
}
}
public Keyboard() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent ke) {
synchronized (this) {
switch ( ke.getID() ) {
case KeyEvent.KEY_PRESSED: {
Key k = _fromKeyEvent(ke);
if ( k != Key.NONE && !_pressed.contains(k) )
_pressed.add(k);
}
break;
case KeyEvent.KEY_RELEASED: {
Key k = _fromKeyEvent(ke);
if ( k != Key.NONE )
_pressed.remove(k);
}
break;
}
return false;
}
}
});
}
private static Key _fromKeyEvent( KeyEvent keyEvent ) {
for ( Key key : Key.values() ) {
if ( key.code == keyEvent.getKeyCode() ) {
return key;
}
}
return Key.NONE;
}
}