From e669fd6dfdeb0d2f3a12a6f12b4aa978511c01cd Mon Sep 17 00:00:00 2001 From: brentfpage Date: Sun, 22 Feb 2026 14:37:52 -0800 Subject: [PATCH 1/4] more information for pinch gestures on mobile --- .../src/main/java/org/libsdl/app/SDLActivity.java | 2 +- .../app/src/main/java/org/libsdl/app/SDLSurface.java | 6 +++++- include/SDL3/SDL_events.h | 4 ++++ src/core/android/SDL_android.c | 12 ++++++------ src/events/SDL_touch.c | 6 +++++- src/events/SDL_touch_c.h | 2 +- src/video/cocoa/SDL_cocoawindow.m | 6 +++--- src/video/uikit/SDL_uikitview.m | 6 +++--- src/video/wayland/SDL_waylandevents.c | 8 ++++---- src/video/x11/SDL_x11xinput2.c | 6 +++--- 10 files changed, 35 insertions(+), 23 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 dcc61d8729..ca1e1a304d 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 @@ -1087,7 +1087,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh public static native int nativeCheckSDLThreadCounter(); public static native void onNativeFileDialog(int requestCode, String[] filelist, int filter); public static native void onNativePinchStart(); - public static native void onNativePinchUpdate(float scale); + public static native void onNativePinchUpdate(float scale, float span_x, float span_y, float focus_x, float focus_y); public static native void onNativePinchEnd(); /** 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 1579b73345..4ff154aa30 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 @@ -431,7 +431,11 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, @Override public boolean onScale(ScaleGestureDetector detector) { float scale = detector.getScaleFactor(); - SDLActivity.onNativePinchUpdate(scale); + float span_x = getNormalizedX(detector.getCurrentSpanX()); + float span_y = getNormalizedY(detector.getCurrentSpanY()); + float focus_x = getNormalizedX(detector.getFocusX()); + float focus_y = getNormalizedY(detector.getFocusY()); + SDLActivity.onNativePinchUpdate(scale, span_x, span_y, focus_x, focus_y); return true; } diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 398c677095..62b7835440 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -802,6 +802,10 @@ typedef struct SDL_PinchFingerEvent Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ float scale; /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ + float span_x; /**< The average X distance between each of the pointers forming the pinch in screen pixel coordinates. */ + float span_y; /**< The average Y distance between each of the pointers forming the pinch in screen pixel coordinates. */ + float focus_x; /**< The X coordinate of the current gesture's focal point in screen pixel coordinates. */ + float focus_y; /**< The Y coordinate of the current gesture's focal point in screen pixel coordinates. */ SDL_WindowID windowID; /**< The window underneath the finger, if any */ } SDL_PinchFingerEvent; diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index fa559484f9..681178d83b 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -126,7 +126,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)( JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)( JNIEnv *env, jclass jcls, - jfloat scale); + jfloat scale, jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)( JNIEnv *env, jclass jcls); @@ -232,7 +232,7 @@ static JNINativeMethod SDLActivity_tab[] = { { "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) }, { "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) }, { "onNativePinchStart", "()V", SDL_JAVA_INTERFACE(onNativePinchStart) }, - { "onNativePinchUpdate", "(F)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) }, + { "onNativePinchUpdate", "(FFFFF)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) }, { "onNativePinchEnd", "()V", SDL_JAVA_INTERFACE(onNativePinchEnd) }, { "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) }, { "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) }, @@ -1400,19 +1400,19 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)( SDL_LockMutex(Android_ActivityMutex); if (Android_Window) { - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0, 0, 0, 0, 0); } SDL_UnlockMutex(Android_ActivityMutex); } JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)( - JNIEnv *env, jclass jcls, jfloat scale) + JNIEnv *env, jclass jcls, jfloat scale, jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y) { SDL_LockMutex(Android_ActivityMutex); if (Android_Window) { - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, Android_Window, scale); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, Android_Window, scale, span_x, span_y, focus_x, focus_y); } SDL_UnlockMutex(Android_ActivityMutex); @@ -1424,7 +1424,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)( SDL_LockMutex(Android_ActivityMutex); if (Android_Window) { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0, 0, 0, 0, 0); } SDL_UnlockMutex(Android_ActivityMutex); diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c index b8ebb78aee..a14ad2d366 100644 --- a/src/events/SDL_touch.c +++ b/src/events/SDL_touch.c @@ -619,7 +619,7 @@ void SDL_QuitTouch(void) SDL_touch_lock = NULL; } -int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale) +int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale, float span_x, float span_y, float focus_x, float focus_y) { /* Post the event, if desired */ int posted = 0; @@ -628,6 +628,10 @@ int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, floa event.type = type; event.common.timestamp = timestamp; event.pinch.scale = scale; + event.pinch.span_x = (span_x * (float)window->w); + event.pinch.span_y = (span_y * (float)window->h); + event.pinch.focus_x = (focus_x * (float)window->w); + event.pinch.focus_y = (focus_y * (float)window->h); event.pinch.windowID = window ? SDL_GetWindowID(window) : 0; posted = (SDL_PushEvent(&event) > 0); } diff --git a/src/events/SDL_touch_c.h b/src/events/SDL_touch_c.h index 2744305979..2309a71882 100644 --- a/src/events/SDL_touch_c.h +++ b/src/events/SDL_touch_c.h @@ -50,6 +50,6 @@ extern void SDL_DelTouch(SDL_TouchID id); extern void SDL_QuitTouch(void); // Send Gesture events -extern int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale); +extern int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, float scale, float span_x, float span_y, float focus_x, float focus_y); #endif // SDL_touch_c_h_ diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 9225c225be..3719f75baa 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -2038,17 +2038,17 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL { switch ([theEvent phase]) { case NSEventPhaseBegan: - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, 0, 0, 0, 0); break; case NSEventPhaseChanged: { CGFloat scale = 1.0f + [theEvent magnification]; - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, scale); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, scale, 0, 0, 0, 0); } break; case NSEventPhaseEnded: case NSEventPhaseCancelled: - SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, 0, 0, 0, 0); break; default: break; diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m index d05a14a1c3..995288e073 100644 --- a/src/video/uikit/SDL_uikitview.m +++ b/src/video/uikit/SDL_uikitview.m @@ -489,12 +489,12 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; case UIGestureRecognizerStateBegan: pinch_scale = 1.0f; - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, sdlwindow, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, sdlwindow, 0, 0, 0, 0, 0); break; case UIGestureRecognizerStateChanged: if (pinch_scale > 0.0f) { - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, sdlwindow, scale / pinch_scale); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, sdlwindow, scale / pinch_scale, 0, 0, 0, 0); } pinch_scale = scale; break; @@ -502,7 +502,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; case UIGestureRecognizerStateFailed: case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, sdlwindow, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, sdlwindow, 0, 0, 0, 0, 0); break; default: diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index b8fb8e0a42..280e0395ed 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -322,7 +322,7 @@ static void handle_pinch_begin(void *data, struct zwp_pointer_gesture_pinch_v1 * seat->pointer.gesture_focus = wind; const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, timestamp, wind->sdlwindow, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, timestamp, wind->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } } @@ -334,7 +334,7 @@ static void handle_pinch_update(void *data, struct zwp_pointer_gesture_pinch_v1 if (seat->pointer.gesture_focus) { const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); const float s = (float)wl_fixed_to_double(scale); - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, timestamp, seat->pointer.gesture_focus->sdlwindow, s); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, timestamp, seat->pointer.gesture_focus->sdlwindow, s, 0.0f, 0.0f, 0.0f, 0.0f); } } @@ -344,7 +344,7 @@ static void handle_pinch_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zw if (seat->pointer.gesture_focus) { const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); - SDL_SendPinch(SDL_EVENT_PINCH_END, timestamp, seat->pointer.gesture_focus->sdlwindow, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_END, timestamp, seat->pointer.gesture_focus->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); seat->pointer.gesture_focus = NULL; } @@ -2390,7 +2390,7 @@ static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat) // End any active gestures. if (seat->pointer.gesture_focus) { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, seat->pointer.gesture_focus->sdlwindow, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, seat->pointer.gesture_focus->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } // Make sure focus is removed from a surface before the pointer is destroyed. diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index c8b37cec98..9b4ba9f823 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -735,11 +735,11 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); if (cookie->evtype == XI_GesturePinchBegin) { - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, window, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, window, 0, 0, 0, 0, 0); } else if (cookie->evtype == XI_GesturePinchUpdate) { - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, window, (float)xev->scale); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, window, (float)xev->scale, 0, 0, 0, 0); } else { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0, 0, 0, 0, 0); } } break; From abe09d08bef0bb659081f839904a994877d65514 Mon Sep 17 00:00:00 2001 From: brentfpage Date: Fri, 13 Mar 2026 00:00:18 -0700 Subject: [PATCH 2/4] ensure windowID retains the same offset in struct SDL_PinchFingerEvent --- include/SDL3/SDL_events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 62b7835440..c6bc98f6cd 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -801,12 +801,12 @@ typedef struct SDL_PinchFingerEvent SDL_EventType type; /**< ::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END */ Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ + SDL_WindowID windowID; /**< The window underneath the finger, if any */ float scale; /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ float span_x; /**< The average X distance between each of the pointers forming the pinch in screen pixel coordinates. */ float span_y; /**< The average Y distance between each of the pointers forming the pinch in screen pixel coordinates. */ float focus_x; /**< The X coordinate of the current gesture's focal point in screen pixel coordinates. */ float focus_y; /**< The Y coordinate of the current gesture's focal point in screen pixel coordinates. */ - SDL_WindowID windowID; /**< The window underneath the finger, if any */ } SDL_PinchFingerEvent; /** From 5d11a7c0f8999b69395db348c16aa0a66d3a2358 Mon Sep 17 00:00:00 2001 From: brentfpage Date: Mon, 4 May 2026 12:40:48 -0700 Subject: [PATCH 3/4] again: ensure windowID retains the same offset in struct SDL_PinchFingerEvent --- include/SDL3/SDL_events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index c6bc98f6cd..def949309b 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -801,8 +801,8 @@ typedef struct SDL_PinchFingerEvent SDL_EventType type; /**< ::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END */ Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ - SDL_WindowID windowID; /**< The window underneath the finger, if any */ float scale; /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ + SDL_WindowID windowID; /**< The window underneath the finger, if any */ float span_x; /**< The average X distance between each of the pointers forming the pinch in screen pixel coordinates. */ float span_y; /**< The average Y distance between each of the pointers forming the pinch in screen pixel coordinates. */ float focus_x; /**< The X coordinate of the current gesture's focal point in screen pixel coordinates. */ From 0c9f1ab8f580e95276d24d4c5cf525ab3cea4811 Mon Sep 17 00:00:00 2001 From: brentfpage Date: Sat, 23 May 2026 14:56:37 -0700 Subject: [PATCH 4/4] capture 'focus' and 'span' info from uikit pinch gestures; for all frameworks, set 'focus' and 'span' to -1 if they're unavailable --- .../main/java/org/libsdl/app/SDLActivity.java | 4 ++-- .../main/java/org/libsdl/app/SDLSurface.java | 12 ++++++++++-- include/SDL3/SDL_events.h | 8 ++++---- src/core/android/SDL_android.c | 18 ++++++++++-------- src/events/SDL_touch.c | 8 ++++---- src/video/cocoa/SDL_cocoawindow.m | 6 +++--- src/video/uikit/SDL_uikitview.m | 17 ++++++++++++++--- src/video/wayland/SDL_waylandevents.c | 8 ++++---- src/video/x11/SDL_x11xinput2.c | 6 +++--- 9 files changed, 54 insertions(+), 33 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 ca1e1a304d..5fc4c386e3 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 @@ -1086,9 +1086,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh public static native boolean nativeAllowRecreateActivity(); public static native int nativeCheckSDLThreadCounter(); public static native void onNativeFileDialog(int requestCode, String[] filelist, int filter); - public static native void onNativePinchStart(); + public static native void onNativePinchStart(float span_x, float span_y, float focus_x, float focus_y); public static native void onNativePinchUpdate(float scale, float span_x, float span_y, float focus_x, float focus_y); - public static native void onNativePinchEnd(); + public static native void onNativePinchEnd(float span_x, float span_y, float focus_x, float focus_y); /** * This method is called by SDL using JNI. 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 4ff154aa30..1314cee329 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 @@ -441,13 +441,21 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, @Override public boolean onScaleBegin(ScaleGestureDetector detector) { - SDLActivity.onNativePinchStart(); + float span_x = getNormalizedX(detector.getCurrentSpanX()); + float span_y = getNormalizedY(detector.getCurrentSpanY()); + float focus_x = getNormalizedX(detector.getFocusX()); + float focus_y = getNormalizedY(detector.getFocusY()); + SDLActivity.onNativePinchStart(span_x, span_y, focus_x, focus_y); return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { - SDLActivity.onNativePinchEnd(); + float span_x = getNormalizedX(detector.getCurrentSpanX()); + float span_y = getNormalizedY(detector.getCurrentSpanY()); + float focus_x = getNormalizedX(detector.getFocusX()); + float focus_y = getNormalizedY(detector.getFocusY()); + SDLActivity.onNativePinchEnd(span_x, span_y, focus_x, focus_y); } } diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index def949309b..54ea84055c 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -802,11 +802,11 @@ typedef struct SDL_PinchFingerEvent Uint32 reserved; Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ float scale; /**< The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */ + float span_x; /**< The average X distance between each of the pointers forming the pinch in screen pixel coordinates. Or, -1 if this information is unavailable. */ + float span_y; /**< The average Y distance between each of the pointers forming the pinch in screen pixel coordinates. Or, -1 if this information is unavailable. */ + float focus_x; /**< The X coordinate of the current gesture's focal point in screen pixel coordinates. Or, -1 if this information is unavailable. */ + float focus_y; /**< The Y coordinate of the current gesture's focal point in screen pixel coordinates. Or, -1 if this information is unavailable. */ SDL_WindowID windowID; /**< The window underneath the finger, if any */ - float span_x; /**< The average X distance between each of the pointers forming the pinch in screen pixel coordinates. */ - float span_y; /**< The average Y distance between each of the pointers forming the pinch in screen pixel coordinates. */ - float focus_x; /**< The X coordinate of the current gesture's focal point in screen pixel coordinates. */ - float focus_y; /**< The Y coordinate of the current gesture's focal point in screen pixel coordinates. */ } SDL_PinchFingerEvent; /** diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 681178d83b..9307f4a2fd 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -122,14 +122,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)( jint action, jfloat x, jfloat y, jfloat p); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)( - JNIEnv *env, jclass jcls); + JNIEnv *env, jclass jcls, + jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)( JNIEnv *env, jclass jcls, jfloat scale, jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)( - JNIEnv *env, jclass jcls); + JNIEnv *env, jclass jcls, + jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y); JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)( JNIEnv *env, jclass jcls, @@ -231,9 +233,9 @@ static JNINativeMethod SDLActivity_tab[] = { { "onNativeSoftReturnKey", "()Z", SDL_JAVA_INTERFACE(onNativeSoftReturnKey) }, { "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) }, { "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) }, - { "onNativePinchStart", "()V", SDL_JAVA_INTERFACE(onNativePinchStart) }, + { "onNativePinchStart", "(FFFF)V", SDL_JAVA_INTERFACE(onNativePinchStart) }, { "onNativePinchUpdate", "(FFFFF)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) }, - { "onNativePinchEnd", "()V", SDL_JAVA_INTERFACE(onNativePinchEnd) }, + { "onNativePinchEnd", "(FFFF)V", SDL_JAVA_INTERFACE(onNativePinchEnd) }, { "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) }, { "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) }, { "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) }, @@ -1395,12 +1397,12 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)( // Pinch JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)( - JNIEnv *env, jclass jcls) + JNIEnv *env, jclass jcls, jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y) { SDL_LockMutex(Android_ActivityMutex); if (Android_Window) { - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0, span_x, span_y, focus_x, focus_y); } SDL_UnlockMutex(Android_ActivityMutex); @@ -1419,12 +1421,12 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)( } JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)( - JNIEnv *env, jclass jcls) + JNIEnv *env, jclass jcls, jfloat span_x, jfloat span_y, jfloat focus_x, jfloat focus_y) { SDL_LockMutex(Android_ActivityMutex); if (Android_Window) { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0, span_x, span_y, focus_x, focus_y); } SDL_UnlockMutex(Android_ActivityMutex); diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c index a14ad2d366..60d6a6489e 100644 --- a/src/events/SDL_touch.c +++ b/src/events/SDL_touch.c @@ -628,10 +628,10 @@ int SDL_SendPinch(SDL_EventType type, Uint64 timestamp, SDL_Window *window, floa event.type = type; event.common.timestamp = timestamp; event.pinch.scale = scale; - event.pinch.span_x = (span_x * (float)window->w); - event.pinch.span_y = (span_y * (float)window->h); - event.pinch.focus_x = (focus_x * (float)window->w); - event.pinch.focus_y = (focus_y * (float)window->h); + event.pinch.span_x = span_x > 0 ? (span_x * (float)window->w) : -1.f; + event.pinch.span_y = span_y > 0 ? (span_y * (float)window->h) : -1.f; + event.pinch.focus_x = focus_x > 0 ? (focus_x * (float)window->w) : -1.f; + event.pinch.focus_y = focus_y > 0 ? (focus_y * (float)window->h) : -1.f; event.pinch.windowID = window ? SDL_GetWindowID(window) : 0; posted = (SDL_PushEvent(&event) > 0); } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 3719f75baa..b9f488564f 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -2038,17 +2038,17 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL { switch ([theEvent phase]) { case NSEventPhaseBegan: - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, -1, -1, -1, -1); break; case NSEventPhaseChanged: { CGFloat scale = 1.0f + [theEvent magnification]; - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, scale, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, scale, -1, -1, -1, -1); } break; case NSEventPhaseEnded: case NSEventPhaseCancelled: - SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, -1, -1, -1, -1); break; default: break; diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m index 995288e073..19395c98fd 100644 --- a/src/video/uikit/SDL_uikitview.m +++ b/src/video/uikit/SDL_uikitview.m @@ -484,17 +484,28 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; { CGFloat scale = sender.scale; UIGestureRecognizerState state = sender.state; + CGPoint point1 = [sender locationOfTouch:0 inView:self]; + CGPoint point2 = [sender locationOfTouch:1 inView:self]; + CGFloat focus_x = (point1.x + point2.x)/2; + CGFloat focus_y = (point1.y + point2.y)/2; + CGFloat span_x = SDL_fabs(point1.x - point2.x); + CGFloat span_y = SDL_fabs(point1.y - point2.y); + CGRect bounds = self.bounds; + focus_x /= bounds.size.width; + focus_y /= bounds.size.height; + span_x /= bounds.size.width; + span_y /= bounds.size.height; switch (state) { case UIGestureRecognizerStateBegan: pinch_scale = 1.0f; - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, sdlwindow, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, sdlwindow, 0, span_x, span_y, focus_x, focus_y); break; case UIGestureRecognizerStateChanged: if (pinch_scale > 0.0f) { - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, sdlwindow, scale / pinch_scale, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, sdlwindow, scale / pinch_scale, span_x, span_y, focus_x, focus_y); } pinch_scale = scale; break; @@ -502,7 +513,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick; case UIGestureRecognizerStateFailed: case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, sdlwindow, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, sdlwindow, 0, span_x, span_y, focus_x, focus_y); break; default: diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 280e0395ed..3e46bbc71a 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -322,7 +322,7 @@ static void handle_pinch_begin(void *data, struct zwp_pointer_gesture_pinch_v1 * seat->pointer.gesture_focus = wind; const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, timestamp, wind->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, timestamp, wind->sdlwindow, 0.0f, -1.0f, -1.0f, -1.0f, -1.0f); } } @@ -334,7 +334,7 @@ static void handle_pinch_update(void *data, struct zwp_pointer_gesture_pinch_v1 if (seat->pointer.gesture_focus) { const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); const float s = (float)wl_fixed_to_double(scale); - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, timestamp, seat->pointer.gesture_focus->sdlwindow, s, 0.0f, 0.0f, 0.0f, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, timestamp, seat->pointer.gesture_focus->sdlwindow, s, -1.0f, -1.0f, -1.0f, -1.0f); } } @@ -344,7 +344,7 @@ static void handle_pinch_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zw if (seat->pointer.gesture_focus) { const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); - SDL_SendPinch(SDL_EVENT_PINCH_END, timestamp, seat->pointer.gesture_focus->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_END, timestamp, seat->pointer.gesture_focus->sdlwindow, 0.0f, -1.0f, -1.0f, -1.0f, -1.0f); seat->pointer.gesture_focus = NULL; } @@ -2390,7 +2390,7 @@ static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat) // End any active gestures. if (seat->pointer.gesture_focus) { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, seat->pointer.gesture_focus->sdlwindow, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, seat->pointer.gesture_focus->sdlwindow, 0.0f, -1.0f, -1.0f, -1.0f, -1.0f); } // Make sure focus is removed from a surface before the pointer is destroyed. diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index 9b4ba9f823..3bb7c1d8c4 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -735,11 +735,11 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); if (cookie->evtype == XI_GesturePinchBegin) { - SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, window, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, window, 0, -1, -1, -1, -1); } else if (cookie->evtype == XI_GesturePinchUpdate) { - SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, window, (float)xev->scale, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, window, (float)xev->scale, -1, -1, -1, -1); } else { - SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0, 0, 0, 0, 0); + SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0, -1, -1, -1, -1); } } break;