tessera_ui/
keyboard_state.rs1use std::collections::VecDeque;
8
9use winit::keyboard::ModifiersState;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct KeyboardEvent {
14 pub physical_key: winit::keyboard::PhysicalKey,
16 pub logical_key: winit::keyboard::Key,
18 pub text: Option<String>,
20 pub location: winit::keyboard::KeyLocation,
22 pub state: winit::event::ElementState,
24 pub repeat: bool,
26}
27
28impl KeyboardEvent {
29 pub fn named(key: winit::keyboard::NamedKey, state: winit::event::ElementState) -> Self {
31 use winit::keyboard::{KeyCode, NamedKey, NativeKeyCode, PhysicalKey};
32 let code = match key {
33 NamedKey::ArrowLeft => Some(KeyCode::ArrowLeft),
34 NamedKey::ArrowRight => Some(KeyCode::ArrowRight),
35 NamedKey::ArrowUp => Some(KeyCode::ArrowUp),
36 NamedKey::ArrowDown => Some(KeyCode::ArrowDown),
37 NamedKey::Tab => Some(KeyCode::Tab),
38 NamedKey::Enter => Some(KeyCode::Enter),
39 NamedKey::Escape => Some(KeyCode::Escape),
40 NamedKey::Space => Some(KeyCode::Space),
41 NamedKey::Backspace => Some(KeyCode::Backspace),
42 NamedKey::Delete => Some(KeyCode::Delete),
43 NamedKey::Home => Some(KeyCode::Home),
44 NamedKey::End => Some(KeyCode::End),
45 NamedKey::PageUp => Some(KeyCode::PageUp),
46 NamedKey::PageDown => Some(KeyCode::PageDown),
47 _ => None,
48 };
49 Self {
50 physical_key: code
51 .map(PhysicalKey::Code)
52 .unwrap_or(PhysicalKey::Unidentified(NativeKeyCode::Unidentified)),
53 logical_key: winit::keyboard::Key::Named(key),
54 text: None,
55 location: winit::keyboard::KeyLocation::Standard,
56 state,
57 repeat: false,
58 }
59 }
60}
61
62impl From<winit::event::KeyEvent> for KeyboardEvent {
63 fn from(event: winit::event::KeyEvent) -> Self {
64 Self {
65 physical_key: event.physical_key,
66 logical_key: event.logical_key,
67 text: event.text.map(|text| text.to_string()),
68 location: event.location,
69 state: event.state,
70 repeat: event.repeat,
71 }
72 }
73}
74
75#[derive(Debug)]
76pub(crate) struct QueuedInput<E = KeyboardEvent> {
77 pub event: E,
78 pub modifiers: ModifiersState,
79 pub sequence: u64,
80}
81
82pub(crate) fn next_input_sequence() -> u64 {
83 #[derive(Default)]
84 struct Sequence(std::cell::Cell<u64>);
85 let sequence = crate::local_runtime_resource::<Sequence>();
86 let next = sequence
87 .0
88 .get()
89 .checked_add(1)
90 .expect("input sequence exhausted");
91 sequence.0.set(next);
92 next
93}
94
95#[derive(Debug)]
96pub(crate) struct KeyboardQueue<E> {
97 events: VecDeque<QueuedInput<E>>,
98 modifiers: ModifiersState,
99}
100
101pub(crate) type KeyboardState = KeyboardQueue<KeyboardEvent>;
102
103impl<E> Default for KeyboardQueue<E> {
104 fn default() -> Self {
105 Self {
106 events: VecDeque::new(),
107 modifiers: ModifiersState::empty(),
108 }
109 }
110}
111
112impl<E> KeyboardQueue<E> {
113 pub fn push_event(&mut self, event: E) {
114 self.events.push_back(QueuedInput {
115 event,
116 modifiers: self.modifiers,
117 sequence: next_input_sequence(),
118 });
119 }
120
121 pub fn take_events(&mut self) -> Vec<QueuedInput<E>> {
122 self.events.drain(..).collect()
123 }
124
125 pub fn update_modifiers(&mut self, new_state: ModifiersState) {
126 self.modifiers = new_state;
127 }
128
129 pub fn modifiers(&self) -> ModifiersState {
130 self.modifiers
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn modifier_release_does_not_rewrite_queued_shortcuts() {
140 let _runtime_session = crate::RuntimeSession::new();
141 let _runtime_scope = _runtime_session.enter();
142 let mut queue = KeyboardQueue::default();
143 queue.update_modifiers(ModifiersState::SHIFT);
144 queue.push_event("Tab pressed");
145 queue.push_event("Tab released");
146 queue.update_modifiers(ModifiersState::empty());
147 queue.push_event("Tab pressed again");
148 let events = queue.take_events();
149 assert_eq!(
150 events.iter().map(|event| event.event).collect::<Vec<_>>(),
151 ["Tab pressed", "Tab released", "Tab pressed again"]
152 );
153 assert_eq!(
154 events
155 .iter()
156 .map(|event| event.modifiers)
157 .collect::<Vec<_>>(),
158 [
159 ModifiersState::SHIFT,
160 ModifiersState::SHIFT,
161 ModifiersState::empty()
162 ]
163 );
164 assert!(queue.take_events().is_empty());
165 }
166
167 #[test]
168 fn long_frames_preserve_order_and_each_modifier_combination() {
169 let _runtime_session = crate::RuntimeSession::new();
170 let _runtime_scope = _runtime_session.enter();
171 let mut queue = KeyboardQueue::default();
172 for index in 0..512 {
173 queue.update_modifiers(if index % 2 == 0 {
174 ModifiersState::CONTROL | ModifiersState::SHIFT
175 } else {
176 ModifiersState::ALT
177 });
178 queue.push_event(index);
179 }
180 queue.update_modifiers(ModifiersState::empty());
181 let events = queue.take_events();
182 assert_eq!(events.len(), 512);
183 for (index, event) in events.iter().enumerate() {
184 assert_eq!(event.event, index);
185 assert_eq!(
186 event.modifiers,
187 if index % 2 == 0 {
188 ModifiersState::CONTROL | ModifiersState::SHIFT
189 } else {
190 ModifiersState::ALT
191 }
192 );
193 }
194 }
195}