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