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