windows: fix freeze on keyboard layout switch (Punto Switcher)#4582
Open
chilango74 wants to merge 1 commit into
Open
windows: fix freeze on keyboard layout switch (Punto Switcher)#4582chilango74 wants to merge 1 commit into
chilango74 wants to merge 1 commit into
Conversation
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a freeze that affects any winit application on Windows when the keyboard
layout is switched by tools such as Punto Switcher (a popular auto layout
switcher). The window stops responding until the process is killed.
This was originally found and fixed in Warp's winit fork
(warpdotdev/winit#15); this PR
ports the same change to upstream.
Root cause (from a minidump of the frozen process)
A full dump was taken with procdump on the frozen window (original, unpatched
code) and analyzed with
minidump-stackwalkusing symbols generated from thelocal system DLLs (so x64 unwind/CFI is exact).
Reliable top of the main thread:
MsgWaitForMultipleObjectsEx— winit'sevent-loop wait (
wait_for_messages_impl) — re-entered during messagedispatch.
pshook64.dll(Punto Switcher's global hook) is injected into the processand present on the stack (
CallNextHookEx), i.e. it runs on our thread duringdispatch.
LAYOUT_CACHE/WaitOnAddressframes anywhere.So this is a re-entrant Win32 message-loop wait mediated by the layout
switcher's hook, not a Rust mutex self-deadlock.
Fix
Handle
WM_INPUTLANGCHANGEto refresh the cached keyboard layout, then defer toDefWindowProc(kept, per theWin32 docs,
so the message still propagates to first-level child windows).
Testing (Windows 11 + Punto Switcher)
Built the winit test app for
x86_64-pc-windows-gnuand exercised real PuntoSwitcher layout switches (English ↔ Russian, confirmed by alphabet changes in
the key log). Isolation variants:
WM_INPUTLANGCHANGEhandlerupdate_modifiers+Value(1)(swallow)DefWindowProc(this PR)DefWindowProc, noupdate_modifiersSo the layout-cache refresh is the minimal change that stops the freeze;
swallowing the message and
update_modifiersare not needed.Known limitation: the operative change was isolated empirically, and we have
proven what it is not (a mutex deadlock), but the precise reason a cache
refresh prevents the re-entrant wait is not fully traced — Punto Switcher's hook
is closed-source, and the dump shows no layout-loading frames at the freeze
point.
changelogmodule