Skip to content

Commit d9e4658

Browse files
committed
Add SDL Pinch events.
backend: x11/wayland/macosx/ios/Android
1 parent 2fb024a commit d9e4658

File tree

20 files changed

+604
-18
lines changed

20 files changed

+604
-18
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,9 @@ public static native void onNativeTouch(int touchDevId, int pointerFingerId,
10191019
public static native void onNativeDarkModeChanged(boolean enabled);
10201020
public static native boolean nativeAllowRecreateActivity();
10211021
public static native int nativeCheckSDLThreadCounter();
1022+
public static native void onNativePinchStart();
1023+
public static native void onNativePinchUpdate(float scale);
1024+
public static native void onNativePinchEnd();
10221025

10231026
/**
10241027
* This method is called by SDL using JNI.

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.view.View;
2121
import android.view.WindowManager;
2222

23+
import android.view.ScaleGestureDetector;
2324

2425
/**
2526
SDLSurface. This is what we draw on, so we need to know when it's created
@@ -28,7 +29,9 @@
2829
Because of this, that's where we set up the SDL thread
2930
*/
3031
public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
31-
View.OnKeyListener, View.OnTouchListener, SensorEventListener {
32+
View.OnKeyListener, View.OnTouchListener, SensorEventListener,
33+
ScaleGestureDetector.OnScaleGestureListener
34+
{
3235

3336
// Sensors
3437
protected SensorManager mSensorManager;
@@ -40,11 +43,16 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
4043
// Is SurfaceView ready for rendering
4144
public boolean mIsSurfaceReady;
4245

46+
// Pinch events
47+
private final ScaleGestureDetector scaleGestureDetector;
48+
4349
// Startup
4450
public SDLSurface(Context context) {
4551
super(context);
4652
getHolder().addCallback(this);
4753

54+
scaleGestureDetector = new ScaleGestureDetector(context, this);
55+
4856
setFocusable(true);
4957
setFocusableInTouchMode(true);
5058
requestFocus();
@@ -214,6 +222,13 @@ private float getNormalizedY(float y)
214222
// Touch events
215223
@Override
216224
public boolean onTouch(View v, MotionEvent event) {
225+
226+
if (scaleGestureDetector.onTouchEvent(event)) {
227+
if (scaleGestureDetector.isInProgress()) {
228+
return true; /* event was consumed as gesture */
229+
}
230+
}
231+
217232
/* Ref: http://developer.android.com/training/gestures/multi.html */
218233
int touchDevId = event.getDeviceId();
219234
final int pointerCount = event.getPointerCount();
@@ -410,4 +425,23 @@ public boolean onCapturedPointerEvent(MotionEvent event)
410425

411426
return false;
412427
}
428+
429+
@Override
430+
public boolean onScale(ScaleGestureDetector detector) {
431+
float scale = detector.getScaleFactor();
432+
SDLActivity.onNativePinchUpdate(scale);
433+
return true;
434+
}
435+
436+
@Override
437+
public boolean onScaleBegin(ScaleGestureDetector detector) {
438+
SDLActivity.onNativePinchStart();
439+
return true;
440+
}
441+
442+
@Override
443+
public void onScaleEnd(ScaleGestureDetector detector) {
444+
SDLActivity.onNativePinchEnd();
445+
}
446+
413447
}

cmake/sdlchecks.cmake

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,23 @@ macro(CheckX11)
408408
if(HAVE_XINPUT2_MULTITOUCH)
409409
set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1)
410410
endif()
411+
412+
# Check for gesture
413+
check_c_source_compiles("
414+
#include <X11/Xlib.h>
415+
#include <X11/Xproto.h>
416+
#include <X11/extensions/XInput2.h>
417+
int event_type = XI_GesturePinchBegin;
418+
XITouchClassInfo *t;
419+
Status XIAllowTouchEvents(Display *a,int b,unsigned int c,Window d,int f) {
420+
return (Status)0;
421+
}
422+
int main(int argc, char **argv) { return 0; }" HAVE_XINPUT2_GESTURE)
423+
if(HAVE_XINPUT2_GESTURE)
424+
set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE 1)
425+
endif()
426+
427+
411428
endif()
412429

413430
# check along with XInput2.h because we use Xfixes with XIBarrierReleasePointer

include/SDL3/SDL_events.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ typedef enum SDL_EventType
185185
SDL_EVENT_FINGER_UP,
186186
SDL_EVENT_FINGER_MOTION,
187187

188+
/* Pinch events */
189+
SDL_EVENT_PINCH_BEGIN = 0x710,
190+
SDL_EVENT_PINCH_UPDATE,
191+
SDL_EVENT_PINCH_END,
192+
188193
/* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */
189194

190195
/* Clipboard events */
@@ -663,6 +668,17 @@ typedef struct SDL_TouchFingerEvent
663668
SDL_WindowID windowID; /**< The window underneath the finger, if any */
664669
} SDL_TouchFingerEvent;
665670

671+
/**
672+
* Pinch event structure (event.pinch.*)
673+
*/
674+
typedef struct SDL_PinchFingerEvent
675+
{
676+
SDL_EventType type; /**< ::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END */
677+
Uint32 reserved;
678+
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
679+
float scale; /**< The scale factor provided with SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */
680+
SDL_WindowID windowID; /**< The window underneath the finger, if any */
681+
} SDL_PinchFingerEvent;
666682

667683
#define SDL_DROPEVENT_DATA_SIZE 64
668684

@@ -847,6 +863,7 @@ typedef union SDL_Event
847863
SDL_QuitEvent quit; /**< Quit request event data */
848864
SDL_UserEvent user; /**< Custom event data */
849865
SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
866+
SDL_PinchFingerEvent pinch; /**< Pinch event data */
850867
SDL_PenTipEvent ptip; /**< Pen tip touching or leaving drawing surface */
851868
SDL_PenMotionEvent pmotion; /**< Pen change in position, pressure, or angle */
852869
SDL_PenButtonEvent pbutton; /**< Pen button press */

include/build_config/SDL_build_config.h.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@
406406
#cmakedefine SDL_VIDEO_DRIVER_X11_XFIXES @SDL_VIDEO_DRIVER_X11_XFIXES@
407407
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
408408
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
409+
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE@
409410
#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
410411
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
411412
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@

src/core/android/SDL_android.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
108108
jint touch_device_id_in, jint pointer_finger_id_in,
109109
jint action, jfloat x, jfloat y, jfloat p);
110110

