Skip to main content

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