On linux, the keyReleased() event is fired, when the user holds a key down, even if the key is not released. This makes it difficult to determine when a key is actually released.On Windows, the keyReleased event is sent only at the end of the keyPressed() / keyTyped() sequence, as documented.

I think it would be good to have a bit of portable code to handle both configurations. Who has already had troubles with this situation?

This apparently has to do with how linux handles repeating keys.. there is already a bug filed (don't feel like searching for the #)... This inconsistency which basically amounts to false information is a major pain in the butt...

@swpalmer,Yes, the bug numbers in Sun Database are 4153069 and 4839127. And Sun does not know how to solve it easily...

@princecCan you confirm that LWJGL handles the sequence of events correctly, on both platforms Windows and linux (the bug is visible on linux; Windows is correct according to the doc). Press and hold a key and look at the KeyEvent generated when the typomatic key-repeat runs.

On Windows you get:pressedtypedpressedtypedpressedtypedpressedtypedpressedtypedreleased

On linux, you get:pressedtypedreleasedpressedtypedreleasedpressedtypedreleasedpressedtypedreleasedpressedtypedreleased

In LWJGL however there's one subtle difference - the keyboard repeat rate is off. That's a consequence of DirectInput on win32 and the disabling of the key repeat on linux (the only solution at hand). So it might not be the best solution after all, if you need the repeat rate of the OS.

I don't think the repeating need do anything special for two keys.. if it wants to repeat only one or none it would make no difference to me.. so long as there is only ONE pressed and ONE released that happen only when the key or keys are actually pressed and released. Wether or not you get multiple key typed events is usually not relevant for games.

Perhaps ignoring the OS repeat and handling it internally with a timer is a better way to go? (When you say it is turned off for Linux in LWJGL does that affect the whole system or just the LWJGL window?) If the repeat rate can be queried from the OS then that seems like a good solution.

As a start, here is some code to filter the surnumerous KeyReleased events under linux.

The ONE advantage:- It's portable code using JDK 1.1.8 API.

The disadvantages:- It creates on thread by KeyListener it manages.- The filtering is based on a delay. If no more event is received during a delay, then the KeyReleased must be the last of the sequence and is sent to the KeyListener. If the delay is chosen too big, there is a lag before the last event is sent; if too short, some KeyReleased events can escape the filter...- The choice of the delay depends on the platform. 100 ms seems to be OK on the Zaurus, but creates problems when accessing it remotely with VNC.

TODO:- Define exactly what we need (in another post) for cross-platform key processing.- Support dumb keys like [Shift] which repeat under Windows but don't under linux.- Put the delay in a system property, or at least in a parameter of the constructor...

/** * When the <code>KeyHandler</code> is garbage collected, the companion * thread is no more necessary and can stop running. */protectedvoidfinalize()throwsThrowable {// KeyEventThread can kill itself now _thread.stopHandler(); }

/** * The delay we have to wait to accept a <code>KeyReleased</code> * event. */finalprivatelong _delay;

/** * Constructor of the KeyHandler thread. * * @param delay The delay while no new event must be received before * we accept a <code>KeyReleased</code> event. */KeyHandlerThread(finallongdelay) {super("KeyHandlerThread");setDaemon(true); _delay = delay; _handleKeys = true; }

/** * The key event queue processing loop. */publicvoidrun() {while (_handleKeys) {synchronized (this) {try {// Sleep only if no more events to processif (_events.size() == 0) {wait(); } }catch (InterruptedExceptionie) {// A new key should be available in the queue... }

if (_events.size() > 0) {// Time to wake up: a key has been detectedKeyEventevent = (KeyEvent) _events.removeElement();

if (event.getID() == KeyEvent.KEY_RELEASED) {// We have to wait for next key to determine what to dotry {wait(_delay); }catch (InterruptedExceptionie2) {// Could be a new key in the queue or delay expired. }

// There is another key waiting in the queueif (_events.size() > 0) {KeyEventevent2 = (KeyEvent) _events.removeElement();// If it's a KeyPressed on the same key...if (event2.getID() == KeyEvent.KEY_PRESSED && event.getKeyChar() == event2.getKeyChar()) {// We can drop the KeyReleased eventdispatchKeyEvent(event2); }else {// Both events (KeyReleased + other) must be re-sentdispatchKeyEvent(event);dispatchKeyEvent(event2); } }else {// No new event after the KeyReleased (we are there// because the delay expired), we send the KeyReleaseddispatchKeyEvent(event); } }else {// Non filtered eventdispatchKeyEvent(event); } } } } }

/** * Add the given element to this queue. * * @param object the element to be added. * @exception QueueFullException the queue cannot be expanded * this only occurs when the machine is nearly out * of memory. */publicvoidaddElement(finalObjectobject) {synchronized (_content) {if (_size == _content.length) {expandFullQueue(); }

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org