mirror of
https://github.com/microsoft/PowerToys
synced 2024-11-21 15:53:19 +00:00
[KBM] Fixed Ctrl key state handling during and after shortcuts invoked by AltGr (#31923)
* [KBM] Fixed Ctrl key state handling during and after shortcuts invoked by AltGr
* [KBM] Release ctrl in Alt gr condition is added to remap shortcut.
* [KBM] Ctrl(Left) stuck fix.
* Revert "[KBM] Ctrl(Left) stuck fix."
This reverts commit 2774e1cf7f
.
* [KBM] Fixed Ctrl key state handling during and after shortcuts invoked by AltGr
* [KBM] Left ctrl stuck bug is solved.
* [KBM] Remove unnecessary changes.
* [KBM] New Ctrl stuck case fix.
---------
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
This commit is contained in:
parent
9f491c8f73
commit
a163bbedc1
@ -247,6 +247,14 @@ namespace KeyboardEventHandlers
|
||||
bool isMatchOnChordEnd = false;
|
||||
bool isMatchOnChordStart = false;
|
||||
|
||||
static bool isAltRightKeyInvoked = false;
|
||||
|
||||
// Check if the right Alt key (AltGr) is pressed.
|
||||
if (data->lParam->vkCode == VK_RMENU && ii.GetVirtualKeyState(VK_LCONTROL))
|
||||
{
|
||||
isAltRightKeyInvoked = true;
|
||||
}
|
||||
|
||||
// If the shortcut has been pressed down
|
||||
if (!it->second.isShortcutInvoked && it->first.CheckModifiersKeyboardState(ii))
|
||||
{
|
||||
@ -522,6 +530,13 @@ namespace KeyboardEventHandlers
|
||||
// 5. The user presses any key apart from the action key or a modifier key in the original shortcut - revert the keyboard state to just the original modifiers being held down along with the current key press
|
||||
// 6. The user releases any key apart from original modifier or original action key - This can't happen since the key down would have to happen first, which is handled above
|
||||
|
||||
// Prevents the unintended release of the Ctrl part when AltGr is pressed. AltGr acts as both Ctrl and Alt being pressed.
|
||||
// After triggering a shortcut involving AltGr, the system might attempt to release the Ctrl part. This code ensures Ctrl remains pressed, maintaining the AltGr state correctly.
|
||||
if (isAltRightKeyInvoked && data->lParam->vkCode == VK_LCONTROL && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the common keys between the two shortcuts
|
||||
int commonKeys = (remapToShortcut && !isRunProgram) ? it->first.GetCommonModifiersCount(std::get<Shortcut>(it->second.targetShortcut)) : 0;
|
||||
|
||||
@ -543,8 +558,15 @@ namespace KeyboardEventHandlers
|
||||
|
||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first, data->lParam->vkCode);
|
||||
|
||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
isAltRightKeyInvoked = false;
|
||||
}
|
||||
|
||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->Ctrl+V, press Win+Ctrl+A and release A then Ctrl, since Win will be pressed here we need to send a dummy event after it
|
||||
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
@ -559,8 +581,16 @@ namespace KeyboardEventHandlers
|
||||
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
|
||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
|
||||
// Ensures that after releasing both the action key and AltGr, Ctrl does not remain falsely pressed.
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate it's own key message
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
isAltRightKeyInvoked = false;
|
||||
}
|
||||
|
||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+Ctrl+A->V, press Win+Ctrl+A and release A then Ctrl, since Win will be pressed here we need to send a dummy event after it
|
||||
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
@ -672,16 +702,22 @@ namespace KeyboardEventHandlers
|
||||
// Release new key state
|
||||
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
||||
// Set original shortcut key down state except the action key
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Set original shortcut key down state except the action key
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
|
||||
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Shift+Win+A and release A, since Win will be pressed here we need to send a dummy event after it
|
||||
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
}
|
||||
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
|
||||
@ -741,7 +777,10 @@ namespace KeyboardEventHandlers
|
||||
if (newRemapping.RemapToKey())
|
||||
{
|
||||
DWORD to = std::get<0>(newRemapping.targetShortcut);
|
||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
||||
{
|
||||
// If the action key from the last shortcut is still being pressed, release it.
|
||||
@ -752,13 +791,19 @@ namespace KeyboardEventHandlers
|
||||
else
|
||||
{
|
||||
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
|
||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
|
||||
}
|
||||
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
|
||||
{
|
||||
// If the action key from the last shortcut is still being pressed, release it.
|
||||
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(from.actionKey), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
|
||||
}
|
||||
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(to.actionKey), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
newRemapping.isShortcutInvoked = true;
|
||||
}
|
||||
@ -783,10 +828,13 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
|
||||
|
||||
// Set old shortcut key down state
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||
// Set old shortcut key down state
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
|
||||
}
|
||||
|
||||
// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
|
||||
if (isActionKeyPressed)
|
||||
@ -800,10 +848,13 @@ namespace KeyboardEventHandlers
|
||||
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after shortcut to shortcut is released to open start menu
|
||||
}
|
||||
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
}
|
||||
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp)
|
||||
@ -848,8 +899,11 @@ namespace KeyboardEventHandlers
|
||||
{
|
||||
std::vector<INPUT> keyEventList;
|
||||
|
||||
// Set original shortcut key down state
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Set original shortcut key down state
|
||||
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
|
||||
}
|
||||
|
||||
// Send the original action key only if it is physically pressed. For remappings to keys other than disabled we already check earlier that it is not pressed in this scenario. For remap to disable
|
||||
if (isRemapToDisable && isOriginalActionKeyPressed)
|
||||
@ -863,10 +917,13 @@ namespace KeyboardEventHandlers
|
||||
|
||||
// Do not send a dummy key as we want the current key press to behave as normal i.e. it can do press+release functionality if required. Required to allow a shortcut to Win key remap invoked directly after another shortcut to key remap is released to open start menu
|
||||
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
if (!isAltRightKeyInvoked)
|
||||
{
|
||||
// Reset the remap state
|
||||
it->second.isShortcutInvoked = false;
|
||||
it->second.winKeyInvoked = ModifierKey::Disabled;
|
||||
it->second.isOriginalActionKeyPressed = false;
|
||||
}
|
||||
|
||||
// If app specific shortcut has finished invoking, reset the target application
|
||||
if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
|
||||
|
Loading…
Reference in New Issue
Block a user