apps/web/event_loop.sg (sigil-apps dacb955) is the T8 sprint deliverable — the browser event loop that connects input events to DOM nodes. It reads ev_overlay events (24B each: type|x|y) from ev_buf @0x300000, hit-tests DOM layout boxes at lb_buf @0x740000 for click events, and dispatches to a focused node for keydown. Hit counters accumulate at hit_buf @0x7B0000. Test: 5 events → 4 dispatched (click h1/p/img + keydown→h1-focus, 1 miss). EVENT-LOOP-PASS 4/4. 13480B arm-el0.
Event format and memory layout
ev_overlay event: 24B at ev_buf @0x300000 + i×24
| Field | Offset | Type | Values |
|---|---|---|---|
type | +0 | i32 | 1=click, 2=keydown, 3=mousemove |
x | +8 | i32 | pixel X (click/move), keycode (keydown) |
y | +16 | i32 | pixel Y (click/move), 0 (keydown) |
comp_present writes to ev_buf after each frame). The event loop drains the buffer ev_count events at a time.DOM layout box: 32B at lb_buf @0x740000 + node_idx×32
| Field | Offset | Type | Meaning |
|---|---|---|---|
x | +0 | i32 | left edge (pixels) |
y | +4 | i32 | top edge (pixels) |
w | +8 | i32 | width (pixels) |
h | +12 | i32 | height (pixels) |
node_idx | +16 | i32 | which DOM node this box belongs to |
flags | +20 | i32 | 1=visible, 0=hidden |
lb_buf is written by layout_box.sg (f33524f). event_loop.sg reads it read-only — it does not modify layout.Hit-testing algorithm
ev_loop_click_hit(ex, ey) → node_idx
(ex, ey), walks all lb_count layout boxes at lb_buf. For each box where flags=1 (visible): tests ex >= box.x && ex < box.x + box.w && ey >= box.y && ey < box.y + box.h.node_idx of the first box whose bounds contain (ex, ey). Hit-test order matches lb_buf order, which is DOM order (depth-first). First match wins — innermost-painted element gets the event, consistent with standard browser hit-test semantics.hit_buf @0x7B0000 — per-node hit counters
hit_buf holds one i32 per DOM node (indexed by node_idx). On a successful hit for node N: hit_buf[N] += 1. On a miss: no counter incremented.ev_loop_hit_count(node_idx): returns hit_buf[node_idx]. Hit counters are monotonic — they accumulate across all ev_loop_tick() calls for the session. Used by the test to verify dispatch: after the 5-event test, check that hit counts match expected dispatch targets.Keydown dispatch + focused node
Focus model: single focused node
i32 at ev_state @0x7C0000 + 0, initialised to 0 (first DOM node is default focus). ev_loop_focus(node_idx): sets ev_focused_node = node_idx.ev_loop_keydown(keycode) — dispatch to focused node
ev_focused_node. Calls ev_loop_focus_set(node_idx) if a prior click updated focus — any successful click hit sets focus to the hit node.x field of the keydown event carries the keycode (raw HID keycode from hid_kb_report), but event_loop.sg does not decode it — it only dispatches the event to the focused node. Keycode decoding is deferred to a future T9 sprint (text input).hit_buf[ev_focused_node] on dispatch.EVENT-LOOP-PASS test
Test sequence: 5 events injected, 4 dispatched, 1 intentional miss.
| Event | type | x | y | Expected | Result |
|---|---|---|---|---|---|
| 1 | click | 50 | 20 | hit h1 (node 0) | ✅ hit_buf[0]=1 |
| 2 | click | 50 | 60 | hit p (node 1) | ✅ hit_buf[1]=1 |
| 3 | click | 50 | 100 | hit img (node 2) | ✅ hit_buf[2]=1 |
| 4 | keydown | 0x04 (keycode A) | 0 | dispatch to focused node (h1=0) | ✅ hit_buf[0]=2 |
| 5 | click | 999 | 999 | miss (out of bounds) | ✅ no counter incremented |
4/4 dispatched (1 intentional miss). EVENT-LOOP-PASS. 13480B arm-el0.
Pipeline position
event_loop.sg slots between comp_present (which writes to ev_buf) and any future input handler (text input, scroll, hover). The browser event pipeline is now:
input hardware
→ hid_kb_report / compositor overlay
→ ev_buf @0x300000
→ event_loop.sg hit-test (lb_buf @0x740000) + dispatch
→ hit_buf @0x7B0000 per-node counters
→ (T9: text insertion into DOM)
event_loop.sg does not own the layout boxes and does not write to the DOM — it is a pure dispatch layer. It reads ev_buf, reads lb_buf, and writes only hit_buf and the ev_focused_node slot in ev_state. The T9 sprint will read the focused node and keycode to perform text insertion.