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

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:

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.