Skip to main content

InputEvent

Enum InputEvent 

Source
pub enum InputEvent {
    Pointer(PointerEvent),
    PointerContact {
        pointer_id: PointerId,
        event: PointerEvent,
    },
    Scroll {
        position: Point,
        delta: ScrollDelta,
    },
    Scale(ScaleEvent),
    Key(KeyEvent),
    Ime(ImeEvent),
    EditCommand(EditCommand),
    Housekeeping,
    Overlay(OverlayEvent),
}
Expand description

An input event delivered to the widget tree.

Pointer gestures, scroll, and scale are hit-tested (routed by position); keyboard, IME, and edit-command events are focus-routed — delivered straight down the recorded focus chain with no hit test and no meaningful position (see crate::widget::ChildPod’s focus bookkeeping and frust-widgets’ route_event). InputEvent::Housekeeping and InputEvent::Overlay are neither: they are broadcasts that reach every child unconditionally.

Variants§

§

Pointer(PointerEvent)

A pointer (mouse/touch/pen) gesture event.

From a shell it means the same as PointerContact with PointerId::MOUSE. It is also the only pointer form a widget ever receives: the root unwraps a PointerContact into this variant and reports the contact’s identity through EventCtx::pointer_id.

§

PointerContact

One identified pointer contact — the shell-facing carrier for a touch contact (or any pointer that is not PointerId::MOUSE).

Widgets never receive this variant. RenderRoot::event unwraps it and dispatches InputEvent::Pointer(event) with EventCtx::pointer_id reporting pointer_id, so every existing match on InputEvent::Pointer keeps working unchanged and a widget that does not care which contact it is seeing never has to ask.

§Multi-contact contract

The root decides what a contact does from its id and the capture latch it holds (the latch records the claimant: the id whose Down took the capture).

  • (a) Slot 0 with no live capture is hit-tested exactly like InputEvent::Pointer. The overlay pre-pass, hover, focus and blur-on-outside-tap bookkeeping are the same code path, so a single-finger gesture behaves identically whichever carrier delivered it. A capture taken on its Down latches pointer_id as the claimant.

  • (b) Slot 1 and above with no live capture is dropped at the root. Additional contacts exist only inside a captured gesture; one that arrives while nothing holds the pointer reaches no widget and moves no root state.

  • (c) While a capture is live, routing is keyed on the claimant. The claimant’s own events take the captured path exactly as before. An event from any other id is delivered down the same captured path to the captor — as InputEvent::Pointer, with EventCtx::pointer_id reporting that id — only if the captor called EventCtx::capture_contacts on the Down it captured with; otherwise it is dropped at the root. Only the claimant’s Up/Cancel releases the capture. Another contact’s Up/Cancel never does — at the root or in any container’s recorded active path — so a finger lifting elsewhere cannot break a mouse drag, nor a mouse release a touch drag.

    The captor is the only widget that sees another contact. The delivery walks the recorded active path forward-only: every container between the root and the captor hands it on without its own pointer handling running (see ChildPod::event_child for the mechanism), so a scroll view or gesture detector enclosing a pinch recognizer never sees the second finger as a Down of its own; the captor’s own handler, and whatever it routes below itself, run as usual. If the walk cannot reach the captor through a container (an overlay owner whose captured pod is a floated surface), that container alone is handed the event the ordinary way.

    A takeover ends the opt-in. A container that cancels the captor and keeps the gesture for itself releases it with EventCtx::release_captured_child; the root then stops routing the other contacts (they fall under rule (c)’s drop branch), while the claimant keeps the capture — now held by that container — until its own Up/Cancel.

A delivered non-claimant contact is not a gesture of its own: it opens or moves no capture, takes no hover pass, resolves no cursor, and blurs nothing (an explicit EventCtx::request_focus/EventCtx::release_focus from its handler is still honoured, as it is for a scroll). When the claimant’s Up/Cancel ends the capture, the captor must treat every other contact it was tracking as ended too: their later events fall under rule (b) and never reach it.

