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