1use crate::input_device::{Handled, InputDeviceEvent, InputEvent, UnhandledInputEvent};
6use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
7use async_trait::async_trait;
8use fidl_fuchsia_ui_input3::{KeyMeaning, Modifiers, NonPrintableKey};
9use fuchsia_inspect::health::Reporter;
10use keymaps::{LockStateKeys, ModifierState};
11use std::cell::RefCell;
12use std::rc::Rc;
13
14#[derive(Debug)]
24pub struct ModifierHandler {
25 modifier_state: RefCell<ModifierState>,
27
28 lock_state: RefCell<LockStateKeys>,
30
31 pub inspect_status: InputHandlerStatus,
33}
34
35#[async_trait(?Send)]
36impl UnhandledInputHandler for ModifierHandler {
37 async fn handle_unhandled_input_event(
38 self: Rc<Self>,
39 unhandled_input_event: UnhandledInputEvent,
40 ) -> Vec<InputEvent> {
41 match unhandled_input_event.clone() {
42 UnhandledInputEvent {
43 device_event: InputDeviceEvent::Keyboard(mut event),
44 device_descriptor,
45 event_time,
46 trace_id: _,
47 } => {
48 self.inspect_status.count_received_event(InputEvent::from(unhandled_input_event));
49 self.modifier_state.borrow_mut().update(event.get_event_type(), event.get_key());
50 self.lock_state.borrow_mut().update(event.get_event_type(), event.get_key());
51 event = event
52 .into_with_lock_state(Some(self.lock_state.borrow().get_state()))
53 .into_with_modifiers(Some(self.modifier_state.borrow().get_state()));
54 log::debug!("modifiers and lock state applied: {:?}", &event);
55 vec![InputEvent {
56 device_event: InputDeviceEvent::Keyboard(event),
57 device_descriptor,
58 event_time,
59 handled: Handled::No,
60 trace_id: None,
61 }]
62 }
63 _ => vec![InputEvent::from(unhandled_input_event)],
65 }
66 }
67
68 fn set_handler_healthy(self: std::rc::Rc<Self>) {
69 self.inspect_status.health_node.borrow_mut().set_ok();
70 }
71
72 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
73 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
74 }
75}
76
77impl ModifierHandler {
78 pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
80 let inspect_status = InputHandlerStatus::new(
81 input_handlers_node,
82 "modifier_handler",
83 false,
84 );
85 Rc::new(Self {
86 modifier_state: RefCell::new(ModifierState::new()),
87 lock_state: RefCell::new(LockStateKeys::new()),
88 inspect_status,
89 })
90 }
91}
92
93#[derive(Debug)]
96pub struct ModifierMeaningHandler {
97 modifier_state: RefCell<ModifierState>,
99
100 pub inspect_status: InputHandlerStatus,
102}
103
104impl ModifierMeaningHandler {
105 pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
107 let inspect_status = InputHandlerStatus::new(
108 input_handlers_node,
109 "modifier_meaning_handler",
110 false,
111 );
112 Rc::new(Self { modifier_state: RefCell::new(ModifierState::new()), inspect_status })
113 }
114}
115
116#[async_trait(?Send)]
117impl UnhandledInputHandler for ModifierMeaningHandler {
118 async fn handle_unhandled_input_event(
119 self: Rc<Self>,
120 unhandled_input_event: UnhandledInputEvent,
121 ) -> Vec<InputEvent> {
122 match unhandled_input_event.clone() {
123 UnhandledInputEvent {
124 device_event: InputDeviceEvent::Keyboard(mut event),
125 device_descriptor,
126 event_time,
127 trace_id: _,
128 } if event.get_key_meaning()
129 == Some(KeyMeaning::NonPrintableKey(NonPrintableKey::AltGraph)) =>
130 {
131 self.inspect_status.count_received_event(InputEvent::from(unhandled_input_event));
132 if let Some(key_meaning) = event.get_key_meaning() {
135 self.modifier_state
136 .borrow_mut()
137 .update_with_key_meaning(event.get_event_type(), key_meaning);
138 let new_modifier = event.get_modifiers().unwrap_or(Modifiers::empty())
139 | self.modifier_state.borrow().get_state();
140 event = event.into_with_modifiers(Some(new_modifier));
141 log::debug!("additinal modifiers and lock state applied: {:?}", &event);
142 }
143 vec![InputEvent {
144 device_event: InputDeviceEvent::Keyboard(event),
145 device_descriptor,
146 event_time,
147 handled: Handled::No,
148 trace_id: None,
149 }]
150 }
151 _ => vec![InputEvent::from(unhandled_input_event)],
153 }
154 }
155
156 fn set_handler_healthy(self: std::rc::Rc<Self>) {
157 self.inspect_status.health_node.borrow_mut().set_ok();
158 }
159
160 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
161 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use crate::input_device::InputDeviceDescriptor;
169 use crate::input_handler::InputHandler;
170 use crate::keyboard_binding::{self, KeyboardEvent};
171 use crate::testing_utilities;
172 use fidl_fuchsia_input::Key;
173 use fidl_fuchsia_ui_input3::{KeyEventType, LockState};
174 use fuchsia_async as fasync;
175 use pretty_assertions::assert_eq;
176
177 fn get_unhandled_input_event(event: KeyboardEvent) -> UnhandledInputEvent {
178 UnhandledInputEvent {
179 device_event: InputDeviceEvent::Keyboard(event),
180 event_time: zx::MonotonicInstant::from_nanos(42),
181 device_descriptor: InputDeviceDescriptor::Fake,
182 trace_id: None,
183 }
184 }
185
186 #[fasync::run_singlethreaded(test)]
187 async fn test_decoration() {
188 let inspector = fuchsia_inspect::Inspector::default();
189 let test_node = inspector.root().create_child("test_node");
190 let handler = ModifierHandler::new(&test_node);
191 let input_event =
192 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed));
193 let result = handler.handle_unhandled_input_event(input_event.clone()).await;
194
195 let expected = InputEvent::from(get_unhandled_input_event(
198 KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
199 .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
200 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
201 ));
202 assert_eq!(vec![expected], result);
203 }
204
205 #[fasync::run_singlethreaded(test)]
206 async fn test_key_meaning_decoration() {
207 let inspector = fuchsia_inspect::Inspector::default();
208 let test_node = inspector.root().create_child("test_node");
209 let handler = ModifierMeaningHandler::new(&test_node);
210 {
211 let input_event = get_unhandled_input_event(
212 KeyboardEvent::new(Key::RightAlt, KeyEventType::Pressed)
213 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
214 NonPrintableKey::AltGraph,
215 )))
216 .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
217 );
218 let result = handler.clone().handle_unhandled_input_event(input_event.clone()).await;
219 let expected = InputEvent::from(get_unhandled_input_event(
220 KeyboardEvent::new(Key::RightAlt, KeyEventType::Pressed)
221 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
222 NonPrintableKey::AltGraph,
223 )))
224 .into_with_modifiers(Some(Modifiers::ALT_GRAPH | Modifiers::CAPS_LOCK)),
225 ));
226 assert_eq!(vec![expected], result);
227 }
228 {
229 let input_event = get_unhandled_input_event(
230 KeyboardEvent::new(Key::RightAlt, KeyEventType::Released)
231 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
232 NonPrintableKey::AltGraph,
233 )))
234 .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
235 );
236 let handler = handler.clone();
237 let result = handler.handle_unhandled_input_event(input_event.clone()).await;
238 let expected = InputEvent::from(get_unhandled_input_event(
239 KeyboardEvent::new(Key::RightAlt, KeyEventType::Released)
240 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
241 NonPrintableKey::AltGraph,
242 )))
243 .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
244 ));
245 assert_eq!(vec![expected], result);
246 }
247 }
248
249 #[fasync::run_singlethreaded(test)]
255 async fn test_modifier_press_lock_release() {
256 let input_events = vec![
257 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
258 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
259 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
260 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
261 ];
262
263 let inspector = fuchsia_inspect::Inspector::default();
264 let test_node = inspector.root().create_child("test_node");
265 let handler = ModifierHandler::new(&test_node);
266 let clone_handler = move || handler.clone();
267 let result = futures::future::join_all(
268 input_events
269 .into_iter()
270 .map(|e| async { clone_handler().handle_unhandled_input_event(e).await }),
271 )
272 .await
273 .into_iter()
274 .flatten()
275 .collect::<Vec<InputEvent>>();
276
277 let expected = IntoIterator::into_iter([
278 get_unhandled_input_event(
279 KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
280 .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
281 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
282 ),
283 get_unhandled_input_event(
284 KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
285 .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
286 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
287 ),
288 get_unhandled_input_event(
289 KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
290 .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
291 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
292 ),
293 get_unhandled_input_event(
294 KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
295 .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
296 .into_with_lock_state(Some(LockState::from_bits_allow_unknown(0))),
297 ),
298 ])
299 .map(InputEvent::from)
300 .collect::<Vec<_>>();
301
302 assert_eq!(expected, result);
303 }
304
305 #[fasync::run_singlethreaded(test)]
312 async fn repeated_modifier_key() {
313 let input_events = vec![
314 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
315 get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
316 get_unhandled_input_event(KeyboardEvent::new(Key::A, KeyEventType::Pressed)),
317 get_unhandled_input_event(KeyboardEvent::new(Key::A, KeyEventType::Released)),
318 ];
319
320 let inspector = fuchsia_inspect::Inspector::default();
321 let test_node = inspector.root().create_child("test_node");
322 let handler = ModifierHandler::new(&test_node);
323 let clone_handler = move || handler.clone();
324 let result = futures::future::join_all(
325 input_events
326 .into_iter()
327 .map(|e| async { clone_handler().handle_unhandled_input_event(e).await }),
328 )
329 .await
330 .into_iter()
331 .flatten()
332 .collect::<Vec<InputEvent>>();
333
334 let expected = IntoIterator::into_iter([
335 get_unhandled_input_event(
336 KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
337 .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
338 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
339 ),
340 get_unhandled_input_event(
341 KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
342 .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
343 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
344 ),
345 get_unhandled_input_event(
346 KeyboardEvent::new(Key::A, KeyEventType::Pressed)
347 .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
348 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
349 ),
350 get_unhandled_input_event(
351 KeyboardEvent::new(Key::A, KeyEventType::Released)
352 .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
353 .into_with_lock_state(Some(LockState::CAPS_LOCK)),
354 ),
355 ])
356 .map(InputEvent::from)
357 .collect::<Vec<_>>();
358 assert_eq!(expected, result);
359 }
360
361 #[fuchsia::test]
362 fn modifier_handlers_initialized_with_inspect_node() {
363 let inspector = fuchsia_inspect::Inspector::default();
364 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
365 let _modifier_handler = ModifierHandler::new(&fake_handlers_node);
366 let _modifier_meaning_handler = ModifierMeaningHandler::new(&fake_handlers_node);
367 diagnostics_assertions::assert_data_tree!(inspector, root: {
368 input_handlers_node: {
369 modifier_handler: {
370 events_received_count: 0u64,
371 events_handled_count: 0u64,
372 last_received_timestamp_ns: 0u64,
373 "fuchsia.inspect.Health": {
374 status: "STARTING_UP",
375 start_timestamp_nanos: diagnostics_assertions::AnyProperty
378 },
379 },
380 modifier_meaning_handler: {
381 events_received_count: 0u64,
382 events_handled_count: 0u64,
383 last_received_timestamp_ns: 0u64,
384 "fuchsia.inspect.Health": {
385 status: "STARTING_UP",
386 start_timestamp_nanos: diagnostics_assertions::AnyProperty
389 },
390 }
391 }
392 });
393 }
394
395 #[fasync::run_singlethreaded(test)]
396 async fn modifier_handler_inspect_counts_events() {
397 let inspector = fuchsia_inspect::Inspector::default();
398 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
399 let modifier_handler = ModifierHandler::new(&fake_handlers_node);
400 let modifier_meaning_handler = ModifierMeaningHandler::new(&fake_handlers_node);
401 let device_descriptor =
402 InputDeviceDescriptor::Keyboard(keyboard_binding::KeyboardDeviceDescriptor {
403 keys: vec![Key::A, Key::B, Key::RightAlt],
404 ..Default::default()
405 });
406 let (_, event_time_u64) = testing_utilities::event_times();
407 let input_events = vec![
408 testing_utilities::create_keyboard_event_with_time(
409 Key::A,
410 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
411 None,
412 event_time_u64,
413 &device_descriptor,
414 None,
415 ),
416 testing_utilities::create_keyboard_event_with_handled(
418 Key::B,
419 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
420 None,
421 event_time_u64,
422 &device_descriptor,
423 None,
424 None,
425 Handled::Yes,
426 ),
427 testing_utilities::create_keyboard_event_with_time(
428 Key::A,
429 fidl_fuchsia_ui_input3::KeyEventType::Released,
430 None,
431 event_time_u64,
432 &device_descriptor,
433 None,
434 ),
435 testing_utilities::create_fake_input_event(event_time_u64),
437 testing_utilities::create_keyboard_event_with_key_meaning(
439 Key::RightAlt,
440 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
441 None,
442 event_time_u64,
443 &device_descriptor,
444 None,
445 Some(KeyMeaning::NonPrintableKey(NonPrintableKey::AltGraph)),
447 ),
448 ];
449
450 for input_event in input_events {
451 let _ = modifier_handler.clone().handle_input_event(input_event.clone()).await;
452 let _ = modifier_meaning_handler.clone().handle_input_event(input_event).await;
453 }
454
455 let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
456
457 diagnostics_assertions::assert_data_tree!(inspector, root: {
458 input_handlers_node: {
459 modifier_handler: {
460 events_received_count: 3u64,
461 events_handled_count: 0u64,
462 last_received_timestamp_ns: last_event_timestamp,
463 "fuchsia.inspect.Health": {
464 status: "STARTING_UP",
465 start_timestamp_nanos: diagnostics_assertions::AnyProperty
468 },
469 },
470 modifier_meaning_handler: {
471 events_received_count: 1u64,
472 events_handled_count: 0u64,
473 last_received_timestamp_ns: last_event_timestamp,
474 "fuchsia.inspect.Health": {
475 status: "STARTING_UP",
476 start_timestamp_nanos: diagnostics_assertions::AnyProperty
479 },
480 }
481 }
482 });
483 }
484}