SDL: Mouse coordinates are floating point

From cefbeb582f4b41f5e4e0eca0ae6d7b652c92e1d1 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 29 Dec 2022 19:31:12 -0800
Subject: [PATCH] Mouse coordinates are floating point

You can get sub-pixel mouse coordinates and motion depending on the platform and display scaling.

Fixes https://github.com/libsdl-org/SDL/issues/2999
---
 docs/README-migration.md                    |   6 +
 include/SDL3/SDL_events.h                   |  30 ++--
 include/SDL3/SDL_mouse.h                    |  10 +-
 include/SDL3/SDL_render.h                   |  14 +-
 src/core/haiku/SDL_BApp.h                   |   4 +-
 src/core/linux/SDL_evdev.c                  |   2 +-
 src/core/openbsd/SDL_wscons_mouse.c         |   4 +-
 src/core/winrt/SDL_winrtapp_direct3d.cpp    |   2 +-
 src/dynapi/SDL_dynapi_procs.h               |  14 +-
 src/events/SDL_events.c                     |  15 +-
 src/events/SDL_mouse.c                      | 179 +++++++-------------
 src/events/SDL_mouse_c.h                    |  26 ++-
 src/events/SDL_touch.c                      |  36 ++--
 src/joystick/apple/SDL_mfijoystick.m        |   2 +-
 src/render/SDL_render.c                     |  56 +++---
 src/render/SDL_sysrender.h                  |   4 -
 src/test/SDL_test_common.c                  |  23 +--
 src/video/SDL_video.c                       |   4 +-
 src/video/android/SDL_androidmouse.c        |   6 +-
 src/video/cocoa/SDL_cocoamouse.m            |  22 +--
 src/video/cocoa/SDL_cocoawindow.h           |   4 +-
 src/video/cocoa/SDL_cocoawindow.m           |  56 +++---
 src/video/emscripten/SDL_emscriptenevents.c |  22 +--
 src/video/emscripten/SDL_emscriptenmouse.c  |   6 -
 src/video/haiku/SDL_BApp.h                  |   4 +-
 src/video/kmsdrm/SDL_kmsdrmmouse.c          |  20 +--
 src/video/raspberry/SDL_rpimouse.c          |  67 ++------
 src/video/riscos/SDL_riscosevents.c         |   2 +-
 src/video/uikit/SDL_uikitevents.m           |   2 +-
 src/video/uikit/SDL_uikitview.m             |   2 +-
 src/video/vita/SDL_vitamouse.c              |   2 +-
 src/video/wayland/SDL_waylandevents.c       |  23 +--
 src/video/wayland/SDL_waylandevents_c.h     |   3 -
 src/video/wayland/SDL_waylandmouse.c        |   8 +-
 src/video/windows/SDL_windowsevents.c       |  29 ++--
 src/video/windows/SDL_windowsmodes.c        |  62 ++++---
 src/video/windows/SDL_windowsmodes.h        |   2 +
 src/video/windows/SDL_windowsmouse.c        |  17 +-
 src/video/windows/SDL_windowswindow.c       |  28 +++
 src/video/windows/SDL_windowswindow.h       |   2 +
 src/video/winrt/SDL_winrtpointerinput.cpp   |   6 +-
 src/video/x11/SDL_x11events.c               |   6 +-
 src/video/x11/SDL_x11mouse.c                |  16 +-
 src/video/x11/SDL_x11xinput2.c              |   4 +-
 test/testautomation_mouse.c                 |  96 ++++++-----
 test/testgamepad.c                          |  54 +++---
 test/testgeometry.c                         |   6 +-
 test/testintersections.c                    |  50 +++---
 test/testmouse.c                            |  23 ++-
 test/testoverlay2.c                         |  16 +-
 test/testrelative.c                         |  13 +-
 test/testwm2.c                              |  20 +--
 52 files changed, 520 insertions(+), 610 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index 2f377d34e6f1..56417441b6b4 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -82,6 +82,8 @@ The timestamp_us member of the sensor events has been renamed sensor_timestamp a
 
 You should set the event.common.timestamp field before passing an event to SDL_PushEvent(). If the timestamp is 0 it will be filled in with SDL_GetTicksNS().
 
