Skip to content

[KBM] New editor: honor the PowerToys language setting - #51147

Open
Niels Laute (niels9001) wants to merge 1 commit into
mainfrom
niels9001/kbm-editor-language
Open

Niels Laute (niels9001) wants to merge 1 commit into
mainfrom
niels9001/kbm-editor-language

Conversation

@niels9001

@niels9001 Niels Laute (niels9001) commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary of the Pull Request

The new Keyboard Manager editor (WinUI 3) ignored the PowerToys language setting and always used the OS region language. It now applies LanguageHelper.LoadLanguage() as ApplicationLanguages.PrimaryLanguageOverride at startup, the same way other WinUI 3 modules do (e.g. File Locksmith).

PR Checklist

  • Communication: I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
  • Tests: Added/updated and all pass
  • Localization: All end-user-facing strings can be localized
  • Dev docs: Added/updated
  • New binaries: Added on the required places
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

The override is set at the top of the App() constructor, before any resources load. Only KeyboardManagerEditorXAML/App.xaml.cs changes.

Part of the new-vs-classic KBM editor parity work. Other draft PRs from the same work: #51148 (engine suspend), #51149 (orphaned-key warning), and #51150 (empty key slot + recording fixes).

Validation Steps Performed

  • tools\build\build.cmd in src\modules\keyboardmanager\KeyboardManagerEditorUI (arm64 Debug): passed, exit code 0.
  • Manually tested: set PowerToys to a language other than the OS region language and confirm the editor UI follows it:
Image

Apply LanguageHelper.LoadLanguage() as PrimaryLanguageOverride at startup, matching other WinUI 3 modules, so the editor no longer follows the OS region language.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused change follows the established WinUI 3 localization pattern without unresolved issues.

0 open findings

What changed in this PR

Applies the configured PowerToys language to the new Keyboard Manager editor at startup.

Changes:

  • Loads the shared PowerToys language setting.
  • Sets the WinUI 3 primary language override before resource initialization.
File Description
src/​modules/​keyboardmanager/​KeyboardManagerEditorUI/​KeyboardManagerEditorXAML/​App.xaml.cs Initializes the editor with the configured PowerToys language.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@niels9001
Niels Laute (niels9001) marked this pull request as ready for review October 9, 2026 14:34
Yu Leng (moooyo) pushed a commit that referenced this pull request Oct 14, 2026
…e editor (#51150)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR fixes two related input gaps in the new WinUI 3 Keyboard Manager
editor compared with the classic editor.

1. **Keys that can't be recorded have no fallback.** When a mapping
starts empty, the trigger and action showed only the "press keys"
recording area. Keys you can't press (media keys, or keys missing from
your keyboard) or that the hook can't capture could not be chosen. The
classic editor always showed a dropdown. An empty mapping now shows a
caption hint ("Press to start recording keys or") followed by a "Select
key" `KeyDropDownButton`, so any key can be picked from the list. The
dropdown's flyout has a search box at the top that filters the key list.
Picking a modifier adds another empty dropdown, so a full shortcut can
be built with the mouse.
2. **Recording leaked and trapped focus.** The low-level recording hook
stayed active even when the editor wasn't in the foreground, so
keystrokes typed in other apps got recorded. While recording, the editor
also swallowed Tab, so keyboard users couldn't leave the field. Now:
   - The hook only records when the editor is in the foreground.
- Tab (or Shift+Tab) with no other keys held stops recording and moves
focus forward (or backward). Keys you already recorded are kept; the
previous keys come back only if nothing was recorded.
   - The recording toggle unchecks when recording stops.

<img width="880" height="724" alt="Image"
src="https://github.com/user-attachments/assets/aa266b16-43d8-4ab5-a582-e5dc8a18c590"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #50852
- [x] Closes: #50360
- [x] Closes: #49158
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

