diff options
author | Sven Gothel <[email protected]> | 2011-11-19 19:32:00 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-11-19 19:32:00 +0100 |
commit | 8a985f8652151684063853f61e479d75d8203f07 (patch) | |
tree | 14acfc1230a974397e52803eefd6785f73be92c9 | |
parent | 2641d1cffebff214c4b37d7291627f76cc3bbe3f (diff) |
NEWT/AWT Focus traversal enhancement/fix (incl. OS X fixes)
- MacWindow/OffscreeSurface
- Exclude native NEWT window calls in case it's an offscreen surface
- MacWindow/DriverClearFocus
- Introduce driver detail DriverClearFocus interface
- OS X needs to clear the focus, before another TK (eg. AWT) can claim it's (native parent window focus)
- MacWindow/KeyCode:
- Move OS X keyCode utils to MacKeyUtil
- MacKeyUtil now uses OS X virtual key codes first, before matching keyChar -> keyCode
- NewtCanvasAWT
- Issue all AWT 'requestFocus()' on current thread,
Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus() impl.
- FocusAction directly issue action on Newt-EDT,
also request AWT focus if not having it (proper AWT traversal)
- Add an FocusPropertyChangeListener, detecting focus lost
to issue DriverClearFocus's clearFocus() if available.
- merge configureNewtChildInputEventHandler() code into configureNewtChild()
to simplify call tree.
- WindowImplAccess: Use getDelegatedWindow()
6 files changed, 533 insertions, 298 deletions
diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 9bde90bc3..f56a95537 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -31,10 +31,11 @@ package com.jogamp.newt.awt; import java.awt.AWTKeyStroke; import java.awt.Canvas; -import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.KeyboardFocusManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; @@ -43,7 +44,6 @@ import java.util.Set; import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.awt.AWTWindowClosingProtocol; import javax.swing.MenuSelectionManager; @@ -51,8 +51,9 @@ import javax.swing.MenuSelectionManager; import jogamp.nativewindow.awt.AWTMisc; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.newt.Debug; +import jogamp.newt.awt.NewtFactoryAWT; import jogamp.newt.awt.event.AWTParentWindowAdapter; -import jogamp.newt.awt.event.NewtFactoryAWT; +import jogamp.newt.driver.DriverClearFocus; import com.jogamp.newt.Display; import com.jogamp.newt.Window; @@ -70,13 +71,13 @@ import com.jogamp.newt.event.awt.AWTMouseAdapter; public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol { public static final boolean DEBUG = Debug.debug("Window"); - JAWTWindow jawtWindow = null; - Window newtChild = null; - boolean isNewtChildOnscreen = true; - int newtChildCloseOp; - AWTAdapter awtAdapter = null; - AWTAdapter awtMouseAdapter = null; - AWTAdapter awtKeyAdapter = null; + private JAWTWindow jawtWindow = null; + private Window newtChild = null; + private boolean isOnscreen = true; + private int newtChildCloseOp; + private AWTAdapter awtAdapter = null; + private AWTAdapter awtMouseAdapter = null; + private AWTAdapter awtKeyAdapter = null; private AWTWindowClosingProtocol awtWindowClosingProtocol = new AWTWindowClosingProtocol(this, new Runnable() { @@ -172,38 +173,27 @@ 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(DEBUG) { + System.err.println("NewtCanvasAWT.FocusAction: "+Display.getThreadName()+", isOnscreen "+isOnscreen+", hasFocus "+hasFocus()); } - if ( EventQueue.isDispatchThread() ) { - focusActionImpl.run(); - } else { - try { - EventQueue.invokeAndWait(focusActionImpl); - } catch (Exception e) { - throw new NativeWindowException(e); - } + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + if(!hasFocus()) { + // Acquire the AWT focus 1st for proper AWT traversal + NewtCanvasAWT.super.requestFocus(); } - return focusActionImpl.result; - } - - class FocusActionImpl implements Runnable { - public final boolean result = false; // NEWT shall always proceed requesting the native focus - public void run() { - if(DEBUG) { - System.err.println("FocusActionImpl.run() "+Display.getThreadName()); - } + if(isOnscreen) { + // Remove the AWT focus in favor of the native NEWT focus KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } + return false; // NEWT shall proceed requesting the native focus } - FocusActionImpl focusActionImpl = new FocusActionImpl(); } - FocusAction focusAction = new FocusAction(); + private FocusAction focusAction = new FocusAction(); WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent arg0) { - MenuSelectionManager.defaultManager().clearSelectedPath(); + MenuSelectionManager.defaultManager().clearSelectedPath(); } }; @@ -223,37 +213,66 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } } - void handleKey(KeyEvent e, boolean onRelease) { - final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(e.getKeyCode(), e.getModifiers(), onRelease); + void handleKey(KeyEvent evt, boolean onRelease) { + if(null == keyboardFocusManager) { + throw new InternalError("XXX"); + } + final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(evt.getKeyCode(), evt.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); + final Set<AWTKeyStroke> fwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + final Set<AWTKeyStroke> bwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); if(fwdKeys.contains(ks)) { if(DEBUG) { - System.err.println("FTKL.handleKey (fwd): "+ks); + System.err.println("NewtCanvasAWT.focusKey (fwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); } - kfm.focusNextComponent(NewtCanvasAWT.this); + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocus(); suppress = true; } else if(bwdKeys.contains(ks)) { if(DEBUG) { - System.err.println("FTKL.handleKey (bwd): "+ks); + System.err.println("NewtCanvasAWT.focusKey (bwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); } - kfm.focusPreviousComponent(NewtCanvasAWT.this); + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocusBackward(); 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); + evt.setAttachment(InputEvent.consumedTag); + } + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey: XXX: "+ks); } } } - FocusTraversalKeyListener newtFocusTraversalKeyListener = null; - + private final FocusTraversalKeyListener newtFocusTraversalKeyListener = new FocusTraversalKeyListener(); + + class FocusPropertyChangeListener implements PropertyChangeListener { + public void propertyChange(PropertyChangeEvent evt) { + final Object oldF = evt.getOldValue(); + final Object newF = evt.getNewValue(); + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: "+evt.getPropertyName()+", src "+evt.getSource()+", "+oldF+" -> "+newF); + } + if(oldF == NewtCanvasAWT.this && newF == null) { + // focus traversal to NEWT - NOP + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: NEWT focus traversal"); + } + } else if(null != newF && newF != NewtCanvasAWT.this) { + // focus traversal to another AWT component + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: lost focus - clear focus"); + } + if(newtChild.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)newtChild.getDelegatedWindow()).clearFocus(); + } + } + } + } + private final FocusPropertyChangeListener focusPropertyChangeListener = new FocusPropertyChangeListener(); + private volatile KeyboardFocusManager keyboardFocusManager = null; + /** sets a new NEWT child, provoking reparenting. */ private NewtCanvasAWT setNEWTChild(Window child) { if(newtChild!=child) { @@ -284,21 +303,6 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto return awtWindowClosingProtocol.setDefaultCloseOperation(op); } - private final void configureNewtChildInputEventHandler() { - if(null==awtMouseAdapter && null != newtChild.getGraphicsConfiguration()) { - isNewtChildOnscreen = newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); - 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); - } - } - } - /* package */ void configureNewtChild(boolean attach) { if(null!=awtAdapter) { awtAdapter.removeFrom(this); @@ -312,18 +316,33 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto awtKeyAdapter.removeFrom(this); awtKeyAdapter = null; } - if(null!=newtFocusTraversalKeyListener) { - newtChild.setKeyboardFocusHandler(null); - newtFocusTraversalKeyListener = null; - } + newtChild.setKeyboardFocusHandler(null); + if(null != keyboardFocusManager) { + keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener); + keyboardFocusManager = null; + } if( null != newtChild ) { if(attach) { + if(null == jawtWindow.getGraphicsConfiguration()) { + throw new InternalError("XXX"); + } + isOnscreen = jawtWindow.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this); newtChild.addWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(focusAction); // enable AWT focus traversal newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingProtocol.DO_NOTHING_ON_CLOSE); awtWindowClosingProtocol.addClosingListenerOneShot(); + keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + keyboardFocusManager.addPropertyChangeListener("focusOwner", focusPropertyChangeListener); + if(isOnscreen) { + // onscreen newt child needs to fwd AWT focus + newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener); + } else { + // offscreen newt child requires AWT to fwd AWT key/mouse event + awtMouseAdapter = new AWTMouseAdapter(newtChild).addTo(this); + awtKeyAdapter = new AWTKeyAdapter(newtChild).addTo(this); + } } else { newtChild.removeWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(null); @@ -447,7 +466,6 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto public void paint(Graphics g) { awtWindowClosingProtocol.addClosingListenerOneShot(); if(null!=newtChild) { - configureNewtChildInputEventHandler(); newtChild.windowRepaint(0, 0, getWidth(), getHeight()); } } @@ -455,7 +473,6 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto public void update(Graphics g) { awtWindowClosingProtocol.addClosingListenerOneShot(); if(null!=newtChild) { - configureNewtChildInputEventHandler(); newtChild.windowRepaint(0, 0, getWidth(), getHeight()); } } @@ -463,7 +480,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto private final void requestFocusNEWTChild() { if(null!=newtChild) { newtChild.setFocusAction(null); - if(isNewtChildOnscreen) { + if(isOnscreen) { KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } newtChild.requestFocus(); diff --git a/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java new file mode 100644 index 000000000..4d23c4ea8 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java @@ -0,0 +1,12 @@ +package jogamp.newt.driver; + +/** + * Interface tagging driver feature / requirement of clearing the focus. + * <p> + * Some drivers require a programmatic {@link #clearFocus()} when traversing the focus. + * </p> + */ +public interface DriverClearFocus { + /** Programmatic clear the focus */ + void clearFocus(); +} diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java new file mode 100644 index 000000000..46625f7a9 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java @@ -0,0 +1,262 @@ +package jogamp.newt.driver.macosx; + +import com.jogamp.newt.event.KeyEvent; + +public class MacKeyUtil { + + // KeyCodes (independent) + private static final int kVK_Return = 0x24; + private static final int kVK_Tab = 0x30; + private static final int kVK_Space = 0x31; + private static final int kVK_Delete = 0x33; + private static final int kVK_Escape = 0x35; + private static final int kVK_Command = 0x37; + private static final int kVK_Shift = 0x38; + private static final int kVK_CapsLock = 0x39; + private static final int kVK_Option = 0x3A; + private static final int kVK_Control = 0x3B; + private static final int kVK_RightShift = 0x3C; + private static final int kVK_RightOption = 0x3D; + private static final int kVK_RightControl = 0x3E; + private static final int kVK_Function = 0x3F; + private static final int kVK_F17 = 0x40; + private static final int kVK_VolumeUp = 0x48; + private static final int kVK_VolumeDown = 0x49; + private static final int kVK_Mute = 0x4A; + private static final int kVK_F18 = 0x4F; + private static final int kVK_F19 = 0x50; + private static final int kVK_F20 = 0x5A; + private static final int kVK_F5 = 0x60; + private static final int kVK_F6 = 0x61; + private static final int kVK_F7 = 0x62; + private static final int kVK_F3 = 0x63; + private static final int kVK_F8 = 0x64; + private static final int kVK_F9 = 0x65; + private static final int kVK_F11 = 0x67; + private static final int kVK_F13 = 0x69; + private static final int kVK_F16 = 0x6A; + private static final int kVK_F14 = 0x6B; + private static final int kVK_F10 = 0x6D; + private static final int kVK_F12 = 0x6F; + private static final int kVK_F15 = 0x71; + private static final int kVK_Help = 0x72; + private static final int kVK_Home = 0x73; + private static final int kVK_PageUp = 0x74; + private static final int kVK_ForwardDelete = 0x75; + private static final int kVK_F4 = 0x76; + private static final int kVK_End = 0x77; + private static final int kVK_F2 = 0x78; + private static final int kVK_PageDown = 0x79; + private static final int kVK_F1 = 0x7A; + private static final int kVK_LeftArrow = 0x7B; + private static final int kVK_RightArrow = 0x7C; + private static final int kVK_DownArrow = 0x7D; + private static final int kVK_UpArrow = 0x7E; + + // Key constants handled differently on Mac OS X than other platforms + private static final char NSUpArrowFunctionKey = 0xF700; + private static final char NSDownArrowFunctionKey = 0xF701; + private static final char NSLeftArrowFunctionKey = 0xF702; + private static final char NSRightArrowFunctionKey = 0xF703; + private static final char NSF1FunctionKey = 0xF704; + private static final char NSF2FunctionKey = 0xF705; + private static final char NSF3FunctionKey = 0xF706; + private static final char NSF4FunctionKey = 0xF707; + private static final char NSF5FunctionKey = 0xF708; + private static final char NSF6FunctionKey = 0xF709; + private static final char NSF7FunctionKey = 0xF70A; + private static final char NSF8FunctionKey = 0xF70B; + private static final char NSF9FunctionKey = 0xF70C; + private static final char NSF10FunctionKey = 0xF70D; + private static final char NSF11FunctionKey = 0xF70E; + private static final char NSF12FunctionKey = 0xF70F; + private static final char NSF13FunctionKey = 0xF710; + private static final char NSF14FunctionKey = 0xF711; + private static final char NSF15FunctionKey = 0xF712; + private static final char NSF16FunctionKey = 0xF713; + private static final char NSF17FunctionKey = 0xF714; + private static final char NSF18FunctionKey = 0xF715; + private static final char NSF19FunctionKey = 0xF716; + private static final char NSF20FunctionKey = 0xF717; + private static final char NSF21FunctionKey = 0xF718; + private static final char NSF22FunctionKey = 0xF719; + private static final char NSF23FunctionKey = 0xF71A; + private static final char NSF24FunctionKey = 0xF71B; + private static final char NSF25FunctionKey = 0xF71C; + private static final char NSF26FunctionKey = 0xF71D; + private static final char NSF27FunctionKey = 0xF71E; + private static final char NSF28FunctionKey = 0xF71F; + private static final char NSF29FunctionKey = 0xF720; + private static final char NSF30FunctionKey = 0xF721; + private static final char NSF31FunctionKey = 0xF722; + private static final char NSF32FunctionKey = 0xF723; + private static final char NSF33FunctionKey = 0xF724; + private static final char NSF34FunctionKey = 0xF725; + private static final char NSF35FunctionKey = 0xF726; + private static final char NSInsertFunctionKey = 0xF727; + private static final char NSDeleteFunctionKey = 0xF728; + private static final char NSHomeFunctionKey = 0xF729; + private static final char NSBeginFunctionKey = 0xF72A; + private static final char NSEndFunctionKey = 0xF72B; + private static final char NSPageUpFunctionKey = 0xF72C; + private static final char NSPageDownFunctionKey = 0xF72D; + private static final char NSPrintScreenFunctionKey = 0xF72E; + private static final char NSScrollLockFunctionKey = 0xF72F; + private static final char NSPauseFunctionKey = 0xF730; + private static final char NSSysReqFunctionKey = 0xF731; + private static final char NSBreakFunctionKey = 0xF732; + private static final char NSResetFunctionKey = 0xF733; + private static final char NSStopFunctionKey = 0xF734; + private static final char NSMenuFunctionKey = 0xF735; + private static final char NSUserFunctionKey = 0xF736; + private static final char NSSystemFunctionKey = 0xF737; + private static final char NSPrintFunctionKey = 0xF738; + private static final char NSClearLineFunctionKey = 0xF739; + private static final char NSClearDisplayFunctionKey = 0xF73A; + private static final char NSInsertLineFunctionKey = 0xF73B; + private static final char NSDeleteLineFunctionKey = 0xF73C; + private static final char NSInsertCharFunctionKey = 0xF73D; + private static final char NSDeleteCharFunctionKey = 0xF73E; + private static final char NSPrevFunctionKey = 0xF73F; + private static final char NSNextFunctionKey = 0xF740; + private static final char NSSelectFunctionKey = 0xF741; + private static final char NSExecuteFunctionKey = 0xF742; + private static final char NSUndoFunctionKey = 0xF743; + private static final char NSRedoFunctionKey = 0xF744; + private static final char NSFindFunctionKey = 0xF745; + private static final char NSHelpFunctionKey = 0xF746; + private static final char NSModeSwitchFunctionKey = 0xF747; + + static int validateKeyCode(int keyCode, char keyChar) { + // OS X Virtual Keycodes + switch(keyCode) { + case kVK_Return: return KeyEvent.VK_ENTER; + case kVK_Tab: return KeyEvent.VK_TAB; + case kVK_Space: return KeyEvent.VK_SPACE; + case kVK_Delete: return KeyEvent.VK_BACK_SPACE; + case kVK_Escape: return KeyEvent.VK_ESCAPE; + case kVK_Command: return KeyEvent.VK_ALT; + case kVK_Shift: return KeyEvent.VK_SHIFT; + case kVK_CapsLock: return KeyEvent.VK_CAPS_LOCK; + case kVK_Option: return KeyEvent.VK_WINDOWS; + case kVK_Control: return KeyEvent.VK_CONTROL; + case kVK_RightShift: return KeyEvent.VK_SHIFT; + case kVK_RightOption: return KeyEvent.VK_WINDOWS; + case kVK_RightControl: return KeyEvent.VK_CONTROL; + // case kVK_Function: return KeyEvent.VK_F; + case kVK_F17: return KeyEvent.VK_F17; + // case kVK_VolumeUp: + // case kVK_VolumeDown: + // case kVK_Mute: + case kVK_F18: return KeyEvent.VK_F18; + case kVK_F19: return KeyEvent.VK_F19; + case kVK_F20: return KeyEvent.VK_F20; + case kVK_F5: return KeyEvent.VK_F5; + case kVK_F6: return KeyEvent.VK_F6; + case kVK_F7: return KeyEvent.VK_F7; + case kVK_F3: return KeyEvent.VK_F3; + case kVK_F8: return KeyEvent.VK_F8; + case kVK_F9: return KeyEvent.VK_F9; + case kVK_F11: return KeyEvent.VK_F11; + case kVK_F13: return KeyEvent.VK_F13; + case kVK_F16: return KeyEvent.VK_F16; + case kVK_F14: return KeyEvent.VK_F14; + case kVK_F10: return KeyEvent.VK_F10; + case kVK_F12: return KeyEvent.VK_F12; + case kVK_F15: return KeyEvent.VK_F15; + case kVK_Help: return KeyEvent.VK_HELP; + case kVK_Home: return KeyEvent.VK_HOME; + case kVK_PageUp: return KeyEvent.VK_PAGE_UP; + case kVK_ForwardDelete: return KeyEvent.VK_DELETE; + case kVK_F4: return KeyEvent.VK_F4; + case kVK_End: return KeyEvent.VK_END; + case kVK_F2: return KeyEvent.VK_F2; + case kVK_PageDown: return KeyEvent.VK_PAGE_DOWN; + case kVK_F1: return KeyEvent.VK_F1; + case kVK_LeftArrow: return KeyEvent.VK_LEFT; + case kVK_RightArrow: return KeyEvent.VK_RIGHT; + case kVK_DownArrow: return KeyEvent.VK_DOWN; + case kVK_UpArrow: return KeyEvent.VK_UP; + } + + if (keyChar == '\r') { + // Turn these into \n + return KeyEvent.VK_ENTER; + } + + if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { + switch (keyChar) { + case NSUpArrowFunctionKey: return KeyEvent.VK_UP; + case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; + case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; + case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; + case NSF1FunctionKey: return KeyEvent.VK_F1; + case NSF2FunctionKey: return KeyEvent.VK_F2; + case NSF3FunctionKey: return KeyEvent.VK_F3; + case NSF4FunctionKey: return KeyEvent.VK_F4; + case NSF5FunctionKey: return KeyEvent.VK_F5; + case NSF6FunctionKey: return KeyEvent.VK_F6; + case NSF7FunctionKey: return KeyEvent.VK_F7; + case NSF8FunctionKey: return KeyEvent.VK_F8; + case NSF9FunctionKey: return KeyEvent.VK_F9; + case NSF10FunctionKey: return KeyEvent.VK_F10; + case NSF11FunctionKey: return KeyEvent.VK_F11; + case NSF12FunctionKey: return KeyEvent.VK_F12; + case NSF13FunctionKey: return KeyEvent.VK_F13; + case NSF14FunctionKey: return KeyEvent.VK_F14; + case NSF15FunctionKey: return KeyEvent.VK_F15; + case NSF16FunctionKey: return KeyEvent.VK_F16; + case NSF17FunctionKey: return KeyEvent.VK_F17; + case NSF18FunctionKey: return KeyEvent.VK_F18; + case NSF19FunctionKey: return KeyEvent.VK_F19; + case NSF20FunctionKey: return KeyEvent.VK_F20; + case NSF21FunctionKey: return KeyEvent.VK_F21; + case NSF22FunctionKey: return KeyEvent.VK_F22; + case NSF23FunctionKey: return KeyEvent.VK_F23; + case NSF24FunctionKey: return KeyEvent.VK_F24; + case NSInsertFunctionKey: return KeyEvent.VK_INSERT; + case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; + case NSHomeFunctionKey: return KeyEvent.VK_HOME; + case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; + case NSEndFunctionKey: return KeyEvent.VK_END; + case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; + case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; + case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; + case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; + case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; + // Not handled: + // NSSysReqFunctionKey + // NSBreakFunctionKey + // NSResetFunctionKey + case NSStopFunctionKey: return KeyEvent.VK_STOP; + // Not handled: + // NSMenuFunctionKey + // NSUserFunctionKey + // NSSystemFunctionKey + // NSPrintFunctionKey + // NSClearLineFunctionKey + // NSClearDisplayFunctionKey + // NSInsertLineFunctionKey + // NSDeleteLineFunctionKey + // NSInsertCharFunctionKey + // NSDeleteCharFunctionKey + // NSPrevFunctionKey + // NSNextFunctionKey + // NSSelectFunctionKey + // NSExecuteFunctionKey + // NSUndoFunctionKey + // NSRedoFunctionKey + // NSFindFunctionKey + // NSHelpFunctionKey + // NSModeSwitchFunctionKey + default: break; + } + } + + if ('a' <= keyChar && keyChar <= 'z') { + return KeyEvent.VK_A + ( keyChar - 'a' ) ; + } + + return (int) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's) + } +} diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index e1b2ef87d..1076c5aac 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -44,100 +44,12 @@ import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import jogamp.newt.WindowImpl; +import jogamp.newt.driver.DriverClearFocus; import com.jogamp.newt.event.KeyEvent; -public class MacWindow extends WindowImpl implements SurfaceChangeable { +public class MacWindow extends WindowImpl implements SurfaceChangeable, DriverClearFocus { - // Window styles - private static final int NSBorderlessWindowMask = 0; - private static final int NSTitledWindowMask = 1 << 0; - private static final int NSClosableWindowMask = 1 << 1; - private static final int NSMiniaturizableWindowMask = 1 << 2; - private static final int NSResizableWindowMask = 1 << 3; - - // Window backing store types - private static final int NSBackingStoreRetained = 0; - private static final int NSBackingStoreNonretained = 1; - private static final int NSBackingStoreBuffered = 2; - - // Key constants handled differently on Mac OS X than other platforms - private static final int NSUpArrowFunctionKey = 0xF700; - private static final int NSDownArrowFunctionKey = 0xF701; - private static final int NSLeftArrowFunctionKey = 0xF702; - private static final int NSRightArrowFunctionKey = 0xF703; - private static final int NSF1FunctionKey = 0xF704; - private static final int NSF2FunctionKey = 0xF705; - private static final int NSF3FunctionKey = 0xF706; - private static final int NSF4FunctionKey = 0xF707; - private static final int NSF5FunctionKey = 0xF708; - private static final int NSF6FunctionKey = 0xF709; - private static final int NSF7FunctionKey = 0xF70A; - private static final int NSF8FunctionKey = 0xF70B; - private static final int NSF9FunctionKey = 0xF70C; - private static final int NSF10FunctionKey = 0xF70D; - private static final int NSF11FunctionKey = 0xF70E; - private static final int NSF12FunctionKey = 0xF70F; - private static final int NSF13FunctionKey = 0xF710; - private static final int NSF14FunctionKey = 0xF711; - private static final int NSF15FunctionKey = 0xF712; - private static final int NSF16FunctionKey = 0xF713; - private static final int NSF17FunctionKey = 0xF714; - private static final int NSF18FunctionKey = 0xF715; - private static final int NSF19FunctionKey = 0xF716; - private static final int NSF20FunctionKey = 0xF717; - private static final int NSF21FunctionKey = 0xF718; - private static final int NSF22FunctionKey = 0xF719; - private static final int NSF23FunctionKey = 0xF71A; - private static final int NSF24FunctionKey = 0xF71B; - private static final int NSF25FunctionKey = 0xF71C; - private static final int NSF26FunctionKey = 0xF71D; - private static final int NSF27FunctionKey = 0xF71E; - private static final int NSF28FunctionKey = 0xF71F; - private static final int NSF29FunctionKey = 0xF720; - private static final int NSF30FunctionKey = 0xF721; - private static final int NSF31FunctionKey = 0xF722; - private static final int NSF32FunctionKey = 0xF723; - private static final int NSF33FunctionKey = 0xF724; - private static final int NSF34FunctionKey = 0xF725; - private static final int NSF35FunctionKey = 0xF726; - private static final int NSInsertFunctionKey = 0xF727; - private static final int NSDeleteFunctionKey = 0xF728; - private static final int NSHomeFunctionKey = 0xF729; - private static final int NSBeginFunctionKey = 0xF72A; - private static final int NSEndFunctionKey = 0xF72B; - private static final int NSPageUpFunctionKey = 0xF72C; - private static final int NSPageDownFunctionKey = 0xF72D; - private static final int NSPrintScreenFunctionKey = 0xF72E; - private static final int NSScrollLockFunctionKey = 0xF72F; - private static final int NSPauseFunctionKey = 0xF730; - private static final int NSSysReqFunctionKey = 0xF731; - private static final int NSBreakFunctionKey = 0xF732; - private static final int NSResetFunctionKey = 0xF733; - private static final int NSStopFunctionKey = 0xF734; - private static final int NSMenuFunctionKey = 0xF735; - private static final int NSUserFunctionKey = 0xF736; - private static final int NSSystemFunctionKey = 0xF737; - private static final int NSPrintFunctionKey = 0xF738; - private static final int NSClearLineFunctionKey = 0xF739; - private static final int NSClearDisplayFunctionKey = 0xF73A; - private static final int NSInsertLineFunctionKey = 0xF73B; - private static final int NSDeleteLineFunctionKey = 0xF73C; - private static final int NSInsertCharFunctionKey = 0xF73D; - private static final int NSDeleteCharFunctionKey = 0xF73E; - private static final int NSPrevFunctionKey = 0xF73F; - private static final int NSNextFunctionKey = 0xF740; - private static final int NSSelectFunctionKey = 0xF741; - private static final int NSExecuteFunctionKey = 0xF742; - private static final int NSUndoFunctionKey = 0xF743; - private static final int NSRedoFunctionKey = 0xF744; - private static final int NSFindFunctionKey = 0xF745; - private static final int NSHelpFunctionKey = 0xF746; - private static final int NSModeSwitchFunctionKey = 0xF747; - - private volatile long surfaceHandle; - private long sscSurfaceHandle; - static { MacDisplay.initSingleton(); } @@ -177,12 +89,17 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { @Override protected int lockSurfaceImpl() { - return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + if(!isOffscreenInstance) { + return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + } + return LOCK_SUCCESS; } @Override protected void unlockSurfaceImpl() { - unlockSurface0(getWindowHandle()); + if(!isOffscreenInstance) { + unlockSurface0(getWindowHandle()); + } } @Override @@ -215,28 +132,43 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { } protected void requestFocusImpl(boolean force) { - requestFocus0(getWindowHandle(), force); + if(!isOffscreenInstance) { + requestFocus0(getWindowHandle(), force); + } else { + focusChanged(false, true); + } + } + + public final void clearFocus() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: clearFocus() - requestFocusParent, isOffscreenInstance "+isOffscreenInstance); + } + if(!isOffscreenInstance) { + requestFocusParent0(getWindowHandle()); + } else { + focusChanged(false, false); + } } protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { final PointImmutable pS = position2TopLevel(new Point(x, y)); - final boolean offscreenInstance = 0 != sscSurfaceHandle || isOffscreenInstance(this, this.getParent()); + isOffscreenInstance = 0 != sscSurfaceHandle || isOffscreenInstance(this, this.getParent()); if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+ - ", offscreenInstance "+offscreenInstance+ + ", offscreenInstance "+isOffscreenInstance+ ", "+getReconfigureFlagsAsString(null, flags)); } if( getWindowHandle() == 0 ) { if( 0 != ( FLAG_IS_VISIBLE & flags) ) { - createWindow(offscreenInstance, false, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + createWindow(isOffscreenInstance, false, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); // no native event .. visibleChanged(true, true); } /* else { ?? } */ } else { if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) { - if ( !offscreenInstance ) { + if ( !isOffscreenInstance ) { orderOut0(getWindowHandle()); } // no native event .. @@ -245,27 +177,32 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { if( 0 != ( FLAG_CHANGE_DECORATION & flags) || 0 != ( FLAG_CHANGE_PARENTING & flags) || 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { - createWindow(offscreenInstance, true, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + // FIXME: need solution for fullscreen .. + createWindow(isOffscreenInstance, true, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; } } if(x>=0 && y>=0) { - setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + if( !isOffscreenInstance ) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + } // FIXME: need solution for position .. // no native event (fullscreen, some reparenting) positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation } if(width>0 && height>0) { - setContentSize0(getWindowHandle(), width, height); + if( !isOffscreenInstance ) { + setContentSize0(getWindowHandle(), width, height); + } // FIXME: need solution for size .. // no native event (fullscreen, some reparenting) sizeChanged(true, width, height, false); // incl. validation (incl. repositioning) } if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 != ( FLAG_IS_VISIBLE & flags) ) { - if( !offscreenInstance ) { + if( !isOffscreenInstance ) { orderFront0(getWindowHandle()); } // no native event .. visibleChanged(true, true); } - if( !offscreenInstance ) { + if( !isOffscreenInstance ) { setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags)); } } @@ -273,7 +210,8 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { } protected Point getLocationOnScreenImpl(int x, int y) { - return (Point) getLocationOnScreen0(getWindowHandle(), x, y); + return position2TopLevel(new Point(x, y)); // allows offscreen .. + // return (Point) getLocationOnScreen0(getWindowHandle(), x, y); } protected void updateInsetsImpl(Insets insets) { @@ -296,25 +234,33 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - return setPointerVisible0(getWindowHandle(), pointerVisible); + if( !isOffscreenInstance ) { + return setPointerVisible0(getWindowHandle(), pointerVisible); + } // else FIXME: need solution + return false; } @Override protected boolean confinePointerImpl(final boolean confine) { - return confinePointer0(getWindowHandle(), confine); + if( !isOffscreenInstance ) { + return confinePointer0(getWindowHandle(), confine); + } // else FIXME: need solution + return false; } @Override protected void warpPointerImpl(final int x, final int y) { - warpPointer0(getWindowHandle(), x, y); + if( !isOffscreenInstance ) { + warpPointer0(getWindowHandle(), x, y); + } // else FIXME: need solution } @Override public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - final int keyCode2 = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: "+keyChar+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(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); @@ -324,8 +270,8 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - final int keyCode2 = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: "+keyChar+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + 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)); // 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,89 +281,6 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { // Internals only // - private char convertKeyChar(char keyChar) { - if (keyChar == '\r') { - // Turn these into \n - return '\n'; - } - - if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { - switch (keyChar) { - case NSUpArrowFunctionKey: return KeyEvent.VK_UP; - case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; - case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; - case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; - case NSF1FunctionKey: return KeyEvent.VK_F1; - case NSF2FunctionKey: return KeyEvent.VK_F2; - case NSF3FunctionKey: return KeyEvent.VK_F3; - case NSF4FunctionKey: return KeyEvent.VK_F4; - case NSF5FunctionKey: return KeyEvent.VK_F5; - case NSF6FunctionKey: return KeyEvent.VK_F6; - case NSF7FunctionKey: return KeyEvent.VK_F7; - case NSF8FunctionKey: return KeyEvent.VK_F8; - case NSF9FunctionKey: return KeyEvent.VK_F9; - case NSF10FunctionKey: return KeyEvent.VK_F10; - case NSF11FunctionKey: return KeyEvent.VK_F11; - case NSF12FunctionKey: return KeyEvent.VK_F12; - case NSF13FunctionKey: return KeyEvent.VK_F13; - case NSF14FunctionKey: return KeyEvent.VK_F14; - case NSF15FunctionKey: return KeyEvent.VK_F15; - case NSF16FunctionKey: return KeyEvent.VK_F16; - case NSF17FunctionKey: return KeyEvent.VK_F17; - case NSF18FunctionKey: return KeyEvent.VK_F18; - case NSF19FunctionKey: return KeyEvent.VK_F19; - case NSF20FunctionKey: return KeyEvent.VK_F20; - case NSF21FunctionKey: return KeyEvent.VK_F21; - case NSF22FunctionKey: return KeyEvent.VK_F22; - case NSF23FunctionKey: return KeyEvent.VK_F23; - case NSF24FunctionKey: return KeyEvent.VK_F24; - case NSInsertFunctionKey: return KeyEvent.VK_INSERT; - case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; - case NSHomeFunctionKey: return KeyEvent.VK_HOME; - case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; - case NSEndFunctionKey: return KeyEvent.VK_END; - case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; - case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; - case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; - case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; - case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; - // Not handled: - // NSSysReqFunctionKey - // NSBreakFunctionKey - // NSResetFunctionKey - case NSStopFunctionKey: return KeyEvent.VK_STOP; - // Not handled: - // NSMenuFunctionKey - // NSUserFunctionKey - // NSSystemFunctionKey - // NSPrintFunctionKey - // NSClearLineFunctionKey - // NSClearDisplayFunctionKey - // NSInsertLineFunctionKey - // NSDeleteLineFunctionKey - // NSInsertCharFunctionKey - // NSDeleteCharFunctionKey - // NSPrevFunctionKey - // NSNextFunctionKey - // NSSelectFunctionKey - // NSExecuteFunctionKey - // NSUndoFunctionKey - // NSRedoFunctionKey - // NSFindFunctionKey - // NSHelpFunctionKey - // NSModeSwitchFunctionKey - default: break; - } - } - - // NSEvent's charactersIgnoringModifiers doesn't ignore the shift key - if (keyChar >= 'a' && keyChar <= 'z') { - return Character.toUpperCase(keyChar); - } - - return keyChar; - } - private void createWindow(final boolean offscreenInstance, final boolean recreate, final PointImmutable pS, final int width, final int height, final boolean fullscreen) { @@ -506,6 +369,7 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { private native boolean lockSurface0(long window); private native void unlockSurface0(long window); private native void requestFocus0(long window, boolean force); + private native void requestFocusParent0(long window); /** in case of a child window, it actually only issues orderBack(..) */ private native void orderOut0(long window); private native void orderFront0(long window); @@ -520,4 +384,21 @@ public class MacWindow extends WindowImpl implements SurfaceChangeable { private static native boolean setPointerVisible0(long windowHandle, boolean visible); private static native boolean confinePointer0(long windowHandle, boolean confine); private static native void warpPointer0(long windowHandle, int x, int y); + + // Window styles + private static final int NSBorderlessWindowMask = 0; + private static final int NSTitledWindowMask = 1 << 0; + private static final int NSClosableWindowMask = 1 << 1; + private static final int NSMiniaturizableWindowMask = 1 << 2; + private static final int NSResizableWindowMask = 1 << 3; + + // Window backing store types + private static final int NSBackingStoreRetained = 0; + private static final int NSBackingStoreNonretained = 1; + private static final int NSBackingStoreBuffered = 2; + + private volatile long surfaceHandle; + private long sscSurfaceHandle; + private boolean isOffscreenInstance; + } 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 index cb94d8f02..75b94f203 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java @@ -52,15 +52,19 @@ import com.jogamp.opengl.util.Animator; import com.jogamp.newt.*; import com.jogamp.newt.opengl.*; import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; import java.io.IOException; +import jogamp.newt.driver.DriverClearFocus; + 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 int numFocus = 8; static long durationPerTest = numFocus * 100; static GLCapabilities glCaps; static boolean manual = false; @@ -73,11 +77,16 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { } @Test - public void testWindowParentingAWTFocusTraversal01() throws InterruptedException, InvocationTargetException, AWTException { - testWindowParentingAWTFocusTraversal(); + public void testWindowParentingAWTFocusTraversal01Onscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(true); } - public void testWindowParentingAWTFocusTraversal() throws InterruptedException, InvocationTargetException, AWTException { + @Test + public void testWindowParentingAWTFocusTraversal02Offscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(false); + } + + public void testWindowParentingAWTFocusTraversal(boolean onscreen) throws InterruptedException, InvocationTargetException, AWTException { Robot robot = new Robot(); // Bug 4908075 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4908075 @@ -105,43 +114,73 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { } 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); + final Button cWest = new Button("WEST"); + final Button cEast = new Button("EAST"); + final GLWindow glWindow1 = GLWindow.create(glCaps); glWindow1.setUpdateFPSFrames(1, null); final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); newtCanvasAWT1.setPreferredSize(glSize); + newtCanvasAWT1.setShallUseOffscreenLayer(!onscreen); + newtCanvasAWT1.setFocusable(true); // Test FocusAdapter NEWTFocusAdapter glWindow1FA = new NEWTFocusAdapter("GLWindow1"); glWindow1.addWindowListener(glWindow1FA); AWTFocusAdapter bWestFA = new AWTFocusAdapter("WEST"); - bWest.addFocusListener(bWestFA); + cWest.addFocusListener(bWestFA); AWTFocusAdapter bEastFA = new AWTFocusAdapter("EAST"); - bEast.addFocusListener(bEastFA); + cEast.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); + AWTKeyAdapter bWestKA = new AWTKeyAdapter("West"); + cWest.addKeyListener(bWestKA); + AWTKeyAdapter bEastKA = new AWTKeyAdapter("East"); + cEast.addKeyListener(bEastKA); // demo .. GLEventListener demo1 = new GearsES2(1); setDemoFields(demo1, glWindow1, false); glWindow1.addGLEventListener(demo1); glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + glWindow1.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + if(e.getKeyChar()=='c') { + System.err.println("Focus Clear"); + if(glWindow1.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)glWindow1.getDelegatedWindow()).clearFocus(); + } + } else if(e.getKeyChar()=='e') { + System.err.println("Focus East"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cEast.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(e.getKeyChar()=='w') { + System.err.println("Focus West"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cWest.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + }); GLAnimatorControl animator1 = new Animator(glWindow1); animator1.start(); // make frame frame1.setLayout(new BorderLayout()); frame1.setLayout(new BorderLayout()); - frame1.add(bWest, BorderLayout.WEST); + frame1.add(cWest, BorderLayout.WEST); frame1.add(newtCanvasAWT1, BorderLayout.CENTER); - frame1.add(bEast, BorderLayout.EAST); + frame1.add(cEast, BorderLayout.EAST); frame1.setLocation(0, 0); frame1.setSize(fSize); @@ -163,7 +202,7 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { // // initial focus on bWest // - AWTRobotUtil.assertRequestFocusAndWait(robot, bWest, bWest, bWestFA, null); + AWTRobotUtil.assertRequestFocusAndWait(robot, cWest, cWest, bWestFA, null); Assert.assertEquals(true, bWestFA.focusGained()); Thread.sleep(durationPerTest/numFocus); @@ -172,7 +211,7 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { // // bWest -> glWin - AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, bWest, null); + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, cWest, null); Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); Assert.assertEquals(true, glWindow1FA.focusGained()); Assert.assertEquals(true, bWestFA.focusLost()); @@ -180,7 +219,7 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { // 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.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cEast, bEastFA, glWindow1FA)); Assert.assertEquals(true, bEastFA.focusGained()); Assert.assertEquals(true, glWindow1FA.focusLost()); Thread.sleep(durationPerTest/numFocus); @@ -189,17 +228,51 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { // back (using custom back traversal key 'backspace') // // bEast -> glWin - AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, bEast, null); + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, cEast, 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.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); Assert.assertEquals(true, bWestFA.focusGained()); Assert.assertEquals(true, glWindow1FA.focusLost()); - Thread.sleep(durationPerTest/numFocus); + Thread.sleep(durationPerTest/numFocus); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + newtCanvasAWT1.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + 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); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + cWest.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct NEWT request focus + System.err.println("AAAAAAAAAAAAAA"); + glWindow1.requestFocus(); + 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); } animator1.stop(); @@ -217,7 +290,7 @@ public class TestParentingFocusTraversal01AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/jogamp/newt/WindowImplAccess.java b/src/test/jogamp/newt/WindowImplAccess.java index 76d0dc050..e8be5f68a 100644 --- a/src/test/jogamp/newt/WindowImplAccess.java +++ b/src/test/jogamp/newt/WindowImplAccess.java @@ -29,26 +29,16 @@ package jogamp.newt; import com.jogamp.newt.Window; -import com.jogamp.newt.opengl.GLWindow; /** * Allows access to protected methods of WindowImpl */ public class WindowImplAccess { public static final void windowDestroyNotify(Window win) { - WindowImpl winImpl = null; - if(win instanceof GLWindow) { - GLWindow glwin = (GLWindow) win; - winImpl = (WindowImpl) glwin.getWindow(); - } else if(win instanceof WindowImpl) { - winImpl = (WindowImpl) win; - } else { - throw new RuntimeException("Given Window not a GLWindow, not WindowImpl, but "+win.getClass()); - } - final WindowImpl winImplF = winImpl; - winImplF.runOnEDTIfAvail(true, new Runnable() { + final WindowImpl winImpl = (WindowImpl) win.getDelegatedWindow(); + winImpl.runOnEDTIfAvail(true, new Runnable() { public void run() { - winImplF.windowDestroyNotify(); + winImpl.windowDestroyNotify(); } }); } |