feather_ui/
input.rs

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