lab / gesture-parser · notation defined in chord-fn-row
Type on the pad; it parses your real key edges into the CLX gesture notation, live.
The proposed chord needs three non-modifier keys down at once (capslock, space, a digit), and five with Ctrl+Shift. Membrane keyboards often ghost past three. Hold them all and watch the counter.
ctrl+shift+capslock+space+5Hold all five at once. If “max simultaneous” reaches 5 and every key shows in the pad, your keyboard has the rollover this design needs.
| t (ms) | edge | key | event.code | held after |
|---|---|---|---|---|
| no events yet | ||||
A pattern closes after 3 s of no key activity, so consecutive gestures accumulate into one line until you pause. Holding a key keeps the pattern open — the countdown only starts once everything is back up.
Three passes, no timers anywhere — the structure comes from edge order alone, which is the same thing the engine has to reason about.
| Pass | What it does |
|---|---|
| 1. tree | Each key-down opens a node inside the currently-innermost open node; each key-up closes it. Containment falls out of the edge order, so a key pressed while another is held becomes its child. |
| 2. collapse | A node holding exactly one child collapses into a group when their two up-edges are adjacent in the log — nothing happened between them. That is precisely the rule that ] needs the whole group released; a partial release leaves the nesting intact instead. A child that has a body is demonstrably a hold — something was struck while it was down — so holding a and b and striking e gives (a->b)[ e ] for any keys at all, with no key table and no clock. Only the childless case is ambiguous: c↓ s↓ s↑ c↑ and space↓ 3↓ 3↑ space↑ are the same shape, so there the key roles break the tie. |
| 2b. connect | Group members are joined with +. Whether your fingers happen to nest or cross on release is not something anyone controls, so that difference is noise in captured input — the same intended gesture would otherwise render two ways. Nothing is lost, because the trace line still records the exact edges: observation lives in the trace, the binding lives in the spec. Flip the connector button to -> to see the order as actually pressed; crossings still show + there, since a crossing is real evidence of symmetry. |
| 3. render | Empty body and closed → X. · empty and still held → X[ · non-empty → X[ body ], or X[ body while the hold is still open. Body keys print bare, because inside a hold a bare name already means a tap. |
Strict nesting turns pass 2 off, so you can see the raw press order the engine sees — useful for reproducing T1, where capslock[ alt[ space[ 1 ] ] ] fails to form a chord because prior_key is alt when Space arrives.
preventDefault catches most but not all.held_keys.