fret_ui/
input_modality.rs1use crate::UiHost;
2use fret_core::{AppWindowId, Event};
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum InputModality {
12 Keyboard,
13 Pointer,
14}
15
16#[derive(Default)]
17struct InputModalityState {
18 per_window: HashMap<AppWindowId, InputModality>,
19}
20
21pub fn modality<H: UiHost>(app: &mut H, window: Option<AppWindowId>) -> InputModality {
22 let Some(window) = window else {
23 return InputModality::Pointer;
24 };
25 let Some(state) = app.global::<InputModalityState>() else {
26 return InputModality::Pointer;
27 };
28 state
29 .per_window
30 .get(&window)
31 .copied()
32 .unwrap_or(InputModality::Pointer)
33}
34
35pub fn is_keyboard<H: UiHost>(app: &mut H, window: Option<AppWindowId>) -> bool {
36 modality(app, window) == InputModality::Keyboard
37}
38
39fn set_modality_if_changed<H: UiHost>(
40 app: &mut H,
41 window: AppWindowId,
42 modality: InputModality,
43) -> bool {
44 app.with_global_mut_untracked(InputModalityState::default, |state, _app| {
45 let prev = state
46 .per_window
47 .get(&window)
48 .copied()
49 .unwrap_or(InputModality::Pointer);
50 if prev != modality {
51 state.per_window.insert(window, modality);
52 true
53 } else {
54 false
55 }
56 })
57}
58
59pub fn update_for_event<H: UiHost>(app: &mut H, window: AppWindowId, event: &Event) -> bool {
63 match event {
64 Event::KeyDown { .. } => set_modality_if_changed(app, window, InputModality::Keyboard),
66 Event::Pointer(_) | Event::ExternalDrag(_) | Event::InternalDrag(_) => {
68 set_modality_if_changed(app, window, InputModality::Pointer)
69 }
70 _ => false,
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::test_host::TestHost;
78 use fret_core::{Modifiers, PointerEvent};
79
80 #[test]
81 fn defaults_to_pointer() {
82 let window = AppWindowId::default();
83 let mut app = TestHost::default();
84 assert_eq!(modality(&mut app, Some(window)), InputModality::Pointer);
85 }
86
87 #[test]
88 fn keydown_sets_keyboard_until_pointer_activity() {
89 let window = AppWindowId::default();
90 let mut app = TestHost::default();
91
92 assert!(update_for_event(
93 &mut app,
94 window,
95 &Event::KeyDown {
96 key: fret_core::KeyCode::KeyA,
97 modifiers: Modifiers::default(),
98 repeat: false,
99 }
100 ));
101 assert_eq!(modality(&mut app, Some(window)), InputModality::Keyboard);
102
103 assert!(update_for_event(
104 &mut app,
105 window,
106 &Event::Pointer(PointerEvent::Move {
107 position: fret_core::Point::new(fret_core::Px(1.0), fret_core::Px(2.0)),
108 buttons: fret_core::MouseButtons::default(),
109 modifiers: Modifiers::default(),
110 pointer_id: fret_core::PointerId(0),
111 pointer_type: fret_core::PointerType::Mouse,
112 })
113 ));
114 assert_eq!(modality(&mut app, Some(window)), InputModality::Pointer);
115 }
116}