aboutsummaryrefslogtreecommitdiffstats
path: root/src/newt/classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/newt/classes')
-rw-r--r--src/newt/classes/com/jogamp/newt/Window.java38
-rw-r--r--src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java81
-rw-r--r--src/newt/classes/com/jogamp/newt/event/KeyEvent.java4
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/GLWindow.java9
-rw-r--r--src/newt/classes/jogamp/newt/WindowImpl.java87
-rw-r--r--src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java11
-rw-r--r--src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java16
-rw-r--r--src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java31
8 files changed, 215 insertions, 62 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java
index ae6bd2b8c..b0df7a28a 100644
--- a/src/newt/classes/com/jogamp/newt/Window.java
+++ b/src/newt/classes/com/jogamp/newt/Window.java
@@ -30,6 +30,8 @@ package com.jogamp.newt;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.MouseListener;
import jogamp.newt.Debug;
import javax.media.nativewindow.CapabilitiesChooser;
@@ -309,16 +311,46 @@ public interface Window extends NativeWindow, WindowClosingProtocol {
}
/**
- * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus.
+ * Sets a {@link FocusRunnable},
+ * which {@link FocusRunnable#run()} method is executed before the native focus is requested.
+ * <p>
* This allows notifying a covered window toolkit like AWT that the focus is requested,
* hence focus traversal can be made transparent.
+ * </p>
*/
void setFocusAction(FocusRunnable focusAction);
+
+ /**
+ * Sets a {@link KeyListener} allowing focus traversal with a covered window toolkit like AWT.
+ * <p>
+ * The {@link KeyListener} methods are invoked prior to all other {@link KeyListener}'s
+ * allowing to suppress the {@link KeyEvent} via the {@link InputEvent#consumedTag}.
+ * </p>
+ * @param l
+ */
+ void setKeyboardFocusHandler(KeyListener l);
+ /**
+ * Request focus for this native window
+ * <p>
+ * The request is handled on this Window EDT and blocked until finished.
+ * </p>
+ *
+ * @see #requestFocus(boolean)
+ */
void requestFocus();
- boolean hasFocus();
-
+ /**
+ * Request focus for this native window
+ * <p>
+ * The request is handled on this Window EDT.
+ * </p>
+ *
+ * @param wait true if waiting until the request is executed, otherwise false
+ * @see #requestFocus()
+ */
+ void requestFocus(boolean wait);
+
void windowRepaint(int x, int y, int width, int height);
void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event);
diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
index 8a0cb8d6c..18ecdf772 100644
--- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
+++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java
@@ -29,6 +29,7 @@
package com.jogamp.newt.awt;
+import java.awt.AWTKeyStroke;
import java.awt.Canvas;
import java.awt.EventQueue;
import java.awt.Graphics;
@@ -37,6 +38,7 @@ import java.awt.KeyboardFocusManager;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Set;
import javax.media.nativewindow.Capabilities;
import javax.media.nativewindow.CapabilitiesImmutable;
@@ -54,6 +56,9 @@ import jogamp.newt.awt.event.NewtFactoryAWT;
import com.jogamp.newt.Display;
import com.jogamp.newt.Window;
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
@@ -167,6 +172,9 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
class FocusAction implements Window.FocusRunnable {
public boolean run() {
+ if(!isNewtChildOnscreen) {
+ throw new InternalError("focusAction() shall not be invoked for offscreen windows by native code");
+ }
if ( EventQueue.isDispatchThread() ) {
focusActionImpl.run();
} else {
@@ -175,11 +183,6 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
} catch (Exception e) {
throw new NativeWindowException(e);
}
- /**
- // wait for AWT focus !
- for(long sleep = Window.TIMEOUT_NATIVEWINDOW; 0<sleep && !isFocusOwner(); sleep-=10 ) {
- try { Thread.sleep(10); } catch (InterruptedException e) { }
- } */
}
return focusActionImpl.result;
}
@@ -190,10 +193,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
if(DEBUG) {
System.err.println("FocusActionImpl.run() "+Display.getThreadName());
}
- NewtCanvasAWT.this.requestFocusAWTParent();
- if(isNewtChildOnscreen) {
- KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
- }
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
}
}
FocusActionImpl focusActionImpl = new FocusActionImpl();
@@ -207,6 +207,53 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
}
};
+ class FocusTraversalKeyListener implements KeyListener {
+ boolean suppress = false;
+
+ public void keyPressed(KeyEvent e) {
+ handleKey(e, false);
+ }
+ public void keyReleased(KeyEvent e) {
+ handleKey(e, true);
+ }
+ public void keyTyped(KeyEvent e) {
+ if(suppress) {
+ e.setAttachment(InputEvent.consumedTag);
+ suppress = false; // reset
+ }
+ }
+
+ void handleKey(KeyEvent e, boolean onRelease) {
+ final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(e.getKeyCode(), e.getModifiers(), onRelease);
+ if(null != ks) {
+ final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ final Set<AWTKeyStroke> fwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ if(fwdKeys.contains(ks)) {
+ if(DEBUG) {
+ System.err.println("FTKL.handleKey (fwd): "+ks);
+ }
+ kfm.focusNextComponent(NewtCanvasAWT.this);
+ suppress = true;
+ } else if(bwdKeys.contains(ks)) {
+ if(DEBUG) {
+ System.err.println("FTKL.handleKey (bwd): "+ks);
+ }
+ kfm.focusPreviousComponent(NewtCanvasAWT.this);
+ suppress = true;
+ } else if(DEBUG) {
+ System.err.println("FTKL.handleKey (nop): "+ks);
+ }
+ } else if(DEBUG) {
+ System.err.println("FTKL.handleKey: null");
+ }
+ if(suppress) {
+ e.setAttachment(InputEvent.consumedTag);
+ }
+ }
+ }
+ FocusTraversalKeyListener newtFocusTraversalKeyListener = null;
+
/** sets a new NEWT child, provoking reparenting. */
private NewtCanvasAWT setNEWTChild(Window child) {
if(newtChild!=child) {
@@ -240,8 +287,12 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
private final void configureNewtChildInputEventHandler() {
if(null==awtMouseAdapter && null != newtChild.getGraphicsConfiguration()) {
isNewtChildOnscreen = newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
- if(!isNewtChildOnscreen) {
- // offscreen childs require AWT event fwd for key/mouse
+ if(isNewtChildOnscreen) {
+ // onscreen child needs to fwd focus traversal
+ newtFocusTraversalKeyListener = new FocusTraversalKeyListener();
+ newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener);
+ } else {
+ // offscreen child require AWT event fwd for key/mouse
awtMouseAdapter = new AWTMouseAdapter(newtChild).addTo(this);
awtKeyAdapter = new AWTKeyAdapter(newtChild).addTo(this);
}
@@ -261,6 +312,10 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
awtKeyAdapter.removeFrom(this);
awtKeyAdapter = null;
}
+ if(null!=newtFocusTraversalKeyListener) {
+ newtChild.setKeyboardFocusHandler(null);
+ newtFocusTraversalKeyListener = null;
+ }
if( null != newtChild ) {
if(attach) {
@@ -401,10 +456,6 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto
}
}
- private final void requestFocusAWTParent() {
- super.requestFocusInWindow();
- }
-
private final void requestFocusNEWTChild() {
if(null!=newtChild) {
newtChild.setFocusAction(null);
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
index 9e4fe372b..44fcea49c 100644
--- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
+++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java
@@ -34,6 +34,7 @@
package com.jogamp.newt.event;
+@SuppressWarnings("serial")
public class KeyEvent extends InputEvent
{
public KeyEvent(int eventType, Object source, long when, int modifiers, int keyCode, char keyChar) {
@@ -42,9 +43,12 @@ public class KeyEvent extends InputEvent
this.keyChar=keyChar;
}
+ /** Only valid if delivered via {@link KeyListener#keyPressed(KeyEvent)} */
public char getKeyChar() {
return keyChar;
}
+
+ /** Always valid. */
public int getKeyCode() {
return keyCode;
}
diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
index e9ac272c8..fd216bfda 100644
--- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
+++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java
@@ -41,6 +41,7 @@ import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.newt.*;
import com.jogamp.newt.event.*;
+
import jogamp.newt.WindowImpl;
import javax.media.nativewindow.*;
@@ -254,10 +255,18 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC
window.setFocusAction(focusAction);
}
+ public void setKeyboardFocusHandler(KeyListener l) {
+ window.setKeyboardFocusHandler(l);
+ }
+
public final void requestFocus() {
window.requestFocus();
}
+ public final void requestFocus(boolean wait) {
+ window.requestFocus(wait);
+ }
+
public boolean hasFocus() {
return window.hasFocus();
}
diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java
index 3865cd6c8..ef927ec16 100644
--- a/src/newt/classes/jogamp/newt/WindowImpl.java
+++ b/src/newt/classes/jogamp/newt/WindowImpl.java
@@ -110,6 +110,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
private RequestFocusAction requestFocusAction = new RequestFocusAction();
private FocusRunnable focusAction = null;
+ private KeyListener keyboardFocusHandler = null;
private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper();
@@ -1415,14 +1416,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- public void requestFocus() {
- enqueueRequestFocus(true);
- }
-
- public final boolean hasFocus() {
- return hasFocus;
- }
-
public final InsetsImmutable getInsets() {
if(isUndecorated()) {
return Insets.getZero();
@@ -1559,15 +1552,18 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
}
- protected void enqueueRequestFocus(boolean wait) {
+ public final boolean hasFocus() {
+ return hasFocus;
+ }
+
+ public void requestFocus() {
+ requestFocus(true);
+ }
+
+ public void requestFocus(boolean wait) {
runOnEDTIfAvail(wait, requestFocusAction);
}
- /**
- * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus.
- * This allows notifying a covered window toolkit like AWT that the focus is requested,
- * hence focus traversal can be made transparent.
- */
public void setFocusAction(FocusRunnable focusAction) {
this.focusAction = focusAction;
}
@@ -1588,7 +1584,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
}
return res;
}
-
+
+ public void setKeyboardFocusHandler(KeyListener l) {
+ keyboardFocusHandler = l;
+ }
+
private class SetPositionActionImpl implements Runnable {
int x, y;
@@ -1830,8 +1830,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
// queue event in case window is locked, ie in operation
if( isWindowLocked() ) {
if(DEBUG_IMPLEMENTATION) {
- // System.err.println("Window.consumeEvent: queued "+e);
- // Thread.dumpStack(); // JAU
+ System.err.println("Window.consumeEvent: queued "+e);
+ // Thread.dumpStack();
}
return false;
}
@@ -2021,8 +2021,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
if(DEBUG_MOUSE_EVENT) {
System.err.println("consumeMouseEvent: event: "+e);
}
-
- for(int i = 0; i < mouseListeners.size(); i++ ) {
+ boolean consumed = false;
+ for(int i = 0; !consumed && i < mouseListeners.size(); i++ ) {
MouseListener l = mouseListeners.get(i);
switch(e.getEventType()) {
case MouseEvent.EVENT_MOUSE_CLICKED:
@@ -2052,13 +2052,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
default:
throw new NativeWindowException("Unexpected mouse event type " + e.getEventType());
}
+ consumed = InputEvent.consumedTag == e.getAttachment();
}
}
//
// KeyListener/Event Support
//
-
public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) );
}
@@ -2107,26 +2107,39 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer
return (KeyListener[]) keyListeners.toArray();
}
- protected void consumeKeyEvent(KeyEvent e) {
- if(DEBUG_KEY_EVENT) {
- System.err.println("consumeKeyEvent: "+e);
+ private final boolean propagateKeyEvent(KeyEvent e, KeyListener l) {
+ switch(e.getEventType()) {
+ case KeyEvent.EVENT_KEY_PRESSED:
+ l.keyPressed(e);
+ break;
+ case KeyEvent.EVENT_KEY_RELEASED:
+ l.keyReleased(e);
+ break;
+ case KeyEvent.EVENT_KEY_TYPED:
+ l.keyTyped(e);
+ break;
+ default:
+ throw new NativeWindowException("Unexpected key event type " + e.getEventType());
}
- for(int i = 0; i < keyListeners.size(); i++ ) {
- KeyListener l = keyListeners.get(i);
- switch(e.getEventType()) {
- case KeyEvent.EVENT_KEY_PRESSED:
- l.keyPressed(e);
- break;
- case KeyEvent.EVENT_KEY_RELEASED:
- l.keyReleased(e);
- break;
- case KeyEvent.EVENT_KEY_TYPED:
- l.keyTyped(e);
- break;
- default:
- throw new NativeWindowException("Unexpected key event type " + e.getEventType());
+ return InputEvent.consumedTag == e.getAttachment();
+ }
+
+ protected void consumeKeyEvent(KeyEvent e) {
+ boolean consumed;
+ if(null != keyboardFocusHandler) {
+ consumed = propagateKeyEvent(e, keyboardFocusHandler);
+ if(DEBUG_KEY_EVENT) {
+ System.err.println("consumeKeyEvent: "+e+", keyboardFocusHandler consumed: "+consumed);
+ }
+ } else {
+ consumed = false;
+ if(DEBUG_KEY_EVENT) {
+ System.err.println("consumeKeyEvent: "+e);
}
}
+ for(int i = 0; !consumed && i < keyListeners.size(); i++ ) {
+ consumed = propagateKeyEvent(e, keyListeners.get(i));
+ }
}
//
diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
index 358864547..313a5e868 100644
--- a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
+++ b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java
@@ -28,6 +28,8 @@
package jogamp.newt.awt.event;
+import java.awt.KeyboardFocusManager;
+
import com.jogamp.newt.event.awt.AWTAdapter;
import com.jogamp.newt.event.awt.AWTWindowAdapter;
@@ -54,9 +56,16 @@ public class AWTParentWindowAdapter
}
public void focusGained(java.awt.event.FocusEvent e) {
+ // forward focus to NEWT child
+ final com.jogamp.newt.Window newtChild = getNewtWindow();
+ final boolean isOnscreen = newtChild.isNativeValid() && newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen();
if(DEBUG_IMPLEMENTATION) {
- System.err.println("AWT: focusGained: "+ e);
+ System.err.println("AWT: focusGained: onscreen "+ isOnscreen+", "+e);
+ }
+ if(isOnscreen) {
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
}
+ newtChild.requestFocus(false);
}
public void focusLost(java.awt.event.FocusEvent e) {
diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java
index 292a9c255..e1b2ef87d 100644
--- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java
+++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java
@@ -311,20 +311,24 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable {
@Override
public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) {
- final int key = convertKeyChar(keyChar);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName());
// 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
- super.sendKeyEvent(eventType, modifiers, key, keyChar);
+ final int keyCode2 = convertKeyChar(keyChar);
+ if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: "+keyChar+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2));
+ // 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);
}
@Override
public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) {
- final int key = convertKeyChar(keyChar);
- if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName());
// 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
- super.enqueueKeyEvent(wait, eventType, modifiers, key, keyChar);
+ final int keyCode2 = convertKeyChar(keyChar);
+ if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: "+keyChar+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2));
+ // 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);
}
//----------------------------------------------------------------------
diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java
index cd5909d42..28be93acd 100644
--- a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java
+++ b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java
@@ -42,6 +42,7 @@ import javax.media.nativewindow.util.Insets;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
+import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
@@ -244,6 +245,36 @@ public class WindowsWindow extends WindowImpl {
// nop - using event driven insetsChange(..)
}
+ private final int validateKeyCode(int eventType, int keyCode) {
+ switch(eventType) {
+ case KeyEvent.EVENT_KEY_PRESSED:
+ lastPressedKeyCode = keyCode;
+ break;
+ case KeyEvent.EVENT_KEY_TYPED:
+ if(-1==keyCode) {
+ keyCode = lastPressedKeyCode;
+ }
+ lastPressedKeyCode = -1;
+ break;
+ }
+ return keyCode;
+ }
+ private int lastPressedKeyCode = 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);
+ }
+
+ @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);
+ super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar);
+ }
+
//----------------------------------------------------------------------
// Internals only
//