[PATCH v10 6/9] winex11.drv: Directly listen to master XInput2 devices if supported

Derek Lesho dereklesho52 at gmail.com
Fri Aug 2 01:24:32 CDT 2019


From: RĂ©mi Bernon <rbernon at codeweavers.com>

Under XInput2 protocol version < 2.1, raw events should not be received
if pointer grab is active. However slave device events are still
received regardless of this specification and Wine implemented a
workaround to get raw events during pointer grabs by listening to these
slave device events.

By advertising to support XInput2 protocol version >= 2.1, where raw
events are sent even during pointer grabs, it is possible to simplify
the code by listening to master device events only.

Signed-off-by: Derek Lesho <dereklesho52 at Gmail.com>
---
v10/v2: I put the adding of DeviceChanged to the mask in the legacy path so we
don't get those on XI >= 2.1 where we don't have any use for the event.
---
 dlls/winex11.drv/event.c | 42 +-----------------------------
 dlls/winex11.drv/mouse.c | 56 +++++++++++++++++++++++++++++-----------
 2 files changed, 42 insertions(+), 56 deletions(-)

diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 5c465aa033..1e64f0d2a3 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -271,46 +271,6 @@ enum event_merge_action
     MERGE_IGNORE    /* ignore the new event, keep the old one */
 };
 
-/***********************************************************************
- *           merge_raw_motion_events
- */
-#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
-static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
-{
-    int i, j, k;
-    unsigned char mask;
-
-    if (!prev->valuators.mask_len) return MERGE_HANDLE;
-    if (!next->valuators.mask_len) return MERGE_HANDLE;
-
-    mask = prev->valuators.mask[0] | next->valuators.mask[0];
-    if (mask == next->valuators.mask[0])  /* keep next */
-    {
-        for (i = j = k = 0; i < 8; i++)
-        {
-            if (XIMaskIsSet( prev->valuators.mask, i ))
-                next->valuators.values[j] += prev->valuators.values[k++];
-            if (XIMaskIsSet( next->valuators.mask, i )) j++;
-        }
-        TRACE( "merging duplicate GenericEvent\n" );
-        return MERGE_DISCARD;
-    }
-    if (mask == prev->valuators.mask[0])  /* keep prev */
-    {
-        for (i = j = k = 0; i < 8; i++)
-        {
-            if (XIMaskIsSet( next->valuators.mask, i ))
-                prev->valuators.values[j] += next->valuators.values[k++];
-            if (XIMaskIsSet( prev->valuators.mask, i )) j++;
-        }
-        TRACE( "merging duplicate GenericEvent\n" );
-        return MERGE_IGNORE;
-    }
-    /* can't merge events with disjoint masks */
-    return MERGE_HANDLE;
-}
-#endif
-
 /***********************************************************************
  *           merge_events
  *
@@ -362,7 +322,7 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
             if (next->xcookie.extension != xinput2_opcode) break;
             if (next->xcookie.evtype != XI_RawMotion) break;
             if (x11drv_thread_data()->warp_serial) break;
-            return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
+            return MERGE_HANDLE;
 #endif
         }
         break;
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index f737a306a5..578efa1931 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -130,6 +130,8 @@ static Cursor create_cursor( HANDLE handle );
 
 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
 static BOOL xinput2_available;
+static int xinput2_version_major = 2;
+static int xinput2_version_minor = 1;
 static BOOL broken_rawevents;
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
 MAKE_FUNCPTR(XIGetClientPointer);
@@ -301,8 +303,11 @@ static void enable_xinput2(void)
 
     if (data->xi2_state == xi_unknown)
     {
-        int major = 2, minor = 0;
-        if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled;
+        if (!pXIQueryVersion( data->display, &xinput2_version_major, &xinput2_version_minor ))
+        {
+            TRACE( "XInput2 v%d.%d available\n", xinput2_version_major, xinput2_version_minor );
+            data->xi2_state = xi_disabled;
+        }
         else
         {
             data->xi2_state = xi_unavailable;
@@ -314,12 +319,20 @@ static void enable_xinput2(void)
 
     mask.mask     = mask_bits;
     mask.mask_len = sizeof(mask_bits);
-    mask.deviceid = XIAllDevices;
+    mask.deviceid = XIAllMasterDevices;
     memset( mask_bits, 0, sizeof(mask_bits) );
-    XISetMask( mask_bits, XI_DeviceChanged );
     XISetMask( mask_bits, XI_RawMotion );
     XISetMask( mask_bits, XI_ButtonPress );
 
+    /* XInput 2.0 has a problematic behavior where master pointer will
+     * not send raw events to the root window whenever a grab is active
+     */
+    if (xinput2_version_major == 2 && xinput2_version_minor == 0)
+    {
+        mask.deviceid = XIAllDevices;
+        XISetMask( mask_bits, XI_DeviceChanged );
+    }
+
     pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
 
     pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count );
@@ -333,7 +346,7 @@ static void enable_xinput2(void)
      * safe to be obtained statically at enable_xinput2() time.
      */
     if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices );
-    data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count );
+    data->xi2_devices = pXIQueryDevice( data->display, mask.deviceid, &data->xi2_device_count );
     data->xi2_current_slave = 0;
 
     data->xi2_state = xi_enabled;
@@ -356,7 +369,13 @@ static void disable_xinput2(void)
 
     mask.mask = NULL;
     mask.mask_len = 0;
-    mask.deviceid = XIAllDevices;
+    mask.deviceid = XIAllMasterDevices;
+
+    /* XInput 2.0 has a problematic behavior where master pointer will
+     * not send raw events to the root window whenever a grab is active
+     */
+    if (xinput2_version_major == 2 && xinput2_version_minor == 0)
+        mask.deviceid = XIAllDevices;
 
     pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
     pXIFreeDeviceInfo( data->xi2_devices );
@@ -1735,25 +1754,32 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
     if (!event->valuators.mask_len) return FALSE;
     if (thread_data->xi2_state != xi_enabled) return FALSE;
 
-    /* If there is no slave currently detected, no previous motion nor device
-     * change events were received. Look it up now on the device list in this
-     * case.
-     */
-    if (!thread_data->xi2_current_slave)
+    if (xinput2_version_major == 2 && xinput2_version_minor == 0)
     {
         XIDeviceInfo *devices = thread_data->xi2_devices;
 
-        for (i = 0; i < thread_data->xi2_device_count; i++)
+        /* If there is no slave currently detected, no previous motion nor device
+         * change events were received. Look it up now on the device list in this
+         * case.
+         */
+        for (i = 0; !thread_data->xi2_current_slave && i < thread_data->xi2_device_count; i++)
         {
             if (devices[i].use != XISlavePointer) continue;
             if (devices[i].deviceid != event->deviceid) continue;
             if (devices[i].attachment != thread_data->xi2_core_pointer) continue;
             thread_data->xi2_current_slave = event->deviceid;
-            break;
         }
-    }
 
-    if (event->deviceid != thread_data->xi2_current_slave) return FALSE;
+        /* Only listen to slave device events on XInput == 2.0 */
+        if (event->deviceid != thread_data->xi2_current_slave)
+            return FALSE;
+    }
+    else
+    {
+        /* Only listen to master device events on XInput >= 2.1 */
+        if (event->deviceid != thread_data->xi2_core_pointer)
+            return FALSE;
+    }
 
     x_rel = &thread_data->x_rel_valuator;
     y_rel = &thread_data->y_rel_valuator;
-- 
2.22.0




More information about the wine-devel mailing list