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