SDL: Enable capturing raw Xinput2 touch events and use to flag global mouse state as dirty

From dbf79405416400cfeecc4b1d92eeda24421edd5f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 27 Jul 2022 10:31:24 -0700
Subject: [PATCH] Enable capturing raw Xinput2 touch events and use to flag
 global mouse state as dirty

- Touch events may be translated to mouse movement events without the normal Xinput2 raw motion events
  being sent. Not all touch events will necessarily move the mouse but this ensures we update the global
  mouse state just in case.

- Fix up some formatting

CR: saml
---
 src/video/x11/SDL_x11xinput2.c | 45 ++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c
index 21d8bd6c14d..83a86997f02 100644
--- a/src/video/x11/SDL_x11xinput2.c
+++ b/src/video/x11/SDL_x11xinput2.c
@@ -120,7 +120,7 @@ X11_InitXinput2(_THIS)
 
     int version = 0;
     XIEventMask eventmask;
-    unsigned char mask[3] = { 0,0,0 };
+    unsigned char mask[4] = { 0, 0, 0, 0 };
     int event, err;
 
     /*
@@ -149,7 +149,7 @@ X11_InitXinput2(_THIS)
     xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2);
 #endif
 
-    /* Enable  Raw motion events for this display */
+    /* Enable raw motion events for this display */
     eventmask.deviceid = XIAllMasterDevices;
     eventmask.mask_len = sizeof(mask);
     eventmask.mask = mask;
@@ -158,7 +158,16 @@ X11_InitXinput2(_THIS)
     XISetMask(mask, XI_RawButtonPress);
     XISetMask(mask, XI_RawButtonRelease);
 
-    if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) {
+#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
+    /* Enable raw touch events if supported */
+    if (X11_Xinput2IsMultitouchSupported()) {
+        XISetMask(mask, XI_RawTouchBegin);
+        XISetMask(mask, XI_RawTouchUpdate);
+        XISetMask(mask, XI_RawTouchEnd);
+    }
+#endif
+
+    if (X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask,1) != Success) {
         return;
     }
 #endif
@@ -168,7 +177,7 @@ int
 X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
 {
 #if SDL_VIDEO_DRIVER_X11_XINPUT2
-    if(cookie->extension != xinput2_opcode) {
+    if (cookie->extension != xinput2_opcode) {
         return 0;
     }
     switch(cookie->evtype) {
@@ -197,11 +206,16 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
             prev_rel_coords[1] = relative_coords[1];
             prev_time = rawev->time;
             return 1;
-            }
-            break;
+        }
+        break;
 
         case XI_RawButtonPress:
         case XI_RawButtonRelease:
+#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
+        case XI_RawTouchBegin:
+        case XI_RawTouchUpdate:
+        case XI_RawTouchEnd:
+#endif
             videodata->global_mouse_changed = SDL_TRUE;
             break;
 
@@ -214,7 +228,7 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
 
             if (! pointer_emulated) {
                 SDL_Mouse *mouse = SDL_GetMouse();
-                if(!mouse->relative_mode || mouse->relative_mode_warp) {
+                if (!mouse->relative_mode || mouse->relative_mode_warp) {
                     SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
                     if (window) {
                         SDL_SendMouseMotion(window, 0, 0, xev->event_x, xev->event_y);
@@ -222,8 +236,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
                 }
             }
             return 1;
-            }
-            break;
+        }
+        break;
 
         case XI_TouchBegin: {
             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
@@ -232,8 +246,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
             xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
             SDL_SendTouch(xev->sourceid, xev->detail, window, SDL_TRUE, x, y, 1.0);
             return 1;
-            }
-            break;
+        }
+        break;
         case XI_TouchEnd: {
             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
             float x, y;
@@ -241,8 +255,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
             xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
             SDL_SendTouch(xev->sourceid, xev->detail, window, SDL_FALSE, x, y, 1.0);
             return 1;
-            }
-            break;
+        }
+        break;
         case XI_TouchUpdate: {
             const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
             float x, y;
@@ -250,8 +264,9 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
             xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
             SDL_SendTouchMotion(xev->sourceid, xev->detail, window, x, y, 1.0);
             return 1;
-            }
-            break;
+        }
+        break;
+
 #endif
     }
 #endif