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