PowerToys
PowerToys copied to clipboard
[KBM] Separate function for key press vs key hold (a la dual-key-remap)
I love the idea of managing key remaps via PowerToys, but there's no way (that I'm aware of) to remap a key to serve two purposed depending on whether it's pressed and released vs pressed in combination. https://github.com/ililim/dual-key-remap <- This tool is a great example. By default, it maps the CapsLock key to Escape when pressed without any other keys and Ctrl when pressed in combination with another key.
@NeodymiumPhish there would be a limitation in this feature though, that the Caps->Esc behavior would work only on "press and release", since when only Caps Lock is held down there would be no way of knowing if another key is going to be pressed or not. So for Caps->Esc it works, but Caps->Shift for example when pressed alone wouldnt make much sense sense it would simulate Shift being pressed and released so it can't really be used in combination with other keys. That said, for other scenarios this looks like a cool idea.
Totally understand the limitations issue. I meant that press and release would be one function and hold/combination presses would be another. What you're describing is how dual-key-remap works; it would be awesome if this were built into the much more user-friendly PowerToys!
I desire this feature. Is there anything I can do for getting it implemented? I'm happy to help specing or coding.
Because I haven't received any objection, let me share my proposal of the spec for the dual key remap feature.
Update [Remap keys] dialog
[Remap keys] dialog adds a combo box under the arrow symbol for each single key remap. It has three values, namely, "Always", "Alone", and "In Combination" (any suggestion for better names is welcome).

I have no plan to support dual remaps for shortcuts. I'm not interested in or aware of any scenario needing it.
Update [Keyboard Manager] Settings page
Each single key remap in [Keys] section adds a label indicating the remap condition. It uses the same style with the app name of a shortcut remap in [Shortcuts] section.

Process dual remap key events
"Always" keeps the current behavior as of today. "Alone" or "Combination" provides the dual key remap functionality where the remap is effective only when the key is pressed alone or in combination with other keys, respectively. When a key has dual-remaps, the remapped key press injection is delayed until the next key event to detect whether another key will be pressed during the key press.
Remaps on the same key can coexist if the condition differs. A table below shows how multiple remaps on A key will be resolved.
| Always | Alone | Combination | Key to inject on pressing A alone |
Key to inject on pressing A in combination |
Pressing A delay? |
|---|---|---|---|---|---|
| - | - | - | A | A | No |
| A -> B | - | - | B | B | No |
| - | A -> C | - | C | A | Yes |
| A -> B | A -> C | - | C | B | Yes |
| - | - | A -> D | A | D | Yes |
| A -> B | - | A -> D | B | D | Yes |
| - | A -> C | A -> D | C | D | Yes |
| A -> B | A -> C | A -> D | C | D | Yes |
Save dual remaps in Keyboard Manager default.json
~~Add two named "alone" and "combination" in "remapKeys" object of Keyboard Manager default.json to save dual remaps in the same format with the current "inProcess" remap array.~~
Add "condition" value for each entry in "inProcess" array of Keyboard Manager default.json to save the remap condition. 0, 1, and 2 means "Always", "Alone", and "Combination" remap condition, respectively. For the backward compatibility, the value is optional and its default value is 0 ("Always").
{
"remapKeys": {
"inProcess": [
{
"originalKeys": "161",
"newRemapKeys": "18"
},
{
"originalKeys": "164",
"newRemapKeys": "29",
"condition": 1
},
{
"originalKeys": "32",
"newRemapKeys": "160",
"condition": 2
}
],
},
// ...
}
https://github.com/microsoft/PowerToys/compare/main...masaru-iritani:patch-1 is my ongoing work. I'm thinking of publishing a draft pull request if I get the green-light (or no objection for a while).
@masaru-iritani You could create a draft PR from the branch 😄
Would you like me to tag this as In progress and assign this to you?
@franky920920
Would you like me to tag this as
In progressand assign this to you?
Yes, please!
@masaru-iritani How's progress going? :)
@masaru-iritani How's progress going? :)
Not good :(
I didn't have enough time to understand the keyboard shortcut handling and find an appropriate design to allow tentative remap errors for both single keys and shortcuts. I'll keep updating the pull request when I make any progress.
Any progress on this? I would like to setup home row mods for my windows laptop and think this would be the solution.
That being said, in the meantime, does anyone have a recommendation for setting up home row mods on a Windows laptop keyword (I can with my external keyboard through its keyboard layout software but have not figured out how to on a regular laptop keyboard). Thanks!
Let me unassign me for now. I'm still hoping to make this happen by myself, but I'm not sure how long it will take to incorporate latest changes in the main branch into my current draft.
I've resumed efforts to implement this feature and, based on my experiences from the previous pull request, plan to divide the work into multiple smaller refactoring pull requests. This approach should help minimize the code difference and enable easier integration with the latest code base.
My plan is:
- Replace
std::make_pairwith aRemapBufferRowinitializer list to prepare for the step 2 (the pull request above). - Convert
RemapBufferRowfromstd::pairto a struct to add a field for the remap condition. - Change
LPINPUT(key event array) tostd::vectorto support the variable number of key events on the fly. - (any other refactoring for reducing the amount of changes at the final step)
- Implement the dual key map.
Fingers crossed 🤞
Very much looking forward to this! Curious if any recent progress / updates? Thanks a bunch @masaru-iritani for your hard work on this!
The review on #32545 is pending. I'd like to know if there is anything I (or anyone else) can do for accelerating the review process.