| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| crate::input_device::{self, InputDeviceBinding}, |
| anyhow::{format_err, Error}, |
| async_trait::async_trait, |
| fidl_fuchsia_input, |
| fidl_fuchsia_input_report::{InputDeviceProxy, InputReport}, |
| fidl_fuchsia_ui_input2 as fidl_ui_input2, |
| fidl_fuchsia_ui_input2::KeyEventPhase, |
| fidl_fuchsia_ui_input3 as fidl_ui_input3, |
| fidl_fuchsia_ui_input3::KeyEventType, |
| fuchsia_async as fasync, |
| fuchsia_syslog::fx_log_err, |
| futures::{channel::mpsc::Sender, SinkExt}, |
| input_synthesis::usages::{is_modifier, is_modifier3}, |
| maplit::hashmap, |
| std::collections::HashMap, |
| }; |
| |
| /// A [`KeyboardEvent`] represents an input event from a keyboard device. |
| /// |
| /// The keyboard event contains information about which keys are pressed, and which |
| /// keys were released. |
| /// |
| /// Clients can expect the following sequence of events for a given key: |
| /// |
| /// 1. [`KeyEventType::Pressed`] |
| /// 2. [`KeyEventType::Released`] |
| /// |
| /// No duplicate [`KeyEventType::Pressed`] events will be sent for keys, even if the |
| /// key is present in a subsequent [`InputReport`]. Clients can assume that |
| /// a key is pressed for all received input events until the key is present in |
| /// the [`KeyEventType::Released`] entry of [`keys`]. |
| #[derive(Clone, Debug, PartialEq)] |
| pub struct KeyboardEvent { |
| /// The keys associated with this input event, sorted by their [`KeyEventPhase`] |
| /// (e.g., whether they are pressed or released). |
| pub keys2: HashMap<KeyEventPhase, Vec<fidl_ui_input2::Key>>, |
| |
| /// The keys associated with this input event, sorted by their [`KeyEventType`] |
| /// (e.g., whether they are pressed or released). |
| pub keys3: HashMap<KeyEventType, Vec<fidl_fuchsia_input::Key>>, |
| |
| /// The [`fidl_ui_input2::Modifiers`] associated with the pressed keys. |
| pub modifiers2: Option<fidl_ui_input2::Modifiers>, |
| |
| /// The [`fidl_ui_input3::Modifiers`] associated with the pressed keys. |
| pub modifiers3: Option<fidl_ui_input3::Modifiers>, |
| } |
| |
| impl KeyboardEvent { |
| /// Returns the [`fidl_ui_input2::Key`]s of the specified `phase`. |
| /// |
| /// # Parameters |
| /// `phase`: The phase of the keys to return. |
| pub fn get_keys2(&self, phase: KeyEventPhase) -> Vec<fidl_ui_input2::Key> { |
| let keys: Option<&Vec<fidl_ui_input2::Key>> = self.keys2.get(&phase); |
| if keys.is_some() { |
| return keys.unwrap().to_vec(); |
| } |
| |
| vec![] |
| } |
| |
| /// Returns the [`fidl_fuchsia_input::Key`]s of the specified `event_type`. |
| /// |
| /// # Parameters |
| /// `event_type`: The type of the keys to return. |
| pub fn get_keys3(&self, event_type: KeyEventType) -> Vec<fidl_fuchsia_input::Key> { |
| let keys: Option<&Vec<fidl_fuchsia_input::Key>> = self.keys3.get(&event_type); |
| if keys.is_some() { |
| return keys.unwrap().to_vec(); |
| } |
| |
| vec![] |
| } |
| } |
| |
| /// A [`KeyboardDeviceDescriptor`] contains information about a specific keyboard device. |
| #[derive(Clone, Debug, PartialEq)] |
| pub struct KeyboardDeviceDescriptor { |
| /// All the [`fidl_ui_input2::Key`]s available on the keyboard device. |
| pub keys2: Vec<fidl_ui_input2::Key>, |
| |
| /// All the [`fidl_fuchsia_input::Key`]s available on the keyboard device. |
| pub keys3: Vec<fidl_fuchsia_input::Key>, |
| } |
| |
| /// A [`KeyboardBinding`] represents a connection to a keyboard input device. |
| /// |
| /// The [`KeyboardBinding`] parses and exposes keyboard device descriptor properties (e.g., the |
| /// available keyboard keys) for the device it is associated with. It also parses [`InputReport`]s |
| /// from the device, and sends them to the device binding owner over `event_sender`. |
| pub struct KeyboardBinding { |
| /// The channel to stream InputEvents to. |
| event_sender: Sender<input_device::InputEvent>, |
| |
| /// Holds information about this device. |
| device_descriptor: KeyboardDeviceDescriptor, |
| } |
| |
| #[async_trait] |
| impl input_device::InputDeviceBinding for KeyboardBinding { |
| fn input_event_sender(&self) -> Sender<input_device::InputEvent> { |
| self.event_sender.clone() |
| } |
| |
| fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor { |
| input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone()) |
| } |
| } |
| |
| impl KeyboardBinding { |
| /// Creates a new [`InputDeviceBinding`] from the `device_proxy`. |
| /// |
| /// The binding will start listening for input reports immediately and send new InputEvents |
| /// to the device binding owner over `input_event_sender`. |
| /// |
| /// # Parameters |
| /// - `device_proxy`: The proxy to bind the new [`InputDeviceBinding`] to. |
| /// - `input_event_sender`: The channel to send new InputEvents to. |
| /// |
| /// # Errors |
| /// If there was an error binding to the proxy. |
| pub async fn new( |
| device_proxy: InputDeviceProxy, |
| input_event_sender: Sender<input_device::InputEvent>, |
| ) -> Result<Self, Error> { |
| let device_binding = Self::bind_device(&device_proxy, input_event_sender).await?; |
| input_device::initialize_report_stream( |
| device_proxy, |
| device_binding.get_device_descriptor(), |
| device_binding.input_event_sender(), |
| Self::process_reports, |
| ); |
| |
| Ok(device_binding) |
| } |
| |
| /// Converts a vector of keyboard keys to the appropriate [`fidl_ui_input2::Modifiers`] bitflags. |
| /// |
| /// For example, if `keys` contains `Key::LeftAlt`, the bitflags will contain the corresponding |
| /// flags for `LeftAlt`. |
| /// |
| /// # Parameters |
| /// - `keys`: The keys to check for modifiers. |
| /// |
| /// # Returns |
| /// Returns `None` if there are no modifier keys present. |
| pub fn to_modifiers2(keys: &Vec<&fidl_ui_input2::Key>) -> Option<fidl_ui_input2::Modifiers> { |
| let mut modifiers = fidl_ui_input2::Modifiers::empty(); |
| for key in keys { |
| let modifier = match key { |
| fidl_ui_input2::Key::LeftAlt => { |
| Some(fidl_ui_input2::Modifiers::Alt | fidl_ui_input2::Modifiers::LeftAlt) |
| } |
| fidl_ui_input2::Key::RightAlt => { |
| Some(fidl_ui_input2::Modifiers::Alt | fidl_ui_input2::Modifiers::RightAlt) |
| } |
| fidl_ui_input2::Key::LeftShift => { |
| Some(fidl_ui_input2::Modifiers::Shift | fidl_ui_input2::Modifiers::LeftShift) |
| } |
| fidl_ui_input2::Key::RightShift => { |
| Some(fidl_ui_input2::Modifiers::Shift | fidl_ui_input2::Modifiers::RightShift) |
| } |
| fidl_ui_input2::Key::LeftCtrl => Some( |
| fidl_ui_input2::Modifiers::Control | fidl_ui_input2::Modifiers::LeftControl, |
| ), |
| fidl_ui_input2::Key::RightCtrl => Some( |
| fidl_ui_input2::Modifiers::Control | fidl_ui_input2::Modifiers::RightControl, |
| ), |
| fidl_ui_input2::Key::LeftMeta => { |
| Some(fidl_ui_input2::Modifiers::Meta | fidl_ui_input2::Modifiers::LeftMeta) |
| } |
| fidl_ui_input2::Key::RightMeta => { |
| Some(fidl_ui_input2::Modifiers::Meta | fidl_ui_input2::Modifiers::RightMeta) |
| } |
| fidl_ui_input2::Key::CapsLock => Some(fidl_ui_input2::Modifiers::CapsLock), |
| fidl_ui_input2::Key::NumLock => Some(fidl_ui_input2::Modifiers::NumLock), |
| fidl_ui_input2::Key::ScrollLock => Some(fidl_ui_input2::Modifiers::ScrollLock), |
| _ => None, |
| }; |
| if let Some(modifier) = modifier { |
| modifiers.insert(modifier); |
| }; |
| } |
| if modifiers.is_empty() { |
| return None; |
| } |
| Some(modifiers) |
| } |
| |
| /// Converts a vector of keyboard keys to the appropriate [`fidl_ui_input3::Modifiers`] bitflags. |
| /// |
| /// For example, if `keys` contains `Key::CapsLock`, the bitflags will contain the corresponding |
| /// flags for `CapsLock`. |
| /// |
| /// # Parameters |
| /// - `keys`: The keys to check for modifiers. |
| /// |
| /// # Returns |
| /// Returns `None` if there are no modifier keys present. |
| pub fn to_modifiers3( |
| keys: &Vec<&fidl_fuchsia_input::Key>, |
| ) -> Option<fidl_ui_input3::Modifiers> { |
| let mut modifiers = fidl_ui_input3::Modifiers::empty(); |
| for key in keys { |
| let modifier = match key { |
| fidl_fuchsia_input::Key::CapsLock => Some(fidl_ui_input3::Modifiers::CapsLock), |
| fidl_fuchsia_input::Key::NumLock => Some(fidl_ui_input3::Modifiers::NumLock), |
| fidl_fuchsia_input::Key::ScrollLock => Some(fidl_ui_input3::Modifiers::ScrollLock), |
| _ => None, |
| }; |
| if let Some(modifier) = modifier { |
| modifiers.insert(modifier); |
| }; |
| } |
| if modifiers.is_empty() { |
| return None; |
| } |
| Some(modifiers) |
| } |
| |
| /// Binds the provided input device to a new instance of `Self`. |
| /// |
| /// # Parameters |
| /// - `device`: The device to use to initalize the binding. |
| /// - `input_event_sender`: The channel to send new InputEvents to. |
| /// |
| /// # Errors |
| /// If the device descriptor could not be retrieved, or the descriptor could not be parsed |
| /// correctly. |
| async fn bind_device( |
| device: &InputDeviceProxy, |
| input_event_sender: Sender<input_device::InputEvent>, |
| ) -> Result<Self, Error> { |
| match device.get_descriptor().await?.keyboard { |
| Some(fidl_fuchsia_input_report::KeyboardDescriptor { |
| input: |
| Some(fidl_fuchsia_input_report::KeyboardInputDescriptor { |
| keys: keys2, keys3, .. |
| }), |
| output: _, |
| .. |
| }) => Ok(KeyboardBinding { |
| event_sender: input_event_sender, |
| device_descriptor: KeyboardDeviceDescriptor { |
| keys2: keys2.unwrap_or_default(), |
| keys3: keys3.unwrap_or_default(), |
| }, |
| }), |
| device_descriptor => Err(format_err!( |
| "Keyboard Device Descriptor failed to parse: \n {:?}", |
| device_descriptor |
| )), |
| } |
| } |
| |
| /// Parses an [`InputReport`] into one or more [`InputEvent`]s. |
| /// |
| /// The [`InputEvent`]s are sent to the device binding owner via [`input_event_sender`]. |
| /// |
| /// # Parameters |
| /// `report`: The incoming [`InputReport`]. |
| /// `previous_report`: The previous [`InputReport`] seen for the same device. This can be |
| /// used to determine, for example, which keys are no longer present in |
| /// a keyboard report to generate key released events. If `None`, no |
| /// previous report was found. |
| /// `device_descriptor`: The descriptor for the input device generating the input reports. |
| /// `input_event_sender`: The sender for the device binding's input event stream. |
| /// |
| /// # Returns |
| /// An [`InputReport`] which will be passed to the next call to [`process_reports`], as |
| /// [`previous_report`]. If `None`, the next call's [`previous_report`] will be `None`. |
| fn process_reports( |
| report: InputReport, |
| previous_report: Option<InputReport>, |
| device_descriptor: &input_device::InputDeviceDescriptor, |
| input_event_sender: &mut Sender<input_device::InputEvent>, |
| ) -> Option<InputReport> { |
| // Input devices can have multiple types so ensure `report` is a KeyboardInputReport. |
| match &report.keyboard { |
| None => return previous_report, |
| _ => (), |
| }; |
| |
| let new_keys2 = match KeyboardBinding::parse_pressed_keys2(&report) { |
| Some(keys) => keys, |
| None => { |
| // It's OK for the report to contain an empty vector of keys, but it's not OK for |
| // the report to not have the appropriate fields set. |
| // |
| // In this case the report is treated as malformed, and the previous report is not |
| // updated. |
| fx_log_err!("Failed to parse keyboard keys: {:?}", report); |
| return previous_report; |
| } |
| }; |
| |
| let new_keys3 = match KeyboardBinding::parse_pressed_keys3(&report) { |
| Some(keys) => keys, |
| None => { |
| // It's OK for the report to contain an empty vector of keys, but it's not OK for |
| // the report to not have the appropriate fields set. |
| // |
| // In this case the report is treated as malformed, and the previous report is not |
| // updated. |
| fx_log_err!("Failed to parse keyboard keys: {:?}", report); |
| return previous_report; |
| } |
| }; |
| |
| // For the previous keys it's OK to not be able to parse the keys, since an empty vector is |
| // a sensible default (this is what happens when there is no previous report). |
| let previous_keys2: Vec<fidl_ui_input2::Key> = previous_report |
| .as_ref() |
| .and_then(|unwrapped_report| KeyboardBinding::parse_pressed_keys2(&unwrapped_report)) |
| .unwrap_or_default(); |
| let previous_keys3: Vec<fidl_fuchsia_input::Key> = previous_report |
| .as_ref() |
| .and_then(|unwrapped_report| KeyboardBinding::parse_pressed_keys3(&unwrapped_report)) |
| .unwrap_or_default(); |
| |
| let event_time: input_device::EventTime = |
| input_device::event_time_or_now(report.event_time); |
| |
| KeyboardBinding::send_key_events( |
| &new_keys2, |
| &new_keys3, |
| &previous_keys2, |
| &previous_keys3, |
| device_descriptor.clone(), |
| event_time, |
| input_event_sender.clone(), |
| ); |
| |
| Some(report) |
| } |
| |
| /// Parses the currently pressed [`fidl_ui_input2::Key`]s from an input report. |
| /// |
| /// # Parameters |
| /// - `input_report`: The input report to parse the keyboard keys from. |
| /// |
| /// # Returns |
| /// Returns `None` if any of the required input report fields are `None`. If all the |
| /// required report fields are present, but there are no pressed keys, an empty vector |
| /// is returned. |
| fn parse_pressed_keys2(input_report: &InputReport) -> Option<Vec<fidl_ui_input2::Key>> { |
| input_report |
| .keyboard |
| .as_ref() |
| .and_then(|unwrapped_keyboard| unwrapped_keyboard.pressed_keys.as_ref()) |
| .and_then(|unwrapped_keys| Some(unwrapped_keys.iter().cloned().collect())) |
| } |
| |
| /// Parses the currently pressed [`fidl_fuchsia_input3::Key`]s from an input report. |
| /// |
| /// # Parameters |
| /// - `input_report`: The input report to parse the keyboard keys from. |
| /// |
| /// # Returns |
| /// Returns `None` if any of the required input report fields are `None`. If all the |
| /// required report fields are present, but there are no pressed keys, an empty vector |
| /// is returned. |
| fn parse_pressed_keys3(input_report: &InputReport) -> Option<Vec<fidl_fuchsia_input::Key>> { |
| input_report |
| .keyboard |
| .as_ref() |
| .and_then(|unwrapped_keyboard| unwrapped_keyboard.pressed_keys3.as_ref()) |
| .and_then(|unwrapped_keys| Some(unwrapped_keys.iter().cloned().collect())) |
| } |
| |
| /// Sends key events to clients based on the new and previously pressed keys. |
| /// |
| /// # Parameters |
| /// - `new_keys2`: The input2 keys which are currently pressed, as reported by the bound device. |
| /// - `new_keys3`: The input3 keys which are currently pressed, as reported by the bound device. |
| /// - `previous_keys2`: The input2 keys which were pressed in the previous input report. |
| /// - `previous_keys3`: The input3 keys which were pressed in the previous input report. |
| /// - `device_descriptor`: The descriptor for the input device generating the input reports. |
| /// - `event_time`: The time in nanoseconds when the event was first recorded. |
| /// - `input_event_sender`: The sender for the device binding's input event stream. |
| fn send_key_events( |
| new_keys2: &Vec<fidl_ui_input2::Key>, |
| new_keys3: &Vec<fidl_fuchsia_input::Key>, |
| previous_keys2: &Vec<fidl_ui_input2::Key>, |
| previous_keys3: &Vec<fidl_fuchsia_input::Key>, |
| device_descriptor: input_device::InputDeviceDescriptor, |
| event_time: input_device::EventTime, |
| mut input_event_sender: Sender<input_device::InputEvent>, |
| ) { |
| // Filter out the keys which were present in the previous keyboard report to avoid sending |
| // multiple `KeyEventType::Pressed` events for a key. |
| let pressed_keys2: Vec<fidl_ui_input2::Key> = |
| new_keys2.iter().cloned().filter(|key| !previous_keys2.contains(key)).collect(); |
| let pressed_keys3: Vec<fidl_fuchsia_input::Key> = |
| new_keys3.iter().cloned().filter(|key| !previous_keys3.contains(key)).collect(); |
| |
| // Any key which is not present in the new keys, but was present in the previous report |
| // is considered to be released. |
| let released_keys2: Vec<fidl_ui_input2::Key> = |
| previous_keys2.iter().cloned().filter(|key| !new_keys2.contains(key)).collect(); |
| let released_keys3: Vec<fidl_fuchsia_input::Key> = |
| previous_keys3.iter().cloned().filter(|key| !new_keys3.contains(key)).collect(); |
| |
| let keys_to_send2 = hashmap! { |
| KeyEventPhase::Pressed => pressed_keys2, |
| KeyEventPhase::Released => released_keys2, |
| }; |
| let keys_to_send3 = hashmap! { |
| KeyEventType::Pressed => pressed_keys3, |
| KeyEventType::Released => released_keys3, |
| }; |
| |
| // Track any pressed modifiers. |
| let modifiers2: Option<fidl_ui_input2::Modifiers> = KeyboardBinding::to_modifiers2( |
| &new_keys2.iter().filter(|key| is_modifier(**key)).collect(), |
| ); |
| let modifiers3: Option<fidl_ui_input3::Modifiers> = KeyboardBinding::to_modifiers3( |
| &new_keys3.iter().filter(|key| is_modifier3(**key)).collect(), |
| ); |
| |
| fasync::Task::spawn(async move { |
| match input_event_sender |
| .send(input_device::InputEvent { |
| device_event: input_device::InputDeviceEvent::Keyboard(KeyboardEvent { |
| keys2: keys_to_send2, |
| keys3: keys_to_send3, |
| modifiers2, |
| modifiers3, |
| }), |
| device_descriptor, |
| event_time, |
| }) |
| .await |
| { |
| Err(error) => { |
| fx_log_err!("Failed to send keyboard key events: {:?}", error); |
| } |
| _ => (), |
| } |
| }) |
| .detach(); |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use {super::*, crate::testing_utilities, fuchsia_async as fasync, futures::StreamExt}; |
| |
| /// Tests that a key that is present in the new report, but was not present in the previous report |
| /// is propagated as pressed. |
| #[fasync::run_singlethreaded(test)] |
| async fn pressed_key() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::A], |
| keys3: vec![fidl_fuchsia_input::Key::A], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| )]; |
| let expected_events = vec![testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| vec![], |
| vec![], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| )]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that a key that is not present in the new report, but was present in the previous report |
| /// is propagated as released. |
| #[fasync::run_singlethreaded(test)] |
| async fn released_key() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::A], |
| keys3: vec![fidl_fuchsia_input::Key::A], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![ |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| testing_utilities::create_keyboard_input_report(vec![], vec![], event_time_i64), |
| ]; |
| |
| let expected_events = vec![ |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| vec![], |
| vec![], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| testing_utilities::create_keyboard_event( |
| vec![], |
| vec![], |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| ]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor.clone(), |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that a key that is present in multiple consecutive input reports is not propagated |
| /// as a pressed event more than once. |
| #[fasync::run_singlethreaded(test)] |
| async fn multiple_pressed_event_filtering() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::A], |
| keys3: vec![fidl_fuchsia_input::Key::A], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![ |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| ]; |
| |
| let expected_events = vec![ |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| vec![], |
| vec![], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| testing_utilities::create_keyboard_event( |
| vec![], |
| vec![], |
| vec![], |
| vec![], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| ]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that both pressed and released keys are sent at once. |
| #[fasync::run_singlethreaded(test)] |
| async fn pressed_and_released_keys() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::A, fidl_ui_input2::Key::B], |
| keys3: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![ |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::B], |
| vec![fidl_fuchsia_input::Key::B], |
| event_time_i64, |
| ), |
| ]; |
| |
| let expected_events = vec![ |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| vec![], |
| vec![], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::B], |
| vec![fidl_fuchsia_input::Key::B], |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| ]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that input2 modifier keys are propagated to the event receiver. |
| #[fasync::run_singlethreaded(test)] |
| async fn input2_modifier_keys() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::LeftShift], |
| keys3: vec![fidl_fuchsia_input::Key::LeftShift], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::LeftShift], |
| vec![fidl_fuchsia_input::Key::LeftShift], |
| event_time_i64, |
| )]; |
| |
| let expected_events = vec![testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::LeftShift], |
| vec![fidl_fuchsia_input::Key::LeftShift], |
| vec![], |
| vec![], |
| Some(fidl_ui_input2::Modifiers::Shift | fidl_ui_input2::Modifiers::LeftShift), |
| None, // Shift is not a supported modifier in input3 |
| event_time_u64, |
| &descriptor, |
| )]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that input3 modifier keys are propagated to the event receiver. |
| #[fasync::run_singlethreaded(test)] |
| async fn input3_modifier_keys() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::CapsLock], |
| keys3: vec![fidl_fuchsia_input::Key::CapsLock], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::CapsLock], |
| vec![fidl_fuchsia_input::Key::CapsLock], |
| event_time_i64, |
| )]; |
| |
| let expected_events = vec![testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::CapsLock], |
| vec![fidl_fuchsia_input::Key::CapsLock], |
| vec![], |
| vec![], |
| Some(fidl_ui_input2::Modifiers::CapsLock), |
| Some(fidl_ui_input3::Modifiers::CapsLock), |
| event_time_u64, |
| &descriptor, |
| )]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| |
| /// Tests that a modifier key applies to all subsequent events until the modifier key is |
| /// released. |
| #[fasync::run_singlethreaded(test)] |
| async fn repeated_modifier_key() { |
| let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor { |
| keys2: vec![fidl_ui_input2::Key::CapsLock, fidl_ui_input2::Key::A], |
| keys3: vec![fidl_fuchsia_input::Key::CapsLock, fidl_fuchsia_input::Key::A], |
| }); |
| let (event_time_i64, event_time_u64) = testing_utilities::event_times(); |
| |
| let reports = vec![ |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::CapsLock], |
| vec![fidl_fuchsia_input::Key::CapsLock], |
| event_time_i64, |
| ), |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::CapsLock, fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::CapsLock, fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| testing_utilities::create_keyboard_input_report( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| event_time_i64, |
| ), |
| ]; |
| |
| let expected_events = vec![ |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::CapsLock], |
| vec![fidl_fuchsia_input::Key::CapsLock], |
| vec![], |
| vec![], |
| Some(fidl_ui_input2::Modifiers::CapsLock), |
| Some(fidl_ui_input3::Modifiers::CapsLock), |
| event_time_u64, |
| &descriptor, |
| ), |
| testing_utilities::create_keyboard_event( |
| vec![fidl_ui_input2::Key::A], |
| vec![fidl_fuchsia_input::Key::A], |
| vec![], |
| vec![], |
| Some(fidl_ui_input2::Modifiers::CapsLock), |
| Some(fidl_ui_input3::Modifiers::CapsLock), |
| event_time_u64, |
| &descriptor, |
| ), |
| testing_utilities::create_keyboard_event( |
| vec![], |
| vec![], |
| vec![fidl_ui_input2::Key::CapsLock], |
| vec![fidl_fuchsia_input::Key::CapsLock], |
| None, |
| None, |
| event_time_u64, |
| &descriptor, |
| ), |
| ]; |
| |
| assert_input_report_sequence_generates_events!( |
| input_reports: reports, |
| expected_events: expected_events, |
| device_descriptor: descriptor, |
| device_type: KeyboardBinding, |
| ); |
| } |
| } |