Просмотр исходного кода

Add more information for pinch gestures on mobile (#15092)

Brent Page 19 часов назад
Родитель
Сommit
65091012b4

+ 3 - 3
android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -1142,9 +1142,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 onNativePinchUpdate(float scale);
-    public static native void onNativePinchEnd();
+    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(float span_x, float span_y, float focus_x, float focus_y);
 
     /**
      * This method is called by SDL using JNI.

+ 15 - 3
android-project/app/src/main/java/org/libsdl/app/SDLSurface.java

@@ -440,19 +440,31 @@ 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;
     }
 
     @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);
     }
 
 }

+ 6 - 0
include/SDL3/SDL_events.h

@@ -837,6 +837,8 @@ typedef struct SDL_TouchFingerEvent
 
 /**
  * Pinch event structure (event.pinch.*)
+ *
+ * span_(x/y) and focus_(x/y) are only available for pinch gestures on mobile devices
  */
 typedef struct SDL_PinchFingerEvent
 {
@@ -845,6 +847,10 @@ typedef struct SDL_PinchFingerEvent
     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". */
     SDL_WindowID windowID; /**< The window underneath the finger, if any */
+    float span_x;        /**< On mobile devices, the average X distance between each of the pointers forming the pinch in window coordinates.  Otherwise, -1. */
+    float span_y;        /**< On mobile devices, the average Y distance between each of the pointers forming the pinch in window coordinates.  Otherwise, -1. */
+    float focus_x;        /**< On mobile devices, the X coordinate of the current gesture's focal point in window coordinates.  Otherwise, -1. */
+    float focus_y;        /**< On mobile devices, the Y coordinate of the current gesture's focal point in window coordinates.  Otherwise, -1. */
 } SDL_PinchFingerEvent;
 
 /**

+ 14 - 12
src/core/android/SDL_android.c

@@ -123,14 +123,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 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,
@@ -228,9 +230,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) },
-    { "onNativePinchUpdate", "(F)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) },
-    { "onNativePinchEnd", "()V", SDL_JAVA_INTERFACE(onNativePinchEnd) },
+    { "onNativePinchStart", "(FFFF)V", SDL_JAVA_INTERFACE(onNativePinchStart) },
+    { "onNativePinchUpdate", "(FFFFF)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) },
+    { "onNativePinchEnd", "(FFFF)V", SDL_JAVA_INTERFACE(onNativePinchEnd) },
     { "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
     { "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) },
     { "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
@@ -1430,36 +1432,36 @@ 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);
+        SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0, span_x, span_y, focus_x, focus_y);
     }
 
     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);
 }
 
 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);
+        SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0, span_x, span_y, focus_x, focus_y);
     }
 
     SDL_UnlockMutex(Android_ActivityMutex);

+ 5 - 1
src/events/SDL_touch.c

@@ -614,7 +614,7 @@ void SDL_QuitTouch(void)
     SDL_UnlockTouch();
 }
 
-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;
@@ -623,6 +623,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 >= 0.0f ? (span_x * (float)window->w) : -1.0f;
+        event.pinch.span_y = span_y >= 0.0f ? (span_y * (float)window->h) : -1.0f;
+        event.pinch.focus_x = focus_x >= 0.0f ? (focus_x * (float)window->w) : -1.0f;
+        event.pinch.focus_y = focus_y >= 0.0f ? (focus_y * (float)window->h) : -1.0f;
         event.pinch.windowID = window ? SDL_GetWindowID(window) : 0;
         posted = (SDL_PushEvent(&event) > 0);
     }

+ 1 - 1
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_

+ 3 - 3
src/video/cocoa/SDL_cocoawindow.m

@@ -2042,17 +2042,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, -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);
+            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);
+        SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0, -1, -1, -1, -1);
         break;
     default:
         break;

+ 14 - 3
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);
+            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);
+                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);
+            SDL_SendPinch(SDL_EVENT_PINCH_END, 0, sdlwindow, 0, span_x, span_y, focus_x, focus_y);
             break;
 
         default:

+ 4 - 4
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, -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);
+        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);
+        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;
     }
@@ -2421,7 +2421,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, -1.0f, -1.0f, -1.0f, -1.0f);
     }
 
     // Make sure focus is removed from a surface before the pointer is destroyed.

+ 3 - 3
src/video/x11/SDL_x11xinput2.c

@@ -760,11 +760,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, -1.0f, -1.0f, -1.0f, -1.0f);
         } 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, -1.0f, -1.0f, -1.0f, -1.0f);
         } else {
-            SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0);
+            SDL_SendPinch(SDL_EVENT_PINCH_END, 0, window, 0, -1.0f, -1.0f, -1.0f, -1.0f);
         }
     } break;