From 0a7877eea817cdc9fb50bf30ece3703898bb38ad Mon Sep 17 00:00:00 2001
From: Duy Tran Khanh <40482367+khanhduytran0@users.noreply.github.com>
Date: Sat, 23 Jan 2021 19:55:17 +0700
Subject: [PATCH] Update Keyboard.java
---
.../main/java/org/lwjgl/input/Keyboard.java | 459 ++++++++++++++----
1 file changed, 366 insertions(+), 93 deletions(-)
diff --git a/JavaApp/src/main/java/org/lwjgl/input/Keyboard.java b/JavaApp/src/main/java/org/lwjgl/input/Keyboard.java
index 5b2b57c0..e384244c 100644
--- a/JavaApp/src/main/java/org/lwjgl/input/Keyboard.java
+++ b/JavaApp/src/main/java/org/lwjgl/input/Keyboard.java
@@ -1,17 +1,63 @@
+/*
+ * Copyright (c) 2002-2008 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
package org.lwjgl.input;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
-import org.lwjgl.glfw.GLFW;
+import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.InputImplementation;
+/**
+ *
+ * A raw Keyboard interface. This can be used to poll the current state of the
+ * keys, or read all the keyboard presses / releases since the last read.
+ *
+ * @author cix_foo
+ * @author elias_naur
+ * @author Brian Matzon
+ * @version $Revision$
+ * $Id$
+ */
public class Keyboard {
-
+ /** Internal use - event size in bytes */
+ public static final int EVENT_SIZE = 4 + 1 + 4 + 8 + 1;
+
/**
* The special character meaning that no
* character was translated for the event.
@@ -150,47 +196,54 @@ public class Keyboard {
public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */
public static final int KEY_CLEAR = 0xDA; /* Clear key (Mac) */
public static final int KEY_LMETA = 0xDB; /* Left Windows/Option key */
+ /**
+ * The left windows key, mapped to KEY_LMETA
+ *
+ * @deprecated Use KEY_LMETA instead
+ */
public static final int KEY_LWIN = KEY_LMETA; /* Left Windows key */
public static final int KEY_RMETA = 0xDC; /* Right Windows/Option key */
+ /**
+ * The right windows key, mapped to KEY_RMETA
+ *
+ * @deprecated Use KEY_RMETA instead
+ */
public static final int KEY_RWIN = KEY_RMETA; /* Right Windows key */
public static final int KEY_APPS = 0xDD; /* AppMenu key */
public static final int KEY_POWER = 0xDE;
public static final int KEY_SLEEP = 0xDF;
- private static EventQueue queue = new EventQueue(32);
- // private static int maxEvents = 32;
-
- // private static int eventCount = 0;
- // private static int currentEventPos = -1;
- // private static int nextEventPos = 0;
-
- private static int[] keyEvents = new int[queue.getMaxEvents()];
- private static boolean[] keyEventStates = new boolean[queue.getMaxEvents()];
- private static long[] nanoTimeEvents = new long[queue.getMaxEvents()];
- private static char[] keyEventChars = new char[256];
-
- private static boolean repeatEvents = false;
- private static int latestEventKey = 0;
-
+ /* public static final int STATE_ON = 0;
+ public static final int STATE_OFF = 1;
+ public static final int STATE_UNKNOWN = 2;
+ */
public static final int KEYBOARD_SIZE = 256;
+ /** Buffer size in events */
+ private static final int BUFFER_SIZE = 50;
+
+ /** Key names */
private static final String[] keyName = new String[KEYBOARD_SIZE];
private static final Map keyMap = new HashMap(253);
+ private static int counter;
static {
// Use reflection to find out key names
Field[] fields = Keyboard.class.getFields();
try {
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())
- && Modifier.isFinal(field.getModifiers()) && field.getType().equals(int.class)
- && field.getName().startsWith("KEY_") && !field.getName().endsWith(
- "WIN")) { /* Don't use deprecated names */
+ for ( Field field : fields ) {
+ if ( Modifier.isStatic(field.getModifiers())
+ && Modifier.isPublic(field.getModifiers())
+ && Modifier.isFinal(field.getModifiers())
+ && field.getType().equals(int.class)
+ && field.getName().startsWith("KEY_")
+ && !field.getName().endsWith("WIN") ) { /* Don't use deprecated names */
int key = field.getInt(null);
String name = field.getName().substring(4);
keyName[key] = name;
keyMap.put(name, key);
+ counter++;
}
}
@@ -199,99 +252,178 @@ public class Keyboard {
}
- public static void addKeyEvent(int key, int status) {
- // eventCount++;
- // if (eventCount > maxEvents) eventCount = maxEvents;
+ /** The number of keys supported */
+ private static final int keyCount = counter;
- switch (status) {
- case GLFW.GLFW_REPEAT:
- if (!repeatEvents)
- break;
- case GLFW.GLFW_RELEASE:
- case GLFW.GLFW_PRESS:
- keyEvents[queue.getNextPos()] = KeyCodes.toLwjglKey(key);
- keyEventStates[queue.getNextPos()] = status == GLFW.GLFW_PRESS || status == GLFW.GLFW_REPEAT;
+ /** Has the keyboard been created? */
+ private static boolean created;
- nanoTimeEvents[queue.getNextPos()] = Sys.getNanoTime();
+ /** Are repeat events enabled? */
+ private static boolean repeat_enabled;
- queue.add();
- }
- /*
- * nextEventPos++; if (nextEventPos == maxEvents) nextEventPos = 0;
- *
- * if (currentEventPos == nextEventPos) currentEventPos++; if
- * (currentEventPos == maxEvents) currentEventPos = 0;
- */
+ /** The keys status from the last poll */
+ private static final ByteBuffer keyDownBuffer = BufferUtils.createByteBuffer(KEYBOARD_SIZE);
+
+ /**
+ * The key events from the last read: a sequence of pairs of key number,
+ * followed by state. The state is followed by
+ * a 4 byte code point representing the translated character.
+ */
+ private static ByteBuffer readBuffer;
+
+ /** current event */
+ private static KeyEvent current_event = new KeyEvent();
+
+ /** scratch event */
+ private static KeyEvent tmp_event = new KeyEvent();
+
+ /** One time initialization */
+ private static boolean initialized;
+
+ private static InputImplementation implementation;
+
+ /**
+ * Keyboard cannot be constructed.
+ */
+ private Keyboard() {
}
- public static void addCharEvent(int key, char c) {
- int index = KeyCodes.toLwjglKey(key);
- keyEventChars[index] = c;
+ /**
+ * Static initialization
+ */
+ private static void initialize() {
+ if (initialized)
+ return;
+ Sys.initialize();
+ initialized = true;
}
- public static boolean areRepeatEventsEnabled() {
- return false;
- }
+ /**
+ * "Create" the keyboard with the given implementation. This is used
+ * reflectively from AWTInputAdapter.
+ *
+ * @throws LWJGLException if the keyboard could not be created for any reason
+ */
+ private static void create(InputImplementation impl) throws LWJGLException {
+ if (created)
+ return;
+ if (!initialized)
+ initialize();
+ implementation = impl;
+ implementation.createKeyboard();
+ created = true;
+ readBuffer = ByteBuffer.allocate(EVENT_SIZE*BUFFER_SIZE);
+ reset();
+ }
+ /**
+ * "Create" the keyboard. The display must first have been created. The
+ * reason for this is so the keyboard has a window to "focus" in.
+ *
+ * @throws LWJGLException if the keyboard could not be created for any reason
+ */
public static void create() throws LWJGLException {
+ if (!Display.isCreated()) throw new IllegalStateException("Display must be created.");
+ create((InputImplementation) GLFWInputImplementation.singleton);
}
- public static boolean isKeyDown(int key) {
- int k = GLFW.glfwGetKey(Display.getWindow(), KeyCodes.toGlfwKey(key));
-
- return k == GLFW.GLFW_PRESS || k == GLFW.GLFW_REPEAT;
+ private static void reset() {
+ readBuffer.limit(0);
+ for (int i = 0; i < keyDownBuffer.remaining(); i++)
+ keyDownBuffer.put(i, (byte)0);
+ current_event.reset();
}
+ /**
+ * @return true if the keyboard has been created
+ */
+ public static boolean isCreated() {
+ return created;
+ }
+
+ /**
+ * "Destroy" the keyboard
+ */
+ public static void destroy() {
+ if (!created)
+ return;
+ created = false;
+ implementation.destroyKeyboard();
+ reset();
+ }
+
+ /**
+ * Polls the keyboard for its current state. Access the polled values using the
+ * isKeyDown method.
+ * By using this method, it is possible to "miss" keyboard keys if you don't
+ * poll fast enough.
+ *
+ * To use buffered values, you have to call next for each event you
+ * want to read. You can query which key caused the event by using
+ * getEventKey. To get the state of that key, for that event, use
+ * getEventKeyState - finally use getEventCharacter to get the
+ * character for that event.
+ *
+ * NOTE: This method does not query the operating system for new events. To do that,
+ * Display.processMessages() (or Display.update()) must be called first.
+ *
+ * @see org.lwjgl.input.Keyboard#isKeyDown(int key)
+ * @see org.lwjgl.input.Keyboard#next()
+ * @see org.lwjgl.input.Keyboard#getEventKey()
+ * @see org.lwjgl.input.Keyboard#getEventKeyState()
+ * @see org.lwjgl.input.Keyboard#getEventCharacter()
+ */
public static void poll() {
- // TODO
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can poll the device");
+ implementation.pollKeyboard(keyDownBuffer);
+ read();
}
- public static void enableRepeatEvents(boolean enable) {
- // TODO
- // System.out.println("TODO: Implement
- // Keyboad.enableRepeatEvents(boolean)");
- repeatEvents = enable;
+ private static void read() {
+ readBuffer.compact();
+ implementation.readKeyboard(readBuffer);
+ readBuffer.flip();
}
- public static boolean isRepeatEvent() {
- // TODO
- return repeatEvents;
+ /**
+ * Checks to see if a key is down.
+ * @param key Keycode to check
+ * @return true if the key is down according to the last poll()
+ */
+ public static boolean isKeyDown(int key) {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can query key state");
+ return keyDownBuffer.get(key) != 0;
}
- public static boolean next() {
- return queue.next();
- /*
- * if (eventCount == 0) return false;
- *
- * eventCount--; currentEventPos++; if (currentEventPos == maxEvents)
- * currentEventPos = 0;
- *
- * return true;
- */
+ /**
+ * Checks whether one of the state keys are "active"
+ *
+ * @param key State key to test (KEY_CAPITAL | KEY_NUMLOCK | KEY_SYSRQ)
+ * @return STATE_ON if on, STATE_OFF if off and STATE_UNKNOWN if the state is unknown
+ */
+/* public static int isStateKeySet(int key) {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can query key state");
+ return implementation.isStateKeySet(key);
}
-
- public static int getEventKey() {
- return keyEvents[queue.getCurrentPos()];
- }
-
- public static char getEventCharacter() {
- return keyEventChars[getEventKey()];
- }
-
- public static boolean getEventKeyState() {
- return keyEventStates[queue.getCurrentPos()];
- }
-
- public static long getEventNanoseconds() {
- return nanoTimeEvents[queue.getCurrentPos()];
- }
-
- public static String getKeyName(int key) {
+*/
+ /**
+ * Gets a key's name
+ * @param key The key
+ * @return a String with the key's human readable name in it or null if the key is unnamed
+ */
+ public static synchronized String getKeyName(int key) {
return keyName[key];
}
- public static int getKeyIndex(java.lang.String keyName) {
+ /**
+ * Get's a key's index. If the key is unrecognised then KEY_NONE is returned.
+ * @param keyName The key name
+ */
+ public static synchronized int getKeyIndex(String keyName) {
Integer ret = keyMap.get(keyName);
if (ret == null)
return KEY_NONE;
@@ -299,11 +431,152 @@ public class Keyboard {
return ret;
}
- public static boolean isCreated() {
- return Display.isCreated();
+ /**
+ * Gets the number of keyboard events waiting after doing a buffer enabled poll().
+ * @return the number of keyboard events
+ */
+ public static int getNumKeyboardEvents() {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can read events");
+ 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;
}
- public static void destroy() {
+ /**
+ * Gets the next keyboard event. You can query which key caused the event by using
+ * getEventKey. To get the state of that key, for that event, use
+ * getEventKeyState - finally use getEventCharacter to get the
+ * character for that event.
+ *
+ * @see org.lwjgl.input.Keyboard#getEventKey()
+ * @see org.lwjgl.input.Keyboard#getEventKeyState()
+ * @see org.lwjgl.input.Keyboard#getEventCharacter()
+ * @return true if a keyboard event was read, false otherwise
+ */
+ public static boolean next() {
+ if (!created)
+ throw new IllegalStateException("Keyboard must be created before you can read events");
+ 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 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 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
+ */
+ public static int getKeyCount() {
+ return keyCount;
+ }
+
+ /**
+ * @return The character from the current event
+ */
+ public static char getEventCharacter() {
+ return (char)current_event.character;
+ }
+
+ /**
+ * Please note that the key code returned is NOT valid against the
+ * current keyboard layout. To get the actual character pressed call
+ * getEventCharacter
+ *
+ * @return The key from the current event
+ */
+ public static int getEventKey() {
+ return current_event.key;
+ }
+
+ /**
+ * Gets the state of the key that generated the
+ * current event
+ *
+ * @return True if key was down, or false if released
+ */
+ public static boolean getEventKeyState() {
+ return current_event.state;
+ }
+
+ /**
+ * Gets the time in nanoseconds of the current event.
+ * Only useful for relative comparisons with other
+ * Keyboard events, as the absolute time has no defined
+ * origin.
+ * @return The time in nanoseconds of the current event
+ */
+ public static long getEventNanoseconds() {
+ return current_event.nanos;
+ }
+
+ /**
+ * @see org.lwjgl.input.Keyboard#enableRepeatEvents(boolean)
+ * @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 boolean isRepeatEvent() {
+ return current_event.repeat;
+ }
+
+ private static final 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;
+ }
}
}