x11: prevent a synthetic mouse event when using a touchscreen
authorSylvain Becker <sylvain.becker@gmail.com>
Wed, 10 Jul 2019 10:06:28 +0200
changeset 12936fe7caa031d3e
parent 12935 7e37d3b5e7a3
child 12937 41528cbd80ab
x11: prevent a synthetic mouse event when using a touchscreen

With multitouch, register to receive XI_Motion (which desctivates MotionNotify),
so that we can distinguish real mouse motions from synthetic one.

(bug 4690)
src/video/x11/SDL_x11xinput2.c
     1.1 --- a/src/video/x11/SDL_x11xinput2.c	Tue Jul 09 17:28:02 2019 -0400
     1.2 +++ b/src/video/x11/SDL_x11xinput2.c	Wed Jul 10 10:06:28 2019 +0200
     1.3 @@ -75,30 +75,38 @@
     1.4  }
     1.5  
     1.6  #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
     1.7 -static void
     1.8 -xinput2_normalize_touch_coordinates(SDL_VideoData *videodata, Window window,
     1.9 -    double in_x, double in_y, float *out_x, float *out_y)
    1.10 +static SDL_Window *
    1.11 +xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window)
    1.12  {
    1.13      int i;
    1.14      for (i = 0; i < videodata->numwindows; i++) {
    1.15          SDL_WindowData *d = videodata->windowlist[i];
    1.16          if (d->xwindow == window) {
    1.17 -            if (d->window->w == 1) {
    1.18 -                *out_x = 0.5f;
    1.19 -            } else {
    1.20 -                *out_x = in_x / (d->window->w - 1);
    1.21 -            }
    1.22 -            if (d->window->h == 1) {
    1.23 -                *out_y = 0.5f;
    1.24 -            } else {
    1.25 -                *out_y = in_y / (d->window->h - 1);
    1.26 -            }
    1.27 -            return;
    1.28 +            return d->window;
    1.29          }
    1.30      }
    1.31 -    // couldn't find the window...
    1.32 -    *out_x = in_x;
    1.33 -    *out_y = in_y;
    1.34 +    return NULL;
    1.35 +}
    1.36 +
    1.37 +static void
    1.38 +xinput2_normalize_touch_coordinates(SDL_Window *window, double in_x, double in_y, float *out_x, float *out_y)
    1.39 +{
    1.40 +    if (window) {
    1.41 +        if (window->w == 1) {
    1.42 +            *out_x = 0.5f;
    1.43 +        } else {
    1.44 +            *out_x = in_x / (window->w - 1);
    1.45 +        }
    1.46 +        if (window->h == 1) {
    1.47 +            *out_y = 0.5f;
    1.48 +        } else {
    1.49 +            *out_y = in_y / (window->h - 1);
    1.50 +        }
    1.51 +    } else {
    1.52 +        // couldn't find the window...
    1.53 +        *out_x = in_x;
    1.54 +        *out_y = in_y;
    1.55 +    }
    1.56  }
    1.57  #endif /* SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH */
    1.58  
    1.59 @@ -198,11 +206,30 @@
    1.60              break;
    1.61  
    1.62  #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
    1.63 +         /* With multitouch, register to receive XI_Motion (which desctivates MotionNotify),
    1.64 +          * so that we can distinguish real mouse motions from synthetic one.  */
    1.65 +        case XI_Motion: {
    1.66 +            const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
    1.67 +            int pointer_emulated = (xev->flags & XIPointerEmulated);
    1.68 +
    1.69 +            if (! pointer_emulated) {
    1.70 +                SDL_Mouse *mouse = SDL_GetMouse();
    1.71 +                if(!mouse->relative_mode || mouse->relative_mode_warp) {
    1.72 +                    SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
    1.73 +                    if (window) {
    1.74 +                        SDL_SendMouseMotion(window, 0, 0, xev->event_x, xev->event_y);
    1.75 +                    }
    1.76 +                }
    1.77 +            }
    1.78 +            return 1;
    1.79 +            }
    1.80 +            break;
    1.81 +
    1.82          case XI_TouchBegin: {
    1.83              const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
    1.84              float x, y;
    1.85 -            xinput2_normalize_touch_coordinates(videodata, xev->event,
    1.86 -                                  xev->event_x, xev->event_y, &x, &y);
    1.87 +            SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
    1.88 +            xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
    1.89              SDL_SendTouch(xev->sourceid,xev->detail, SDL_TRUE, x, y, 1.0);
    1.90              return 1;
    1.91              }
    1.92 @@ -210,8 +237,8 @@
    1.93          case XI_TouchEnd: {
    1.94              const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
    1.95              float x, y;
    1.96 -            xinput2_normalize_touch_coordinates(videodata, xev->event,
    1.97 -                                  xev->event_x, xev->event_y, &x, &y);
    1.98 +            SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
    1.99 +            xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
   1.100              SDL_SendTouch(xev->sourceid,xev->detail, SDL_FALSE, x, y, 1.0);
   1.101              return 1;
   1.102              }
   1.103 @@ -219,8 +246,8 @@
   1.104          case XI_TouchUpdate: {
   1.105              const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
   1.106              float x, y;
   1.107 -            xinput2_normalize_touch_coordinates(videodata, xev->event,
   1.108 -                                  xev->event_x, xev->event_y, &x, &y);
   1.109 +            SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
   1.110 +            xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
   1.111              SDL_SendTouchMotion(xev->sourceid,xev->detail, x, y, 1.0);
   1.112              return 1;
   1.113              }
   1.114 @@ -272,9 +299,9 @@
   1.115  #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
   1.116      SDL_VideoData *data = NULL;
   1.117      XIEventMask eventmask;
   1.118 -    unsigned char mask[3] = { 0,0,0 };
   1.119 +    unsigned char mask[4] = { 0, 0, 0, 0 };
   1.120      SDL_WindowData *window_data = NULL;
   1.121 -    
   1.122 +
   1.123      if (!X11_Xinput2IsMultitouchSupported()) {
   1.124          return;
   1.125      }
   1.126 @@ -289,6 +316,7 @@
   1.127      XISetMask(mask, XI_TouchBegin);
   1.128      XISetMask(mask, XI_TouchUpdate);
   1.129      XISetMask(mask, XI_TouchEnd);
   1.130 +    XISetMask(mask, XI_Motion);
   1.131  
   1.132      X11_XISelectEvents(data->display,window_data->xwindow,&eventmask,1);
   1.133  #endif