diff options
author | Sven Gothel <[email protected]> | 2013-02-28 13:31:29 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-02-28 13:31:29 +0100 |
commit | 3a4892c43be4a9dabba73d42175c2cfa39bd6d8d (patch) | |
tree | 8780bb35234f6d16c89efc34c94409816f54464a | |
parent | 1f9bff1aab54c399438c735581508ac85c6a29b3 (diff) |
Fix Bug 677: NEWT/Android: Add support for Android's KeyEvent.KEYCODE_BACK
Original author: Eric Brayet <[email protected]>
Revised by: Sven Gothel <[email protected]>
I took the freedom to cleanup the three original patches
from https://github.com/Pooouf/jogl.git branch 'bug_677':
- 7449d4726633d524a3bb79efffd04cfd0ca25e58 (removed by followup patch!)
- 68c739a4f03e46deecdbb71c125b4586aec08d63 (removes previous patch!)
- c2813dfc325a1482d18b6fc304e4e483f5633964
Further more I was able to reduce the 'extra' code while utilizing
- Window's isKeyboardVisible() and using keyboardVisibilityChanged(false)
to update the hidden keyboard state.
- Moving the key-handling code to the containing WindowDriver class
avoiding passing a reference to the inner view.
- Using AndroidNewtEventFactory for NEWT KeyEvent creation
+++
- Handle KeyEvent.KEYCODE_BACK w/ jogamp.newt.driver.android.WindowDriver.MSurfaceView.onKeyPreIme(..):
if( soft keyboard is up )
[1] Update keyboard visibility state and return NEWT KeyEvent.VK_KEYBOARD_INVISIBLE;
else
[2] call WindowImpl.windowDestroyNotify(true)
[3] then cont. processing, i.e. return false;
- Turns out respecting WindowClosingMode might be
- too complicated
- interfere w/ Android UI behavior
- AndroidNewtEventFactory
- createKeyEvent
- static
- adding boolean param 'inclSysKeys', if true, KEYCODE_BACK and KEYCODE_HOME are mapped
- Unit tests: GearsES2 + MovieCubeActivity0 shows keyboard if pressure > 0.6f
- pressure on Android shall be between [0..1], however we have to figure out
badly calibrated touchpads/Android device where we could experience
pressure > 2.0f !
- TODO: API documentation of pressure [0..1]
8 files changed, 105 insertions, 45 deletions
diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java index f626fec38..5117ffe29 100644 --- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java @@ -872,6 +872,11 @@ public class KeyEvent extends InputEvent public static final short VK_BEGIN = (short) 0xFF58; /** + * Constant for Keyboard became invisible, e.g. Android's soft keyboard Back button hit while keyboard is visible. + */ + public static final short VK_KEYBOARD_INVISIBLE = (short) 0xDEAD; + + /** * This value is used to indicate that the keyCode is unknown. * KEY_TYPED events do not have a keyCode value; this value * is used instead. diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java index 6f4561ce6..17210cef8 100644 --- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java @@ -107,7 +107,7 @@ public class NEWTEvent extends java.util.EventObject { return sb.append("NEWTEvent[source:").append(getSource().getClass().getName()).append(", when:").append(getWhen()).append(" d ").append((System.currentTimeMillis()-getWhen())).append("ms]"); } - static String toHexString(short hex) { + public static String toHexString(short hex) { return "0x" + Integer.toHexString( (int)hex & 0x0000FFFF ); } } diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java index a85febca0..c5371ae9c 100644 --- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java @@ -30,6 +30,7 @@ package jogamp.newt.driver.android; import jogamp.common.os.android.StaticContext; import jogamp.newt.WindowImpl; +import jogamp.newt.driver.android.event.AndroidNewtEventFactory; import jogamp.newt.driver.android.event.AndroidNewtEventTranslator; import javax.media.nativewindow.Capabilities; @@ -65,6 +66,8 @@ import android.view.SurfaceHolder.Callback2; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.view.SurfaceView; +import android.view.KeyEvent; + public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { static { @@ -573,10 +576,8 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { @Override public final void surfaceDestroyed(SurfaceHolder holder) { Log.d(MD.TAG, "surfaceDestroyed - on thread "+Thread.currentThread().getName()); - if(WindowImpl.DEBUG_IMPLEMENTATION) { - Thread.dumpStack(); - } windowDestroyNotify(true); // actually too late .. however .. + Thread.dumpStack(); } @Override @@ -585,6 +586,27 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { windowRepaint(0, 0, getWidth(), getHeight()); } + protected boolean handleKeyCodeBack(KeyEvent.DispatcherState state, android.view.KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { + state.startTracking(event, this); + } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled() && state.isTracking(event)) { + if( isKeyboardVisible() ) { + keyboardVisibilityChanged(false); + enqueueAKey2NKeyUpDown(event); + } else { + Log.d(MD.TAG, "handleKeyCodeBack : "+event); + windowDestroyNotify(true); + } + } + return false; // cont. processing + } + private void enqueueAKey2NKeyUpDown(android.view.KeyEvent aEvent) { + final com.jogamp.newt.event.KeyEvent eDown = AndroidNewtEventFactory.createKeyEvent(aEvent, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED, this, true); + final com.jogamp.newt.event.KeyEvent eUp = AndroidNewtEventFactory.createKeyEvent(aEvent, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED, this, true); + enqueueEvent(false, eDown); + enqueueEvent(false, eUp); + } + private boolean added2StaticViewGroup; private MSurfaceView androidView; private int nativeFormat; // chosen current native PixelFormat (suitable for EGL) @@ -600,6 +622,17 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { setBackgroundDrawable(null); // setBackgroundColor(Color.TRANSPARENT); } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if ( event.getKeyCode() == KeyEvent.KEYCODE_BACK ) { + final KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + return handleKeyCodeBack(state, event); + } + } + return false; // cont. processing + } } //---------------------------------------------------------------------- // Internals only diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java index 4f19e9c4d..a9c642d8c 100644 --- a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java +++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java @@ -31,6 +31,7 @@ package jogamp.newt.driver.android.event; import com.jogamp.common.os.AndroidVersion; import com.jogamp.newt.Window; import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.NEWTEvent; public class AndroidNewtEventFactory { @@ -86,7 +87,7 @@ public class AndroidNewtEventFactory { return (short)0; } - private static final short aKeyCode2NewtKeyCode(int androidKeyCode) { + private static final short aKeyCode2NewtKeyCode(int androidKeyCode, boolean inclSysKeys) { if(android.view.KeyEvent.KEYCODE_0 <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_9) { return (short) ( com.jogamp.newt.event.KeyEvent.VK_0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_0 ) ); } @@ -122,11 +123,19 @@ public class AndroidNewtEventFactory { // case android.view.KeyEvent.KEYCODE_MUTE: ?? case android.view.KeyEvent.KEYCODE_PAGE_UP: return com.jogamp.newt.event.KeyEvent.VK_PAGE_UP; case android.view.KeyEvent.KEYCODE_PAGE_DOWN: return com.jogamp.newt.event.KeyEvent.VK_PAGE_DOWN; - // case android.view.KeyEvent.KEYCODE_HOME: return com.jogamp.newt.event.KeyEvent.VK_HOME; - // case android.view.KeyEvent.KEYCODE_BACK: return com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE; case android.view.KeyEvent.KEYCODE_ESCAPE: return com.jogamp.newt.event.KeyEvent.VK_ESCAPE; case android.view.KeyEvent.KEYCODE_CTRL_LEFT: return com.jogamp.newt.event.KeyEvent.VK_CONTROL; case android.view.KeyEvent.KEYCODE_CTRL_RIGHT: return com.jogamp.newt.event.KeyEvent.VK_CONTROL; // ?? + case android.view.KeyEvent.KEYCODE_BACK: + if( inclSysKeys ) { + return com.jogamp.newt.event.KeyEvent.VK_KEYBOARD_INVISIBLE; + } + break; + case android.view.KeyEvent.KEYCODE_HOME: + if( inclSysKeys ) { + return com.jogamp.newt.event.KeyEvent.VK_HOME; + } + break; } return (short)0; } @@ -140,19 +149,7 @@ public class AndroidNewtEventFactory { return newtMods; } - private final NewtGestureListener gestureListener; - private final android.view.GestureDetector gestureDetector; - private final float touchSlop; - - public AndroidNewtEventFactory(android.content.Context context, android.os.Handler handler) { - gestureListener = new NewtGestureListener(); - gestureDetector = new android.view.GestureDetector(context, gestureListener, handler, false /* ignoreMultitouch */); - gestureDetector.setIsLongpressEnabled(false); // favor scroll event! - final android.view.ViewConfiguration configuration = android.view.ViewConfiguration.get(context); - touchSlop = configuration.getScaledTouchSlop(); - } - - public com.jogamp.newt.event.WindowEvent createWindowEvent(android.view.accessibility.AccessibilityEvent event, com.jogamp.newt.Window newtSource) { + public static com.jogamp.newt.event.WindowEvent createWindowEvent(android.view.accessibility.AccessibilityEvent event, com.jogamp.newt.Window newtSource) { final int aType = event.getEventType(); final short nType = aAccessibilityEventType2Newt(aType); @@ -163,25 +160,54 @@ public class AndroidNewtEventFactory { } - public com.jogamp.newt.event.KeyEvent createKeyEvent(int keyCode, android.view.KeyEvent event, com.jogamp.newt.Window newtSource) { - final short type = aKeyEventType2NewtEventType(event.getAction()); - if(Window.DEBUG_MOUSE_EVENT) { - System.err.println("createKeyEvent: type 0x"+Integer.toHexString(type)+", keyCode 0x"+Integer.toHexString(keyCode)+", "+event); + public static com.jogamp.newt.event.KeyEvent createKeyEvent(android.view.KeyEvent aEvent, com.jogamp.newt.Window newtSource, boolean inclSysKeys) { + final com.jogamp.newt.event.KeyEvent res; + final short newtType = aKeyEventType2NewtEventType(aEvent.getAction()); + if( (short)0 != newtType) { + final short newtKeyCode = aKeyCode2NewtKeyCode(aEvent.getKeyCode(), inclSysKeys); + res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource); + } else { + res = null; } - if( (short)0 != type) { - final short newtKeyCode = aKeyCode2NewtKeyCode(keyCode); - if( (short)0 != newtKeyCode ) { - final Object src = (null==newtSource)?null:(Object)newtSource; - final long unixTime = System.currentTimeMillis() + ( event.getEventTime() - android.os.SystemClock.uptimeMillis() ); - final int newtMods = aKeyModifiers2Newt(event.getMetaState()); - - return new com.jogamp.newt.event.KeyEvent( - type, src, unixTime, newtMods, newtKeyCode, newtKeyCode, (char) event.getUnicodeChar()); - } + if(Window.DEBUG_KEY_EVENT) { + System.err.println("createKeyEvent0: "+aEvent+" -> "+res); } - return null; + return res; } + public static com.jogamp.newt.event.KeyEvent createKeyEvent(android.view.KeyEvent aEvent, short newtType, com.jogamp.newt.Window newtSource, boolean inclSysKeys) { + final short newtKeyCode = aKeyCode2NewtKeyCode(aEvent.getKeyCode(), inclSysKeys); + final com.jogamp.newt.event.KeyEvent res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource); + if(Window.DEBUG_KEY_EVENT) { + System.err.println("createKeyEvent1: newtType "+NEWTEvent.toHexString(newtType)+", "+aEvent+" -> "+res); + } + return res; + } + + private static com.jogamp.newt.event.KeyEvent createKeyEventImpl(android.view.KeyEvent aEvent, short newtType, short newtKeyCode, com.jogamp.newt.Window newtSource) { + if( (short)0 != newtType && (short)0 != newtKeyCode ) { + final Object src = null==newtSource ? null : newtSource; + final long unixTime = System.currentTimeMillis() + ( aEvent.getEventTime() - android.os.SystemClock.uptimeMillis() ); + final int newtMods = aKeyModifiers2Newt(aEvent.getMetaState()); + + return new com.jogamp.newt.event.KeyEvent( + newtType, src, unixTime, newtMods, newtKeyCode, newtKeyCode, (char) aEvent.getUnicodeChar()); + } + return null; + } + + private final NewtGestureListener gestureListener; + private final android.view.GestureDetector gestureDetector; + private final float touchSlop; + + public AndroidNewtEventFactory(android.content.Context context, android.os.Handler handler) { + gestureListener = new NewtGestureListener(); + gestureDetector = new android.view.GestureDetector(context, gestureListener, handler, false /* ignoreMultitouch */); + gestureDetector.setIsLongpressEnabled(false); // favor scroll event! + final android.view.ViewConfiguration configuration = android.view.ViewConfiguration.get(context); + touchSlop = configuration.getScaledTouchSlop(); + } + private int gestureScrollPointerDown = 0; public com.jogamp.newt.event.MouseEvent[] createMouseEvents(boolean isOnTouchEvent, diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java index 2d972f752..93735863e 100644 --- a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java +++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java @@ -38,7 +38,7 @@ public class AndroidNewtEventTranslator implements View.OnKeyListener, View.OnTo @Override public boolean onKey(View v, int keyCode, android.view.KeyEvent event) { - final com.jogamp.newt.event.KeyEvent newtEvent = factory.createKeyEvent(keyCode, event, newtWindow); + final com.jogamp.newt.event.KeyEvent newtEvent = AndroidNewtEventFactory.createKeyEvent(event, newtWindow, false /* no system keys */); if(null != newtEvent) { newtWindow.enqueueEvent(false, newtEvent); return true; diff --git a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java index a30262ee3..0c65b6d53 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java +++ b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java @@ -54,7 +54,7 @@ public class MovieCubeActivity0 extends NewtBaseActivity { MouseAdapter showKeyboardMouseListener = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { - if(e.getPressure()>2f) { + if(e.getPressure()>0.6f) { ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true); } } diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java index e782ac75f..931ffdbb2 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java @@ -66,14 +66,6 @@ public class NEWTGearsES2Activity extends NewtBaseActivity { GLWindow glWindow = GLWindow.create(caps); glWindow.setFullscreen(true); setContentView(getWindow(), glWindow); - glWindow.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - if(e.getPressure()>2f) { // show Keyboard - ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true); - } - } - }); GearsES2 demo = new GearsES2(-1); // demo.enableAndroidTrace(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 74377a5f8..14c6a0cda 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 @@ -366,6 +366,10 @@ public class GearsES2 implements GLEventListener { public void mousePressed(MouseEvent e) { prevMouseX = e.getX(); prevMouseY = e.getY(); + Object src = e.getSource(); + if(e.getPressure()>0.6f && src instanceof Window) { // show Keyboard + ((Window) src).setKeyboardVisible(true); + } } public void mouseReleased(MouseEvent e) { |