From a419debd293f53dcd19b2daba1eb064c7145533e Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sun, 11 Oct 2026 10:40:04 -0400
Subject: [PATCH] win: Prevent rapid focus switching when using DPI unaware
mode
Windows has a rounding bug when a DPI unaware context and fractional scale value are used that will cause the cursor coordinates to bounce in and out of the window while dragging along the edge when the clip rect is set to the window bounds. If the context is DPI unaware, and the display scale is fractional, move the sides of the clip rect in by 1 in each dimension to prevent rapid focus switching when the cursor is at the window edge.
---
src/video/windows/SDL_windowsevents.c | 1 +
src/video/windows/SDL_windowsvideo.c | 1 +
src/video/windows/SDL_windowsvideo.h | 1 +
src/video/windows/SDL_windowswindow.c | 36 +++++++++++++++++++++++++++
4 files changed, 39 insertions(+)
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 923b69fe2afe3..35312606b4c57 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1795,6 +1795,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_WINDOWPOSCHANGING:
+ SDL_Log("Changing");
if (data->expected_resize) {
returnCode = 0;
} else if (data->in_modal_loop) {
diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c
index 3b99f179c8e02..4824b76f69e51 100644
--- a/src/video/windows/SDL_windowsvideo.c
+++ b/src/video/windows/SDL_windowsvideo.c
@@ -471,6 +471,7 @@ static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this)
SDL_VideoData *data = _this->internal;
if (data->SetProcessDpiAwarenessContext) {
+ data->dpi_unaware_context_declared = true;
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
} else if (data->SetProcessDpiAwareness) {
// Windows 8.1
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index 928fcd054ba53..d8d0c91d5178d 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -582,6 +582,7 @@ struct SDL_VideoData
#endif
bool cleared;
+ bool dpi_unaware_context_declared;
bool detect_device_hotplug;
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 7d064ece501e1..a13a78c5f24f8 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -1540,6 +1540,7 @@ void WIN_UnclipCursorForWindow(SDL_Window *window) {
void WIN_UpdateClipCursor(SDL_Window *window)
{
SDL_WindowData *data = window->internal;
+ SDL_VideoData *videodata = data->videodata;
if (data->in_title_click || data->focus_click_pending || data->postpone_clipcursor) {
return;
}
@@ -1624,6 +1625,41 @@ void WIN_UpdateClipCursor(SDL_Window *window)
WIN_UnclipCursorForWindow(window);
return;
}
+ } else if (videodata->dpi_unaware_context_declared) {
+ /* Windows has a rounding bug when a DPI unaware context and fractional scale value
+ * are used that will cause the cursor coordinates to jitter across a confining edge
+ * while dragging along it, which can cause spurious pointer enter/leave events when the
+ * clip rect matches the window bounds. Move the sides of the clip rect in by 1 in each
+ * dimension to prevent rapid focus switching when the cursor is at the window edge.
+ *
+ * NOTE: Remove or bypass this if Microsoft ever fixes the issue.
+ */
+
+ // Temporarily set the thread to per-monitor awareness v2 to get the display DPI.
+ if (videodata->SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
+ HMONITOR hmon = MonitorFromWindow(data->hwnd, MONITOR_DEFAULTTONEAREST);
+ if (hmon) {
+ UINT hdpi_uint, vdpi_uint;
+ if (videodata->GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &hdpi_uint, &vdpi_uint) == S_OK) {
+ const float scale = (float)hdpi_uint / (float)USER_DEFAULT_SCREEN_DPI;
+ if (scale != SDL_floorf(scale)) {
+ if (target.left < target.right) {
+ target.left += 1;
+ }
+ if (target.right > target.left) {
+ target.right -= 1;
+ }
+ if (target.top < target.bottom) {
+ target.top += 1;
+ }
+ if (target.bottom > target.top) {
+ target.bottom -= 1;
+ }
+ }
+ }
+ }
+ videodata->SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
+ }
}
if (GetClipCursor(&client) &&