mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-09 12:00:14 +02:00
[KBM] Fix modifier key remapped to non-modifier delivering WM_SYSKEYDOWN (#47192)
## Summary of the Pull Request When a modifier key (Ctrl/Alt/Shift) is remapped to a non-modifier key using Keyboard Manager, the injected key event is delivered to applications as WM_SYSKEYDOWN instead of WM_KEYDOWN. This causes unexpected behavior — for example, remapping Left Alt to Backspace results in whole words being deleted instead of single characters, because applications interpret WM_SYSKEYDOWN + VK_BACK as Alt+Backspace. The fix resets the modifier state with a suppress-flag key-up event before injecting the target key, consistent with the existing approach used for the Caps Lock remapping scenario. ## PR Checklist - [ ] Closes: #47191 - [ ] 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 - [ ] Localization: All end-user-facing strings can be localized - [ ] Dev docs: Added/updated - [ ] New binaries: Added on the required places ## Detailed Description of the Pull Request / Additional comments The root cause is that SendInput is called inside the low-level keyboard hook callback before the original modifier event is suppressed. At that point the modifier state is still active, so the OS delivers the injected key as WM_SYSKEYDOWN (system key with Alt context) rather than WM_KEYDOWN. This is the same mechanism that was already fixed for the Ctrl/Alt/Shift ↔ Caps Lock case. This PR extends the fix to cover modifier → non-modifier remaps. ## Validation Steps Performed 1. Remapped Left Alt → Backspace in Keyboard Manager 2. Opened a text editor, typed text, pressed the remapped key 3. Confirmed single characters are deleted instead of whole words 4. All 93 unit tests pass (KeyboardManager.Engine.UnitTests)
This commit is contained in:
@@ -139,6 +139,14 @@ namespace KeyboardEventHandlers
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, it->first, target);
|
||||
|
||||
// If a Ctrl/Alt/Shift key is remapped to a non-modifier key, reset the modifier state to prevent the injected key from being delivered as WM_SYSKEYDOWN instead of WM_KEYDOWN
|
||||
if (Helpers::IsModifierKey(it->first) && !Helpers::IsModifierKey(target) && target != VK_CAPITAL && !(it->first == VK_LWIN || it->first == VK_RWIN || it->first == CommonSharedConstants::VK_WIN_BOTH))
|
||||
{
|
||||
std::vector<INPUT> suppressList;
|
||||
Helpers::SetKeyEvent(suppressList, INPUT_KEYBOARD, static_cast<WORD>(it->first), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);
|
||||
ii.SendVirtualInput(suppressList);
|
||||
}
|
||||
}
|
||||
|
||||
if (remapToKey)
|
||||
|
||||
Reference in New Issue
Block a user