SDL icon indicating copy to clipboard operation
SDL copied to clipboard

OS cursor appears in unexpected position when losing focus in relative mode

Open Susko3 opened this issue 2 years ago • 3 comments

Steps to reproduce

  1. Run testwm.exe --resizable --geometry 600x500 --title testwm.exe
  2. Enable relative mode: Ctrl+R
  3. Move the mouse around the window
  4. Alt-tab to another window
    • or close or minimise the window, the expected behaviour should be the same
  5. 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)

Susko3 avatar Jun 29 '23 19:06 Susko3

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.

Susko3 avatar Jun 29 '23 21:06 Susko3

Is this still active in SDL3? I believe we made this more robust since this bug report was entered.

slouken avatar Oct 06 '24 17:10 slouken

The behaviour hasn't changed. It's still exactly the same as described in the OP. Running commit e31c68427a3aa29db6a8ab8ceb1cdd52d3d7edf5.

Susko3 avatar Oct 11 '24 11:10 Susko3

Fixed, thanks!

slouken avatar Dec 23 '24 23:12 slouken