Skip to content

Only fire the longest matching sequence when combos overlap#72

Open
MichaelBuessemeyer wants to merge 1 commit into
RobertWHurst:masterfrom
scalableminds:execute-longest-sequences-only
Open

Only fire the longest matching sequence when combos overlap#72
MichaelBuessemeyer wants to merge 1 commit into
RobertWHurst:masterfrom
scalableminds:execute-longest-sequences-only

Conversation

@MichaelBuessemeyer
Copy link
Copy Markdown

@MichaelBuessemeyer MichaelBuessemeyer commented May 21, 2026

Hej! Thanks for the great library — Up until now, we've been using keyboardjs, but now we're migrating to Keystrokes in our project WEBKNOSSOS. Keystrokes is more feature-rich, but we still ran into a behavior issue we'd love to contribute a fix for.

The problem

When a multi-stroke combo and a single-key combo share the same final key, both handlers fire simultaneously. For example, if you have:

bindKeyCombo('ctrl > k, m', () => console.log('long sequence activated'))
bindKeyCombo('m', () => console.log('short sequence activated))
Pressing Ctrl+K then M triggers both handlers. From our point of view, in almost every real-world use case, if the user consciously pressed a prefix chord first, they clearly intend the longer sequence — the shorter one firing is more of an unintended side effect in our opinion.

The fix

After _updateKeyComboStates() resolves which combos are now pressed, we find the maximum sequence length among all currently-pressed combos and only call executePressed on those with the longest sequence. Shorter overlapping combos are silently skipped for that key event.

To make sure release events stay consistent, we track which combos were actually activated per key in a _keyCombosPressedByKey map, and only fire executeReleased on those same combos when the key is lifted.

Changes

  • KeyComboState: adds a sequenceLength getter (exposes _parsedKeyCombo.length) so Keystrokes can compare sequence lengths without reaching into private state
  • Keystrokes._handleKeyPress: filters pressed combos to only those with the maximum sequence length before calling executePressed
  • Keystrokes._handleKeyRelease: uses the new _keyCombosPressedByKey map to release only the combos that were actually activated

If only one combo matches (the common case), pressedCombos has a single entry, and everything flows exactly as before.

If you believe the behavior change introduced by this update should be optional, I’d be happy to adjust the PR accordingly. For example, it could become an option passable to Keystrokes instances.
Of course, other suggestions are welcome as well :)

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.

1 participant