[BUG] "special key" collisions handled badly/inconsistently

Started by ouattwtym, October 29, 2011, 21:06:24

Previous topic - Next topic

ouattwtym

1
If L/RMENU, L/RCONTROL is pressed then release events from the opposite key are ignored (but press events are not).

2
If LSHIFT is pressed then all events from RSHIFT are ignored.

3
Strangest of all: if RSHIFT is pressed then all events from LSHIFT are ignored except that if there is an LSHIFT pressed event while RSHIFT is pressed then when you release RSHIFT you get an LSHIFT(!) released event. e.g.

Actual:

Press RSHIFT
Press LSHIFT
Release LSHIFT
Release RSHIFT

Reported:

Press RSHIFT
Release LSHIFT

Tested on lwjgl2.7.1 and lwjgl2.8.1 on Windows7.
Two different physical keyboards used to be safe.


ouattwtym

The above report was about inconsistency in
Keyboard.getEventKey()
Keyboard.getEventKeyState()

I just noticed there is a Keyboard.isKeyDown(key) method. I was hoping that would be correct and read the special keys correctly but it also gets confused :(

Here is my test code:

package sandbox.lwjgl.demos;

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

public class KeyboardTest {
	private static int WINDOW_WIDTH = 640;

	private static int WINDOW_HEIGHT = 640;

	private void initialize() {
		DisplayMode dm = new DisplayMode(WINDOW_WIDTH, WINDOW_HEIGHT);
		try {
			Display.setDisplayMode(dm);
			Display.setVSyncEnabled(true);
			Display.create();
		}
		catch (LWJGLException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Executes the actual test
	 */
	public void executeTest() {
		initialize();

		runTest();

		Display.destroy();
	}

	/**
	 * Runs the test
	 */
	private void runTest() {
		// while not exiting
		boolean active = true;
		for (;;) {
			Display.update();
			if (Display.isCloseRequested()) break;

			if (Display.isActive()) {
				if (!active) {
					active = true;
				}
			}
			else {
				active = false;
			}

			// poll and check keyboard and mouse
			handleKeyboard();

			pause(100);
			Thread.yield();
		}
	}

	/**
	 * Pauses the current thread for a specified time
	 * 
	 * @param time
	 *            milliseconds to pause
	 */
	private static void pause(long time) {
		try {
			Thread.sleep(time);
		}
		catch (InterruptedException inte) {
			inte.printStackTrace();
		}
	}

	/**
	 * Handles the keyboard
	 */
	private void handleKeyboard() {
		while (Keyboard.next()) {
			int keyCode = Keyboard.getEventKey();
			boolean down = Keyboard.getEventKeyState();
			System.out.println(String.format("Received : %s %s", down ? "Press  " : "Release", Keyboard.getKeyName(keyCode)));

			StringBuffer b = new StringBuffer();
			int keys[] = { Keyboard.KEY_LSHIFT, Keyboard.KEY_RSHIFT };
			for (int key: keys) {
				if (b.length()!=0) b.append(", ");
				b.append(String.format("%s %s", Keyboard.getKeyName(key), Keyboard.isKeyDown(key) ? "Down" : "Up  "));
			}
			System.out.println("Now      : "+b);
		}
	}

	/**
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String[] args) {
		KeyboardTest mt = new KeyboardTest();
		mt.executeTest();
		System.exit(0);
	}
}


If you run it and then press down both shift keys (in either order) then release them both then, after that,  isKeyDown() will report Keyboard.KEY_RSHIFT
as being stuck down. This will continue (giving the impression other keys are being pressed with shift) until you press and release RSHIFT again.
Doing that my test code outputs:

Received : Press   LSHIFT
Now      : LSHIFT Down, RSHIFT Up  
Received : Release LSHIFT
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   O
Now      : LSHIFT Up  , RSHIFT Down
Received : Release O
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   H
Now      : LSHIFT Up  , RSHIFT Down
Received : Release H
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   N
Now      : LSHIFT Up  , RSHIFT Down
Received : Release N
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   O
Now      : LSHIFT Up  , RSHIFT Down
Received : Release O
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   LSHIFT
Now      : LSHIFT Down, RSHIFT Down
Received : Release LSHIFT
Now      : LSHIFT Up  , RSHIFT Down
Received : Press   RSHIFT
Now      : LSHIFT Up  , RSHIFT Down
Received : Release RSHIFT
Now      : LSHIFT Up  , RSHIFT Up  
Received : Press   O
Now      : LSHIFT Up  , RSHIFT Up  
Received : Release O
Now      : LSHIFT Up  , RSHIFT Up  
Received : Press   K
Now      : LSHIFT Up  , RSHIFT Up  
Received : Release K
Now      : LSHIFT Up  , RSHIFT Up 


i.e. Keyboard.isKeyDown() is not a reliable way to find if RSHIFT is down
There isn't currently any reliable way to track the left&right special keys individually.

Workaround:
I think the best that can be done is to ignore Keyboard.isKeyDown(). Use Keyboard.getEventKey() and merge
KEY_Lxxx and KEY_Rxxx events. Then the state of a given special key KEY_xxx
(e.g. KEY_SHIFT) can be tracked accurately but at the cost of having discarded the left and right information.