+Mouse events use floating point values for mouse coordinates and relative motion values. You can get sub-pixel motion depending on the platform and display scaling.
+
 The SDL_DISPLAYEVENT_* events have been moved to top level events, and SDL_DISPLAYEVENT has been removed. In general, handling this change just means checking for the individual events instead of first checking for SDL_DISPLAYEVENT and then checking for display events. You can compare the event >= SDL_DISPLAYEVENT_FIRST and <= SDL_DISPLAYEVENT_LAST if you need to see whether it's a display event.
 
 The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed. In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT and then checking for window events. You can compare the event >= SDL_WINDOWEVENT_FIRST and <= SDL_WINDOWEVENT_LAST if you need to see whether it's a window event.
@@ -411,6 +413,8 @@ used by additional platforms that didn't have a SDL_RunApp-like function before)
 
 SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
 
+SDL_GetMouseState(), SDL_GetGlobalMouseState(), SDL_GetRelativeMouseState(), SDL_WarpMouseInWindow(), and SDL_WarpMouseGlobal() all use floating point mouse positions, to provide sub-pixel precision on platforms that support it.
+
 The following functions have been renamed:
 * SDL_FreeCursor() => SDL_DestroyCursor()
 
@@ -463,6 +467,8 @@ which index is the "opengl" or whatnot driver, you can just pass that string dir
 here, now. Passing NULL is the same as passing -1 here in SDL2, to signify you want SDL
 to decide for you.
 
+SDL_RenderWindowToLogical() and SDL_RenderLogicalToWindow() take floating point coordinates in both directions.
+
 The following functions have been renamed:
 * SDL_RenderCopy() => SDL_RenderTexture()
 * SDL_RenderCopyEx() => SDL_RenderTextureRotated()
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 6e068ff40c43..736c94e93c6e 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -297,12 +297,12 @@ typedef struct SDL_MouseMotionEvent
     Uint32 type;        /**< ::SDL_MOUSEMOTION */
     Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
-    SDL_MouseID which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+    SDL_MouseID which;  /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
     Uint32 state;       /**< The current button state */
-    Sint32 x;           /**< X coordinate, relative to window */
-    Sint32 y;           /**< Y coordinate, relative to window */
-    Sint32 xrel;        /**< The relative motion in the X direction */
-    Sint32 yrel;        /**< The relative motion in the Y direction */
+    float x;            /**< X coordinate, relative to window */
+    float y;            /**< Y coordinate, relative to window */
+    float xrel;         /**< The relative motion in the X direction */
+    float yrel;         /**< The relative motion in the Y direction */
 } SDL_MouseMotionEvent;
 
 /**
@@ -313,13 +313,13 @@ typedef struct SDL_MouseButtonEvent
     Uint32 type;        /**< ::SDL_MOUSEBUTTONDOWN or ::SDL_MOUSEBUTTONUP */
     Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
-    SDL_MouseID which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+    SDL_MouseID which;  /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
     Uint8 button;       /**< The mouse button index */
     Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
     Uint8 clicks;       /**< 1 for single-click, 2 for double-click, etc. */
-    Uint8 padding1;
-    Sint32 x;           /**< X coordinate, relative to window */
-    Sint32 y;           /**< Y coordinate, relative to window */
+    Uint8 padding;
+    float x;            /**< X coordinate, relative to window */
+    float y;            /**< Y coordinate, relative to window */
 } SDL_MouseButtonEvent;
 
 /**
@@ -330,14 +330,12 @@ typedef struct SDL_MouseWheelEvent
     Uint32 type;        /**< ::SDL_MOUSEWHEEL */
     Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
-    SDL_MouseID which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
-    Sint32 x;           /**< The amount scrolled horizontally, positive to the right and negative to the left */
-    Sint32 y;           /**< The amount scrolled vertically, positive away from the user and negative toward the user */
+    SDL_MouseID which;  /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
+    float x;            /**< The amount scrolled horizontally, positive to the right and negative to the left */
+    float y;            /**< The amount scrolled vertically, positive away from the user and negative toward the user */
     Uint32 direction;   /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
