diff --git a/src/java/org/lwjgl/input/Keyboard.java b/src/java/org/lwjgl/input/Keyboard.java index b370093f..b81201e5 100644 --- a/src/java/org/lwjgl/input/Keyboard.java +++ b/src/java/org/lwjgl/input/Keyboard.java @@ -57,7 +57,7 @@ import org.lwjgl.opengl.InputImplementation; */ public class Keyboard { /** Internal use - event size in bytes */ - public static final int EVENT_SIZE = 4 + 1 + 4 + 8; + public static final int EVENT_SIZE = 4 + 1 + 4 + 8 + 1; /** * The special character meaning that no @@ -239,6 +239,9 @@ public class Keyboard { /** Has the keyboard been created? */ private static boolean created; + /** Are repeat events enabled? */ + private static boolean repeat_enabled; + /** The keys status from the last poll */ private static final ByteBuffer keyDownBuffer = BufferUtils.createByteBuffer(KEYBOARD_SIZE); @@ -249,17 +252,11 @@ public class Keyboard { */ private static ByteBuffer readBuffer; - /** The current keyboard character being examined */ - private static int eventCharacter; + /** current event */ + private static KeyEvent current_event = new KeyEvent(); - /** The current keyboard event key being examined */ - private static int eventKey; - - /** The current state of the key being examined in the event queue */ - private static boolean eventState; - - /** The current event time */ - private static long eventNanos; + /** scratch event */ + private static KeyEvent tmp_event = new KeyEvent(); /** One time initialization */ private static boolean initialized; @@ -318,9 +315,7 @@ public class Keyboard { readBuffer.limit(0); for (int i = 0; i < keyDownBuffer.remaining(); i++) keyDownBuffer.put(i, (byte)0); - eventCharacter = 0; - eventKey = 0; - eventState = false; + current_event.reset(); } /** @@ -432,7 +427,12 @@ public class Keyboard { synchronized (OpenGLPackageAccess.global_lock) { if (!created) throw new IllegalStateException("Keyboard must be created before you can read events"); - return readBuffer.remaining()/EVENT_SIZE; + int old_position = readBuffer.position(); + int num_events = 0; + while (readNext(tmp_event) && (!tmp_event.repeat || repeat_enabled)) + num_events++; + readBuffer.position(old_position); + return num_events; } } @@ -452,18 +452,47 @@ public class Keyboard { if (!created) throw new IllegalStateException("Keyboard must be created before you can read events"); - if (readBuffer.hasRemaining()) { - eventKey = readBuffer.getInt() & 0xFF; - eventState = readBuffer.get() != 0; - eventCharacter = readBuffer.getInt(); - eventNanos = readBuffer.getLong(); - return true; - } else { - return false; - } + boolean result; + while ((result = readNext(current_event)) && current_event.repeat && !repeat_enabled) + ; + return result; } } + /** + * Controls whether repeat events are reported or not. If repeat events + * are enabled, key down events are reported when a key is pressed and held for + * a OS dependent amount of time. To distinguish a repeat event from a normal event, + * use isRepeatEvent(). + * + * @see org.lwjgl.input.Keyboard#getEventKey() + */ + public static synchronized void enableRepeatEvents(boolean enable) { + repeat_enabled = enable; + } + + /** + * Check whether repeat events are currently reported or not. + * + * @return true is repeat events are reported, false if not. + * @see org.lwjgl.input.Keyboard#getEventKey() + */ + public static synchronized boolean areRepeatEventsEnabled() { + return repeat_enabled; + } + + private static boolean readNext(KeyEvent event) { + if (readBuffer.hasRemaining()) { + event.key = readBuffer.getInt() & 0xFF; + event.state = readBuffer.get() != 0; + event.character = readBuffer.getInt(); + event.nanos = readBuffer.getLong(); + event.repeat = readBuffer.get() == 1; + return true; + } else + return false; + } + /** * @return Number of keys on this keyboard */ @@ -478,7 +507,7 @@ public class Keyboard { */ public static synchronized char getEventCharacter() { synchronized (OpenGLPackageAccess.global_lock) { - return (char)eventCharacter; + return (char)current_event.character; } } @@ -491,7 +520,7 @@ public class Keyboard { */ public static synchronized int getEventKey() { synchronized (OpenGLPackageAccess.global_lock) { - return eventKey; + return current_event.key; } } @@ -503,7 +532,7 @@ public class Keyboard { */ public static synchronized boolean getEventKeyState() { synchronized (OpenGLPackageAccess.global_lock) { - return eventState; + return current_event.state; } } @@ -516,7 +545,42 @@ public class Keyboard { */ public static synchronized long getEventNanoseconds() { synchronized (OpenGLPackageAccess.global_lock) { - return eventNanos; + return current_event.nanos; + } + } + + /** + * @see org.lwjgl.input.Keyboard#enableRepeatEvents() + * @return true if the current event is a repeat event, false if + * the current event is not a repeat even or if repeat events are disabled. + */ + public static synchronized boolean isRepeatEvent() { + synchronized (OpenGLPackageAccess.global_lock) { + return current_event.repeat; + } + } + + private final static class KeyEvent { + /** The current keyboard character being examined */ + private int character; + + /** The current keyboard event key being examined */ + private int key; + + /** The current state of the key being examined in the event queue */ + private boolean state; + + /** The current event time */ + private long nanos; + + /** Is the current event a repeated event? */ + private boolean repeat; + + private void reset() { + character = 0; + key = 0; + state = false; + repeat = false; } } } diff --git a/src/java/org/lwjgl/opengl/KeyboardEventQueue.java b/src/java/org/lwjgl/opengl/KeyboardEventQueue.java index 51251b37..aebed87b 100644 --- a/src/java/org/lwjgl/opengl/KeyboardEventQueue.java +++ b/src/java/org/lwjgl/opengl/KeyboardEventQueue.java @@ -264,9 +264,9 @@ final class KeyboardEventQueue extends EventQueue implements KeyListener { //component.removeKeyListener(this); } - private void putKeyboardEvent(int key_code, byte state, int character, long nanos) { + private void putKeyboardEvent(int key_code, byte state, int character, long nanos, boolean repeat) { event.clear(); - event.putInt(key_code).put(state).putInt(character).putLong(nanos); + event.putInt(key_code).put(state).putInt(character).putLong(nanos).put(repeat ? (byte)1 : (byte)0); event.flip(); putEvent(event); } @@ -287,15 +287,16 @@ final class KeyboardEventQueue extends EventQueue implements KeyListener { if (character == KeyEvent.CHAR_UNDEFINED) character = Keyboard.CHAR_NONE; if (state == 1) { + boolean repeat = false; if (has_deferred_event) { if ((nanos == deferred_nanos && deferred_key_code == key_code && deferred_key_location == key_location)) { has_deferred_event = false; - return; // Ignore repeated key down, key up event pair - } - flushDeferredEvent(); + repeat = true; // Repeat event + } else + flushDeferredEvent(); } - putKeyEvent(key_code, key_location, state, character, nanos); + putKeyEvent(key_code, key_location, state, character, nanos, repeat); } else { flushDeferredEvent(); has_deferred_event = true; @@ -309,19 +310,19 @@ final class KeyboardEventQueue extends EventQueue implements KeyListener { private void flushDeferredEvent() { if (has_deferred_event) { - putKeyEvent(deferred_key_code, deferred_key_location, deferred_key_state, deferred_character, deferred_nanos); + putKeyEvent(deferred_key_code, deferred_key_location, deferred_key_state, deferred_character, deferred_nanos, false); has_deferred_event = false; } } - private void putKeyEvent(int key_code, int key_location, byte state, int character, long nanos) { + private void putKeyEvent(int key_code, int key_location, byte state, int character, long nanos, boolean repeat) { int key_code_mapped = getMappedKeyCode(key_code, key_location); /* Ignore repeating presses */ if ( key_states[key_code_mapped] == state ) - return; + repeat = true; key_states[key_code_mapped] = state; int key_int_char = character & 0xffff; - putKeyboardEvent(key_code_mapped, state, key_int_char, nanos); + putKeyboardEvent(key_code_mapped, state, key_int_char, nanos, repeat); } private int getMappedKeyCode(int key_code, int position) { diff --git a/src/java/org/lwjgl/opengl/LinuxKeyboard.java b/src/java/org/lwjgl/opengl/LinuxKeyboard.java index 4261f3c1..7c760282 100644 --- a/src/java/org/lwjgl/opengl/LinuxKeyboard.java +++ b/src/java/org/lwjgl/opengl/LinuxKeyboard.java @@ -75,7 +75,7 @@ final class LinuxKeyboard { private final CharBuffer char_buffer = CharBuffer.allocate(KEYBOARD_BUFFER_SIZE); // Deferred key released event, to detect key repeat - private boolean has_deferred_event = true; + private boolean has_deferred_event; private int deferred_keycode; private int deferred_event_keycode; private long deferred_nanos; @@ -169,9 +169,9 @@ final class LinuxKeyboard { keyDownBuffer.position(old_position); } - private void putKeyboardEvent(int keycode, byte state, int ch, long nanos) { + private void putKeyboardEvent(int keycode, byte state, int ch, long nanos, boolean repeat) { tmp_event.clear(); - tmp_event.putInt(keycode).put(state).putInt(ch).putLong(nanos); + tmp_event.putInt(keycode).put(state).putInt(ch).putLong(nanos).put(repeat ? (byte)1 : (byte)0); tmp_event.flip(); event_queue.putEvent(tmp_event); } @@ -211,20 +211,20 @@ final class LinuxKeyboard { return lookupStringISO88591(event_ptr, translation_buffer); } - private void translateEvent(long event_ptr, int keycode, byte key_state, long nanos) { + private void translateEvent(long event_ptr, int keycode, byte key_state, long nanos, boolean repeat) { int num_chars, i; int ch; num_chars = lookupString(event_ptr, temp_translation_buffer); if (num_chars > 0) { ch = temp_translation_buffer[0]; - putKeyboardEvent(keycode, key_state, ch, nanos); + putKeyboardEvent(keycode, key_state, ch, nanos, repeat); for (i = 1; i < num_chars; i++) { ch = temp_translation_buffer[i]; - putKeyboardEvent(0, (byte)0, ch, nanos); + putKeyboardEvent(0, (byte)0, ch, nanos, repeat); } } else { - putKeyboardEvent(keycode, key_state, 0, nanos); + putKeyboardEvent(keycode, key_state, 0, nanos, repeat); } } @@ -305,14 +305,15 @@ final class LinuxKeyboard { key_down_buffer[keycode] = key_state; long nanos = millis*1000000; if (event_type == LinuxEvent.KeyPress) { + boolean repeat = false; if (has_deferred_event) { if (nanos == deferred_nanos && event_keycode == deferred_event_keycode) { has_deferred_event = false; - return; // Repeated event, ignore it - } - flushDeferredEvent(); + repeat = true; // Repeated event + } else + flushDeferredEvent(); } - translateEvent(event_ptr, keycode, key_state, nanos); + translateEvent(event_ptr, keycode, key_state, nanos, repeat); } else { flushDeferredEvent(); has_deferred_event = true; @@ -325,7 +326,7 @@ final class LinuxKeyboard { private void flushDeferredEvent() { if (has_deferred_event) { - putKeyboardEvent(deferred_keycode, deferred_key_state, 0, deferred_nanos); + putKeyboardEvent(deferred_keycode, deferred_key_state, 0, deferred_nanos, false); has_deferred_event = false; } } diff --git a/src/java/org/lwjgl/opengl/WindowsDisplay.java b/src/java/org/lwjgl/opengl/WindowsDisplay.java index 7e1d11df..38e3229f 100644 --- a/src/java/org/lwjgl/opengl/WindowsDisplay.java +++ b/src/java/org/lwjgl/opengl/WindowsDisplay.java @@ -608,12 +608,11 @@ final class WindowsDisplay implements DisplayImplementation { private void handleKeyButton(long wParam, long lParam, long millis) { byte previous_state = (byte)((lParam >>> 30) & 0x1); byte state = (byte)(1 - ((lParam >>> 31) & 0x1)); - if (state == previous_state) - return; // Auto-repeat message + boolean repeat = state == previous_state; // Repeat message byte extended = (byte)((lParam >>> 24) & 0x1); int scan_code = (int)((lParam >>> 16) & 0xFF); if (keyboard != null) - keyboard.handleKey((int)wParam, scan_code, extended != 0, state, millis); + keyboard.handleKey((int)wParam, scan_code, extended != 0, state, millis, repeat); } private static int transformY(long hwnd, int y) { diff --git a/src/java/org/lwjgl/opengl/WindowsKeyboard.java b/src/java/org/lwjgl/opengl/WindowsKeyboard.java index e33e2789..c22be229 100644 --- a/src/java/org/lwjgl/opengl/WindowsKeyboard.java +++ b/src/java/org/lwjgl/opengl/WindowsKeyboard.java @@ -63,6 +63,7 @@ final class WindowsKeyboard { private byte retained_state; private int retained_char; private long retained_millis; + private boolean retained_repeat; public WindowsKeyboard(long hwnd) throws LWJGLException { this.hwnd = hwnd; @@ -97,9 +98,9 @@ final class WindowsKeyboard { private static native int GetKeyboardState(ByteBuffer lpKeyState); private static native int GetKeyState(int virt_key); - private void putEvent(int keycode, byte state, int ch, long millis) { + private void putEvent(int keycode, byte state, int ch, long millis, boolean repeat) { tmp_event.clear(); - tmp_event.putInt(keycode).put(state).putInt(ch).putLong(millis*1000000); + tmp_event.putInt(keycode).put(state).putInt(ch).putLong(millis*1000000).put(repeat ? (byte)1 : (byte)0); tmp_event.flip(); event_queue.putEvent(tmp_event); } @@ -144,11 +145,11 @@ final class WindowsKeyboard { private void flushRetained() { if (has_retained_event) { has_retained_event = false; - putEvent(retained_key_code, retained_state, retained_char, retained_millis); + putEvent(retained_key_code, retained_state, retained_char, retained_millis, retained_repeat); } } - public void handleKey(int virt_key, int scan_code, boolean extended, byte event_state, long millis) { + public void handleKey(int virt_key, int scan_code, boolean extended, byte event_state, long millis, boolean repeat) { virt_key = translateExtended(virt_key, scan_code, event_state, extended); flushRetained(); has_retained_event = true; @@ -159,12 +160,13 @@ final class WindowsKeyboard { retained_state = event_state; retained_millis = millis; retained_char = 0; + retained_repeat = repeat; // translate(virt_key, event_state, millis*1000000); } public void handleChar(int event_char, long millis) { if (!has_retained_event) { - putEvent(0, (byte)0, event_char, millis); + putEvent(0, (byte)0, event_char, millis, false); } else retained_char = event_char; } diff --git a/src/java/org/lwjgl/test/input/KeyboardTest.java b/src/java/org/lwjgl/test/input/KeyboardTest.java index 638e8fe2..a4d42245 100644 --- a/src/java/org/lwjgl/test/input/KeyboardTest.java +++ b/src/java/org/lwjgl/test/input/KeyboardTest.java @@ -152,7 +152,11 @@ public class KeyboardTest { System.out.println("Pressed:" + Keyboard.getEventKeyState()); System.out.println("Key character code: " + character_code); System.out.println("Key character: " + Keyboard.getEventCharacter()); + System.out.println("Repeat event: " + Keyboard.isRepeatEvent()); + if (Keyboard.getEventKey() == Keyboard.KEY_R && Keyboard.getEventKeyState()) { + Keyboard.enableRepeatEvents(!Keyboard.areRepeatEventsEnabled()); + } if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) { return; }