← Blog
0.6.0 · WM input

HID→WM: Cap-Gated Input Delivery to Lumen Windows

June 22, 2026 · sigil-os · Sigil-Docs
wm hid input security 0.6.0

hidinput.sg wires the HID driver output to the Lumen WM event model. HID_CAP_TOKEN (0x48494421, "HID!") is broker-held — no EL0 code can forge or supply it. Per-window key rings live at 0xA60000 (8 windows × 64B each). Keyboard char delivery, Alt+Tab focus cycling, and mouse dispatch via pointer.sg are all wired and QEMU raspi3b PASS. (36de866)

WM scene ABI verify on raspi3b
WM scene ABI verify on raspi3b — input dispatch QEMU PASS

The capability gate

HID_CAP_TOKEN = 0x48494421 ("HID!" as ASCII). The broker holds this token and injects it at the HID driver seam. EL0 code receives event data but never the token itself. A call with the wrong token returns -1 and delivers no event. This is the same trust model used across sigilOS for sensitive I/O: AU_MIC_TOKEN (audio mic), HP_NET_TOKEN (network), ID_ELEV_TOKEN (identity elevation). The token is the boundary; EL0 stays on the results side.


Per-window key rings

The key ring region starts at 0xA60000. Eight windows, 64 bytes each. Layout per window:

offset  0  — write_head  (u32, WM writes here)
offset  8  — read_head   (u32, EL0 reads here)
offset 16  — char buf    (48 bytes, circular SPSC)

The WM writes to the circular buffer and advances write_head. The focused window's EL0 app reads from read_head. SPSC — no lock needed in standalone; a real kernel implementation adds a futex for cross-core wakeup. Overflow is guarded: a full ring drops the incoming character (harness assertion #8 verifies the guard holds).


Keyboard dispatch

hid_kbd_dispatch is the entry point from the HID driver. Flow:


Mouse dispatch

hid_mouse_dispatch enforces the same cap gate (HID_CAP_TOKEN check first, return -1 on mismatch), then delegates to pt_dispatch() in pointer.sg. pointer.sg handles cursor clamping to screen bounds and WM pointer-down / drag / pointer-up routing, dispatching to whichever overlay or window owns the hit point.


12-assertion harness (hidinputtest.sg)

#Assertion
1Ring init: write_head=0, read_head=0
2Ring write: write_head advances
3Ring read: read_head advances, correct char returned
4Ring pending: correct count returned
5Cap gate: wrong token → -1, no event delivered
6Cap gate: correct token → event routed
7Char delivery: char appears in focused window's ring
8Mouse cap gate: wrong token → -1
9Ring overflow guard: full ring drops char, heads unchanged
10Focus switch: event routes to new focused window after Alt+Tab
11Shift decode: uppercase char delivered with L-shift active
12Mouse dispatch: pt_dispatch called with correct coords on valid token

All 12 assertions PASS on QEMU raspi3b.