aboutsummaryrefslogtreecommitdiffstats
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
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
-rwxr-xr-xmake/scripts/tests-x64.bat1
-rwxr-xr-xmake/scripts/tests.sh5
-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
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java22
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/TestKeyPressReleaseUnmaskRepeatNEWT.java222
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java8
8 files changed, 350 insertions, 108 deletions
diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat
index f67bda373..21e303dc2 100755
--- a/make/scripts/tests-x64.bat
+++ b/make/scripts/tests-x64.bat
@@ -34,6 +34,7 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestParenting01
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestListenerCom01AWT
scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestKeyEventOrderNEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestKeyEventAutoRepeatNEWT %*
+REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestKeyPressReleaseUnmaskRepeatNEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT %*
REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01bAWT %*
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 047c0ed63..734fa671f 100755
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -375,8 +375,9 @@ function testawtswt() {
#testawt com.jogamp.opengl.test.junit.newt.TestEventSourceNotAWTBug
#testawt com.jogamp.opengl.test.junit.newt.TestFocus01SwingAWTRobot $*
#testawt com.jogamp.opengl.test.junit.newt.TestFocus02SwingAWTRobot $*
-#testawt com.jogamp.opengl.test.junit.newt.TestKeyEventOrderNEWT $*
-testawt com.jogamp.opengl.test.junit.newt.TestKeyEventAutoRepeatNEWT $*
+testawt com.jogamp.opengl.test.junit.newt.TestKeyEventOrderNEWT $*
+#testawt com.jogamp.opengl.test.junit.newt.TestKeyEventAutoRepeatNEWT $*
+#testawt com.jogamp.opengl.test.junit.newt.TestKeyPressReleaseUnmaskRepeatNEWT $*
#testawt com.jogamp.opengl.test.junit.newt.TestListenerCom01AWT
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01aAWT $*
#testawt com.jogamp.opengl.test.junit.newt.parenting.TestParenting01bAWT $*
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;
}
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java
index e0c3005a2..31d9912d1 100644
--- a/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java
@@ -141,17 +141,33 @@ public class TestKeyEventOrderNEWT extends UITestCase {
System.err.println("KEY Event Order Test: "+loops);
keyAdapter.reset();
for(int i=0; i<loops; i++) {
+ // 1
AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_A, 10);
- robot.waitForIdle();
AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_A, 100);
robot.waitForIdle();
+ // 2
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_B, 10);
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_B, 100);
+ robot.waitForIdle();
+ // 3 + 4
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_A, 10);
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_B, 10);
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_A, 10);
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_B, 10);
+ robot.waitForIdle();
+ // 5 + 6
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_A, 10);
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_B, 10);
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_B, 10);
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_A, 10);
+ robot.waitForIdle();
}
robot.delay(250);
// dumpKeyEvents(keyAdapter.getQueued());
NEWTKeyUtil.validateKeyEventOrder(keyAdapter.getQueued());
- NEWTKeyUtil.validateKeyAdapterStats(keyAdapter, loops, 0);
+ NEWTKeyUtil.validateKeyAdapterStats(keyAdapter, 6*loops, 0);
}
void testImpl(GLWindow glWindow) throws AWTException, InterruptedException, InvocationTargetException {
@@ -182,7 +198,7 @@ public class TestKeyEventOrderNEWT extends UITestCase {
//
// Test the key event order w/o auto-repeat
//
- testKeyEventOrder(robot, glWindow1KA, 12);
+ testKeyEventOrder(robot, glWindow1KA, 6);
// Remove listeners to avoid logging during dispose/destroy.
glWindow.removeKeyListener(glWindow1KA);
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestKeyPressReleaseUnmaskRepeatNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyPressReleaseUnmaskRepeatNEWT.java
new file mode 100644
index 000000000..6f3b97f0c
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyPressReleaseUnmaskRepeatNEWT.java
@@ -0,0 +1,222 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.newt;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Before;
+
+import java.awt.AWTException;
+import java.awt.BorderLayout;
+import java.awt.Robot;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.swing.JFrame;
+
+import java.io.IOException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.newt.awt.NewtCanvasAWT;
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2;
+
+import com.jogamp.opengl.test.junit.util.*;
+
+/**
+ * Testing key press and release events w/o AUTO-REPEAT
+ */
+public class TestKeyPressReleaseUnmaskRepeatNEWT extends UITestCase {
+ static int width, height;
+ static long durationPerTest = 100;
+ static long awtWaitTimeout = 1000;
+
+ static GLCapabilities glCaps;
+
+ @BeforeClass
+ public static void initClass() {
+ width = 640;
+ height = 480;
+ glCaps = new GLCapabilities(null);
+ }
+
+ @AfterClass
+ public static void release() {
+ }
+
+ @Before
+ public void initTest() {
+ }
+
+ @After
+ public void releaseTest() {
+ }
+
+ @Test
+ public void test01NEWT() throws AWTException, InterruptedException, InvocationTargetException {
+ GLWindow glWindow = GLWindow.create(glCaps);
+ glWindow.setSize(width, height);
+ glWindow.setVisible(true);
+
+ testImpl(glWindow);
+
+ glWindow.destroy();
+ }
+
+ // @Test
+ public void test02NewtCanvasAWT() throws AWTException, InterruptedException, InvocationTargetException {
+ GLWindow glWindow = GLWindow.create(glCaps);
+
+ // Wrap the window in a canvas.
+ final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow);
+
+ // Add the canvas to a frame, and make it all visible.
+ final JFrame frame1 = new JFrame("Swing AWT Parent Frame: "+ glWindow.getTitle());
+ frame1.getContentPane().add(newtCanvasAWT, BorderLayout.CENTER);
+ frame1.setSize(width, height);
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame1.setVisible(true);
+ } } );
+
+ Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame1, true));
+
+ testImpl(glWindow);
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame1.setVisible(false);
+ frame1.dispose();
+ }});
+ } catch( Throwable throwable ) {
+ throwable.printStackTrace();
+ Assume.assumeNoException( throwable );
+ }
+ glWindow.destroy();
+ }
+
+ void testImpl(GLWindow glWindow) throws AWTException, InterruptedException, InvocationTargetException {
+ final Robot robot = new Robot();
+ robot.setAutoWaitForIdle(true);
+
+ GLEventListener demo1 = new RedSquareES2();
+ TestListenerCom01AWT.setDemoFields(demo1, glWindow, false);
+ glWindow.addGLEventListener(demo1);
+
+ SimpleKeyPressRelease simpleKeyPressRelease = new SimpleKeyPressRelease();
+ glWindow.addKeyListener(simpleKeyPressRelease);
+
+ Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glWindow, true));
+ AWTRobotUtil.clearAWTFocus(robot);
+
+ // Continuous animation ..
+ Animator animator = new Animator(glWindow);
+ animator.start();
+
+ Thread.sleep(durationPerTest); // manual testing
+
+ AWTRobotUtil.assertRequestFocusAndWait(null, glWindow, glWindow, null, null); // programmatic
+ // AWTRobotUtil.assertRequestFocusAndWait(robot, glWindow, glWindow, null, null); // by mouse click
+
+ // Remove listeners to avoid logging during dispose/destroy.
+ glWindow.removeKeyListener(simpleKeyPressRelease);
+
+ // Shutdown the test.
+ animator.stop();
+ }
+
+ static int atoi(String a) {
+ int i=0;
+ try {
+ i = Integer.parseInt(a);
+ } catch (Exception ex) { ex.printStackTrace(); }
+ return i;
+ }
+
+ static class SimpleKeyPressRelease implements KeyListener {
+ int seq;
+
+ SimpleKeyPressRelease() {
+ reset();
+ }
+
+ public void reset() {
+ seq=0;
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if( 0 == ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) ) {
+ seq++;
+ System.err.println(seq+": "+e);
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if( 0 == ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) ) {
+ seq++;
+ System.err.println(seq+": "+e);
+ }
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ }
+
+ }
+
+ public static void main(String args[]) throws IOException {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-time")) {
+ durationPerTest = atoi(args[++i]);
+ }
+ }
+ /**
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+ System.err.println("Press enter to continue");
+ System.err.println(stdin.readLine());
+ */
+ System.out.println("durationPerTest: "+durationPerTest);
+ String tstname = TestKeyPressReleaseUnmaskRepeatNEWT.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java
index dfc96edcb..299ea3a6e 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java
@@ -32,6 +32,7 @@ import java.util.List;
import org.junit.Assert;
+import com.jogamp.common.util.IntIntHashMap;
import com.jogamp.newt.event.KeyEvent;
public class NEWTKeyUtil {
@@ -56,12 +57,17 @@ public class NEWTKeyUtil {
}
public static void validateKeyEventOrder(List<EventObject> keyEvents) {
- int eet = KeyEvent.EVENT_KEY_PRESSED;
+ IntIntHashMap keyCode2NextEvent = new IntIntHashMap();
for(int i=0; i<keyEvents.size(); i++) {
final KeyEvent e = (KeyEvent) keyEvents.get(i);
+ int eet = keyCode2NextEvent.get(e.getKeyCode());
+ if( 0 >= eet ) {
+ eet = KeyEvent.EVENT_KEY_PRESSED;
+ }
final int et = e.getEventType();
Assert.assertEquals("Key event not in proper order", eet, et);
eet = getNextKeyEventType(et);
+ keyCode2NextEvent.put(e.getKeyCode(), eet);
}
}