summaryrefslogtreecommitdiffstats
path: root/src/newt
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-10-27 02:48:43 +0200
committerSven Gothel <[email protected]>2012-10-27 02:48:43 +0200
commit2f9c77a347b76bebdadd4bec1ac92aa7ab72365f (patch)
treed3280300b69ddb841eaf6f05aeaed1effabe8395 /src/newt
parentb8588b12e65ee47b5a74d75ea420a5252e0d93bb (diff)
Fix Bug 631 and enhance 601: Handle multiple keys (pressed, released, types incl. auto-repeat)
- Using keyCode (bit) maps to isPressed and isAutoRepeat, allowing use of multiple keys - Enhance unit test TestKeyEventOrderNEWT w/ injecting variations of 2 diff. keys - Manual tested on X11, Windows and OSX w/ and w/o auto-repeat
Diffstat (limited to 'src/newt')
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java25
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java100
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java75
3 files changed, 98 insertions, 102 deletions
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 8901411a3..311ed0bbb 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -37,6 +37,7 @@ package jogamp.newt;
import java.util.ArrayList;
import java.lang.reflect.Method;
+import com.jogamp.common.util.IntBitfield;
import com.jogamp.common.util.ReflectionUtil;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Display;
@@ -2169,6 +2170,30 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
//
// KeyListener/Event Support
//
+ protected IntBitfield keyPressedState = new IntBitfield(KeyEvent.VK_CONTEXT_MENU+1);
+ protected IntBitfield keyRepeatState = new IntBitfield(KeyEvent.VK_CONTEXT_MENU+1);
+
+ /**
+ * @param keyCode
+ * @return 1 if pressed, 0 if not pressed, -1 if not handled.
+ */
+ protected final int isKeyPressed(int keyCode) {
+ if( 0 <= keyCode && keyCode < keyPressedState.capacity() ) {
+ return keyPressedState.get(keyCode) ? 1 : 0;
+ }
+ return -1;
+ }
+ /**
+ * @param keyCode
+ * @return 1 if pressed, 0 if not pressed, -1 if not handled.
+ */
+ protected final int isKeyInAutoRepeat(int keyCode) {
+ if( 0 <= keyCode && keyCode < keyRepeatState.capacity() ) {
+ return keyRepeatState.get(keyCode) ? 1 : 0;
+ }
+ return -1;
+ }
+
public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) );
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index 4eeafb244..bcdd6b9df 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -306,74 +306,60 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
} // else may need offscreen solution ? FIXME
}
- @Override
- public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
- // Note that we send the key char for the key code on this
- // platform -- we do not get any useful key codes out of the system
- final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar);
- final boolean valid = validateKeyEvent(eventType, modifiers, keyCode);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)+", valid "+valid);
- if(valid) {
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: OSX delivers only PRESSED
- // inject auto-repeat RELEASE and TYPED keys _before_
- pressedKeyBalance--;
- modifiers |= InputEvent.AUTOREPEAT_MASK;
- super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1); // RELEASED
- super.sendKeyEvent(KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); // TYPED
- }
- // only deliver keyChar on key Typed events, harmonizing platform behavior
- keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1;
- super.sendKeyEvent(eventType, modifiers, keyCode2, keyChar);
+ private final void emitKeyEvent(boolean send, boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
+ if( send ) {
+ super.sendKeyEvent(eventType, modifiers, keyCode, keyChar);
+ } else {
+ super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar);
}
}
-
- @Override
- public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
+
+ private final void handleKeyEvent(boolean send, boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
// Note that we send the key char for the key code on this
// platform -- we do not get any useful key codes out of the system
- final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar);
- final boolean valid = validateKeyEvent(eventType, modifiers, keyCode);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)+", valid "+valid);
- if(valid) {
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: OSX delivers only PRESSED
- // inject auto-repeat RELEASE and TYPED keys _before_
- pressedKeyBalance--;
- modifiers |= InputEvent.AUTOREPEAT_MASK;
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1); // RELEASED
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); // TYPED
- }
- // only deliver keyChar on key Typed events, harmonizing platform behavior
- keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1;
- super.enqueueKeyEvent(wait, eventType, modifiers, keyCode2, keyChar);
+ keyCode = MacKeyUtil.validateKeyCode(keyCode, keyChar);
+ if(DEBUG_IMPLEMENTATION) {
+ System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode));
}
- }
-
- private int keyDownModifiers = 0;
- private int keyDownCode = 0;
- private int pressedKeyBalance = 0;
-
- private boolean validateKeyEvent(int eventType, int modifiers, int keyCode) {
+ // Auto-Repeat: OSX delivers only PRESSED, inject auto-repeat RELEASE and TYPED keys _before_ PRESSED
switch(eventType) {
- case KeyEvent.EVENT_KEY_PRESSED:
- pressedKeyBalance++;
- keyDownModifiers = modifiers;
- keyDownCode = keyCode;
- return true;
case KeyEvent.EVENT_KEY_RELEASED:
- pressedKeyBalance--;
- return keyDownModifiers == modifiers && keyDownCode == keyCode;
+ if( 1 == isKeyInAutoRepeat(keyCode) ) {
+ // AR out
+ keyRepeatState.put(keyCode, false);
+ }
+ keyPressedState.put(keyCode, false);
+ keyChar = (char)-1;
+ break;
+ case KeyEvent.EVENT_KEY_PRESSED:
+ if( 1 == isKeyPressed(keyCode) ) {
+ if( 0 == isKeyInAutoRepeat(keyCode) ) {
+ // AR in
+ keyRepeatState.put(keyCode, true);
+ }
+ modifiers |= InputEvent.AUTOREPEAT_MASK;
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1); // RELEASED
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, keyChar); // TYPED
+ } else {
+ keyPressedState.put(keyCode, true);
+ }
+ keyChar = (char)-1;
+ break;
case KeyEvent.EVENT_KEY_TYPED:
- final boolean matchKeyDown = keyDownModifiers == modifiers && keyDownCode == keyCode;
- keyDownModifiers = 0;
- keyDownCode = 0;
- return matchKeyDown;
- default:
- throw new NativeWindowException("Unexpected key event type " + eventType);
+ break;
}
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ }
+
+ @Override
+ public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
+ handleKeyEvent(true, false, eventType, modifiers, keyCode, keyChar);
}
+ @Override
+ public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
+ handleKeyEvent(false, wait, eventType, modifiers, keyCode, keyChar);
+ }
//----------------------------------------------------------------------
// Internals only
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
index c211bac61..be9f6603e 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
@@ -46,6 +46,7 @@ import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import com.jogamp.common.util.IntIntHashMap;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseAdapter;
@@ -259,29 +260,10 @@ public class WindowDriver extends WindowImpl {
// nop - using event driven insetsChange(..)
}
- private final int validateKeyCode(int eventType, int modifiers, int keyCode, char keyChar) {
- switch(eventType) {
- case KeyEvent.EVENT_KEY_RELEASED:
- pressedKeyBalance--;
- lastPressedKeyCode = keyCode;
- break;
- case KeyEvent.EVENT_KEY_PRESSED:
- pressedKeyBalance++;
- lastPressedKeyCode = keyCode;
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- if(-1==keyCode) {
- keyCode = lastPressedKeyCode;
- }
- lastPressedKeyCode = -1;
- break;
- }
- return keyCode;
- }
+ /** We have to regenerate the keyCode for EVENT_KEY_TYPED on this platform. */
private int lastPressedKeyCode = 0;
- private char lastTypedKeyChar = 0;
- private int pressedKeyBalance = 0;
- private int autoRepeat = 0;
+ /** We have to reorder the native key events to match NEWT's order */
+ private IntIntHashMap typedKeyCode2KeyChar = new IntIntHashMap(KeyEvent.VK_CONTEXT_MENU+1);
private final void emitKeyEvent(boolean send, boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
if( send ) {
@@ -292,47 +274,50 @@ public class WindowDriver extends WindowImpl {
}
private final void handleKeyEvent(boolean send, boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
- // System.err.println("*** handleKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+", mods "+toHexString(modifiers));
-
- // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform
- keyCode = validateKeyCode(eventType, modifiers, keyCode, keyChar);
-
+ // final int kc = 0 <= keyCode ? keyCode : lastPressedKeyCode;
+ // System.err.println("*** handleKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+", key "+toHexString(kc)+", mods "+toHexString(modifiers)+", was: pressed "+isKeyPressed(kc)+", repeat "+isKeyInAutoRepeat(kc));
+
// Reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
- // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
+ // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
switch(eventType) {
case KeyEvent.EVENT_KEY_RELEASED:
- if( 0 != autoRepeat ) {
+ if( 1 == isKeyInAutoRepeat(keyCode) ) {
// AR out - send out missing PRESSED
- emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_PRESSED, modifiers | autoRepeat, keyCode, lastTypedKeyChar);
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_PRESSED, modifiers | InputEvent.AUTOREPEAT_MASK, keyCode, (char)-1);
+ keyRepeatState.put(keyCode, false);
}
- autoRepeat = 0;
- emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
- if( 0 != lastTypedKeyChar ) {
+ keyPressedState.put(keyCode, false);
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ final char lastTypedKeyChar = (char) typedKeyCode2KeyChar.put(keyCode, 0);
+ if( 0 < lastTypedKeyChar ) {
emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, lastTypedKeyChar);
- lastTypedKeyChar = 0;
}
break;
case KeyEvent.EVENT_KEY_PRESSED:
- if( pressedKeyBalance > 1 ) {
- pressedKeyBalance--;
- if ( 0 == autoRepeat ) {
+ lastPressedKeyCode = keyCode;
+ if( 1 == isKeyPressed(keyCode) ) {
+ if( 0 == isKeyInAutoRepeat(keyCode) ) {
// AR in - skip already send PRESSED
- autoRepeat = InputEvent.AUTOREPEAT_MASK;
+ keyRepeatState.put(keyCode, true);
} else {
- emitKeyEvent(send, wait, eventType, modifiers | autoRepeat, keyCode, (char)-1);
+ emitKeyEvent(send, wait, eventType, modifiers | InputEvent.AUTOREPEAT_MASK, keyCode, (char)-1);
}
} else {
- autoRepeat = 0;
+ keyPressedState.put(keyCode, true);
emitKeyEvent(send, wait, eventType, modifiers, keyCode, (char)-1);
}
break;
case KeyEvent.EVENT_KEY_TYPED:
- if( 0 == autoRepeat ) {
- lastTypedKeyChar = keyChar;
- } else {
- modifiers |= autoRepeat;
+ if(-1==keyCode) {
+ keyCode = lastPressedKeyCode;
+ }
+ lastPressedKeyCode = -1;
+ if( 1 == isKeyInAutoRepeat(keyCode) ) {
+ modifiers |= InputEvent.AUTOREPEAT_MASK;
emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
- emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ } else {
+ typedKeyCode2KeyChar.put(keyCode, keyChar);
}
break;
}