incular_platform/pointer.rs
1use std::fmt;
2
3use incular_core::{PointerDeviceKind, PointerPhase, PointerSampleMetadata};
4
5/// Native device details that enrich a Winit pointer sample without changing
6/// its logical contact identity or phase. This is used only when an OS adapter
7/// can supply semantics Winit intentionally omits (for example Win32 pen kind,
8/// tilt, and eraser state).
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub struct NativePointerSample {
11 /// Backend-local opaque physical-device token when available. This must
12 /// never contain a raw native handle. Shared desktop coordination remaps
13 /// the token into the same process-local ID namespace used for Winit
14 /// devices before a portable [`incular_core::InputEvent`] is emitted.
15 /// `None` preserves the stable Winit device ID rather than manufacturing
16 /// one.
17 pub device: Option<u64>,
18 pub kind: PointerDeviceKind,
19 pub sample: PointerSampleMetadata,
20 /// Native contact state when the device distinguishes hover from contact.
21 /// `None` preserves the ordinary Winit touch semantics.
22 pub in_contact: Option<bool>,
23}
24
25/// Portable metadata attached to one native pointer sample before its physical
26/// position is normalized into logical window coordinates.
27#[derive(Clone, Copy, Debug, PartialEq)]
28pub struct PointerMetadata {
29 pub pointer: u64,
30 pub device: u64,
31 pub kind: PointerDeviceKind,
32 pub buttons: u32,
33 pub button: Option<u32>,
34 pub sample: PointerSampleMetadata,
35 pub phase: PointerPhase,
36}
37
38/// Native cursor grab policy for one window.
39#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
40pub enum CursorGrabMode {
41 /// Release any pointer confinement or lock owned by the window.
42 #[default]
43 None,
44 /// Keep the pointer inside the window while preserving absolute motion.
45 Confined,
46 /// Lock the pointer for relative-motion style interaction.
47 Locked,
48}
49
50/// Finite logical cursor position relative to a window's client area.
51///
52/// The validated wrapper prevents NaN/infinity from reaching native APIs whose
53/// integer/physical conversion behavior is platform-dependent.
54#[derive(Clone, Copy, Debug, PartialEq)]
55pub struct LogicalWindowPosition {
56 x: f64,
57 y: f64,
58}
59
60impl LogicalWindowPosition {
61 pub fn new(x: f64, y: f64) -> Result<Self, LogicalWindowPositionError> {
62 if !x.is_finite() || !y.is_finite() {
63 return Err(LogicalWindowPositionError);
64 }
65 Ok(Self { x, y })
66 }
67
68 #[must_use]
69 pub const fn x(self) -> f64 {
70 self.x
71 }
72
73 #[must_use]
74 pub const fn y(self) -> f64 {
75 self.y
76 }
77}
78
79#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
80pub struct LogicalWindowPositionError;
81
82impl fmt::Display for LogicalWindowPositionError {
83 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
84 formatter.write_str("logical window position must contain finite coordinates")
85 }
86}
87
88impl std::error::Error for LogicalWindowPositionError {}