cocoa: Added hint to treat MacBook trackpads as touch devices, not mice. Fixes #5511.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index b0e7338..f50b5e0 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -2208,6 +2208,28 @@ extern "C" {
/**
+ * \brief A variable that treats trackpads as touch devices.
+ *
+ * On macOS (and possibly other platforms in the future), SDL will report
+ * touches on a trackpad as mouse input, which is generally what users
+ * expect from this device; however, these are often actually full
+ * multitouch-capable touch devices, so it might be preferable to some apps
+ * to treat them as such.
+ *
+ * Setting this hint to true will make the trackpad input report as a
+ * multitouch device instead of a mouse. The default is false.
+ *
+ * Note that most platforms don't support this hint. As of 2.24.0, it
+ * only supports MacBooks' trackpads on macOS. Others may follow later.
+ *
+ * This hint is checked during SDL_Init and can not be changed after.
+ *
+ * This hint is available since SDL 2.24.0.
+ */
+#define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
+
+
+/**
* \brief An enumeration of hint priorities
*/
typedef enum
diff --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h
index 4de8511..8f4a413 100644
--- a/src/video/cocoa/SDL_cocoavideo.h
+++ b/src/video/cocoa/SDL_cocoavideo.h
@@ -99,6 +99,7 @@ DECLARE_ALERT_STYLE(Critical);
@interface SDL_VideoData : NSObject
@property (nonatomic) int allow_spaces;
+ @property (nonatomic) int trackpad_is_touch_only;
@property (nonatomic) unsigned int modifierFlags;
@property (nonatomic) void *key_layout;
@property (nonatomic) SDLTranslatorResponder *fieldEdit;
diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m
index 987fa2d..11a581b 100644
--- a/src/video/cocoa/SDL_cocoavideo.m
+++ b/src/video/cocoa/SDL_cocoavideo.m
@@ -197,6 +197,7 @@ Cocoa_VideoInit(_THIS)
}
data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_TRUE);
+ data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, SDL_FALSE);
data.swaplock = SDL_CreateMutex();
if (!data.swaplock) {
diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h
index 9691fa3..ec25e1f 100644
--- a/src/video/cocoa/SDL_cocoawindow.h
+++ b/src/video/cocoa/SDL_cocoawindow.h
@@ -56,6 +56,7 @@ typedef enum
BOOL isDragAreaRunning;
}
+-(BOOL) isTouchFromTrackpad:(NSEvent *)theEvent;
-(void) listen:(SDL_WindowData *) data;
-(void) pauseVisibleObservation;
-(void) resumeVisibleObservation;
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index 6c7e33d..655bf05 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -1359,26 +1359,39 @@ Cocoa_SendMouseButtonClicks(SDL_Mouse * mouse, NSEvent *theEvent, SDL_Window * w
Cocoa_HandleMouseWheel(_data.window, theEvent);
}
+
+- (BOOL)isTouchFromTrackpad:(NSEvent *)theEvent
+{
+ SDL_Window *window = _data.window;
+ SDL_VideoData *videodata = ((__bridge SDL_WindowData *) window->driverdata).videodata;
+
+ /* if this a MacBook trackpad, we'll make input look like a synthesized
+ event. This is backwards from reality, but better matches user
+ expectations. You can make it look like a generic touch device instead
+ with the SDL_HINT_TRACKPAD_IS_TOUCH_ONLY hint. */
+ BOOL istrackpad = NO;
+ if (!videodata.trackpad_is_touch_only) {
+ @try {
+ istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
+ }
+ @catch (NSException *e) {
+ /* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on
+ * macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown.
+ * This still prints a message to terminal so catching it's not an ideal solution.
+ *
+ * *** Assertion failure in -[NSEvent subtype]
+ */
+ }
+ }
+ return istrackpad;
+}
+
- (void)touchesBeganWithEvent:(NSEvent *) theEvent
{
NSSet *touches;
SDL_TouchID touchID;
int existingTouchCount;
-
- /* probably a MacBook trackpad; make this look like a synthesized event.
- This is backwards from reality, but better matches user expectations. */
- BOOL istrackpad = NO;
- @try {
- istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
- }
- @catch (NSException *e) {
- /* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on
- * macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown.
- * This still prints a message to terminal so catching it's not an ideal solution.
- *
- * *** Assertion failure in -[NSEvent subtype]
- */
- }
+ const BOOL istrackpad = [self isTouchFromTrackpad:theEvent];
touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
touchID = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[[touches anyObject] device];
@@ -1426,24 +1439,10 @@ Cocoa_SendMouseButtonClicks(SDL_Mouse * mouse, NSEvent *theEvent, SDL_Window * w
- (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
{
NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
+ const BOOL istrackpad = [self isTouchFromTrackpad:theEvent];
SDL_FingerID fingerId;
float x, y;
- /* probably a MacBook trackpad; make this look like a synthesized event.
- This is backwards from reality, but better matches user expectations. */
- BOOL istrackpad = NO;
- @try {
- istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
- }
- @catch (NSException *e) {
- /* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on
- * macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown.
- * This still prints a message to terminal so catching it's not an ideal solution.
- *
- * *** Assertion failure in -[NSEvent subtype]
- */
- }
-
for (NSTouch *touch in touches) {
const SDL_TouchID touchId = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[touch device];
SDL_TouchDeviceType devtype = SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE;