Conversation
Add LayoutCache::refresh_current_layout, which unconditionally recomputes the current layout instead of trusting an existing cache entry keyed by HKL. Handle WM_INPUTLANGCHANGE in the window procedure to call it, since Windows can reuse an HKL value after a layout is unloaded and a different one is loaded in its place, which would otherwise leave LayoutCache::get_current_layout serving stale key mappings. DefWindowProc is still invoked afterwards per the WM_INPUTLANGCHANGE docs, so the message still propagates to first-level child windows.
Comment on lines
+241
to
+253
| name: Minimize JavaScript | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: taiki-e/checkout-action@v1 | ||
| - name: Install SWC | ||
| run: sudo npm i -g @swc/cli | ||
| - name: Run SWC | ||
| run: | | ||
| swc src/platform_impl/web/web_sys/worker.js -o src/platform_impl/web/web_sys/worker.min.js | ||
| - name: Check for diff | ||
| run: | | ||
| [[ -z $(git status -s) ]] |
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
Investigating warpdotdev/warp#8675 ("Punto Switcher freezes Warp") and its linked chain (#7073, #8857, #9967, #10050), I found that the previously-linked "fix" (this repo's PR #15, referencing rust-windowing#4584 and an alleged upstream merge rust-windowing#4582) is not trustworthy evidence:
rust-windowing/winit's real commit history forsrc/platform_impl/windows/keyboard.rsshows the Windows backend was moved out to a separatewinit-win32crate on 2025-05-25, before the dates on the alleged windows: fix freeze on keyboard layout switch (Punto Switcher) rust-windowing/winit#4582 fix/merge. That PR does not exist in winit's real history.{ let mut layouts = LAYOUT_CACHE.lock().unwrap(); layouts.get_current_layout(); }) is a no-op:get_current_layoutreturns an already-cached entry unchanged viaEntry::Occupied, so it can't "refresh" anything.What I can confirm is a real, narrower gap:
LayoutCacheis keyed byHKL, and nothing ever explicitly refreshes an entry once cached --get_current_layoutintentionally trustsEntry::Occupied. Since Windows can reuse anHKLvalue after a layout is unloaded and a different one loaded in its place, a stale entry could theoretically serve the wrong key mappings after a layout switch. This PR addsLayoutCache::refresh_current_layout, which unconditionally recomputes and replaces the cache entry (unlike the no-op proposed previously), and wires it up to theWM_INPUTLANGCHANGEmessage, still deferring toDefWindowProcper the Win32 docs so the message keeps propagating to child windows.Testing
cargo test --lib(addedrefresh_current_layout_replaces_a_stale_entry, which plants a cache entry that could not have come fromprepare_layoutand assertsrefresh_current_layoutreplaces it, whileget_current_layoutwould not).Real-world dynamic verification (not just a caveat)
This sandbox has no interactive desktop by default (my shell runs in the non-interactive Session 0), so I could not simply run a GUI app and switch layouts by hand. Instead I got a genuine interactive Win32 session by launching the test binaries via a Task Scheduler task with the
/IT(interactive) flag targeting the already-logged-on console session (Session 1), which gives real access toLoadKeyboardLayoutW/ActivateKeyboardLayout(these silently no-op in Session 0).I built a harness (
winit_repro) against both this pinned commit's parent (14db95a, pre-fix) and this branch (4a8fe6b, post-fix) that:WH_GETMESSAGEhook on the winit event-loop thread, standing in for Punto Switcher's injected hook (a real global hook needs DLL injection, which is out of scope here, but a thread-local hook exercises the same "fires synchronously nested inside the thread's ownPeekMessage/GetMessage" mechanism the linked (fabricated) analysis describes).LoadKeyboardLayoutW/ActivateKeyboardLayout(alternating Russian/US English,00000419/00000409), then posts a retype keydown/up -- mirroring Punto Switcher's autocorrect flow (erase, switch layout, retype).IsHungAppWindowplus a processed-event counter, so a genuine "Not Responding" freeze is detected without any human interaction.Ran both builds for 25s each in that real session:
14db95a): 49 real, successful layout switches (LoadKeyboardLayoutW/ActivateKeyboardLayoutboth succeeded every time,switch_failures=0), interleaved with real keystroke dispatch (318KeyboardInputevents processed).IsHungAppWindowwas0for the entire run; no freeze.4a8fe6b, this branch): same setup, 48 real layout switches, 312 events processed,IsHungAppWindowstayed0throughout; no freeze.Honest conclusion: this is real, non-caveated verification that (a) the fix compiles and behaves correctly under load, and (b) neither the pre-fix nor post-fix code hangs under genuine, repeated OS-level keyboard-layout switching via the specific mechanism (hook-nested
WM_INPUTLANGCHANGE) the previously-linked analysis described. I could not get a hang to reproduce in either version this way, which is itself useful signal that this specific mechanism isn't the cause of the reported freeze -- so I can't claim this PR fixes #8675's exact "Not Responding" symptom. What's verified is narrower and real: theLayoutCachestaleness gap this PR closes, confirmed both by a targeted unit test and by this dynamic run showing no regressions or new hangs under real layout-switch load.