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