- **`KeyDropDownButton`**:
- Shows a localized "Select key" placeholder
(`KeyDropDownButton_SelectKeyPlaceholder`) when `KeyName` is empty.
- The flyout now has an `AutoSuggestBox` ("Search keys") above the
`ListView`. It gets focus when the flyout opens and filters by display
name, ignoring case. Enter picks the first match, and "No keys found"
shows when nothing matches. The search text resets each time the flyout
opens.
- **`UnifiedMappingControl`**:
- New `TriggerEmptyKeyPickerPanel` and `ActionEmptyKeyPickerPanel`
appear when the trigger or action has no keys. Each shows a
`CaptionTextBlockStyle` hint ("Press to start recording keys or") and an
empty `KeyDropDownButton`.
- Picking a key from the dropdown fills the first slot
(`TrySetFirstDropDownKey`).
- Before recording starts, the previous keys are saved. If recording
ends with nothing captured, they are restored.
- Key getters ignore empty placeholder entries, so an empty slot is
never saved as a key.
- **`KeyboardHookHelper`**:
- The hook's "is active" predicate is now `IsEditorForeground`: the
foreground window's process must be the editor's own process.
- `ShouldHandleKeyboardEvent` treats Tab or Shift+Tab with no other keys
held as "exit recording". It restores the previous keys only if nothing
was captured (or only the Shift held for Shift+Tab). For Shift+Tab it
swallows the Tab, because the hook already swallowed Shift and the
window would see a plain Tab, and the control moves focus backward with
`FocusManager.TryMoveFocus` scoped to the dialog.
- Cleanup is deferred to the `DispatcherQueue` because the native
`KeyboardHook::HookProc` is still running the callback, and disposing
the hook from inside it is unsafe.
- `CleanupHook` tells the target through the new
`IKeyboardHookTarget.OnRecordingStopped(bool)`, so the toggle unchecks
and keys are restored when needed.

**Trade-offs:**
- A lone Tab can no longer be recorded. You can still pick it from the
dropdown, which this PR makes always available.

Part of the new-vs-classic KBM editor parity work. Other draft PRs from
the same work: #51147 (language), #51148 (engine suspend) and #51149
(orphaned-key warning).

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- `tools\build\build.cmd` in
`src\modules\keyboardmanager\KeyboardManagerEditorUI` (arm64 Debug):
passed, exit code 0.
- No new unit tests: the changes are in UI and hook plumbing, which the
existing unit test project doesn't cover.
- Manually tested on an arm64 Debug dev runner: new mappings show the
caption hint and "Select key" for both trigger and action. The search
box gets focus when the flyout opens, and typing "k" filters the list.
Typing in the search box doesn't start key recording.
- Other manual checks:
- Add a new mapping and confirm the empty trigger and action show
"Select key". Pick a media key (e.g. Play/Pause) from the dropdown and
save.
- Start recording, switch to another app and type there. Confirm nothing
is recorded in the editor.
- Start recording and press Tab. Confirm recording stops, the toggle
unchecks and focus moves on. Record a key, release it, then press Tab:
the recorded key stays. Press Shift+Tab: focus moves backward.
- Start recording and stop without pressing a key. Confirm the previous
keys come back.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4c7f42fd-7fad-43c2-9281-e581ddfd45eb
Boliang Zhang (LegendaryBlair) pushed a commit that referenced this pull request Oct 15, 2026
…e editor (#51150)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR fixes two related input gaps in the new WinUI 3 Keyboard Manager
editor compared with the classic editor.

1. **Keys that can't be recorded have no fallback.** When a mapping
starts empty, the trigger and action showed only the "press keys"
recording area. Keys you can't press (media keys, or keys missing from
your keyboard) or that the hook can't capture could not be chosen. The
classic editor always showed a dropdown. An empty mapping now shows a
caption hint ("Press to start recording keys or") followed by a "Select
key" `KeyDropDownButton`, so any key can be picked from the list. The
dropdown's flyout has a search box at the top that filters the key list.
Picking a modifier adds another empty dropdown, so a full shortcut can
be built with the mouse.
2. **Recording leaked and trapped focus.** The low-level recording hook
stayed active even when the editor wasn't in the foreground, so
keystrokes typed in other apps got recorded. While recording, the editor
also swallowed Tab, so keyboard users couldn't leave the field. Now:
   - The hook only records when the editor is in the foreground.
