Skip to Content

Scanning

The scanner state machine and how it handles late reactions.

The scanner is in src/renderer/board/scanner.ts. It is a pure state machine: the app owns the clock and calls tick() and select().

States

rows ──select──▶ cols ──select──▶ key returned, back to rows at the top
  ▲               │
  └── ↩, or two unselected passes ──┘

Late reactions

People react after they see a change. If a select arrives within 350 ms of the highlight moving, the user was almost certainly reacting to the previous item, so the scanner picks that one. This matters more for a gesture than for a key press, because the gesture itself takes time to detect.

highlight350 ms grace windoweyebrow raise (select)0 s1 s2 s3 s4 s5 srow: phrasesrow: ␣ E T A O ⌫row: I N S H R Dkey: ␣key: Ekey: T+200 ms, in the window: previous rowtimer restarted: a full 1 s+400 ms, past the window: T is typed
Typing T at the default 1 s step. The first raise lands 200 ms after the highlight moved, so the scanner takes the previous row. The second lands after the window has closed, so it takes the key still highlighted.

The timer

The app schedules each step with a timer, restarted on every select, so you always get a full step after a gesture. It does not advance while the SDK's validation is failing.

On this page