Skip to content

Don't reload the UI when the keyboard layout changes - #14498

Closed
Mike Griese (zadjii-msft) wants to merge 6 commits into
mainfrom
dev/migrie/b/11522-dumb-idea
Closed

Mike Griese (zadjii-msft) wants to merge 6 commits into
mainfrom
dev/migrie/b/11522-dumb-idea

Conversation

@zadjii-msft

@zadjii-msft Mike Griese (zadjii-msft) commented Dec 6, 2022 •

Copy link
Copy Markdown
Member

Alrighty, this is a silly solution to the problem. Go read #11522.

What if, we just didn't reload the UI for a settings reload?

Terminal refreshes the appearance of panes, profiles, tabs, etc, in TerminalPage::_RefreshUIForSettingsReload. That's only called in TerminalPage::SetSettings, when we specify that we didn't need to reload the UI. Currently, we only don't reload the UI on an initial load of the settings (that makes sense, there's no UI to "reload" yet.)

So what if we did all of TerminalPage::SetSettings, but without the UI reload? We update the keybindings, the command palette, the current language, but not the actual content of the tabs.

before

11522-test-before

after

11522-test-after

Closes #11522?


A caveat from discussion:

This might have some weird irreproducible bugs in it. Consider

  1. Open two terminal windows
  2. Install a WSL distro
  3. Switch the KB layout

Both these windows will reload the settings, find that the new settings (& dynamic profile) are different, and will try to write the settings to the disk. One will win? Maybe? Both will probably end up with a full UI refresh, for determining that the settings file changed.

But is this fine anyways? We're pretty sure there's a backlog item for "reload the settings on a distro install" anyways. And the value add of this fix is probably worth more than the very rare new edge case where this still happens.

@ghost ghost added Area-Settings Issues related to settings and customizability, for console or terminal Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-3 A description (P3) Product-Terminal The new Windows Terminal. labels Dec 6, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, I don't mind this solution. If anything, I bet there's a few other scenarios we want to apply the exact same thing to.

Comment thread src/cascadia/TerminalApp/AppLogic.cpp Outdated
Comment on lines +1060 to +1061
// - Reloads the settings from the settings.json file.
void AppLogic::_ReloadSettings()
void AppLogic::_ReloadSettings(const bool keybindingsOnly)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nits...

  • update method description
  • I'd rename this needRefreshUI or something similar just to make it more general

@DHowett

Copy link
Copy Markdown
Member

You know, one of the things that weirds me out about this is that we don't need to reload the settings at all... just re-apply their effects.

Would it be possible to only reprocess the key bindings from the original model objects? That would address the bulk of the issue and make for a more targeted fix...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Per discussion, not sure this is the right solution -- we may benefit from iterating further!)

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 14, 2022
@zadjii-msft

Copy link
Copy Markdown
Member Author

Would it be possible to only reprocess the key bindings from the original model objects?

Leonard Hecker (@lhecker) might need to back me up on this - could we just call ActionMap::_RefreshKeyBindingCaches(), and have that reload the keybindings for the new kbd layout? I assumed that we couldn't do it trivially - I guess I assumed the layering effects would be lost by this point, and we'd need to re-parse the settings to get the right layering.

Now that I'm re-reading ActionMap::_PopulateKeyBindingMapWithStandardCommands, that seems like it'd work without a whole reparse

@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 14, 2022
@lhecker

Copy link
Copy Markdown
Member

_RefreshKeyBindingCaches() is not the most important thing that needs to be reloaded when the keyboard layout changes. The KeyChord instances need to be refreshed, as they translate scan-codes to vkeys via MapVirtualKeyW and those are then used for the Hash() they return. In other words, yeah this is 100% doable, but it needs a bit more work than just calling _RefreshKeyBindingCaches().

@zadjii-msft

Copy link
Copy Markdown
Member Author

Hmm. Updating the KeyChords seems... hard. The ctor will evaluate the SC->VK on construction, and store that the same as if we parsed the VK directly. So we can't just make a new _KeyMap map, take all the old KeyChords and just re-evaluate them.

