feather_ui/
input.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 Fundament Research Institute <https://fundament.institute>
3
4use enum_variant_type::EnumVariantType;
5use feather_macro::Dispatch;
6use guillotiere::euclid::default::Rotation3D;
7use guillotiere::euclid::{Point3D, Vector3D};
8use winit::dpi::PhysicalPosition;
9use winit::event::{DeviceId, TouchPhase};
10
11use crate::{Pixel, PxPoint, PxVector, RelVector};
12
13#[derive(Debug, Copy, Clone, PartialEq, Eq)]
14#[repr(u8)]
15pub enum TouchState {
16    Start = 0,
17    Move = 1,
18    End = 2,
19}
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22#[repr(u8)]
23pub enum MouseState {
24    Down = 0,
25    Up = 1,
26    DblClick = 2,
27}
28
29#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30#[repr(u16)]
31pub enum MouseButton {
32    Left = (1 << 0),
33    Right = (1 << 1),
34    Middle = (1 << 2),
35    Back = (1 << 3),
36    Forward = (1 << 4),
37    X1 = (1 << 5),
38    X2 = (1 << 6),
39    X3 = (1 << 7),
40    X4 = (1 << 8),
41    X5 = (1 << 9),
42    X6 = (1 << 10),
43    X7 = (1 << 11),
44    X8 = (1 << 12),
45    X9 = (1 << 13),
46    X10 = (1 << 14),
47    X11 = (1 << 15),
48}
49
50#[derive(Debug, Copy, Clone, PartialEq, Eq)]
51#[repr(u8)]
52pub enum ModifierKeys {
53    Shift = 1,
54    Control = 2,
55    Alt = 4,
56    Super = 8,
57    Capslock = 16,
58    Numlock = 32,
59    Held = 64,
60}
61
62#[derive(Debug, Dispatch, EnumVariantType, Clone)]
63#[evt(derive(Clone), module = "raw_event")]
64pub enum RawEvent {
65    Drag, // TBD, must be included here so RawEvent matches RawEventKind
66    Drop {
67        device_id: DeviceId,
68        pos: PhysicalPosition<f32>,
69    },
70    Focus {
71        acquired: bool,
72        window: std::sync::Arc<winit::window::Window>, // Allows setting IME mode for textboxes
73    },
74    JoyAxis {
75        device_id: DeviceId,
76        value: f64,
77        axis: u32,
78    },
79    JoyButton {
80        device_id: DeviceId,
81        down: bool,
82        button: u32,
83    },
84    JoyOrientation {
85        // 32 bytes
86        device_id: DeviceId,
87        velocity: Vector3D<f32, crate::Pixel>,
88        rotation: Rotation3D<f32>,
89    },
90    Key {
91        // 48 bytes
92        device_id: DeviceId,
93        physical_key: winit::keyboard::PhysicalKey,
94        location: winit::keyboard::KeyLocation,
95        down: bool,
96        logical_key: winit::keyboard::Key,
97        modifiers: u8,
98    },
99    Mouse {
100        // 24 bytes
101        device_id: DeviceId,
102        state: MouseState,
103        pos: PxPoint,
104        button: MouseButton,
105        all_buttons: u16,
106        modifiers: u8,
107    },
108    MouseOn {
109        device_id: DeviceId,
110        pos: PxPoint,
111        modifiers: u8,
112        all_buttons: u16,
113    },
114    MouseMove {
115        device_id: DeviceId,
116        pos: PxPoint,
117        modifiers: u8,
118        all_buttons: u16,
119    },
120    MouseOff {
121        device_id: DeviceId,
122        modifiers: u8,
123        all_buttons: u16,
124    },
125    MouseScroll {
126        device_id: DeviceId,
127        state: TouchState,
128        pos: PxPoint,
129        delta: Result<PxVector, RelVector>,
130    },
131    Touch {
132        // 48 bytes
133        device_id: DeviceId,
134        index: u32,
135        state: TouchState,
136        pos: Point3D<f32, Pixel>,
137        angle: Rotation3D<f32>,
138        pressure: f64,
139    },
140}
141
142static_assertions::const_assert!(size_of::<RawEvent>() == 48);
143
144impl RawEvent {
145    pub fn kind(&self) -> RawEventKind {
146        self.into()
147    }
148}
149
150#[derive(Debug, Copy, Clone, PartialEq, Eq)]
151#[repr(u64)]
152pub enum RawEventKind {
153    Drag = (1 << 0), // This must start from 1 and perfectly match RawEvent to ensure the dispatch works correctly
154    Drop = (1 << 1),
155    Focus = (1 << 2),
156    JoyAxis = (1 << 3),
157    JoyButton = (1 << 4),
158    JoyOrientation = (1 << 5),
159    Key = (1 << 6),
160    Mouse = (1 << 7),
161    MouseOn = (1 << 8),
162    MouseMove = (1 << 9),
163    MouseOff = (1 << 10),
164    MouseScroll = (1 << 11),
165    Touch = (1 << 12),
166}
167
168impl From<&RawEvent> for RawEventKind {
169    fn from(value: &RawEvent) -> Self {
170        match value {
171            RawEvent::Drag => RawEventKind::Drag,
172            RawEvent::Drop { .. } => RawEventKind::Drop,
173            RawEvent::Focus { .. } => RawEventKind::Focus,
174            RawEvent::JoyAxis { .. } => RawEventKind::JoyAxis,
175            RawEvent::JoyButton { .. } => RawEventKind::JoyButton,
176            RawEvent::JoyOrientation { .. } => RawEventKind::JoyOrientation,
177            RawEvent::Key { .. } => RawEventKind::Key,
178            RawEvent::Mouse { .. } => RawEventKind::Mouse,
179            RawEvent::MouseOn { .. } => RawEventKind::MouseOn,
180            RawEvent::MouseMove { .. } => RawEventKind::MouseMove,
181            RawEvent::MouseOff { .. } => RawEventKind::MouseOff,
182            RawEvent::MouseScroll { .. } => RawEventKind::MouseScroll,
183            RawEvent::Touch { .. } => RawEventKind::Touch,
184        }
185    }
186}
187
188impl From<TouchPhase> for TouchState {
189    fn from(value: TouchPhase) -> Self {
190        match value {
191            TouchPhase::Started => TouchState::Start,
192            TouchPhase::Moved => TouchState::Move,
193            TouchPhase::Ended => TouchState::End,
194            TouchPhase::Cancelled => TouchState::End,
195        }
196    }
197}
198
199impl From<winit::event::MouseButton> for MouseButton {
200    fn from(value: winit::event::MouseButton) -> Self {
201        use winit::event;
202        match value {
203            event::MouseButton::Left => MouseButton::Left,
204            event::MouseButton::Right => MouseButton::Right,
205            event::MouseButton::Middle => MouseButton::Middle,
206            event::MouseButton::Back => MouseButton::Back,
207            event::MouseButton::Forward => MouseButton::Forward,
208            event::MouseButton::Other(5) => MouseButton::X1,
209            event::MouseButton::Other(6) => MouseButton::X2,
210            event::MouseButton::Other(7) => MouseButton::X3,
211            event::MouseButton::Other(8) => MouseButton::X4,
212            event::MouseButton::Other(9) => MouseButton::X5,
213            event::MouseButton::Other(10) => MouseButton::X6,
214            event::MouseButton::Other(11) => MouseButton::X7,
215            event::MouseButton::Other(12) => MouseButton::X8,
216            event::MouseButton::Other(13) => MouseButton::X9,
217            event::MouseButton::Other(14) => MouseButton::X10,
218            event::MouseButton::Other(15) => MouseButton::X11,
219            event::MouseButton::Other(_) => panic!("Mouse button out of range"),
220        }
221    }
222}