blob: 12526d8a4030657dc039205f7973a17993145039 [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_report::{InputDeviceProxy, InputReport},
fidl_fuchsia_ui_input2::{Key, KeyEventPhase, Modifiers},
fuchsia_async as fasync,
fuchsia_syslog::fx_log_err,
futures::{
channel::mpsc::{Receiver, Sender},
SinkExt, StreamExt,
},
input_synthesis::usages::is_modifier,
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. [`KeyEventPhase::Pressed`]
/// 2. [`KeyEventPhase::Released`]
///
/// No duplicate [`KeyEventPhase::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 [`KeyEventPhase::Released`] entry of [`keys`].
#[derive(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 keys: HashMap<KeyEventPhase, Vec<Key>>,
/// The modifiers associated with the pressed keys.
pub modifiers: Option<Modifiers>,
}
impl KeyboardEvent {
/// Returns the keys of the specified `phase`.
///
/// # Parameters
/// `phase`: The phase of the keys to return.
pub fn get_keys(&self, phase: KeyEventPhase) -> Vec<Key> {
let keys: Option<&Vec<Key>> = self.keys.get(&phase);
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 keys available on the keyboard device.
pub keys: Vec<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 clients via the stream available at
/// [`KeyboardBinding::input_event_stream()`].
///
/// # Example
/// ```
/// let mut keyboard_device: KeyboardBinding = input_device::InputDeviceBinding::new().await?;
///
/// while let Some(report) = keyboard_device.input_event_stream().next().await {}
/// ```
pub struct KeyboardBinding {
/// The channel to stream InputEvents to.
event_sender: Sender<input_device::InputEvent>,
/// The receiving end of the input event channel. Clients use this indirectly via
/// [`input_event_stream()`].
event_receiver: Receiver<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 input_event_stream(&mut self) -> &mut Receiver<input_device::InputEvent> {
return &mut self.event_receiver;
}
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone())
}
fn process_reports(
report: InputReport,
previous_report: Option<InputReport>,
device_descriptor: &input_device::InputDeviceDescriptor,
input_event_sender: &mut Sender<input_device::InputEvent>,
) -> Option<InputReport> {
let new_keys = match KeyboardBinding::parse_pressed_keys(&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_keys: Vec<Key> = previous_report
.as_ref()
.and_then(|unwrapped_report| KeyboardBinding::parse_pressed_keys(&unwrapped_report))
.unwrap_or_default();
KeyboardBinding::send_key_events(
&new_keys,
&previous_keys,
device_descriptor.clone(),
input_event_sender.clone(),
);
Some(report)
}
async fn any_input_device() -> Result<InputDeviceProxy, Error> {
let mut devices = Self::all_devices().await?;
devices.pop().ok_or(format_err!("Couldn't find a default keyboard."))
}
async fn all_devices() -> Result<Vec<InputDeviceProxy>, Error> {
input_device::all_devices(input_device::InputDeviceType::Keyboard).await
}
async fn bind_device(device: &InputDeviceProxy) -> Result<Self, Error> {
match device.get_descriptor().await?.keyboard {
Some(fidl_fuchsia_input_report::KeyboardDescriptor {
input: Some(fidl_fuchsia_input_report::KeyboardInputDescriptor { keys }),
output: _,
}) => {
let (event_sender, event_receiver) =
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
Ok(KeyboardBinding {
event_sender,
event_receiver,
device_descriptor: KeyboardDeviceDescriptor { keys: keys.unwrap_or_default() },
})
}
device_descriptor => Err(format_err!(
"Keyboard Device Descriptor failed to parse: \n {:?}",
device_descriptor
)),
}
}
}
/// Returns a vector of [`KeyboardBindings`] for all currently connected keyboards.
///
/// # Errors
/// If there was an error binding to any keyboard.
pub async fn all_keyboard_bindings() -> Result<Vec<KeyboardBinding>, Error> {
let device_proxies = input_device::all_devices(input_device::InputDeviceType::Keyboard).await?;
let mut device_bindings: Vec<KeyboardBinding> = vec![];
for device_proxy in device_proxies {
let device_binding: KeyboardBinding =
input_device::InputDeviceBinding::new(device_proxy).await?;
device_bindings.push(device_binding);
}
Ok(device_bindings)
}
/// Returns a stream of InputEvents from all keyboard devices.
///
/// # Errors
/// If there was an error binding to any keyboard.
pub async fn all_keyboard_events() -> Result<Receiver<input_device::InputEvent>, Error> {
let bindings = all_keyboard_bindings().await?;
let (event_sender, event_receiver) =
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
for mut keyboard in bindings {
let mut sender = event_sender.clone();
fasync::spawn(async move {
while let Some(input_event) = keyboard.input_event_stream().next().await {
let _ = sender.try_send(input_event);
}
});
}
Ok(event_receiver)
}
impl KeyboardBinding {
/// Converts a vector of keyboard keys to the appropriate [`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_modifiers(keys: &Vec<&Key>) -> Option<Modifiers> {
let mut modifiers = Modifiers::empty();
for key in keys {
let modifier = match key {
Key::LeftAlt => Some(Modifiers::Alt | Modifiers::LeftAlt),
Key::RightAlt => Some(Modifiers::Alt | Modifiers::RightAlt),
Key::LeftShift => Some(Modifiers::Shift | Modifiers::LeftShift),
Key::RightShift => Some(Modifiers::Shift | Modifiers::RightShift),
Key::LeftCtrl => Some(Modifiers::Control | Modifiers::LeftControl),
Key::RightCtrl => Some(Modifiers::Control | Modifiers::RightControl),
Key::LeftMeta => Some(Modifiers::Meta | Modifiers::LeftMeta),
Key::RightMeta => Some(Modifiers::Meta | Modifiers::RightMeta),
Key::CapsLock => Some(Modifiers::CapsLock),
Key::NumLock => Some(Modifiers::NumLock),
Key::ScrollLock => Some(Modifiers::ScrollLock),
_ => None,
};
if let Some(modifier) = modifier {
modifiers.insert(modifier);
};
}
if modifiers.is_empty() {
return None;
}
Some(modifiers)
}
/// Parses the currently pressed keys 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_keys(input_report: &InputReport) -> Option<Vec<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()))
}
/// Sends key events to clients based on the new and previously pressed keys.
///
/// # Parameters
/// - `new_keys`: The keys which are currently pressed, as reported by the bound device.
/// - `previous_keys`: The keys which were pressed in the previous input report.
fn send_key_events(
new_keys: &Vec<Key>,
previous_keys: &Vec<Key>,
device_descriptor: input_device::InputDeviceDescriptor,
mut input_event_sender: Sender<input_device::InputEvent>,
) {
// Filter out the keys which were present in the previous keyboard report to avoid sending
// multiple `KeyEventPhase::Pressed` events for a key.
let pressed_keys: Vec<Key> =
new_keys.iter().cloned().filter(|key| !previous_keys.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_keys: Vec<Key> =
previous_keys.iter().cloned().filter(|key| !new_keys.contains(key)).collect();
let keys_to_send = hashmap! {
KeyEventPhase::Pressed => pressed_keys,
KeyEventPhase::Released => released_keys,
};
// Track any pressed modifiers.
let modifiers: Option<Modifiers> = KeyboardBinding::to_modifiers(
&new_keys.iter().filter(|key| is_modifier(**key)).collect(),
);
fasync::spawn(async move {
match input_event_sender
.send(input_device::InputEvent {
device_event: input_device::InputDeviceEvent::Keyboard(KeyboardEvent {
keys: keys_to_send,
modifiers: modifiers,
}),
device_descriptor,
})
.await
{
Err(error) => {
fx_log_err!("Failed to send keyboard key events: {:?}", error);
}
_ => (),
}
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing_utilities;
/// 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 {
keys: vec![Key::A],
});
let reports = vec![testing_utilities::create_keyboard_input_report(vec![Key::A])];
let expected_events =
vec![testing_utilities::create_keyboard_event(vec![Key::A], vec![], None, &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 {
keys: vec![Key::A],
});
let reports = vec![
testing_utilities::create_keyboard_input_report(vec![Key::A]),
testing_utilities::create_keyboard_input_report(vec![]),
];
let expected_events = vec![
testing_utilities::create_keyboard_event(vec![Key::A], vec![], None, &descriptor),
testing_utilities::create_keyboard_event(vec![], vec![Key::A], None, &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 {
keys: vec![Key::A],
});
let reports = vec![
testing_utilities::create_keyboard_input_report(vec![Key::A]),
testing_utilities::create_keyboard_input_report(vec![Key::A]),
];
let expected_events = vec![
testing_utilities::create_keyboard_event(vec![Key::A], vec![], None, &descriptor),
testing_utilities::create_keyboard_event(vec![], vec![], None, &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 {
keys: vec![Key::A, Key::B],
});
let reports = vec![
testing_utilities::create_keyboard_input_report(vec![Key::A]),
testing_utilities::create_keyboard_input_report(vec![Key::B]),
];
let expected_events = vec![
testing_utilities::create_keyboard_event(vec![Key::A], vec![], None, &descriptor),
testing_utilities::create_keyboard_event(vec![Key::B], vec![Key::A], None, &descriptor),
];
assert_input_report_sequence_generates_events!(
input_reports: reports,
expected_events: expected_events,
device_descriptor: descriptor,
device_type: KeyboardBinding,
);
}
/// Tests that modifier keys are propagated to the event receiver.
#[fasync::run_singlethreaded(test)]
async fn modifier_keys() {
let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
keys: vec![Key::LeftShift],
});
let reports = vec![testing_utilities::create_keyboard_input_report(vec![Key::LeftShift])];
let expected_events = vec![testing_utilities::create_keyboard_event(
vec![Key::LeftShift],
vec![],
Some(Modifiers::Shift | Modifiers::LeftShift),
&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 {
keys: vec![Key::A, Key::LeftShift],
});
let reports = vec![
testing_utilities::create_keyboard_input_report(vec![Key::LeftShift]),
testing_utilities::create_keyboard_input_report(vec![Key::LeftShift, Key::A]),
testing_utilities::create_keyboard_input_report(vec![Key::A]),
];
let expected_events = vec![
testing_utilities::create_keyboard_event(
vec![Key::LeftShift],
vec![],
Some(Modifiers::Shift | Modifiers::LeftShift),
&descriptor,
),
testing_utilities::create_keyboard_event(
vec![Key::A],
vec![],
Some(Modifiers::Shift | Modifiers::LeftShift),
&descriptor,
),
testing_utilities::create_keyboard_event(
vec![],
vec![Key::LeftShift],
None,
&descriptor,
),
];
assert_input_report_sequence_generates_events!(
input_reports: reports,
expected_events: expected_events,
device_descriptor: descriptor,
device_type: KeyboardBinding,
);
}
}