[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:
gokcekantarci 2024-08-21 17:29:13 +03:00 committed by GitHub
parent 9f491c8f73
commit a163bbedc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -247,6 +247,14 @@ namespace KeyboardEventHandlers
bool isMatchOnChordEnd = false; bool isMatchOnChordEnd = false;
bool isMatchOnChordStart = 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 the shortcut has been pressed down
if (!it->second.isShortcutInvoked && it->first.CheckModifiersKeyboardState(ii)) 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 // 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 // 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 // Get the common keys between the two shortcuts
int commonKeys = (remapToShortcut && !isRunProgram) ? it->first.GetCommonModifiersCount(std::get<Shortcut>(it->second.targetShortcut)) : 0; 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); 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 if (!isAltRightKeyInvoked)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), 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);
}
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 // 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); 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); 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 // Ensures that after releasing both the action key and AltGr, Ctrl does not remain falsely pressed.
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), 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, 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 // 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); Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
@ -672,16 +702,22 @@ namespace KeyboardEventHandlers
// Release new key state // 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); 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 if (!isAltRightKeyInvoked)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, 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);
}
// 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 // 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); Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Reset the remap state if (!isAltRightKeyInvoked)
it->second.isShortcutInvoked = false; {
it->second.winKeyInvoked = ModifierKey::Disabled; // Reset the remap state
it->second.isOriginalActionKeyPressed = false; 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 app specific shortcut has finished invoking, reset the target application
if (activatedApp != KeyboardManagerConstants::NoActivatedApp) if (activatedApp != KeyboardManagerConstants::NoActivatedApp)
@ -741,7 +777,10 @@ namespace KeyboardEventHandlers
if (newRemapping.RemapToKey()) if (newRemapping.RemapToKey())
{ {
DWORD to = std::get<0>(newRemapping.targetShortcut); 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 (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
{ {
// If the action key from the last shortcut is still being pressed, release it. // If the action key from the last shortcut is still being pressed, release it.
@ -752,13 +791,19 @@ namespace KeyboardEventHandlers
else else
{ {
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut); 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 (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
{ {
// If the action key from the last shortcut is still being pressed, release it. // 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::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); Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(to.actionKey), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
newRemapping.isShortcutInvoked = true; 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::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 // 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)); 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 // key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
if (isActionKeyPressed) 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 // 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 if (!isAltRightKeyInvoked)
it->second.isShortcutInvoked = false; {
it->second.winKeyInvoked = ModifierKey::Disabled; // Reset the remap state
it->second.isOriginalActionKeyPressed = false; 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 app specific shortcut has finished invoking, reset the target application
if (activatedApp) if (activatedApp)
@ -848,8 +899,11 @@ namespace KeyboardEventHandlers
{ {
std::vector<INPUT> keyEventList; std::vector<INPUT> keyEventList;
// Set original shortcut key down state if (!isAltRightKeyInvoked)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); {
// 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 // 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) 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 // 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 if (!isAltRightKeyInvoked)
it->second.isShortcutInvoked = false; {
it->second.winKeyInvoked = ModifierKey::Disabled; // Reset the remap state
it->second.isOriginalActionKeyPressed = false; 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 app specific shortcut has finished invoking, reset the target application
if (activatedApp != KeyboardManagerConstants::NoActivatedApp) if (activatedApp != KeyboardManagerConstants::NoActivatedApp)