1use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
10use crate::{input_device, keyboard_binding};
11use async_trait::async_trait;
12use fuchsia_inspect::health::Reporter;
13
14use std::cell::RefCell;
15use std::rc::Rc;
16
17#[derive(Debug, Default)]
23pub struct KeymapHandler {
24 modifier_state: RefCell<keymaps::ModifierState>,
26
27 lock_state: RefCell<keymaps::LockStateKeys>,
29
30 pub inspect_status: InputHandlerStatus,
32}
33
34#[async_trait(?Send)]
37impl UnhandledInputHandler for KeymapHandler {
38 async fn handle_unhandled_input_event(
39 self: Rc<Self>,
40 input_event: input_device::UnhandledInputEvent,
41 ) -> Vec<input_device::InputEvent> {
42 match input_event.clone() {
43 input_device::UnhandledInputEvent {
45 device_event: input_device::InputDeviceEvent::Keyboard(event),
46 device_descriptor,
47 event_time,
48 trace_id: _,
49 } => {
50 self.inspect_status
51 .count_received_event(input_device::InputEvent::from(input_event));
52 vec![input_device::InputEvent::from(self.process_keyboard_event(
53 event,
54 device_descriptor,
55 event_time,
56 ))]
57 }
58 _ => vec![input_device::InputEvent::from(input_event)],
60 }
61 }
62
63 fn set_handler_healthy(self: std::rc::Rc<Self>) {
64 self.inspect_status.health_node.borrow_mut().set_ok();
65 }
66
67 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
68 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
69 }
70}
71
72impl KeymapHandler {
73 pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
75 let inspect_status = InputHandlerStatus::new(
76 input_handlers_node,
77 "keymap_handler",
78 false,
79 );
80 Rc::new(Self {
81 modifier_state: Default::default(),
82 lock_state: Default::default(),
83 inspect_status,
84 })
85 }
86
87 fn process_keyboard_event(
89 self: &Rc<Self>,
90 event: keyboard_binding::KeyboardEvent,
91 device_descriptor: input_device::InputDeviceDescriptor,
92 event_time: zx::MonotonicInstant,
93 ) -> input_device::UnhandledInputEvent {
94 let (key, event_type) = (event.get_key(), event.get_event_type());
95 log::debug!(
96 concat!(
97 "Keymap::process_keyboard_event: key:{:?}, ",
98 "modifier_state:{:?}, lock_state: {:?}, event_type: {:?}"
99 ),
100 key,
101 self.modifier_state.borrow(),
102 self.lock_state.borrow(),
103 event_type
104 );
105
106 self.modifier_state.borrow_mut().update(event_type, key);
107 self.lock_state.borrow_mut().update(event_type, key);
108 let key_meaning = keymaps::select_keymap(&event.get_keymap()).apply(
109 key,
110 &*self.modifier_state.borrow(),
111 &*self.lock_state.borrow(),
112 );
113 input_device::UnhandledInputEvent {
114 device_event: input_device::InputDeviceEvent::Keyboard(
115 event.into_with_key_meaning(key_meaning),
116 ),
117 device_descriptor,
118 event_time,
119 trace_id: None,
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::input_handler::InputHandler;
128 use crate::{consumer_controls_binding, testing_utilities};
129 use pretty_assertions::assert_eq;
130 use std::convert::TryFrom as _;
131 use {
132 fidl_fuchsia_input as finput, fidl_fuchsia_ui_input3 as finput3, fuchsia_async as fasync,
133 zx,
134 };
135
136 fn create_unhandled_keyboard_event(
138 key: finput::Key,
139 event_type: finput3::KeyEventType,
140 keymap: Option<String>,
141 ) -> input_device::UnhandledInputEvent {
142 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
143 keyboard_binding::KeyboardDeviceDescriptor {
144 keys: vec![finput::Key::A, finput::Key::B],
145 ..Default::default()
146 },
147 );
148 let (_, event_time_u64) = testing_utilities::event_times();
149 input_device::UnhandledInputEvent::try_from(
150 testing_utilities::create_keyboard_event_with_time(
151 key,
152 event_type,
153 None,
154 event_time_u64,
155 &device_descriptor,
156 keymap,
157 ),
158 )
159 .unwrap()
160 }
161
162 fn create_unhandled_consumer_controls_event(
164 pressed_buttons: Vec<fidl_fuchsia_input_report::ConsumerControlButton>,
165 event_time: zx::MonotonicInstant,
166 device_descriptor: &input_device::InputDeviceDescriptor,
167 ) -> input_device::UnhandledInputEvent {
168 input_device::UnhandledInputEvent::try_from(
169 testing_utilities::create_consumer_controls_event(
170 pressed_buttons,
171 event_time,
172 device_descriptor,
173 ),
174 )
175 .unwrap()
176 }
177
178 fn get_key_meaning(event: &input_device::InputEvent) -> Option<finput3::KeyMeaning> {
179 match event {
180 input_device::InputEvent {
181 device_event: input_device::InputDeviceEvent::Keyboard(event),
182 ..
183 } => event.get_key_meaning(),
184 _ => None,
185 }
186 }
187
188 #[fasync::run_singlethreaded(test)]
189 async fn test_keymap_application() {
190 #[derive(Debug)]
193 struct TestCase {
194 events: Vec<input_device::UnhandledInputEvent>,
195 expected: Vec<Option<finput3::KeyMeaning>>,
196 }
197 let tests: Vec<TestCase> = vec![
198 TestCase {
199 events: vec![create_unhandled_keyboard_event(
200 finput::Key::A,
201 finput3::KeyEventType::Pressed,
202 Some("US_QWERTY".into()),
203 )],
204 expected: vec![
205 Some(finput3::KeyMeaning::Codepoint(97)), ],
207 },
208 TestCase {
209 events: vec![create_unhandled_consumer_controls_event(
211 vec![],
212 zx::MonotonicInstant::ZERO,
213 &input_device::InputDeviceDescriptor::ConsumerControls(
214 consumer_controls_binding::ConsumerControlsDeviceDescriptor {
215 buttons: vec![],
216 device_id: 0,
217 },
218 ),
219 )],
220 expected: vec![None],
221 },
222 TestCase {
223 events: vec![
224 create_unhandled_keyboard_event(
225 finput::Key::LeftShift,
226 finput3::KeyEventType::Pressed,
227 Some("US_QWERTY".into()),
228 ),
229 create_unhandled_keyboard_event(
230 finput::Key::A,
231 finput3::KeyEventType::Pressed,
232 Some("US_QWERTY".into()),
233 ),
234 ],
235 expected: vec![
236 Some(finput3::KeyMeaning::NonPrintableKey(finput3::NonPrintableKey::Shift)),
237 Some(finput3::KeyMeaning::Codepoint(65)), ],
239 },
240 TestCase {
241 events: vec![
242 create_unhandled_keyboard_event(
243 finput::Key::Tab,
244 finput3::KeyEventType::Pressed,
245 Some("US_QWERTY".into()),
246 ),
247 create_unhandled_keyboard_event(
248 finput::Key::A,
249 finput3::KeyEventType::Pressed,
250 Some("US_QWERTY".into()),
251 ),
252 ],
253 expected: vec![
254 Some(finput3::KeyMeaning::NonPrintableKey(finput3::NonPrintableKey::Tab)),
255 Some(finput3::KeyMeaning::Codepoint(97)), ],
257 },
258 ];
259 let inspector = fuchsia_inspect::Inspector::default();
260 let test_node = inspector.root().create_child("test_node");
261 for test in &tests {
262 let mut actual: Vec<Option<finput3::KeyMeaning>> = vec![];
263 let handler = KeymapHandler::new(&test_node);
264 for event in &test.events {
265 let mut result = handler
266 .clone()
267 .handle_unhandled_input_event(event.clone())
268 .await
269 .iter()
270 .map(get_key_meaning)
271 .collect();
272 actual.append(&mut result);
273 }
274 assert_eq!(test.expected, actual);
275 }
276 }
277
278 #[fuchsia::test]
279 fn keymap_handler_initialized_with_inspect_node() {
280 let inspector = fuchsia_inspect::Inspector::default();
281 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
282 let _handler = KeymapHandler::new(&fake_handlers_node);
283 diagnostics_assertions::assert_data_tree!(inspector, root: {
284 input_handlers_node: {
285 keymap_handler: {
286 events_received_count: 0u64,
287 events_handled_count: 0u64,
288 last_received_timestamp_ns: 0u64,
289 "fuchsia.inspect.Health": {
290 status: "STARTING_UP",
291 start_timestamp_nanos: diagnostics_assertions::AnyProperty
294 },
295 }
296 }
297 });
298 }
299
300 #[fasync::run_singlethreaded(test)]
301 async fn keymap_handler_inspect_counts_events() {
302 let inspector = fuchsia_inspect::Inspector::default();
303 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
304 let keymap_handler = KeymapHandler::new(&fake_handlers_node);
305 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
306 keyboard_binding::KeyboardDeviceDescriptor {
307 keys: vec![finput::Key::A, finput::Key::B],
308 ..Default::default()
309 },
310 );
311 let (_, event_time_u64) = testing_utilities::event_times();
312 let input_events = vec![
313 testing_utilities::create_keyboard_event_with_time(
314 finput::Key::A,
315 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
316 None,
317 event_time_u64,
318 &device_descriptor,
319 None,
320 ),
321 testing_utilities::create_keyboard_event_with_handled(
323 finput::Key::B,
324 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
325 None,
326 event_time_u64,
327 &device_descriptor,
328 None,
329 None,
330 input_device::Handled::Yes,
331 ),
332 testing_utilities::create_keyboard_event_with_time(
333 finput::Key::A,
334 fidl_fuchsia_ui_input3::KeyEventType::Released,
335 None,
336 event_time_u64,
337 &device_descriptor,
338 None,
339 ),
340 testing_utilities::create_fake_input_event(event_time_u64),
342 testing_utilities::create_keyboard_event_with_time(
343 finput::Key::B,
344 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
345 None,
346 event_time_u64,
347 &device_descriptor,
348 None,
349 ),
350 ];
351
352 for input_event in input_events {
353 let _ = keymap_handler.clone().handle_input_event(input_event).await;
354 }
355
356 let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
357
358 diagnostics_assertions::assert_data_tree!(inspector, root: {
359 input_handlers_node: {
360 keymap_handler: {
361 events_received_count: 3u64,
362 events_handled_count: 0u64,
363 last_received_timestamp_ns: last_event_timestamp,
364 "fuchsia.inspect.Health": {
365 status: "STARTING_UP",
366 start_timestamp_nanos: diagnostics_assertions::AnyProperty
369 },
370 }
371 }
372 });
373 }
374}