@@ -271,10 +271,18 @@ namespace KeyboardEventHandlers
271271 continue ;
272272 }
273273
274- if (data-> lParam -> vkCode == itShortcut. GetSecondKey () && itShortcut.IsChordStarted () && itShortcut.HasChord ())
274+ if (itShortcut.IsChordStarted () && itShortcut.HasChord ())
275275 {
276- Logger::trace (L" ChordKeyboardHandler:found chord match {}, {}" , itShortcut.GetActionKey (), itShortcut.GetSecondKey ());
277- isMatchOnChordEnd = true ;
276+ if (data->lParam ->vkCode == itShortcut.GetSecondKey ())
277+ {
278+ Logger::trace (L" ChordKeyboardHandler:found chord match {}, {}" , itShortcut.GetActionKey (), itShortcut.GetSecondKey ());
279+ isMatchOnChordEnd = true ;
280+ }
281+ // Resets chord status for the shortcut. A key was pressed and we registered if it was the end of the chord. We can reset it.
282+ if (data->lParam ->vkCode != itShortcut.GetActionKey ())
283+ {
284+ itShortcut.SetChordStarted (false );
285+ }
278286 }
279287
280288 if (resetChordsResults.AnyChordStarted && !isMatchOnChordEnd)
@@ -670,7 +678,7 @@ namespace KeyboardEventHandlers
670678 if (!remapToShortcut || (remapToShortcut && std::get<Shortcut>(it->second .targetShortcut ).CheckModifiersKeyboardState (ii)))
671679 {
672680 // Case 2: If the original shortcut is still held down the keyboard will get a key down message of the action key in the original shortcut and the new shortcut's modifiers will be held down (keys held down send repeated keydown messages)
673- if (data->lParam ->vkCode == it->first .GetActionKey () && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
681+ if ((( data->lParam ->vkCode == it->first .GetActionKey () && !it-> first . HasChord ())||(data-> lParam -> vkCode == it-> first . GetSecondKey () && it-> first . HasChord ()) ) && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
674682 {
675683 // In case of mapping to disable do not send anything
676684 if (remapToKey && std::get<DWORD>(it->second .targetShortcut ) == CommonSharedConstants::VK_DISABLED)
@@ -716,15 +724,46 @@ namespace KeyboardEventHandlers
716724 }
717725
718726 // Case 3: If the action key is released from the original shortcut, keep modifiers of the new shortcut until some other key event which doesn't apply to the original shortcut
719- if (!remapToText && data->lParam ->vkCode == it->first .GetActionKey () && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
727+ if (!remapToText && ((!it-> first . HasChord () && data->lParam ->vkCode == it->first .GetActionKey ()) || (it-> first . HasChord () && data-> lParam -> vkCode ==it-> first . GetSecondKey ()) ) && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
720728 {
721729 size_t key_count = 1 ;
722730 LPINPUT keyEventList = nullptr ;
723- if (remapToShortcut)
731+ if (remapToShortcut && !it-> first . HasChord () )
724732 {
733+ // Just lift the action key for no chords.
725734 keyEventList = new INPUT[key_count]{};
726735 Helpers::SetKeyEvent (keyEventList, 0 , INPUT_KEYBOARD, static_cast <WORD>(std::get<Shortcut>(it->second .targetShortcut ).GetActionKey ()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
727736 }
737+ else if (remapToShortcut && it->first .HasChord ())
738+ {
739+ // If it has a chord, we'll want a full clean contemplated in the else, since you can't really repeat chords by pressing the end key again.
740+
741+ // Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated
742+ key_count = (dest_size) + (src_size +1 ) - (2 * static_cast <size_t >(commonKeys));
743+ int i = 0 ;
744+
745+ keyEventList = new INPUT[key_count]{};
746+ Helpers::SetKeyEvent (keyEventList, i, INPUT_KEYBOARD, static_cast <WORD>(std::get<Shortcut>(it->second .targetShortcut ).GetActionKey ()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
747+ i++;
748+
749+ // Release new shortcut state (release in reverse order of shortcut to be accurate)
750+ Helpers::SetModifierKeyEvents (std::get<Shortcut>(it->second .targetShortcut ), it->second .winKeyInvoked , keyEventList, i, false , KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first );
751+
752+ // Set old shortcut key down state
753+ Helpers::SetModifierKeyEvents (it->first , it->second .winKeyInvoked , keyEventList, i, true , KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second .targetShortcut ));
754+
755+ // Reset the remap state
756+ it->second .isShortcutInvoked = false ;
757+ it->second .winKeyInvoked = ModifierKey::Disabled;
758+ it->second .isOriginalActionKeyPressed = false ;
759+
760+ // If app specific shortcut has finished invoking, reset the target application
761+ if (activatedApp)
762+ {
763+ state.SetActivatedApp (KeyboardManagerConstants::NoActivatedApp);
764+ }
765+
766+ }
728767 else if (std::get<DWORD>(it->second .targetShortcut ) == CommonSharedConstants::VK_DISABLED)
729768 {
730769 // If remapped to disable, do nothing and suppress the key event
@@ -822,7 +861,7 @@ namespace KeyboardEventHandlers
822861 Shortcut currentlyPressed = it->first ;
823862 currentlyPressed.actionKey = data->lParam ->vkCode ;
824863 auto newRemappingIter = reMap.find (currentlyPressed);
825- if (newRemappingIter != reMap.end ())
864+ if (newRemappingIter != reMap.end () && !newRemappingIter-> first . HasChord () )
826865 {
827866 auto & newRemapping = newRemappingIter->second ;
828867 Shortcut from = std::get<Shortcut>(it->second .targetShortcut );
0 commit comments