Skip to content

Commit

Permalink
Add SDL Pinch events.
Browse files Browse the repository at this point in the history
backend: x11/wayland/macosx/ios/Android
  • Loading branch information
1bsyl committed Jun 12, 2024
1 parent 463984e commit f90c0c7
Show file tree
Hide file tree
Showing 20 changed files with 606 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,10 @@ public static native void onNativeTouch(int touchDevId, int pointerFingerId,
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();


/**
* This method is called by SDL using JNI.
Expand Down
36 changes: 35 additions & 1 deletion android-project/app/src/main/java/org/libsdl/app/SDLSurface.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.view.View;
import android.view.WindowManager;

import android.view.ScaleGestureDetector;

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

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

// Pinch events
private final ScaleGestureDetector scaleGestureDetector;

// Startup
public SDLSurface(Context context) {
super(context);
getHolder().addCallback(this);

scaleGestureDetector = new ScaleGestureDetector(context, this);

setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
Expand Down Expand Up @@ -214,6 +222,13 @@ private float getNormalizedY(float y)
// Touch events
@Override
public boolean onTouch(View v, MotionEvent event) {

if (scaleGestureDetector.onTouchEvent(event)) {
if (scaleGestureDetector.isInProgress()) {
return true; /* event was consumed as gesture */
}
}

/* Ref: http://developer.android.com/training/gestures/multi.html */
int touchDevId = event.getDeviceId();
final int pointerCount = event.getPointerCount();
Expand Down Expand Up @@ -410,4 +425,23 @@ public boolean onCapturedPointerEvent(MotionEvent event)

return false;
}

@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
SDLActivity.onNativePinchUpdate(scale);
return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
SDLActivity.onNativePinchStart();
return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector detector) {
SDLActivity.onNativePinchEnd();
}

}
17 changes: 17 additions & 0 deletions cmake/sdlchecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,23 @@ macro(CheckX11)
if(HAVE_XINPUT2_MULTITOUCH)
set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1)
endif()

# Check for gesture
check_c_source_compiles("
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/extensions/XInput2.h>
int event_type = XI_GesturePinchBegin;
XITouchClassInfo *t;
Status XIAllowTouchEvents(Display *a,int b,unsigned int c,Window d,int f) {
return (Status)0;
}
int main(int argc, char **argv) { return 0; }" HAVE_XINPUT2_GESTURE)
if(HAVE_XINPUT2_GESTURE)
set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE 1)
endif()


endif()

# check along with XInput2.h because we use Xfixes with XIBarrierReleasePointer
Expand Down
17 changes: 17 additions & 0 deletions include/SDL3/SDL_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ typedef enum SDL_EventType
SDL_EVENT_FINGER_UP,
SDL_EVENT_FINGER_MOTION,

/* Pinch events */
SDL_EVENT_PINCH_BEGIN = 0x710, /**< Pinch gesture started */
SDL_EVENT_PINCH_UPDATE, /**< Pinch gesture updated */
SDL_EVENT_PINCH_END, /**< Pinch gesture ended */

/* 0x800, 0x801, and 0x802 were the Gesture events from SDL2. Do not reuse these values! sdl2-compat needs them! */

/* Clipboard events */
Expand Down Expand Up @@ -667,6 +672,17 @@ typedef struct SDL_TouchFingerEvent
SDL_WindowID windowID; /**< The window underneath the finger, if any */
} SDL_TouchFingerEvent;

/**
* Pinch event structure (event.pinch.*)
*/
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() */
float scale; /**< The scale factor provided with SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in". */
SDL_WindowID windowID; /**< The window underneath the finger, if any */
} SDL_PinchFingerEvent;