A bare InputEvent::Pointer from a shell is this variant with PointerId::MOUSE, so a host that emits only Pointer (desktop, web) sees exactly the single-pointer behaviour it always had.

Fields

§pointer_id: PointerId

Which contact this is.

§event: PointerEvent

The contact’s event, positioned like any InputEvent::Pointer.

§

Scroll

A scroll event at position (local logical space) carrying delta.

Fields

§position: Point

Where the scroll occurred, in the receiving widget’s local space.

§delta: ScrollDelta

How much to scroll.

§

Scale(ScaleEvent)

A scale (pinch/zoom) gesture event — hit-tested exactly like Scroll, by its ScaleEvent::focal point, and bubbles up the tree until a widget reports EventResult::Handled. See ScaleEvent for the field contract.

§

Key(KeyEvent)

A keyboard key event, routed down the focus path (no hit test).

§

Ime(ImeEvent)

An IME event, routed down the focus path (no hit test).

§

EditCommand(EditCommand)

A decoded clipboard / selection command, routed down the focus path (no hit test) exactly like Key and Ime.

Focus-routed rather than hit-tested because a clipboard verb is about the selection, and the selection lives wherever focus is — a Cmd+V carries no pointer position, and an edit-menu tap’s position is the menu’s, not the field’s. Focus routing is also what makes a paste with nothing focused a harmless no-op: the event reaches no widget and is dropped, so a shell may answer a stale paste request unconditionally (see EventCtx::request_paste).

§

Housekeeping

Not user input: a state-bearing housekeeping pass, broadcast to the whole tree so a widget that queued a callback needing &mut State during a state-free BuildCtx pass can run it.

§Why it exists

crate::app::RenderRoot::rebuild is the only unconditional per-frame pass holding &mut State, and it hands that state to the build closure alone — the view diff itself (and therefore every View::rebuild, where a navigator applies its queued push/pop ops) is state-free. A widget that needs to call back into app state from there had, before this variant, no pass to run in except the next event, which on a touch device may be seconds away or may never reach that widget at all (a pop-result callback measured 3.2s late on device, and was lost entirely when the next tap was consumed by chrome outside the navigator). rebuild now dispatches this variant instead, so the deferred callback runs on the very frame that queued it.

§Routing contract

Broadcast, never consumed. It carries no position, is not hit-tested, and is not focus-routed: a container forwards it to every child unconditionally (before any capture/focus/hit-test branch) and reports EventResult::Ignored regardless of what the children returned, so no “first handler wins” short-circuit can hide a subtree from it. A leaf widget with nothing deferred simply ignores it — the fall-through is harmless by construction. It never opens or releases a capture, never moves focus, and never blurs.

§Naming

Deliberately not Tick: Tick already means frame pacing in this codebase (crate::widget::TickClass), and this variant has nothing to do with the frame gate.

§

Overlay(OverlayEvent)

Not user input either: one floated overlay surface’s own input, broadcast to the whole tree so it reaches the owner that registered the surface, wherever in the tree that owner sits.

§Why a broadcast

The owner of a floated surface is an ordinary widget somewhere in the tree, and the pointer that hit its surface is nowhere near its own bounds — that is the entire point of floating. Hit-testing the event would therefore deliver it to whatever the main tree has under the pointer, and focus-routing it would deliver it to a text field that has nothing to do with the surface. Broadcasting is the only route that reaches the owner without knowing where it is, so this is the second broadcast variant (see InputEvent::is_broadcast), and every routing helper’s existing broadcast-first branch already forwards it correctly with no change.

§Routing contract

Only the owner whose OverlayKey matches acts on it; every other widget ignores it. A container forwards it to every child unconditionally — no hit test, no capture fast path, no focus gate — and reports EventResult::Ignored regardless, exactly like Housekeeping. A widget that is not an overlay owner, or whose key differs, must fall through: the key comparison is the whole addressing mechanism.

