Created
September 1, 2025 23:05
-
-
Save trodemaster/448f6096e423b97969839420cda72bb0 to your computer and use it in GitHub Desktop.
Patch to fix command key function on input-leap 3.0.3 for macOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/lib/inputleap/KeyMap.cpp b/src/lib/inputleap/KeyMap.cpp | |
| index 4dd10917..994972b2 100644 | |
| --- a/src/lib/inputleap/KeyMap.cpp | |
| +++ b/src/lib/inputleap/KeyMap.cpp | |
| @@ -652,6 +652,8 @@ const KeyMap::KeyItem* KeyMap::mapCharacterKey(Keystrokes& keys, KeyID id, std:: | |
| keys.push_back(Keystroke(group, true, true)); | |
| } | |
| + // Prefer Super over Meta to avoid bouncing modifiers during Command combos | |
| + newState = (newState | KeyModifierSuper) & ~KeyModifierMeta; | |
| // save new modifiers | |
| activeModifiers = newModifiers; | |
| currentState = newState; | |
| @@ -987,7 +989,23 @@ KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, | |
| break; | |
| case kKeystrokeModify: | |
| - case kKeystrokeUnmodify: | |
| + case kKeystrokeUnmodify: { | |
| + // Normalize Meta→Super for Command on macOS to prevent mid-combo flips | |
| + KeyModifierMask modifierMask = keyItem.m_generates; | |
| + if ((modifierMask & KeyModifierMeta) != 0) { | |
| + modifierMask = (modifierMask & ~KeyModifierMeta) | KeyModifierSuper; | |
| + } | |
| + | |
| + // Skip redundant Command (Meta/Super) toggle on the same physical button | |
| + if ((modifierMask & (KeyModifierSuper | KeyModifierMeta)) != 0) { | |
| + for (const auto& it : activeModifiers) { | |
| + if ((it.first & (KeyModifierSuper | KeyModifierMeta)) != 0 && | |
| + it.second.m_button == keyItem.m_button) { | |
| + return; | |
| + } | |
| + } | |
| + } | |
| + | |
| if (keyItem.m_lock) { | |
| // we assume there's just one button for this modifier | |
| if (m_halfDuplex.count(button) > 0) { | |
| @@ -1013,7 +1031,7 @@ KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, | |
| else { | |
| // release all the keys that generate the modifier that are | |
| // currently down | |
| - auto range = activeModifiers.equal_range(keyItem.m_generates); | |
| + auto range = activeModifiers.equal_range(modifierMask); | |
| for (auto i = range.first; i != range.second; ++i) { | |
| keystrokes.push_back(Keystroke(i->second.m_button, | |
| false, false, i->second.m_client)); | |
| @@ -1021,15 +1039,15 @@ KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, | |
| } | |
| if (type == kKeystrokeModify) { | |
| - activeModifiers.insert(std::make_pair( | |
| - keyItem.m_generates, keyItem)); | |
| - currentState |= keyItem.m_generates; | |
| + activeModifiers.insert(std::make_pair(modifierMask, keyItem)); | |
| + currentState |= modifierMask; | |
| } | |
| else { | |
| - activeModifiers.erase(keyItem.m_generates); | |
| - currentState &= ~keyItem.m_generates; | |
| + activeModifiers.erase(modifierMask); | |
| + currentState &= ~modifierMask; | |
| } | |
| break; | |
| + } | |
| default: | |
| break; | |
| } | |
| diff --git a/src/lib/platform/OSXKeyState.cpp b/src/lib/platform/OSXKeyState.cpp | |
| index 89e57e2b..cf9986db 100644 | |
| --- a/src/lib/platform/OSXKeyState.cpp | |
| +++ b/src/lib/platform/OSXKeyState.cpp | |
| @@ -498,6 +498,8 @@ static io_connect_t getEventDriver(void) | |
| void OSXKeyState::postHIDVirtualKey(const std::uint8_t virtualKeyCode, const bool postDown) | |
| { | |
| static std::uint32_t modifiers = 0; | |
| + static bool leftCommandPressed = false; | |
| + static bool rightCommandPressed = false; | |
| NXEventData event; | |
| IOGPoint loc = { 0, 0 }; | |
| @@ -527,12 +529,18 @@ void OSXKeyState::postHIDVirtualKey(const std::uint8_t virtualKeyCode, const boo | |
| m_shiftPressed = postDown; | |
| break; | |
| case kVK_Command: | |
| - modifiersDelta = NX_COMMANDMASK | NX_DEVICELCMDKEYMASK; | |
| - m_superPressed = postDown; | |
| + // Track left Command separately and update only the device bit here. | |
| + // The global NX_COMMANDMASK is computed from both sides below. | |
| + modifiersDelta = NX_DEVICELCMDKEYMASK; | |
| + leftCommandPressed = postDown; | |
| + m_superPressed = leftCommandPressed || rightCommandPressed; | |
| break; | |
| case kVK_RightCommand: | |
| - modifiersDelta = NX_COMMANDMASK | NX_DEVICERCMDKEYMASK; | |
| - m_superPressed = postDown; | |
| + // Track right Command separately and update only the device bit here. | |
| + // The global NX_COMMANDMASK is computed from both sides below. | |
| + modifiersDelta = NX_DEVICERCMDKEYMASK; | |
| + rightCommandPressed = postDown; | |
| + m_superPressed = leftCommandPressed || rightCommandPressed; | |
| break; | |
| case kVK_Option: | |
| modifiersDelta = NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK; | |
| @@ -556,7 +564,7 @@ void OSXKeyState::postHIDVirtualKey(const std::uint8_t virtualKeyCode, const boo | |
| break; | |
| } | |
| - // update the modifier bit | |
| + // update the modifier bit(s) for this specific key's device mask | |
| if (postDown) { | |
| modifiers |= modifiersDelta; | |
| } | |
| @@ -564,6 +572,14 @@ void OSXKeyState::postHIDVirtualKey(const std::uint8_t virtualKeyCode, const boo | |
| modifiers &= ~modifiersDelta; | |
| } | |
| + // Ensure global Command reflects combined left/right state. | |
| + if (leftCommandPressed || rightCommandPressed) { | |
| + modifiers |= NX_COMMANDMASK; | |
| + } | |
| + else { | |
| + modifiers &= ~NX_COMMANDMASK; | |
| + } | |
| + | |
| kern_return_t kr; | |
| event.key.keyCode = virtualKeyCode; | |
| kr = IOHIDPostEvent(getEventDriver(), NX_FLAGSCHANGED, loc, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment