Skip to main content

Module event

Module event 

Source
Expand description

ShellEvent — everything the window system tells the engine, in engine types.

§Timestamps, and the clock they are on

Every input-bearing variant carries an EventTime. This is not decoration: the input design makes the pattern evaluator a pure function over timestamped edges (docs/notes/simulation.md) — tap versus hold versus double-tap are defined by inter-event durations — and topic 26’s client prediction needs input-to-photon latency, which is a subtraction between an event timestamp and a present timestamp. Neither works if the timestamp is the moment the engine got around to draining the queue: a 20 ms frame quantizes every duration to 20 ms and makes a fast double-tap indistinguishable from a slow one.

So the timestamp is the window system’s, rebased onto the engine’s monotonic clock. EventTime’s own documentation states the epoch and spells out the per-platform rebasing each backend owes; the short version is that an EventTime and FrameClock readings live on one timeline, so they can be subtracted.

Non-input variants (Resized, MonitorsChanged) carry no timestamp. They are state transitions, not samples; nothing computes a duration between two resizes, and a field that exists only to be ignored invites someone to use it for something it is not.

§Modifiers are stamped onto every event, not delivered separately

Wayland sends wl_keyboard.modifiers as its own message, X11 puts a modifier mask on each event, and Win32 makes you call GetKeyState. The seam picks the X11 shape: the backend tracks modifier state and stamps the current value onto each event.

The reason is that the alternative loses information the consumer cannot recover. If modifiers arrive as a separate event, a consumer that batches a frame’s events — which every consumer does — sees “Ctrl went down” and “S went down” as two facts in a list and has to replay them in order to know whether it was Ctrl+S. That replay is exactly the state machine each backend has to write anyway, so it is written once, in the backend, where the ordering is authoritative.

§Non-exhaustive, unlike SurfaceTarget

SurfaceTarget is deliberately exhaustive so a new platform breaks every HAL backend loudly. ShellEvent is the opposite: a consumer that ignores an event it has never heard of degrades gracefully (touch input does nothing, rather than doing something wrong), and TextPreedit arrived that way after it. Breaking every match in the engine for each new event is not a useful forcing function, it is churn. (Gamepads are not window events and do not come through here: their backends emit crcbl_input::GamepadEvents from a poll of their own.)

Touch is what that promise looked like when it was collected: it landed without touching a single match outside the shell, and a game that never heard of it kept playing with one finger because the primary contact is reported through the pointer variants as well.

Enums§

ShellEvent
Something the window system reported.