1use crate::Vec2;
2use std::cell::Cell;
3use std::rc::Rc;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
6pub struct PointerId(pub u64);
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum PointerKind {
10 Mouse,
11 Touch,
12 Pen,
13}
14
15#[derive(Clone, Copy, Debug)]
16pub enum PointerButton {
17 Primary, Secondary, Tertiary, }
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum PointerEventPass {
24 Initial,
27 Main,
31 Final,
34}
35
36#[derive(Clone, Copy, Debug)]
37pub enum PointerEventKind {
38 Down(PointerButton),
39 Up(PointerButton),
40 Move,
41 Cancel,
42 Enter,
43 Leave,
44}
45
46#[derive(Clone, Debug)]
47pub struct PointerEvent {
48 pub id: PointerId,
49 pub kind: PointerKind,
50 pub event: PointerEventKind,
51 pub position: Vec2,
53 pub origin: Vec2,
55 pub pressure: f32,
56 pub modifiers: Modifiers,
57 pub consumed: Rc<Cell<bool>>,
60}
61
62impl PointerEvent {
63 pub fn new(
64 id: PointerId,
65 kind: PointerKind,
66 event: PointerEventKind,
67 position: Vec2,
68 pressure: f32,
69 modifiers: Modifiers,
70 ) -> Self {
71 Self {
72 id,
73 kind,
74 event,
75 position,
76 origin: Vec2::ZERO,
77 pressure,
78 modifiers,
79 consumed: Rc::new(Cell::new(false)),
80 }
81 }
82
83 pub fn position_in_window(&self) -> Vec2 {
85 self.position + self.origin
86 }
87
88 pub fn consume(&self) {
92 self.consumed.set(true);
93 }
94
95 pub fn is_consumed(&self) -> bool {
97 self.consumed.get()
98 }
99}
100
101#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
102pub struct Modifiers {
103 pub shift: bool,
104 pub ctrl: bool,
105 pub alt: bool,
106 pub meta: bool, pub command: bool, }
109
110#[derive(Clone, Debug, PartialEq, Eq, Hash)]
111pub enum Key {
112 Character(char),
113 Enter,
114 Tab,
115 Backspace,
116 Delete,
117 Insert,
118 Escape,
119 ArrowLeft,
120 ArrowRight,
121 ArrowUp,
122 ArrowDown,
123 Home,
124 End,
125 PageUp,
126 PageDown,
127 Space,
128 F(u8), Unknown,
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq)]
133pub enum KeyEventType {
134 Down,
136 Up,
138 Unknown,
140}
141
142#[derive(Clone, Debug)]
143pub struct KeyEvent {
144 pub key: Key,
145 pub modifiers: Modifiers,
146 pub is_repeat: bool,
147 pub event_type: KeyEventType,
149 pub utf16_code_point: u16,
152}
153
154#[derive(Clone, Debug)]
155pub struct TextInputEvent {
156 pub text: String,
157}
158
159#[derive(Clone, Debug)]
160pub enum ImeEvent {
161 Start,
163 Update {
165 text: String,
166 cursor: Option<(usize, usize)>, },
168 Commit(String),
170 Cancel,
172}
173
174#[derive(Clone, Debug)]
175pub enum InputEvent {
176 Pointer(PointerEvent),
177 Key(KeyEvent),
178 Text(TextInputEvent),
179 Ime(ImeEvent),
180 Gamepad(GamepadEvent),
181}
182
183#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
186pub struct GamepadId(pub u32);
187
188#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
191pub enum GamepadButton {
192 South,
194 East,
196 West,
198 North,
200 Start,
201 Select,
202 LeftShoulder,
203 RightShoulder,
204 LeftStick,
205 RightStick,
206 DPadUp,
207 DPadDown,
208 DPadLeft,
209 DPadRight,
210}
211
212#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
214pub enum GamepadAxis {
215 LeftStickX,
216 LeftStickY,
217 RightStickX,
218 RightStickY,
219 LeftTrigger,
220 RightTrigger,
221}
222
223#[derive(Clone, Debug)]
224pub enum GamepadEvent {
225 Connected {
226 id: GamepadId,
227 name: String,
228 },
229 Disconnected {
230 id: GamepadId,
231 },
232 Button {
233 id: GamepadId,
234 button: GamepadButton,
235 pressed: bool,
236 },
237 Axis {
238 id: GamepadId,
239 axis: GamepadAxis,
240 value: f32,
242 },
243}
244
245impl GamepadEvent {
246 pub fn id(&self) -> GamepadId {
247 match *self {
248 GamepadEvent::Connected { id, .. } => id,
249 GamepadEvent::Disconnected { id } => id,
250 GamepadEvent::Button { id, .. } => id,
251 GamepadEvent::Axis { id, .. } => id,
252 }
253 }
254}
255
256#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
257pub enum InputMode {
258 #[default]
259 Touch,
260 Keyboard,
262}
263
264thread_local! {
265 static INPUT_MODE: Cell<InputMode> = const { Cell::new(InputMode::Touch) };
266}
267
268#[inline]
273pub fn input_mode() -> InputMode {
274 crate::locals::local_input_mode().unwrap_or_else(|| INPUT_MODE.get())
275}
276
277#[inline]
280pub fn set_input_mode_default(mode: InputMode) {
281 INPUT_MODE.set(mode);
282}
283
284pub fn request_input_mode(mode: InputMode) -> bool {
288 let prev = INPUT_MODE.get();
289 if prev == mode {
290 return false;
291 }
292 INPUT_MODE.set(mode);
293 crate::frame_clock::request_frame();
294 true
295}
296
297#[inline]
299pub fn is_focus_visible(focused: bool) -> bool {
300 focused && input_mode() == InputMode::Keyboard
301}
302
303#[cfg(test)]
304mod input_mode_tests {
305 use super::*;
306 use crate::frame_clock::take_frame_request;
307 use crate::modifier::{Interaction, MutableInteractionSource};
308
309 #[test]
310 fn request_input_mode_changes_and_requests_frame() {
311 set_input_mode_default(InputMode::Touch);
312 let _ = take_frame_request();
313
314 assert!(!request_input_mode(InputMode::Touch));
315 assert!(!take_frame_request());
316
317 assert!(request_input_mode(InputMode::Keyboard));
318 assert_eq!(input_mode(), InputMode::Keyboard);
319 assert!(take_frame_request());
320
321 assert!(request_input_mode(InputMode::Touch));
322 assert_eq!(input_mode(), InputMode::Touch);
323 set_input_mode_default(InputMode::Touch);
324 }
325
326 #[test]
327 fn focus_visible_requires_keyboard_mode() {
328 set_input_mode_default(InputMode::Touch);
329 let src = MutableInteractionSource::new();
330 src.emit(Interaction::Focus);
331 assert!(src.source().collect_is_focused());
332 assert!(!src.source().collect_is_focus_visible());
333
334 set_input_mode_default(InputMode::Keyboard);
335 assert!(src.source().collect_is_focus_visible());
336
337 set_input_mode_default(InputMode::Touch);
338 src.emit(Interaction::Unfocus);
339 }
340
341 #[test]
342 fn with_input_mode_overrides_global() {
343 set_input_mode_default(InputMode::Touch);
344 crate::locals::with_input_mode(InputMode::Keyboard, || {
345 assert_eq!(input_mode(), InputMode::Keyboard);
346 });
347 assert_eq!(input_mode(), InputMode::Touch);
348 }
349}