This update has wine use XI2.1 and removes the legacy code dealing with the quirks in XI2.0. It also removes the duplicate event detection, as the server is smarter and will only accept raw-input events from the correct thread.

Thank you again for debugging the XI2.0 issue Remi!

On Fri, Jul 26, 2019 at 3:31 PM Derek Lesho <dereklesho52@gmail.com> wrote:
Signed-off-by: Derek Lesho <dereklesho52@Gmail.com>
---
 dlls/winex11.drv/mouse.c       | 150 ++++++++++++++++-----------------
 dlls/winex11.drv/x11drv.h      |   8 +-
 dlls/winex11.drv/x11drv_main.c |   4 +
 3 files changed, 81 insertions(+), 81 deletions(-)

diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index f737a306a5..f328eb369c 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -284,15 +284,31 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator
 }
 #endif

+/***********************************************************************
+ *              inform_wineserver
+ */
+static void inform_wineserver(void)
+{
+    static int once = 0;
+    if (!once)
+    {
+        RAWINPUT raw_input;
+        raw_input.header.dwType = RIM_ENABLE_NATIVE_MOUSE_MOVE;
+        __wine_send_raw_input(&raw_input);
+        once = 1;
+    }
+}
+

 /***********************************************************************
- *              enable_xinput2
+ *              X11DRV_XInput2_Enable
  */
-static void enable_xinput2(void)
+void X11DRV_XInput2_Enable(void)
 {
 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
     struct x11drv_thread_data *data = x11drv_thread_data();
     XIEventMask mask;
+    int core_pointer;
     XIDeviceInfo *pointer_info;
     unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)];
     int count;
@@ -301,7 +317,7 @@ static void enable_xinput2(void)

     if (data->xi2_state == xi_unknown)
     {
-        int major = 2, minor = 0;
+        int major = 2, minor = 1;
         if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled;
         else
         {
@@ -310,64 +326,65 @@ static void enable_xinput2(void)
         }
     }
     if (data->xi2_state == xi_unavailable) return;
-    if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return;
+    if (!pXIGetClientPointer( data->display, None, &core_pointer )) return;

     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 );

     pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );

-    pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count );
+    pointer_info = pXIQueryDevice( data->display, core_pointer, &count );
     update_relative_valuators( pointer_info->classes, pointer_info->num_classes );
     pXIFreeDeviceInfo( pointer_info );

-    /* This device info list is only used to find the initial current slave if
-     * no XI_DeviceChanged events happened. If any hierarchy change occurred that
-     * might be relevant here (eg. user switching mice after (un)plugging), a
-     * XI_DeviceChanged event will point us to the right slave. So this list is
-     * 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_current_slave = 0;
-
     data->xi2_state = xi_enabled;
+
+    inform_wineserver();
 #endif
 }

 /***********************************************************************
- *              disable_xinput2
+ *              X11DRV_XInput2_Disable
  */
-static void disable_xinput2(void)
+void X11DRV_XInput2_Disable(void)
 {
 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
     struct x11drv_thread_data *data = x11drv_thread_data();
     XIEventMask mask;

-    if (data->xi2_state != xi_enabled) return;
+    if (data->xi2_state < xi_enabled) return;

     TRACE( "disabling\n" );
     data->xi2_state = xi_disabled;

     mask.mask = NULL;
     mask.mask_len = 0;
-    mask.deviceid = XIAllDevices;
+    mask.deviceid = XIAllMasterDevices;

     pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
-    pXIFreeDeviceInfo( data->xi2_devices );
     data->x_rel_valuator.number = -1;
     data->y_rel_valuator.number = -1;
-    data->xi2_devices = NULL;
-    data->xi2_core_pointer = 0;
-    data->xi2_current_slave = 0;
 #endif
 }

+static void use_xinput2_path(void)
+{
+    struct x11drv_thread_data *thread_data = x11drv_thread_data();
+
+    if (thread_data->xi2_state == xi_enabled)
+        thread_data->xi2_state = xi_extra;
+}
+
+static void disable_xinput2_path(void)
+{
+    struct x11drv_thread_data *thread_data = x11drv_thread_data();
+
+    if (thread_data->xi2_state == xi_extra)
+        thread_data->xi2_state = xi_enabled;
+}

 /***********************************************************************
  *             grab_clipping_window
@@ -393,9 +410,9 @@ static BOOL grab_clipping_window( const RECT *clip )
         return TRUE;

     /* enable XInput2 unless we are already clipping */
-    if (!data->clip_hwnd) enable_xinput2();
+    if (!data->clip_hwnd) use_xinput2_path();

-    if (data->xi2_state != xi_enabled)
+    if (data->xi2_state < xi_extra)
     {
         WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) );
         DestroyWindow( msg_hwnd );
@@ -423,7 +440,7 @@ static BOOL grab_clipping_window( const RECT *clip )

     if (!clipping_cursor)
     {
-        disable_xinput2();
+        disable_xinput2_path();
         DestroyWindow( msg_hwnd );
         return FALSE;
     }
@@ -489,7 +506,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd )
         TRACE( "clip hwnd reset from %p\n", hwnd );
         data->clip_hwnd = 0;
         data->clip_reset = GetTickCount();
-        disable_xinput2();
+        disable_xinput2_path();
         DestroyWindow( hwnd );
     }
     else if (hwnd == GetForegroundWindow())  /* request to clip */
@@ -1701,22 +1718,6 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )

 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H

