diff options
author | Sven Gothel <[email protected]> | 2011-11-18 09:14:08 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-11-18 09:14:08 +0100 |
commit | 3db4e89cb2c36f63c6d0a8f3450705d1ef3694b0 (patch) | |
tree | 193deaa032784afb368c3e097d3ec2031760dd38 /src | |
parent | 3b38957f36d4f89b85730755a41c00892ac70591 (diff) |
NEWT/AWT Focus Traversal / Deadlock Fix (Windows) ; Harmonized NEWT KeyListener handling (Bug 526)
NativeWindow:
- expose 'hasFocus()'
Window:
- 'protected enqueueRequestFocus(..)' -> 'public requestFocus(boolean wait)'
- New: 'setKeyboardFocusHandler(KeyListener)' allowing focus traversal co-op w/ covered TK (AWT)
WindowImpl:
- Impl Window changes (see above)
- Impl 'consumedTag' see commit 3b38957f36d4f89b85730755a41c00892ac70591
NewtCanvasAWT:
- FocusAction only removes the global AWT focus owner.
This fixes a deadlock on the Windows platform of AWT's native peer requestFocus impl,
since it's no more called at this point.
- NEW FocusTraversalKeyListener is set as the newtChild's KeyboardFocusHandler,
allowing traversal to the next/previous AWT component.
AWTParentWindowAdapter:
- focusGained(..) clears AWT focus and propagates focus to Newt child,
non blocking w/ 'requestFocus(false)' (see above)
KeyEvent:
- Document limitations of getKeyChar() (Bug 526)
MacWindow:
- only deliver keyChar on key Typed events, harmonizing platform behavior (Bug 526)
WindowsWindow:
- regenerate the keyCode for EVENT_KEY_TYPED (Bug 526)
X11Windows:
- complete keyCode mapping X11 -> Newt - X11KeySym2NewtVKey()
- only deliver keyChar on key Typed events, harmonizing platform behavior (Bug 526)
Tests:
- GearsES2: Make focus visible
- TestParentingFocusTraversal01AWT: unit test for keyboard focus traversal w/ NewtCanvasAWT
Diffstat (limited to 'src')
18 files changed, 611 insertions, 117 deletions
diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 76ac72953..e3ee85cf4 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -126,4 +126,7 @@ public interface NativeWindow extends NativeSurface { */ public Point getLocationOnScreen(Point point); + /** Returns true if this native window owns the focus, otherwise false. */ + boolean hasFocus(); + } 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 // diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 70c4c2ecf..29cb57bd0 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -76,7 +76,7 @@ static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; @@ -325,9 +325,9 @@ static jmethodID windowRepaintID = NULL; focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && - positionChangedID && focusChangedID && windowDestroyNotifyID && enqueueRequestFocusID && windowRepaintID) + positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) { return YES; } @@ -613,7 +613,7 @@ static jint mods2JavaMods(NSUInteger mods) return; } if (evType == EVENT_MOUSE_PRESSED) { - (*env)->CallVoidMethod(env, javaWindowObject, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, javaWindowObject, requestFocusID, JNI_FALSE); } NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index d60c40496..a62343d0e 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -116,7 +116,7 @@ static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); @@ -870,7 +870,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_LBUTTONDOWN: DBG_PRINT("*** WindowsWindow: LBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -890,7 +890,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_MBUTTONDOWN: DBG_PRINT("*** WindowsWindow: MBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -910,7 +910,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_RBUTTONDOWN: DBG_PRINT("*** WindowsWindow: RBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -1270,7 +1270,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); if (insetsChangedID == NULL || @@ -1285,7 +1285,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs enqueueKeyEventID == NULL || sendKeyEventID == NULL || focusActionID == NULL || - enqueueRequestFocusID == NULL) { + requestFocusID == NULL) { return JNI_FALSE; } BuildDynamicKeyMapTable(); diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index f14138a0a..8ff078931 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -105,34 +105,91 @@ static jint X11KeySym2NewtVKey(KeySym keySym) { if(IS_WITHIN(keySym,XK_F1,XK_F12)) return (keySym-XK_F1)+J_VK_F1; + if(IS_WITHIN(keySym,XK_KP_0,XK_KP_9)) + return (keySym-XK_KP_0)+J_VK_NUMPAD0; switch(keySym) { + case XK_Return: + case XK_KP_Enter: + return J_VK_ENTER; + case XK_BackSpace: + return J_VK_BACK_SPACE; + case XK_Tab: + case XK_KP_Tab: + case XK_ISO_Left_Tab: + return J_VK_TAB; + case XK_Cancel: + return J_VK_CANCEL; + case XK_Clear: + return J_VK_CLEAR; + case XK_Shift_L: + case XK_Shift_R: + return J_VK_SHIFT; + case XK_Control_L: + case XK_Control_R: + return J_VK_CONTROL; case XK_Alt_L: case XK_Alt_R: return J_VK_ALT; - + case XK_Pause: + return J_VK_PAUSE; + case XK_Caps_Lock: + return J_VK_CAPS_LOCK; + case XK_Escape: + return J_VK_ESCAPE; + case XK_space: + case XK_KP_Space: + return J_VK_SPACE; + case XK_Page_Up: + case XK_KP_Page_Up: + return J_VK_PAGE_UP; + case XK_Page_Down: + case XK_KP_Page_Down: + return J_VK_PAGE_DOWN; + case XK_End: + case XK_KP_End: + return J_VK_END; + case XK_Home: + case XK_KP_Home: + return J_VK_HOME; case XK_Left: + case XK_KP_Left: return J_VK_LEFT; - case XK_Right: - return J_VK_RIGHT; case XK_Up: + case XK_KP_Up: return J_VK_UP; + case XK_Right: + case XK_KP_Right: + return J_VK_RIGHT; case XK_Down: + case XK_KP_Down: return J_VK_DOWN; - case XK_Page_Up: - return J_VK_PAGE_UP; - case XK_Page_Down: - return J_VK_PAGE_DOWN; - case XK_Shift_L: - case XK_Shift_R: - return J_VK_SHIFT; - case XK_Control_L: - case XK_Control_R: - return J_VK_CONTROL; - case XK_Escape: - return J_VK_ESCAPE; + case XK_KP_Multiply: + return J_VK_MULTIPLY; + case XK_KP_Add: + return J_VK_ADD; + case XK_KP_Separator: + return J_VK_SEPARATOR; + case XK_KP_Subtract: + return J_VK_SUBTRACT; + case XK_KP_Decimal: + return J_VK_DECIMAL; + case XK_KP_Divide: + return J_VK_DIVIDE; case XK_Delete: + case XK_KP_Delete: return J_VK_DELETE; + case XK_Num_Lock: + return J_VK_NUM_LOCK; + case XK_Scroll_Lock: + return J_VK_SCROLL_LOCK; + case XK_Print: + return J_VK_PRINTSCREEN; + case XK_Insert: + case XK_KP_Insert: + return J_VK_INSERT; + case XK_Help: + return J_VK_HELP; } return keySym; } @@ -180,7 +237,7 @@ static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static jmethodID displayCompletedID = NULL; @@ -787,11 +844,12 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 keyChar=text[0]; XConvertCase(keySym, &lower_return, &upper_return); // always return upper case, set modifier masks (SHIFT, ..) - keySym = upper_return; - modifiers = X11InputState2NewtModifiers(evt.xkey.state); + keySym = X11KeySym2NewtVKey(upper_return); } else { keyChar=0; + keySym = X11KeySym2NewtVKey(keySym); } + modifiers = X11InputState2NewtModifiers(evt.xkey.state); break; case ButtonPress: @@ -806,7 +864,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 switch(evt.type) { case ButtonPress: - (*env)->CallVoidMethod(env, jwindow, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, modifiers, @@ -866,26 +924,26 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 case KeyPress: #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); #endif break; case KeyRelease: #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); + modifiers, keySym, (jchar) keyChar); #else (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); + modifiers, keySym, (jchar) -1); (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); + modifiers, keySym, (jchar) keyChar); #endif break; @@ -1480,7 +1538,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Window_initIDs0 sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); if (insetsChangedID == NULL || @@ -1496,7 +1554,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Window_initIDs0 enqueueKeyEventID == NULL || sendKeyEventID == NULL || focusActionID == NULL || - enqueueRequestFocusID == NULL) { + requestFocusID == NULL) { return JNI_FALSE; } return JNI_TRUE; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index 3fa61bf1d..63bbab66e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -34,6 +34,8 @@ import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.util.glsl.ShaderState; import java.nio.FloatBuffer; + +import javax.media.nativewindow.NativeWindow; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; @@ -244,8 +246,16 @@ public class GearsES2 implements GLEventListener { // Get the GL corresponding to the drawable we are animating GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + boolean hasFocus = false; + if(drawable.getNativeSurface() instanceof NativeWindow) { + hasFocus = ((NativeWindow)drawable.getNativeSurface()).hasFocus(); + } + if(hasFocus) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } else { + gl.glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + } + // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java index adc885191..664cab03b 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java @@ -39,10 +39,9 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.util.Point; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; + import com.jogamp.newt.Window; import com.jogamp.newt.awt.NewtCanvasAWT; -import com.jogamp.newt.event.WindowAdapter; -import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -53,6 +52,7 @@ public class TestCloseNewtAWT extends UITestCase { NewtCanvasAWT newtCanvas = null; JFrame frame = null; + @SuppressWarnings("serial") class MyCanvas extends NewtCanvasAWT { public MyCanvas(Window window) { super(window); @@ -78,7 +78,7 @@ public class TestCloseNewtAWT extends UITestCase { NativeWindow nw = MyCanvas.this.getNativeWindow(); if(null != nw) { Point p = nw.getLocationOnScreen(null); - System.err.println("MyCanvas On NEWT-EDT: position: "+p); + System.err.println("MyCanvas On NEWT-EDT: position: "+p); } else { System.err.println("MyCanvas On NEWT-EDT: position n/a, null NativeWindow"); } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java index 46748cb52..473f2f584 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java @@ -51,7 +51,11 @@ class NewtAWTReparentingKeyAdapter extends KeyAdapter { if(e.getKeyChar()=='d') { glWindow.setUndecorated(!glWindow.isUndecorated()); } else if(e.getKeyChar()=='f') { - glWindow.setFullscreen(!glWindow.isFullscreen()); + glWindow.setFullscreen(!glWindow.isFullscreen()); + } else if(e.getKeyChar()=='l') { + javax.media.nativewindow.util.Point p0 = newtCanvasAWT.getNativeWindow().getLocationOnScreen(null); + javax.media.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + System.err.println("NewtCanvasAWT position: "+p0+", "+p1); } else if(e.getKeyChar()=='p') { new Thread() { public void run() { diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java index 387d8a9a2..4a75d1343 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java @@ -66,11 +66,16 @@ public class TestParenting03AWT extends UITestCase { } @Test - public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { - testWindowParenting1AWTTwoNewtChilds(); + public void testWindowParenting1AWTOneNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(false); } - public void testWindowParenting1AWTTwoNewtChilds() throws InterruptedException, InvocationTargetException { + @Test + public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(true); + } + + public void testWindowParenting1AWT(boolean use2nd) throws InterruptedException, InvocationTargetException { final Frame frame1 = new Frame("AWT Parent Frame"); GLWindow glWindow1 = GLWindow.create(glCaps); glWindow1.setUpdateFPSFrames(1, null); @@ -84,7 +89,6 @@ public class TestParenting03AWT extends UITestCase { GLAnimatorControl animator1 = new Animator(glWindow1); animator1.start(); - final boolean use2nd = true; GLWindow glWindow2 = null; NewtCanvasAWT newtCanvasAWT2 = null; GLAnimatorControl animator2 = null; diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java new file mode 100644 index 000000000..cb94d8f02 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java @@ -0,0 +1,262 @@ +/** + * Copyright 2010 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.parenting; + +import java.lang.reflect.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.awt.AWTException; +import java.awt.AWTKeyStroke; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; + +import javax.media.opengl.*; + +import com.jogamp.opengl.util.Animator; +import com.jogamp.newt.*; +import com.jogamp.newt.opengl.*; +import com.jogamp.newt.awt.NewtCanvasAWT; + +import java.io.IOException; + +import com.jogamp.opengl.test.junit.util.*; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; + +public class TestParentingFocusTraversal01AWT extends UITestCase { + static Dimension glSize, fSize; + static int numFocus = 5; + static long durationPerTest = numFocus * 100; + static GLCapabilities glCaps; + static boolean manual = false; + + @BeforeClass + public static void initClass() { + glSize = new Dimension(200,200); + fSize = new Dimension(300,300); + glCaps = new GLCapabilities(null); + } + + @Test + public void testWindowParentingAWTFocusTraversal01() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(); + } + + public void testWindowParentingAWTFocusTraversal() throws InterruptedException, InvocationTargetException, AWTException { + Robot robot = new Robot(); + + // Bug 4908075 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4908075 + // Bug 6463168 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6463168 + { + final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + final AWTKeyStroke newBack = AWTKeyStroke.getAWTKeyStroke(java.awt.event.KeyEvent.VK_BACK_SPACE, 0, false); + Assert.assertNotNull(newBack); + final Set<AWTKeyStroke> bwdKeys2 = new HashSet<AWTKeyStroke>(bwdKeys); + bwdKeys2.add(newBack); + kfm.setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, bwdKeys2); + } + { + 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); + Iterator<AWTKeyStroke> iter; + for(iter = fwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.fwd-keys: "+iter.next()); + } + for(iter = bwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.bwd-keys: "+iter.next()); + } + } + + final Frame frame1 = new Frame("AWT Parent Frame"); + final Button bWest = new Button("WEST"); + final Button bEast = new Button("EAST"); + GLWindow glWindow1 = GLWindow.create(glCaps); + glWindow1.setUpdateFPSFrames(1, null); + final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setPreferredSize(glSize); + + // Test FocusAdapter + NEWTFocusAdapter glWindow1FA = new NEWTFocusAdapter("GLWindow1"); + glWindow1.addWindowListener(glWindow1FA); + AWTFocusAdapter bWestFA = new AWTFocusAdapter("WEST"); + bWest.addFocusListener(bWestFA); + AWTFocusAdapter bEastFA = new AWTFocusAdapter("EAST"); + bEast.addFocusListener(bEastFA); + + // Test KeyAdapter + NEWTKeyAdapter glWindow1KA = new NEWTKeyAdapter("GLWindow1"); + glWindow1.addKeyListener(glWindow1KA); + AWTKeyAdapter bWestKA = new AWTKeyAdapter("bWest"); + bWest.addKeyListener(bWestKA); + AWTKeyAdapter bEastKA = new AWTKeyAdapter("bEast"); + bEast.addKeyListener(bEastKA); + + // demo .. + GLEventListener demo1 = new GearsES2(1); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + GLAnimatorControl animator1 = new Animator(glWindow1); + animator1.start(); + + // make frame + frame1.setLayout(new BorderLayout()); + frame1.setLayout(new BorderLayout()); + frame1.add(bWest, BorderLayout.WEST); + frame1.add(newtCanvasAWT1, BorderLayout.CENTER); + frame1.add(bEast, BorderLayout.EAST); + + frame1.setLocation(0, 0); + frame1.setSize(fSize); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.validate(); + frame1.setVisible(true); + }}); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glWindow1, true)); + Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); + + Assert.assertEquals(true, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertNotNull(animator1.getThread()); + + if(manual) { + Thread.sleep(durationPerTest); + } else { + // + // initial focus on bWest + // + AWTRobotUtil.assertRequestFocusAndWait(robot, bWest, bWest, bWestFA, null); + Assert.assertEquals(true, bWestFA.focusGained()); + Thread.sleep(durationPerTest/numFocus); + + // + // forth + // + + // bWest -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, bWest, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // glWin -> bEast + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(bEast, bEastFA, glWindow1FA)); + Assert.assertEquals(true, bEastFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // + // back (using custom back traversal key 'backspace') + // + // bEast -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, bEast, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bEastFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bEastFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(bWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + } + + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertEquals(null, animator1.getThread()); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.dispose(); + } } ); + glWindow1.destroy(); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + 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]); + } else if(args[i].equals("-manual")) { + manual = true; + } + } + String tstname = TestParentingFocusTraversal01AWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} 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 7df8645de..131e3a714 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java @@ -67,7 +67,7 @@ public class AWTRobotUtil { int x0, y0; if(null!=comp) { - java.awt.Point p0 = comp.getLocationOnScreen(); + java.awt.Point p0 = comp.getLocationOnScreen(); java.awt.Rectangle r0 = comp.getBounds(); if( onTitleBarIfWindow && comp instanceof java.awt.Window) { java.awt.Window window = (java.awt.Window) comp; @@ -78,7 +78,7 @@ public class AWTRobotUtil { } x0 = (int) ( p0.getX() + r0.getWidth() / 2.0 + .5 ) ; } else { - javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); + javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); if( onTitleBarIfWindow ) { javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); p0.translate(win.getWidth()/2, insets.getTopHeight()/2); @@ -280,8 +280,8 @@ public class AWTRobotUtil { Assert.assertTrue("Did not gain focus", hasFocus); } - static int keyType(int i, Robot robot, int keyCode, - Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException + public static int keyType(int i, Robot robot, int keyCode, + Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException { int tc = 0; int j; @@ -293,13 +293,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" KC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null!=counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" KC1.1: "+counter); } robot.waitForIdle(); robot.keyPress(keyCode); robot.keyRelease(keyCode); if(DEBUG) { System.err.println(i+":"+j+" KC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null!=counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; @@ -355,13 +355,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" MC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null != counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" MC1.1: "+counter); } robot.waitForIdle(); robot.mousePress(mouseButton); robot.mouseRelease(mouseButton); if(DEBUG) { System.err.println(i+":"+j+" MC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null != counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; |