ui_events/pointer/
mod.rs

1// Copyright 2025 the UI Events Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Pointer Event Types
5
6mod buttons;
7
8pub use buttons::{PointerButton, PointerButtons};
9
10extern crate alloc;
11use alloc::vec::Vec;
12
13use core::num::NonZeroU64;
14
15use dpi::{PhysicalPosition, PhysicalSize};
16use keyboard_types::Modifiers;
17
18use crate::ScrollDelta;
19
20/// A unique identifier for the pointer.
21///
22/// PointerId(1) is reserved for the primary pointer.
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
24pub struct PointerId(NonZeroU64);
25
26impl PointerId {
27    /// The id of the primary pointer.
28    pub const PRIMARY: Self = Self(NonZeroU64::MIN);
29
30    /// Make a new `PointerId` from a `u64`.
31    #[inline(always)]
32    pub fn new(n: u64) -> Option<Self> {
33        NonZeroU64::new(n).map(PointerId)
34    }
35}
36
37/// An identifier for the pointing device that is stable across the session.
38///
39/// PointerId(1) is reserved for the primary pointer.
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
41pub struct PersistentDeviceId(NonZeroU64);
42
43impl PersistentDeviceId {
44    /// Make a new `PersistentDeviceId` from a `u64`.
45    #[inline(always)]
46    pub fn new(n: u64) -> Option<Self> {
47        NonZeroU64::new(n).map(PersistentDeviceId)
48    }
49}
50
51/// The type of device that has generated a pointer event.
52#[non_exhaustive]
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
54#[repr(u8)]
55pub enum PointerType {
56    /// The type of device could not be determined.
57    #[default]
58    Unknown,
59    /// A mouse.
60    Mouse,
61    /// A pen or stylus.
62    Pen,
63    /// A touch contact.
64    Touch,
65}
66
67/// Identifying information about a pointer, stable across states.
68#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
69pub struct PointerInfo {
70    /// Pointer ID.
71    ///
72    /// [`PointerId::PRIMARY`] is reserved for the primary pointer,
73    /// so when converting platform pointer IDs on a platform that
74    /// does not reserve this value, add an offset to avoid collision.
75    ///
76    /// `None` is for events not originating from a pointing device.
77    pub pointer_id: Option<PointerId>,
78    /// Persistent device ID.
79    ///
80    /// This should be set when the platform can identify a given pointing
81    /// device during the whole session, and associate it with events.
82    /// If this is not possible for the given event, it should be `None`.
83    pub persistent_device_id: Option<PersistentDeviceId>,
84    /// Pointer type.
85    pub pointer_type: PointerType,
86}
87
88/// Orientation of a pointer.
89#[derive(Clone, Copy, Debug, PartialEq)]
90pub struct PointerOrientation {
91    /// Spherical altitude.
92    ///
93    /// 0 is parallel to the surface, π/2 is perpendicular.
94    pub altitude: f32,
95    /// Spherical azimuth.
96    ///
97    /// 0 is the positive x axis, π/2 is positive y.
98    pub azimuth: f32,
99}
100
101impl Default for PointerOrientation {
102    fn default() -> Self {
103        Self {
104            altitude: core::f32::consts::FRAC_PI_2,
105            azimuth: core::f32::consts::FRAC_PI_2,
106        }
107    }
108}
109
110/// The size of an input, usually touch.
111///
112/// If this is not provided by the underlying API, platform, or device,
113/// then it should be a single pixel.
114pub type ContactGeometry = PhysicalSize<f64>;
115
116/// A single pointer state.
117#[derive(Clone, Debug, PartialEq)]
118pub struct PointerState {
119    /// `u64` nanoseconds real time.
120    ///
121    /// The base time is not important, except by convention, and should
122    /// generally be the same at least for states originating from the
123    /// same device.
124    pub time: u64,
125    /// Position.
126    pub position: PhysicalPosition<f64>,
127    /// Pressed buttons.
128    pub buttons: PointerButtons,
129    /// Modifiers state.
130    pub modifiers: Modifiers,
131    /// Click or tap count associated with the pointer.
132    pub count: u8,
133    /// The size of an input, usually touch.
134    ///
135    /// If this is not provided by the underlying API, platform, or device,
136    /// then it should be a single pixel.
137    pub contact_geometry: ContactGeometry,
138    /// Orientation.
139    pub orientation: PointerOrientation,
140    /// Normalized pressure in range 0..1.
141    ///
142    /// Where pressure is not reported by the platform, it
143    /// is always 0.5 when activated and 0.0 when not.
144    pub pressure: f32,
145    /// Normalized ‘tangential pressure’ in range -1..1.
146    ///
147    /// This is an arbitrary parameter and, despite its name,
148    /// it may not originate from a pressure sensitive control.
149    /// This is often controlled by something like a wheel on the
150    /// barrel of an ‘airbrush’ style pen.
151    pub tangential_pressure: f32,
152}
153
154impl Default for PointerState {
155    fn default() -> Self {
156        Self {
157            time: 0,
158            position: PhysicalPosition::<f64>::default(),
159            buttons: PointerButtons::default(),
160            modifiers: Modifiers::default(),
161            count: 0,
162            contact_geometry: ContactGeometry {
163                width: 1.0,
164                height: 1.0,
165            },
166            orientation: PointerOrientation::default(),
167            // No buttons pressed, therefore no pressure.
168            pressure: 0.0,
169            tangential_pressure: 0.0,
170        }
171    }
172}
173
174/// A pointer update, along with coalesced and predicted states.
175#[derive(Clone, Debug, PartialEq)]
176pub struct PointerUpdate {
177    /// Identifying information about pointer.
178    pub pointer: PointerInfo,
179    /// Current state.
180    pub current: PointerState,
181    /// Coalesced states, ordered by `time`.
182    ///
183    /// Coalescing is application-specific.
184    /// On the web, the browser does its own coalescing, whereas
185    /// on other platforms you may do your own, or forego it
186    /// altogether, delivering every state.
187    pub coalesced: Vec<PointerState>,
188    /// Predicted states, ordered by `time`.
189    ///
190    /// Some platforms provide predicted states directly,
191    /// and you may choose to add your own predictor.
192    pub predicted: Vec<PointerState>,
193}
194
195/// A standard `PointerEvent`.
196///
197/// This is intentionally limited to standard pointer events,
198/// and it is expected that applications and frameworks that
199/// support more event types will use this as a base and add
200/// what they need in a conversion.
201#[derive(Clone, Debug)]
202pub enum PointerEvent {
203    /// A [`PointerButton`] was pressed.
204    Down {
205        /// The [`PointerButton`] that was pressed..
206        button: Option<PointerButton>,
207        /// Identity of the pointer.
208        pointer: PointerInfo,
209        /// The state of the pointer (i.e. position, pressure, etc.).
210        state: PointerState,
211    },
212    /// A [`PointerButton`] was released.
213    Up {
214        /// The [`PointerButton`] that was released.
215        button: Option<PointerButton>,
216        /// Identity of the pointer.
217        pointer: PointerInfo,
218        /// The state of the pointer (i.e. position, pressure, etc.).
219        state: PointerState,
220    },
221    /// Pointer moved.
222    Move(PointerUpdate),
223    /// Pointer motion was cancelled.
224    ///
225    /// Usually this is a touch which was taken over somewhere else.
226    /// You should try to undo the effect of the gesture when you receive this.
227    Cancel(PointerInfo),
228    /// Pointer entered the area that receives this event.
229    Enter(PointerInfo),
230    /// Pointer left the area that receives these events.
231    Leave(PointerInfo),
232    /// A scroll was requested at the pointer location.
233    ///
234    /// Usually this is caused by a mouse wheel or a touchpad.
235    Scroll {
236        /// Identity of the pointer.
237        pointer: PointerInfo,
238        /// The delta of the scroll.
239        delta: ScrollDelta,
240        /// The state of the pointer (i.e. position, pressure, etc.).
241        state: PointerState,
242    },
243}