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 278be4682544a..0f4bbb9b309cc 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 @@ -234,9 +234,11 @@ public enum NativeState { private static SDLFileDialogState mFileDialogState = null; protected static boolean mDispatchingKeyEvent = false; - protected static SDLGenericMotionListener_API14 getMotionListener() { + public static SDLGenericMotionListener_API14 getMotionListener() { if (mMotionListener == null) { - if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) { + if (Build.VERSION.SDK_INT >= 29 /* Android 10 (Q) */) { + mMotionListener = new SDLGenericMotionListener_API29(); + } else 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(); @@ -1072,7 +1074,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 onNativePen(int penId, int device_type, 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/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index 7395bd2e64324..6d36e7b1e7380 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 @@ -663,6 +663,10 @@ protected SDLHaptic getHaptic(int device_id) { } class SDLGenericMotionListener_API14 implements View.OnGenericMotionListener { + protected static final int SDL_PEN_DEVICE_TYPE_UNKNOWN = 0; + protected static final int SDL_PEN_DEVICE_TYPE_DIRECT = 1; + protected static final int SDL_PEN_DEVICE_TYPE_INDIRECT = 2; + // Generic Motion (mouse hover, joystick...) events go here @Override public boolean onGenericMotion(View v, MotionEvent event) { @@ -714,7 +718,7 @@ public boolean onGenericMotion(View v, MotionEvent event) { // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4, and apply SDL_PEN_INPUT_DOWN/SDL_PEN_INPUT_ERASER_TIP int buttons = (event.getButtonState() >> 4) | (1 << (toolType == MotionEvent.TOOL_TYPE_STYLUS ? 0 : 30)); - SDLActivity.onNativePen(event.getPointerId(i), buttons, action, x, y, p); + SDLActivity.onNativePen(event.getPointerId(i), getPenDeviceType(event.getDevice()), buttons, action, x, y, p); consumed = true; break; } @@ -752,6 +756,9 @@ float getEventY(MotionEvent event, int pointerIndex) { return event.getY(pointerIndex); } + int getPenDeviceType(InputDevice penDevice) { + return SDL_PEN_DEVICE_TYPE_UNKNOWN; + } } class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 { @@ -847,3 +854,15 @@ float getEventY(MotionEvent event, int pointerIndex) { return event.getY(pointerIndex); } } + +class SDLGenericMotionListener_API29 extends SDLGenericMotionListener_API26 { + @Override + int getPenDeviceType(InputDevice penDevice) + { + if (penDevice == null) { + return SDL_PEN_DEVICE_TYPE_UNKNOWN; + } + + return penDevice.isExternal() ? SDL_PEN_DEVICE_TYPE_INDIRECT : SDL_PEN_DEVICE_TYPE_DIRECT; + } +} 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 42b4f362caa66..3adfe3b1c5364 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 @@ -275,7 +275,7 @@ public boolean onTouch(View v, MotionEvent event) { // 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); + SDLActivity.onNativePen(pointerId, SDLActivity.getMotionListener().getPenDeviceType(event.getDevice()), buttonState, action, x, y, p); } else { // MotionEvent.TOOL_TYPE_FINGER or MotionEvent.TOOL_TYPE_UNKNOWN pointerId = event.getPointerId(i); x = getNormalizedX(event.getX(i)); diff --git a/include/SDL3/SDL_pen.h b/include/SDL3/SDL_pen.h index 5182eeb0ce1dd..3c8f6d4182ab2 100644 --- a/include/SDL3/SDL_pen.h +++ b/include/SDL3/SDL_pen.h @@ -43,6 +43,7 @@ #include #include +#include /* Set up for C function definitions, even when using C++ */ #ifdef __cplusplus extern "C" { @@ -75,7 +76,6 @@ typedef Uint32 SDL_PenID; */ #define SDL_PEN_TOUCHID ((SDL_TouchID)-2) - /** * Pen input flags, as reported by various pen events' `pen_state` field. * @@ -118,10 +118,36 @@ typedef enum SDL_PenAxis SDL_PEN_AXIS_COUNT /**< Total known pen axis types in this version of SDL. This number may grow in future releases! */ } SDL_PenAxis; +/** + * An enum that describes the type of a pen device. + * + * \since This enum is available since SDL 3.4.0. + */ +typedef enum SDL_PenDeviceType +{ + SDL_PEN_DEVICE_TYPE_INVALID = -1, + SDL_PEN_DEVICE_TYPE_UNKNOWN, + SDL_PEN_DEVICE_TYPE_DIRECT, + SDL_PEN_DEVICE_TYPE_INDIRECT +} SDL_PenDeviceType; + +/** + * Get the device type of the given pen. + * + * \param instance_id the pen instance ID. + * \returns the device type of the given pen, or SDL_PEN_DEVICE_TYPE_INVALID on failure; call SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PenDeviceType SDLCALL SDL_GetPenDeviceType(SDL_PenID instance_id); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } #endif +#include #endif /* SDL_pen_h_ */ diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 6cdffef2458d4..a8d01062ed27d 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -121,7 +121,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)( 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); + jint pen_id_in, jint device_type, jint button, jint action, jfloat x, jfloat y, jfloat p); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)( JNIEnv *env, jclass jcls, @@ -214,7 +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) }, + { "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) }, { "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) }, { "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) }, { "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) }, @@ -1361,11 +1361,11 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)( // 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) + jint pen_id_in, jint device_type, 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); + Android_OnPen(Android_Window, pen_id_in, device_type, button, action, x, y, p); SDL_UnlockMutex(Android_ActivityMutex); } diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 91bd4300c732f..36d38b3c4d66d 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1254,6 +1254,7 @@ SDL3_0.0.0 { SDL_SetAudioIterationCallbacks; SDL_GetEventDescription; SDL_PutAudioStreamDataNoCopy; + SDL_GetPenDeviceType; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index fcc0bad7b25ff..3e6292c25d1d0 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1279,3 +1279,4 @@ #define SDL_SetAudioIterationCallbacks SDL_SetAudioIterationCallbacks_REAL #define SDL_GetEventDescription SDL_GetEventDescription_REAL #define SDL_PutAudioStreamDataNoCopy SDL_PutAudioStreamDataNoCopy_REAL +#define SDL_GetPenDeviceType SDL_GetPenDeviceType_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 60e0dfea5728f..4abdceb38ad14 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1287,3 +1287,4 @@ SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamPlanarData,(SDL_AudioStream *a,const void SDL_DYNAPI_PROC(bool,SDL_SetAudioIterationCallbacks,(SDL_AudioDeviceID a,SDL_AudioIterationCallback b,SDL_AudioIterationCallback c,void *d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_GetEventDescription,(const SDL_Event *a,char *b,int c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamDataNoCopy,(SDL_AudioStream *a,const void *b,int c,SDL_AudioStreamDataCompleteCallback d,void *e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(SDL_PenDeviceType,SDL_GetPenDeviceType,(SDL_PenID a),(a),return) diff --git a/src/events/SDL_pen.c b/src/events/SDL_pen.c index cd3730cabe8fa..f8cdc60830077 100644 --- a/src/events/SDL_pen.c +++ b/src/events/SDL_pen.c @@ -199,6 +199,15 @@ SDL_PenInputFlags SDL_GetPenStatus(SDL_PenID instance_id, float *axes, int num_a return result; } +SDL_PenDeviceType SDL_GetPenDeviceType(SDL_PenID instance_id) +{ + SDL_LockRWLockForReading(pen_device_rwlock); + const SDL_Pen *pen = FindPenByInstanceId(instance_id); + const SDL_PenDeviceType result = pen ? pen->info.device_type : SDL_PEN_DEVICE_TYPE_INVALID; + SDL_UnlockRWLock(pen_device_rwlock); + return result; +} + 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 1eff47f230716..83f412c1a8e6b 100644 --- a/src/events/SDL_pen_c.h +++ b/src/events/SDL_pen_c.h @@ -36,6 +36,8 @@ typedef Uint32 SDL_PenCapabilityFlags; #define SDL_PEN_CAPABILITY_TANGENTIAL_PRESSURE (1u << 6) /**< Provides barrel pressure on SDL_PEN_AXIS_TANGENTIAL_PRESSURE. */ #define SDL_PEN_CAPABILITY_ERASER (1u << 7) /**< Pen also has an eraser tip. */ +// Rename before making this public as it clashes with SDL_PenDeviceType. +// Prior art in Android calls this "tool type". typedef enum SDL_PenSubtype { SDL_PEN_TYPE_UNKNOWN, /**< Unknown pen device */ @@ -53,6 +55,7 @@ typedef struct SDL_PenInfo Uint32 wacom_id; /**< For Wacom devices: wacom tool type ID, otherwise 0 (useful e.g. with libwacom) */ int num_buttons; /**< Number of pen buttons (not counting the pen tip), or -1 if unknown. */ SDL_PenSubtype subtype; /**< type of pen device */ + SDL_PenDeviceType device_type; } SDL_PenInfo; // Backend calls this when a new pen device is hotplugged, plus once for each pen already connected at startup. diff --git a/src/video/android/SDL_androidpen.c b/src/video/android/SDL_androidpen.c index e287cabd8b266..727d8bd8626f3 100644 --- a/src/video/android/SDL_androidpen.c +++ b/src/video/android/SDL_androidpen.c @@ -33,7 +33,7 @@ #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) +void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_type, int button, int action, float x, float y, float p) { if (!window) { return; @@ -50,6 +50,7 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, fl peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ERASER; peninfo.num_buttons = 2; peninfo.subtype = SDL_PEN_TYPE_PEN; + peninfo.device_type = device_type; 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); diff --git a/src/video/android/SDL_androidpen.h b/src/video/android/SDL_androidpen.h index 99a5aee0dd0dd..0fd90485e2585 100644 --- a/src/video/android/SDL_androidpen.h +++ b/src/video/android/SDL_androidpen.h @@ -22,4 +22,4 @@ #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); +extern void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_type, int button, int action, float x, float y, float p);