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 itsDownlatchespointer_idas 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, withEventCtx::pointer_idreporting that id — only if the captor calledEventCtx::capture_contactson theDownit captured with; otherwise it is dropped at the root. Only the claimant’sUp/Cancelreleases the capture. Another contact’sUp/Cancelnever 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_childfor the mechanism), so a scroll view or gesture detector enclosing a pinch recognizer never sees the second finger as aDownof 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 ownUp/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
event: PointerEventThe contact’s event, positioned like any InputEvent::Pointer.
Scroll
A scroll event at position (local logical space) carrying delta.
Fields
delta: ScrollDeltaHow 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
impl InputEvent
Sourcepub fn position(&self) -> Point
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).
Sourcepub fn translated(&self, offset: Vec2) -> InputEvent
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).
Sourcepub fn transformed(&self, affine: &Affine) -> InputEvent
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).
Sourcepub fn is_focus_routed(&self) -> bool
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.
Sourcepub fn is_broadcast(&self) -> bool
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
impl Clone for InputEvent
Source§fn clone(&self) -> InputEvent
fn clone(&self) -> InputEvent
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for InputEvent
impl Debug for InputEvent
Source§impl PartialEq for InputEvent
impl PartialEq for InputEvent
impl StructuralPartialEq for InputEvent
Auto Trait Implementations§
impl Freeze for InputEvent
impl RefUnwindSafe for InputEvent
impl Send for InputEvent
impl Sync for InputEvent
impl Unpin for InputEvent
impl UnsafeUnpin for InputEvent
impl UnwindSafe for InputEvent
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.