LWJGL Forum

Archive => Resolved Bugs/RFE => Topic started by: Mytrill on April 02, 2012, 14:38:00

Title: [FIXED] Keyboard.isKeyDown() returns false true
Post by: Mytrill on April 02, 2012, 14:38:00
Hi,

I am working on a project using LWJGL and I ran across a bug when pulling input keyboards inputs (it probably does the same with the mouse inputs, I haven't checked yet.)

He is a short demo of the bug:


import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

public class DemoBugLWJGL {

public void start() {
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}

boolean running = true;

while (!Display.isCloseRequested() && running) {
pollInput();

if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
running = false;
}

if(Keyboard.isKeyDown(Keyboard.KEY_A)) {
System.out.println("key A down");
}

try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}

Display.update();
}

Display.destroy();
}

public void pollInput() {
while(Mouse.next()) {
// do stuff
}

while (Keyboard.next()) {
// do stuff
}
}

public static void main(String[] argv) {
DemoBugLWJGL inputExample = new DemoBugLWJGL();
inputExample.start();
}
}


This code is almost the same as the Input tutorial in the wiki.

When the user press the A key, the message is displayed in the console.
The bug occurs if the user changes the main windows (with alt-tab or just by clicking outside of the lwjgl windows) while pressing the key and then releases the key.
The message keeps being displayed even if the key has been released (that is normal because the jwjgl windows cannot access the input
once not on focus).
The problem is when the focus is gained back by the display, the method Keyboard.isKeyDown(Keyboard.KEY_A) keeps returning true.

I ran across the method Keyboard.reset(), but this method is private, maybe calling this method when the display loses/get the focus can fix this bug.

Thanks for your time,
Mytrill.

