From: RĂ©mi Bernon rbernon@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@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;