Skip to content

fix(windows): release cursor clip on focus loss - #4654

Open
Saratii wants to merge 1 commit into
rust-windowing:masterfrom
Saratii:fix/win32-release-cursor-clip-on-focus-loss
Open

fix(windows): release cursor clip on focus loss#4654
Saratii wants to merge 1 commit into
rust-windowing:masterfrom
Saratii:fix/win32-release-cursor-clip-on-focus-loss

Conversation

@Saratii

@Saratii Saratii commented Aug 1, 2026

Copy link
Copy Markdown

Problem

ClipCursor is global OS state that Windows does not reset when a window loses focus. A clip rect applied while the window was focused therefore stays active after focus loss, keeping the cursor trapped in the unfocused window. Applications cannot release it either: Window::set_cursor_grab(CursorGrabMode::None) has no effect while unfocused, because refresh_os_cursor skips all ClipCursor updates when the window is not focused.

Reported downstream in bevyengine/bevy#22750 (confine on focus gain, None on focus loss — the cursor stays trapped after pressing the Windows key).

Fix

  • refresh_os_cursor: when the window is unfocused, release the active clip if it lies within the window's client area — i.e. it is the clip this window applied (Confined = client rect, Locked = 1px rect inside it). A clip set by the now-active application elsewhere is left untouched, which is why the focused-only gate existed in the first place.
  • WM_KILLFOCUS / WM_SETFOCUS: refresh cursor flags so the clip is released on focus loss and reapplied on focus gain even if the application never changes the grab mode, matching grab behavior on other platforms.

Note: during WM_KILLFOCUS, GetActiveWindow() may in some message orderings still return the window; in that case the release happens on the next cursor-flag refresh (e.g. the application's own set_cursor_grab call or a cursor move) instead of immediately.

Verified with the bevy reproduction from the linked issue on Windows 11: the cursor now frees on focus loss and re-confines on focus gain. A backport to v0.30.x is available at https://github.com/Saratii/winit/tree/fix/win32-release-cursor-clip-on-focus-loss-v0.30.

🤖 Generated with Claude Code

ClipCursor is global OS state that Windows does not reset when a window
loses focus. A clip rect applied while the window was focused therefore
stayed active after focus loss, keeping the cursor trapped in the
unfocused window. Worse, set_cursor_grab(CursorGrabMode::None) could not
release it either, because refresh_os_cursor skips all ClipCursor
updates when the window is not focused.

Fix by releasing the active clip in refresh_os_cursor when the window is
unfocused and the clip lies within the window client area (i.e. it is
the clip this window applied, not one belonging to the now-active
application), and by refreshing cursor flags on WM_KILLFOCUS/WM_SETFOCUS
so the clip is released on focus loss and reapplied on focus gain even
if the application does not change the grab mode itself.

Fixes the Windows half of bevyengine/bevy#22750.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant