Skip to main content

input_pipeline/
keyboard_binding.rs

1// Copyright 2019 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_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::{Dispatcher, Transport, metrics, utils};
7use anyhow::{Error, Result, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_ui_input3 as fidl_ui_input3;
10use fidl_fuchsia_ui_input3::KeyEventType;
11use fuchsia_inspect::health::Reporter;
12use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
13use metrics_registry::*;
14
15/// A [`KeyboardEvent`] represents an input event from a keyboard device.
16///
17/// The keyboard event contains information about a key event.  A key event represents a change in
18/// the key state. Clients can expect the following sequence of events for a given key:
19///
20/// 1. [`KeyEventType::Pressed`]: the key has transitioned to being pressed.
21/// 2. [`KeyEventType::Released`]: the key has transitioned to being released.
22///
23/// No duplicate [`KeyEventType::Pressed`] events will be sent for keys, even if the
24/// key is present in a subsequent [`InputReport`]. Clients can assume that
25/// a key is pressed for all received input events until the key is present in
26/// the [`KeyEventType::Released`] entry of [`keys`].
27///
28/// Use `new` to create.  Use `get_*` methods to read fields.  Use `into_with_*`
29/// methods to add optional information.
30#[derive(Clone, Debug, PartialEq)]
31pub struct KeyboardEvent {
32    /// The key that changed state in this [KeyboardEvent].
33    key: fidl_fuchsia_input::Key,
34
35    /// A description of what happened to `key`.
36    event_type: KeyEventType,
37
38    /// The [`fidl_ui_input3::Modifiers`] associated with the pressed keys.
39    modifiers: Option<fidl_ui_input3::Modifiers>,
40
41    /// The [`fidl_ui_input3::LockState`] currently computed.
42    lock_state: Option<fidl_ui_input3::LockState>,
43
44    /// If set, contains the unique identifier of the keymap to be used when or
45    /// if remapping the keypresses.
46    keymap: Option<String>,
47
48    /// If set, denotes the meaning of `key` in terms of the key effect.
49    /// A `KeyboardEvent` starts off with `key_meaning` unset, and the key
50    /// meaning is added in the input pipeline by the appropriate
51    /// keymap-aware input handlers.
52    key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
53
54    /// If this keyboard event has been generated as a result of a repeated
55    /// generation of the same key, then this will be a nonzero. A nonzero
56    /// value N here means that this is Nth generated autorepeat for this
57    /// keyboard event.  The counter is reset for each new autorepeat key
58    /// span.
59    repeat_sequence: u32,
60}
61
62impl KeyboardEvent {
63    /// Creates a new KeyboardEvent, with required fields filled out.  Use the
64    /// `into_with_*` methods to add optional information.
65    pub fn new(key: fidl_fuchsia_input::Key, event_type: KeyEventType) -> Self {
66        KeyboardEvent {
67            key,
68            event_type,
69            modifiers: None,
70            lock_state: None,
71            keymap: None,
72            key_meaning: None,
73            repeat_sequence: 0,
74        }
75    }
76
77    pub fn get_key(&self) -> fidl_fuchsia_input::Key {
78        self.key
79    }
80
81    /// Converts [KeyboardEvent] into the same one, but with specified key.
82    pub fn into_with_key(self, key: fidl_fuchsia_input::Key) -> Self {
83        Self { key, ..self }
84    }
85
86    pub fn get_event_type(&self) -> KeyEventType {
87        self.event_type
88    }
89
90    /// Converts [KeyboardEvent] into the same one, but with specified event type.
91    pub fn into_with_event_type(self, event_type: KeyEventType) -> Self {
92        Self { event_type, ..self }
93    }
94
95    /// Folds the key event type into an active event (Pressed, Released).
96    pub fn into_with_folded_event(self) -> Self {
97        Self { event_type: self.get_event_type_folded(), ..self }
98    }
99
100    /// Gets [KeyEventType], folding `SYNC` into `PRESSED` and `CANCEL` into `RELEASED`.
101    pub fn get_event_type_folded(&self) -> KeyEventType {
102        match self.event_type {
103            KeyEventType::Pressed | KeyEventType::Sync => KeyEventType::Pressed,
104            KeyEventType::Released | KeyEventType::Cancel => KeyEventType::Released,
105        }
106    }
107
108    /// Converts [KeyboardEvent] into the same one, but with specified modifiers.
109    pub fn into_with_modifiers(self, modifiers: Option<fidl_ui_input3::Modifiers>) -> Self {
110        Self { modifiers, ..self }
111    }
112
113    /// Returns the currently applicable modifiers.
114    pub fn get_modifiers(&self) -> Option<fidl_ui_input3::Modifiers> {
115        self.modifiers
116    }
117
118    /// Returns the currently applicable modifiers, with the sided modifiers removed.
119    ///
120    /// For example, if LEFT_SHIFT is pressed, returns SHIFT, rather than SHIFT | LEFT_SHIFT
121    pub fn get_unsided_modifiers(&self) -> fidl_fuchsia_ui_input3::Modifiers {
122        use fidl_fuchsia_ui_input3::Modifiers;
123        let mut modifiers = self.modifiers.unwrap_or(Modifiers::empty());
124        modifiers.set(
125            Modifiers::LEFT_ALT
126                | Modifiers::LEFT_CTRL
127                | Modifiers::LEFT_SHIFT
128                | Modifiers::LEFT_META
129                | Modifiers::RIGHT_ALT
130                | Modifiers::RIGHT_CTRL
131                | Modifiers::RIGHT_SHIFT
132                | Modifiers::RIGHT_META,
133            false,
134        );
135        modifiers
136    }
137
138    /// Converts [KeyboardEvent] into the same one, but with the specified lock state.
139    pub fn into_with_lock_state(self, lock_state: Option<fidl_ui_input3::LockState>) -> Self {
140        Self { lock_state, ..self }
141    }
142
143    /// Returns the currently applicable lock state.
144    pub fn get_lock_state(&self) -> Option<fidl_ui_input3::LockState> {
145        self.lock_state
146    }
147
148    /// Converts [KeyboardEvent] into the same one, but with the specified keymap
149    /// applied.
150    pub fn into_with_keymap(self, keymap: Option<String>) -> Self {
151        Self { keymap, ..self }
152    }
153
154    /// Returns the currently applied keymap.
155    pub fn get_keymap(&self) -> Option<String> {
156        self.keymap.clone()
157    }
158
159    /// Converts [KeyboardEvent] into the same one, but with the key meaning applied.
160    pub fn into_with_key_meaning(
161        self,
162        key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
163    ) -> Self {
164        Self { key_meaning, ..self }
165    }
166
167    /// Returns the currently valid key meaning.
168    pub fn get_key_meaning(&self) -> Option<fidl_fuchsia_ui_input3::KeyMeaning> {
169        self.key_meaning
170    }
171
172    /// Returns the repeat sequence number.  If a nonzero number N is returned,
173    /// that means this [KeyboardEvent] is the N-th generated autorepeat event.
174    /// A zero means this is an event that came from the keyboard driver.
175    pub fn get_repeat_sequence(&self) -> u32 {
176        self.repeat_sequence
177    }
178
179    /// Converts [KeyboardEvent] into the same one, but with the repeat sequence
180    /// changed.
181    pub fn into_with_repeat_sequence(self, repeat_sequence: u32) -> Self {
182        Self { repeat_sequence, ..self }
183    }
184
185    /// Centralizes the conversion from [KeyboardEvent] to `KeyEvent`.
186    #[cfg(test)]
187    pub(crate) fn from_key_event_at_time(
188        &self,
189        event_time: zx::MonotonicInstant,
190    ) -> fidl_ui_input3::KeyEvent {
191        fidl_ui_input3::KeyEvent {
192            timestamp: Some(event_time.into_nanos()),
193            type_: Some(self.event_type),
194            key: Some(self.key),
195            modifiers: self.modifiers,
196            lock_state: self.lock_state,
197            repeat_sequence: Some(self.repeat_sequence),
198            key_meaning: self.key_meaning,
199            ..Default::default()
200        }
201    }
202}
203
204impl KeyboardEvent {
205    /// Returns true if the two keyboard events are about the same key.
206    pub fn same_key(this: &KeyboardEvent, that: &KeyboardEvent) -> bool {
207        this.get_key() == that.get_key()
208    }
209}
210
211/// A [`KeyboardDeviceDescriptor`] contains information about a specific keyboard device.
212#[derive(Clone, Debug, PartialEq)]
213pub struct KeyboardDeviceDescriptor {
214    /// All the [`fidl_fuchsia_input::Key`]s available on the keyboard device.
215    pub keys: Vec<fidl_fuchsia_input::Key>,
216
217    /// The vendor ID, product ID and version.
218    pub device_information: fidl_fuchsia_input_report::DeviceInformation,
219
220    /// The unique identifier of this device.
221    pub device_id: u32,
222}
223
224#[cfg(test)]
225impl Default for KeyboardDeviceDescriptor {
226    fn default() -> Self {
227        KeyboardDeviceDescriptor {
228            keys: vec![],
229            device_information: fidl_fuchsia_input_report::DeviceInformation {
230                vendor_id: Some(0),
231                product_id: Some(0),
232                version: Some(0),
233                polling_rate: Some(0),
234                ..Default::default()
235            },
236            device_id: 0,
237        }
238    }
239}
240
241/// A [`KeyboardBinding`] represents a connection to a keyboard input device.
242///
243/// The [`KeyboardBinding`] parses and exposes keyboard device descriptor properties (e.g., the
244/// available keyboard keys) for the device it is associated with. It also parses [`InputReport`]s
245/// from the device, and sends them to the device binding owner over `event_sender`.
246pub struct KeyboardBinding {
247    /// The channel to stream InputEvents to.
248    event_sender: UnboundedSender<Vec<InputEvent>>,
249
250    /// Holds information about this device.
251    device_descriptor: KeyboardDeviceDescriptor,
252}
253
254#[async_trait]
255impl input_device::InputDeviceBinding for KeyboardBinding {
256    fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
257        self.event_sender.clone()
258    }
259
260    fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
261        input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone())
262    }
263}
264
265impl KeyboardBinding {
266    /// Creates a new [`InputDeviceBinding`] from the `device_proxy`.
267    ///
268    /// The binding will start listening for input reports immediately and send new InputEvents
269    /// to the device binding owner over `input_event_sender`.
270    ///
271    /// # Parameters
272    /// - `device_proxy`: The proxy to bind the new [`InputDeviceBinding`] to.
273    /// - `device_id`: The unique identifier of this device.
274    /// - `input_event_sender`: The channel to send new InputEvents to.
275    /// - `device_node`: The inspect node for this device binding
276    /// - `metrics_logger`: The metrics logger.
277    ///
278    /// # Errors
279    /// If there was an error binding to the proxy.
280    pub async fn new(
281        device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
282        device_id: u32,
283        input_event_sender: UnboundedSender<Vec<InputEvent>>,
284        device_node: fuchsia_inspect::Node,
285        feature_flags: input_device::InputPipelineFeatureFlags,
286        metrics_logger: metrics::MetricsLogger,
287    ) -> Result<Self, Error> {
288        let (device_binding, mut inspect_status) = Self::bind_device(
289            &device_proxy,
290            input_event_sender,
291            device_id,
292            device_node,
293            metrics_logger.clone(),
294        )
295        .await?;
296        inspect_status.health_node.set_ok();
297        input_device::initialize_report_stream(
298            device_proxy,
299            device_binding.get_device_descriptor(),
300            device_binding.input_event_sender(),
301            inspect_status,
302            metrics_logger.clone(),
303            feature_flags,
304            Self::process_reports,
305        );
306
307        Ok(device_binding)
308    }
309
310    /// Converts a vector of keyboard keys to the appropriate [`fidl_ui_input3::Modifiers`] bitflags.
311    ///
312    /// For example, if `keys` contains `Key::CapsLock`, the bitflags will contain the corresponding
313    /// flags for `CapsLock`.
314    ///
315    /// # Parameters
316    /// - `keys`: The keys to check for modifiers.
317    ///
318    /// # Returns
319    /// Returns `None` if there are no modifier keys present.
320    pub fn to_modifiers(keys: &[&fidl_fuchsia_input::Key]) -> Option<fidl_ui_input3::Modifiers> {
321        let mut modifiers = fidl_ui_input3::Modifiers::empty();
322        for key in keys {
323            let modifier = match key {
324                fidl_fuchsia_input::Key::CapsLock => Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
325                fidl_fuchsia_input::Key::NumLock => Some(fidl_ui_input3::Modifiers::NUM_LOCK),
326                fidl_fuchsia_input::Key::ScrollLock => Some(fidl_ui_input3::Modifiers::SCROLL_LOCK),
327                _ => None,
328            };
329            if let Some(modifier) = modifier {
330                modifiers.insert(modifier);
331            };
332        }
333        if modifiers.is_empty() {
334            return None;
335        }
336        Some(modifiers)
337    }
338
339    /// Binds the provided input device to a new instance of `Self`.
340    ///
341    /// # Parameters
342    /// - `device`: The device to use to initialize the binding.
343    /// - `input_event_sender`: The channel to send new InputEvents to.
344    /// - `device_id`: The device ID being bound.
345    /// - `device_node`: The inspect node for this device binding
346    ///
347    /// # Errors
348    /// If the device descriptor could not be retrieved, or the descriptor could not be parsed
349    /// correctly.
350    async fn bind_device(
351        device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
352        input_event_sender: UnboundedSender<Vec<InputEvent>>,
353        device_id: u32,
354        device_node: fuchsia_inspect::Node,
355        metrics_logger: metrics::MetricsLogger,
356    ) -> Result<(Self, InputDeviceStatus), Error> {
357        let mut input_device_status = InputDeviceStatus::new(device_node);
358        let descriptor = match device.get_descriptor().await {
359            Ok(descriptor) => descriptor.descriptor,
360            Err(_) => {
361                input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
362                return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
363            }
364        };
365
366        let device_info = descriptor.device_information.ok_or_else(|| {
367            input_device_status.health_node.set_unhealthy("Empty device_information in descriptor");
368            // Logging in addition to returning an error, as in some test
369            // setups the error may never be displayed to the user.
370            metrics_logger.log_error(
371                InputPipelineErrorMetricDimensionEvent::KeyboardEmptyDeviceInfo,
372                std::format!("DRIVER BUG: empty device_information for device_id: {}", device_id),
373            );
374            format_err!("empty device info for device_id: {}", device_id)
375        })?;
376        match descriptor.keyboard {
377            Some(fidl_next_fuchsia_input_report::KeyboardDescriptor {
378                input: Some(fidl_next_fuchsia_input_report::KeyboardInputDescriptor { keys3, .. }),
379                output: _,
380                ..
381            }) => Ok((
382                KeyboardBinding {
383                    event_sender: input_event_sender,
384                    device_descriptor: KeyboardDeviceDescriptor {
385                        keys: keys3
386                            .unwrap_or_default()
387                            .into_iter()
388                            .map(|k| utils::key_to_old(&k))
389                            .collect(),
390                        device_information: fidl_fuchsia_input_report::DeviceInformation {
391                            vendor_id: device_info.vendor_id,
392                            product_id: device_info.product_id,
393                            version: device_info.version,
394                            polling_rate: device_info.polling_rate,
395                            ..Default::default()
396                        },
397                        device_id,
398                    },
399                },
400                input_device_status,
401            )),
402            device_descriptor => {
403                input_device_status
404                    .health_node
405                    .set_unhealthy("Keyboard Device Descriptor failed to parse.");
406                Err(format_err!(
407                    "Keyboard Device Descriptor failed to parse: \n {:?}",
408                    device_descriptor
409                ))
410            }
411        }
412    }
413
414    /// Parses an [`InputReport`] into one or more [`InputEvent`]s.
415    ///
416    /// The [`InputEvent`]s are sent to the device binding owner via [`input_event_sender`].
417    ///
418    /// # Parameters
419    /// `reports`: The incoming [`InputReport`].
420    /// `previous_report`: The previous [`InputReport`] seen for the same device. This can be
421    ///                    used to determine, for example, which keys are no longer present in
422    ///                    a keyboard report to generate key released events. If `None`, no
423    ///                    previous report was found.
424    /// `device_descriptor`: The descriptor for the input device generating the input reports.
425    /// `input_event_sender`: The sender for the device binding's input event stream.
426    ///
427    /// # Returns
428    /// An [`InputReport`] which will be passed to the next call to [`process_reports`], as
429    /// [`previous_report`]. If `None`, the next call's [`previous_report`] will be `None`.
430    /// A [`UnboundedReceiver<InputEvent>`] which will poll asynchronously generated events to be
431    /// recorded by `inspect_status` in `input_device::initialize_report_stream()`. If device
432    /// binding does not generate InputEvents asynchronously, this will be `None`.
433    ///
434    /// The returned [`InputReport`] is guaranteed to have no `wake_lease`.
435    fn process_reports(
436        reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
437        mut previous_state: Option<input_device::PreviousDeviceState>,
438        device_descriptor: &input_device::InputDeviceDescriptor,
439        input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
440        inspect_status: &InputDeviceStatus,
441        metrics_logger: &metrics::MetricsLogger,
442        _feature_flags: &input_device::InputPipelineFeatureFlags,
443    ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
444        fuchsia_trace::duration!("input", "keyboard-binding-process-report", "num_reports" => reports.len());
445        let (inspect_sender, inspect_receiver) = futures::channel::mpsc::unbounded();
446
447        for report in reports {
448            previous_state = Self::process_report(
449                report,
450                previous_state,
451                device_descriptor,
452                input_event_sender,
453                inspect_status,
454                metrics_logger,
455                inspect_sender.clone(),
456            );
457        }
458        (previous_state, Some(inspect_receiver))
459    }
460
461    fn process_report(
462        report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
463        previous_state: Option<input_device::PreviousDeviceState>,
464        device_descriptor: &input_device::InputDeviceDescriptor,
465        input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
466        inspect_status: &InputDeviceStatus,
467        metrics_logger: &metrics::MetricsLogger,
468        inspect_sender: UnboundedSender<InputEvent>,
469    ) -> Option<input_device::PreviousDeviceState> {
470        if let Some(trace_id) = report.trace_id() {
471            fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
472        }
473
474        let tracing_id = fuchsia_trace::Id::new();
475        fuchsia_trace::flow_begin!("input", "key_event_thread", tracing_id);
476
477        inspect_status.count_received_report_wire(report);
478        // Input devices can have multiple types so ensure `report` is a KeyboardInputReport.
479        match report.keyboard() {
480            None => {
481                inspect_status.count_filtered_report();
482                return previous_state;
483            }
484            _ => (),
485        };
486
487        let new_keys = match KeyboardBinding::parse_pressed_keys_wire(report) {
488            Some(keys) => keys,
489            None => {
490                // It's OK for the report to contain an empty vector of keys, but it's not OK for
491                // the report to not have the appropriate fields set.
492                //
493                // In this case the report is treated as malformed, and the previous state is not
494                // updated.
495                metrics_logger.log_error(
496                    InputPipelineErrorMetricDimensionEvent::KeyboardFailedToParse,
497                    std::format!("Failed to parse keyboard keys: {:?}", report),
498                );
499                inspect_status.count_filtered_report();
500                return previous_state;
501            }
502        };
503
504        let previous_keys: Vec<fidl_fuchsia_input::Key> = match previous_state {
505            Some(input_device::PreviousDeviceState::Keyboard { pressed_keys }) => pressed_keys,
506            _ => vec![],
507        };
508
509        KeyboardBinding::send_key_events(
510            &new_keys,
511            &previous_keys,
512            device_descriptor.clone(),
513            zx::MonotonicInstant::get(),
514            input_event_sender.clone(),
515            inspect_sender,
516            metrics_logger,
517            tracing_id,
518        );
519
520        Some(input_device::PreviousDeviceState::Keyboard { pressed_keys: new_keys })
521    }
522
523    fn parse_pressed_keys_wire(
524        input_report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
525    ) -> Option<Vec<fidl_fuchsia_input::Key>> {
526        input_report
527            .keyboard()
528            .and_then(|unwrapped_keyboard| unwrapped_keyboard.pressed_keys3())
529            .map(|unwrapped_keys| {
530                unwrapped_keys
531                    .iter()
532                    .map(|&k| {
533                        let natural_key = fidl_next::FromWire::from_wire(k);
534                        utils::key_to_old(&natural_key)
535                    })
536                    .collect()
537            })
538    }
539
540    /// Sends key events to clients based on the new and previously pressed keys.
541    ///
542    /// # Parameters
543    /// - `new_keys`: The input3 keys which are currently pressed, as reported by the bound device.
544    /// - `previous_keys`: The input3 keys which were pressed in the previous input report.
545    /// - `device_descriptor`: The descriptor for the input device generating the input reports.
546    /// - `event_time`: The time in nanoseconds when the event was first recorded.
547    /// - `input_event_sender`: The sender for the device binding's input event stream.
548    fn send_key_events(
549        new_keys: &Vec<fidl_fuchsia_input::Key>,
550        previous_keys: &Vec<fidl_fuchsia_input::Key>,
551        device_descriptor: input_device::InputDeviceDescriptor,
552        event_time: zx::MonotonicInstant,
553        input_event_sender: UnboundedSender<Vec<InputEvent>>,
554        inspect_sender: UnboundedSender<input_device::InputEvent>,
555        metrics_logger: &metrics::MetricsLogger,
556        tracing_id: fuchsia_trace::Id,
557    ) {
558        // Dispatches all key events individually in a separate task.  This is done in a separate
559        // function so that the lifetime of `new_keys` above could be detached from that of the
560        // spawned task.
561        fn dispatch_events(
562            key_events: Vec<(fidl_fuchsia_input::Key, fidl_fuchsia_ui_input3::KeyEventType)>,
563            device_descriptor: input_device::InputDeviceDescriptor,
564            event_time: zx::MonotonicInstant,
565            input_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
566            inspect_sender: UnboundedSender<input_device::InputEvent>,
567            metrics_logger: metrics::MetricsLogger,
568            tracing_id: fuchsia_trace::Id,
569        ) {
570            Dispatcher::spawn_local(async move {
571                fuchsia_trace::duration!("input", "key_event_thread");
572                fuchsia_trace::flow_end!("input", "key_event_thread", tracing_id);
573
574                let mut event_time = event_time;
575                for (key, event_type) in key_events.into_iter() {
576                    let trace_id = fuchsia_trace::Id::new();
577                    fuchsia_trace::duration!("input", "keyboard_event_in_binding");
578                    fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
579
580                    let event = input_device::InputEvent {
581                        device_event: input_device::InputDeviceEvent::Keyboard(KeyboardEvent::new(
582                            key, event_type,
583                        )),
584                        device_descriptor: device_descriptor.clone(),
585                        event_time,
586                        handled: Handled::No,
587                        trace_id: Some(trace_id),
588                    };
589                    match input_event_sender.unbounded_send(vec![event.clone()]) {
590                        Err(error) => {
591                            metrics_logger.log_error(
592                                InputPipelineErrorMetricDimensionEvent::KeyboardFailedToSendKeyboardEvent,
593                                std::format!(
594                                    "Failed to send KeyboardEvent for key: {:?}, event_type: {:?}: {:?}",
595                                    key,
596                                    event_type,
597                                    error));
598                        }
599                        _ => {
600                            let _ = inspect_sender.unbounded_send(event).expect("Failed to count generated KeyboardEvent in Input Pipeline Inspect tree.");
601                        }
602                    }
603                    // If key events happen to have been reported at the same time,
604                    // we pull them apart artificially. A 1ns increment will likely
605                    // be enough of a difference that it is recognizable but that it
606                    // does not introduce confusion.
607                    event_time = event_time + zx::MonotonicDuration::from_nanos(1);
608                }
609            }).detach();
610        }
611
612        // Filter out the keys which were present in the previous keyboard report to avoid sending
613        // multiple `KeyEventType::Pressed` events for a key.
614        let pressed_keys = new_keys
615            .iter()
616            .cloned()
617            .filter(|key| !previous_keys.contains(key))
618            .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Pressed));
619
620        // Any key which is not present in the new keys, but was present in the previous report
621        // is considered to be released.
622        let released_keys = previous_keys
623            .iter()
624            .cloned()
625            .filter(|key| !new_keys.contains(key))
626            .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Released));
627
628        // It is important that key releases are dispatched before key presses,
629        // so that modifier tracking would work correctly.  We collect the result
630        // into a vector since an iterator is not Send and can not be moved into
631        // a closure.
632        let all_keys = released_keys.chain(pressed_keys).collect::<Vec<_>>();
633
634        dispatch_events(
635            all_keys,
636            device_descriptor,
637            event_time,
638            input_event_sender,
639            inspect_sender,
640            metrics_logger.clone(),
641            tracing_id,
642        );
643    }
644}
645
646#[cfg(test)]
647mod tests {
648    use super::*;
649    use crate::testing_utilities;
650    use fuchsia_async as fasync;
651    use futures::StreamExt;
652
653    /// Tests that a key that is present in the new report, but was not present in the previous report
654    /// is propagated as pressed.
655    #[fasync::run_singlethreaded(test)]
656    async fn pressed_key() {
657        let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
658            keys: vec![fidl_fuchsia_input::Key::A],
659            ..Default::default()
660        });
661        let (event_time_i64, _) = testing_utilities::event_times();
662
663        let reports = vec![testing_utilities::create_keyboard_input_report(
664            vec![fidl_fuchsia_input::Key::A],
665            event_time_i64,
666        )];
667        let expected_events = vec![testing_utilities::create_keyboard_event(
668            fidl_fuchsia_input::Key::A,
669            fidl_fuchsia_ui_input3::KeyEventType::Pressed,
670            None,
671            &descriptor,
672            /* keymap= */ None,
673        )];
674
675        assert_input_report_sequence_generates_events!(
676            input_reports: reports,
677            expected_events: expected_events,
678            device_descriptor: descriptor,
679            device_type: KeyboardBinding,
680        );
681    }
682
683    /// Tests that a key that is not present in the new report, but was present in the previous report
684    /// is propagated as released.
685    #[fasync::run_singlethreaded(test)]
686    async fn released_key() {
687        let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
688            keys: vec![fidl_fuchsia_input::Key::A],
689            ..Default::default()
690        });
691        let (event_time_i64, _) = testing_utilities::event_times();
692
693        let reports = vec![
694            testing_utilities::create_keyboard_input_report(
695                vec![fidl_fuchsia_input::Key::A],
696                event_time_i64,
697            ),
698            testing_utilities::create_keyboard_input_report(vec![], event_time_i64),
699        ];
700
701        let expected_events = vec![
702            testing_utilities::create_keyboard_event(
703                fidl_fuchsia_input::Key::A,
704                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
705                None,
706                &descriptor,
707                /* keymap= */ None,
708            ),
709            testing_utilities::create_keyboard_event(
710                fidl_fuchsia_input::Key::A,
711                fidl_fuchsia_ui_input3::KeyEventType::Released,
712                None,
713                &descriptor,
714                /* keymap= */ None,
715            ),
716        ];
717
718        assert_input_report_sequence_generates_events!(
719            input_reports: reports,
720            expected_events: expected_events,
721            device_descriptor: descriptor.clone(),
722            device_type: KeyboardBinding,
723        );
724    }
725
726    /// Tests that a key that is present in multiple consecutive input reports is not propagated
727    /// as a pressed event more than once.
728    #[fasync::run_singlethreaded(test)]
729    async fn multiple_pressed_event_filtering() {
730        let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
731            keys: vec![fidl_fuchsia_input::Key::A],
732            ..Default::default()
733        });
734        let (event_time_i64, _) = testing_utilities::event_times();
735
736        let reports = vec![
737            testing_utilities::create_keyboard_input_report(
738                vec![fidl_fuchsia_input::Key::A],
739                event_time_i64,
740            ),
741            testing_utilities::create_keyboard_input_report(
742                vec![fidl_fuchsia_input::Key::A],
743                event_time_i64,
744            ),
745        ];
746
747        let expected_events = vec![testing_utilities::create_keyboard_event(
748            fidl_fuchsia_input::Key::A,
749            fidl_fuchsia_ui_input3::KeyEventType::Pressed,
750            None,
751            &descriptor,
752            /* keymap= */ None,
753        )];
754
755        assert_input_report_sequence_generates_events!(
756            input_reports: reports,
757            expected_events: expected_events,
758            device_descriptor: descriptor,
759            device_type: KeyboardBinding,
760        );
761    }
762
763    /// Tests that both pressed and released keys are sent at once.
764    #[fasync::run_singlethreaded(test)]
765    async fn pressed_and_released_keys() {
766        let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
767            keys: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B],
768            ..Default::default()
769        });
770        let (event_time_i64, _) = testing_utilities::event_times();
771
772        let reports = vec![
773            testing_utilities::create_keyboard_input_report(
774                vec![fidl_fuchsia_input::Key::A],
775                event_time_i64,
776            ),
777            testing_utilities::create_keyboard_input_report(
778                vec![fidl_fuchsia_input::Key::B],
779                event_time_i64,
780            ),
781        ];
782
783        let expected_events = vec![
784            testing_utilities::create_keyboard_event(
785                fidl_fuchsia_input::Key::A,
786                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
787                None,
788                &descriptor,
789                /* keymap= */ None,
790            ),
791            testing_utilities::create_keyboard_event(
792                fidl_fuchsia_input::Key::A,
793                fidl_fuchsia_ui_input3::KeyEventType::Released,
794                None,
795                &descriptor,
796                /* keymap= */ None,
797            ),
798            testing_utilities::create_keyboard_event(
799                fidl_fuchsia_input::Key::B,
800                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
801                None,
802                &descriptor,
803                /* keymap= */ None,
804            ),
805        ];
806
807        assert_input_report_sequence_generates_events!(
808            input_reports: reports,
809            expected_events: expected_events,
810            device_descriptor: descriptor,
811            device_type: KeyboardBinding,
812        );
813    }
814
815    #[fuchsia::test]
816    fn get_unsided_modifiers() {
817        use fidl_ui_input3::Modifiers;
818        let event = KeyboardEvent::new(fidl_fuchsia_input::Key::A, KeyEventType::Pressed)
819            .into_with_modifiers(Some(Modifiers::all()));
820        assert_eq!(
821            event.get_unsided_modifiers(),
822            Modifiers::CAPS_LOCK
823                | Modifiers::NUM_LOCK
824                | Modifiers::SCROLL_LOCK
825                | Modifiers::FUNCTION
826                | Modifiers::SYMBOL
827                | Modifiers::SHIFT
828                | Modifiers::ALT
829                | Modifiers::ALT_GRAPH
830                | Modifiers::META
831                | Modifiers::CTRL
832        )
833    }
834
835    #[fuchsia::test]
836    fn conversion_fills_out_all_fields() {
837        use fidl_fuchsia_input::Key;
838        use fidl_ui_input3::{KeyMeaning, LockState, Modifiers, NonPrintableKey};
839        let event = KeyboardEvent::new(Key::A, KeyEventType::Pressed)
840            .into_with_modifiers(Some(Modifiers::all()))
841            .into_with_lock_state(Some(LockState::all()))
842            .into_with_repeat_sequence(42)
843            .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)));
844
845        let actual = event.from_key_event_at_time(zx::MonotonicInstant::from_nanos(42));
846        assert_eq!(
847            actual,
848            fidl_fuchsia_ui_input3::KeyEvent {
849                timestamp: Some(42),
850                type_: Some(KeyEventType::Pressed),
851                key: Some(Key::A),
852                modifiers: Some(Modifiers::all()),
853                key_meaning: Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)),
854                repeat_sequence: Some(42),
855                lock_state: Some(LockState::all()),
856                ..Default::default()
857            }
858        );
859    }
860}