-    float preciseX;     /**< The amount scrolled horizontally, positive to the right and negative to the left, with float precision (added in 2.0.18) */
-    float preciseY;     /**< The amount scrolled vertically, positive away from the user and negative toward the user, with float precision (added in 2.0.18) */
-    Sint32 mouseX;      /**< X coordinate, relative to window (added in 2.26.0) */
-    Sint32 mouseY;      /**< Y coordinate, relative to window (added in 2.26.0) */
+    float mouseX;       /**< X coordinate, relative to window */
+    float mouseY;       /**< Y coordinate, relative to window */
 } SDL_MouseWheelEvent;
 
 /**
diff --git a/include/SDL3/SDL_mouse.h b/include/SDL3/SDL_mouse.h
index ed58a76a77f1..836ef513e88b 100644
--- a/include/SDL3/SDL_mouse.h
+++ b/include/SDL3/SDL_mouse.h
@@ -103,7 +103,7 @@ extern DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void);
  * \sa SDL_GetRelativeMouseState
  * \sa SDL_PumpEvents
  */
-extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y);
+extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(float *x, float *y);
 
 /**
  * Get the current state of the mouse in relation to the desktop.
@@ -132,7 +132,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y);
  *
  * \sa SDL_CaptureMouse
  */
-extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(int *x, int *y);
+extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(float *x, float *y);
 
 /**
  * Retrieve the relative state of the mouse.
@@ -151,7 +151,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(int *x, int *y);
  *
  * \sa SDL_GetMouseState
  */
-extern DECLSPEC Uint32 SDLCALL SDL_GetRelativeMouseState(int *x, int *y);
+extern DECLSPEC Uint32 SDLCALL SDL_GetRelativeMouseState(float *x, float *y);
 
 /**
  * Move the mouse cursor to the given position within the window.
@@ -173,7 +173,7 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetRelativeMouseState(int *x, int *y);
  * \sa SDL_WarpMouseGlobal
  */
 extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window,
-                                                   int x, int y);
+                                                   float x, float y);
 
 /**
  * Move the mouse to the given position in global screen space.
@@ -195,7 +195,7 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window,
  *
  * \sa SDL_WarpMouseInWindow
  */
-extern DECLSPEC int SDLCALL SDL_WarpMouseGlobal(int x, int y);
+extern DECLSPEC int SDLCALL SDL_WarpMouseGlobal(float x, float y);
 
 /**
  * Set relative mouse mode.
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index ef2a9c520fc1..3eda734b1242 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -1034,10 +1034,10 @@ extern DECLSPEC void SDLCALL SDL_GetRenderScale(SDL_Renderer * renderer,
  * \sa SDL_GetRenderLogicalSize
  * \sa SDL_SetRenderLogicalSize
  */
-extern DECLSPEC void SDLCALL SDL_RenderWindowToLogical(SDL_Renderer * renderer, 
-                                                            int windowX, int windowY, 
-                                                            float *logicalX, float *logicalY);
-                                                  
+extern DECLSPEC void SDLCALL SDL_RenderWindowToLogical(SDL_Renderer *renderer,
+                                                       float windowX, float windowY,
+                                                       float *logicalX, float *logicalY);
+
 
 /**
  * Get real coordinates of point in window when given logical coordinates of
@@ -1060,9 +1060,9 @@ extern DECLSPEC void SDLCALL SDL_RenderWindowToLogical(SDL_Renderer * renderer,
  * \sa SDL_GetRenderLogicalSize
  * \sa SDL_SetRenderLogicalSize
  */