111+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)(
112+
JNIEnv *env, jclass jcls);
113+
114+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)(
115+
JNIEnv *env, jclass jcls,
116+
jfloat scale);
117+
118+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)(
119+
JNIEnv *env, jclass jcls);
120+
111121
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
112122
JNIEnv *env, jclass jcls,
113123
jint button, jint action, jfloat x, jfloat y, jboolean relative);
@@ -192,6 +202,9 @@ static JNINativeMethod SDLActivity_tab[] = {
192202
{ "onNativeSoftReturnKey", "()Z", SDL_JAVA_INTERFACE(onNativeSoftReturnKey) },
193203
{ "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) },
194204
{ "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) },
205+
{ "onNativePinchStart", "()V", SDL_JAVA_INTERFACE(onNativePinchStart) },
206+
{ "onNativePinchUpdate", "(F)V", SDL_JAVA_INTERFACE(onNativePinchUpdate) },
207+
{ "onNativePinchEnd", "()V", SDL_JAVA_INTERFACE(onNativePinchEnd) },
195208
{ "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
196209
{ "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) },
197210
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
@@ -1239,6 +1252,43 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
12391252
SDL_UnlockMutex(Android_ActivityMutex);
12401253
}
12411254

1255+
/* Pinch */
1256+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)(
1257+
JNIEnv *env, jclass jcls)
1258+
{
1259+
SDL_LockMutex(Android_ActivityMutex);
1260+
1261+
if (Android_Window) {
1262+
SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0);
1263+
}
1264+
1265+
SDL_UnlockMutex(Android_ActivityMutex);
1266+
}
1267+
1268+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)(
1269+
JNIEnv *env, jclass jcls, jfloat scale)
1270+
{
1271+
SDL_LockMutex(Android_ActivityMutex);
1272+
1273+
if (Android_Window) {
1274+
SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, Android_Window, scale);
1275+
}
1276+
1277+
SDL_UnlockMutex(Android_ActivityMutex);
1278+
}
1279+
1280+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)(
1281+
JNIEnv *env, jclass jcls)
1282+
{
1283+
SDL_LockMutex(Android_ActivityMutex);
1284+
1285+
if (Android_Window) {
1286+
SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0);
1287+
}
1288+
1289+
SDL_UnlockMutex(Android_ActivityMutex);
1290+
}
1291+
12421292
/* Mouse */
12431293
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
12441294
JNIEnv *env, jclass jcls,

