diff options
author | Sven Gothel <[email protected]> | 2013-01-14 05:58:21 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-01-14 05:58:21 +0100 |
commit | da14d647581751f3d2f6d651741eaec485e255b5 (patch) | |
tree | e8d228fa27ca2ccf5820abcd7c49a9f054377ae9 /src/newt/classes | |
parent | 955a444939ba67c6077b6937e191719aa184dafe (diff) |
NEWT-MouseEvent getWheelRotation() API Update - Fixes Bug 659: NEWT Horizontal Scrolling Behavior (OSX, X11, Win32); Bug 639: High-Res Mouse-Wheel
- API update 'float getWheelRotation()':
Usually a wheel rotation of > 0.0f is up, and < 0.0f is down.
Usually a wheel rotations is considered a vertical scroll.
If isShiftDown(), a wheel rotations is considered a horizontal scroll,
where shift-up = left = > 0.0f, and shift-down = right = < 0.0f.
However, on some OS this might be flipped due to the OS default behavior.
The latter is true for OS X 10.7 (Lion) for example.
The events will be send usually in steps of one, ie. -1.0f and 1.0f.
Higher values may result due to fast scrolling.
Fractional values may result due to slow scrolling with high resolution devices.
The button number refers to the wheel number.
- Fix Bug 659: NEWT Horizontal Scrolling Behavior (OSX, X11, Win32)
- See new API doc above
- X11/Horiz: Keep using button1 and set SHIFT modifier
- OSX/Horiz:
- PAD: Use highes absolute scrolling value (Axis1/Axis2)
and set SHIFT modifier for horizontal scrolling (Axis2)
- XXX: Use deltaX for horizontal scrolling, detected by SHIFT modifier. (traditional)
- Windows/Horiz:
- Add WM_MOUSEHWHEEL support (-> set SHIFT modifier), but it's rarely impl. for trackpads!
- Add exp. WM_HSCROLL, but it will only be delivered if windows has WS_HSCROLL, hence dead code!
- Android:
- Add ACTION_SCROLL (API Level 12), only used if layout is a scroll layout
- Using GestureDetector to detect scroll even w/ pointerCount > 2, while:
- skipping 1st scroll event (value too high)
- skipping other events while in-scroll mode
- waiting until all pointers were released before cont. normally
- using View config's 1/touchSlope as scale factor
- Fix Bug 639: High-Res Mouse-Wheel
- getWheelRotation() return value changed: int -> float
allowing fractions, see API doc changes above.
- Fractions are currently supported natively (API) on
- Windows
- OSX
- Android
- AndroidNewtEventFactory ir refactored (requires an instance now) and
AndroidNewtEventTranslator (event listener) is pulled our of Android WindowDriver.
Diffstat (limited to 'src/newt/classes')
11 files changed, 446 insertions, 160 deletions
diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index b3e904310..e66b2f624 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -44,8 +44,6 @@ import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowFactory; -import com.jogamp.common.os.Platform; - import jogamp.newt.Debug; import jogamp.newt.DisplayImpl; import jogamp.newt.ScreenImpl; @@ -56,13 +54,15 @@ public class NewtFactory { public static final String DRIVER_DEFAULT_ROOT_PACKAGE = "jogamp.newt.driver"; - // Work-around for initialization order problems on Mac OS X - // between native Newt and (apparently) Fmod static { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { NativeWindowFactory.initSingleton(); // last resort .. + + // Work-around for initialization order problems on Mac OS X + // between native Newt and (apparently) Fmod WindowImpl.init(NativeWindowFactory.getNativeWindowType(true)); + return null; } } ); } diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java index 914aaa647..e6b3d8a24 100644 --- a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java @@ -65,7 +65,7 @@ public class MouseEvent extends InputEvent public MouseEvent(int eventType, Object source, long when, int modifiers, int x, int y, int clickCount, int button, - int rotation) + float rotation) { super(eventType, source, when, modifiers); this.x = new int[]{x}; @@ -79,7 +79,7 @@ public class MouseEvent extends InputEvent public MouseEvent(int eventType, Object source, long when, int modifiers, int[] x, int[] y, float[] pressure, int[] pointerids, int clickCount, int button, - int rotation) + float rotation) { super(eventType, source, when, modifiers); this.x = x; @@ -154,20 +154,29 @@ public class MouseEvent extends InputEvent } /** - * <i>Usually</i> a wheel rotation of <b>> 0 is up</b>, - * and <b>< 0 is down</b>.<br> + * <i>Usually</i> a wheel rotation of <b>> 0.0f is up</b>, + * and <b>< 0.0f is down</b>. + * <p> + * Usually a wheel rotations is considered a vertical scroll.<br/> + * If {@link #isShiftDown()}, a wheel rotations is + * considered a horizontal scroll, where <b>shift-up = left = > 0.0f</b>, + * and <b>shift-down = right = < 0.0f</b>. + * </p> + * <p> * <i>However</i>, on some OS this might be flipped due to the OS <i>default</i> behavior. * The latter is true for OS X 10.7 (Lion) for example. + * </p> * <p> - * The events will be send usually in steps of one, ie. <i>-1</i> and <i>1</i>. + * The events will be send usually in steps of one, ie. <i>-1.0f</i> and <i>1.0f</i>. * Higher values may result due to fast scrolling. + * Fractional values may result due to slow scrolling with high resolution devices. * </p> * <p> * The button number refers to the wheel number. * </p> * @return */ - public int getWheelRotation() { + public float getWheelRotation() { return wheelRotation; } @@ -212,7 +221,8 @@ public class MouseEvent extends InputEvent default: return "unknown (" + type + ")"; } } - private final int x[], y[], clickCount, button, wheelRotation; + private final int x[], y[], clickCount, button; + private final float wheelRotation; private final float pressure[]; private final int pointerids[]; diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 6e1059952..3c93de5b3 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -133,10 +133,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private ArrayList<WindowListener> windowListeners = new ArrayList<WindowListener>(); private boolean repaintQueued = false; - // Workaround for initialization order problems on Mac OS X - // between native Newt and (apparently) Fmod -- if Fmod is - // initialized first then the connection to the window server - // breaks, leading to errors from deep within the AppKit + /** + * Workaround for initialization order problems on Mac OS X + * between native Newt and (apparently) Fmod -- if Fmod is + * initialized first then the connection to the window server + * breaks, leading to errors from deep within the AppKit + */ public static void init(String type) { if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { try { @@ -1974,16 +1976,16 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // MouseListener/Event Support // public void sendMouseEvent(int eventType, int modifiers, - int x, int y, int button, int rotation) { + int x, int y, int button, float rotation) { doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); } public void enqueueMouseEvent(boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { + int x, int y, int button, float rotation) { doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); } protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { + int x, int y, int button, float rotation) { if( eventType == MouseEvent.EVENT_MOUSE_ENTERED || eventType == MouseEvent.EVENT_MOUSE_EXITED ) { if( eventType == MouseEvent.EVENT_MOUSE_EXITED && x==-1 && y==-1 ) { x = lastMousePosition.getX(); diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java index 1a61d0528..e0f7af69c 100644 --- a/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java +++ b/src/newt/classes/jogamp/newt/awt/event/AWTNewtEventFactory.java @@ -262,10 +262,10 @@ public class AWTNewtEventFactory { public static final com.jogamp.newt.event.MouseEvent createMouseEvent(java.awt.event.MouseEvent event, com.jogamp.newt.Window newtSource) { int type = eventTypeAWT2NEWT.get(event.getID()); if(0xFFFFFFFF != type) { - int rotation = 0; + float rotation = 0; if (event instanceof java.awt.event.MouseWheelEvent) { // AWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up. - rotation = -1 * ((java.awt.event.MouseWheelEvent)event).getWheelRotation(); + rotation = -1f * ((java.awt.event.MouseWheelEvent)event).getWheelRotation(); } final int newtButton = awtButton2Newt(event.getButton()); diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java index f18520630..281bd9e0f 100644 --- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java @@ -29,7 +29,7 @@ package jogamp.newt.driver.android; import jogamp.common.os.android.StaticContext; -import jogamp.newt.driver.android.event.AndroidNewtEventFactory; +import jogamp.newt.driver.android.event.AndroidNewtEventTranslator; import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.CapabilitiesImmutable; @@ -41,6 +41,7 @@ import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; +import com.jogamp.common.os.AndroidVersion; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import jogamp.opengl.egl.EGL; @@ -58,7 +59,6 @@ import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback2; import android.view.inputmethod.InputMethodManager; import android.view.SurfaceView; -import android.view.View; public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { static { @@ -139,42 +139,6 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { return false; } - class AndroidEvents implements View.OnKeyListener, View.OnTouchListener, View.OnFocusChangeListener { - - @Override - public boolean onTouch(View v, android.view.MotionEvent event) { - final com.jogamp.newt.event.MouseEvent[] newtEvents = AndroidNewtEventFactory.createMouseEvents(event, WindowDriver.this); - if(null != newtEvents) { - focusChanged(false, true); - for(int i=0; i<newtEvents.length; i++) { - WindowDriver.this.enqueueEvent(false, newtEvents[i]); - } - try { Thread.sleep((long) (1000.0F/30.0F)); } - catch(InterruptedException e) { } - return true; // consumed/handled, further interest in events - } - return false; // no mapping, no further interest in the event! - } - - @Override - public boolean onKey(View v, int keyCode, android.view.KeyEvent event) { - final com.jogamp.newt.event.KeyEvent[] newtEvents = AndroidNewtEventFactory.createKeyEvents(keyCode, event, WindowDriver.this); - if(null != newtEvents) { - for(int i=0; i<newtEvents.length; i++) { - WindowDriver.this.enqueueEvent(false, newtEvents[i]); - } - return true; - } - return false; - } - - @Override - public void onFocusChange(View v, boolean hasFocus) { - WindowDriver.this.focusChanged(false, hasFocus); - } - - } - public static Class<?>[] getCustomConstructorArgumentTypes() { return new Class<?>[] { Context.class } ; } @@ -196,22 +160,33 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { setBrokenFocusChange(true); } + private void setupInputListener(boolean enable) { + Log.d(MD.TAG, "setupInputListener(enable "+enable+") - "+Thread.currentThread().getName()); + + final AndroidNewtEventTranslator eventTranslator = + enable ? new AndroidNewtEventTranslator(this, androidView.getContext(), androidView.getHandler()) : null; + androidView.setOnTouchListener(eventTranslator); + androidView.setOnKeyListener(eventTranslator); + androidView.setOnFocusChangeListener(eventTranslator); + if(AndroidVersion.SDK_INT >= 12) { // API Level 12 + Log.d(MD.TAG, "instantiationFinished() - enable GenericMotionListener - "+Thread.currentThread().getName()); + androidView.setOnGenericMotionListener(eventTranslator); + } + androidView.setClickable(false); + androidView.setFocusable(enable); + androidView.setFocusableInTouchMode(enable); + } + @Override protected void instantiationFinished() { + Log.d(MD.TAG, "instantiationFinished() - "+Thread.currentThread().getName()); + final Context ctx = StaticContext.getContext(); if(null == ctx) { throw new NativeWindowException("No static [Application] Context has been set. Call StaticContext.setContext(Context) first."); } androidView = new MSurfaceView(ctx); - - final AndroidEvents ae = new AndroidEvents(); - androidView.setOnTouchListener(ae); - androidView.setClickable(false); - androidView.setOnKeyListener(ae); - androidView.setOnFocusChangeListener(ae); - androidView.setFocusable(true); - androidView.setFocusableInTouchMode(true); - + final SurfaceHolder sh = androidView.getHolder(); sh.addCallback(WindowDriver.this); sh.setFormat(getFormat(getRequestedCapabilities())); @@ -220,7 +195,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { defineSize(0, 0); } - public SurfaceView getAndroidView() { return androidView; } + public final SurfaceView getAndroidView() { return androidView; } @Override protected boolean canCreateNativeImpl() { @@ -259,11 +234,14 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { if (EGL.EGL_NO_SURFACE==eglSurface) { throw new NativeWindowException("Creation of window surface failed: "+eglConfig+", surfaceHandle 0x"+Long.toHexString(surfaceHandle)+", error "+toHexString(EGL.eglGetError())); } - + // propagate data .. setGraphicsConfiguration(eglConfig); setWindowHandle(surfaceHandle); focusChanged(false, true); + + setupInputListener(true); + Log.d(MD.TAG, "createNativeImpl X: eglSurfaceHandle 0x"+Long.toHexString(eglSurface)); } @@ -272,6 +250,9 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { Log.d(MD.TAG, "closeNativeImpl 0 - surfaceHandle 0x"+Long.toHexString(surfaceHandle)+ ", eglSurfaceHandle 0x"+Long.toHexString(eglSurface)+ ", format [a "+androidFormat+", n "+nativeFormat+"], "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+" - "+Thread.currentThread().getName()); + + setupInputListener(false); + if(0 != eglSurface) { final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) getScreen().getDisplay().getGraphicsDevice(); if (!EGL.eglDestroySurface(eglDevice.getHandle(), eglSurface)) { @@ -289,6 +270,19 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { return eglSurface; } + /** + * <p> + * Accessible protected method! + * </p> + * + * {@inheritDoc} + */ + @Override + public void focusChanged(boolean defer, boolean focusGained) { + super.focusChanged(defer, focusGained); + } + + @Override protected void requestFocusImpl(boolean reparented) { if(null != androidView) { Log.d(MD.TAG, "requestFocusImpl: reparented "+reparented); @@ -301,6 +295,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { } } + @Override protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { boolean res = true; @@ -330,10 +325,12 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { return res; } + @Override protected Point getLocationOnScreenImpl(int x, int y) { return new Point(x,y); } + @Override protected void updateInsetsImpl(Insets insets) { // nop .. } @@ -367,6 +364,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { } private KeyboardVisibleReceiver keyboardVisibleReceiver = new KeyboardVisibleReceiver(); + @Override protected final boolean setKeyboardVisibleImpl(boolean visible) { if(null != androidView) { final InputMethodManager imm = (InputMethodManager) getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); @@ -388,10 +386,12 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { // Surface Callbacks // + @Override public void surfaceCreated(SurfaceHolder holder) { Log.d(MD.TAG, "surfaceCreated: "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()); } + @Override public void surfaceChanged(SurfaceHolder aHolder, int aFormat, int aWidth, int aHeight) { Log.d(MD.TAG, "surfaceChanged: f "+nativeFormat+" -> "+aFormat+", "+aWidth+"x"+aHeight+", current surfaceHandle: 0x"+Long.toHexString(surfaceHandle)); if(0!=surfaceHandle && androidFormat != aFormat ) { @@ -436,11 +436,13 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { Log.d(MD.TAG, "surfaceChanged: X"); } + @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d(MD.TAG, "surfaceDestroyed"); windowDestroyNotify(true); // actually too late .. however .. } + @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { Log.d(MD.TAG, "surfaceRedrawNeeded"); windowRepaint(0, 0, getWidth(), getHeight()); 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 d23b5f576..dc1e8aeef 100644 --- a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java +++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java @@ -28,38 +28,81 @@ package jogamp.newt.driver.android.event; -import java.awt.event.MouseEvent; - -import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.common.os.AndroidVersion; import com.jogamp.newt.Window; import com.jogamp.newt.event.InputEvent; public class AndroidNewtEventFactory { - protected static final IntIntHashMap eventTypeANDROID2NEWT; - - private static final String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" , - "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" }; + private static final String names[] = { "DOWN" , "UP" , "MOVE", "CANCEL" , "OUTSIDE", // 0 - 4 + "POINTER_DOWN" , "POINTER_UP" , "HOVER_MOVE" , "SCROLL", // 5 - 8 + "HOVER_ENTER", "HOVER_EXIT" // 0 - 10 + }; - static { - IntIntHashMap map = new IntIntHashMap(); - map.setKeyNotFoundValue(0xFFFFFFFF); - - map.put(android.view.MotionEvent.ACTION_DOWN, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED); - map.put(android.view.MotionEvent.ACTION_UP, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); - map.put(android.view.MotionEvent.ACTION_CANCEL, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); - map.put(android.view.MotionEvent.ACTION_MOVE, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED); - map.put(android.view.MotionEvent.ACTION_OUTSIDE, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED); - - map.put(android.view.MotionEvent.ACTION_POINTER_DOWN, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED); - map.put(android.view.MotionEvent.ACTION_POINTER_UP, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); - - map.put(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS); - - eventTypeANDROID2NEWT = map; + /** API Level 12: {@link android.view.MotionEvent#ACTION_SCROLL} = {@value} */ + private static final int ACTION_SCROLL = 8; + + private static final int aMotionEventType2Newt(int aType) { + final int nType; + switch( aType ) { + case android.view.MotionEvent.ACTION_DOWN: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED; + break; + case android.view.MotionEvent.ACTION_UP: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED; + break; + case android.view.MotionEvent.ACTION_MOVE: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED; + break; + case android.view.MotionEvent.ACTION_CANCEL: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED; + break; + case android.view.MotionEvent.ACTION_OUTSIDE: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED; + break; + // + case android.view.MotionEvent.ACTION_POINTER_DOWN: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED; + break; + case android.view.MotionEvent.ACTION_POINTER_UP: + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED; + break; + // case ACTION_HOVER_MOVE + case ACTION_SCROLL: // API Level 12 ! + nType = com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED; + break; + // case ACTION_HOVER_ENTER + // case ACTION_HOVER_EXIT + default: + nType = 0xFFFFFFFF; + } + return nType; + } + + private static final int aAccessibilityEventType2Newt(int aType) { + final int nType; + switch( aType ) { + case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED: + nType = com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS; break; + default: + nType = 0xFFFFFFFF; + } + return nType; } - static final int androidKeyCode2Newt(int androidKeyCode) { + private static final int aKeyEventType2NewtEventType(int androidKeyAction) { + switch(androidKeyAction) { + case android.view.KeyEvent.ACTION_DOWN: + case android.view.KeyEvent.ACTION_MULTIPLE: + return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED; + case android.view.KeyEvent.ACTION_UP: + return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED; + default: + return 0; + } + } + + private static final int aKeyCode2NewtKeyCode(int androidKeyCode) { if(android.view.KeyEvent.KEYCODE_0 <= androidKeyCode && androidKeyCode <= android.view.KeyEvent.KEYCODE_9) { return com.jogamp.newt.event.KeyEvent.VK_0 + ( androidKeyCode - android.view.KeyEvent.KEYCODE_0 ) ; } @@ -104,15 +147,7 @@ public class AndroidNewtEventFactory { return 0; } - public static final com.jogamp.newt.event.WindowEvent createWindowEvent(android.view.accessibility.AccessibilityEvent event, com.jogamp.newt.Window newtSource) { - int type = eventTypeANDROID2NEWT.get(event.getEventType()); - if(0xFFFFFFFF != type) { - return new com.jogamp.newt.event.WindowEvent(type, ((null==newtSource)?null:(Object)newtSource), event.getEventTime()); - } - return null; // no mapping .. - } - - static final int androidKeyModifiers2Newt(int androidMods) { + private static final int aKeyModifiers2Newt(int androidMods) { int newtMods = 0; if ((androidMods & android.view.KeyEvent.META_SYM_ON) != 0) newtMods |= com.jogamp.newt.event.InputEvent.META_MASK; if ((androidMods & android.view.KeyEvent.META_SHIFT_ON) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK; @@ -121,29 +156,40 @@ public class AndroidNewtEventFactory { return newtMods; } - private static final int androidKeyAction2NewtEventType(int androidKeyAction) { - switch(androidKeyAction) { - case android.view.KeyEvent.ACTION_DOWN: - case android.view.KeyEvent.ACTION_MULTIPLE: - return com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED; - case android.view.KeyEvent.ACTION_UP: - return com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED; - default: - return 0; + 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) { + final int aType = event.getEventType(); + final int nType = aAccessibilityEventType2Newt(aType); + + if(0xFFFFFFFF != nType) { + return new com.jogamp.newt.event.WindowEvent(nType, ((null==newtSource)?null:(Object)newtSource), event.getEventTime()); } + return null; // no mapping .. } + - public static final com.jogamp.newt.event.KeyEvent[] createKeyEvents(int keyCode, android.view.KeyEvent event, com.jogamp.newt.Window newtSource) { - final int type = androidKeyAction2NewtEventType(event.getAction()); + public com.jogamp.newt.event.KeyEvent[] createKeyEvents(int keyCode, android.view.KeyEvent event, com.jogamp.newt.Window newtSource) { + final int type = aKeyEventType2NewtEventType(event.getAction()); if(Window.DEBUG_MOUSE_EVENT) { System.err.println("createKeyEvent: type 0x"+Integer.toHexString(type)+", keyCode 0x"+Integer.toHexString(keyCode)+", "+event); } if(0xFFFFFFFF != type) { - final int newtKeyCode = androidKeyCode2Newt(keyCode); + final int newtKeyCode = aKeyCode2NewtKeyCode(keyCode); if(0 != newtKeyCode) { final Object src = (null==newtSource)?null:(Object)newtSource; final long unixTime = System.currentTimeMillis() + ( event.getEventTime() - android.os.SystemClock.uptimeMillis() ); - final int newtMods = androidKeyModifiers2Newt(event.getMetaState()); + final int newtMods = aKeyModifiers2Newt(event.getMetaState()); final com.jogamp.newt.event.KeyEvent ke1 = new com.jogamp.newt.event.KeyEvent( type, src, unixTime, newtMods, newtKeyCode, event.getDisplayLabel()); @@ -161,29 +207,145 @@ public class AndroidNewtEventFactory { return null; } - public static final com.jogamp.newt.event.MouseEvent[] createMouseEvents(android.view.MotionEvent event, com.jogamp.newt.Window newtSource) { + private int gestureScrollPointerDown = 0; + + public com.jogamp.newt.event.MouseEvent[] createMouseEvents(boolean isOnTouchEvent, + android.view.MotionEvent event, com.jogamp.newt.Window newtSource) { if(Window.DEBUG_MOUSE_EVENT) { - System.err.println("createMouseEvent: "+toString(event)); + System.err.println("createMouseEvent: "+toString(event)); } - int type = eventTypeANDROID2NEWT.get(event.getAction()); - if(0xFFFFFFFF != type) { - int rotation = 0; - int clickCount = 1; + + // + // Prefilter Android Event (Gesture, ..) and determine final type + // + final int aType, nType; + float[] rotationXY = null; + int rotationSource = 0; // 1 - Gesture, 2 - ACTION_SCROLL + { + final int pointerCount = event.getPointerCount(); + final boolean gestureEvent = isOnTouchEvent && pointerCount>1 && gestureDetector.onTouchEvent(event); + int _aType = 0xFFFFFFFF; + if( gestureEvent ) { + rotationXY = gestureListener.getScrollDistanceXY(); + if( null != rotationXY) { + final boolean skip = 0 == gestureScrollPointerDown; // skip 1st .. too bug distance + gestureScrollPointerDown = pointerCount; + if( skip ) { + if(Window.DEBUG_MOUSE_EVENT) { + System.err.println("createMouseEvent: GestureEvent Scroll Start - SKIP "+rotationXY[0]+"/"+rotationXY[1]+", gestureScrollPointerDown "+gestureScrollPointerDown); + } + return null; + } + _aType = ACTION_SCROLL; // 8 + rotationSource = 1; + } else { + throw new InternalError("Gesture Internal Error: consumed onTouchEvent, but no result (Scroll)"); + } + } + if( 0xFFFFFFFF == _aType ) { + _aType = event.getActionMasked(); + } + aType = _aType; + nType = aMotionEventType2Newt(aType); + + // + // Check whether events shall be skipped + // + if( !gestureEvent ) { + // Scroll Gesture: Wait for all pointers up - ACTION_UP, ACTION_POINTER_UP + if( 0 < gestureScrollPointerDown ) { + if( com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED == nType ) { + gestureScrollPointerDown--; + } + if(Window.DEBUG_MOUSE_EVENT) { + System.err.println("createMouseEvent: !GestureEvent SKIP gestureScrollPointerDown "+gestureScrollPointerDown); + } + return null; + } + } + } + + if(0xFFFFFFFF != nType) { + final int clickCount = 1; int modifiers = 0; - int[] x = new int[event.getPointerCount()]; - int[] y = new int[event.getPointerCount()]; - float[] pressure = new float[event.getPointerCount()]; - int[] pointers = new int[event.getPointerCount()]; - int index = 0; - while(index < event.getPointerCount()) { - x[index] = (int)event.getX(index); - y[index] = (int)event.getY(index); - pressure[index] = event.getPressure(index); - pointers[index] = event.getPointerId(index); - index++; + if( null == rotationXY && AndroidVersion.SDK_INT >= 12 && ACTION_SCROLL == aType ) { // API Level 12 + rotationXY = new float[] { event.getAxisValue(android.view.MotionEvent.AXIS_X), + event.getAxisValue(android.view.MotionEvent.AXIS_Y) }; + rotationSource = 2; } - + + final float rotation; + if( null != rotationXY ) { + final float _rotation; + if( rotationXY[0]*rotationXY[0] > rotationXY[1]*rotationXY[1] ) { + // Horizontal + modifiers |= com.jogamp.newt.event.InputEvent.SHIFT_MASK; + _rotation = rotationXY[0]; + } else { + // Vertical + _rotation = rotationXY[1]; + } + rotation = _rotation / touchSlop; + if(Window.DEBUG_MOUSE_EVENT) { + System.err.println("createMouseEvent: Scroll "+rotationXY[0]+"/"+rotationXY[1]+" -> "+_rotation+" / "+touchSlop+" -> "+rotation+" scaled -- mods "+modifiers+", source "+rotationSource); + } + } else { + rotation = 0.0f; + } + + // + // Determine newt-button and whether dedicated pointer is pressed + // + final int pCount; + final int pIndex; + final int button; + switch( aType ) { + case android.view.MotionEvent.ACTION_POINTER_DOWN: + case android.view.MotionEvent.ACTION_POINTER_UP: { + pIndex = event.getActionIndex(); + pCount = 1; + final int b = event.getPointerId(pIndex) + 1; // FIXME: Assumption that Pointer-ID starts w/ 0 ! + if( com.jogamp.newt.event.MouseEvent.BUTTON1 <= b && b <= com.jogamp.newt.event.MouseEvent.BUTTON_NUMBER ) { + button = b; + } else { + button = com.jogamp.newt.event.MouseEvent.BUTTON1; + } + } + break; + default: { + pIndex = 0; + pCount = event.getPointerCount(); // all + button = com.jogamp.newt.event.MouseEvent.BUTTON1; + } + } + + // + // Collect common data + // + final int[] x = new int[pCount]; + final int[] y = new int[pCount]; + final float[] pressure = new float[pCount]; + final int[] pointerIds = new int[pCount]; + { + if(Window.DEBUG_MOUSE_EVENT) { + System.err.println("createMouseEvent: collect ptr-data ["+pIndex+".."+(pIndex+pCount-1)+", "+pCount+"], aType "+aType+", button "+button+", gestureScrollPointerDown "+gestureScrollPointerDown); + } + int i = pIndex; + int j = 0; + while(j < pCount) { + x[j] = (int)event.getX(i); + y[j] = (int)event.getY(i); + pressure[j] = event.getPressure(i); + pointerIds[j] = event.getPointerId(i); + if(Window.DEBUG_MOUSE_EVENT) { + System.err.println("createMouseEvent: ptr-data["+i+" -> "+j+"] "+x[j]+"/"+y[j]+", pressure "+pressure[j]+", id "+pointerIds[j]); + } + i++; + j++; + } + } + if(null!=newtSource) { if(newtSource.isPointerConfined()) { modifiers |= InputEvent.CONFINED_MASK; @@ -195,21 +357,20 @@ public class AndroidNewtEventFactory { final Object src = (null==newtSource)?null:(Object)newtSource; final long unixTime = System.currentTimeMillis() + ( event.getEventTime() - android.os.SystemClock.uptimeMillis() ); - final int button = pointers.length==1 ? MouseEvent.BUTTON1 : 0; final com.jogamp.newt.event.MouseEvent me1 = new com.jogamp.newt.event.MouseEvent( - type, src, unixTime, - modifiers, x, y, pressure, pointers, clickCount, + nType, src, unixTime, + modifiers, x, y, pressure, pointerIds, clickCount, button, rotation); - if(type == com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED) { + if( com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED == nType ) { return new com.jogamp.newt.event.MouseEvent[] { me1, new com.jogamp.newt.event.MouseEvent( com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED, - src, unixTime, modifiers, x, y, pressure, pointers, clickCount, + src, unixTime, modifiers, x, y, pressure, pointerIds, clickCount, button, rotation) }; } else { - return new com.jogamp.newt.event.MouseEvent[] { me1 }; + return new com.jogamp.newt.event.MouseEvent[] { me1 }; } } return null; // no mapping .. @@ -238,6 +399,58 @@ public class AndroidNewtEventFactory { } sb.append("]" ); return sb.toString(); - } + } + + class NewtGestureListener implements android.view.GestureDetector.OnGestureListener { + private float[] scrollDistance; + + NewtGestureListener() { + scrollDistance = null; + } + + /** Returns non null w/ 2 float values, XY, if storing onScroll's XY distance - otherwise null */ + public float[] getScrollDistanceXY() { + float[] sd = scrollDistance; + scrollDistance = null; + return sd; + } + + // + // Simple feedback + // + + @Override + public void onShowPress(android.view.MotionEvent e) { + } + + @Override + public void onLongPress(android.view.MotionEvent e) { + } + + @Override + public boolean onSingleTapUp(android.view.MotionEvent e) { + return false; + } + + // + // Consumed or not consumed ! + // + + @Override + public boolean onDown(android.view.MotionEvent e) { + return false; + } + + @Override + public boolean onScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float distanceX, float distanceY) { + scrollDistance = new float[] { distanceX, distanceY }; + return true; + } + + @Override + public boolean onFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY) { + return false; + } + }; } diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java new file mode 100644 index 000000000..ee0c8f8b1 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventTranslator.java @@ -0,0 +1,55 @@ +package jogamp.newt.driver.android.event; + +import jogamp.newt.driver.android.WindowDriver; +import android.view.View; + +public class AndroidNewtEventTranslator implements View.OnKeyListener, View.OnTouchListener, View.OnFocusChangeListener, View.OnGenericMotionListener { + private final WindowDriver newtWindow; + private final AndroidNewtEventFactory factory; + + public AndroidNewtEventTranslator(WindowDriver newtWindow, android.content.Context context, android.os.Handler handler) { + this.newtWindow = newtWindow; + this.factory = new AndroidNewtEventFactory(context, handler); + } + + private final boolean processTouchMotionEvents(View v, android.view.MotionEvent event, boolean isOnTouchEvent) { + final com.jogamp.newt.event.MouseEvent[] newtEvents = factory.createMouseEvents(isOnTouchEvent, event, newtWindow); + if(null != newtEvents) { + newtWindow.focusChanged(false, true); + for(int i=0; i<newtEvents.length; i++) { + newtWindow.enqueueEvent(false, newtEvents[i]); + } + try { Thread.sleep((long) (1000.0F/30.0F)); } + catch(InterruptedException e) { } + return true; // consumed/handled, further interest in events + } + return false; // no mapping, no further interest in the event! + } + + @Override + public boolean onTouch(View v, android.view.MotionEvent event) { + return processTouchMotionEvents(v, event, true); + } + + @Override + public boolean onGenericMotion(View v, android.view.MotionEvent event) { + return processTouchMotionEvents(v, event, false); + } + + @Override + public boolean onKey(View v, int keyCode, android.view.KeyEvent event) { + final com.jogamp.newt.event.KeyEvent[] newtEvents = factory.createKeyEvents(keyCode, event, newtWindow); + if(null != newtEvents) { + for(int i=0; i<newtEvents.length; i++) { + newtWindow.enqueueEvent(false, newtEvents[i]); + } + return true; + } + return false; + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + newtWindow.focusChanged(false, hasFocus); + } +} diff --git a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java index 615f9e63b..1b9ec0f25 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/DisplayDriver.java @@ -51,16 +51,21 @@ public class DisplayDriver extends DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); - if (!WindowDriver.initIDs0()) { + sharedClassFactory = new RegisteredClassFactory(newtClassBaseName, WindowDriver.getNewtWndProc0()); + + if (!WindowDriver.initIDs0(RegisteredClassFactory.getHInstance())) { throw new NativeWindowException("Failed to initialize WindowsWindow jmethodIDs"); } - sharedClassFactory = new RegisteredClassFactory(newtClassBaseName, WindowDriver.getNewtWndProc0()); } public static void initSingleton() { // just exist to ensure static init has been run } + protected static long getHInstance() { + return RegisteredClassFactory.getHInstance(); + } + private RegisteredClass sharedClass; public DisplayDriver() { @@ -80,10 +85,6 @@ public class DisplayDriver extends DisplayImpl { DispatchMessages0(); } - protected long getHInstance() { - return sharedClass.getHandle(); - } - protected String getWindowClassName() { return sharedClass.getName(); } diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java index 2ec88852c..b2e518f45 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowDriver.java @@ -132,13 +132,13 @@ public class WindowDriver extends WindowImpl { setGraphicsConfiguration(cfg); final int flags = getReconfigureFlags(0, true) & ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; - setWindowHandle(CreateWindow0(display.getHInstance(), display.getWindowClassName(), display.getWindowClassName(), + setWindowHandle(CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(), getParentWindowHandle(), getX(), getY(), getWidth(), getHeight(), autoPosition(), flags)); if (getWindowHandle() == 0) { throw new NativeWindowException("Error creating window"); } windowHandleClose = getWindowHandle(); - addMouseListener(new MouseTracker()); + addMouseListener(mouseTracker); if(DEBUG_IMPLEMENTATION) { Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+ @@ -146,13 +146,12 @@ public class WindowDriver extends WindowImpl { ") : HWND "+toHexString(getWindowHandle())+", "+Thread.currentThread()); e.printStackTrace(); } - } - - class MouseTracker extends MouseAdapter { + } + private MouseAdapter mouseTracker = new MouseAdapter() { public void mouseEntered(MouseEvent e) { WindowDriver.trackPointerLeave0(WindowDriver.this.getWindowHandle()); } - } + }; protected void closeNativeImpl() { if(windowHandleClose != 0) { @@ -334,8 +333,8 @@ public class WindowDriver extends WindowImpl { //---------------------------------------------------------------------- // Internals only // - protected static native boolean initIDs0(); protected static native long getNewtWndProc0(); + protected static native boolean initIDs0(long hInstance); private native long CreateWindow0(long hInstance, String wndClassName, String wndName, long parentWindowHandle, diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index c21cb4b40..8cea76ca5 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -47,6 +47,7 @@ import javax.media.nativewindow.util.Point; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; +import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.MouseEvent; public class WindowDriver extends WindowImpl { @@ -231,8 +232,9 @@ public class WindowDriver extends WindowImpl { // nop - using event driven insetsChange(..) } + @Override protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { + int x, int y, int button, float rotation) { switch(eventType) { case MouseEvent.EVENT_MOUSE_PRESSED: switch(button) { @@ -256,15 +258,17 @@ public class WindowDriver extends WindowImpl { button = 1; rotation = -1; break; - case X11_WHEEL_TWO_UP_BUTTON: + case X11_WHEEL_TWO_UP_BUTTON: // vertical scroll left eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; - button = 2; + button = 1; rotation = 1; + modifiers |= InputEvent.SHIFT_MASK; break; - case X11_WHEEL_TWO_DOWN_BUTTON: + case X11_WHEEL_TWO_DOWN_BUTTON: // vertical scroll right eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; - button = 2; + button = 1; rotation = -1; + modifiers |= InputEvent.SHIFT_MASK; break; } break; diff --git a/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java index e238f5d9e..0fc487e91 100644 --- a/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java +++ b/src/newt/classes/jogamp/newt/swt/event/SWTNewtEventFactory.java @@ -95,11 +95,11 @@ public class SWTNewtEventFactory { } int type = eventTypeSWT2NEWT.get(event.type); if(0xFFFFFFFF != type) { - int rotation = 0; + float rotation = 0; if (SWT.MouseVerticalWheel == event.type) { // SWT/NEWT rotation is reversed - AWT +1 is down, NEWT +1 is up. // rotation = -1 * (int) event.rotation; - rotation = (int) event.rotation; + rotation = (float) event.rotation; } int mods = swtModifiers2Newt(event.stateMask, true); |