Skip to content

🐞 Consume unmatched keys while Loop is open and the trigger is held#1116

Open
bit-saver wants to merge 1 commit into
mrkai77:developfrom
bit-saver:fix/consume-unmatched-keys
Open

🐞 Consume unmatched keys while Loop is open and the trigger is held#1116
bit-saver wants to merge 1 commit into
mrkai77:developfrom
bit-saver:fix/consume-unmatched-keys

Conversation

@bit-saver

Copy link
Copy Markdown
Contributor

Summary

While Loop is open and the trigger key is still held (mid-chord), a keyDown that doesn't match any bound action leaks to the focused app — e.g. holding the trigger and pressing an unbound "2" types "2222…" into the frontmost app.

Root cause

KeybindTrigger.performKeybind ends with return .forward for any event that didn't match an action. That's correct when Loop is closed, but while Loop is open and the trigger is held, unmatched keyDowns should be consumed (the user is mid-chord). No branch handles that case, so it falls through to .forward.

(Users currently work around this by binding the key to a "do nothing" action, which makes it "match" and thus consume.)

Fix

Consume unmatched keyDowns while Loop is open and the trigger is held. Gated on checkIfLoopOpen(), containsTrigger, and type == .keyDown, so: keys still forward when Loop is closed; key releases (keyUp) still forward; keys typed after releasing the trigger still forward; and the emoji/globe special-event passthrough (handled earlier) is unaffected.

Testing

Built (Release) and verified in real use: an unbound key pressed mid-chord is no longer typed into the focused app; normal typing (Loop closed) and other chords are unaffected.

Note / edge case

Returning .consume short-circuits the outer system-keybind passthrough, so a global shortcut pressed simultaneously with the held Loop trigger would be swallowed rather than forwarded + force-close Loop. This is rare (requires holding the Loop trigger during a system shortcut). If you'd prefer to preserve it, the consume can be gated behind a system-keybind-cache check — happy to adjust.

When Loop is open and the trigger key is still held (mid-chord), a keyDown that
doesn't match any bound action fell through to `.forward`, leaking the key to
the focused app (e.g. typing "2" repeatedly during a `trigger+2+arrow` chord
that isn't bound). Consume unmatched keyDowns while Loop is open and the
trigger is held; releases and post-trigger keys still forward.
@mrkai77

mrkai77 commented Jul 2, 2026

Copy link
Copy Markdown
Owner

I think this requires further discussion. Currently, it’s intended behavior that unmatched key combos pass through Loop. This is important for setups where a user might set Hyper as the trigger key, assign some shortcuts in Loop, and still use other Hyper-based shortcuts in other apps.

That said, I can see how this passthrough could become annoying for combos with more than one non-modifier key event. Maybe a small delay before passing the event through, to check whether another key is pressed, could make sense? Though that should definitely be handled outside the CGEventTap, since adding a delay there is asking for trouble.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants