blob: 8c4f1cece591ca576783a84444ce493863a02622 [file] [log] [blame]
// 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,
);
}
}