src/events/SDL_events.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,11 @@ static void SDL_LogEvent(const SDL_Event *event)
211211
char name[64];
212212
char details[128];
213213

214-
/* sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded. */
214+
/* sensor/mouse/pen/finger/pinch motion are spammy, ignore these if they aren't demanded. */
215215
if ((SDL_EventLoggingVerbosity < 2) &&
216216
((event->type == SDL_EVENT_MOUSE_MOTION) ||
217217
(event->type == SDL_EVENT_FINGER_MOTION) ||
218+
(event->type == SDL_EVENT_PINCH_UPDATE) ||
218219
(event->type == SDL_EVENT_PEN_MOTION) ||
219220
(event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) ||
220221
(event->type == SDL_EVENT_GAMEPAD_SENSOR_UPDATE) ||
@@ -508,6 +509,20 @@ static void SDL_LogEvent(const SDL_Event *event)
508509
break;
509510
#undef PRINT_FINGER_EVENT
510511

512+
#define PRINT_PINCH_EVENT(event) \
513+
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u scale=%f)", \
514+
(uint)event->pinch.timestamp, event->pinch.scale)
515+
SDL_EVENT_CASE(SDL_EVENT_PINCH_BEGIN)
516+
PRINT_PINCH_EVENT(event);
517+
break;
518+
SDL_EVENT_CASE(SDL_EVENT_PINCH_UPDATE)
519+
PRINT_PINCH_EVENT(event);
520+
break;
521+
SDL_EVENT_CASE(SDL_EVENT_PINCH_END)
522+
PRINT_PINCH_EVENT(event);
523+
break;
524+
#undef PRINT_PINCH_EVENT
525+
511526
#define PRINT_PTIP_EVENT(event) \
512527
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u tip=%u state=%s x=%g y=%g)", \
513528
(uint)event->ptip.timestamp, (uint)event->ptip.windowID, \

src/events/SDL_touch.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,19 @@ void SDL_QuitTouch(void)
507507
SDL_free(SDL_touchDevices);
508508
SDL_touchDevices = NULL;
509509
}
510+
511+
int SDL_SendPinch(int event_type, Uint64 timestamp, SDL_Window *window, float scale)
512+
{
513+
/* Post the event, if desired */
514+
int posted = 0;
515+
if (SDL_EventEnabled(SDL_EVENT_PINCH_BEGIN)) {
516+
SDL_Event event;
517+
event.type = event_type;
518+
event.common.timestamp = timestamp;
519+
event.pinch.scale = scale;
520+
event.pinch.windowID = window ? SDL_GetWindowID(window) : 0;
521+
posted = (SDL_PushEvent(&event) > 0);
522+
}
523+
return posted;
524+
}
525+

src/events/SDL_touch_c.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,7 @@ extern void SDL_DelTouch(SDL_TouchID id);
5757
/* Shutdown the touch subsystem */
5858
extern void SDL_QuitTouch(void);
5959

60+
/* Send Gesture events */
61+
extern int SDL_SendPinch(int event_type, Uint64 timestamp, SDL_Window *window, float scale);
62+
6063
#endif /* SDL_touch_c_h_ */

src/test/SDL_test_common.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,16 @@ static void SDLTest_PrintEvent(const SDL_Event *event)
18231823
event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
18241824
break;
18251825

1826+
case SDL_EVENT_PINCH_BEGIN:
1827+
SDL_Log("SDL EVENT: Pinch Begin");
1828+
break;
1829+
case SDL_EVENT_PINCH_UPDATE:
1830+
SDL_Log("SDL EVENT: Pinch Update, scale=%f", event->pinch.scale);
1831+
break;
1832+
case SDL_EVENT_PINCH_END:
1833+
SDL_Log("SDL EVENT: Pinch End");
1834+
break;
1835+
18261836
case SDL_EVENT_RENDER_DEVICE_RESET:
18271837
SDL_Log("SDL EVENT: render device reset");
18281838
break;
@@ -2056,7 +2066,8 @@ int SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event
20562066

20572067
if (state->verbose & VERBOSE_EVENT) {
20582068
if (((event->type != SDL_EVENT_MOUSE_MOTION) &&
2059-
(event->type != SDL_EVENT_FINGER_MOTION)) ||
2069+
(event->type != SDL_EVENT_FINGER_MOTION) &&
2070+
(event->type != SDL_EVENT_PINCH_UPDATE)) ||
20602071
(state->verbose & VERBOSE_MOTION)) {
20612072
SDLTest_PrintEvent(event);
20622073
}

0 commit comments

Comments
 (0)