At the root it is inert in the ways a broadcast must be — it advances no hover epoch and never blurs — but, unlike Housekeeping, it is a real user gesture underneath, so a focus request or a pointer capture bubbled from inside the surface is honoured (see crate::app::RenderRoot::event).

Implementations§

Source§

impl InputEvent

Source

pub fn position(&self) -> Point

The event’s location, in the receiving widget’s local coordinate space.

InputEvent::Scale reports its ScaleEvent::focal point here, the same way InputEvent::Scroll reports position. Focus-routed events (InputEvent::Key/InputEvent::Ime/ InputEvent::EditCommand) and the two broadcasts (Housekeeping and Overlay) have no spatial position — they are delivered down the focus chain, or to every child, not hit-tested — so this reports Point::ZERO for them; callers must never hit-test on it (routing helpers early-return both classes). An overlay event’s payload does carry a position, but in window space rather than in the receiver’s local space, which is precisely why it is not reported here (see OverlayEventKind).

Source

pub fn translated(&self, offset: Vec2) -> InputEvent

Return a copy of this event with its position shifted by offset.

Containers use this (with offset = -child_origin) to translate an event from their own coordinate space into a child’s local space before forwarding it — see crate::widget::ChildPod::event_child. InputEvent::Scale shifts its ScaleEvent::focal point the same way InputEvent::Scroll shifts its position. Focus-routed events (InputEvent::Key/InputEvent::Ime/ InputEvent::EditCommand) and the Housekeeping broadcast carry no position, so they are returned unchanged (cloned). An Overlay event is returned unchanged for the opposite reason — its payload carries a window-space position that the container chain between the root and the owner must not shift, since that chain describes where the owner sits and not where the floated surface does (see OverlayEventKind).

Source

pub fn transformed(&self, affine: &Affine) -> InputEvent

Return a copy of this event with its position mapped through affine — the general form of InputEvent::translated, for a container that places a child under an arbitrary transform (crate::widget::ChildPod::set_transform).

Maps exactly the positions translated shifts, and leaves alone exactly what it leaves alone: InputEvent::Pointer’s position, the inner event of an InputEvent::PointerContact, InputEvent::Scroll’s position and InputEvent::Scale’s ScaleEvent::focal are mapped; the focus-routed events, the Housekeeping broadcast and the window-space Overlay payload are returned unchanged (cloned), for the reasons translated gives.

Only positions are mapped. A scroll delta, a scale’s multiplicative scale_delta and its velocity are carried over as-is: they describe the gesture’s magnitude in the input device’s terms, not a point in the receiver’s space.

A container routing into a transformed child passes the inverse of the child’s local→container mapping here; the caller owns checking that the inverse exists (see crate::hit::checked_inverse).

Source

pub fn is_focus_routed(&self) -> bool

Whether this event is focus-routed (delivered down the focus chain with no hit test) rather than hit-tested by position.

Housekeeping is not focus-routed — it reaches every child, focused or not; see is_broadcast.

Source

pub fn is_broadcast(&self) -> bool

Whether this event is a broadcast: forwarded to every child unconditionally, with no hit test, no capture fast-path, and no focus routing — InputEvent::Housekeeping and InputEvent::Overlay.

Every routing helper branches on this first, before its capture, focus, and hit-test branches (frust-widgets’ route_event/route_event_single, and this crate’s own [crate::component] mirror), so a broadcast can never be swallowed by a captured child or a contains() miss. That existing branch is exactly what carries an overlay event to its owner with no router change: the two variants differ in what they mean (a deferred callback flush vs one floated surface’s own input), not in how they travel.

Trait Implementations§

Source§

impl Clone for InputEvent

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for InputEvent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for InputEvent

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for InputEvent

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> StorageAccess<T> for T

Source§

fn as_borrowed(&self) -> &T

Borrows the value.
Source§

fn into_taken(self) -> T

Takes the value.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.