Skip to content

feat: Config.inferKeyRepeat for devices that never set KeyboardEvent.repeat - #80

Merged
chiefcll merged 1 commit into
mainfrom
feat/infer-key-repeat
Oct 23, 2026
Merged

chiefcll merged 1 commit into
mainfrom
feat/infer-key-repeat

Conversation

@chiefcll

Copy link
Copy Markdown
Contributor

Problem

Some devices never set KeyboardEvent.repeat. Holding a key sends a stream of repeat=false key-downs and a single key-up on release:

keydown Enter 13 repeat=false   (×N while held)
keyup   Enter 13 repeat=false   (once)

Two things break:

  • useHold treats each key-down as a new press, so the hold timer keeps restarting. onHold never fires, and the release resolves as a tap.
  • The focus manager lifts a hold's suppression latch on any fresh key-down. So even a hold that fired would have the following key-downs reach whatever onHold focused.

An app-level workaround (rewrite repeated key-downs as repeat: true until key-up) disables the key permanently if a key-up is ever missed.

Change

New opt-in Config.inferKeyRepeat (ms, off by default). When it's set, the focus manager marks a key-down as a repeat when the same key sent a key-down less than that long ago with no key-up in between. It overwrites repeat on the event so useHold, the suppression latch and app handlers all read the same value.

  • The window runs from the previous key-down, so it only needs to cover the device's initial auto-repeat delay. A missed key-up stops mattering once the window passes.
  • Held keys are matched by name or keyCode, like suppressions. A key-up that renames the key (webOS Back → Unidentified) still ends the press.
  • useHold is unchanged.

Off by default because on a key that never sends key-up (webOS OK), a second tap inside the window would be read as a repeat. Enable it per device.

Tests

8 new cases in tests/keySuppression.test.tsx, including an end-to-end useHold hold on the device's key pattern. That test fails with inference off (onHold never called). Full suite, lint and tsc pass.

Not yet verified on the physical device.

🤖 Generated with Claude Code

…repeat

Some devices send a stream of repeat=false key-downs while a key is held,
and a single key-up on release. useHold saw each as a new press, so a hold
never fired, and the hold latch was lifted by what looked like a fresh press.

With Config.inferKeyRepeat set (ms), the focus manager marks a key-down as a
repeat when the same key sent a key-down within the window with no key-up in
between. The window runs from the previous key-down, so a missed key-up
cannot wedge a key. Off by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chiefcll
chiefcll merged commit cd9fd94 into main Oct 23, 2026
1 check passed
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