-extern DECLSPEC void SDLCALL SDL_RenderLogicalToWindow(SDL_Renderer * renderer, 
-                                                            float logicalX, float logicalY,
-                                                            int *windowX, int *windowY);
+extern DECLSPEC void SDLCALL SDL_RenderLogicalToWindow(SDL_Renderer *renderer,
+                                                       float logicalX, float logicalY,
+                                                       float *windowX, float *windowY);
 
 /**
  * Set the color used for drawing operations (Rect, Line and Clear).
diff --git a/src/core/haiku/SDL_BApp.h b/src/core/haiku/SDL_BApp.h
index fa108a5c4da0..d635c648ec24 100644
--- a/src/core/haiku/SDL_BApp.h
+++ b/src/core/haiku/SDL_BApp.h
@@ -254,12 +254,12 @@ class SDL_BApp : public BApplication
             SDL_GetWindowPosition(win, &winPosX, &winPosY);
             int dx = x - (winWidth / 2);
             int dy = y - (winHeight / 2);
-            SDL_SendMouseMotion(0, win, 0, SDL_GetMouse()->relative_mode, dx, dy);
+            SDL_SendMouseMotion(0, win, 0, SDL_GetMouse()->relative_mode, (float)dx, (float)dy);
             set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2));
             if (!be_app->IsCursorHidden())
                 be_app->HideCursor();
         } else {
-            SDL_SendMouseMotion(0, win, 0, 0, x, y);
+            SDL_SendMouseMotion(0, win, 0, 0, (float)x, (float)y);
             if (SDL_CursorVisible() && be_app->IsCursorHidden())
                 be_app->ShowCursor();
         }
diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c
index 05303604fdfb..df8fcb479839 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -448,7 +448,7 @@ void SDL_EVDEV_Poll(void)
                     case SYN_REPORT:
                         /* Send mouse axis changes together to ensure consistency and reduce event processing overhead */
                         if (item->mouse_x != 0 || item->mouse_y != 0) {
-                            SDL_SendMouseMotion(SDL_EVDEV_GetEventTimestamp(event), mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, item->mouse_x, item->mouse_y);
+                            SDL_SendMouseMotion(SDL_EVDEV_GetEventTimestamp(event), mouse->focus, (SDL_MouseID)item->fd, item->relative_mouse, (float)item->mouse_x, (float)item->mouse_y);
                             item->mouse_x = item->mouse_y = 0;
                         }
                         if (item->mouse_wheel != 0 || item->mouse_hwheel != 0) {
diff --git a/src/core/openbsd/SDL_wscons_mouse.c b/src/core/openbsd/SDL_wscons_mouse.c
index 58d2ab58b7d0..de3ab8ec8e7a 100644
--- a/src/core/openbsd/SDL_wscons_mouse.c
+++ b/src/core/openbsd/SDL_wscons_mouse.c
@@ -100,12 +100,12 @@ void updateMouse(SDL_WSCONS_mouse_input_data *inputData)
             } break;
             case WSCONS_EVENT_MOUSE_DELTA_X:
             {
-                SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, events[i].value, 0);
+                SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, (float)events[i].value, 0.0f);
                 break;
             }
             case WSCONS_EVENT_MOUSE_DELTA_Y:
             {
-                SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, 0, -events[i].value);
+                SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, 0.0f, -(float)events[i].value);
                 break;
             }
             case WSCONS_EVENT_MOUSE_DELTA_W:
diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp
index e70e132ab66f..bed939c48734 100644
--- a/src/core/winrt/SDL_winrtapp_direct3d.cpp
+++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp
@@ -547,7 +547,7 @@ void SDL_WinRTApp::OnWindowActivated(CoreWindow ^ sender, WindowActivatedEventAr
              */
 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE)
             Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