EDIT: I work with the last version of LWJGL, and my OS is Windows 7 pro 32bit, if that is relevant to the problem^^
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: l3eta on May 14, 2012, 00:15:27
Seeing how I ran into this just a few mins ago, I tried to find a fix and didn't find one so I created my own.. It's not very clean (As in the way it's done is awful) but it works.

The Util class I use.

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;

public class MiscUtil {
private static boolean destroyed = false;
public static void keyboardReset() {
if(!destroyed) {
Keyboard.destroy();
try {
Keyboard.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
destroyed = true;
}
}

public static void resetKeyboardDestroy() {
destroyed = false;
}
}


Now to actually make it do what it's supposed to do.


public void doInputUpdate() {
if(!Display.isActive()) {
MiscUtil.keyboardReset();
return;
}
MiscUtil.resetKeyboardDestroy();
//TODO add all of your keyboard input code here.
}


Figured I'd share my little fix for those who run into this and need to fix it.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: Matzon on May 14, 2012, 06:33:34
not sure what the fix is here ... do we nuke all key states when alt-tab occurs? - what about other input? - is it a win7 only issue?
anyone else seeing this on non-win7?
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: l3eta on May 14, 2012, 07:14:26
Majority, I think there should be a void for us to remove all key events or certain keys. And I'm on Windows 7 so I couldn't really tell you.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: kappa on May 14, 2012, 10:13:57
I think this is a cross platform issue as I've seen it on Linux too. Often known as the sticky key problem since once the Display window loses focus it has no way to read key input and doesn't update the internal key down buffer. When the Display window gets focus again you get the keys that were down before focus was lost reporting themselves as being permanently down (until pressed again).

A simple solution (as mentioned above) would be something like calling Keyboard.reset() internally once the Display window loses focus.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: Simon Felix on May 14, 2012, 18:41:08
But just resetting the Keyboard on focus loss won't result in KeyUp-events, correct? Our game relies on getting KeyUp events. IMHO a proper fix would work like this:

1. Wait for focus loss
2. Add KeyUp events to the event buffer for all keys that are currently down
3. Reset keyboard (while keeping the event buffer)


#2 is missing from the original fix. Other thoughts?
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: l3eta on May 14, 2012, 18:50:55
I would guess it would not result in keyUpEvents.
So yes that is how a proper fix would work but all there really needs to be is a void that allows us to either set a key up or clear all down keys (Set them all to up)
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on May 14, 2012, 22:59:04
Ok so after talking with kappa, MatthiasM, and l3eta on IRC, it seems like the general consensus for the fix is to simply nuke all pressed keys once focus is lost.

I wrote a patch for this (http://www.ra4king.com/public/Keyboard.java.patch), however please revise since this isn't tested (I can't get LWJGL to build properly :'()

I was finally able to test it on Windows, it seems that it doesn't fully fix it. The original patch nuked the keys when the focus was lost, but as soon as focus was regained, isKeyDown returned true again even if the key was not pressed anymore.

I traced it down to each platform-specific Keyboard class. The fix was to reset the byte array in WindowsKeyboard, LinuxKeyboard, and KeyboardEventQueue. This patch works on Windows, could someone using Linux and Mac test it?

The patch. (http://www.ra4king.com/public/Patch.patch)
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: l3eta on May 15, 2012, 22:03:22
Windows Title bar bug fix of this also

NOTE: This only fixes the Windows problem, Linux and Mac will have to be handled differently most likely.

http://pastebin.com/6sGAikSH -- Windows Keyboard
http://pastebin.com/PDh5Qbjs -- Windows Display
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on May 16, 2012, 01:37:43
How do you know Linux and Mac aren't fixed? The Windows Keyboard link is my patch, and the Windows Display link doesn't work ;)
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on May 16, 2012, 07:29:13
Ok I just tested my patch under Ubuntu and Linux Mint and it works, so I'm assuming it would work fine for Macs too.

Also, thanks to l3eta, there was another keyboard bug when dragging the window. The original patch link (http://www.ra4king.com/public/Patch.patch) still works as I have uploaded a new version.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on May 21, 2012, 13:44:18
Any updates on this? I tried the patch on some more Linux flavors and things work fine.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: JoeK5142 on August 06, 2012, 01:09:21
ra4king, I've run across the same isKeyDown() issue, and I'm not sure how to use the sh.exe tool to patch the original class files.  Could you point me in the right direction?  I'm on Windows Vista 32-bit.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on August 06, 2012, 02:15:38
No clue. The patch is mostly for the devs. If you want to apply it, look up how to apply SVN patches.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: princec on August 06, 2012, 08:47:33
Just wait for a nighty in which the patch has been incorporated for you is easiest.

Cas :)
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: Matzon on August 06, 2012, 09:32:09
patch hasn't been applied... - and thats a good thing, imo.

The call to WindowsKeyboard.nukeDownKeys(); on all WM_MOVE and WM_WINDOWPOSCHANGING seems extremely excessive?
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on August 06, 2012, 19:04:55
Yeah this patch hasn't been incorporated yet. KappaOne told me this needed more testing, even the only change is in Java and this mostly affects Windows. However, I have tested it on Windows and Linux and it works :)

EDIT: @Matzon, nukeDownKeys only nukes the keys once, all further calls are ignored until the keys are set again.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: aldacron on August 07, 2012, 12:29:22
The proper solution to this (on Windows) has to be implemented on the native side. When a mouse button is pressed, the Win32 API function SetCapture (http://msdn.microsoft.com/en-us/library/ms646262%28VS.85%29.aspx) should be called. This guarantees that the window will continue receiving mouse button events even when the mouse is outside the window and does not block other windows from getting those same events. Then, when a button up event is received, ReleaseCapture (http://msdn.microsoft.com/en-us/library/ms646261(v=vs.85).aspx) should be called. Using this approach will allow LWJGL's internal mouse button state to remain consistent and not interfere with other programs.

There are likely alternatives for the other OSes, if it is an issue there. The GLFW library (https://github.com/elmindreda/glfw) uses this approach on Windows and AFAIK behaves consistently across its supported platforms.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: NateS on August 16, 2012, 17:09:33
Just want to throw in my "me too!". A fix for this would be great. Every once in a while switching to/from my app, the ctrl key gets stuck down. This is a modifier in my app and its very confusing for a moment. The repro is simply: press ctrl, lose window focus, release ctrl, focus window. It then sees ctrl down until pressed again.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: NateS on August 23, 2012, 07:41:20
I've been spending a lot of time using my desktop tools. I curse this issue every single day! :-[
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: spasi on August 23, 2012, 10:53:16
I committed a fix for this on Windows, please test the next nightly build.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: kappa on August 23, 2012, 13:00:56
Quote from: spasi on August 23, 2012, 10:53:16
I committed a fix for this on Windows, please test the next nightly build.
Nice job.

Just curious, WindowsKeyboard.fireLostKeyEvents() is called every frame, we might be able to get away with only calling it on focus change (i.e. when WindowsDisplay.appActive(boolean) method is called). Not sure if it'll have any practical effect on performance but if it works it should reduce a number of jni calls each frame.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: spasi on August 23, 2012, 14:00:38
It's only called on appActive(true).
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: kappa on August 23, 2012, 14:02:31
Quote from: spasi on August 23, 2012, 14:00:38
It's only called on appActive(true).
Ah cool, guess I read code wrong, sorry.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: ra4king on August 23, 2012, 21:33:15
The new commit isn't showing up on CIA, but it is on SourceForge.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: NateS on August 28, 2012, 05:37:17
Quote from: spasi on August 23, 2012, 10:53:16
I committed a fix for this on Windows, please test the next nightly build.
Sorry for the delay. With the nightly #1782, I start my app and ctrl is correctly not reported as pressed. After pressing and releasing ctrl, ctrl is incorrectly reported as still being pressed. Subsequent presses of ctrl do not remedy the problem. Ctrl is reported and being pressed until I focus a different application and then return to my app.

TLDR; clearing the button states seems to work, but normal usage is now broken.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: spasi on August 28, 2012, 09:06:48
Thanks, fixed on next nightly.
Title: Re: [BUG] Keyboard.isKeyDown() returns false true
Post by: NateS on December 03, 2012, 23:30:21
I've got a bug report from a Linux user where if they use ctrl+alt+arrow to switch desktops, when they switch back the ctrl key is reported as down until it is pressed again.
Title: Re: [FIXED] Keyboard.isKeyDown() returns false true
Post by: NateS on September 30, 2014, 21:44:21
Sorry to bring this up again, but it is still an problem on Linux. Eg, if I alt+tab from my app to another, when I come back to my app it still sees the alt key as being down.
Title: Re: [FIXED] Keyboard.isKeyDown() returns false true
Post by: spasi on October 01, 2014, 18:15:49
This should be fixed now. I ended up copying GLFW's approach; LWJGL will now create virtual key up events for all keys that were pressed when the window loses focus. If a key is pressed before regaining focus (or it was never released), normally you'd get a stream of repeat events (if enabled) after the window activation. The trick is to handle the first of those repeat events as a normal key down event. So, it'll go like this:

key down -> repeat down -> ... -> repeat down -> focus lost -> key up

then after gaining focus:

focus gained -> key down -> repeat down -> ...

On Windows, it works perfectly and is actually a cleaner solution than the previous workaround.

On Linux, it works just as great, except for modifier keys. Linux apparently does not send repeat events for those. It still works better than before though, if the user never releases the modifier between the focus events, they'll just have to release and press again. The app will only receive the virtual up when focus was lost, not the real one after focus was gained.
Title: Re: [FIXED] Keyboard.isKeyDown() returns false true
Post by: NateS on October 01, 2014, 18:28:09
Neat solution. 8) Thanks for the fix Spasi! I will test it out soon.
Title: Re: [FIXED] Keyboard.isKeyDown() returns false true
Post by: ra4king on October 03, 2014, 02:22:41
Wow, excellent fix! Nice job Spasi.