1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.input;
33 
34 import java.lang.reflect.Field;
35 import java.lang.reflect.Modifier;
36 import java.nio.ByteBuffer;
37 import java.util.HashMap;
38 import java.util.Map;
39 
40 import org.lwjgl.BufferUtils;
41 import org.lwjgl.LWJGLException;
42 import org.lwjgl.Sys;
43 import org.lwjgl.opengl.Display;
44 import org.lwjgl.opengl.InputImplementation;
45 
46 /**
47  * <br>
48  * A raw Keyboard interface. This can be used to poll the current state of the
49  * keys, or read all the keyboard presses / releases since the last read.
50  *
51  * @author cix_foo <cix_foo@users.sourceforge.net>
52  * @author elias_naur <elias_naur@users.sourceforge.net>
53  * @author Brian Matzon <brian@matzon.dk>
54  * @version $Revision$
55  * $Id$
56  */
57 public class Keyboard {
58 	/** Internal use - event size in bytes */
59 	public static final int EVENT_SIZE = 4 + 1 + 4 + 8 + 1;
60 
61 	/**
62 	 * The special character meaning that no
63 	 * character was translated for the event.
64 	 */
65 	public static final int CHAR_NONE          = '\0';
66 
67 	/**
68 	 * The special keycode meaning that only the
69 	 * translated character is valid.
70 	 */
71 	public static final int KEY_NONE            = 0x00;
72 
73 	public static final int KEY_ESCAPE          = 0x01;
74 	public static final int KEY_1               = 0x02;
75 	public static final int KEY_2               = 0x03;
76 	public static final int KEY_3               = 0x04;
77 	public static final int KEY_4               = 0x05;
78 	public static final int KEY_5               = 0x06;
79 	public static final int KEY_6               = 0x07;
80 	public static final int KEY_7               = 0x08;
81 	public static final int KEY_8               = 0x09;
82 	public static final int KEY_9               = 0x0A;
83 	public static final int KEY_0               = 0x0B;
84 	public static final int KEY_MINUS           = 0x0C; /* - on main keyboard */
85 	public static final int KEY_EQUALS          = 0x0D;
86 	public static final int KEY_BACK            = 0x0E; /* backspace */
87 	public static final int KEY_TAB             = 0x0F;
88 	public static final int KEY_Q               = 0x10;
89 	public static final int KEY_W               = 0x11;
90 	public static final int KEY_E               = 0x12;
91 	public static final int KEY_R               = 0x13;
92 	public static final int KEY_T               = 0x14;
93 	public static final int KEY_Y               = 0x15;
94 	public static final int KEY_U               = 0x16;
95 	public static final int KEY_I               = 0x17;
96 	public static final int KEY_O               = 0x18;
97 	public static final int KEY_P               = 0x19;
98 	public static final int KEY_LBRACKET        = 0x1A;
99 	public static final int KEY_RBRACKET        = 0x1B;
100 	public static final int KEY_RETURN          = 0x1C; /* Enter on main keyboard */
101 	public static final int KEY_LCONTROL        = 0x1D;
102 	public static final int KEY_A               = 0x1E;
103 	public static final int KEY_S               = 0x1F;
104 	public static final int KEY_D               = 0x20;
105 	public static final int KEY_F               = 0x21;
106 	public static final int KEY_G               = 0x22;
107 	public static final int KEY_H               = 0x23;
108 	public static final int KEY_J               = 0x24;
109 	public static final int KEY_K               = 0x25;
110 	public static final int KEY_L               = 0x26;
111 	public static final int KEY_SEMICOLON       = 0x27;
112 	public static final int KEY_APOSTROPHE      = 0x28;
113 	public static final int KEY_GRAVE           = 0x29; /* accent grave */
114 	public static final int KEY_LSHIFT          = 0x2A;
115 	public static final int KEY_BACKSLASH       = 0x2B;
116 	public static final int KEY_Z               = 0x2C;
117 	public static final int KEY_X               = 0x2D;
118 	public static final int KEY_C               = 0x2E;
119 	public static final int KEY_V               = 0x2F;
120 	public static final int KEY_B               = 0x30;
121 	public static final int KEY_N               = 0x31;
122 	public static final int KEY_M               = 0x32;
123 	public static final int KEY_COMMA           = 0x33;
124 	public static final int KEY_PERIOD          = 0x34; /* . on main keyboard */
125 	public static final int KEY_SLASH           = 0x35; /* / on main keyboard */
126 	public static final int KEY_RSHIFT          = 0x36;
127 	public static final int KEY_MULTIPLY        = 0x37; /* * on numeric keypad */
128 	public static final int KEY_LMENU           = 0x38; /* left Alt */
129 	public static final int KEY_SPACE           = 0x39;
130 	public static final int KEY_CAPITAL         = 0x3A;
131 	public static final int KEY_F1              = 0x3B;
132 	public static final int KEY_F2              = 0x3C;
133 	public static final int KEY_F3              = 0x3D;
134 	public static final int KEY_F4              = 0x3E;
135 	public static final int KEY_F5              = 0x3F;
136 	public static final int KEY_F6              = 0x40;
137 	public static final int KEY_F7              = 0x41;
138 	public static final int KEY_F8              = 0x42;
139 	public static final int KEY_F9              = 0x43;
140 	public static final int KEY_F10             = 0x44;
141 	public static final int KEY_NUMLOCK         = 0x45;
142 	public static final int KEY_SCROLL          = 0x46; /* Scroll Lock */
143 	public static final int KEY_NUMPAD7         = 0x47;
144 	public static final int KEY_NUMPAD8         = 0x48;
145 	public static final int KEY_NUMPAD9         = 0x49;
146 	public static final int KEY_SUBTRACT        = 0x4A; /* - on numeric keypad */
147 	public static final int KEY_NUMPAD4         = 0x4B;
148 	public static final int KEY_NUMPAD5         = 0x4C;
149 	public static final int KEY_NUMPAD6         = 0x4D;
150 	public static final int KEY_ADD             = 0x4E; /* + on numeric keypad */
151 	public static final int KEY_NUMPAD1         = 0x4F;
152 	public static final int KEY_NUMPAD2         = 0x50;
153 	public static final int KEY_NUMPAD3         = 0x51;
154 	public static final int KEY_NUMPAD0         = 0x52;
155 	public static final int KEY_DECIMAL         = 0x53; /* . on numeric keypad */
156 	public static final int KEY_F11             = 0x57;
157 	public static final int KEY_F12             = 0x58;
158 	public static final int KEY_F13             = 0x64; /*                     (NEC PC98) */
159 	public static final int KEY_F14             = 0x65; /*                     (NEC PC98) */
160 	public static final int KEY_F15             = 0x66; /*                     (NEC PC98) */
161 	public static final int KEY_F16             = 0x67; /* Extended Function keys - (Mac) */
162 	public static final int KEY_F17             = 0x68;
163 	public static final int KEY_F18             = 0x69;
164 	public static final int KEY_KANA            = 0x70; /* (Japanese keyboard)            */
165 	public static final int KEY_F19             = 0x71; /* Extended Function keys - (Mac) */
166 	public static final int KEY_CONVERT         = 0x79; /* (Japanese keyboard)            */
167 	public static final int KEY_NOCONVERT       = 0x7B; /* (Japanese keyboard)            */
168 	public static final int KEY_YEN             = 0x7D; /* (Japanese keyboard)            */
169 	public static final int KEY_NUMPADEQUALS    = 0x8D; /* = on numeric keypad (NEC PC98) */
170 	public static final int KEY_CIRCUMFLEX      = 0x90; /* (Japanese keyboard)            */
171 	public static final int KEY_AT              = 0x91; /*                     (NEC PC98) */
172 	public static final int KEY_COLON           = 0x92; /*                     (NEC PC98) */
173 	public static final int KEY_UNDERLINE       = 0x93; /*                     (NEC PC98) */
174 	public static final int KEY_KANJI           = 0x94; /* (Japanese keyboard)            */
175 	public static final int KEY_STOP            = 0x95; /*                     (NEC PC98) */
176 	public static final int KEY_AX              = 0x96; /*                     (Japan AX) */
177 	public static final int KEY_UNLABELED       = 0x97; /*                        (J3100) */
178 	public static final int KEY_NUMPADENTER     = 0x9C; /* Enter on numeric keypad */
179 	public static final int KEY_RCONTROL        = 0x9D;
180 	public static final int KEY_SECTION         = 0xA7; /* Section symbol (Mac) */
181 	public static final int KEY_NUMPADCOMMA     = 0xB3; /* , on numeric keypad (NEC PC98) */
182 	public static final int KEY_DIVIDE          = 0xB5; /* / on numeric keypad */
183 	public static final int KEY_SYSRQ           = 0xB7;
184 	public static final int KEY_RMENU           = 0xB8; /* right Alt */
185 	public static final int KEY_FUNCTION        = 0xC4; /* Function (Mac) */
186 	public static final int KEY_PAUSE           = 0xC5; /* Pause */
187 	public static final int KEY_HOME            = 0xC7; /* Home on arrow keypad */
188 	public static final int KEY_UP              = 0xC8; /* UpArrow on arrow keypad */
189 	public static final int KEY_PRIOR           = 0xC9; /* PgUp on arrow keypad */
190 	public static final int KEY_LEFT            = 0xCB; /* LeftArrow on arrow keypad */
191 	public static final int KEY_RIGHT           = 0xCD; /* RightArrow on arrow keypad */
192 	public static final int KEY_END             = 0xCF; /* End on arrow keypad */
193 	public static final int KEY_DOWN            = 0xD0; /* DownArrow on arrow keypad */
194 	public static final int KEY_NEXT            = 0xD1; /* PgDn on arrow keypad */
195 	public static final int KEY_INSERT          = 0xD2; /* Insert on arrow keypad */
196 	public static final int KEY_DELETE          = 0xD3; /* Delete on arrow keypad */
197 	public static final int KEY_CLEAR           = 0xDA; /* Clear key (Mac) */
198 	public static final int KEY_LMETA           = 0xDB; /* Left Windows/Option key */
199 	/**
200 	 * The left windows key, mapped to KEY_LMETA
201 	 *
202 	 * @deprecated Use KEY_LMETA instead
203 	 */
204 	public static final int KEY_LWIN            = KEY_LMETA; /* Left Windows key */
205 	public static final int KEY_RMETA            = 0xDC; /* Right Windows/Option key */
206 	/**
207 	 * The right windows key, mapped to KEY_RMETA
208 	 *
209 	 * @deprecated Use KEY_RMETA instead
210 	 */
211 	public static final int KEY_RWIN            = KEY_RMETA; /* Right Windows key */
212 	public static final int KEY_APPS            = 0xDD; /* AppMenu key */
213 	public static final int KEY_POWER           = 0xDE;
214 	public static final int KEY_SLEEP           = 0xDF;
215 
216 /*	public static final int STATE_ON							= 0;
217 	public static final int STATE_OFF						 = 1;
218 	public static final int STATE_UNKNOWN				 = 2;
219 */
220 	public static final int KEYBOARD_SIZE = 256;
221 
222 	/** Buffer size in events */
223 	private static final int BUFFER_SIZE = 50;
224 
225 	/** Key names */
226 	private static final String[] keyName = new String[KEYBOARD_SIZE];
227 	private static final Map<String, Integer> keyMap = new HashMap<String, Integer>(253);
228 	private static int counter;
229 
230 	static {
231 		// Use reflection to find out key names
232 		Field[] fields = Keyboard.class.getFields();
233 		try {
234 			for ( Field field : fields ) {
235 				if ( Modifier.isStatic(field.getModifiers())
236 				     && Modifier.isPublic(field.getModifiers())
237 				     && Modifier.isFinal(field.getModifiers())
238 				     && field.getType().equals(int.class)
239 				     && field.getName().startsWith("KEY_")
240 				     && !field.getName().endsWith("WIN") ) { /* Don't use deprecated names */
241 
242 					int key = field.getInt(null);
243 					String name = field.getName().substring(4);
244 					keyName[key] = name;
keyMap.put(name, key)245 					keyMap.put(name, key);
246 					counter++;
247 				}
248 
249 			}
250 		} catch (Exception e) {
251 		}
252 
253 	}
254 
255 	/** The number of keys supported */
256 	private static final int keyCount = counter;
257 
258 	/** Has the keyboard been created? */
259 	private static boolean created;
260 
261 	/** Are repeat events enabled? */
262 	private static boolean repeat_enabled;
263 
264 	/** The keys status from the last poll */
265 	private static final ByteBuffer keyDownBuffer = BufferUtils.createByteBuffer(KEYBOARD_SIZE);
266 
267 	/**
268 	 * The key events from the last read: a sequence of pairs of key number,
269 	 * followed by state. The state is followed by
270 	 * a 4 byte code point representing the translated character.
271 	 */
272 	private static ByteBuffer readBuffer;
273 
274 	/** current event */
275 	private static KeyEvent current_event = new KeyEvent();
276 
277 	/** scratch event */
278 	private static KeyEvent tmp_event = new KeyEvent();
279 
280 	/** One time initialization */
281 	private static boolean initialized;
282 
283 	private static InputImplementation implementation;
284 
285 	/**
286 	 * Keyboard cannot be constructed.
287 	 */
Keyboard()288 	private Keyboard() {
289 	}
290 
291 	/**
292 	 * Static initialization
293 	 */
initialize()294 	private static void initialize() {
295 		if (initialized)
296 			return;
297 		Sys.initialize();
298 		initialized = true;
299 	}
300 
301 	/**
302 	 * "Create" the keyboard with the given implementation. This is used
303 	 * reflectively from AWTInputAdapter.
304 	 *
305 	 * @throws LWJGLException if the keyboard could not be created for any reason
306 	 */
create(InputImplementation impl)307 	private static void create(InputImplementation impl) throws LWJGLException {
308 		if (created)
309 			return;
310 		if (!initialized)
311 			initialize();
312 		implementation = impl;
313 		implementation.createKeyboard();
314 		created = true;
315 		readBuffer = ByteBuffer.allocate(EVENT_SIZE*BUFFER_SIZE);
316 		reset();
317 	}
318 
319 	/**
320 	 * "Create" the keyboard. The display must first have been created. The
321 	 * reason for this is so the keyboard has a window to "focus" in.
322 	 *
323 	 * @throws LWJGLException if the keyboard could not be created for any reason
324 	 */
create()325 	public static void create() throws LWJGLException {
326 		synchronized (OpenGLPackageAccess.global_lock) {
327 			if (!Display.isCreated()) throw new IllegalStateException("Display must be created.");
328 
329 			create(OpenGLPackageAccess.createImplementation());
330 		}
331 	}
332 
reset()333 	private static void reset() {
334 		readBuffer.limit(0);
335 		for (int i = 0; i < keyDownBuffer.remaining(); i++)
336 			keyDownBuffer.put(i, (byte)0);
337 		current_event.reset();
338 	}
339 
340 	/**
341 	 * @return true if the keyboard has been created
342 	 */
isCreated()343 	public static boolean isCreated() {
344 		synchronized (OpenGLPackageAccess.global_lock) {
345 			return created;
346 		}
347 	}
348 
349 	/**
350 	 * "Destroy" the keyboard
351 	 */
destroy()352 	public static void destroy() {
353 		synchronized (OpenGLPackageAccess.global_lock) {
354 			if (!created)
355 				return;
356 			created = false;
357 			implementation.destroyKeyboard();
358 			reset();
359 		}
360 	}
361 
362 	/**
363 	 * Polls the keyboard for its current state. Access the polled values using the
364 	 * <code>isKeyDown</code> method.
365 	 * By using this method, it is possible to "miss" keyboard keys if you don't
366 	 * poll fast enough.
367 	 *
368 	 * To use buffered values, you have to call <code>next</code> for each event you
369 	 * want to read. You can query which key caused the event by using
370 	 * <code>getEventKey</code>. To get the state of that key, for that event, use
371 	 * <code>getEventKeyState</code> - finally use <code>getEventCharacter</code> to get the
372 	 * character for that event.
373 	 *
374 	 * NOTE: This method does not query the operating system for new events. To do that,
375 	 * Display.processMessages() (or Display.update()) must be called first.
376 	 *
377 	 * @see org.lwjgl.input.Keyboard#isKeyDown(int key)
378 	 * @see org.lwjgl.input.Keyboard#next()
379 	 * @see org.lwjgl.input.Keyboard#getEventKey()
380 	 * @see org.lwjgl.input.Keyboard#getEventKeyState()
381 	 * @see org.lwjgl.input.Keyboard#getEventCharacter()
382 	 */
poll()383 	public static void poll() {
384 		synchronized (OpenGLPackageAccess.global_lock) {
385 			if (!created)
386 				throw new IllegalStateException("Keyboard must be created before you can poll the device");
387 			implementation.pollKeyboard(keyDownBuffer);
388 			read();
389 		}
390 	}
391 
read()392 	private static void read() {
393 		readBuffer.compact();
394 		implementation.readKeyboard(readBuffer);
395 		readBuffer.flip();
396 	}
397 
398 	/**
399 	 * Checks to see if a key is down.
400 	 * @param key Keycode to check
401 	 * @return true if the key is down according to the last poll()
402 	 */
isKeyDown(int key)403 	public static boolean isKeyDown(int key) {
404 		synchronized (OpenGLPackageAccess.global_lock) {
405 			if (!created)
406 				throw new IllegalStateException("Keyboard must be created before you can query key state");
407 			return keyDownBuffer.get(key) != 0;
408 		}
409 	}
410 
411 	/**
412 	 * Checks whether one of the state keys are "active"
413 	 *
414 	 * @param key State key to test (KEY_CAPITAL | KEY_NUMLOCK | KEY_SYSRQ)
415 	 * @return STATE_ON if on, STATE_OFF if off and STATE_UNKNOWN if the state is unknown
416 	 */
417 /*	public static int isStateKeySet(int key) {
418 		if (!created)
419 			throw new IllegalStateException("Keyboard must be created before you can query key state");
420 		return implementation.isStateKeySet(key);
421 	}
422 */
423 	/**
424 	 * Gets a key's name
425 	 * @param key The key
426 	 * @return a String with the key's human readable name in it or null if the key is unnamed
427 	 */
getKeyName(int key)428 	public static synchronized String getKeyName(int key) {
429 		return keyName[key];
430 	}
431 
432 	/**
433 	 * Get's a key's index. If the key is unrecognised then KEY_NONE is returned.
434 	 * @param keyName The key name
435 	 */
getKeyIndex(String keyName)436 	public static synchronized int getKeyIndex(String keyName) {
437 		Integer ret = keyMap.get(keyName);
438 		if (ret == null)
439 			return KEY_NONE;
440 		else
441 			return ret;
442 	}
443 
444 	/**
445 	 * Gets the number of keyboard events waiting after doing a buffer enabled poll().
446 	 * @return the number of keyboard events
447 	 */
getNumKeyboardEvents()448 	public static int getNumKeyboardEvents() {
449 		synchronized (OpenGLPackageAccess.global_lock) {
450 			if (!created)
451 				throw new IllegalStateException("Keyboard must be created before you can read events");
452 			int old_position = readBuffer.position();
453 			int num_events = 0;
454 			while (readNext(tmp_event) && (!tmp_event.repeat || repeat_enabled))
455 				num_events++;
456 			readBuffer.position(old_position);
457 			return num_events;
458 		}
459 	}
460 
461 	/**
462 	 * Gets the next keyboard event. You can query which key caused the event by using
463 	 * <code>getEventKey</code>. To get the state of that key, for that event, use
464 	 * <code>getEventKeyState</code> - finally use <code>getEventCharacter</code> to get the
465 	 * character for that event.
466 	 *
467 	 * @see org.lwjgl.input.Keyboard#getEventKey()
468 	 * @see org.lwjgl.input.Keyboard#getEventKeyState()
469 	 * @see org.lwjgl.input.Keyboard#getEventCharacter()
470 	 * @return true if a keyboard event was read, false otherwise
471 	 */
next()472 	public static boolean next() {
473 		synchronized (OpenGLPackageAccess.global_lock) {
474 			if (!created)
475 				throw new IllegalStateException("Keyboard must be created before you can read events");
476 
477 			boolean result;
478 			while ((result = readNext(current_event)) && current_event.repeat && !repeat_enabled)
479 				;
480 			return result;
481 		}
482 	}
483 
484 	/**
485      * Controls whether repeat events are reported or not. If repeat events
486 	 * are enabled, key down events are reported when a key is pressed and held for
487 	 * a OS dependent amount of time. To distinguish a repeat event from a normal event,
488 	 * use isRepeatEvent().
489 	 *
490 	 * @see org.lwjgl.input.Keyboard#getEventKey()
491 	 */
enableRepeatEvents(boolean enable)492 	public static void enableRepeatEvents(boolean enable) {
493 		synchronized (OpenGLPackageAccess.global_lock) {
494 			repeat_enabled = enable;
495 		}
496 	}
497 
498 	/**
499      * Check whether repeat events are currently reported or not.
500 	 *
501 	 * @return true is repeat events are reported, false if not.
502 	 * @see org.lwjgl.input.Keyboard#getEventKey()
503 	 */
areRepeatEventsEnabled()504 	public static boolean areRepeatEventsEnabled() {
505 		synchronized (OpenGLPackageAccess.global_lock) {
506 			return repeat_enabled;
507 		}
508 	}
509 
readNext(KeyEvent event)510 	private static boolean readNext(KeyEvent event) {
511 		if (readBuffer.hasRemaining()) {
512 			event.key = readBuffer.getInt() & 0xFF;
513 			event.state = readBuffer.get() != 0;
514 			event.character = readBuffer.getInt();
515 			event.nanos = readBuffer.getLong();
516 			event.repeat = readBuffer.get() == 1;
517 			return true;
518 		} else
519 			return false;
520 	}
521 
522 	/**
523 	 * @return Number of keys on this keyboard
524 	 */
getKeyCount()525 	public static int getKeyCount() {
526 		return keyCount;
527 	}
528 
529 	/**
530 	 * @return The character from the current event
531 	 */
getEventCharacter()532 	public static char getEventCharacter() {
533 		synchronized (OpenGLPackageAccess.global_lock) {
534 			return (char)current_event.character;
535 		}
536 	}
537 
538 	/**
539    * Please note that the key code returned is NOT valid against the
540    * current keyboard layout. To get the actual character pressed call
541    * getEventCharacter
542    *
543 	 * @return The key from the current event
544 	 */
getEventKey()545 	public static int getEventKey() {
546 		synchronized (OpenGLPackageAccess.global_lock) {
547 			return current_event.key;
548 		}
549 	}
550 
551 	/**
552 	 * Gets the state of the key that generated the
553 	 * current event
554 	 *
555 	 * @return True if key was down, or false if released
556 	 */
getEventKeyState()557 	public static boolean getEventKeyState() {
558 		synchronized (OpenGLPackageAccess.global_lock) {
559 			return current_event.state;
560 		}
561 	}
562 
563 	/**
564 	 * Gets the time in nanoseconds of the current event.
565 	 * Only useful for relative comparisons with other
566 	 * Keyboard events, as the absolute time has no defined
567 	 * origin.
568 	 * @return The time in nanoseconds of the current event
569 	 */
getEventNanoseconds()570 	public static long getEventNanoseconds() {
571 		synchronized (OpenGLPackageAccess.global_lock) {
572 			return current_event.nanos;
573 		}
574 	}
575 
576 	/**
577 	 * @see org.lwjgl.input.Keyboard#enableRepeatEvents(boolean)
578 	 * @return true if the current event is a repeat event, false if
579 	 * the current event is not a repeat even or if repeat events are disabled.
580 	 */
isRepeatEvent()581 	public static boolean isRepeatEvent() {
582 		synchronized (OpenGLPackageAccess.global_lock) {
583 			return current_event.repeat;
584 		}
585 	}
586 
587 	private static final class KeyEvent {
588 		/** The current keyboard character being examined */
589 		private int character;
590 
591 		/** The current keyboard event key being examined */
592 		private int key;
593 
594 		/** The current state of the key being examined in the event queue */
595 		private boolean state;
596 
597 		/** The current event time */
598 		private long nanos;
599 
600 		/** Is the current event a repeated event? */
601 		private boolean repeat;
602 
reset()603 		private void reset() {
604 			character = 0;
605 			key = 0;
606 			state = false;
607 			repeat = false;
608 		}
609 	}
610 }
611