diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index fbff514ac2..c5c19c3089 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -1836,7 +1836,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) case MotionNotify: { - if (data->xinput2_mouse_enabled && !data->mouse_grabbed) { + if (X11_Xinput2HandlesMotionForWindow(data)) { // This input is being handled by XInput2 break; } diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index 60c4e6bf57..d5c739ae68 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -38,6 +38,8 @@ static bool xinput2_initialized; #if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) static bool xinput2_scrolling_supported; static bool xinput2_multitouch_supported; +static bool xinput2_grabbed_touch_raised; +static int xinput2_active_touch_count; #endif #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_GESTURE static bool xinput2_gesture_supported; @@ -673,15 +675,17 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) } #endif - if (xev->deviceid == videodata->xinput_master_pointer_device) { - // Use the master device for non-relative motion, as the slave devices can seemingly lag behind. + /* Use the master device for non-relative motion, as the slave devices can seemingly lag behind, + * except when the mouse is grabbed and touches are active, as core input events are used for + * absolute motion while the mouse is grabbed, and core events don't have the XIPointerEmulated + * flag to filter out pointer events emulated from touch events. + */ + SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); + if (window && (xev->deviceid == videodata->xinput_master_pointer_device || (xinput2_active_touch_count && window->internal->mouse_grabbed))) { SDL_Mouse *mouse = SDL_GetMouse(); if (!mouse->relative_mode) { - SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); - if (window) { X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false); SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y); - } } } } @@ -692,6 +696,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) { const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data; float x, y; + ++xinput2_active_touch_count; SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_EVENT_FINGER_DOWN, x, y, 1.0); @@ -702,6 +707,9 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data; float x, y; SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); + if (!--xinput2_active_touch_count && window && window->internal->mouse_grabbed) { + xinput2_grabbed_touch_raised = true; + } xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y); SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_EVENT_FINGER_UP, x, y, 1.0); } break; @@ -743,6 +751,20 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) void X11_InitXinput2Multitouch(SDL_VideoDevice *_this) { + xinput2_grabbed_touch_raised = false; + xinput2_active_touch_count = 0; +} + +bool X11_Xinput2HandlesMotionForWindow(SDL_WindowData *window_data) +{ + /* Send the active flag once more after the touch count is zero, to suppress the + * emulated motion event when the last touch is raised. + */ + const bool ret = window_data->xinput2_mouse_enabled && + (!window_data->mouse_grabbed || xinput2_active_touch_count || xinput2_grabbed_touch_raised); + xinput2_grabbed_touch_raised = false; + + return ret; } void X11_Xinput2Select(SDL_VideoDevice *_this, SDL_Window *window) @@ -888,6 +910,8 @@ void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window) return; } + xinput2_grabbed_touch_raised = false; + mods.modifiers = XIAnyModifier; mods.status = 0; diff --git a/src/video/x11/SDL_x11xinput2.h b/src/video/x11/SDL_x11xinput2.h index f05e96cd1e..20595055ea 100644 --- a/src/video/x11/SDL_x11xinput2.h +++ b/src/video/x11/SDL_x11xinput2.h @@ -41,5 +41,6 @@ extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window); extern bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this); extern void X11_Xinput2UpdatePointerMapping(SDL_VideoDevice *_this); +extern bool X11_Xinput2HandlesMotionForWindow(SDL_WindowData *window_data); #endif // SDL_x11xinput2_h_