Not sure what there is to do here. I can try to look if there's a way to build a fresh Settings object and just steal the actions map? Maybe that would work?

@zadjii-msft

Copy link
Copy Markdown
Member Author

I could theoretically make changes to AppLogic::ReloadSettings:

  • AppLogic::_TryLoadSettings returns out the new Settings rather than placing it in _settings.
  • then, it would:
    if (SUCCEEDED(_settingsLoadedResult) && keybindingsOnly) {
      _settings.CopyActionsFrom(newSettingsObject);
      _page->UpdateKeyboardSettings()
      return;
    }
    // the rest of the handling
    • CopyActionsFrom(other) does basically what it would sound like, just replace the globals.ActionsMap with the new one
    • UpdateKeyboardSettings would just _UpdateCommandsForPalette(); CommandPalette().SetActionMap(_settings.ActionMap()); to update any labels, etc.

Does that seem like it's sensible? How egregious of a layering violation does that feel like?

@DHowett

Copy link
Copy Markdown
Member

I think this is the problem:

The ctor will evaluate the SC->VK on construction

The thing consuming the settings model object here should be on the hook for this.

If we made that change, would it be easier to do "reevaluate all SC/VK" as a follow-on?

@DHowett

Copy link
Copy Markdown
Member

(Feel free to veto me)

@zadjii-msft Mike Griese (zadjii-msft) removed this from the Terminal v1.19 milestone Jul 16, 2024
@zadjii-msft

Copy link
Copy Markdown
Member Author

This is super stale. Like 1.5 years is too long, and there have been major rewrites since. We need to surely just start fresh

Oleksandr (Skydev0h) added a commit to Skydev0h/terminal that referenced this pull request Apr 11, 2026
Standalone investigation branch for microsoft#11522.
Not intended for upstream merge.

Instrumentation (AppLogic.cpp):
- Log every LanguageProfileNotifier OnActivated firing with process
  memory snapshots (priv/ws) via OutputDebugString and TraceLogging
  under the existing Microsoft.Windows.Terminal.App provider.
- Time the full SettingsChanged.raise() path, which synchronously runs
  TerminalPage::_RefreshUIForSettingsReload and is responsible for the
  multi-second UI freeze observed on layout switch.
- Add WT_GH11522_SKIP environment variable: when set to any value,
  suppresses the ReloadSettingsThrottled() call in the callback so A/B
  comparison against the default reload path is possible without
  rebuilding.

Reproducer (stress-tab.ps1):
- PowerShell script that fills a new tab with 10 000 lines of URL-ish
  scrollback content to exercise ControlCore::UpdatePatternLocations
  under the same til::ticket_lock that _RefreshUIForSettingsReload
  competes with during per-tab UpdateSettings propagation.
- Used with:
    1..40 | ForEach-Object {
        wtd -w 0 nt powershell -NoExit -File <path>\stress-tab.ps1
        Start-Sleep -Milliseconds 150
    }
  to produce ~1.1-1.5 GB private-bytes stressed state in under a minute
  instead of waiting days for natural accumulation.

Writeup (wt-keyboard-layout-lag-investigation.md):
- Full root-cause call-chain walkthrough
- Empirical measurements: ~3.5 s per reload at stressed state,
  +329/+633 MB private-bytes delta on first reload after state change,
  zero lag and stable memory with WT_GH11522_SKIP=1
- Additional finding on ThrottledFunc double-reload under rapid events
  (9 layout events -> 2 back-to-back reloads, 7.2 s total freeze)
- Connection between the lag and the 8.78 GB host-process memory bloat
- Upstream status and prior art (microsoft#14498, microsoft#19933)
- Three escalating tiers of what a proper fix could look like

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Settings Issues related to settings and customizability, for console or terminal Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-3 A description (P3) Product-Terminal The new Windows Terminal.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switching OS input method resets Terminal colors and zoom

4 participants