The event model
The Event struct
Every input is one flat Event. The fields valid for a given type are documented on the struct, and the same struct carries both the raw event and its synthesized intent:
struct Event {
EventType type; // CursorMove, ButtonDown/Up, Wheel, KeyDown/Up, Window*
Int2 pos; // pointer position (points, top-left origin)
MouseButton button; // Left, Right, Middle, Other
Float2 scroll; // wheel / trackpad delta
EventValue value; // synthesized: None/Press/Release/Click/DoubleClick/Drag
Int2 pressPos; // where the active button went down (the drag baseline)
Key key; // physical, layout-independent
uint32_t codepoint; // printable character for KeyDown
uint32_t modifiers; // Shift/Ctrl/Alt/Cmd bitmask, platform-neutral
};
Synthesizing intent
Hardware reports presses, releases and moves; widgets want clicks and drags. EventSynth derives the value from the raw stream:
EventSynth synth; // dragThreshold ≈ 6px (Chebyshev), doubleClickTime ≈ 0.35s
Event e = synth.feed(rawEvent); // sets e.value + e.pressPos
- Click — a press and release with no movement past the drag threshold.
- Drag — a held move that crosses the threshold (and every move after, while held).
- DoubleClick — a quick second press near the first.
It is header-only and portable (no OS calls), so it is unit-tested in isolation. Prism UI feeds every raw event through it before dispatch, which is why every widget agrees on what a click is — the logic lives here, once.
Normalization: quirks gone before you see them
The backend erases platform differences so the UI never branches on the OS:
- Modifiers are platform-neutral.
Mod_Altis Option on macOS and Alt elsewhere;Mod_Cmdis Command on macOS and Super/Win elsewhere — one flag each, mapped by the backend. - Button emulation. On macOS, Option+Left is mapped to the Middle button for the whole press-drag-release (and the Alt modifier is consumed from those events), so the UI just handles
MouseButton::Middle. Ctrl+Left maps to Right the same way, for trackpads and one-button mice. - Physical keys. Letters and digits are reported as physical US-ANSI positions, so a shortcut (⌘Z) binds the same chord regardless of the active keyboard layout.
By the time an event reaches a widget, there are no platform quirks left to handle — only intent. A future Windows/Linux backend performs the same normalizations, so the entire stack above is written once. From raw events to drawn frames, the rendering side is the RHI.