libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
10.09k stars 1.85k forks source link

Relative mouse mode drag does not report mouse button state. #11246

Open mcourteaux opened 1 month ago

mcourteaux commented 1 month ago

I have implemented a slider which supports relative mouse mode, to drag more precise than the pixels on the screen. The SDL_MouseMotionEvent::state field loses its mouse button flags when enabling relative mouse mode in Wayland and XWayland. I did not experience this issue before migrating from SDL2 to SDL3.

Eyeballing the code (without proper debugging so far), I'm a bit suspicious about these: https://github.com/libsdl-org/SDL/blob/4612db21a3450a5c2a0353558692dd32ccd3a794/src/events/SDL_mouse.c#L741-L744

https://github.com/libsdl-org/SDL/blob/4612db21a3450a5c2a0353558692dd32ccd3a794/src/events/SDL_mouse.c#L932-L937

This suggests that if we enter relative mouse mode, there is a different SDL_MouseID used. I fear that that might cause it to keep track of the button state in a different SDL_MouseInputSource, which gets obtained here:

https://github.com/libsdl-org/SDL/blob/4612db21a3450a5c2a0353558692dd32ccd3a794/src/events/SDL_mouse.c#L849

Susko3 commented 2 weeks ago

So what is happening is:

  1. The application gets a SDL_EVENT_MOUSE_BUTTON_DOWN (eg. left button)
  2. The application determines that a slider was clicked and calls SDL_SetWindowRelativeMouseMode(window, true)
  3. The application gets a SDL_EVENT_MOUSE_MOTION with all 0 state
    • The application considers the left button as released and stops the slider, disables relative mouse mode, etc.
  4. The user releases the left mouse button and you get a SDL_EVENT_MOUSE_BUTTON_UP
    • The application seemingly ignores this event, as the mouse button is already released?

Do I understand it correctly?

I'm curious what SDL_GetMouseState returns if called in step 3. It's supposed to be a global function, maybe it just combines all the mice into one. Or try SDL_GetGlobalMouseState.

mcourteaux commented 2 weeks ago

You are almost correct in your understanding, but that actually doesn't matter for SDL. The to-SDL3-irrelevant subtle difference is that I had programmed the application to ignore the MOUSE_MOTION events with the state 0, as that was not considered a drag, but a simple mouse motion.

I'm curious what SDL_GetMouseState returns if called in step 3. It's supposed to be a global function, maybe it just combines all the mice into one. Or try SDL_GetGlobalMouseState.

I tested this, and indeed, these give the correct state:

...
Dragging: event.state=0, GetMouseState=1, GetGlobalMouseState=1
Dragging: event.state=0, GetMouseState=1, GetGlobalMouseState=1
Dragging: event.state=0, GetMouseState=1, GetGlobalMouseState=1
...