From 286413f8f8e977c7c1b1881584eebb6d320a7f02 Mon Sep 17 00:00:00 2001 From: hwsmm <9151706+hwsmm@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:54:29 +0900 Subject: [PATCH 1/4] Expose SDL_GetPenStatus for Android pen buttons --- src/events/SDL_pen.c | 20 ++++++++++---------- src/events/SDL_pen_c.h | 3 +++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/events/SDL_pen.c b/src/events/SDL_pen.c index 65f7720853fc9..509dc2c8e54b9 100644 --- a/src/events/SDL_pen.c +++ b/src/events/SDL_pen.c @@ -158,6 +158,16 @@ bool SDL_GetPenInfo(SDL_PenID instance_id, SDL_PenInfo *info) return result; } +bool SDL_PenConnected(SDL_PenID instance_id) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + const bool result = (pen != NULL); + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} +#endif + SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_axes) { if (num_axes < 0) { @@ -181,16 +191,6 @@ SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_a return result; } -bool SDL_PenConnected(SDL_PenID instance_id) -{ - SDL_LockRWLockForReading(pen_device_rwlock); - const SDL_Pen *pen = FindPenByInstanceId(instance_id); - const bool result = (pen != NULL); - SDL_UnlockRWLock(pen_device_rwlock); - return result; -} -#endif - SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis) { // the initial capability bits happen to match up, but as diff --git a/src/events/SDL_pen_c.h b/src/events/SDL_pen_c.h index 7e069b00052af..3b24551c7d4d0 100644 --- a/src/events/SDL_pen_c.h +++ b/src/events/SDL_pen_c.h @@ -84,6 +84,9 @@ extern SDL_PenID SDL_FindPenByHandle(void *handle); // Backend can optionally use this to find a SDL_PenID, selected by a callback examining all devices. Zero if not found. extern SDL_PenID SDL_FindPenByCallback(bool (*callback)(void *handle, void *userdata), void *userdata); +// Backend can use this to query current pen status. +SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_axes); + // Backend can use this to map an axis to a capability bit. SDL_PenCapabilityFlags SDL_GetPenCapabilityFromAxis(SDL_PenAxis axis); From e6ae8fef969ef4c6902d7a682e448c8dc2d66a9a Mon Sep 17 00:00:00 2001 From: hwsmm <9151706+hwsmm@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:56:32 +0900 Subject: [PATCH 2/4] Add SDL_androidpen --- src/video/android/SDL_androidpen.c | 96 ++++++++++++++++++++++++++++++ src/video/android/SDL_androidpen.h | 25 ++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/video/android/SDL_androidpen.c create mode 100644 src/video/android/SDL_androidpen.h diff --git a/src/video/android/SDL_androidpen.c b/src/video/android/SDL_androidpen.c new file mode 100644 index 0000000000000..65730bd75dce3 --- /dev/null +++ b/src/video/android/SDL_androidpen.c @@ -0,0 +1,96 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidpen.h" +#include "../../events/SDL_pen_c.h" +#include "../../core/android/SDL_android.h" + +#define ACTION_DOWN 0 +#define ACTION_UP 1 +#define ACTION_POINTER_DOWN 5 +#define ACTION_POINTER_UP 6 +#define ACTION_HOVER_EXIT 10 + +void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p) +{ + if (!window) { + return; + } + + // pointer index starts from zero. + pen_id_in++; + + SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) pen_id_in); + if (!pen) { + // TODO: Query JNI for pen device info + SDL_PenInfo peninfo; + SDL_zero(peninfo); + peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ERASER; + peninfo.num_buttons = 2; + peninfo.subtype = SDL_PEN_TYPE_PEN; + pen = SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) pen_id_in); + if (!pen) { + SDL_Log("error: can't add a pen device %d", pen_id_in); + return; + } + } + + if (action == ACTION_HOVER_EXIT) { + SDL_RemovePenDevice(0, pen); + return; + } + + SDL_SendPenMotion(0, pen, window, x, y); + SDL_SendPenAxis(0, pen, window, SDL_PEN_AXIS_PRESSURE, p); + // TODO: add more axis + + SDL_PenInputFlags current = SDL_GetPenStatus(pen, NULL, 0); + int diff = current ^ button; + if (diff != 0) { + // Android only exposes BUTTON_STYLUS_PRIMARY and BUTTON_STYLUS_SECONDARY + if (diff & SDL_PEN_INPUT_BUTTON_1) + SDL_SendPenButton(0, pen, window, 1, (button & SDL_PEN_INPUT_BUTTON_1) != 0); + + if (diff & SDL_PEN_INPUT_BUTTON_2) + SDL_SendPenButton(0, pen, window, 2, (button & SDL_PEN_INPUT_BUTTON_2) != 0); + } + + // button contains DOWN/ERASER_TIP on DOWN/UP regardless of pressed state, use action to distinguish + switch (action) { + case ACTION_DOWN: + case ACTION_POINTER_DOWN: + SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, true); + break; + + case ACTION_UP: + case ACTION_POINTER_UP: + SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, false); + break; + + default: + break; + } +} + +#endif // SDL_VIDEO_DRIVER_ANDROID diff --git a/src/video/android/SDL_androidpen.h b/src/video/android/SDL_androidpen.h new file mode 100644 index 0000000000000..15c2256361da7 --- /dev/null +++ b/src/video/android/SDL_androidpen.h @@ -0,0 +1,25 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "SDL_androidvideo.h" + +extern void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p); From 9355f0caa8068608f9842a0bc46135525dbd512f Mon Sep 17 00:00:00 2001 From: hwsmm <9151706+hwsmm@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:58:39 +0900 Subject: [PATCH 3/4] Make onNativePen available for Android --- .../main/java/org/libsdl/app/SDLActivity.java | 1 + src/core/android/SDL_android.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) 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 8666885a4a4bd..a1edff7f407de 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 @@ -1059,6 +1059,7 @@ protected boolean sendCommand(int command, Object data) { public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p); + public static native void onNativePen(int penId, int button, int action, float x, float y, float p); public static native void onNativeAccel(float x, float y, float z); public static native void onNativeClipboardChanged(); public static native void onNativeSurfaceCreated(); diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 904237a2b47aa..1354952a655f1 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -28,6 +28,7 @@ #include "../../video/android/SDL_androidkeyboard.h" #include "../../video/android/SDL_androidmouse.h" #include "../../video/android/SDL_androidtouch.h" +#include "../../video/android/SDL_androidpen.h" #include "../../video/android/SDL_androidvideo.h" #include "../../video/android/SDL_androidwindow.h" #include "../../joystick/android/SDL_sysjoystick_c.h" @@ -118,6 +119,10 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)( JNIEnv *env, jclass jcls, jint button, jint action, jfloat x, jfloat y, jboolean relative); +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePen)( + JNIEnv *env, jclass jcls, + jint pen_id_in, jint button, jint action, jfloat x, jfloat y, jfloat p); + JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)( JNIEnv *env, jclass jcls, jfloat x, jfloat y, jfloat z); @@ -209,6 +214,7 @@ static JNINativeMethod SDLActivity_tab[] = { { "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) }, { "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) }, { "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) }, + { "onNativePen", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) }, { "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) }, { "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) }, { "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) }, @@ -1362,6 +1368,18 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)( SDL_UnlockMutex(Android_ActivityMutex); } +// Pen +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePen)( + JNIEnv *env, jclass jcls, + jint pen_id_in, jint button, jint action, jfloat x, jfloat y, jfloat p) +{ + SDL_LockMutex(Android_ActivityMutex); + + Android_OnPen(Android_Window, pen_id_in, button, action, x, y, p); + + SDL_UnlockMutex(Android_ActivityMutex); +} + // Accelerometer JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)( JNIEnv *env, jclass jcls, From 6003842e31ea5e6da7c4ca4be5e52fb67a2afac8 Mon Sep 17 00:00:00 2001 From: hwsmm <9151706+hwsmm@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:04:40 +0900 Subject: [PATCH 4/4] Refactor Android input handling and add pen support --- .../main/java/org/libsdl/app/SDLActivity.java | 6 +- .../org/libsdl/app/SDLControllerManager.java | 183 ++++++----------- .../main/java/org/libsdl/app/SDLSurface.java | 193 ++++++++---------- src/video/android/SDL_androidpen.c | 22 +- 4 files changed, 163 insertions(+), 241 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 a1edff7f407de..6067fa74dcafc 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 @@ -223,7 +223,7 @@ public enum NativeState { protected static SDLClipboardHandler mClipboardHandler; protected static Hashtable mCursors; protected static int mLastCursorID; - protected static SDLGenericMotionListener_API12 mMotionListener; + protected static SDLGenericMotionListener_API14 mMotionListener; protected static HIDDeviceManager mHIDDeviceManager; // This is what SDL runs in. It invokes SDL_main(), eventually @@ -232,14 +232,14 @@ public enum NativeState { protected static boolean mActivityCreated = false; private static SDLFileDialogState mFileDialogState = null; - protected static SDLGenericMotionListener_API12 getMotionListener() { + protected static SDLGenericMotionListener_API14 getMotionListener() { if (mMotionListener == null) { if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) { mMotionListener = new SDLGenericMotionListener_API26(); } else if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) { mMotionListener = new SDLGenericMotionListener_API24(); } else { - mMotionListener = new SDLGenericMotionListener_API12(); + mMotionListener = new SDLGenericMotionListener_API14(); } } 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 b7faee89972e3..dc6fb9d12a6ce 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 @@ -662,44 +662,61 @@ protected SDLHaptic getHaptic(int device_id) { } } -class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { +class SDLGenericMotionListener_API14 implements View.OnGenericMotionListener { // Generic Motion (mouse hover, joystick...) events go here @Override public boolean onGenericMotion(View v, MotionEvent event) { + if (event.getSource() == InputDevice.SOURCE_JOYSTICK) + return SDLControllerManager.handleJoystickMotionEvent(event); + float x, y; - int action; + int action = event.getActionMasked(); + int pointerCount = event.getPointerCount(); + boolean consumed = false; - switch ( event.getSource() ) { - case InputDevice.SOURCE_JOYSTICK: - return SDLControllerManager.handleJoystickMotionEvent(event); + for (int i = 0; i < pointerCount; i++) { + int toolType = event.getToolType(i); - case InputDevice.SOURCE_MOUSE: - action = event.getActionMasked(); + if (toolType == MotionEvent.TOOL_TYPE_MOUSE) { switch (action) { case MotionEvent.ACTION_SCROLL: - x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); - y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, i); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, i); SDLActivity.onNativeMouse(0, action, x, y, false); - return true; + consumed = true; + break; case MotionEvent.ACTION_HOVER_MOVE: - x = event.getX(0); - y = event.getY(0); + x = getEventX(event, i); + y = getEventY(event, i); - SDLActivity.onNativeMouse(0, action, x, y, false); - return true; + SDLActivity.onNativeMouse(0, action, x, y, checkRelativeEvent(event)); + consumed = true; + break; default: break; } - break; + } else if (toolType == MotionEvent.TOOL_TYPE_STYLUS || toolType == MotionEvent.TOOL_TYPE_ERASER) { + switch (action) { + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + case MotionEvent.ACTION_HOVER_EXIT: + x = event.getX(i); + y = event.getY(i); + float p = event.getPressure(i); + + // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4 + int buttons = event.getButtonState() >> 4; - default: - break; + SDLActivity.onNativePen(event.getPointerId(i), buttons, action, x, y, p); + consumed = true; + break; + } + } } - // Event was not managed - return false; + return consumed; } public boolean supportsRelativeMouse() { @@ -714,46 +731,29 @@ public boolean setRelativeMouseEnabled(boolean enabled) { return false; } - public void reclaimRelativeMouseModeIfNeeded() - { + public void reclaimRelativeMouseModeIfNeeded() { + + } + public boolean checkRelativeEvent(MotionEvent event) { + return inRelativeMode(); } - public float getEventX(MotionEvent event) { - return event.getX(0); + public float getEventX(MotionEvent event, int pointerIndex) { + return event.getX(pointerIndex); } - public float getEventY(MotionEvent event) { - return event.getY(0); + public float getEventY(MotionEvent event, int pointerIndex) { + return event.getY(pointerIndex); } } -class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 { +class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 { // Generic Motion (mouse hover, joystick...) events go here private boolean mRelativeModeEnabled; - @Override - public boolean onGenericMotion(View v, MotionEvent event) { - - // Handle relative mouse mode - if (mRelativeModeEnabled) { - if (event.getSource() == InputDevice.SOURCE_MOUSE) { - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_HOVER_MOVE) { - float x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); - float y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); - SDLActivity.onNativeMouse(0, action, x, y, true); - return true; - } - } - } - - // Event was not managed, call SDLGenericMotionListener_API12 method - return super.onGenericMotion(v, event); - } - @Override public boolean supportsRelativeMouse() { return true; @@ -771,20 +771,20 @@ public boolean setRelativeMouseEnabled(boolean enabled) { } @Override - public float getEventX(MotionEvent event) { - if (mRelativeModeEnabled) { - return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + public float getEventX(MotionEvent event, int pointerIndex) { + if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) { + return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X, pointerIndex); } else { - return event.getX(0); + return event.getX(pointerIndex); } } @Override - public float getEventY(MotionEvent event) { - if (mRelativeModeEnabled) { - return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + public float getEventY(MotionEvent event, int pointerIndex) { + if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) { + return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y, pointerIndex); } else { - return event.getY(0); + return event.getY(pointerIndex); } } } @@ -793,65 +793,6 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 { // 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: - return SDLControllerManager.handleJoystickMotionEvent(event); - - case InputDevice.SOURCE_MOUSE: - // DeX desktop mouse cursor is a separate non-standard input type. - case InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN: - 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: - x = event.getX(0); - y = event.getY(0); - SDLActivity.onNativeMouse(0, action, x, y, false); - return true; - - default: - break; - } - break; - - case InputDevice.SOURCE_MOUSE_RELATIVE: - 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: - x = event.getX(0); - y = event.getY(0); - SDLActivity.onNativeMouse(0, action, x, y, true); - return true; - - default: - break; - } - break; - - default: - break; - } - - // Event was not managed - return false; - } - @Override public boolean supportsRelativeMouse() { return (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */); @@ -878,22 +819,26 @@ public boolean setRelativeMouseEnabled(boolean enabled) { } @Override - public void reclaimRelativeMouseModeIfNeeded() - { + public void reclaimRelativeMouseModeIfNeeded() { if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) { SDLActivity.getContentView().requestPointerCapture(); } } @Override - public float getEventX(MotionEvent event) { + public boolean checkRelativeEvent(MotionEvent event) { + return event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE; + } + + @Override + public float getEventX(MotionEvent event, int pointerIndex) { // Relative mouse in capture mode will only have relative for X/Y - return event.getX(0); + return event.getX(pointerIndex); } @Override - public float getEventY(MotionEvent event) { + public float getEventY(MotionEvent event, int pointerIndex) { // Relative mouse in capture mode will only have relative for X/Y - return event.getY(0); + return event.getY(pointerIndex); } } diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java b/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java index d896f6ce4a663..6b5f4346622db 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java @@ -239,93 +239,65 @@ public boolean onTouch(View v, MotionEvent event) { int touchDevId = event.getDeviceId(); final int pointerCount = event.getPointerCount(); int action = event.getActionMasked(); - int pointerFingerId; - int i = -1; + int pointerId; + int i = 0; float x,y,p; - // 12290 = Samsung DeX mode desktop mouse - // 12290 = 0x3002 = 0x2002 | 0x1002 = SOURCE_MOUSE | SOURCE_TOUCHSCREEN - // 0x2 = SOURCE_CLASS_POINTER - if (event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == (InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN)) { - int mouseButton = 1; - try { - Object object = event.getClass().getMethod("getButtonState").invoke(event); - if (object != null) { - mouseButton = (Integer) object; + if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) + i = event.getActionIndex(); + + do { + int toolType = event.getToolType(i); + + if (toolType == MotionEvent.TOOL_TYPE_MOUSE) { + int buttonState = event.getButtonState(); + boolean relative = false; + + // 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_API14 motionListener = SDLActivity.getMotionListener(); + x = motionListener.getEventX(event, i); + y = motionListener.getEventY(event, i); + relative = motionListener.inRelativeMode(); + + SDLActivity.onNativeMouse(buttonState, action, x, y, relative); + } else if (toolType == MotionEvent.TOOL_TYPE_STYLUS || toolType == MotionEvent.TOOL_TYPE_ERASER) { + pointerId = event.getPointerId(i); + x = event.getX(i); + y = event.getY(i); + p = event.getPressure(i); + if (p > 1.0f) { + // may be larger than 1.0f on some devices + // see the documentation of getPressure(i) + p = 1.0f; } - } catch(Exception ignored) { - } - - // 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: - for (i = 0; i < pointerCount; i++) { - pointerFingerId = event.getPointerId(i); - x = getNormalizedX(event.getX(i)); - y = getNormalizedY(event.getY(i)); - p = event.getPressure(i); - if (p > 1.0f) { - // may be larger than 1.0f on some devices - // see the documentation of getPressure(i) - p = 1.0f; - } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_DOWN: - // Primary pointer up/down, the index is always zero - i = 0; - /* fallthrough */ - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: - // Non primary pointer up/down - if (i == -1) { - i = event.getActionIndex(); - } - - pointerFingerId = event.getPointerId(i); - x = getNormalizedX(event.getX(i)); - y = getNormalizedY(event.getY(i)); - p = event.getPressure(i); - if (p > 1.0f) { - // may be larger than 1.0f on some devices - // see the documentation of getPressure(i) - p = 1.0f; - } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - break; - - case MotionEvent.ACTION_CANCEL: - for (i = 0; i < pointerCount; i++) { - pointerFingerId = event.getPointerId(i); - x = getNormalizedX(event.getX(i)); - y = getNormalizedY(event.getY(i)); - p = event.getPressure(i); - if (p > 1.0f) { - // may be larger than 1.0f on some devices - // see the documentation of getPressure(i) - p = 1.0f; - } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); - } - break; + // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4, and apply SDL_PEN_INPUT_DOWN/SDL_PEN_INPUT_ERASER_TIP + int buttonState = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30)); + + SDLActivity.onNativePen(pointerId, buttonState, action, x, y, p); + } else if (toolType == MotionEvent.TOOL_TYPE_FINGER) { + pointerId = event.getPointerId(i); + x = getNormalizedX(event.getX(i)); + y = getNormalizedY(event.getY(i)); + p = event.getPressure(i); + if (p > 1.0f) { + // may be larger than 1.0f on some devices + // see the documentation of getPressure(i) + p = 1.0f; + } - default: - break; + SDLActivity.onNativeTouch(touchDevId, pointerId, + action == MotionEvent.ACTION_CANCEL ? MotionEvent.ACTION_UP : action, x, y, p); } - } + + // Non-primary up/down + if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) + break; + } while (++i < pointerCount); return true; - } + } // Sensor events public void enableSensor(int sensortype, boolean enabled) { @@ -395,39 +367,42 @@ public void onSensorChanged(SensorEvent event) { public boolean onCapturedPointerEvent(MotionEvent event) { int action = event.getActionMasked(); + int pointerCount = event.getPointerCount(); - float x, y; - 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: - case MotionEvent.ACTION_MOVE: - x = event.getX(0); - y = event.getY(0); - SDLActivity.onNativeMouse(0, action, x, y, true); - return true; - - case MotionEvent.ACTION_BUTTON_PRESS: - case MotionEvent.ACTION_BUTTON_RELEASE: - - // Change our action value to what SDL's code expects. - if (action == MotionEvent.ACTION_BUTTON_PRESS) { - action = MotionEvent.ACTION_DOWN; - } else { /* MotionEvent.ACTION_BUTTON_RELEASE */ - action = MotionEvent.ACTION_UP; - } + for (int i = 0; i < pointerCount; i++) { + float x, y; + switch (action) { + case MotionEvent.ACTION_SCROLL: + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, i); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, i); + SDLActivity.onNativeMouse(0, action, x, y, false); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + case MotionEvent.ACTION_MOVE: + x = event.getX(i); + y = event.getY(i); + SDLActivity.onNativeMouse(0, action, x, y, true); + return true; + + case MotionEvent.ACTION_BUTTON_PRESS: + case MotionEvent.ACTION_BUTTON_RELEASE: + + // Change our action value to what SDL's code expects. + if (action == MotionEvent.ACTION_BUTTON_PRESS) { + action = MotionEvent.ACTION_DOWN; + } else { /* MotionEvent.ACTION_BUTTON_RELEASE */ + action = MotionEvent.ACTION_UP; + } - x = event.getX(0); - y = event.getY(0); - int button = event.getButtonState(); + x = event.getX(i); + y = event.getY(i); + int button = event.getButtonState(); - SDLActivity.onNativeMouse(button, action, x, y, true); - return true; - } + SDLActivity.onNativeMouse(button, action, x, y, true); + return true; + } + } return false; } diff --git a/src/video/android/SDL_androidpen.c b/src/video/android/SDL_androidpen.c index 65730bd75dce3..a691b2e146ba3 100644 --- a/src/video/android/SDL_androidpen.c +++ b/src/video/android/SDL_androidpen.c @@ -26,11 +26,12 @@ #include "../../events/SDL_pen_c.h" #include "../../core/android/SDL_android.h" -#define ACTION_DOWN 0 -#define ACTION_UP 1 -#define ACTION_POINTER_DOWN 5 -#define ACTION_POINTER_UP 6 -#define ACTION_HOVER_EXIT 10 +#define ACTION_DOWN 0 +#define ACTION_UP 1 +#define ACTION_CANCEL 3 +#define ACTION_POINTER_DOWN 5 +#define ACTION_POINTER_UP 6 +#define ACTION_HOVER_EXIT 10 void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p) { @@ -56,11 +57,6 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, fl } } - if (action == ACTION_HOVER_EXIT) { - SDL_RemovePenDevice(0, pen); - return; - } - SDL_SendPenMotion(0, pen, window, x, y); SDL_SendPenAxis(0, pen, window, SDL_PEN_AXIS_PRESSURE, p); // TODO: add more axis @@ -77,7 +73,13 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, fl } // button contains DOWN/ERASER_TIP on DOWN/UP regardless of pressed state, use action to distinguish + // we don't compare tip flags above because MotionEvent.getButtonState doesn't return stylus tip/eraser state. switch (action) { + case ACTION_CANCEL: + case ACTION_HOVER_EXIT: + SDL_RemovePenDevice(0, pen); + break; + case ACTION_DOWN: case ACTION_POINTER_DOWN: SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, true);