[FIXED] Keyboard.isKeyDown() returns false true

Started by Mytrill, April 02, 2012, 14:38:00

Previous topic - Next topic

Mytrill

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^^

l3eta

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.

Matzon

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?

l3eta

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.

kappa

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.

Simon Felix

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?
Download Cultris II, the fastest Tetris clone from http://gewaltig.net/

l3eta

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)

ra4king

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, 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.
-Roi

l3eta

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

ra4king

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 ;)
-Roi

ra4king

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 still works as I have uploaded a new version.
-Roi

ra4king

Any updates on this? I tried the patch on some more Linux flavors and things work fine.
-Roi

JoeK5142

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.

ra4king

No clue. The patch is mostly for the devs. If you want to apply it, look up how to apply SVN patches.
-Roi

princec

Just wait for a nighty in which the patch has been incorporated for you is easiest.

Cas :)