From dd67bba74220cc0882e70af490a4d564ac89f03d Mon Sep 17 00:00:00 2001 From: pelya Date: Wed, 13 Jun 2012 19:35:29 +0300 Subject: [PATCH] Proper mouse/stylus support in Gingerbread and ICS --- project/java/Settings.java | 1 - project/java/Video.java | 74 +++++---- .../ballfield/AndroidAppSettings.cfg | 6 +- .../jni/application/ballfield/ballfield.cpp | 13 +- .../src/video/android/SDL_androidinput.c | 150 ++++++++++++++---- 5 files changed, 172 insertions(+), 72 deletions(-) diff --git a/project/java/Settings.java b/project/java/Settings.java index 1c6c8411c..966fc95a1 100644 --- a/project/java/Settings.java +++ b/project/java/Settings.java @@ -2603,7 +2603,6 @@ class Settings int leftClickTimeout, int rightClickTimeout, int relativeMovement, int relativeMovementSpeed, int relativeMovementAccel, int showMouseCursor); - public static native void nativeSetExternalMouseDetected(); private static native void nativeSetJoystickUsed(); private static native void nativeSetMultitouchUsed(); private static native void nativeSetTouchscreenKeyboardUsed(); diff --git a/project/java/Video.java b/project/java/Video.java index 5f9798fa6..8e23a56f5 100644 --- a/project/java/Video.java +++ b/project/java/Video.java @@ -89,7 +89,10 @@ class Mouse abstract class DifferentTouchInput { - public static boolean ExternalMouseDetected = true; + public abstract void process(final MotionEvent event); + public abstract void processGenericEvent(final MotionEvent event); + + public static boolean ExternalMouseDetected = false; public static DifferentTouchInput getInstance() { @@ -105,7 +108,9 @@ abstract class DifferentTouchInput multiTouchAvailable2 = true; } try { - if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD ) + if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH && IcsTouchInput.Holder.sInstance != null ) + return IcsTouchInput.Holder.sInstance; + if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD && XperiaPlayTouchpadTouchInput.Holder.sInstance != null ) return XperiaPlayTouchpadTouchInput.Holder.sInstance; if (multiTouchAvailable1 && multiTouchAvailable2) return MultiTouchInput.Holder.sInstance; @@ -122,8 +127,6 @@ abstract class DifferentTouchInput } } } - public abstract void process(final MotionEvent event); - public abstract void processGenericEvent(final MotionEvent event); private static class SingleTouchInput extends DifferentTouchInput { private static class Holder @@ -145,14 +148,13 @@ abstract class DifferentTouchInput if( event.getAction() == MotionEvent.ACTION_MOVE ) action = Mouse.SDL_FINGER_MOVE; if ( action >= 0 ) - DemoGLSurfaceView.nativeMouse( (int)event.getX(), (int)event.getY(), action, 0, + DemoGLSurfaceView.nativeMotionEvent( (int)event.getX(), (int)event.getY(), action, 0, (int)(event.getPressure() * 1000.0), (int)(event.getSize() * 1000.0) ); } } private static class MultiTouchInput extends DifferentTouchInput { - public static final int TOUCH_EVENTS_MAX = 16; // Max multitouch pointers private class touchEvent @@ -196,7 +198,7 @@ abstract class DifferentTouchInput if( touchEvents[i].down ) { touchEvents[i].down = false; - DemoGLSurfaceView.nativeMouse( touchEvents[i].x, touchEvents[i].y, action, i, touchEvents[i].pressure, touchEvents[i].size ); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[i].x, touchEvents[i].y, action, i, touchEvents[i].pressure, touchEvents[i].size ); } } } @@ -213,7 +215,7 @@ abstract class DifferentTouchInput touchEvents[id].y = (int)event.getY(i); touchEvents[id].pressure = (int)(event.getPressure(i) * 1000.0); touchEvents[id].size = (int)(event.getSize(i) * 1000.0); - DemoGLSurfaceView.nativeMouse( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); } } if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE || @@ -247,7 +249,7 @@ abstract class DifferentTouchInput { action = Mouse.SDL_FINGER_UP; touchEvents[id].down = false; - DemoGLSurfaceView.nativeMouse( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); } } else @@ -270,20 +272,12 @@ abstract class DifferentTouchInput touchEvents[id].y = (int)event.getY(ii); touchEvents[id].pressure = (int)(event.getPressure(ii) * 1000.0); touchEvents[id].size = (int)(event.getSize(ii) * 1000.0); - DemoGLSurfaceView.nativeMouse( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); } } } if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_HOVER_MOVE ) // Support bluetooth/USB mouse - available since Android 3.1 { - /* - if( !ExternalMouseDetected ) - { - ExternalMouseDetected = true; - Settings.nativeSetExternalMouseDetected(); - Toast.makeText(MainActivity.instance, R.string.hardware_mouse_detected, Toast.LENGTH_SHORT).show(); - } - */ // TODO: it is possible that multiple pointers return that event, but we're handling only pointer #0 if( touchEvents[0].down ) action = Mouse.SDL_FINGER_UP; @@ -294,7 +288,7 @@ abstract class DifferentTouchInput touchEvents[0].y = (int)event.getY(); touchEvents[0].pressure = 0; touchEvents[0].size = 0; - DemoGLSurfaceView.nativeMouse( touchEvents[0].x, touchEvents[0].y, action, 0, touchEvents[0].pressure, touchEvents[0].size ); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[0].x, touchEvents[0].y, action, 0, touchEvents[0].pressure, touchEvents[0].size ); } } } @@ -343,19 +337,20 @@ abstract class DifferentTouchInput minRange = Math.min( Math.abs(ymax - ymin), Math.abs(xmax - xmin) ); } } + public void process(final MotionEvent event) + { + boolean hwMouseEvent = ( event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == InputDevice.SOURCE_STYLUS ); + if( ExternalMouseDetected != hwMouseEvent ) + { + ExternalMouseDetected = hwMouseEvent; + DemoGLSurfaceView.nativeHardwareMouseDetected(hwMouseEvent ? 1 : 0); + } + super.process(event); + } public void processGenericEvent(final MotionEvent event) { if( event.getSource() != InputDevice.SOURCE_TOUCHPAD ) { - /* - if( !ExternalMouseDetected && - ( event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == InputDevice.SOURCE_STYLUS ) ) - { - ExternalMouseDetected = true; - Settings.nativeSetExternalMouseDetected(); - Toast.makeText(MainActivity.instance, R.string.hardware_mouse_detected, Toast.LENGTH_SHORT).show(); - } - */ process(event); return; } @@ -385,6 +380,24 @@ abstract class DifferentTouchInput DemoGLSurfaceView.nativeTouchpad( x, 65535-y, down, multitouch ); // Y axis is inverted, as you may have guessed } } + private static class IcsTouchInput extends XperiaPlayTouchpadTouchInput + { + private static class Holder + { + private static final IcsTouchInput sInstance = new IcsTouchInput(); + } + private int buttonState = 0; + public void process(final MotionEvent event) + { + if( event.getButtonState() != buttonState ) + { + buttonState = event.getButtonState(); + //System.out.println("IcsTouchInput: button state " + buttonState); + DemoGLSurfaceView.nativeMouseButtonsPressed(buttonState); + } + super.process(event); + } + } } @@ -436,7 +449,6 @@ class DemoRenderer extends GLSurfaceView_SDL.Renderer MainActivity.LoadApplicationLibrary(context); Settings.Apply(context); - DifferentTouchInput.ExternalMouseDetected = false; accelerometer = new AccelerometerReader(context); // Tweak video thread priority, if user selected big audio buffer if(Globals.AudioBufferConfig >= 2) @@ -676,10 +688,12 @@ class DemoGLSurfaceView extends GLSurfaceView_SDL { MainActivity mParent; DifferentTouchInput touchInput = null; - public static native void nativeMouse( int x, int y, int action, int pointerId, int pressure, int radius ); + public static native void nativeMotionEvent( int x, int y, int action, int pointerId, int pressure, int radius ); public static native int nativeKey( int keyCode, int down ); public static native void nativeTouchpad( int x, int y, int down, int multitouch ); public static native void initJavaCallbacks(); + public static native void nativeHardwareMouseDetected( int detected ); + public static native void nativeMouseButtonsPressed( int buttons ); } diff --git a/project/jni/application/ballfield/AndroidAppSettings.cfg b/project/jni/application/ballfield/AndroidAppSettings.cfg index e32fd64f5..a91e87815 100644 --- a/project/jni/application/ballfield/AndroidAppSettings.cfg +++ b/project/jni/application/ballfield/AndroidAppSettings.cfg @@ -19,16 +19,16 @@ AppUsesMouse=y AppNeedsTwoButtonMouse=y ShowMouseCursor=n ForceRelativeMouseMode=n -AppNeedsArrowKeys=y +AppNeedsArrowKeys=n AppNeedsTextInput=y -AppUsesJoystick=y +AppUsesJoystick=n AppHandlesJoystickSensitivity=n AppUsesMultitouch=y NonBlockingSwapBuffers=n RedefinedKeys="SPACE RETURN NO_REMAP NO_REMAP SPACE ESCAPE" AppTouchscreenKeyboardKeysAmount=0 AppTouchscreenKeyboardKeysAmountAutoFire=0 -RedefinedKeysScreenKb="1 2 3 4 5 6 1 2 3 4" +RedefinedKeysScreenKb="0 1 2 3 4 5 6 7 8 9" StartupMenuButtonTimeout=3000 HiddenMenuOptions='OptionalDownloadConfig' FirstStartMenuOptions='' diff --git a/project/jni/application/ballfield/ballfield.cpp b/project/jni/application/ballfield/ballfield.cpp index 594e4edbc..e16d19a24 100644 --- a/project/jni/application/ballfield/ballfield.cpp +++ b/project/jni/application/ballfield/ballfield.cpp @@ -615,11 +615,12 @@ int main(int argc, char* argv[]) val1 = misaligned_mem_access(val0, 1); val2 = misaligned_mem_access(val0, 2); val3 = misaligned_mem_access(val0, 3); + /* print_num_hex(screen, font_hex, 0, 40, val0); print_num_hex(screen, font_hex, 0, 60, val1); print_num_hex(screen, font_hex, 0, 80, val2); print_num_hex(screen, font_hex, 0, 100, val3); - + */ print_num(screen, font, screen->w-37, screen->h-12, fps); ++fps_count; @@ -643,10 +644,12 @@ int main(int argc, char* argv[]) if( b ) { color = 0; - if( b & SDL_BUTTON_LEFT ) - color |= 0xff00; - if( b & SDL_BUTTON_RIGHT ) - color |= 0xff0000; + if( b & SDL_BUTTON_LMASK ) + color |= 0xf000; + if( b & SDL_BUTTON_RMASK ) + color |= 0x1f0; + if( b & SDL_BUTTON_MMASK ) + color |= 0x1f; } r.x = mx; r.y = my; diff --git a/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c b/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c index d798d9919..b6ce49de9 100644 --- a/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c +++ b/project/jni/sdl-1.3/src/video/android/SDL_androidinput.c @@ -83,40 +83,45 @@ SDL_Joystick *SDL_ANDROID_CurrentJoysticks[MAX_MULTITOUCH_POINTERS+1] = {NULL}; static int TrackballDampening = 0; // in milliseconds static Uint32 lastTrackballAction = 0; enum { TOUCH_PTR_UP = 0, TOUCH_PTR_MOUSE = 1, TOUCH_PTR_SCREENKB = 2 }; -int touchPointers[MAX_MULTITOUCH_POINTERS] = {0}; -int firstMousePointerId = -1; +static int touchPointers[MAX_MULTITOUCH_POINTERS] = {0}; +static int firstMousePointerId = -1; enum { MAX_MULTITOUCH_GESTURES = 4 }; -int multitouchGestureKeycode[MAX_MULTITOUCH_GESTURES] = { +static int multitouchGestureKeycode[MAX_MULTITOUCH_GESTURES] = { SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_6)), SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_7)), SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_8)), SDL_KEY(SDL_KEY_VAL(SDL_ANDROID_SCREENKB_KEYCODE_9)) }; -int multitouchGestureKeyPressed[MAX_MULTITOUCH_GESTURES] = { 0, 0, 0, 0 }; -int multitouchGestureSensitivity = 0; -int multitouchGestureDist = -1; -int multitouchGestureAngle = 0; -int multitouchGestureX = -1; -int multitouchGestureY = -1; +static int multitouchGestureKeyPressed[MAX_MULTITOUCH_GESTURES] = { 0, 0, 0, 0 }; +static int multitouchGestureSensitivity = 0; +static int multitouchGestureDist = -1; +static int multitouchGestureAngle = 0; +static int multitouchGestureX = -1; +static int multitouchGestureY = -1; int SDL_ANDROID_TouchscreenCalibrationWidth = 480; int SDL_ANDROID_TouchscreenCalibrationHeight = 320; int SDL_ANDROID_TouchscreenCalibrationX = 0; int SDL_ANDROID_TouchscreenCalibrationY = 0; -int leftClickTimeout = 0; -int rightClickTimeout = 0; -int mouseInitialX = -1; -int mouseInitialY = -1; -unsigned int mouseInitialTime = 0; -volatile int deferredMouseTap = 0; -int relativeMovement = 0; -int relativeMovementSpeed = 2; -int relativeMovementAccel = 0; -int relativeMovementX = 0; -int relativeMovementY = 0; -unsigned int relativeMovementTime = 0; -int oldMouseX = 0; -int oldMouseY = 0; -int oldMouseButtons = 0; +static int leftClickTimeout = 0; +static int rightClickTimeout = 0; +static int mouseInitialX = -1; +static int mouseInitialY = -1; +static unsigned int mouseInitialTime = 0; +static volatile int deferredMouseTap = 0; +static int relativeMovement = 0; +static int relativeMovementSpeed = 2; +static int relativeMovementAccel = 0; +static int relativeMovementX = 0; +static int relativeMovementY = 0; +static unsigned int relativeMovementTime = 0; +static int oldMouseX = 0; +static int oldMouseY = 0; +static int oldMouseButtons = 0; + +static int hardwareMouseDetected = 0; +enum { MOUSE_HW_BUTTON_LEFT = 1, MOUSE_HW_BUTTON_RIGHT = 2, MOUSE_HW_BUTTON_MIDDLE = 4, MOUSE_HW_BUTTON_BACK = 8, MOUSE_HW_BUTTON_FORWARD = 16, MOUSE_HW_BUTTON_MAX = MOUSE_HW_BUTTON_FORWARD }; +static int hardwareMouseButtonsPressed = 0; +static int hardwareMouseButtonsPressedOld = 0; static int UnicodeToUtf8(int src, char * dest) { @@ -265,7 +270,7 @@ void UpdateScreenUnderFingerRect(int x, int y) JNIEXPORT void JNICALL -JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouse) ( JNIEnv* env, jobject thiz, jint x, jint y, jint action, jint pointerId, jint force, jint radius ) +JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMotionEvent) ( JNIEnv* env, jobject thiz, jint x, jint y, jint action, jint pointerId, jint force, jint radius ) { // TODO: this method is damn huge int i; @@ -351,7 +356,7 @@ JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouse) ( JNIEnv* env, jobject thiz, j } } } - else + else if( !hardwareMouseDetected ) { if( firstMousePointerId != pointerId ) { @@ -438,6 +443,7 @@ JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouse) ( JNIEnv* env, jobject thiz, j #endif // The old, bad, deprecated, but still used multitouch API + /* if( action == MOUSE_DOWN ) SDL_ANDROID_MainThreadPushJoystickButton(pointerId+1, 0, SDL_PRESSED); SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 0, x); @@ -446,6 +452,7 @@ JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouse) ( JNIEnv* env, jobject thiz, j SDL_ANDROID_MainThreadPushJoystickAxis(pointerId+1, 3, radius); if( action == MOUSE_UP ) SDL_ANDROID_MainThreadPushJoystickButton(pointerId+1, 0, SDL_RELEASED); + */ // The new, good, clean multitouch API, which is using only the first joystick, and sending both X and Y coords simultaneously in one event if( action == MOUSE_DOWN ) SDL_ANDROID_MainThreadPushJoystickButton(0, pointerId, SDL_PRESSED); @@ -465,7 +472,46 @@ JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouse) ( JNIEnv* env, jobject thiz, j if( !isMouseUsed ) return; - if( pointerId == firstMousePointerId ) + //__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse buttons %d pointerId %d firstMousePointerId %d", hardwareMouseButtonsPressed, pointerId, firstMousePointerId); + if( pointerId == firstMousePointerId && (hardwareMouseButtonsPressedOld != hardwareMouseButtonsPressed || hardwareMouseButtonsPressed != 0) ) + { + SDL_ANDROID_MainThreadPushMouseMotion(x, y); + for( i = 1; i <= MOUSE_HW_BUTTON_MAX; i *= 2 ) + { + int btn = SDL_BUTTON_LEFT; + switch(i) + { + case MOUSE_HW_BUTTON_LEFT: + btn = SDL_BUTTON_LEFT; + break; + case MOUSE_HW_BUTTON_RIGHT: + btn = SDL_BUTTON_RIGHT; + break; + case MOUSE_HW_BUTTON_MIDDLE: + btn = SDL_BUTTON_MIDDLE; + break; + case MOUSE_HW_BUTTON_BACK: + btn = SDL_BUTTON_WHEELUP; + break; + case MOUSE_HW_BUTTON_FORWARD: + btn = SDL_BUTTON_WHEELDOWN; + break; + } + if( (hardwareMouseButtonsPressed & i) && !(hardwareMouseButtonsPressedOld & i) ) + { + //__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse button DOWN: %d", btn); + SDL_ANDROID_MainThreadPushMouseButton( SDL_PRESSED, btn ); + } + else + if( !(hardwareMouseButtonsPressed & i) && (hardwareMouseButtonsPressedOld & i) ) + { + //__android_log_print(ANDROID_LOG_INFO, "libSDL", "Mouse button UP : %d", btn); + SDL_ANDROID_MainThreadPushMouseButton( SDL_RELEASED, btn ); + } + } + hardwareMouseButtonsPressedOld = hardwareMouseButtonsPressed; + } + else if( pointerId == firstMousePointerId ) { if( relativeMovement ) { @@ -919,16 +965,54 @@ JAVA_EXPORT_NAME(Settings_nativeSetMouseUsed) (JNIEnv* env, jobject thiz, } JNIEXPORT void JNICALL -JAVA_EXPORT_NAME(Settings_nativeSetExternalMouseDetected) (JNIEnv* env, jobject thiz) +JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeHardwareMouseDetected) (JNIEnv* env, jobject thiz, int detected) { if( !isMouseUsed ) return; - leftClickMethod = LEFT_CLICK_NORMAL; - SDL_ANDROID_ShowScreenUnderFinger = 0; - leftClickTimeout = 0; - relativeMovement = 0; - SDL_ANDROID_ShowMouseCursor = 0; + static struct { + int leftClickMethod; + int ShowScreenUnderFinger; + int leftClickTimeout; + int relativeMovement; + int ShowMouseCursor; + } cfg = { 0 }; + + if( hardwareMouseDetected != detected ) + { + hardwareMouseDetected = detected; + if(detected) + { + cfg.leftClickMethod = leftClickMethod; + cfg.ShowScreenUnderFinger = SDL_ANDROID_ShowScreenUnderFinger; + cfg.leftClickTimeout = leftClickTimeout; + cfg.relativeMovement = relativeMovement; + cfg.ShowMouseCursor = SDL_ANDROID_ShowMouseCursor; + + leftClickMethod = LEFT_CLICK_NORMAL; + SDL_ANDROID_ShowScreenUnderFinger = 0; + leftClickTimeout = 0; + relativeMovement = 0; + SDL_ANDROID_ShowMouseCursor = 0; + } + else + { + leftClickMethod = cfg.leftClickMethod; + SDL_ANDROID_ShowScreenUnderFinger = cfg.ShowScreenUnderFinger; + leftClickTimeout = cfg.leftClickTimeout; + relativeMovement = cfg.relativeMovement; + SDL_ANDROID_ShowMouseCursor = cfg.ShowMouseCursor; + } + } +} + +JNIEXPORT void JNICALL +JAVA_EXPORT_NAME(DemoGLSurfaceView_nativeMouseButtonsPressed) (JNIEnv* env, jobject thiz, int buttons) +{ + if( !isMouseUsed ) + return; + + hardwareMouseButtonsPressed = buttons; } JNIEXPORT void JNICALL