mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -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,
|
||||
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_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN,
|
||||
WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE,
|
||||
WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN,
|
||||
WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS,
|
||||
WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH,
|
||||
WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WMSZ_BOTTOM,
|
||||
WM_INPUT, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP,
|
||||
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL,
|
||||
WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT,
|
||||
WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR,
|
||||
WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP,
|
||||
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_TOPRIGHT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW,
|
||||
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) });
|
||||
},
|
||||
|
||||
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
|
||||
WM_SYSCOMMAND => {
|
||||
if wparam == SC_RESTORE as usize {
|
||||
|
||||
Reference in New Issue
Block a user