- Tab (or Shift+Tab) with no other keys held stops recording and moves
focus forward (or backward). Keys you already recorded are kept; the
previous keys come back only if nothing was recorded.
   - The recording toggle unchecks when recording stops.

<img width="880" height="724" alt="Image"
src="https://github.com/user-attachments/assets/aa266b16-43d8-4ab5-a582-e5dc8a18c590"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #50852
- [x] Closes: #50360
- [x] Closes: #49158
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

- **`KeyDropDownButton`**:
- Shows a localized "Select key" placeholder
(`KeyDropDownButton_SelectKeyPlaceholder`) when `KeyName` is empty.
- The flyout now has an `AutoSuggestBox` ("Search keys") above the
`ListView`. It gets focus when the flyout opens and filters by display
name, ignoring case. Enter picks the first match, and "No keys found"
shows when nothing matches. The search text resets each time the flyout
opens.
- **`UnifiedMappingControl`**:
- New `TriggerEmptyKeyPickerPanel` and `ActionEmptyKeyPickerPanel`
appear when the trigger or action has no keys. Each shows a
`CaptionTextBlockStyle` hint ("Press to start recording keys or") and an
empty `KeyDropDownButton`.
- Picking a key from the dropdown fills the first slot
(`TrySetFirstDropDownKey`).
- Before recording starts, the previous keys are saved. If recording
ends with nothing captured, they are restored.
- Key getters ignore empty placeholder entries, so an empty slot is
never saved as a key.
- **`KeyboardHookHelper`**:
- The hook's "is active" predicate is now `IsEditorForeground`: the
foreground window's process must be the editor's own process.
- `ShouldHandleKeyboardEvent` treats Tab or Shift+Tab with no other keys
held as "exit recording". It restores the previous keys only if nothing
was captured (or only the Shift held for Shift+Tab). For Shift+Tab it
swallows the Tab, because the hook already swallowed Shift and the
window would see a plain Tab, and the control moves focus backward with
`FocusManager.TryMoveFocus` scoped to the dialog.
- Cleanup is deferred to the `DispatcherQueue` because the native
`KeyboardHook::HookProc` is still running the callback, and disposing
the hook from inside it is unsafe.
- `CleanupHook` tells the target through the new
`IKeyboardHookTarget.OnRecordingStopped(bool)`, so the toggle unchecks
and keys are restored when needed.

**Trade-offs:**
- A lone Tab can no longer be recorded. You can still pick it from the
dropdown, which this PR makes always available.

Part of the new-vs-classic KBM editor parity work. Other draft PRs from
the same work: #51147 (language), #51148 (engine suspend) and #51149
(orphaned-key warning).

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- `tools\build\build.cmd` in
`src\modules\keyboardmanager\KeyboardManagerEditorUI` (arm64 Debug):
passed, exit code 0.
- No new unit tests: the changes are in UI and hook plumbing, which the
existing unit test project doesn't cover.
- Manually tested on an arm64 Debug dev runner: new mappings show the
caption hint and "Select key" for both trigger and action. The search
box gets focus when the flyout opens, and typing "k" filters the list.
Typing in the search box doesn't start key recording.
- Other manual checks:
- Add a new mapping and confirm the empty trigger and action show
"Select key". Pick a media key (e.g. Play/Pause) from the dropdown and
save.
- Start recording, switch to another app and type there. Confirm nothing
is recorded in the editor.
- Start recording and press Tab. Confirm recording stops, the toggle
unchecks and focus moves on. Record a key, release it, then press Tab:
the recorded key stays. Press Shift+Tab: focus moves backward.
- Start recording and stop without pressing a key. Confirm the previous
keys come back.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4c7f42fd-7fad-43c2-9281-e581ddfd45eb
(cherry picked from commit 9501b98)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Keyboard Manager] KM Editor Language stuck in Italian While PowerToys is in English.

3 participants