aboutsummaryrefslogtreecommitdiffstats
path: root/src/newt/classes
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2012-09-16 21:13:51 +0200
committerSven Gothel <[email protected]>2012-09-16 21:13:51 +0200
commit646714d3dab87396b9a3119bf90ca26e0b1c97ce (patch)
tree678209f657c5f3bfa29e54c171565488a15f9951 /src/newt/classes
parentf2bd50ff25009de477a203460abe8a5597acdbc5 (diff)
Fix Bug 601: Harmonize order of key events incl. auto-repeat and adding AUTOREPEAT_MASK modifier bit. Refine InputEvent toString(..) and list modifiers by name.
As now described in NEWT's KeyEvent: +/** + * Key events are delivered in the following order: + * <ol> + * <li>{@link #EVENT_KEY_PRESSED}</li> + * <li>{@link #EVENT_KEY_RELEASED}</li> + * <li>{@link #EVENT_KEY_TYPED}</li> + * </ol> + * In case the native platform does not + * deliver keyboard events in the above order or skip events, + * the NEWT driver will reorder and inject synthetic events if required. + * <p> + * Besides regular modifiers like {@link InputEvent##SHIFT_MASK} etc., + * the {@link InputEvent#AUTOREPEAT_MASK} bit is added if repetition is detected. + * </p> + */
Diffstat (limited to 'src/newt/classes')
-rw-r--r--src/newt/classes/com/jogamp/newt/Window.java2
-rw-r--r--src/newt/classes/com/jogamp/newt/event/InputEvent.java82
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyEvent.java26
-rw-r--r--src/newt/classes/com/jogamp/newt/event/MouseEvent.java12
-rw-r--r--src/newt/classes/com/jogamp/newt/event/NEWTEvent.java10
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowEvent.java13
-rw-r--r--src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java11
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java20
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java36
9 files changed, 184 insertions, 28 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index e8537fec5..78e2abc6e 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -245,6 +245,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
String getTitle();
+ /** @see #setPointerVisible(boolean) */
boolean isPointerVisible();
/**
@@ -256,6 +257,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
*/
void setPointerVisible(boolean pointerVisible);
+ /** @see #confinePointer(boolean) */
boolean isPointerConfined();
/**
diff --git a/src/newt/classes/com/jogamp/newt/event/InputEvent.java b/src/newt/classes/com/jogamp/newt/event/InputEvent.java
index 819338ccb..148ac5962 100644
--- a/src/newt/classes/com/jogamp/newt/event/InputEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/InputEvent.java
@@ -34,22 +34,31 @@
package com.jogamp.newt.event;
+import com.jogamp.newt.Window;
+
@SuppressWarnings("serial")
public abstract class InputEvent extends NEWTEvent
{
- public static final int SHIFT_MASK = 1 << 0;
- public static final int CTRL_MASK = 1 << 1;
- public static final int META_MASK = 1 << 2;
- public static final int ALT_MASK = 1 << 3;
- public static final int ALT_GRAPH_MASK = 1 << 5;
- public static final int BUTTON1_MASK = 1 << 6;
- public static final int BUTTON2_MASK = 1 << 7;
- public static final int BUTTON3_MASK = 1 << 8;
- public static final int BUTTON4_MASK = 1 << 9;
- public static final int BUTTON5_MASK = 1 << 10;
- public static final int BUTTON6_MASK = 1 << 11;
- public static final int CONFINED_MASK = 1 << 16;
- public static final int INVISIBLE_MASK = 1 << 17;
+ public static final int SHIFT_MASK = 1 << 0;
+ public static final int CTRL_MASK = 1 << 1;
+ public static final int META_MASK = 1 << 2;
+ public static final int ALT_MASK = 1 << 3;
+ public static final int ALT_GRAPH_MASK = 1 << 5;
+ public static final int BUTTON1_MASK = 1 << 6;
+ public static final int BUTTON2_MASK = 1 << 7;
+ public static final int BUTTON3_MASK = 1 << 8;
+ public static final int BUTTON4_MASK = 1 << 9;
+ public static final int BUTTON5_MASK = 1 << 10;
+ public static final int BUTTON6_MASK = 1 << 11;
+
+ /** Event is caused by auto-repeat. */
+ public static final int AUTOREPEAT_MASK = 1 << 15;
+
+ /** Pointer is confined, see {@link Window#confinePointer(boolean)}. */
+ public static final int CONFINED_MASK = 1 << 16;
+
+ /** Pointer is invisible, see {@link Window#setPointerVisible(boolean)}. */
+ public static final int INVISIBLE_MASK = 1 << 17;
/**
* Returns the corresponding button mask for the given button.
@@ -76,30 +85,64 @@ public abstract class InputEvent extends NEWTEvent
this.modifiers=modifiers;
}
+ /** Return the modifier bits of this event, e.g. see {@link #SHIFT_MASK} .. etc. */
public int getModifiers() {
return modifiers;
}
+ /** {@link #getModifiers()} contains {@link #ALT_MASK}. */
public boolean isAltDown() {
return (modifiers&ALT_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #ALT_GRAPH_MASK}. */
public boolean isAltGraphDown() {
return (modifiers&ALT_GRAPH_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #CTRL_MASK}. */
public boolean isControlDown() {
return (modifiers&CTRL_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #META_MASK}. */
public boolean isMetaDown() {
return (modifiers&META_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #SHIFT_MASK}. */
public boolean isShiftDown() {
return (modifiers&SHIFT_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #AUTOREPEAT_MASK}. */
+ public boolean isAutoRepeat() {
+ return (modifiers&AUTOREPEAT_MASK)!=0;
+ }
+ /** {@link #getModifiers()} contains {@link #CONFINED_MASK}. Pointer is confined, see {@link Window#confinePointer(boolean)}. */
public boolean isConfined() {
return (modifiers&CONFINED_MASK)!=0;
}
+ /** {@link #getModifiers()} contains {@link #INVISIBLE_MASK}. Pointer is invisible, see {@link Window#setPointerVisible(boolean)}. */
public boolean isInvisible() {
return (modifiers&INVISIBLE_MASK)!=0;
}
+
+ public StringBuilder getModifiersString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("[");
+ boolean isFirst = true;
+ if(isShiftDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("shift"); }
+ if(isControlDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("ctrl"); }
+ if(isMetaDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("meta"); }
+ if(isAltDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("alt"); }
+ if(isAltGraphDown()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("altg"); }
+ if(isAutoRepeat()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("repeat"); }
+ for(int i=1; i<=MouseEvent.BUTTON_NUMBER; i++) {
+ if(isButtonDown(i)) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("button").append(i); }
+ }
+ if(isConfined()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("confined"); }
+ if(isInvisible()) { if(!isFirst) { sb.append(", "); } isFirst = false; sb.append("invisible"); }
+ sb.append("]");
+
+ return sb;
+ }
/**
* @return Array of pressed mouse buttons [{@link MouseEvent#BUTTON1} .. {@link MouseEvent#BUTTON6}].
@@ -124,7 +167,18 @@ public abstract class InputEvent extends NEWTEvent
}
public String toString() {
- return "InputEvent[modifiers: 0x"+Integer.toHexString(modifiers)+", "+super.toString()+"]";
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("InputEvent[modifiers: ");
+ getModifiersString(sb);
+ sb.append(", ");
+ super.toString(sb).append("]");
+ return sb;
}
private final int modifiers;
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
index 4db661eeb..bd48981da 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
@@ -34,6 +34,21 @@
package com.jogamp.newt.event;
+/**
+ * Key events are delivered in the following order:
+ * <ol>
+ * <li>{@link #EVENT_KEY_PRESSED}</li>
+ * <li>{@link #EVENT_KEY_RELEASED}</li>
+ * <li>{@link #EVENT_KEY_TYPED}</li>
+ * </ol>
+ * In case the native platform does not
+ * deliver keyboard events in the above order or skip events,
+ * the NEWT driver will reorder and inject synthetic events if required.
+ * <p>
+ * Besides regular modifiers like {@link InputEvent##SHIFT_MASK} etc.,
+ * the {@link InputEvent#AUTOREPEAT_MASK} bit is added if repetition is detected.
+ * </p>
+ */
@SuppressWarnings("serial")
public class KeyEvent extends InputEvent
{
@@ -54,8 +69,15 @@ public class KeyEvent extends InputEvent
}
public String toString() {
- return "KeyEvent["+getEventTypeString(getEventType())+
- ", code "+keyCode+"("+toHexString(keyCode)+"), char '"+keyChar+"' ("+toHexString((int)keyChar)+"), isActionKey "+isActionKey()+", "+super.toString()+"]";
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("KeyEvent[").append(getEventTypeString(getEventType())).append(", code ").append(keyCode).append("(").append(toHexString(keyCode)).append("), char '").append(keyChar).append("' (").append(toHexString((int)keyChar)).append("), isActionKey ").append(isActionKey()).append(", ");
+ return super.toString(sb).append("]");
}
public static String getEventTypeString(int type) {
diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
index ceaf7d47a..d293d2db7 100644
--- a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java
@@ -165,7 +165,13 @@ public class MouseEvent extends InputEvent
}
public String toString() {
- StringBuilder sb = new StringBuilder();
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
sb.append("MouseEvent[").append(getEventTypeString(getEventType()))
.append(", ").append(x).append("/").append(y)
.append(", button ").append(button).append(", count ")
@@ -182,8 +188,8 @@ public class MouseEvent extends InputEvent
}
sb.append("]");
}
- sb.append(", ").append(super.toString()).append("]");
- return sb.toString();
+ sb.append(", ");
+ return super.toString(sb).append("]");
}
public static String getEventTypeString(int type) {
diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
index 3f3817b91..fd5b69ccc 100644
--- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java
@@ -151,7 +151,14 @@ public class NEWTEvent extends java.util.EventObject {
}
public String toString() {
- return "NEWTEvent[sys:"+isSystemEvent()+", source:"+getSource().getClass().getName()+", when:"+getWhen()+" d "+(System.currentTimeMillis()-getWhen())+"ms]";
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ 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) {
@@ -161,5 +168,4 @@ public class NEWTEvent extends java.util.EventObject {
public static String toHexString(long hex) {
return "0x" + Long.toHexString(hex);
}
-
}
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
index f3d62d8c6..163b51439 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java
@@ -39,6 +39,7 @@ package com.jogamp.newt.event;
* NEWT will automatically handle component moves and resizes internally, regardless of whether a program is receiving these events or not. <br>
* The actual event semantic, here move and resize, is processed before the event is send.<br>
*/
+@SuppressWarnings("serial")
public class WindowEvent extends NEWTEvent {
public static final int EVENT_WINDOW_RESIZED = 100;
public static final int EVENT_WINDOW_MOVED = 101;
@@ -64,8 +65,16 @@ public class WindowEvent extends NEWTEvent {
default: return "unknown (" + type + ")";
}
}
+
public String toString() {
- return "WindowEvent["+getEventTypeString(getEventType()) +
- ", " + super.toString() + "]";
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("WindowEvent[").append(getEventTypeString(getEventType())).append(", ");
+ return super.toString(sb).append("]");
}
}
diff --git a/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
index 505939de2..e3f0373ec 100644
--- a/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java
@@ -30,6 +30,7 @@ package com.jogamp.newt.event;
import javax.media.nativewindow.util.Rectangle;
+@SuppressWarnings("serial")
public class WindowUpdateEvent extends WindowEvent {
final Rectangle bounds;
@@ -44,6 +45,14 @@ public class WindowUpdateEvent extends WindowEvent {
}
public String toString() {
- return "WindowUpdateEvent["+super.toString()+", "+bounds+"]";
+ return toString(null).toString();
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("WindowUpdateEvent[").append(bounds).append(", ");
+ return super.toString(sb).append("]");
}
}
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
index d0c0b8b20..4eeafb244 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/WindowDriver.java
@@ -49,6 +49,7 @@ import jogamp.newt.WindowImpl;
import jogamp.newt.driver.DriverClearFocus;
import jogamp.newt.driver.DriverUpdatePosition;
+import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
public class WindowDriver extends WindowImpl implements MutableSurface, DriverClearFocus, DriverUpdatePosition {
@@ -313,6 +314,14 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
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);
@@ -327,6 +336,14 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
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);
@@ -335,14 +352,17 @@ public class WindowDriver extends WindowImpl implements MutableSurface, DriverCl
private int keyDownModifiers = 0;
private int keyDownCode = 0;
+ private int pressedKeyBalance = 0;
private boolean validateKeyEvent(int eventType, int modifiers, int keyCode) {
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;
case KeyEvent.EVENT_KEY_TYPED:
final boolean matchKeyDown = keyDownModifiers == modifiers && keyDownCode == keyCode;
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java
index 5dbdeb458..18cc88472 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.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
@@ -258,9 +259,14 @@ public class WindowDriver extends WindowImpl {
// nop - using event driven insetsChange(..)
}
- private final int validateKeyCode(int eventType, int keyCode) {
+ 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:
@@ -273,18 +279,40 @@ public class WindowDriver extends WindowImpl {
return keyCode;
}
private int lastPressedKeyCode = 0;
+ private int pressedKeyBalance = 0;
+ private int autoRepeat = 0;
@Override
public void sendKeyEvent(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, keyCode);
- super.sendKeyEvent(eventType, modifiers, keyCode, keyChar);
+ 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.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);
+ break;
+ }
}
@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, keyCode);
+ keyCode = validateKeyCode(eventType, modifiers, keyCode, keyChar);
super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar);
}