/**
* Pressure-sensitive pen touched or stopped touching surface (event.ptip.*)
Expand Down Expand Up @@ -849,6 +865,7 @@ typedef union SDL_Event
SDL_QuitEvent quit; /**< Quit request event data */
SDL_UserEvent user; /**< Custom event data */
SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
SDL_PinchFingerEvent pinch; /**< Pinch event data */
SDL_PenTipEvent ptip; /**< Pen tip touching or leaving drawing surface */
SDL_PenMotionEvent pmotion; /**< Pen change in position, pressure, or angle */
SDL_PenButtonEvent pbutton; /**< Pen button press */
Expand Down
1 change: 1 addition & 0 deletions include/build_config/SDL_build_config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@
#cmakedefine SDL_VIDEO_DRIVER_X11_XFIXES @SDL_VIDEO_DRIVER_X11_XFIXES@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE@
#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
Expand Down
50 changes: 50 additions & 0 deletions src/core/android/SDL_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
jint touch_device_id_in, jint pointer_finger_id_in,
jint action, jfloat x, jfloat y, jfloat p);

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)(
JNIEnv *env, jclass jcls);

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)(
JNIEnv *env, jclass jcls,
jfloat scale);

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)(
JNIEnv *env, jclass jcls);

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
JNIEnv *env, jclass jcls,
jint button, jint action, jfloat x, jfloat y, jboolean relative);
Expand Down Expand Up @@ -196,6 +206,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) },
{ "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
{ "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) },
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
Expand Down Expand Up @@ -1279,6 +1292,43 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
SDL_UnlockMutex(Android_ActivityMutex);
}

/* Pinch */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchStart)(
JNIEnv *env, jclass jcls)
{
SDL_LockMutex(Android_ActivityMutex);

if (Android_Window) {
SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, Android_Window, 0);
}

SDL_UnlockMutex(Android_ActivityMutex);
}

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchUpdate)(
JNIEnv *env, jclass jcls, jfloat scale)
{
SDL_LockMutex(Android_ActivityMutex);

if (Android_Window) {
SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, Android_Window, scale);
}

SDL_UnlockMutex(Android_ActivityMutex);
}

JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePinchEnd)(
JNIEnv *env, jclass jcls)
{
SDL_LockMutex(Android_ActivityMutex);

if (Android_Window) {
SDL_SendPinch(SDL_EVENT_PINCH_END, 0, Android_Window, 0);
}

SDL_UnlockMutex(Android_ActivityMutex);
}

/* Mouse */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
JNIEnv *env, jclass jcls,
Expand Down
17 changes: 16 additions & 1 deletion src/events/SDL_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,11 @@ static void SDL_LogEvent(const SDL_Event *event)
char name[64];
char details[128];

/* sensor/mouse/pen/finger motion are spammy, ignore these if they aren't demanded. */
/* sensor/mouse/pen/finger/pinch motion are spammy, ignore these if they aren't demanded. */
if ((SDL_EventLoggingVerbosity < 2) &&
((event->type == SDL_EVENT_MOUSE_MOTION) ||
(event->type == SDL_EVENT_FINGER_MOTION) ||
(event->type == SDL_EVENT_PINCH_UPDATE) ||
(event->type == SDL_EVENT_PEN_MOTION) ||
(event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) ||
(event->type == SDL_EVENT_GAMEPAD_SENSOR_UPDATE) ||
Expand Down Expand Up @@ -523,6 +524,20 @@ static void SDL_LogEvent(const SDL_Event *event)
break;
#undef PRINT_FINGER_EVENT

#define PRINT_PINCH_EVENT(event) \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u scale=%f)", \
(uint)event->pinch.timestamp, event->pinch.scale)
SDL_EVENT_CASE(SDL_EVENT_PINCH_BEGIN)
PRINT_PINCH_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_PINCH_UPDATE)
PRINT_PINCH_EVENT(event);
break;
SDL_EVENT_CASE(SDL_EVENT_PINCH_END)
PRINT_PINCH_EVENT(event);
break;
#undef PRINT_PINCH_EVENT

