aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-10-26 16:43:13 +0200
committerSven Gothel <[email protected]>2012-10-26 16:43:13 +0200
commitb008de41549e38aebdfcb7b094046235a8dde72f (patch)
tree4e51584207f22bd7203d1cc64bdab25e7a171eae /src
parent4f05d5add18048c2fbd1837c0563446c11177e8c (diff)
Fix Bug 601 - Auto-Repeat Behavior: Adding unit tests for typed key order w/ and w/o auto repeat. Incl. fix for Windows.
Auto-Repeat tests recognizes whether auto-repeat could be triggered by AWT Robot. The latter is not possible on Windows, hence manual testing was required on this platform. Impact: X11, Windows and OSX produce proper key sequence incl. auto-repeat modifier mask.
Diffstat (limited to 'src')
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyEvent.java11
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEvent.java6
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java82
-rw-r--r--src/newt/native/X11Display.c2
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventAutoRepeatNEWT.java309
-rw-r--r--src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java219
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTFocusAdapter.java11
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTKeyAdapter.java49
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTMouseAdapter.java27
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java51
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java11
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/EventCountAdapter.java9
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/InputEventCountAdapter.java5
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/KeyEventCountAdapter.java38
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/NEWTFocusAdapter.java11
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/NEWTKeyAdapter.java64
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java103
-rw-r--r--src/test/com/jogamp/opengl/test/junit/util/NEWTMouseAdapter.java28
18 files changed, 969 insertions, 67 deletions
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
index 7daaeada6..b6f4264f5 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
@@ -48,6 +48,17 @@ package com.jogamp.newt.event;
* Besides regular modifiers like {@link InputEvent#SHIFT_MASK} etc.,
* the {@link InputEvent#AUTOREPEAT_MASK} bit is added if repetition is detected.
* </p>
+ * <p>
+ * Auto-Repeat shall behave as follow:
+ * <pre>
+ D = pressed, U = released, T = typed
+ 0 = normal, 1 = auto-repeat
+
+ D(0), [ U(1), T(1), D(1), U(1) T(1) ..], U(0) T(0)
+ * </pre>
+ * The idea is if you mask out auto-repeat in your event listener
+ * you just get one long pressed key D/U/T triple.
+ * </p>
*/
@SuppressWarnings("serial")
public class KeyEvent extends InputEvent
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
index fd5b69ccc..9d8d92ff6 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
@@ -161,11 +161,7 @@ public class NEWTEvent extends java.util.EventObject {
return sb.append("NEWTEvent[sys:").append(isSystemEvent()).append(", source:").append(getSource().getClass().getName()).append(", when:").append(getWhen()).append(" d ").append((System.currentTimeMillis()-getWhen())).append("ms]");
}
- public static String toHexString(int hex) {
+ static String toHexString(int hex) {
return "0x" + Integer.toHexString(hex);
}
-
- public static String toHexString(long hex) {
- return "0x" + Long.toHexString(hex);
- }
}
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
index 71437c461..c211bac61 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
@@ -279,61 +279,73 @@ public class WindowDriver extends WindowImpl {
return keyCode;
}
private int lastPressedKeyCode = 0;
+ private char lastTypedKeyChar = 0;
private int pressedKeyBalance = 0;
private int autoRepeat = 0;
- @Override
- public void sendKeyEvent(int eventType, int modifiers, int keyCode, char 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);
+ }
+ }
+
+ 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);
+
+ // Reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
+ // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
switch(eventType) {
case KeyEvent.EVENT_KEY_RELEASED:
- // reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
+ if( 0 != autoRepeat ) {
+ // AR out - send out missing PRESSED
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_PRESSED, modifiers | autoRepeat, keyCode, lastTypedKeyChar);
+ }
+ autoRepeat = 0;
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ if( 0 != lastTypedKeyChar ) {
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_TYPED, modifiers, keyCode, lastTypedKeyChar);
+ lastTypedKeyChar = 0;
+ }
break;
case KeyEvent.EVENT_KEY_PRESSED:
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
- // Since reordering already injects RELEASE, we only need to set the AUTOREPEAT_MASK.
+ if( pressedKeyBalance > 1 ) {
pressedKeyBalance--;
- autoRepeat |= InputEvent.AUTOREPEAT_MASK;
+ if ( 0 == autoRepeat ) {
+ // AR in - skip already send PRESSED
+ autoRepeat = InputEvent.AUTOREPEAT_MASK;
+ } else {
+ emitKeyEvent(send, wait, eventType, modifiers | autoRepeat, keyCode, (char)-1);
+ }
} else {
- autoRepeat &= ~InputEvent.AUTOREPEAT_MASK;
+ autoRepeat = 0;
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, (char)-1);
}
- super.sendKeyEvent(eventType, modifiers | autoRepeat, keyCode, (char)-1);
break;
case KeyEvent.EVENT_KEY_TYPED:
- modifiers |= autoRepeat;
- super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
- super.sendKeyEvent(eventType, modifiers, keyCode, keyChar);
+ if( 0 == autoRepeat ) {
+ lastTypedKeyChar = keyChar;
+ } else {
+ modifiers |= autoRepeat;
+ emitKeyEvent(send, wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
+ emitKeyEvent(send, wait, eventType, modifiers, keyCode, keyChar);
+ }
break;
}
}
@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) {
- // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform
- keyCode = validateKeyCode(eventType, modifiers, keyCode, keyChar);
- switch(eventType) {
- case KeyEvent.EVENT_KEY_RELEASED:
- // reorder: WINDOWS delivery order is PRESSED, TYPED and RELEASED -> NEWT order: PRESSED, RELEASED and TYPED
- break;
- case KeyEvent.EVENT_KEY_PRESSED:
- if(pressedKeyBalance > 1) {
- // Auto-Repeat: WINDOWS delivers only PRESSED and TYPED.
- // Since reordering already injects RELEASE, we only need to set the AUTOREPEAT_MASK.
- pressedKeyBalance--;
- autoRepeat |= InputEvent.AUTOREPEAT_MASK;
- } else {
- autoRepeat &= ~InputEvent.AUTOREPEAT_MASK;
- }
- super.enqueueKeyEvent(wait, eventType, modifiers | autoRepeat, keyCode, (char)-1);
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- modifiers |= autoRepeat;
- super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, (char)-1);
- super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar);
- break;
- }
+ handleKeyEvent(false, wait, eventType, modifiers, keyCode, keyChar);
}
//----------------------------------------------------------------------
diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c
index d8202fcde..9f29acc0c 100644
--- a/src/newt/native/X11Display.c
+++ b/src/newt/native/X11Display.c
@@ -381,6 +381,8 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage
} else {
autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK;
}
+ } else {
+ autoRepeatModifiers &= ~EVENT_AUTOREPEAT_MASK;
}
// fall through intended
case KeyPress:
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventAutoRepeatNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventAutoRepeatNEWT.java
new file mode 100644
index 000000000..22c362dd8
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventAutoRepeatNEWT.java
@@ -0,0 +1,309 @@
+/**
+ * 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 java.util.Arrays;
+import java.util.EventObject;
+import java.util.List;
+
+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.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 event order incl. auto-repeat (Bug 601)
+ *
+ * <p>
+ * Note Event order:
+ * <ol>
+ * <li>{@link #EVENT_KEY_PRESSED}</li>
+ * <li>{@link #EVENT_KEY_RELEASED}</li>
+ * <li>{@link #EVENT_KEY_TYPED}</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Auto-Repeat shall behave as follow:
+ * <pre>
+ D = pressed, U = released, T = typed
+ 0 = normal, 1 = auto-repeat
+
+ D(0), [ U(1), T(1), D(1), U(1) T(1) ..], U(0) T(0)
+ * </pre>
+ *
+ * The idea is if you mask out auto-repeat in your event listener
+ * you just get one long pressed key D/U/T triple.
+ */
+public class TestKeyEventAutoRepeatNEWT 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();
+ }
+
+ static void testKeyEventAutoRepeat(Robot robot, NEWTKeyAdapter keyAdapter, int loops, int pressDurationMS) {
+ System.err.println("KEY Event Auto-Repeat Test: "+loops);
+ EventObject[][] first = new EventObject[loops][3];
+ EventObject[][] last = new EventObject[loops][3];
+
+ keyAdapter.reset();
+ final List<EventObject> keyEvents = keyAdapter.getQueued();
+ int firstIdx = 0;
+ for(int i=0; i<loops; i++) {
+ System.err.println("+++ KEY Event Auto-Repeat START Input Loop: "+i);
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_A, pressDurationMS);
+ robot.waitForIdle();
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_A, 1000); // 1s .. no AR anymore
+ robot.waitForIdle();
+ first[i][0] = (KeyEvent) keyEvents.get(firstIdx+0);
+ first[i][1] = (KeyEvent) keyEvents.get(firstIdx+1);
+ first[i][2] = (KeyEvent) keyEvents.get(firstIdx+2);
+ firstIdx = keyEvents.size() - 3;
+ last[i][0] = (KeyEvent) keyEvents.get(firstIdx+0);
+ last[i][1] = (KeyEvent) keyEvents.get(firstIdx+1);
+ last[i][2] = (KeyEvent) keyEvents.get(firstIdx+2);
+ System.err.println("+++ KEY Event Auto-Repeat END Input Loop: "+i);
+
+ // add a pair of normal press/release in between auto-repeat!
+ AWTRobotUtil.keyPress(0, robot, true, java.awt.event.KeyEvent.VK_B, 10);
+ robot.waitForIdle();
+ AWTRobotUtil.keyPress(0, robot, false, java.awt.event.KeyEvent.VK_B, 250);
+ robot.waitForIdle();
+ firstIdx = keyEvents.size();
+ }
+ // dumpKeyEvents(keyEvents);
+
+ NEWTKeyUtil.validateKeyEventOrder(keyEvents);
+
+ final boolean hasAR = 0 < keyAdapter.getKeyPressedCount(true) ;
+
+ Assert.assertEquals("Key event count not multiple of 3", 0, keyEvents.size()%3);
+ final int expTotal = keyEvents.size()/3;
+ final int expAR = hasAR ? expTotal - loops - loops : 0;
+ NEWTKeyUtil.validateKeyAdapterStats(keyAdapter, expTotal, expAR);
+
+ if( !hasAR ) {
+ System.err.println("No AUTO-REPEAT triggered by AWT Robot .. aborting test analysis");
+ return;
+ }
+
+ for(int i=0; i<loops; i++) {
+ System.err.println("Auto-Repeat Loop "+i+" - Head:");
+ NEWTKeyUtil.dumpKeyEvents(Arrays.asList(first[i]));
+ System.err.println("Auto-Repeat Loop "+i+" - Tail:");
+ NEWTKeyUtil.dumpKeyEvents(Arrays.asList(last[i]));
+ }
+ for(int i=0; i<loops; i++) {
+ KeyEvent e = (KeyEvent) first[i][0];
+ Assert.assertTrue("1st Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("1st Shall be PRESSED, but is "+e, KeyEvent.EVENT_KEY_PRESSED == e.getEventType() );
+ Assert.assertTrue("1st Shall not be AR, but is "+e, 0 == ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+
+ e = (KeyEvent) first[i][1];
+ Assert.assertTrue("2nd Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("2nd Shall be RELEASED, but is "+e, KeyEvent.EVENT_KEY_RELEASED == e.getEventType() );
+ Assert.assertTrue("2nd Shall be AR, but is "+e, 0 != ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+
+ e = (KeyEvent) first[i][2];
+ Assert.assertTrue("3rd Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("3rd Shall be TYPED, but is "+e, KeyEvent.EVENT_KEY_TYPED == e.getEventType() );
+ Assert.assertTrue("3rd Shall be AR, but is "+e, 0 != ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+
+ e = (KeyEvent) last[i][0];
+ Assert.assertTrue("last-2 Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("last-2 Shall be PRESSED, but is "+e, KeyEvent.EVENT_KEY_PRESSED == e.getEventType() );
+ Assert.assertTrue("last-2 Shall be AR, but is "+e, 0 != ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+
+ e = (KeyEvent) last[i][1];
+ Assert.assertTrue("last-1 Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("last-1 Shall be RELEASED, but is "+e, KeyEvent.EVENT_KEY_RELEASED == e.getEventType() );
+ Assert.assertTrue("last-1 Shall not be AR, but is "+e, 0 == ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+
+ e = (KeyEvent) last[i][2];
+ Assert.assertTrue("last-0 Shall be A, but is "+e, KeyEvent.VK_A == e.getKeyCode() );
+ Assert.assertTrue("last-0 Shall be TYPED, but is "+e, KeyEvent.EVENT_KEY_TYPED == e.getEventType() );
+ Assert.assertTrue("last-0 Shall not be AR, but is "+e, 0 == ( InputEvent.AUTOREPEAT_MASK & e.getModifiers() ) );
+ }
+ }
+
+ 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);
+
+ NEWTKeyAdapter glWindow1KA = new NEWTKeyAdapter("GLWindow1");
+ glWindow1KA.setVerbose(false);
+ glWindow.addKeyListener(glWindow1KA);
+
+ Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glWindow, true));
+ AWTRobotUtil.clearAWTFocus(robot);
+
+ // Continuous animation ..
+ Animator animator = new Animator(glWindow);
+ animator.start();
+
+ Thread.sleep(durationPerTest); // manual testing
+
+ glWindow1KA.reset();
+ AWTRobotUtil.assertRequestFocusAndWait(null, glWindow, glWindow, null, null); // programmatic
+ // AWTRobotUtil.assertRequestFocusAndWait(robot, glWindow, glWindow, null, null); // by mouse click
+
+ //
+ // Test the key event order w/ auto-repeat
+ //
+ final int origAutoDelay = robot.getAutoDelay();
+ robot.setAutoDelay(10);
+ try {
+ testKeyEventAutoRepeat(robot, glWindow1KA, 3, 1000);
+ } finally {
+ robot.setAutoDelay(origAutoDelay);
+ }
+
+ // Remove listeners to avoid logging during dispose/destroy.
+ glWindow.removeKeyListener(glWindow1KA);
+
+ // 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;
+ }
+
+ 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 = TestKeyEventAutoRepeatNEWT.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java
new file mode 100644
index 000000000..e0c3005a2
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/newt/TestKeyEventOrderNEWT.java
@@ -0,0 +1,219 @@
+/**
+ * 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.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 event order incl. auto-repeat (Bug 601)
+ *
+ * <p>
+ * Note Event order:
+ * <ol>
+ * <li>{@link #EVENT_KEY_PRESSED}</li>
+ * <li>{@link #EVENT_KEY_RELEASED}</li>
+ * <li>{@link #EVENT_KEY_TYPED}</li>
+ * </ol>
+ * </p>
+ */
+public class TestKeyEventOrderNEWT 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();
+ }
+
+ static void testKeyEventOrder(Robot robot, NEWTKeyAdapter keyAdapter, int loops) {
+ System.err.println("KEY Event Order Test: "+loops);
+ keyAdapter.reset();
+ for(int i=0; i<loops; i++) {
+ 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();
+ }
+ robot.delay(250);
+ // dumpKeyEvents(keyAdapter.getQueued());
+
+ NEWTKeyUtil.validateKeyEventOrder(keyAdapter.getQueued());
+
+ NEWTKeyUtil.validateKeyAdapterStats(keyAdapter, loops, 0);
+ }
+
+ 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);
+
+ NEWTKeyAdapter glWindow1KA = new NEWTKeyAdapter("GLWindow1");
+ glWindow1KA.setVerbose(false);
+ glWindow.addKeyListener(glWindow1KA);
+
+ Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glWindow, true));
+ AWTRobotUtil.clearAWTFocus(robot);
+
+ // Continuous animation ..
+ Animator animator = new Animator(glWindow);
+ animator.start();
+
+ Thread.sleep(durationPerTest); // manual testing
+
+ glWindow1KA.reset();
+ AWTRobotUtil.assertRequestFocusAndWait(null, glWindow, glWindow, null, null); // programmatic
+ // AWTRobotUtil.assertRequestFocusAndWait(robot, glWindow, glWindow, null, null); // by mouse click
+
+ //
+ // Test the key event order w/o auto-repeat
+ //
+ testKeyEventOrder(robot, glWindow1KA, 12);
+
+ // Remove listeners to avoid logging during dispose/destroy.
+ glWindow.removeKeyListener(glWindow1KA);
+
+ // 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;
+ }
+
+ 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 = TestKeyEventOrderNEWT.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTFocusAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTFocusAdapter.java
index fe0f2acc0..32ff6022c 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTFocusAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTFocusAdapter.java
@@ -36,12 +36,15 @@ public class AWTFocusAdapter implements FocusEventCountAdapter, FocusListener {
String prefix;
int focusCount;
boolean wasTemporary;
+ boolean verbose = true;
public AWTFocusAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean focusLost() {
return focusCount<0;
}
@@ -65,7 +68,9 @@ public class AWTFocusAdapter implements FocusEventCountAdapter, FocusListener {
if(focusCount<0) { focusCount=0; }
focusCount++;
wasTemporary = e.isTemporary();
- System.err.println("FOCUS AWT GAINED "+(wasTemporary?"TEMP":"PERM")+" [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS AWT GAINED "+(wasTemporary?"TEMP":"PERM")+" [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
/* @Override */
@@ -73,7 +78,9 @@ public class AWTFocusAdapter implements FocusEventCountAdapter, FocusListener {
if(focusCount>0) { focusCount=0; }
focusCount--;
wasTemporary = e.isTemporary();
- System.err.println("FOCUS AWT LOST "+(wasTemporary?"TEMP":"PERM")+" [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS AWT LOST "+(wasTemporary?"TEMP":"PERM")+" [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[focusCount "+focusCount +", temp "+wasTemporary+"]"; }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTKeyAdapter.java
index 6c0156170..a9fa373b5 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTKeyAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTKeyAdapter.java
@@ -29,18 +29,25 @@
package com.jogamp.opengl.test.junit.util;
import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
-public class AWTKeyAdapter extends java.awt.event.KeyAdapter implements InputEventCountAdapter {
+public class AWTKeyAdapter extends java.awt.event.KeyAdapter implements KeyEventCountAdapter {
String prefix;
- int keyTyped;
+ int keyPressed, keyReleased, keyTyped;
boolean pressed;
+ List<EventObject> queue = new ArrayList<EventObject>();
+ boolean verbose = true;
public AWTKeyAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean isPressed() {
return pressed;
}
@@ -49,24 +56,54 @@ public class AWTKeyAdapter extends java.awt.event.KeyAdapter implements InputEve
return keyTyped;
}
+ public int getKeyPressedCount(boolean autoRepeatOnly) {
+ return keyPressed;
+ }
+
+ public int getKeyReleasedCount(boolean autoRepeatOnly) {
+ return keyReleased;
+ }
+
+ public int getKeyTypedCount(boolean autoRepeatOnly) {
+ return keyTyped;
+ }
+
+ public List<EventObject> getQueued() {
+ return queue;
+ }
+
public void reset() {
keyTyped = 0;
+ keyPressed = 0;
+ keyReleased = 0;
pressed = false;
+ queue.clear();
}
public void keyPressed(KeyEvent e) {
pressed = true;
- System.err.println("KEY AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ keyPressed++;
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("KEY AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void keyReleased(KeyEvent e) {
pressed = false;
- System.err.println("KEY AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ keyReleased++;
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("KEY AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void keyTyped(java.awt.event.KeyEvent e) {
- ++keyTyped;
- System.err.println("KEY AWT TYPED ["+keyTyped+"]: "+prefix+", "+e);
+ keyTyped++;
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("KEY AWT TYPED ["+keyTyped+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[pressed "+pressed+", typed "+keyTyped+"]"; }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTMouseAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTMouseAdapter.java
index b94802348..3334f18ea 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTMouseAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTMouseAdapter.java
@@ -29,17 +29,24 @@
package com.jogamp.opengl.test.junit.util;
import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
public class AWTMouseAdapter extends java.awt.event.MouseAdapter implements InputEventCountAdapter {
String prefix;
int mouseClicked;
boolean pressed;
+ List<EventObject> queue = new ArrayList<EventObject>();
+ boolean verbose = true;
public AWTMouseAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean isPressed() {
return pressed;
}
@@ -48,24 +55,38 @@ public class AWTMouseAdapter extends java.awt.event.MouseAdapter implements Inpu
return mouseClicked;
}
+ public List<EventObject> getQueued() {
+ return queue;
+ }
+
public void reset() {
mouseClicked = 0;
pressed = false;
+ queue.clear();
}
public void mousePressed(MouseEvent e) {
pressed = true;
- System.err.println("MOUSE AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void mouseReleased(MouseEvent e) {
pressed = false;
- System.err.println("MOUSE AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void mouseClicked(java.awt.event.MouseEvent e) {
mouseClicked+=e.getClickCount();
- System.err.println("MOUSE AWT CLICKED ["+mouseClicked+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE AWT CLICKED ["+mouseClicked+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[pressed "+pressed+", clicked "+mouseClicked+"]"; }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
index 160653cd5..06e172a5d 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java
@@ -312,7 +312,7 @@ public class AWTRobotUtil {
}
if(!hasFocus) {
System.err.print("*** AWTRobotUtil.assertRequestFocusAndWait() ");
- if(gain.focusGained() && !lost.focusLost()) {
+ if( ( null == gain || gain.focusGained() ) && ( null == lost || !lost.focusLost() ) ) {
// be error tolerant here, some impl. may lack focus-lost events (OS X)
System.err.println("minor UI failure");
hasFocus = true;
@@ -337,7 +337,7 @@ public class AWTRobotUtil {
}
public static int keyType(int i, Robot robot, int keyCode,
- Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException
+ Object obj, KeyEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException
{
int tc = 0;
int j;
@@ -365,13 +365,26 @@ public class AWTRobotUtil {
Assert.assertEquals("Key ("+i+":"+j+") not typed one time", 1, tc);
return (int) ( System.currentTimeMillis() - t0 ) ;
}
+
+ /** No validation is performed .. */
+ public static int keyPress(int i, Robot robot, boolean press, int keyCode, int msDelay) {
+ final long t0 = System.currentTimeMillis();
+ if(press) {
+ robot.keyPress(keyCode);
+ } else {
+ robot.keyRelease(keyCode);
+ }
+ robot.delay(msDelay);
+
+ return (int) ( System.currentTimeMillis() - t0 ) ;
+ }
/**
* @param keyCode TODO
* @param counter shall return the number of keys typed (press + release)
*/
public static void assertKeyType(Robot robot, int keyCode, int typeCount,
- Object obj, InputEventCountAdapter counter)
+ Object obj, KeyEventCountAdapter counter)
throws AWTException, InterruptedException, InvocationTargetException {
if(null == robot) {
@@ -398,6 +411,38 @@ public class AWTRobotUtil {
Assert.assertEquals("Wrong key count", typeCount, counter.getCount()-c0);
}
+ /**
+ * @param keyCode TODO
+ * @param counter shall return the number of keys typed (press + release)
+ */
+ public static void assertKeyPress(Robot robot, int keyCode, int typeCount,
+ Object obj, KeyEventCountAdapter counter)
+ throws AWTException, InterruptedException, InvocationTargetException {
+
+ if(null == robot) {
+ robot = new Robot();
+ robot.setAutoWaitForIdle(true);
+ }
+
+ centerMouse(robot, obj, false);
+
+ Assert.assertEquals("Key already pressed", false, counter.isPressed());
+
+ if(DEBUG) {
+ System.err.println("**************************************");
+ System.err.println("KC0: "+counter);
+ }
+
+ final int c0 = counter.getCount();
+
+ for(int i=0; i<typeCount; i++) {
+ keyType(i, robot, keyCode, obj, counter);
+ }
+
+ if(DEBUG) { System.err.println("KC3.0: "+counter); }
+ Assert.assertEquals("Wrong key count", typeCount, counter.getCount()-c0);
+ }
+
static int mouseClick(int i, Robot robot, int mouseButton,
Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException
{
diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java
index 16aacd2fd..2e74dfae8 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java
@@ -35,12 +35,15 @@ public class AWTWindowFocusAdapter implements FocusEventCountAdapter, WindowFocu
String prefix;
int focusCount;
+ boolean verbose = true;
public AWTWindowFocusAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean focusLost() {
return focusCount<0;
}
@@ -57,14 +60,18 @@ public class AWTWindowFocusAdapter implements FocusEventCountAdapter, WindowFocu
public void windowGainedFocus(WindowEvent e) {
if(focusCount<0) { focusCount=0; }
focusCount++;
- System.err.println("FOCUS AWT GAINED (Window) [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS AWT GAINED (Window) [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
/* @Override */
public void windowLostFocus(WindowEvent e) {
if(focusCount>0) { focusCount=0; }
focusCount--;
- System.err.println("FOCUS AWT LOST (Window) [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS AWT LOST (Window) [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[focusCount "+focusCount +"]"; }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/EventCountAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/EventCountAdapter.java
index 76a1884c8..906e4a7c9 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/EventCountAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/EventCountAdapter.java
@@ -28,7 +28,16 @@
package com.jogamp.opengl.test.junit.util;
+/**
+ * Base event count adapter.
+ * <p>
+ * Instance starts in verbose mode.
+ * </p>
+ */
public interface EventCountAdapter {
void reset();
+
+ /** Instance starts in verbose mode, call w/ false to disable verbosity. */
+ void setVerbose(boolean v);
}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/InputEventCountAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/InputEventCountAdapter.java
index 27f3d7e29..ed7485951 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/InputEventCountAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/InputEventCountAdapter.java
@@ -28,8 +28,13 @@
package com.jogamp.opengl.test.junit.util;
+import java.util.EventObject;
+import java.util.List;
+
public interface InputEventCountAdapter extends EventCountAdapter {
int getCount();
boolean isPressed();
+
+ public List<EventObject> getQueued();
}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/KeyEventCountAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/KeyEventCountAdapter.java
new file mode 100644
index 000000000..832f5ae82
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/util/KeyEventCountAdapter.java
@@ -0,0 +1,38 @@
+/**
+ * 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.util;
+
+public interface KeyEventCountAdapter extends InputEventCountAdapter {
+ public int getKeyPressedCount(boolean autoRepeatOnly);
+
+ public int getKeyReleasedCount(boolean autoRepeatOnly);
+
+ public int getKeyTypedCount(boolean autoRepeatOnly);
+}
+
diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTFocusAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTFocusAdapter.java
index 27d4abd9c..ccb1bde78 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/NEWTFocusAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTFocusAdapter.java
@@ -36,12 +36,15 @@ public class NEWTFocusAdapter implements WindowListener, FocusEventCountAdapter
String prefix;
int focusCount;
+ boolean verbose = true;
public NEWTFocusAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean focusLost() {
return focusCount<0;
}
@@ -57,13 +60,17 @@ public class NEWTFocusAdapter implements WindowListener, FocusEventCountAdapter
public void windowGainedFocus(WindowEvent e) {
if(focusCount<0) { focusCount=0; }
focusCount++;
- System.err.println("FOCUS NEWT GAINED [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS NEWT GAINED [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
public void windowLostFocus(WindowEvent e) {
if(focusCount>0) { focusCount=0; }
focusCount--;
- System.err.println("FOCUS NEWT LOST [fc "+focusCount+"]: "+prefix+", "+e);
+ if( verbose ) {
+ System.err.println("FOCUS NEWT LOST [fc "+focusCount+"]: "+prefix+", "+e);
+ }
}
public void windowResized(WindowEvent e) { }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyAdapter.java
index 32b392ca8..42235254a 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyAdapter.java
@@ -28,19 +28,29 @@
package com.jogamp.opengl.test.junit.util;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
+
+import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyAdapter;
import com.jogamp.newt.event.KeyEvent;
-public class NEWTKeyAdapter extends KeyAdapter implements InputEventCountAdapter {
+public class NEWTKeyAdapter extends KeyAdapter implements KeyEventCountAdapter {
String prefix;
- int keyTyped;
+ int keyPressed, keyReleased, keyTyped;
+ int keyPressedAR, keyReleasedAR, keyTypedAR;
boolean pressed;
+ List<EventObject> queue = new ArrayList<EventObject>();
+ boolean verbose = true;
public NEWTKeyAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+
+ public void setVerbose(boolean v) { verbose = false; }
public boolean isPressed() {
return pressed;
@@ -50,25 +60,67 @@ public class NEWTKeyAdapter extends KeyAdapter implements InputEventCountAdapter
return keyTyped;
}
+ public int getKeyPressedCount(boolean autoRepeatOnly) {
+ return autoRepeatOnly ? keyPressedAR: keyPressed;
+ }
+
+ public int getKeyReleasedCount(boolean autoRepeatOnly) {
+ return autoRepeatOnly ? keyReleasedAR: keyReleased;
+ }
+
+ public int getKeyTypedCount(boolean autoRepeatOnly) {
+ return autoRepeatOnly ? keyTypedAR: keyTyped;
+ }
+
+ public List<EventObject> getQueued() {
+ return queue;
+ }
+
public void reset() {
keyTyped = 0;
+ keyPressed = 0;
+ keyReleased = 0;
+ keyTypedAR = 0;
+ keyPressedAR = 0;
+ keyReleasedAR = 0;
pressed = false;
+ queue.clear();
}
public void keyPressed(KeyEvent e) {
pressed = true;
- System.err.println("NEWT AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ keyPressed++;
+ if( 0 != ( e.getModifiers() & InputEvent.AUTOREPEAT_MASK ) ) {
+ keyPressedAR++;
+ }
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("NEWT AWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void keyReleased(KeyEvent e) {
pressed = false;
- System.err.println("NEWT AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ keyReleased++;
+ if( 0 != ( e.getModifiers() & InputEvent.AUTOREPEAT_MASK ) ) {
+ keyReleasedAR++;
+ }
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("NEWT AWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ }
}
@Override
public void keyTyped(KeyEvent e) {
- ++keyTyped;
- System.err.println("KEY NEWT TYPED ["+keyTyped+"]: "+prefix+", "+e);
+ keyTyped++;
+ if( 0 != ( e.getModifiers() & InputEvent.AUTOREPEAT_MASK ) ) {
+ keyTypedAR++;
+ }
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("KEY NEWT TYPED ["+keyTyped+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[pressed "+pressed+", typed "+keyTyped+"]"; }
diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java
new file mode 100644
index 000000000..dfc96edcb
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTKeyUtil.java
@@ -0,0 +1,103 @@
+/**
+ * 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.util;
+
+import java.util.EventObject;
+import java.util.List;
+
+import org.junit.Assert;
+
+import com.jogamp.newt.event.KeyEvent;
+
+public class NEWTKeyUtil {
+ public static void dumpKeyEvents(List<EventObject> keyEvents) {
+ for(int i=0; i<keyEvents.size(); i++) {
+ System.err.println(i+": "+keyEvents.get(i));
+ }
+ }
+
+ public static int getNextKeyEventType(int et) {
+ switch( et ) {
+ case KeyEvent.EVENT_KEY_PRESSED:
+ return KeyEvent.EVENT_KEY_RELEASED;
+ case KeyEvent.EVENT_KEY_RELEASED:
+ return KeyEvent.EVENT_KEY_TYPED;
+ case KeyEvent.EVENT_KEY_TYPED:
+ return KeyEvent.EVENT_KEY_PRESSED;
+ default:
+ Assert.assertTrue("Invalid event type "+et, false);
+ return 0;
+ }
+ }
+
+ public static void validateKeyEventOrder(List<EventObject> keyEvents) {
+ int eet = KeyEvent.EVENT_KEY_PRESSED;
+ for(int i=0; i<keyEvents.size(); i++) {
+ final KeyEvent e = (KeyEvent) keyEvents.get(i);
+ final int et = e.getEventType();
+ Assert.assertEquals("Key event not in proper order", eet, et);
+ eet = getNextKeyEventType(et);
+ }
+ }
+
+ /**
+ *
+ * @param keyAdapter
+ * @param expTotalCount number of physical key press/release, i.e. 1 shall result in 3 events (press, release and typed)
+ * @param expARCount as auto-release ..
+ */
+ public static void validateKeyAdapterStats(NEWTKeyAdapter keyAdapter, int expTotalCount, int expARCount) {
+ final int keyPressed = keyAdapter.getKeyPressedCount(false);
+ final int keyPressedAR = keyAdapter.getKeyPressedCount(true);
+ final int keyReleased = keyAdapter.getKeyReleasedCount(false);
+ final int keyReleasedAR = keyAdapter.getKeyReleasedCount(true);
+ final int keyTyped = keyAdapter.getKeyTypedCount(false);
+ final int keyTypedAR = keyAdapter.getKeyTypedCount(true);
+ final int keyPressedNR = keyPressed-keyPressedAR;
+ final int keyReleasedNR = keyReleased-keyReleasedAR;
+ final int keyTypedNR = keyTyped-keyTypedAR;
+ System.err.println("Total Press "+keyPressed +", Release "+keyReleased +", Typed "+keyTyped);
+ System.err.println("AutoR Press "+keyPressedAR+", Release "+keyReleasedAR+", Typed "+keyTypedAR);
+ System.err.println("No AR Press "+keyPressedNR+", Release "+keyReleasedNR+", Typed "+keyTypedNR);
+
+ final List<EventObject> keyEvents = keyAdapter.getQueued();
+ Assert.assertEquals("Key event count not multiple of 3", 0, keyEvents.size()%3);
+ Assert.assertEquals("Key event count not 3 * press_release_count", 3*expTotalCount, keyEvents.size());
+ Assert.assertEquals("Key press count failure", expTotalCount, keyPressed);
+ Assert.assertEquals("Key press count failure (AR)", expARCount, keyPressedAR);
+ Assert.assertEquals("Key released count failure", expTotalCount, keyReleased);
+ Assert.assertEquals("Key released count failure (AR)", expARCount, keyReleasedAR);
+ Assert.assertEquals("Key typed count failure", expTotalCount, keyTyped);
+ Assert.assertEquals("Key typed count failure (AR)", expARCount, keyTypedAR);
+
+ // should be true - always, reaching this point - duh!
+ Assert.assertEquals(expTotalCount-expARCount, keyPressedNR);
+ Assert.assertEquals(expTotalCount-expARCount, keyReleasedNR);
+ Assert.assertEquals(expTotalCount-expARCount, keyTypedNR);
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTMouseAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTMouseAdapter.java
index d98b9ca74..c77462884 100644
--- a/src/test/com/jogamp/opengl/test/junit/util/NEWTMouseAdapter.java
+++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTMouseAdapter.java
@@ -28,6 +28,10 @@
package com.jogamp.opengl.test.junit.util;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
+
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
@@ -36,12 +40,16 @@ public class NEWTMouseAdapter extends MouseAdapter implements InputEventCountAda
String prefix;
int mouseClicked;
boolean pressed;
+ List<EventObject> queue = new ArrayList<EventObject>();
+ boolean verbose = true;
public NEWTMouseAdapter(String prefix) {
this.prefix = prefix;
reset();
}
+ public void setVerbose(boolean v) { verbose = false; }
+
public boolean isPressed() {
return pressed;
}
@@ -50,24 +58,38 @@ public class NEWTMouseAdapter extends MouseAdapter implements InputEventCountAda
return mouseClicked;
}
+ public List<EventObject> getQueued() {
+ return queue;
+ }
+
public void reset() {
mouseClicked = 0;
pressed = false;
+ queue.clear();
}
public void mousePressed(MouseEvent e) {
pressed = true;
- System.err.println("MOUSE NEWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE NEWT PRESSED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void mouseReleased(MouseEvent e) {
pressed = false;
- System.err.println("MOUSE NEWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE NEWT RELEASED ["+pressed+"]: "+prefix+", "+e);
+ }
}
public void mouseClicked(MouseEvent e) {
mouseClicked+=e.getClickCount();
- System.err.println("MOUSE NEWT CLICKED ["+mouseClicked+"]: "+prefix+", "+e);
+ queue.add(e);
+ if( verbose ) {
+ System.err.println("MOUSE NEWT CLICKED ["+mouseClicked+"]: "+prefix+", "+e);
+ }
}
public String toString() { return prefix+"[pressed "+pressed+", clicked "+mouseClicked+"]"; }