-            SDL_SendMouseMotion(0, window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y);
+            SDL_SendMouseMotion(0, window, 0, 0, cursorPos.X, cursorPos.Y);
 #endif
 
             /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index be0d18a6bc5c..f4cf4b731170 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -317,7 +317,7 @@ SDL_DYNAPI_PROC(int,SDL_GetGamepadTouchpadFinger,(SDL_Gamepad *a, int b, int c,
 SDL_DYNAPI_PROC(SDL_GamepadType,SDL_GetGamepadType,(SDL_Gamepad *a),(a),return)
 SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadVendor,(SDL_Gamepad *a),(a),return)
 SDL_DYNAPI_PROC(SDL_JoystickID*,SDL_GetGamepads,(int *a),(a),return)
-SDL_DYNAPI_PROC(Uint32,SDL_GetGlobalMouseState,(int *a, int *b),(a,b),return)
+SDL_DYNAPI_PROC(Uint32,SDL_GetGlobalMouseState,(float *a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetHint,(const char *a),(a),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_GetHintBoolean,(const char *a, SDL_bool b),(a,b),return)
@@ -360,7 +360,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GetMasksForPixelFormatEnum,(Uint32 a, int *b, Uint3
 SDL_DYNAPI_PROC(void,SDL_GetMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),)
 SDL_DYNAPI_PROC(SDL_Keymod,SDL_GetModState,(void),(),return)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GetMouseFocus,(void),(),return)
-SDL_DYNAPI_PROC(Uint32,SDL_GetMouseState,(int *a, int *b),(a,b),return)
+SDL_DYNAPI_PROC(Uint32,SDL_GetMouseState,(float *a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAllocations,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAudioDevices,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumAudioDrivers,(void),(),return)
@@ -396,7 +396,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GetRectIntersectionFloat,(const SDL_FRect *a, const
 SDL_DYNAPI_PROC(void,SDL_GetRectUnion,(const SDL_Rect *a, const SDL_Rect *b, SDL_Rect *c),(a,b,c),)
 SDL_DYNAPI_PROC(void,SDL_GetRectUnionFloat,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),)
 SDL_DYNAPI_PROC(SDL_bool,SDL_GetRelativeMouseMode,(void),(),return)
-SDL_DYNAPI_PROC(Uint32,SDL_GetRelativeMouseState,(int *a, int *b),(a,b),return)
+SDL_DYNAPI_PROC(Uint32,SDL_GetRelativeMouseState,(float *a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_GetRenderClipRect,(SDL_Renderer *a, SDL_Rect *b),(a,b),)
 SDL_DYNAPI_PROC(int,SDL_GetRenderDrawBlendMode,(SDL_Renderer *a, SDL_BlendMode *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColor,(SDL_Renderer *a, Uint8 *b, Uint8 *c, Uint8 *d, Uint8 *e),(a,b,c,d,e),return)
@@ -628,7 +628,7 @@ SDL_DYNAPI_PROC(int,SDL_RenderLine,(SDL_Renderer *a, int b, int c, int d, int e)
 SDL_DYNAPI_PROC(int,SDL_RenderLineFloat,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(int,SDL_RenderLines,(SDL_Renderer *a, const SDL_Point *b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_RenderLinesFloat,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
-SDL_DYNAPI_PROC(void,SDL_RenderLogicalToWindow,(SDL_Renderer *a, float b, float c, int *d, int *e),(a,b,c,d,e),)
+SDL_DYNAPI_PROC(void,SDL_RenderLogicalToWindow,(SDL_Renderer *a, float b, float c, float *d, float *e),(a,b,c,d,e),)
 SDL_DYNAPI_PROC(int,SDL_RenderPoint,(SDL_Renderer *a, int b, int c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_RenderPointFloat,(SDL_Renderer *a, float b, float c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_RenderPoints,(SDL_Renderer *a, const SDL_Point *b, int c),(a,b,c),return)
@@ -644,7 +644,7 @@ SDL_DYNAPI_PROC(int,SDL_RenderTexture,(SDL_Renderer *a, SDL_Texture *b, const SD
 SDL_DYNAPI_PROC(int,SDL_RenderTextureFloat,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_FRect *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(int,SDL_RenderTextureRotated,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_Rect *d, const double e, const SDL_Point *f, const SDL_RendererFlip g),(a,b,c,d,e,f,g),return)
 SDL_DYNAPI_PROC(int,SDL_RenderTextureRotatedFloat,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_FRect *d, const double e, const SDL_FPoint *f, const SDL_RendererFlip g),(a,b,c,d,e,f,g),return)
-SDL_DYNAPI_PROC(void,SDL_RenderWindowToLogical,(SDL_Renderer *a, int b, int c, float *d, float *e),(a,b,c,d,e),)
+SDL_DYNAPI_PROC(void,SDL_RenderWindowToLogical,(SDL_Renderer *a, float b, float c, float *d, float *e),(a,b,c,d,e),)
 SDL_DYNAPI_PROC(SDL_AssertState,SDL_ReportAssertion,(SDL_AssertData *a, const char *b, const char *c, int d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(void,SDL_ResetAssertionReport,(void),(),)
 SDL_DYNAPI_PROC(SDL_bool,SDL_ResetHint,(const char *a),(a),return)
@@ -781,8 +781,8 @@ SDL_DYNAPI_PROC(void,SDL_Vulkan_UnloadLibrary,(void),(),)
 SDL_DYNAPI_PROC(int,SDL_WaitEvent,(SDL_Event *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_WaitEventTimeout,(SDL_Event *a, Sint32 b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_WaitThread,(SDL_Thread *a, int *b),(a,b),)
-SDL_DYNAPI_PROC(int,SDL_WarpMouseGlobal,(int a, int b),(a,b),return)
-SDL_DYNAPI_PROC(void,SDL_WarpMouseInWindow,(SDL_Window *a, int b, int c),(a,b,c),)
+SDL_DYNAPI_PROC(int,SDL_WarpMouseGlobal,(float a, float b),(a,b),return)
+SDL_DYNAPI_PROC(void,SDL_WarpMouseInWindow,(SDL_Window *a, float b, float c),(a,b,c),)
 SDL_DYNAPI_PROC(Uint32,SDL_WasInit,(Uint32 a),(a),return)
 SDL_DYNAPI_PROC(size_t,SDL_WriteBE16,(SDL_RWops *a, Uint16 b),(a,b),return)
 SDL_DYNAPI_PROC(size_t,SDL_WriteBE32,(SDL_RWops *a, Uint32 b),(a,b),return)
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index 4ca6fd09b4df..7090168171b0 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -300,19 +300,19 @@ static void SDL_LogEvent(const SDL_Event *event)
         break;
 
         SDL_EVENT_CASE(SDL_MOUSEMOTION)
-        (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)",
+        (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u state=%u x=%g y=%g xrel=%g yrel=%g)",
                            (uint)event->motion.timestamp, (uint)event->motion.windowID,
                            (uint)event->motion.which, (uint)event->motion.state,
-                           (int)event->motion.x, (int)event->motion.y,
-                           (int)event->motion.xrel, (int)event->motion.yrel);
+                           event->motion.x, event->motion.y,
+                           event->motion.xrel, event->motion.yrel);
         break;
 
 #define PRINT_MBUTTON_EVENT(event)                                                                                              \
-    (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \
+    (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%g y=%g)", \
                        (uint)event->button.timestamp, (uint)event->button.windowID,                                             \
                        (uint)event->button.which, (uint)event->button.button,                                                   \
                        event->button.state == SDL_PRESSED ? "pressed" : "released",                                             \
-                       (uint)event->button.clicks, (int)event->button.x, (int)event->button.y)
+                       (uint)event->button.clicks, event->button.x, event->button.y)
         SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN)
         PRINT_MBUTTON_EVENT(event);
         break;
@@ -322,10 +322,9 @@ static void SDL_LogEvent(const SDL_Event *event)
 #undef PRINT_MBUTTON_EVENT
 
         SDL_EVENT_CASE(SDL_MOUSEWHEEL)
-        (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%d y=%d preciseX=%f preciseY=%f direction=%s)",
+        (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u windowid=%u which=%u x=%g y=%g direction=%s)",
                            (uint)event->wheel.timestamp, (uint)event->wheel.windowID,
-                           (uint)event->wheel.which, (int)event->wheel.x, (int)event->wheel.y,
-                           event->wheel.preciseX, event->wheel.preciseY,
+                           (uint)event->wheel.which, event->wheel.x, event->wheel.y,
                            event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
         break;
 
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index b6e47ce96301..247f577a51db 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -37,7 +37,7 @@ static SDL_Mouse SDL_mouse;
 /* for mapping mouse events to touch */
 static SDL_bool track_mouse_down = SDL_FALSE;
 
-static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y);
+static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y);
 
 static void SDLCALL SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
 {
@@ -305,15 +305,13 @@ void SDL_SetMouseFocus(SDL_Window *window)
 }
 
 /* Check to see if we need to synthesize focus events */
-static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, int x, int y, Uint32 buttonstate, SDL_bool send_mouse_motion)
+static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, float x, float y, Uint32 buttonstate, SDL_bool send_mouse_motion)
 {
     SDL_Mouse *mouse = SDL_GetMouse();
     SDL_bool inWindow = SDL_TRUE;
 
     if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
-        int w, h;
-        SDL_GetWindowSize(window, &w, &h);
-        if (x < 0 || y < 0 || x >= w || y >= h) {
+        if (x < 0.0f || y < 0.0f || x >= (float)window->w || y >= (float)window->h) {
             inWindow = SDL_FALSE;
         }
     }
@@ -343,7 +341,7 @@ static SDL_bool SDL_UpdateMouseFocus(SDL_Window *window, int x, int y, Uint32 bu
     return SDL_TRUE;
 }
 
-int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
+int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y)
 {
     if (window && !relative) {
         SDL_Mouse *mouse = SDL_GetMouse();
@@ -355,24 +353,7 @@ int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseI
     return SDL_PrivateSendMouseMotion(timestamp, window, mouseID, relative, x, y);
 }
 
-static int GetScaledMouseDelta(float scale, int value, float *accum)
-{
-    if (value && scale != 1.0f) {
-        if ((value > 0) != (*accum > 0)) {
-            *accum = 0.0f;
-        }
-        *accum += scale * value;
-        if (*accum >= 0.0f) {
-            value = (int)SDL_floor(*accum);
-        } else {
-            value = (int)SDL_ceil(*accum);
-        }
-        *accum -= value;
-    }
-    return value;
-}
-
-static float CalculateSystemScale(SDL_Mouse *mouse, const int *x, const int *y)
+static float CalculateSystemScale(SDL_Mouse *mouse, const float *x, const float *y)
 {
     int i;
     int n = mouse->num_system_scale_values;
@@ -384,7 +365,7 @@ static float CalculateSystemScale(SDL_Mouse *mouse, const int *x, const int *y)
         return v[0];
     }
 
-    speed = SDL_sqrtf((float)(*x * *x) + (*y * *y));
+    speed = SDL_sqrtf((*x * *x) + (*y * *y));
     for (i = 0; i < (n - 2); i += 2) {
         if (speed < v[i + 2]) {
             break;
@@ -398,7 +379,6 @@ static float CalculateSystemScale(SDL_Mouse *mouse, const int *x, const int *y)
         coef = (speed - v[i]) / (v[i + 2] - v[i]);
         scale = v[i + 1] + (coef * (v[i + 3] - v[i + 1]));
     }
-    SDL_Log("speed = %.2f, scale = %.2f\n", speed, scale);
     return scale;
 }
 
@@ -444,39 +424,39 @@ int SDL_SetMouseSystemScale(int num_values, const float *values)
     return 0;
 }
 
-static void GetScaledMouseDeltas(SDL_Mouse *mouse, int *x, int *y)
+static void GetScaledMouseDeltas(SDL_Mouse *mouse, float *x, float *y)
 {
     if (mouse->relative_mode) {
         if (mouse->enable_relative_speed_scale) {
-            *x = GetScaledMouseDelta(mouse->relative_speed_scale, *x, &mouse->scale_accum_x);
-            *y = GetScaledMouseDelta(mouse->relative_speed_scale, *y, &mouse->scale_accum_y);
+            *x *= mouse->relative_speed_scale;
+            *y *= mouse->relative_speed_scale;
         } else if (mouse->enable_relative_system_scale && mouse->num_system_scale_values > 0) {
             float relative_system_scale = CalculateSystemScale(mouse, x, y);
-            *x = GetScaledMouseDelta(relative_system_scale, *x, &mouse->scale_accum_x);
-            *y = GetScaledMouseDelta(relative_system_scale, *y, &mouse->scale_accum_y);
+            *x *= relative_system_scale;
+            *y *= relative_system_scale;
         }
     } else {
         if (mouse->enable_normal_speed_scale) {
-            *x = GetScaledMouseDelta(mouse->normal_speed_scale, *x, &mouse->scale_accum_x);
-            *y = GetScaledMouseDelta(mouse->normal_speed_scale, *y, &mouse->scale_accum_y);
+            *x *= mouse->normal_speed_scale;
+            *y *= mouse->normal_speed_scale;
         }
     }
 }
 
-static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
+static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, int relative, float x, float y)
 {
     SDL_Mouse *mouse = SDL_GetMouse();
     int posted;
-    int xrel = 0;
-    int yrel = 0;
+    float xrel = 0.0f;
+    float yrel = 0.0f;
 
     /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
     if (mouse->mouse_touch_events) {
         if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
             if (window) {
-                float fx = (float)x / (float)window->w;
-                float fy = (float)y / (float)window->h;
-                SDL_SendTouchMotion(timestamp, SDL_MOUSE_TOUCHID, 0, window, fx, fy, 1.0f);
+                float normalized_x = x / (float)window->w;
+                float normalized_y = y / (float)window->h;
+                SDL_SendTouchMotion(timestamp, SDL_MOUSE_TOUCHID, 0, window, normalized_x, normalized_y, 1.0f);
             }
         }
     }
@@ -489,11 +469,13 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
     }
 
     if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
-        int center_x = 0, center_y = 0;
-        SDL_GetWindowSize(window, &center_x, &center_y);
-        center_x /= 2;
-        center_y /= 2;
-        if (x == center_x && y == center_y) {
+        int w = 0, h = 0;
+        float center_x, cente

(Patch may be truncated, please check the link at the top of this post.)