Skip to content

Commit

Permalink
Detect trackpad pinch and expose SDL_PINCH custom event
Browse files Browse the repository at this point in the history
Represented PRs: libsdl-org#4, libsdl-org#5
  • Loading branch information
Suriya Kandaswamy authored and schkillten committed Jan 3, 2022
1 parent cd67a86 commit 614334a
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -11,6 +11,8 @@ This repository is Fractal's fork of SDL, with a few modifications. We forked SD

- Allow `Command+W` to passthrough to the application on macOS, instead of being captured by the "Close Window" shortcut

- Enable capturing macOS pinch gestures using Cocoa, to enable pinch-to-zoom on macOS trackpad devices

- Created a GitHub Actions workflow, `build-and-publish-sdl.yml` to build, test and publish on Windows, macOS and Linux Ubuntu

## Development
Expand Down
15 changes: 15 additions & 0 deletions include/SDL_events.h
Expand Up @@ -139,6 +139,7 @@ typedef enum
SDL_DOLLARGESTURE = 0x800,
SDL_DOLLARRECORD,
SDL_MULTIGESTURE,
SDL_PINCH,

/* Clipboard events */
SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
Expand Down Expand Up @@ -503,6 +504,19 @@ typedef struct SDL_MultiGestureEvent
} SDL_MultiGestureEvent;


/**
* \brief Finger Pinch Event (event.pinch.*)
*/
typedef struct SDL_PinchEvent
{
Uint32 type; /**< ::SDL_PINCH */
Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */
float magnification; /***< The magnification factor */
float scroll_amount; /***< Equivalent vertical scroll factor */
Uint32 windowID; /**< The window underneath the pinch, if any */
} SDL_PinchEvent;


/**
* \brief Dollar Gesture Event (event.dgesture.*)
*/
Expand Down Expand Up @@ -626,6 +640,7 @@ typedef union SDL_Event
SDL_MultiGestureEvent mgesture; /**< Gesture event data */
SDL_DollarGestureEvent dgesture; /**< Gesture event data */
SDL_DropEvent drop; /**< Drag and drop event data */
SDL_PinchEvent pinch; /**< Trackpad pinch event data */

/* This is necessary for ABI compatibility between Visual C++ and GCC.
Visual C++ will respect the push pack pragma and use 52 bytes (size of
Expand Down
15 changes: 15 additions & 0 deletions src/events/SDL_touch.c
Expand Up @@ -475,4 +475,19 @@ SDL_TouchQuit(void)
SDL_GestureQuit();
}

int
SDL_SendPinch(SDL_Window* window, float magnification, float scroll_amount)
{
int posted = 0;
if (SDL_GetEventState(SDL_PINCH) == SDL_ENABLE) {
SDL_Event event;
event.pinch.type = SDL_PINCH;
event.pinch.magnification = magnification;
event.pinch.scroll_amount = scroll_amount;
event.pinch.windowID = window ? SDL_GetWindowID(window) : 0;
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}

/* vi: set ts=4 sw=4 expandtab: */
2 changes: 2 additions & 0 deletions src/events/SDL_touch_c.h
Expand Up @@ -51,6 +51,8 @@ extern int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * win
extern int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
float x, float y, float pressure);

extern int SDL_SendPinch(SDL_Window* window, float magnification, float scroll_amount);

/* Remove a touch */
extern void SDL_DelTouch(SDL_TouchID id);

Expand Down
1 change: 1 addition & 0 deletions src/video/cocoa/SDL_cocoawindow.h
Expand Up @@ -106,6 +106,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
25 changes: 18 additions & 7 deletions src/video/cocoa/SDL_cocoawindow.m
Expand Up @@ -910,7 +910,7 @@ - (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification

isFullscreenSpace = NO;
inFullscreenTransition = NO;

[self windowDidExitFullScreen:nil];
}

Expand All @@ -926,7 +926,7 @@ - (void)windowDidEnterFullScreen:(NSNotification *)aNotification
pendingWindowOperation = PENDING_OPERATION_NONE;
[self setFullscreenSpace:NO];
} else {
/* Unset the resizable flag.
/* Unset the resizable flag.
This is a workaround for https://bugzilla.libsdl.org/show_bug.cgi?id=3697
*/
SetWindowStyle(window, [nswindow styleMask] & (~NSWindowStyleMaskResizable));
Expand Down Expand Up @@ -967,16 +967,16 @@ when returning to windowed mode from a space (instead of using a pending
- (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification
{
SDL_Window *window = _data->window;

if (window->is_destroying) {
return;
}

SetWindowStyle(window, (NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable));

isFullscreenSpace = YES;
inFullscreenTransition = NO;

[self windowDidEnterFullScreen:nil];
}

Expand Down Expand Up @@ -1403,6 +1403,17 @@ - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
[self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
}

- (void)magnifyWithEvent:(NSEvent *) theEvent
{
// The scroll amount is relative to the magnification (a percentage)
// and the current height of the window.
// Visit `Cocoa_HandleMouseWheel` to understand the division by 80
// Ming and Suriya did some manual testing to find that dividing by 2
// yields a more accurate zoom feel, so that's where the 2 comes from
CGFloat scroll_amount = [theEvent magnification] * _data->window->h / (80 * 2);
SDL_SendPinch(NULL, [theEvent magnification], scroll_amount);
}

- (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
{
NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
Expand Down Expand Up @@ -1760,7 +1771,7 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
if (!(window->flags & SDL_WINDOW_OPENGL)) {
return 0;
}

/* The rest of this macro mess is for OpenGL or OpenGL ES windows */
#if SDL_VIDEO_OPENGL_ES2
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
Expand Down Expand Up @@ -2257,7 +2268,7 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent

NSArray *contexts = [[data->nscontexts copy] autorelease];
for (SDLOpenGLContext *context in contexts) {
/* Calling setWindow:NULL causes the context to remove itself from the context list. */
/* Calling setWindow:NULL causes the context to remove itself from the context list. */
[context setWindow:NULL];
}
[data->nscontexts release];
Expand Down

0 comments on commit 614334a

Please sign in to comment.