The Input Router Capsule

July 16, 2026 ยท View on GitHub

capsule_input_router is the single consumer of the kernel input ring and the fan-out point for the whole desktop. Driver capsules post hardware events into the kernel ring; this capsule drains that ring, decides where each event belongs, and delivers it to the owning window over IPC. It is the userland counterpart to the kernel input subsystem, and the routing decisions here are the userland half of the event path.

Its source is organized into six top-level modules, and this documentation mirrors that structure so a page can be read beside the folders it describes. The one fact to hold before anything else: the router sees every keystroke and every pointer motion on the machine, yet it holds no InputSource capability. It can drain the ring and speak IPC, but it cannot inject a synthetic event back into the ring the way a driver can. That property is the spine of every page here.

Identity

Everything the kernel and the service registry need to name and reach the router comes from its Capsule.mk and its kernel-side spawn record.

FieldValueSource
Capsule sluginput-routerCapsule.mk:5
Service handleinput_routerCapsule.mk:6, src/userspace/capsule_input_router/spawn.rs:31
Namespacesystems.nonos.input_routerCapsule.mk:11
Service endpointservice:4320:input_routerCapsule.mk:12, spawn.rs:32
Reply endpointreply:4321:endpoint.input_router.replyCapsule.mk:13, spawn.rs:33, spawn.rs:34
Capability mask0x19Capsule.mk:15
Binary nameinput_routerCapsule.mk:9
Kernel mirrorsrc/userspace/capsule_input_routerCapsule.mk:16

The mask 0x19 decomposes into exactly three bits, checked against src/capabilities/types.rs:

BitValueGrants
CoreExec0x0001run as a process (types.rs:56)
IPC0x0008send and receive on its endpoints and speak the drain syscalls (types.rs:59)
Memory0x0010map its own heap and stack (types.rs:60)
  0x0019 = 0x0001 + 0x0008 + 0x0010
         = CoreExec + IPC + Memory

The kernel spawn path requests exactly those three capabilities and no others (src/userspace/capsule_input_router/spawn.rs:50). The router does not hold InputSource. InputSource (capability value 2097152, src/capabilities/types.rs:77) is the post authority, and MkInputEventPost is gated on it (src/syscall/contract/cap_table/mk.rs:78); only the signed driver capsules that own the hardware hold it. The router only drains, and MkInputEventDrain and MkInputEventWait are gated on can_ipc (src/syscall/contract/cap_table/mk.rs:79), which the IPC bit satisfies. So the router can read the ring and speak IPC, but it cannot inject a synthetic event, and it holds no network, filesystem, graphics, or hardware capability at all. Compromising the router yields those three bits and the right to ask the window manager, compositor, and policy services a question.

The six pillars

The source under userland/capsule_input_router/src/ is six top-level modules, and this documentation is one page per pillar (two of the modules pair with a partner). Data flows from the kernel ring on the left, through classification and delivery, to the consumer on the right; the clients on the bottom answer the questions each decision needs.

  sources/  ->  route/          ->  consumers
  drain the     classify and         (windows, shell,
  kernel ring   deliver each event    grab holders)
                    |
  server/  <-- IPC in (subscribe / grab / release / health)
  the loop and handlers, protocol/ the wire formats
                    |
  state/    the routing memory (cursor, grabs, subs, press, hover, key targets)
  clients/  the questions out (wm focus and hit-test, compositor, policy)
PageMirrorsWhat it covers
operations.mdsrc/protocol/, src/server/The NIRS request frame and the NINP delivery frame, the four opcodes, the non-blocking IPC drain, the four handlers, and the reply path on port 4321.
routing.mdsrc/sources/, src/route/The kernel-ring batch drain and the routing decision engine: the grab-first / pointer / keyboard / broadcast order, and the pointer specialization with focus query, hit-test, and the press-drag latch.
state.mdsrc/state/The routing memory: the cursor, the grab table, the subscription table, the per-key targets, the press and hover caches, and the Context that owns them all.
clients.mdsrc/clients/The outbound service clients: the window manager (focus, hit-test, route-focus), the compositor (display size, cursor update), the policy field read, and the shared NIRS wire helper.
contributing.mdthe whole treeWhere to work, how to add an operation or a routing rule, the build and sign steps, and the code standards.
debugging.mdruntimeThe boot marker, the first-event bench markers, and where to look when input never reaches a window or a grab is stuck.

Lifecycle

The router is spawned first in the desktop GUI fleet, before the compositor, so the rest of the desktop comes up behind it (src/userspace/init/spawn_plan/desktop_fleet.rs:38, :72). The spawn is idempotent through an is_alive guard, verifies the embedded ELF, cert, manifest, and attestation, and registers input_router on port 4320 (src/userspace/capsule_input_router/spawn.rs:37). It also runs as part of the input-probe fleet (src/userspace/init/spawn_plan/input_probe_fleet.rs:24).

_start initializes the heap and calls server::run, which never returns (src/main.rs:32). Each loop iteration drains pending IPC, does periodic maintenance every 64th tick, drains a batch of input events from the kernel ring, routes each event, pushes a cursor update to the compositor if the cursor moved, and blocks on the ring's sequence number when there is nothing left to do (src/server/runner.rs:38). So the router never spins when idle and never blocks while events are pending. On a successful spawn the kernel logs [INPUT-ROUTER] capsule spawned; the debugging page covers what each later marker means.

Source map

  Capsule.mk                                 slug, handle, ports, capability mask, kernel mirror
  userland/capsule_input_router/src/main.rs  _start -> heap_init -> server::run
  userland/capsule_input_router/src/protocol/  the NIRS request and NINP delivery wire formats
  userland/capsule_input_router/src/server/    the loop, the IPC drain, and the four op handlers
  userland/capsule_input_router/src/sources/   the kernel-ring batch drain
  userland/capsule_input_router/src/route/     the routing decision engine
  userland/capsule_input_router/src/state/     the routing memory
  userland/capsule_input_router/src/clients/   the outbound service clients
  src/capabilities/types.rs                  the CoreExec / IPC / Memory / InputSource capability bits
  src/syscall/contract/cap_table/mk.rs       the per-syscall capability gate
  src/userspace/capsule_input_router/        the kernel-side embed and verified spawn
  src/userspace/init/spawn_plan/             the desktop and input-probe fleet spawn entries

Every reference above is verified against those trees.