## Summary of the Pull Request
Adds an optional **"alone" condition** to single-key remaps in Keyboard
Manager, bringing
Karabiner-style `to_if_alone` (dual-key / tap-vs-hold) behavior: a key
can perform one action
when **tapped by itself** while still acting as its normal self **when
combined** with other
keys — via the keyboard **or the mouse**.
Example use case: **Right Ctrl → IME On when tapped alone**, **Left Ctrl
→ IME Off when tapped alone**,
while **Right/Left Ctrl + other keys / clicks / wheel** keep working as
normal Ctrl. This is the
Windows equivalent of the popular macOS "left/right ⌘ → 英数/かな" mapping.
## Demo
Muted screen recording with on-screen captions (the physical keys I
press aren't visible; a red ring marks the tray IME indicator あ / A so
the On/Off switching is easy to follow):
https://github.com/user-attachments/assets/0da27a7d-3ae9-4718-94c9-5e79f054ca58
What it shows:
1. Tap **Right Ctrl** alone → IME On (Japanese); tap **Left Ctrl** alone
→ IME Off (English) — directional and idempotent (repeated taps keep the
same state).
2. The same keys still act as **normal modifiers in combination**: Right
Ctrl + H/J/K/L → arrow keys (Vim-style), and Ctrl+A / Ctrl+C / Ctrl+V
behave normally.
3. **Mouse combinations preserved**: a plain click follows a link, while
**Ctrl+Click** opens it in a new tab (via the companion low-level mouse
hook).
4. In Keyboard Manager the whole config is just two "Alone" single-key
remaps plus the Ctrl+H/J/K/L arrows, and the edit dialog shows the new
**Condition → "Alone (tap)"**.
## PR Checklist
- [ ] Closes: #40647
- [ ] Related: #5679 (broader dual-key / `to_if_alone` tracking issue;
#40647 was closed as a duplicate of it)
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places — *N/A: no new
binaries/projects are introduced (existing engine, editor UI and test
projects only).*
- [ ] **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
**Engine (C++):**
- New separate remap table `aloneSingleKeyReMap` (parallel to
`singleKeyReMap`) with
`Add/Clear/GetSingleKeyAloneRemap` (`MappingConfiguration`).
- New handler `HandleSingleKeyAloneRemapEvent` using a **lazy +
release-fire** strategy:
suppress the alone key's key-down; on the first *other* key it flushes
the original key-down
(promoting to a normal combination); on solo release it fires the alone
action. Wired into the
hook dispatch **before** the normal single-key handler; per-key runtime
state lives in `State`.
- **Mouse combinations:** a companion low-level mouse hook
(`WH_MOUSE_LL`) is installed alongside
the keyboard hook **only while alone remaps exist** (reconciled on
settings reload). On a
button-down or wheel event — but **not** mouse-move, which must not
cancel a tap — it promotes
the held alone key(s) to a real modifier via the shared
`PromotePendingAloneKeysToCombination`,
so **Ctrl+Click / Ctrl+Wheel** work while an alone-mapped Ctrl is held.
The mouse event itself is
never suppressed; `State::HasPendingAloneKeys` gives the hook a cheap
early-out.
- Settings JSON: an optional `"condition"` field per single-key remap
(`"always"` default, or
`"alone"`). Fully backward compatible; both **load** and **save** handle
it, so hand-edited or
UI-created alone remaps round-trip without loss.
**Editor UI (WinUI3):**
- Native wrapper exposes parallel alone add/get/delete over the alone
table (reuses the existing
`SingleKeyMapping` marshaling struct).
- `SingleKeyRemapCondition` (Always / Alone) flows through the C#
interop/service/model layers.
- A localized **"Condition"** combo box in the add/edit dialog, shown
**only for a single-key
remap whose action is a key/shortcut** (the case the engine supports),
plus a localized
**"Alone" badge** on such rows in the list.
- **Modifier-conflict validation fix:** two *distinct* modifier sides
(e.g. Left Ctrl and Right
Ctrl) are no longer flagged as a "conflicting modifier". The check now
only fires when one side
is the generic, side-agnostic modifier (Ctrl/Shift/Alt/Win) versus a
specific side — which is
exactly the left/right pairing this feature targets.
- **Duplicate-entry fix:** the editor's own settings store now rejects
exact-duplicate remaps
(guarding the add path the way the engine tables already do,
condition-aware so "always" vs
"alone" stay distinct) and **self-heals** pre-existing duplicates on
load, so a remap can no
longer appear twice in the list after mixed GUI / hand-edited-config
changes.
**Known limitations / follow-ups (intentionally not in this PR):**
- Hold-timeout not implemented (holding the alone key then releasing
still fires the alone action;
needs an injectable clock — deferred, noted in code).
- Alone *target* supports a single key or a shortcut (not text/URL/app).
## Validation Steps Performed
- Engine unit tests: **110/110** (alone tests + edge cases, incl. 2 new
mouse-promotion cases).
Editor C++ tests: **88/88**.
- Editor UI project compiles clean (0 warnings / 0 errors).
- **Manual E2E on real hardware** (self-built x64 Release, multiple
machines):
- Right Ctrl tapped alone → IME On; Left Ctrl tapped alone → IME Off
(directional, idempotent).
- Ctrl+C / V / Z / A and existing Ctrl-based custom shortcuts unaffected
(keyboard modifier
pass-through OK).
- **Ctrl+Click and Ctrl+Wheel** work while an alone-mapped Ctrl is held
(mouse-combo pass-through).
- Left Ctrl and Right Ctrl can both be mapped at once with no false
"conflicting modifier" error.
- Editor UI: opening an existing alone remap shows Condition = "Alone
(tap)"; saving round-trips a
full real-world config (single-key + dozens of global and app-specific
shortcuts) with **zero
loss** and **no duplicate rows**; the "Alone" badge and the show/hide
gating of the Condition
combo both behave correctly.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes#37100
This does not migrate the rest of the solutions (why do we have so
many?)
Not migrated:
- TemplateCmdPalExtension.sln
- FancyZonesEditor.sln
- BugReportTool.sln
- CleanUp_tool.sln
- FancyZones_DrawLayoutTest.sln
- FancyZones_zonable_tester.sln
- FancyZone_HitTest.sln
- MonitorReportTool.sln
- PowerToyTemplate.sln
- StylesReportTool.sln
---------
Co-authored-by: vanzue <vanzue@outlook.com>
This upgrades to [v0.0.24](https://github.com/check-spelling/check-spelling/releases/tag/v0.0.24).
A number of GitHub APIs are being turned off shortly, so you need to upgrade or various uncertain outcomes will occur.
There's a new accessibility forbidden pattern:
> Do not use `(click) here` links
> For more information, see:
> * https://www.w3.org/QA/Tips/noClickHere
> * https://webaim.org/techniques/hypertext/link_text
> * https://granicus.com/blog/why-click-here-links-are-bad/
> * https://heyoka.medium.com/dont-use-click-here-f32f445d1021
```pl
(?i)(?:>|\[)(?:(?:click |)here|link|(?:read |)more)(?:</|\]\()
```
There are some minor bugs that I'm aware of and which I've fixed since this release, but I don't expect to make another release this month.
I've added a pair of patterns for includes and pragmas. My argument is that the **compiler** will _generally_ tell you if you've misspelled an include and the **linker** will _generally_ tell you if you misspell a lib.
- There's a caveat here: If your include case-insensitively matches the referenced file (but doesn't properly match it), then unless you either use a case-sensitive file system (as opposed to case-preserving) or beg clang to warn, you won't notice when you make this specific mistake -- this matters in that a couple of Windows headers (e.g. Unknwn.h) have particular case and repositories don't tend to consistently/properly write them.
* Fix dark title bar for shortcuts window
* Adjust editor sizes
* Fetch accent button style from resources instead
* Modernize the editor UI
Reimplemented the XAML bridge to support Mica
* Use fluent icons
* Modernize the preview key visuals
* Implement teaching tips for key drop-down messages
* Fix spelling
* Fix delete button alignment in keys editor
* Remove trace log from bridge message handler
* Add WinUI depends to installer script
* Hide icon and caption from editor title bar
* Update remap entries to look like cards
* Use built-in content dialog buttons
* Update add button
* Fix spelling
* Fix installer script for ARM64
* Fix spelling AGAIN
* Update dev documentation
* Prevent white flash on dark mode
* Revert 3-key layout but make window wider
* f: align webview versions
* f: add pipeline exceptions for Microsoft DLLs that are not versioned
* f: add vcruntime140_1_app.dll to the exception list
* f: update webview versions
This commit replaces all references to PowerToys' master branch
with "main" in documentation, code and build rules.
- [x] **Linked issue:** #5433
- [x] **Communication:** I've discussed this with core contributors in
the issue.
- [ ] **Tests:** Added/updated and all pass (not applicable)
- [ ] **Installer:** Added/updated and all pass (not applicable)
- [ ] **Localization:** All end user facing strings can be localized
(not applicable)
- [x] **Docs:** Updated
- [x] **Binaries:** Any new files are added to WXS / YML
- [x] No new binaries
* Create kbm md file
* Documented KBM main module (without links)
* Completed docs for backend except links
* Added docs for UI and created doc file for KBM Common
* Added docs for KBM common and for tests
* Add table of contents for all files
* Started updating links
* Added some more links
* Updated links
* testing link
* Resolve all links on keyboardmanager.md
* Added links in KBM Common
* Added comments for keyboardeventhandlers
* Added links for KBM-UI
* Added mention of shortcut to key
* Add section link for settings update code.
* Include more information on updating remap tables