Finger motion also sends mouse motion when SDL_SetWindowMouseGrab is set on XWayland
Not sure if https://github.com/libsdl-org/SDL/issues/11204 should be re-opened, or this should be it's own issue
When SDL_SetWindowMouseGrab is set to true, under XWayland, while there is no issue with extra mouse down events, mouse motion events are sent along finger motion events of the first finger
Giving @Kontrabant a ping here
To elaborate a bit more, the mouse motion events from the first finger have SDL_MouseID of 0, which is the same id as the system cursor.
It looks like the motion mask is set when initiating a touch grab: https://github.com/libsdl-org/SDL/blob/ab67be7e5a2e32315227ec05b49aa4ac362ca6c0/src/video/x11/SDL_x11xinput2.c#L883-L888
It's been that way since the initial commit adding touch grabs years ago, but let's try removing it, as it probably shouldn't be there. See if https://github.com/Kontrabant/SDL/tree/xi_grab_touch fixes the issue.
@Kontrabant Thanks for looking into this. Unfortunately c69cb97 does not seem to help on kwin_wayland + XWayland; first finger movement still generates mouse motion events.
Below are stack traces from mouse and the touch screen, they seem to both be MotionNotify xevents
mouse:
Thread 1 "sdl_touch_test" hit Breakpoint 1, SDL_SendMouseMotion (timestamp=0, window=0x470530, mouseID=0, relative=false, x=270, y=365) at /work_dir/src/events/SDL_mouse.c:654
warning: 654 /work_dir/src/events/SDL_mouse.c: No such file or directory
(gdb) bt
#0 SDL_SendMouseMotion (timestamp=0, window=0x470530, mouseID=0, relative=false, x=270, y=365) at /work_dir/src/events/SDL_mouse.c:654
#1 0x00007ffff7ca815f in X11_DispatchEvent (_this=0x422600, xevent=0x7fffffffd390) at /work_dir/src/video/x11/SDL_x11events.c:1854
#2 0x00007ffff7ca92d8 in X11_PumpEvents (_this=0x422600) at /work_dir/src/video/x11/SDL_x11events.c:2327
#3 0x00007ffff7a8cff1 in SDL_PumpEventsInternal (push_sentinel=true) at /work_dir/src/events/SDL_events.c:1521
#4 0x00007ffff7a8d3f4 in SDL_WaitEventTimeoutNS (event=0x7fffffffd650, timeoutNS=0) at /work_dir/src/events/SDL_events.c:1694
#5 0x00007ffff7a8d09f in SDL_PollEvent_REAL (event=0x7fffffffd650) at /work_dir/src/events/SDL_events.c:1550
#6 0x00007ffff7a7b28c in SDL_PollEvent (a=0x7fffffffd650) at /work_dir/src/dynapi/SDL_dynapi_procs.h:713
#7 0x0000000000401fde in main () at main.c:281
multitouch screen:
Thread 1 "sdl_touch_test" hit Breakpoint 1, SDL_SendMouseMotion (timestamp=0, window=0x470530, mouseID=0, relative=false, x=354, y=491) at /work_dir/src/events/SDL_mouse.c:654
654 in /work_dir/src/events/SDL_mouse.c
(gdb) bt
#0 SDL_SendMouseMotion (timestamp=0, window=0x470530, mouseID=0, relative=false, x=354, y=491) at /work_dir/src/events/SDL_mouse.c:654
#1 0x00007ffff7ca815f in X11_DispatchEvent (_this=0x422600, xevent=0x7fffffffd390) at /work_dir/src/video/x11/SDL_x11events.c:1854
#2 0x00007ffff7ca92d8 in X11_PumpEvents (_this=0x422600) at /work_dir/src/video/x11/SDL_x11events.c:2327
#3 0x00007ffff7a8cff1 in SDL_PumpEventsInternal (push_sentinel=true) at /work_dir/src/events/SDL_events.c:1521
#4 0x00007ffff7a8d3f4 in SDL_WaitEventTimeoutNS (event=0x7fffffffd650, timeoutNS=0) at /work_dir/src/events/SDL_events.c:1694
#5 0x00007ffff7a8d09f in SDL_PollEvent_REAL (event=0x7fffffffd650) at /work_dir/src/events/SDL_events.c:1550
#6 0x00007ffff7a7b28c in SDL_PollEvent (a=0x7fffffffd650) at /work_dir/src/dynapi/SDL_dynapi_procs.h:713
#7 0x0000000000401fde in main () at main.c:281
Sorry while I was preparing the last comment, I accidentally closed the issue by some kind of github hotkey, please reopen :(
Edit: Wait now github lets me reopen the issue, huh
Ah, thanks for the stack trace. The problem is here:
https://github.com/libsdl-org/SDL/blob/b74ba6298c9aba97037975b1cc5f44a5c091cef9/src/video/x11/SDL_x11events.c#L1840-L1846
When the mouse is grabbed, XInput stops getting events from the master device, so the core X events are used for motion instead, and there is no XIPointerEmulated flag to signal that this motion event should be ignored.
XInput still gets input from the slave devices, however, they lag behind the master device by one report for some reason, so the coordinates from the master device are favored. XIGrabDevice would be preferable to use here, however, it doesn't allow confining the cursor to the window, and XWayland doesn't support the pointer barrier extension, so the core XGrabPointer function is the only way to effectively grab the mouse.
Experimenting a bit, it looks like the serials for the XInput and core motion events are the same, and the XInput events arrive before the core events. I might have an idea to work around this…
I pushed a possible fix to the previously posted branch. Can you try the updated version?
@Kontrabant Unfortunately c34d991 still doesn't fix this issue. The emulated serial is updated on finger down, but then every movement event has an incremented serial
added debug print for the below output:
case MotionNotify:
{
fprintf(stderr, "%s: last emulated motion serial 0x%lx, current serial 0x%lx\n", __func__, data->last_emulated_motion_serial, xevent->xmotion.serial);
fflush(stderr);
if (data->xinput2_mouse_enabled &&
(!data->mouse_grabbed || xevent->xmotion.serial == data->last_emulated_motion_serial)) {
...
mouse jiggle after test application has started:
...
X11_DispatchEvent: last emulated motion serial 0x0, current serial 0x4cf
X11_DispatchEvent: last emulated motion serial 0x0, current serial 0x4d0
X11_DispatchEvent: last emulated motion serial 0x0, current serial 0x4d1
X11_DispatchEvent: last emulated motion serial 0x0, current serial 0x4d2
...
finger down then jiggle afterwards:
...
X11_DispatchEvent: last emulated motion serial 0x5ef, current serial 0x615
X11_DispatchEvent: last emulated motion serial 0x5ef, current serial 0x616
X11_DispatchEvent: last emulated motion serial 0x5ef, current serial 0x617
X11_DispatchEvent: last emulated motion serial 0x5ef, current serial 0x617
...
It looks like emulated pointer events from touches are only reported via the master pointer device, which makes sense as they have no associated slave pointer devices, so once the grab is started, no further events are sent to XInput.
I've pushed yet another workaround to the working branch: this tracks if any touches are active, and falls back to XInput for handling pointer events if both the pointer is grabbed and touches are active. Events from pointer devices received while touches are active will be a report behind the master in this case, as they are from the slave devices, but simultaneously receiving events from both the mouse and touches is not likely to be a common occurrence in real usage.
Observations with 5d2730d on Kwin + Xwayland :
- Mouse motion events are not longer sent when there is only finger movement, so the work around is functioning
- On finger up however, a mouse motion event is sent to update the mouse to where the finger was
- When both mouse and finger are moving, mouse motion events has a mix of both the finger's and the cursor's location
Another interesting observation is that on Steam Gamescope session + Xwayland, even without the workaround, there is no extra mouse movement from finger. It might make sense to test more compositors as well when paired with Xwayland, as the extra mouse movement might be from Kwin trying to retroactively move the mouse cursor to where the finger is, when grab is active.
Steam Gamescope session multitouch was enabled as per: https://www.reddit.com/r/SteamDeck/comments/10455uw/comment/j34emkl/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
On finger up however, a mouse motion event is sent to update the mouse to where the finger was
Ah, when the last finger was raised, the touch count was zero, so the flag to suppress core motion events was no longer set. We just need to make sure that one core motion event past the last touch being raised is ignored as well. I pushed a change that should fix this.
When both mouse and finger are moving, mouse motion events has a mix of both the finger's and the cursor's location
I suspect this is touch and pointer events fighting with one another internally in X or the desktop. It probably keeps trying to place the pointer at the last finger location for consistency, which causes havoc when both are active at the same time. I don't think there's anything SDL can do about this, except for completely ignoring pointer motion events while touches are active, which is not ideal.
Sorry to bother you, but could you test one more time with the latest update, which should fix the last errant pointer motion when lifting the last touch? Once that is confirmed, we can get this merged.
Thanks for following up with traces/logs and doing the testing on this issue. It's difficult to fix things like this when you lack access to the affected hardware.
Sorry to bother you, but could you test one more time with the latest update, which should fix the last errant pointer motion when lifting the last touch? Once that is confirmed, we can get this merged.
Thanks for following up with traces/logs and doing the testing on this issue. It's difficult to fix things like this when you lack access to the affected hardware.
Hi, thanks for looking into the issue, and sorry for missing the email for the last two days
489dea8 does not emit mouse motion on finger up in KWin + XWayland
The fix has been merged. Thanks again for your patience and testing!