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