From 03ff7dcf6b3f8ea80ea76379e34f9bcc01832a2c Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 29 May 2018 11:18:01 -0700 Subject: [PATCH] Added support for Android relative mouse mode on API 24 and above --- .../main/java/org/libsdl/app/SDLActivity.java | 42 ++++++- .../org/libsdl/app/SDLControllerManager.java | 111 +++++++++++++++++- 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 3ea99da9b..b1cd982c3 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -79,11 +79,24 @@ public class SDLActivity extends Activity { protected static SDLClipboardHandler mClipboardHandler; protected static Hashtable mCursors; protected static int mLastCursorID; + protected static SDLGenericMotionListener_API12 mMotionListener; // This is what SDL runs in. It invokes SDL_main(), eventually protected static Thread mSDLThread; + protected static SDLGenericMotionListener_API12 getMotionListener() { + if (mMotionListener == null) { + if (Build.VERSION.SDK_INT >= 24) { + mMotionListener = new SDLGenericMotionListener_API24(); + } else { + mMotionListener = new SDLGenericMotionListener_API12(); + } + } + + return mMotionListener; + } + /** * This method returns the name of the shared object with the application entry point * It can be overridden by derived classes. @@ -543,7 +556,7 @@ public class SDLActivity extends Activity { public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeKeyboardFocusLost(); - public static native void onNativeMouse(int button, int action, float x, float y); + public static native void onNativeMouse(int button, int action, float x, float y, boolean relative); public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p); @@ -641,6 +654,22 @@ public class SDLActivity extends Activity { } + /** + * This method is called by SDL using JNI. + */ + public static boolean supportsRelativeMouse() + { + return SDLActivity.getMotionListener().supportsRelativeMouse(); + } + + /** + * This method is called by SDL using JNI. + */ + public static boolean setRelativeMouseEnabled(boolean enabled) + { + return SDLActivity.getMotionListener().setRelativeMouseEnabled(enabled); + } + /** * This method is called by SDL using JNI. */ @@ -1231,7 +1260,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); if (Build.VERSION.SDK_INT >= 12) { - setOnGenericMotionListener(new SDLGenericMotionListener_API12()); + setOnGenericMotionListener(SDLActivity.getMotionListener()); } // Some arbitrary defaults to avoid a potential division by zero @@ -1456,7 +1485,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, mouseButton = 1; // oh well. } } - SDLActivity.onNativeMouse(mouseButton, action, event.getX(0), event.getY(0)); + + // We need to check if we're in relative mouse mode and get the axis offset rather than the x/y values + // if we are. We'll leverage our existing mouse motion listener + SDLGenericMotionListener_API12 motionListener = SDLActivity.getMotionListener(); + x = motionListener.getEventX(event); + y = motionListener.getEventY(event); + + SDLActivity.onNativeMouse(mouseButton, action, x, y, motionListener.inRelativeMode()); } else { switch(action) { case MotionEvent.ACTION_MOVE: diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index d0e9c8d5e..c2d394cd9 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -534,14 +534,14 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { case MotionEvent.ACTION_SCROLL: x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); - SDLActivity.onNativeMouse(0, action, x, y); + SDLActivity.onNativeMouse(0, action, x, y, false); return true; case MotionEvent.ACTION_HOVER_MOVE: x = event.getX(0); y = event.getY(0); - SDLActivity.onNativeMouse(0, action, x, y); + SDLActivity.onNativeMouse(0, action, x, y, false); return true; default: @@ -556,5 +556,112 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { // Event was not managed return false; } + + public boolean supportsRelativeMouse() { + return false; + } + + public boolean inRelativeMode() { + return false; + } + + public boolean setRelativeMouseEnabled(boolean enabled) { + return false; + } + + public float getEventX(MotionEvent event) { + return event.getX(0); + } + + public float getEventY(MotionEvent event) { + return event.getY(0); + } + +} + +class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 { + // Generic Motion (mouse hover, joystick...) events go here + + private boolean mRelativeModeEnabled; + + @Override + public boolean onGenericMotion(View v, MotionEvent event) { + float x, y; + int action; + + switch ( event.getSource() ) { + case InputDevice.SOURCE_JOYSTICK: + case InputDevice.SOURCE_GAMEPAD: + case InputDevice.SOURCE_DPAD: + return SDLControllerManager.handleJoystickMotionEvent(event); + + case InputDevice.SOURCE_MOUSE: + if (!SDLActivity.mSeparateMouseAndTouch) { + break; + } + action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_SCROLL: + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); + SDLActivity.onNativeMouse(0, action, x, y, false); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + if (mRelativeModeEnabled) { + x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + } + else { + x = event.getX(0); + y = event.getY(0); + } + + SDLActivity.onNativeMouse(0, action, x, y, mRelativeModeEnabled); + return true; + + default: + break; + } + break; + + default: + break; + } + + // Event was not managed + return false; + } + + public boolean supportsRelativeMouse() { + return true; + } + + public boolean inRelativeMode() { + return mRelativeModeEnabled; + } + + public boolean setRelativeMouseEnabled(boolean enabled) { + mRelativeModeEnabled = enabled; + return true; + } + + public float getEventX(MotionEvent event) { + if (mRelativeModeEnabled) { + return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + } + else { + return event.getX(0); + } + } + + public float getEventY(MotionEvent event) { + if (mRelativeModeEnabled) { + return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + } + else { + return event.getY(0); + } + } }