-/***********************************************************************
- *           X11DRV_DeviceChanged
- */
-static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev )
-{
-    XIDeviceChangedEvent *event = xev->data;
-    struct x11drv_thread_data *data = x11drv_thread_data();
-
-    if (event->deviceid != data->xi2_core_pointer) return FALSE;
-    if (event->reason != XISlaveSwitch) return FALSE;
-
-    update_relative_valuators( event->classes, event->num_classes );
-    data->xi2_current_slave = event->sourceid;
-    return TRUE;
-}
-
 /***********************************************************************
  *           X11DRV_RawMotion
  */
@@ -1724,46 +1725,36 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
 {
     XIRawEvent *event = xev->data;
     const double *values = event->valuators.values;
+    const double *raw_values = event->raw_values;
     RECT virtual_rect;
     INPUT input;
+    RAWINPUT raw_input;
     int i;
-    double dx = 0, dy = 0, val;
+    double dx = 0, dy = 0, raw_dx = 0, raw_dy = 0, val, raw_val;
     struct x11drv_thread_data *thread_data = x11drv_thread_data();
     struct x11drv_valuator_data *x_rel, *y_rel;

     if (thread_data->x_rel_valuator.number < 0 || thread_data->y_rel_valuator.number < 0) return FALSE;
     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)
-    {
-        XIDeviceInfo *devices = thread_data->xi2_devices;
-
-        for (i = 0; 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;
+    if (thread_data->xi2_state < xi_enabled) return FALSE;

     x_rel = &thread_data->x_rel_valuator;
     y_rel = &thread_data->y_rel_valuator;

+    input.type = INPUT_MOUSE;
     input.u.mi.mouseData   = 0;
     input.u.mi.dwFlags     = MOUSEEVENTF_MOVE;
     input.u.mi.time        = EVENT_x11_time_to_win32_time( event->time );
     input.u.mi.dwExtraInfo = 0;
-    input.u.mi.dx          = 0;
-    input.u.mi.dy          = 0;
+    input.u.mi.dx = 0;
+    input.u.mi.dy = 0;
+
+    raw_input.header.dwType = RIM_TYPEMOUSE;
+    raw_input.data.mouse.u.usButtonFlags = 0;
+    raw_input.data.mouse.u.usButtonData = 0;
+    raw_input.data.mouse.ulExtraInformation = 0;
+    raw_input.data.mouse.lLastX = 0;
+    raw_input.data.mouse.lLastY = 0;

     virtual_rect = get_virtual_screen_rect();

@@ -1771,12 +1762,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
     {
         if (!XIMaskIsSet( event->valuators.mask, i )) continue;
         val = *values++;
+        raw_val = *raw_values++;
         if (i == x_rel->number)
         {
             input.u.mi.dx = dx = val;
             if (x_rel->min < x_rel->max)
                 input.u.mi.dx = val * (virtual_rect.right - virtual_rect.left)
                                     / (x_rel->max - x_rel->min);
+
+            raw_input.data.mouse.lLastX = raw_dx = raw_val;
         }
         if (i == y_rel->number)
         {
@@ -1784,6 +1778,8 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
             if (y_rel->min < y_rel->max)
                 input.u.mi.dy = val * (virtual_rect.bottom - virtual_rect.top)
                                     / (y_rel->max - y_rel->min);
+
+            raw_input.data.mouse.lLastY = raw_dy = raw_val;
         }
     }

@@ -1793,10 +1789,15 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev )
         return FALSE;
     }

-    TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
+    if (thread_data->xi2_state == xi_extra)
+    {
+        TRACE( "pos %d,%d (event %f,%f)\n", input.u.mi.dx, input.u.mi.dy, dx, dy );
+        __wine_send_input( 0, &input );
+    }
+
+    TRACE("raw event %f,%f\n",  raw_dx, raw_dy);
+    __wine_send_raw_input( &raw_input );

-    input.type = INPUT_MOUSE;
-    __wine_send_input( 0, &input );
     return TRUE;
 }

@@ -1858,9 +1859,6 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev )

     switch (event->evtype)
     {
-    case XI_DeviceChanged:
-        ret = X11DRV_DeviceChanged( event );
-        break;
     case XI_RawMotion:
         ret = X11DRV_RawMotion( event );
         break;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index a0308b0675..a6d64f4383 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -194,6 +194,8 @@ extern BOOL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN;

 extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN;
 extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN;
+extern void X11DRV_XInput2_Enable(void) DECLSPEC_HIDDEN;
+extern void X11DRV_XInput2_Disable(void) DECLSPEC_HIDDEN;

 extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
                               const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
@@ -335,13 +337,9 @@ struct x11drv_thread_data
     HWND     clip_hwnd;            /* message window stored in desktop while clipping is active */
     DWORD    clip_reset;           /* time when clipping was last reset */
     HKL      kbd_layout;           /* active keyboard layout */
-    enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */
-    void    *xi2_devices;          /* list of XInput2 devices (valid when state is enabled) */
-    int      xi2_device_count;
+    enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled, xi_extra } xi2_state; /* XInput2 state */
     struct x11drv_valuator_data x_rel_valuator;
     struct x11drv_valuator_data y_rel_valuator;
-    int      xi2_core_pointer;     /* XInput2 core pointer id */
-    int      xi2_current_slave;    /* Current slave driving the Core pointer */
 };

 extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index e67a3c05a9..351ab89781 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -610,6 +610,8 @@ void CDECL X11DRV_ThreadDetach(void)

     if (data)
     {
+        X11DRV_XInput2_Disable();
+
         if (data->xim) XCloseIM( data->xim );
         if (data->font_set) XFreeFontSet( data->display, data->font_set );
         XCloseDisplay( data->display );
@@ -680,6 +682,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)

     if (use_xim) X11DRV_SetupXIM();

+    X11DRV_XInput2_Enable();
+
     return data;
 }

--
2.22.0