input_pipeline/
ime_handler.rs

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