mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
windows: fix freeze on keyboard layout switch
Any winit app on Windows freezes when the keyboard layout is switched by tools such as Punto Switcher. A minidump of the frozen process shows the main thread blocked in MsgWaitForMultipleObjectsEx (winit's event-loop wait), re-entered during message dispatch through the switcher's injected global hook (pshook64.dll, via CallNextHookEx) — a re-entrant Win32 message-loop wait, not a mutex deadlock (no LAYOUT_CACHE frames present). Handle WM_INPUTLANGCHANGE to refresh the cached keyboard layout, then defer to DefWindowProc so the message still propagates to first-level child windows as the Win32 docs require. The cache refresh is the minimal change that stops the freeze (verified on Windows 11 by isolation variants); update_modifiers and swallowing the message are not needed.
This commit is contained in:
@@ -51,12 +51,12 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||||||
SystemParametersInfoW, TranslateMessage, WHEEL_DELTA, WINDOWPOS, WM_CAPTURECHANGED, WM_CLOSE,
|
SystemParametersInfoW, TranslateMessage, WHEEL_DELTA, WINDOWPOS, WM_CAPTURECHANGED, WM_CLOSE,
|
||||||
WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO,
|
WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO,
|
||||||
WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION,
|
WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION,
|
||||||
WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN,
|
WM_INPUT, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP,
|
||||||
WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE,
|
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL,
|
||||||
WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN,
|
WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT,
|
||||||
WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS,
|
WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR,
|
||||||
WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH,
|
WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP,
|
||||||
WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WMSZ_BOTTOM,
|
WM_TOUCH, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WMSZ_BOTTOM,
|
||||||
WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
|
WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
|
||||||
WMSZ_TOPRIGHT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW,
|
WMSZ_TOPRIGHT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW,
|
||||||
WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
||||||
@@ -1508,6 +1508,21 @@ unsafe fn public_window_callback_inner(
|
|||||||
result = ProcResult::Value(unsafe { DefWindowProcW(window, msg, wparam, lparam) });
|
result = ProcResult::Value(unsafe { DefWindowProcW(window, msg, wparam, lparam) });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
WM_INPUTLANGCHANGE => {
|
||||||
|
// Refresh the cached keyboard layout for the newly activated input
|
||||||
|
// language. This message is sent (by Windows or by layout switchers
|
||||||
|
// such as Punto Switcher) after the layout changes. Refreshing the
|
||||||
|
// cache here prevents a freeze that otherwise occurs when switching
|
||||||
|
// layout via such tools. We still defer to `DefWindowProc` so the
|
||||||
|
// message keeps propagating to first-level child windows, as the
|
||||||
|
// Win32 documentation requires.
|
||||||
|
{
|
||||||
|
let mut layouts = LAYOUT_CACHE.lock().unwrap();
|
||||||
|
layouts.get_current_layout();
|
||||||
|
}
|
||||||
|
result = ProcResult::DefWindowProc(wparam);
|
||||||
|
},
|
||||||
|
|
||||||
// this is necessary for us to maintain minimize/restore state
|
// this is necessary for us to maintain minimize/restore state
|
||||||
WM_SYSCOMMAND => {
|
WM_SYSCOMMAND => {
|
||||||
if wparam == SC_RESTORE as usize {
|
if wparam == SC_RESTORE as usize {
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ changelog entry.
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- On Windows, fix a freeze that occurs when the keyboard layout is switched by
|
||||||
|
tools such as Punto Switcher. The `WM_INPUTLANGCHANGE` message is now handled
|
||||||
|
to refresh the cached keyboard layout, while still deferring to
|
||||||
|
`DefWindowProc` for normal propagation.
|
||||||
- On Redox, handle `EINTR` when reading from `event_socket` instead of panicking.
|
- On Redox, handle `EINTR` when reading from `event_socket` instead of panicking.
|
||||||
- On Wayland, switch from using the `ahash` hashing algorithm to `foldhash`.
|
- On Wayland, switch from using the `ahash` hashing algorithm to `foldhash`.
|
||||||
- On macOS, fix borderless game presentation options not sticking after switching spaces.
|
- On macOS, fix borderless game presentation options not sticking after switching spaces.
|
||||||
|
|||||||
Reference in New Issue
Block a user