cocoa: Another attempt at mouse vs touch support.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 08 Jul 2019 13:41:01 -0400
changeset 12929d6c5eb7a0afb
parent 12928 3c4a4b1077cd
child 12930 92e72926b7f5
cocoa: Another attempt at mouse vs touch support.

This time, we make anything we think is a MacBook trackpad report its touches
as SDL_MOUSE_TOUCHID, even though they're not _actually_ synthesized events,
and let all mouse input--even if the OS synthesized it from a multitouch
trackpad on our behalf--look like physical input. This is backwards from
reality, but produces the results most apps will expect.

Note that if you have a real touch device that doesn't appear to be the
trackpad, it'll produce real touch events with unique device ids, so it's
not a total loss here, but also note that the way we decide if it was the
trackpad is an imperfect heuristic; it happens to work out right now, but
it's not impossible that a real touchscreen could come to the Mac at some
point and (incorrectly?) call it a "mouse" input, etc.

But for now, good enough.

Fixes Bugzilla #4690.
src/events/SDL_mouse.c
src/events/SDL_touch.c
src/video/cocoa/SDL_cocoamouse.m
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/events/SDL_mouse.c	Sun Jul 07 09:10:56 2019 -0700
     1.2 +++ b/src/events/SDL_mouse.c	Mon Jul 08 13:41:01 2019 -0400
     1.3 @@ -383,13 +383,11 @@
     1.4          mouse->has_position = SDL_TRUE;
     1.5      }
     1.6  
     1.7 -#ifndef __MACOSX__  /* all your trackpad input would lack relative motion when not dragging in this case. */
     1.8      /* Ignore relative motion positioning the first touch */
     1.9      if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
    1.10          xrel = 0;
    1.11          yrel = 0;
    1.12      }
    1.13 -#endif
    1.14  
    1.15      /* Update internal mouse coordinates */
    1.16      if (!mouse->relative_mode) {
     2.1 --- a/src/events/SDL_touch.c	Sun Jul 07 09:10:56 2019 -0700
     2.2 +++ b/src/events/SDL_touch.c	Mon Jul 08 13:41:01 2019 -0400
     2.3 @@ -33,11 +33,7 @@
     2.4  
     2.5  /* for mapping touch events to mice */
     2.6  
     2.7 -#ifndef __MACOSX__  /* don't generate mouse events from touch on macOS, the OS handles that. */
     2.8  #define SYNTHESIZE_TOUCH_TO_MOUSE 1
     2.9 -#else
    2.10 -#define SYNTHESIZE_TOUCH_TO_MOUSE 0
    2.11 -#endif
    2.12  
    2.13  #if SYNTHESIZE_TOUCH_TO_MOUSE
    2.14  static SDL_bool finger_touching = SDL_FALSE;
     3.1 --- a/src/video/cocoa/SDL_cocoamouse.m	Sun Jul 07 09:10:56 2019 -0700
     3.2 +++ b/src/video/cocoa/SDL_cocoamouse.m	Mon Jul 08 13:41:01 2019 -0400
     3.3 @@ -38,8 +38,6 @@
     3.4  #define DLog(...) do { } while (0)
     3.5  #endif
     3.6  
     3.7 -#define TRACKPAD_REPORTS_TOUCH_MOUSEID 0
     3.8 -
     3.9  @implementation NSCursor (InvisibleCursor)
    3.10  + (NSCursor *)invisibleCursor
    3.11  {
    3.12 @@ -381,16 +379,6 @@
    3.13      }
    3.14  
    3.15      SDL_MouseID mouseID = mouse ? mouse->mouseID : 0;
    3.16 -    #if TRACKPAD_REPORTS_TOUCH_MOUSEID
    3.17 -    if ([event subtype] == NSEventSubtypeTouch) {  /* this is a synthetic from the OS */
    3.18 -        if (mouse->touch_mouse_events) {
    3.19 -            mouseID = SDL_TOUCH_MOUSEID;   /* Hint is set */
    3.20 -        } else {
    3.21 -            return;  /* no hint set, drop this one. */
    3.22 -        }
    3.23 -    }
    3.24 -    #endif
    3.25 -
    3.26      const SDL_bool seenWarp = driverdata->seenWarp;
    3.27      driverdata->seenWarp = NO;
    3.28  
    3.29 @@ -436,16 +424,6 @@
    3.30      }
    3.31  
    3.32      SDL_MouseID mouseID = mouse->mouseID;
    3.33 -    #if TRACKPAD_REPORTS_TOUCH_MOUSEID
    3.34 -    if ([event subtype] == NSEventSubtypeTouch) {  /* this is a synthetic from the OS */
    3.35 -        if (mouse->touch_mouse_events) {
    3.36 -            mouseID = SDL_TOUCH_MOUSEID;   /* Hint is set */
    3.37 -        } else {
    3.38 -            return;  /* no hint set, drop this one. */
    3.39 -        }
    3.40 -    }
    3.41 -    #endif
    3.42 -
    3.43      CGFloat x = -[event deltaX];
    3.44      CGFloat y = [event deltaY];
    3.45      SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL;
     4.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Sun Jul 07 09:10:56 2019 -0700
     4.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Mon Jul 08 13:41:01 2019 -0400
     4.3 @@ -918,20 +918,10 @@
     4.4          return;
     4.5      }
     4.6  
     4.7 -    SDL_MouseID mouseID = mouse->mouseID;
     4.8 +    const SDL_MouseID mouseID = mouse->mouseID;
     4.9      int button;
    4.10      int clicks;
    4.11  
    4.12 -    #if TRACKPAD_REPORTS_TOUCH_MOUSEID
    4.13 -    if ([theEvent subtype] == NSEventSubtypeTouch) {  /* this is a synthetic from the OS */
    4.14 -        if (mouse->touch_mouse_events) {
    4.15 -            mouseID = SDL_TOUCH_MOUSEID;   /* Hint is set */
    4.16 -        } else {
    4.17 -            return;  /* no hint set, drop this one. */
    4.18 -        }
    4.19 -    }
    4.20 -    #endif
    4.21 -
    4.22      /* Ignore events that aren't inside the client area (i.e. title bar.) */
    4.23      if ([theEvent window]) {
    4.24          NSRect windowRect = [[[theEvent window] contentView] frame];
    4.25 @@ -989,20 +979,10 @@
    4.26          return;
    4.27      }
    4.28  
    4.29 -    SDL_MouseID mouseID = mouse->mouseID;
    4.30 +    const SDL_MouseID mouseID = mouse->mouseID;
    4.31      int button;
    4.32      int clicks;
    4.33  
    4.34 -    #if TRACKPAD_REPORTS_TOUCH_MOUSEID
    4.35 -    if ([theEvent subtype] == NSEventSubtypeTouch) {  /* this is a synthetic from the OS */
    4.36 -        if (mouse->touch_mouse_events) {
    4.37 -            mouseID = SDL_TOUCH_MOUSEID;   /* Hint is set */
    4.38 -        } else {
    4.39 -            return;  /* no hint set, drop this one. */
    4.40 -        }
    4.41 -    }
    4.42 -    #endif
    4.43 -
    4.44      if ([self processHitTest:theEvent]) {
    4.45          SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0);
    4.46          return;  /* stopped dragging, drop event. */
    4.47 @@ -1050,21 +1030,11 @@
    4.48          return;
    4.49      }
    4.50  
    4.51 -    SDL_MouseID mouseID = mouse->mouseID;
    4.52 +    const SDL_MouseID mouseID = mouse->mouseID;
    4.53      SDL_Window *window = _data->window;
    4.54      NSPoint point;
    4.55      int x, y;
    4.56  
    4.57 -    #if TRACKPAD_REPORTS_TOUCH_MOUSEID
    4.58 -    if ([theEvent subtype] == NSEventSubtypeTouch) {  /* this is a synthetic from the OS */
    4.59 -        if (mouse->touch_mouse_events) {
    4.60 -            mouseID = SDL_TOUCH_MOUSEID;   /* Hint is set */
    4.61 -        } else {
    4.62 -            return;  /* no hint set, drop this one. */
    4.63 -        }
    4.64 -    }
    4.65 -    #endif
    4.66 -
    4.67      if ([self processHitTest:theEvent]) {
    4.68          SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIT_TEST, 0, 0);
    4.69          return;  /* dragging, drop event. */
    4.70 @@ -1134,7 +1104,12 @@
    4.71  
    4.72  - (void)touchesBeganWithEvent:(NSEvent *) theEvent
    4.73  {
    4.74 +    /* probably a MacBook trackpad; make this look like a synthesized event.
    4.75 +       This is backwards from reality, but better matches user expectations. */
    4.76 +    const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
    4.77 +
    4.78      NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
    4.79 +    const SDL_TouchID touchID = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[[touches anyObject] device];
    4.80      int existingTouchCount = 0;
    4.81  
    4.82      for (NSTouch* touch in touches) {
    4.83 @@ -1143,7 +1118,6 @@
    4.84          }
    4.85      }
    4.86      if (existingTouchCount == 0) {
    4.87 -        const SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device];
    4.88          int numFingers = SDL_GetNumTouchFingers(touchID);
    4.89          DLog("Reset Lost Fingers: %d", numFingers);
    4.90          for (--numFingers; numFingers >= 0; --numFingers) {
    4.91 @@ -1175,8 +1149,12 @@
    4.92  {
    4.93      NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
    4.94  
    4.95 +    /* probably a MacBook trackpad; make this look like a synthesized event.
    4.96 +       This is backwards from reality, but better matches user expectations. */
    4.97 +    const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
    4.98 +
    4.99      for (NSTouch *touch in touches) {
   4.100 -        const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
   4.101 +        const SDL_TouchID touchId = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[touch device];
   4.102          SDL_TouchDeviceType devtype = SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE;
   4.103  
   4.104  #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101202 /* Added in the 10.12.2 SDK. */