1use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
6use crate::{input_device, keyboard_binding, metrics};
7use anyhow::Error;
8use async_trait::async_trait;
9use fidl_fuchsia_ui_input3::{self as fidl_ui_input3, LockState, Modifiers};
10use fuchsia_component::client::connect_to_protocol;
11use fuchsia_inspect::health::Reporter;
12
13use keymaps::{LockStateChecker, ModifierChecker};
14use metrics_registry::*;
15use std::rc::Rc;
16
17#[derive(Debug)]
18pub struct FrozenLockState {
19 lock_state: LockState,
20}
21
22impl From<LockState> for FrozenLockState {
23 fn from(lock_state: LockState) -> Self {
24 FrozenLockState { lock_state }
25 }
26}
27
28impl LockStateChecker for FrozenLockState {
29 fn test(&self, value: LockState) -> bool {
30 self.lock_state.contains(value)
31 }
32}
33
34#[derive(Debug)]
36pub struct FrozenModifierState {
37 state: Modifiers,
38}
39
40impl From<fidl_fuchsia_ui_input3::Modifiers> for FrozenModifierState {
41 fn from(state: Modifiers) -> Self {
42 FrozenModifierState { state }
43 }
44}
45
46impl ModifierChecker for FrozenModifierState {
47 fn test(&self, value: Modifiers) -> bool {
48 self.state.contains(value)
49 }
50}
51
52pub struct ImeHandler {
57 key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
59
60 pub inspect_status: InputHandlerStatus,
62
63 metrics_logger: metrics::MetricsLogger,
65}
66
67#[async_trait(?Send)]
68impl UnhandledInputHandler for ImeHandler {
69 async fn handle_unhandled_input_event(
70 self: Rc<Self>,
71 unhandled_input_event: input_device::UnhandledInputEvent,
72 ) -> Vec<input_device::InputEvent> {
73 match unhandled_input_event {
74 input_device::UnhandledInputEvent {
75 device_event: input_device::InputDeviceEvent::Keyboard(ref keyboard_device_event),
76 device_descriptor:
77 input_device::InputDeviceDescriptor::Keyboard(ref keyboard_description),
78 event_time,
79 trace_id,
80 } => {
81 fuchsia_trace::duration!(c"input", c"ime_handler");
82 if let Some(trace_id) = trace_id {
83 fuchsia_trace::flow_end!(c"input", c"event_in_input_pipeline", trace_id.into());
84 }
85
86 self.inspect_status.count_received_event(input_device::InputEvent::from(
87 unhandled_input_event.clone(),
88 ));
89 let key_event = create_key_event(
90 &keyboard_device_event,
91 event_time,
92 keyboard_description.device_id,
93 );
94 self.dispatch_key(key_event).await;
95 self.inspect_status.count_handled_event();
97 vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
98 }
99 _ => vec![input_device::InputEvent::from(unhandled_input_event)],
100 }
101 }
102
103 fn set_handler_healthy(self: std::rc::Rc<Self>) {
104 self.inspect_status.health_node.borrow_mut().set_ok();
105 }
106
107 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
108 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
109 }
110}
111
112impl ImeHandler {
113 pub async fn new(
115 input_handlers_node: &fuchsia_inspect::Node,
116 metrics_logger: metrics::MetricsLogger,
117 ) -> Result<Rc<Self>, Error> {
118 let key_event_injector = connect_to_protocol::<fidl_ui_input3::KeyEventInjectorMarker>()?;
119
120 Self::new_handler(key_event_injector, input_handlers_node, metrics_logger).await
121 }
122
123 async fn new_handler(
129 key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
130 input_handlers_node: &fuchsia_inspect::Node,
131 metrics_logger: metrics::MetricsLogger,
132 ) -> Result<Rc<Self>, Error> {
133 let inspect_status = InputHandlerStatus::new(
134 input_handlers_node,
135 "ime_handler",
136 false,
137 );
138 let handler = ImeHandler { key_event_injector, inspect_status, metrics_logger };
139
140 Ok(Rc::new(handler))
141 }
142
143 async fn dispatch_key(self: &Rc<Self>, key_event: fidl_ui_input3::KeyEvent) {
149 assert!(
150 key_event.timestamp.is_some(),
151 "dispatch_key: got a key_event without a timestamp: {:?}",
152 &key_event
153 );
154 match self.key_event_injector.inject(&key_event).await {
155 Err(err) => self.metrics_logger.log_error(
156 InputPipelineErrorMetricDimensionEvent::ImeFailedToDispatchKeyToIme,
157 std::format!("Failed to dispatch key to IME: {:?}", err),
158 ),
159 _ => {}
160 };
161 }
162}
163
164fn create_key_event(
170 event: &keyboard_binding::KeyboardEvent,
171 event_time: zx::MonotonicInstant,
172 device_id: u32,
173) -> fidl_ui_input3::KeyEvent {
174 let modifier_state: FrozenModifierState =
175 event.get_modifiers().unwrap_or_else(|| Modifiers::from_bits_allow_unknown(0)).into();
176 let lock_state: FrozenLockState =
177 event.get_lock_state().unwrap_or_else(|| LockState::from_bits_allow_unknown(0)).into();
178 log::debug!(
179 "ImeHandler::create_key_event: key:{:?}, modifier_state: {:?}, lock_state: {:?}, event_type: {:?}",
180 event.get_key(),
181 modifier_state,
182 lock_state,
183 event.get_event_type(),
184 );
185 let key_meaning = event
187 .get_key_meaning()
188 .or_else(|| keymaps::US_QWERTY.apply(event.get_key(), &modifier_state, &lock_state));
189
190 let repeat_sequence = match event.get_repeat_sequence() {
192 0 => None,
193 s => Some(s),
194 };
195
196 fidl_ui_input3::KeyEvent {
197 timestamp: Some(event_time.into_nanos()),
198 type_: event.get_event_type().into(),
199 key: event.get_key().into(),
200 modifiers: event.get_modifiers(),
201 lock_state: event.get_lock_state(),
202 key_meaning,
203 repeat_sequence,
204 device_id: Some(device_id),
205 ..Default::default()
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212 use crate::input_handler::InputHandler;
213 use crate::keyboard_binding::{self, KeyboardEvent};
214 use crate::testing_utilities;
215 use assert_matches::assert_matches;
216 use futures::StreamExt;
217 use std::convert::TryFrom as _;
218 use test_case::test_case;
219 use {
220 fidl_fuchsia_input as fidl_input, fidl_fuchsia_ui_input3 as fidl_ui_input3,
221 fuchsia_async as fasync,
222 };
223
224 fn handle_events(
225 ime_handler: Rc<ImeHandler>,
226 input_events: Vec<input_device::UnhandledInputEvent>,
227 ) {
228 fasync::Task::local(async move {
229 for input_event in input_events {
230 assert_matches!(
231 ime_handler.clone().handle_unhandled_input_event(input_event).await.as_slice(),
232 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
233 );
234 }
235 })
236 .detach();
237 }
238
239 async fn assert_ime_receives_events(
240 expected_events: Vec<fidl_ui_input3::KeyEvent>,
241 mut request_stream: fidl_ui_input3::KeyEventInjectorRequestStream,
242 ) {
243 let mut expected_events_iter = expected_events.iter().peekable();
244 while let Some(Ok(fidl_ui_input3::KeyEventInjectorRequest::Inject {
245 key_event,
246 responder,
247 ..
248 })) = request_stream.next().await
249 {
250 pretty_assertions::assert_eq!(&key_event, expected_events_iter.next().unwrap());
251
252 if expected_events_iter.peek().is_none() {
255 responder
256 .send(fidl_ui_input3::KeyEventStatus::Handled)
257 .expect("error responding to DispatchKey");
258 return;
259 }
260 responder
261 .send(fidl_ui_input3::KeyEventStatus::Handled)
262 .expect("error responding to DispatchKey");
263 }
264
265 assert!(false);
266 }
267
268 fn connect_to_key_event_injector(
269 ) -> (fidl_ui_input3::KeyEventInjectorProxy, fidl_ui_input3::KeyEventInjectorRequestStream)
270 {
271 fidl::endpoints::create_proxy_and_stream::<fidl_ui_input3::KeyEventInjectorMarker>()
272 }
273
274 fn create_unhandled_keyboard_event(
275 key: fidl_fuchsia_input::Key,
276 event_type: fidl_fuchsia_ui_input3::KeyEventType,
277 modifiers: Option<fidl_ui_input3::Modifiers>,
278 event_time: zx::MonotonicInstant,
279 device_descriptor: &input_device::InputDeviceDescriptor,
280 keymap: Option<String>,
281 ) -> input_device::UnhandledInputEvent {
282 create_unhandled_keyboard_event_with_key_meaning(
283 key,
284 event_type,
285 modifiers,
286 event_time,
287 device_descriptor,
288 keymap,
289 None,
290 )
291 }
292
293 fn create_unhandled_keyboard_event_with_key_meaning(
294 key: fidl_fuchsia_input::Key,
295 event_type: fidl_fuchsia_ui_input3::KeyEventType,
296 modifiers: Option<fidl_ui_input3::Modifiers>,
297 event_time: zx::MonotonicInstant,
298 device_descriptor: &input_device::InputDeviceDescriptor,
299 keymap: Option<String>,
300 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
301 ) -> input_device::UnhandledInputEvent {
302 input_device::UnhandledInputEvent::try_from(
303 testing_utilities::create_keyboard_event_with_key_meaning(
304 key,
305 event_type,
306 modifiers,
307 event_time,
308 device_descriptor,
309 keymap,
310 key_meaning,
311 ),
312 )
313 .unwrap()
314 }
315
316 fn create_unhandled_input_event(
317 keyboard_event: keyboard_binding::KeyboardEvent,
318 device_descriptor: &input_device::InputDeviceDescriptor,
319 event_time: zx::MonotonicInstant,
320 ) -> input_device::UnhandledInputEvent {
321 input_device::UnhandledInputEvent {
322 device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
323 device_descriptor: device_descriptor.clone(),
324 event_time,
325 trace_id: None,
326 }
327 }
328
329 #[fasync::run_singlethreaded(test)]
335 async fn pressed_key() {
336 let (proxy, request_stream) = connect_to_key_event_injector();
337 let inspector = fuchsia_inspect::Inspector::default();
338 let test_node = inspector.root().create_child("test_node");
339 let ime_handler =
340 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
341 .await
342 .expect("Failed to create ImeHandler.");
343
344 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
345 keyboard_binding::KeyboardDeviceDescriptor {
346 keys: vec![fidl_input::Key::A],
347 device_id: 0,
348 ..Default::default()
349 },
350 );
351 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
352 let input_events = vec![create_unhandled_keyboard_event(
353 fidl_input::Key::A,
354 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
355 None,
356 event_time_u64,
357 &device_descriptor,
358 None,
359 )];
360
361 let expected_events = vec![fidl_ui_input3::KeyEvent {
362 timestamp: Some(event_time_i64),
363 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
364 key: Some(fidl_input::Key::A),
365 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
367 device_id: Some(0),
368 ..Default::default()
369 }];
370
371 handle_events(ime_handler, input_events);
372 assert_ime_receives_events(expected_events, request_stream).await;
373 }
374
375 #[fasync::run_singlethreaded(test)]
377 async fn released_key() {
378 let (proxy, request_stream) = connect_to_key_event_injector();
379 let inspector = fuchsia_inspect::Inspector::default();
380 let test_node = inspector.root().create_child("test_node");
381 let ime_handler =
382 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
383 .await
384 .expect("Failed to create ImeHandler.");
385
386 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
387 keyboard_binding::KeyboardDeviceDescriptor {
388 keys: vec![fidl_input::Key::A],
389 device_id: 0,
390 ..Default::default()
391 },
392 );
393 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
394 let input_events = vec![create_unhandled_keyboard_event(
395 fidl_input::Key::A,
396 fidl_fuchsia_ui_input3::KeyEventType::Released,
397 None,
398 event_time_u64,
399 &device_descriptor,
400 None,
401 )];
402
403 let expected_events = vec![fidl_ui_input3::KeyEvent {
404 timestamp: Some(event_time_i64),
405 type_: Some(fidl_ui_input3::KeyEventType::Released),
406 key: Some(fidl_input::Key::A),
407 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
408 device_id: Some(0),
409 ..Default::default()
410 }];
411
412 handle_events(ime_handler, input_events);
413 assert_ime_receives_events(expected_events, request_stream).await;
414 }
415
416 #[fasync::run_singlethreaded(test)]
418 async fn pressed_and_released_key() {
419 let (proxy, request_stream) = connect_to_key_event_injector();
420 let inspector = fuchsia_inspect::Inspector::default();
421 let test_node = inspector.root().create_child("test_node");
422 let ime_handler =
423 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
424 .await
425 .expect("Failed to create ImeHandler.");
426
427 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
428 keyboard_binding::KeyboardDeviceDescriptor {
429 keys: vec![fidl_input::Key::A, fidl_input::Key::B],
430 device_id: 0,
431 ..Default::default()
432 },
433 );
434 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
435 let input_events = vec![
436 create_unhandled_keyboard_event(
437 fidl_input::Key::A,
438 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
439 None,
440 event_time_u64,
441 &device_descriptor,
442 None,
443 ),
444 create_unhandled_keyboard_event(
445 fidl_input::Key::A,
446 fidl_fuchsia_ui_input3::KeyEventType::Released,
447 None,
448 event_time_u64,
449 &device_descriptor,
450 None,
451 ),
452 create_unhandled_keyboard_event(
453 fidl_input::Key::B,
454 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
455 None,
456 event_time_u64,
457 &device_descriptor,
458 None,
459 ),
460 create_unhandled_keyboard_event_with_key_meaning(
461 fidl_input::Key::C,
462 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
463 None,
464 event_time_u64,
465 &device_descriptor,
466 None,
467 Some(fidl_fuchsia_ui_input3::KeyMeaning::Codepoint(42)),
468 ),
469 ];
470
471 let expected_events = vec![
472 fidl_ui_input3::KeyEvent {
473 timestamp: Some(event_time_i64),
474 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
475 key: Some(fidl_input::Key::A),
476 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
477 device_id: Some(0),
478 ..Default::default()
479 },
480 fidl_ui_input3::KeyEvent {
481 timestamp: Some(event_time_i64),
482 type_: Some(fidl_ui_input3::KeyEventType::Released),
483 key: Some(fidl_input::Key::A),
484 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
485 device_id: Some(0),
486 ..Default::default()
487 },
488 fidl_ui_input3::KeyEvent {
489 timestamp: Some(event_time_i64),
490 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
491 key: Some(fidl_input::Key::B),
492 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(98)),
493 device_id: Some(0),
494 ..Default::default()
495 },
496 fidl_ui_input3::KeyEvent {
497 timestamp: Some(event_time_i64),
498 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
499 key: Some(fidl_input::Key::C),
500 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(42)),
501 device_id: Some(0),
502 ..Default::default()
503 },
504 ];
505
506 handle_events(ime_handler, input_events);
507 assert_ime_receives_events(expected_events, request_stream).await;
508 }
509
510 #[fasync::run_singlethreaded(test)]
516 async fn repeated_modifier_key() {
517 let (proxy, request_stream) = connect_to_key_event_injector();
518 let inspector = fuchsia_inspect::Inspector::default();
519 let test_node = inspector.root().create_child("test_node");
520 let ime_handler =
521 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
522 .await
523 .expect("Failed to create ImeHandler.");
524
525 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
526 keyboard_binding::KeyboardDeviceDescriptor {
527 keys: vec![fidl_input::Key::A, fidl_input::Key::CapsLock],
528 device_id: 0,
529 ..Default::default()
530 },
531 );
532 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
533 let input_events = vec![
534 create_unhandled_input_event(
535 KeyboardEvent::new(
536 fidl_input::Key::CapsLock,
537 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
538 )
539 .into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
540 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
541 &device_descriptor,
542 event_time_u64,
543 ),
544 create_unhandled_input_event(
545 KeyboardEvent::new(
546 fidl_input::Key::A,
547 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
548 )
549 .into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
550 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
551 &device_descriptor,
552 event_time_u64,
553 ),
554 create_unhandled_input_event(
555 KeyboardEvent::new(
556 fidl_input::Key::CapsLock,
557 fidl_fuchsia_ui_input3::KeyEventType::Released,
558 )
559 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
560 &device_descriptor,
561 event_time_u64,
562 ),
563 ];
564
565 let expected_events = vec![
566 fidl_ui_input3::KeyEvent {
567 timestamp: Some(event_time_i64),
568 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
569 key: Some(fidl_input::Key::CapsLock),
570 modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
571 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
572 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
573 fidl_ui_input3::NonPrintableKey::CapsLock,
574 )),
575 device_id: Some(0),
576 ..Default::default()
577 },
578 fidl_ui_input3::KeyEvent {
579 timestamp: Some(event_time_i64),
580 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
581 key: Some(fidl_input::Key::A),
582 modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
583 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
584 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)),
585 device_id: Some(0),
586 ..Default::default()
587 },
588 fidl_ui_input3::KeyEvent {
589 timestamp: Some(event_time_i64),
590 type_: Some(fidl_ui_input3::KeyEventType::Released),
591 key: Some(fidl_input::Key::CapsLock),
592 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
593 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
594 fidl_ui_input3::NonPrintableKey::CapsLock,
595 )),
596 device_id: Some(0),
597 ..Default::default()
598 },
599 ];
600
601 handle_events(ime_handler, input_events);
602 assert_ime_receives_events(expected_events, request_stream).await;
603 }
604
605 #[fasync::run_singlethreaded(test)]
606 async fn nonprintable_key_meanings_set_correctly() {
607 let (proxy, request_stream) = connect_to_key_event_injector();
608 let inspector = fuchsia_inspect::Inspector::default();
609 let test_node = inspector.root().create_child("test_node");
610 let ime_handler =
611 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
612 .await
613 .expect("Failed to create ImeHandler.");
614
615 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
616 keyboard_binding::KeyboardDeviceDescriptor {
617 keys: vec![
618 fidl_input::Key::Enter,
619 fidl_input::Key::Tab,
620 fidl_input::Key::Backspace,
621 ],
622 device_id: 0,
623 ..Default::default()
624 },
625 );
626 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
627 let input_events = vec![
628 create_unhandled_keyboard_event(
629 fidl_input::Key::Enter,
630 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
631 None,
632 event_time_u64,
633 &device_descriptor,
634 None,
635 ),
636 create_unhandled_keyboard_event(
637 fidl_input::Key::Tab,
638 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
639 None,
640 event_time_u64,
641 &device_descriptor,
642 None,
643 ),
644 create_unhandled_keyboard_event(
645 fidl_input::Key::Backspace,
646 fidl_fuchsia_ui_input3::KeyEventType::Released,
647 None,
648 event_time_u64,
649 &device_descriptor,
650 None,
651 ),
652 ];
653
654 let expected_events = vec![
655 fidl_ui_input3::KeyEvent {
656 timestamp: Some(event_time_i64),
657 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
658 key: Some(fidl_input::Key::Enter),
659 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
660 fidl_ui_input3::NonPrintableKey::Enter,
661 )),
662 device_id: Some(0),
663 ..Default::default()
664 },
665 fidl_ui_input3::KeyEvent {
666 timestamp: Some(event_time_i64),
667 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
668 key: Some(fidl_input::Key::Tab),
669 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
670 fidl_ui_input3::NonPrintableKey::Tab,
671 )),
672 device_id: Some(0),
673 ..Default::default()
674 },
675 fidl_ui_input3::KeyEvent {
676 timestamp: Some(event_time_i64),
677 type_: Some(fidl_ui_input3::KeyEventType::Released),
679 key: Some(fidl_input::Key::Backspace),
680 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
681 fidl_ui_input3::NonPrintableKey::Backspace,
682 )),
683 device_id: Some(0),
684 ..Default::default()
685 },
686 ];
687
688 handle_events(ime_handler, input_events);
689 assert_ime_receives_events(expected_events, request_stream).await;
690 }
691
692 #[fasync::run_singlethreaded(test)]
693 async fn tab() {
694 let (proxy, request_stream) = connect_to_key_event_injector();
695 let inspector = fuchsia_inspect::Inspector::default();
696 let test_node = inspector.root().create_child("test_node");
697 let ime_handler =
698 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
699 .await
700 .expect("Failed to create ImeHandler.");
701
702 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
703 keyboard_binding::KeyboardDeviceDescriptor {
704 keys: vec![
705 fidl_input::Key::Enter,
706 fidl_input::Key::Tab,
707 fidl_input::Key::Backspace,
708 ],
709 device_id: 0,
710 ..Default::default()
711 },
712 );
713 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
714 let input_events = vec![create_unhandled_keyboard_event(
715 fidl_input::Key::Tab,
716 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
717 None,
718 event_time_u64,
719 &device_descriptor,
720 None,
721 )];
722
723 let expected_events = vec![fidl_ui_input3::KeyEvent {
724 timestamp: Some(event_time_i64),
725 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
726 key: Some(fidl_input::Key::Tab),
727 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
728 fidl_ui_input3::NonPrintableKey::Tab,
729 )),
730 device_id: Some(0),
731 ..Default::default()
732 }];
733
734 handle_events(ime_handler, input_events);
735 assert_ime_receives_events(expected_events, request_stream).await;
736 }
737
738 #[fasync::run_singlethreaded(test)]
739 async fn shift_shift_a() {
740 let (proxy, request_stream) = connect_to_key_event_injector();
741 let inspector = fuchsia_inspect::Inspector::default();
742 let test_node = inspector.root().create_child("test_node");
743 let ime_handler =
744 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
745 .await
746 .expect("Failed to create ImeHandler.");
747
748 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
749 keyboard_binding::KeyboardDeviceDescriptor {
750 keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
751 device_id: 0,
752 ..Default::default()
753 },
754 );
755 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
756 let input_events = vec![
757 create_unhandled_keyboard_event(
758 fidl_input::Key::LeftShift,
759 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
760 Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
761 event_time_u64,
762 &device_descriptor,
763 None,
764 ),
765 create_unhandled_keyboard_event(
766 fidl_input::Key::RightShift,
767 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
768 Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
769 event_time_u64,
770 &device_descriptor,
771 None,
772 ),
773 create_unhandled_keyboard_event(
774 fidl_input::Key::A,
775 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
776 Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
777 event_time_u64,
778 &device_descriptor,
779 None,
780 ),
781 ];
782
783 let expected_events = vec![
784 fidl_ui_input3::KeyEvent {
785 timestamp: Some(event_time_i64),
786 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
787 key: Some(fidl_input::Key::LeftShift),
788 modifiers: Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
789 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
790 fidl_ui_input3::NonPrintableKey::Shift,
791 )),
792 device_id: Some(0),
793 ..Default::default()
794 },
795 fidl_ui_input3::KeyEvent {
796 timestamp: Some(event_time_i64),
797 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
798 key: Some(fidl_input::Key::RightShift),
799 modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
800 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
801 fidl_ui_input3::NonPrintableKey::Shift,
802 )),
803 device_id: Some(0),
804 ..Default::default()
805 },
806 fidl_ui_input3::KeyEvent {
807 timestamp: Some(event_time_i64),
808 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
809 key: Some(fidl_input::Key::A),
810 modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
811 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)), device_id: Some(0),
813 ..Default::default()
814 },
815 ];
816
817 handle_events(ime_handler, input_events);
818 assert_ime_receives_events(expected_events, request_stream).await;
819 }
820
821 #[fasync::run_singlethreaded(test)]
822 async fn ctrl_tab() {
823 let (proxy, request_stream) = connect_to_key_event_injector();
824 let inspector = fuchsia_inspect::Inspector::default();
825 let test_node = inspector.root().create_child("test_node");
826 let ime_handler =
827 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
828 .await
829 .expect("Failed to create ImeHandler.");
830
831 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
832 keyboard_binding::KeyboardDeviceDescriptor {
833 keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
834 device_id: 0,
835 ..Default::default()
836 },
837 );
838 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
839 let input_events = vec![
840 create_unhandled_keyboard_event(
841 fidl_input::Key::LeftCtrl,
842 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
843 None,
844 event_time_u64,
845 &device_descriptor,
846 None,
847 ),
848 create_unhandled_keyboard_event(
849 fidl_input::Key::Tab,
850 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
851 None,
852 event_time_u64,
853 &device_descriptor,
854 None,
855 ),
856 ];
857
858 let expected_events = vec![
859 fidl_ui_input3::KeyEvent {
860 timestamp: Some(event_time_i64),
861 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
862 key: Some(fidl_input::Key::LeftCtrl),
863 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
864 fidl_ui_input3::NonPrintableKey::Control,
865 )),
866 device_id: Some(0),
867 ..Default::default()
868 },
869 fidl_ui_input3::KeyEvent {
870 timestamp: Some(event_time_i64),
871 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
872 key: Some(fidl_input::Key::Tab),
873 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
874 fidl_ui_input3::NonPrintableKey::Tab,
875 )),
876 device_id: Some(0),
877 ..Default::default()
878 },
879 ];
880
881 handle_events(ime_handler, input_events);
882 assert_ime_receives_events(expected_events, request_stream).await;
883 }
884
885 #[fasync::run_singlethreaded(test)]
886 async fn ime_handler_initialized_with_inspect_node() {
887 let (proxy, _) = connect_to_key_event_injector();
888 let inspector = fuchsia_inspect::Inspector::default();
889 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
890 let _handler =
891 ImeHandler::new_handler(proxy, &fake_handlers_node, metrics::MetricsLogger::default())
892 .await
893 .expect("Failed to create ImeHandler.");
894 diagnostics_assertions::assert_data_tree!(inspector, root: {
895 input_handlers_node: {
896 ime_handler: {
897 events_received_count: 0u64,
898 events_handled_count: 0u64,
899 last_received_timestamp_ns: 0u64,
900 "fuchsia.inspect.Health": {
901 status: "STARTING_UP",
902 start_timestamp_nanos: diagnostics_assertions::AnyProperty
905 },
906 }
907 }
908 });
909 }
910
911 #[fasync::run_singlethreaded(test)]
912 async fn ime_handler_inspect_counts_events() {
913 let (proxy, _) = connect_to_key_event_injector();
914 let inspector = fuchsia_inspect::Inspector::default();
915 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
916 let ime_handler =
917 ImeHandler::new_handler(proxy, &fake_handlers_node, metrics::MetricsLogger::default())
918 .await
919 .expect("Failed to create ImeHandler.");
920 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
921 keyboard_binding::KeyboardDeviceDescriptor {
922 keys: vec![fidl_input::Key::A, fidl_input::Key::B],
923 ..Default::default()
924 },
925 );
926 let (_, event_time_u64) = testing_utilities::event_times();
927 let input_events = vec![
928 testing_utilities::create_keyboard_event_with_time(
929 fidl_input::Key::A,
930 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
931 None,
932 event_time_u64,
933 &device_descriptor,
934 None,
935 ),
936 testing_utilities::create_keyboard_event_with_handled(
938 fidl_input::Key::B,
939 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
940 None,
941 event_time_u64,
942 &device_descriptor,
943 None,
944 None,
945 input_device::Handled::Yes,
946 ),
947 testing_utilities::create_keyboard_event_with_time(
948 fidl_input::Key::A,
949 fidl_fuchsia_ui_input3::KeyEventType::Released,
950 None,
951 event_time_u64,
952 &device_descriptor,
953 None,
954 ),
955 testing_utilities::create_fake_input_event(event_time_u64),
957 testing_utilities::create_keyboard_event_with_time(
958 fidl_input::Key::B,
959 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
960 None,
961 event_time_u64,
962 &device_descriptor,
963 None,
964 ),
965 ];
966
967 for input_event in input_events {
968 let _ = ime_handler.clone().handle_input_event(input_event).await;
969 }
970
971 let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
972
973 diagnostics_assertions::assert_data_tree!(inspector, root: {
974 input_handlers_node: {
975 ime_handler: {
976 events_received_count: 3u64,
977 events_handled_count: 3u64,
978 last_received_timestamp_ns: last_event_timestamp,
979 "fuchsia.inspect.Health": {
980 status: "STARTING_UP",
981 start_timestamp_nanos: diagnostics_assertions::AnyProperty
984 },
985 }
986 }
987 });
988 }
989
990 #[test_case(
991 keyboard_binding::KeyboardEvent::new(
992 fidl_input::Key::A,
993 fidl_ui_input3::KeyEventType::Pressed),
994 zx::MonotonicInstant::from_nanos(42) => fidl_ui_input3::KeyEvent{
995 timestamp: Some(42),
996 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
997 key: Some(fidl_input::Key::A),
998 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
999 device_id: Some(0),
1000 ..Default::default()}; "basic value copy")]
1001 #[test_case(
1002 keyboard_binding::KeyboardEvent::new(
1003 fidl_input::Key::A,
1004 fidl_ui_input3::KeyEventType::Pressed)
1005 .into_with_repeat_sequence(13),
1006 zx::MonotonicInstant::from_nanos(42) => fidl_ui_input3::KeyEvent{
1007 timestamp: Some(42),
1008 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
1009 key: Some(fidl_input::Key::A),
1010 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
1011 repeat_sequence: Some(13),
1012 device_id: Some(0),
1013 ..Default::default()}; "repeat_sequence is honored")]
1014 fn test_create_key_event(
1015 event: keyboard_binding::KeyboardEvent,
1016 event_time: zx::MonotonicInstant,
1017 ) -> fidl_ui_input3::KeyEvent {
1018 super::create_key_event(&event, event_time, 0)
1019 }
1020}