OS cursor appears in unexpected position when losing focus in relative mode
Steps to reproduce
- Run
testwm.exe --resizable --geometry 600x500 --title testwm.exe - Enable relative mode: Ctrl+R
- Move the mouse around the window
- Alt-tab to another window
- or close or minimise the window, the expected behaviour should be the same
- Keep note of where the OS mouse cursor appears
Expected behaviour
The OS cursor should appear at the current SDL mouse position: where it would appear if relative mode was manually disabled.
No SDL_EVENT_MOUSE_MOTION should be generated, as the user didn't move the mouse, just alt+tab was pressed.
Actual behaviour
The OS cursor will appear in the centre of the window and a mouse move event for that will be generated (unexpected, as the mouse didn't actually move, and the difference between the old and the new position might be large).
If using SDL_HINT_MOUSE_RELATIVE_MODE_CENTER: 0 and the SDL mouse speed doesn't match the Windows speed, the mouse will appear in a (seemingly) random location. You can use PoweToys Mouse pointer Crosshairs to see where it will appear (not shown in the video).
https://github.com/libsdl-org/SDL/assets/16479013/ec9fc5e1-5813-4dd0-a975-02975287c3a9
Environment
- latest SDL3
main: 4d23eaf81e6918deb7521e4b81bb83545c92097f - Windows 11 22H2 (OS Build 22621.1848)
I've edited the original post to also mention closing and minimising the window since it also leaves the cursor in an invalid position.
This naïve approach does work, but only for alt-tabbing.
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index eb8f6a4bf..086120342 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -3465,6 +3465,14 @@ void SDL_OnWindowEnter(SDL_Window *window)
void SDL_OnWindowLeave(SDL_Window *window)
{
+ SDL_Mouse *mouse = SDL_GetMouse();
+
+ if (mouse->relative_mode && mouse->WarpMouse) {
+ /* relative mode implementations might leave the OS/global mouse position
+ * in an invalid state, so warp it to the expected position before
+ * returning control of the mouse to the OS */
+ mouse->WarpMouse(window, mouse->x, mouse->y);
+ }
}
void SDL_OnWindowFocusGained(SDL_Window *window)
But this regresses minimising as the cursor will be warped to (0, 0). I reckon this is because the window is minimised and therefore converting coordinates is invalid: WIN_SetCursorPos is called with (-32000, -32000) if the SDL mouse is in the upper-left corner.
Is this still active in SDL3? I believe we made this more robust since this bug report was entered.
The behaviour hasn't changed. It's still exactly the same as described in the OP. Running commit e31c68427a3aa29db6a8ab8ceb1cdd52d3d7edf5.
Fixed, thanks!