#define PRINT_PTIP_EVENT(event) \
(void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u tip=%u state=%s x=%g y=%g)", \
(uint)event->ptip.timestamp, (uint)event->ptip.windowID, \
Expand Down
18 changes: 17 additions & 1 deletion src/events/SDL_touch.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ static int SDL_DelFinger(SDL_Touch *touch, SDL_FingerID fingerid)
// Move the deleted finger to just past the end of the active fingers array and shift the active fingers by one.
// This ensures that the descriptor for the now-deleted finger is located at `touch->fingers[touch->num_fingers]`
// and is ready for use in SDL_AddFinger.
SDL_Finger *deleted_finger = touch->fingers[index];
SDL_Finger *deleted_finger = touch->fingers[index];
SDL_memmove(&touch->fingers[index], &touch->fingers[index + 1], (touch->num_fingers - index) * sizeof(touch->fingers[index]));
touch->fingers[touch->num_fingers] = deleted_finger;
}
Expand Down Expand Up @@ -512,3 +512,19 @@ void SDL_QuitTouch(void)
SDL_free(SDL_touchDevices);
SDL_touchDevices = NULL;
}

int SDL_SendPinch(int event_type, Uint64 timestamp, SDL_Window *window, float scale)
{
/* Post the event, if desired */
int posted = 0;
if (SDL_EventEnabled(event_type)) {
SDL_Event event;
event.type = event_type;
event.common.timestamp = timestamp;
event.pinch.scale = scale;
event.pinch.windowID = window ? SDL_GetWindowID(window) : 0;
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}

3 changes: 3 additions & 0 deletions src/events/SDL_touch_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,7 @@ extern void SDL_DelTouch(SDL_TouchID id);
/* Shutdown the touch subsystem */
extern void SDL_QuitTouch(void);

/* Send Gesture events */
extern int SDL_SendPinch(int event_type, Uint64 timestamp, SDL_Window *window, float scale);

#endif /* SDL_touch_c_h_ */
13 changes: 12 additions & 1 deletion src/test/SDL_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1836,6 +1836,16 @@ static void SDLTest_PrintEvent(const SDL_Event *event)
event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure);
break;

case SDL_EVENT_PINCH_BEGIN:
SDL_Log("SDL EVENT: Pinch Begin");
break;
case SDL_EVENT_PINCH_UPDATE:
SDL_Log("SDL EVENT: Pinch Update, scale=%f", event->pinch.scale);
break;
case SDL_EVENT_PINCH_END:
SDL_Log("SDL EVENT: Pinch End");
break;

case SDL_EVENT_RENDER_DEVICE_RESET:
SDL_Log("SDL EVENT: render device reset");
break;
Expand Down Expand Up @@ -2069,7 +2079,8 @@ int SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event

if (state->verbose & VERBOSE_EVENT) {
if (((event->type != SDL_EVENT_MOUSE_MOTION) &&
(event->type != SDL_EVENT_FINGER_MOTION)) ||
(event->type != SDL_EVENT_FINGER_MOTION) &&
(event->type != SDL_EVENT_PINCH_UPDATE)) ||
(state->verbose & VERBOSE_MOTION)) {
SDLTest_PrintEvent(event);
}
Expand Down
1 change: 1 addition & 0 deletions src/video/cocoa/SDL_cocoawindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ typedef enum
- (void)touchesMovedWithEvent:(NSEvent *)theEvent;
- (void)touchesEndedWithEvent:(NSEvent *)theEvent;
- (void)touchesCancelledWithEvent:(NSEvent *)theEvent;
- (void)magnifyWithEvent:(NSEvent *) theEvent;

/* Touch event handling */
- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent;
Expand Down
21 changes: 21 additions & 0 deletions src/video/cocoa/SDL_cocoawindow.m
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,27 @@ - (void)touchesCancelledWithEvent:(NSEvent *)theEvent
[self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
}

- (void)magnifyWithEvent:(NSEvent *)theEvent
{
switch ([theEvent phase]) {
case NSEventPhaseBegan:
SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0);
break;
case NSEventPhaseChanged:
{
CGFloat magnification = [theEvent magnification];
SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, magnification);
}
break;
case NSEventPhaseEnded:
case NSEventPhaseCancelled:
SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0);
break;
default:
break;
}
}

- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent
{
NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
Expand Down
3 changes: 3 additions & 0 deletions src/video/uikit/SDL_uikitview.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
#if !defined(SDL_PLATFORM_TVOS)
- (IBAction)sdlPinchGesture:(UIPinchGestureRecognizer *)sender;
#endif

@end
Loading

0 comments on commit f90c0c7

Please sign in to comment.