#![warn(missing_docs)]
use crate::modern_backend::input_reports_reader::InputReportsReader;
use crate::synthesizer;
use crate::usages::hid_usage_to_input3_key;
use anyhow::{format_err, Context as _, Error};
use async_trait::async_trait;
use fidl::endpoints::ServerEnd;
use fidl::Error as FidlError;
use fidl_fuchsia_input::Key;
use fidl_fuchsia_input_report::{
ConsumerControlButton, ConsumerControlInputReport, ContactInputReport, DeviceDescriptor,
FeatureReport, InputDeviceRequest, InputDeviceRequestStream, InputReport,
InputReportsReaderMarker, KeyboardInputReport, MouseInputReport, TouchInputReport,
TOUCH_MAX_CONTACTS,
};
use fidl_fuchsia_ui_input::{KeyboardReport, Touch};
use fuchsia_async as fasync;
use futures::{future, pin_mut, StreamExt, TryFutureExt};
use std::convert::TryFrom as _;
pub(super) struct InputDevice {
report_sender: futures::channel::mpsc::UnboundedSender<InputReport>,
input_device_task: fasync::Task<Result<(), Error>>,
}
impl std::convert::From<synthesizer::MediaButton> for ConsumerControlButton {
fn from(synthesizer_button: synthesizer::MediaButton) -> Self {
match synthesizer_button {
synthesizer::MediaButton::VolumeUp => Self::VolumeUp,
synthesizer::MediaButton::VolumeDown => Self::VolumeDown,
synthesizer::MediaButton::MicMute => Self::MicMute,
synthesizer::MediaButton::FactoryReset => Self::FactoryReset,
synthesizer::MediaButton::Pause => Self::Pause,
synthesizer::MediaButton::CameraDisable => Self::CameraDisable,
}
}
}
#[async_trait(?Send)]
impl synthesizer::InputDevice for self::InputDevice {
fn media_buttons(
&mut self,
pressed_buttons: Vec<synthesizer::MediaButton>,
time: u64,
) -> Result<(), Error> {
self.report_sender
.unbounded_send(InputReport {
event_time: Some(i64::try_from(time).context("converting time to i64")?),
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some(pressed_buttons.into_iter().map(Into::into).collect()),
..Default::default()
}),
..Default::default()
})
.context("sending media button InputReport")
}
fn key_press(&mut self, report: KeyboardReport, time: u64) -> Result<(), Error> {
self.key_press_internal(report, time, Self::convert_keyboard_report_to_keys)
}
fn key_press_raw(&mut self, report: KeyboardReport, time: u64) -> Result<(), Error> {
self.key_press_internal(report, time, Self::convert_keyboard_report_to_keys_no_transform)
}
fn key_press_usage(&mut self, usage: Option<u32>, time: u64) -> Result<(), Error> {
self.key_press(KeyboardReport { pressed_keys: usage.into_iter().collect() }, time)
}
fn tap(&mut self, pos: Option<(u32, u32)>, time: u64) -> Result<(), Error> {
let fingers = pos.and_then(|(x, y)| {
Some(vec![Touch { finger_id: 1, x: x as i32, y: y as i32, width: 0, height: 0 }])
});
self.multi_finger_tap(fingers, time)
}
fn multi_finger_tap(&mut self, fingers: Option<Vec<Touch>>, time: u64) -> Result<(), Error> {
let num_fingers = match &fingers {
Some(fingers_vec) => fingers_vec.len(),
None => 0,
};
if num_fingers > usize::try_from(TOUCH_MAX_CONTACTS).context("usize is at least 32 bits")? {
return Err(format_err!(
"Got {} fingers, but max is {}",
num_fingers,
TOUCH_MAX_CONTACTS
));
}
self.multi_finger_tap_internal(
TouchInputReport {
contacts: Some(fingers.map_or_else(Vec::new, |fingers_vec| {
fingers_vec
.into_iter()
.map(|finger| ContactInputReport {
contact_id: Some(finger.finger_id),
position_x: Some(i64::from(finger.x)),
position_y: Some(i64::from(finger.y)),
contact_width: Some(i64::from(finger.width)),
contact_height: Some(i64::from(finger.height)),
..Default::default()
})
.collect()
})),
pressed_buttons: Some(vec![]),
..Default::default()
},
time,
)
}
fn mouse(&mut self, report: MouseInputReport, time: u64) -> Result<(), Error> {
self.report_sender
.unbounded_send(InputReport {
event_time: Some(i64::try_from(time).context("converting time to i64")?),
mouse: Some(report),
..Default::default()
})
.context("error sending mouse InputReport")
}
async fn flush(self: Box<Self>) -> Result<(), Error> {
let Self { input_device_task, report_sender } = *self;
std::mem::drop(report_sender); input_device_task.await
}
}
impl InputDevice {
pub(super) fn new(
request_stream: InputDeviceRequestStream,
descriptor: DeviceDescriptor,
) -> Self {
let (report_sender, report_receiver) = futures::channel::mpsc::unbounded::<InputReport>();
let input_device_task =
fasync::Task::local(Self::serve_reports(request_stream, descriptor, report_receiver));
Self { report_sender, input_device_task }
}
async fn serve_reports(
request_stream: InputDeviceRequestStream,
descriptor: DeviceDescriptor,
report_receiver: futures::channel::mpsc::UnboundedReceiver<InputReport>,
) -> Result<(), Error> {
let mut input_reports_reader_server_end_stream = request_stream
.filter_map(|r| future::ready(Self::handle_device_request(r, &descriptor)));
let input_reports_reader_fut = {
let reader_server_end = input_reports_reader_server_end_stream
.next()
.await
.ok_or_else(|| format_err!("stream ended without a call to GetInputReportsReader"))?
.context("handling InputDeviceRequest")?;
InputReportsReader { request_stream: reader_server_end.into_stream(), report_receiver }
.into_future()
};
pin_mut!(input_reports_reader_fut);
let input_device_server_fut = async {
match input_reports_reader_server_end_stream.next().await {
Some(Ok(_server_end)) => {
Err(format_err!(
"InputDevice does not support multiple GetInputReportsReader calls"
))
}
Some(Err(e)) => Err(e.context("handling InputDeviceRequest")),
None => Ok(()),
}
};
pin_mut!(input_device_server_fut);
future::select(
input_device_server_fut.and_then(|_: ()| future::pending()),
input_reports_reader_fut,
)
.await
.factor_first()
.0
}
fn key_press_internal(
&mut self,
report: KeyboardReport,
time: u64,
transform: fn(r: &KeyboardReport) -> Result<Vec<Key>, Error>,
) -> Result<(), Error> {
self.report_sender
.unbounded_send(InputReport {
event_time: Some(i64::try_from(time).context("converting time to i64")?),
keyboard: Some(KeyboardInputReport {
pressed_keys3: Some(transform(&report)?),
..Default::default()
}),
..Default::default()
})
.context("sending key press InputReport")
}
fn multi_finger_tap_internal(
&mut self,
touch: TouchInputReport,
time: u64,
) -> Result<(), Error> {
self.report_sender
.unbounded_send(InputReport {
event_time: Some(i64::try_from(time).context("converting time to i64")?),
touch: Some(touch),
..Default::default()
})
.context("sending touch InputReport")
}
fn handle_device_request(
request: Result<InputDeviceRequest, FidlError>,
descriptor: &DeviceDescriptor,
) -> Option<Result<ServerEnd<InputReportsReaderMarker>, Error>> {
match request {
Ok(InputDeviceRequest::GetInputReportsReader { reader: reader_server_end, .. }) => {
Some(Ok(reader_server_end))
}
Ok(InputDeviceRequest::GetDescriptor { responder }) => {
match responder.send(&descriptor) {
Ok(()) => None,
Err(e) => {
Some(Err(anyhow::Error::from(e).context("sending GetDescriptor response")))
}
}
}
Ok(InputDeviceRequest::GetFeatureReport { responder }) => {
match responder.send(Ok(&FeatureReport::default())) {
Ok(()) => None,
Err(e) => Some(Err(
anyhow::Error::from(e).context("sending GetFeatureReport response")
)),
}
}
Err(e) => {
panic!("InputDevice got an error while reading request: {:?}", &e);
}
_ => {
panic!(
"InputDevice::handle_device_request does not support this request: {:?}",
&request
);
}
}
}
fn convert_keyboard_report_to_keys(report: &KeyboardReport) -> Result<Vec<Key>, Error> {
report
.pressed_keys
.iter()
.map(|&usage| {
hid_usage_to_input3_key(usage as u16)
.ok_or_else(|| format_err!("no Key for usage {:?}", usage))
})
.collect()
}
fn convert_keyboard_report_to_keys_no_transform(
report: &KeyboardReport,
) -> Result<Vec<Key>, Error> {
report
.pressed_keys
.iter()
.map(|&usage| {
Key::from_primitive(usage)
.ok_or_else(|| anyhow::anyhow!("could not convert to input::Key: {}", &usage))
})
.collect()
}
}
#[cfg(test)]
mod tests {
use super::synthesizer::InputDevice as _;
use super::*;
use fidl::endpoints;
use fidl_fuchsia_input_report::{
DeviceDescriptor, InputDeviceMarker, KeyboardDescriptor, KeyboardInputDescriptor,
};
use fuchsia_async as fasync;
const DEFAULT_REPORT_TIMESTAMP: u64 = 0;
mod responds_to_get_feature_report_request {
use super::*;
#[fasync::run_until_stalled(test)]
async fn single_request_before_call_to_get_feature_report() -> Result<(), Error> {
let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
let input_device_server_fut =
Box::new(InputDevice::new(request_stream, DeviceDescriptor::default())).flush();
let get_feature_report_fut = proxy.get_feature_report();
std::mem::drop(proxy); let (_, get_feature_report_result) =
future::join(input_device_server_fut, get_feature_report_fut).await;
assert_eq!(
get_feature_report_result.context("fidl error")?,
Ok(FeatureReport::default())
);
Ok(())
}
}
mod responds_to_get_descriptor_request {
use super::utils::{make_input_device_proxy_and_struct, make_keyboard_descriptor};
use super::*;
use assert_matches::assert_matches;
use futures::task::Poll;
#[fasync::run_until_stalled(test)]
async fn single_request_before_call_to_get_input_reports_reader() -> Result<(), Error> {
let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
let input_device_server_fut =
Box::new(InputDevice::new(request_stream, make_keyboard_descriptor(vec![Key::A])))
.flush();
let get_descriptor_fut = proxy.get_descriptor();
std::mem::drop(proxy); let (_, get_descriptor_result) =
future::join(input_device_server_fut, get_descriptor_fut).await;
assert_eq!(
get_descriptor_result.context("fidl error")?,
make_keyboard_descriptor(vec![Key::A])
);
Ok(())
}
#[test]
fn multiple_requests_before_call_to_get_input_reports_reader() -> Result<(), Error> {
let mut executor = fasync::TestExecutor::new();
let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
let mut input_device_server_fut =
Box::new(InputDevice::new(request_stream, make_keyboard_descriptor(vec![Key::A])))
.flush();
let mut get_descriptor_fut = proxy.get_descriptor();
assert_matches!(
executor.run_until_stalled(&mut input_device_server_fut),
Poll::Pending
);
std::mem::drop(executor.run_until_stalled(&mut get_descriptor_fut));
let mut get_descriptor_fut = proxy.get_descriptor();
let _ = executor.run_until_stalled(&mut input_device_server_fut);
assert_matches!(
executor.run_until_stalled(&mut get_descriptor_fut),
Poll::Ready(Ok(_))
);
Ok(())
}
#[test]
fn after_call_to_get_input_reports_reader_with_report_pending() -> Result<(), Error> {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.context("internal error queuing input event")?;
let input_device_server_fut = input_device.flush();
pin_mut!(input_device_server_fut);
let (_input_reports_reader_proxy, input_reports_reader_server_end) =
endpoints::create_proxy::<InputReportsReaderMarker>();
input_device_proxy
.get_input_reports_reader(input_reports_reader_server_end)
.context("sending get_input_reports_reader request")?;
assert_matches!(
executor.run_until_stalled(&mut input_device_server_fut),
Poll::Pending
);
let mut get_descriptor_fut = input_device_proxy.get_descriptor();
assert_matches!(
executor.run_until_stalled(&mut input_device_server_fut),
Poll::Pending
);
assert_matches!(executor.run_until_stalled(&mut get_descriptor_fut), Poll::Ready(_));
Ok(())
}
}
mod report_contents {
use super::utils::{get_input_reports, make_input_device_proxy_and_struct};
use super::*;
use crate::usages::Usages;
use assert_matches::assert_matches;
use std::convert::TryInto as _;
#[fasync::run_until_stalled(test)]
async fn media_buttons_generates_empty_consumer_controls_input_report() -> Result<(), Error>
{
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.media_buttons(vec![], DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn media_buttons_generates_full_consumer_controls_input_report() -> Result<(), Error>
{
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.media_buttons(
vec![
synthesizer::MediaButton::VolumeUp,
synthesizer::MediaButton::VolumeDown,
synthesizer::MediaButton::MicMute,
synthesizer::MediaButton::FactoryReset,
synthesizer::MediaButton::Pause,
synthesizer::MediaButton::CameraDisable,
],
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some(vec![
ConsumerControlButton::VolumeUp,
ConsumerControlButton::VolumeDown,
ConsumerControlButton::MicMute,
ConsumerControlButton::FactoryReset,
ConsumerControlButton::Pause,
ConsumerControlButton::CameraDisable,
]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn media_buttons_generates_partial_consumer_controls_input_report(
) -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.media_buttons(
vec![
synthesizer::MediaButton::VolumeUp,
synthesizer::MediaButton::MicMute,
synthesizer::MediaButton::Pause,
],
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some(vec![
ConsumerControlButton::VolumeUp,
ConsumerControlButton::MicMute,
ConsumerControlButton::Pause,
]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn key_press_generates_expected_keyboard_input_report() -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.key_press(
KeyboardReport {
pressed_keys: vec![Usages::HidUsageKeyA as u32, Usages::HidUsageKeyB as u32],
},
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
keyboard: Some(KeyboardInputReport {
pressed_keys3: Some(vec![Key::A, Key::B]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn key_press_usage_generates_expected_keyboard_input_report_for_some(
) -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device
.key_press_usage(Some(Usages::HidUsageKeyA as u32), DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
keyboard: Some(KeyboardInputReport {
pressed_keys3: Some(vec![Key::A]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn key_press_usage_generates_expected_keyboard_input_report_for_none(
) -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.key_press_usage(None, DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
keyboard: Some(KeyboardInputReport {
pressed_keys3: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn key_press_returns_error_if_usage_cannot_be_mapped_to_key() {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
assert_matches!(
input_device.key_press(
KeyboardReport { pressed_keys: vec![0xffff_ffff] },
DEFAULT_REPORT_TIMESTAMP
),
Err(_)
);
}
#[fasync::run_until_stalled(test)]
async fn key_press_usage_returns_error_if_usage_cannot_be_mapped_to_key() {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
assert_matches!(
input_device.key_press_usage(Some(0xffff_ffff), DEFAULT_REPORT_TIMESTAMP),
Err(_)
);
}
#[fasync::run_until_stalled(test)]
async fn key_events_generates_expected_keyboard_response() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.key_press_raw(
KeyboardReport {
pressed_keys: vec![Key::A.into_primitive(), Key::B.into_primitive()],
},
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
keyboard: Some(KeyboardInputReport {
pressed_keys3: Some(vec![Key::A, Key::B]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn tap_generates_expected_report_for_some() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.tap(Some((10, 20)), DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(1),
position_x: Some(10),
position_y: Some(20),
pressure: None,
contact_width: Some(0),
contact_height: Some(0),
..Default::default()
}]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn tap_generates_expected_report_for_none() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.tap(None, DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_generates_report_for_single_finger() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.multi_finger_tap(
Some(vec![Touch { finger_id: 5, x: 10, y: 20, width: 100, height: 200 }]),
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(5),
position_x: Some(10),
position_y: Some(20),
pressure: None,
contact_width: Some(100),
contact_height: Some(200),
..Default::default()
}]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_generates_expected_report_for_two_fingers() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.multi_finger_tap(
Some(vec![
Touch { finger_id: 5, x: 10, y: 20, width: 100, height: 200 },
Touch { finger_id: 0, x: 30, y: 40, width: 300, height: 400 },
]),
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![
ContactInputReport {
contact_id: Some(5),
position_x: Some(10),
position_y: Some(20),
pressure: None,
contact_width: Some(100),
contact_height: Some(200),
..Default::default()
},
ContactInputReport {
contact_id: Some(0),
position_x: Some(30),
position_y: Some(40),
pressure: None,
contact_width: Some(300),
contact_height: Some(400),
..Default::default()
}
]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_generates_expected_report_for_zero_fingers() -> Result<(), Error>
{
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.multi_finger_tap(Some(vec![]), DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_generates_expected_report_for_none() -> Result<(), Error> {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.multi_finger_tap(None, DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, _input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
touch: Some(TouchInputReport {
contacts: Some(vec![]),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_returns_error_when_num_fingers_is_to_large() {
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
assert_matches!(
input_device.multi_finger_tap(
Some(
(0..=TOUCH_MAX_CONTACTS)
.map(|i| Touch {
finger_id: i,
x: i as i32,
y: i as i32,
width: i,
height: i
})
.collect(),
),
DEFAULT_REPORT_TIMESTAMP,
),
Err(_)
);
}
#[fasync::run_until_stalled(test)]
async fn mouse_generates_empty_mouse_input_report() -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.mouse(MouseInputReport::default(), DEFAULT_REPORT_TIMESTAMP)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
mouse: Some(MouseInputReport::default()),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn mouse_generates_full_mouse_input_report() -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.mouse(
MouseInputReport {
movement_x: Some(10),
movement_y: Some(15),
pressed_buttons: Some(vec![1, 2, 3]),
scroll_v: Some(1),
scroll_h: Some(-1),
..Default::default()
},
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
mouse: Some(MouseInputReport {
movement_x: Some(10),
movement_y: Some(15),
pressed_buttons: Some(vec![1, 2, 3]),
scroll_v: Some(1),
scroll_h: Some(-1),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn mouse_generates_partial_mouse_input_report() -> Result<(), Error> {
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device.mouse(
MouseInputReport {
movement_x: Some(10),
movement_y: Some(15),
pressed_buttons: Some(vec![]),
..Default::default()
},
DEFAULT_REPORT_TIMESTAMP,
)?;
let input_reports = get_input_reports(input_device, input_device_proxy).await;
assert_eq!(
input_reports.as_slice(),
[InputReport {
event_time: Some(
DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
),
mouse: Some(MouseInputReport {
movement_x: Some(10),
movement_y: Some(15),
pressed_buttons: Some(vec![]),
..Default::default()
}),
..Default::default()
}]
);
Ok(())
}
}
mod future_resolution {
use super::utils::{make_input_device_proxy_and_struct, make_input_reports_reader_proxy};
use super::*;
use futures::task::Poll;
mod yields_ok_after_all_reports_are_sent_to_input_reports_reader {
use super::*;
use assert_matches::assert_matches;
#[test]
fn if_device_request_channel_was_closed() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
let mut input_device_fut = input_device.flush();
std::mem::drop(input_device_proxy); assert_matches!(
executor.run_until_stalled(&mut input_device_fut),
Poll::Ready(Ok(()))
);
}
#[test]
fn even_if_device_request_channel_is_open() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
let mut input_device_fut = input_device.flush();
assert_matches!(
executor.run_until_stalled(&mut input_device_fut),
Poll::Ready(Ok(()))
);
}
#[test]
fn even_if_reports_was_empty_and_device_request_channel_is_open() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
let input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
let mut input_device_fut = input_device.flush();
assert_matches!(
executor.run_until_stalled(&mut input_device_fut),
Poll::Ready(Ok(()))
);
}
}
mod yields_err_if_peer_closed_device_channel_without_calling_get_input_reports_reader {
use super::*;
use assert_matches::assert_matches;
#[test]
fn if_reports_were_available() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let mut input_device_fut = input_device.flush();
std::mem::drop(input_device_proxy);
assert_matches!(
executor.run_until_stalled(&mut input_device_fut),
Poll::Ready(Err(_))
)
}
#[test]
fn even_if_no_reports_were_available() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
let mut input_device_fut = input_device.flush();
std::mem::drop(input_device_proxy);
assert_matches!(
executor.run_until_stalled(&mut input_device_fut),
Poll::Ready(Err(_))
)
}
}
mod is_pending_if_peer_has_device_channel_open_and_has_not_called_get_input_reports_reader {
use super::*;
use assert_matches::assert_matches;
#[test]
fn if_reports_were_available() {
let mut executor = fasync::TestExecutor::new();
let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let mut input_device_fut = input_device.flush();
assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
#[test]
fn even_if_no_reports_were_available() {
let mut executor = fasync::TestExecutor::new();
let (_input_device_proxy, input_device) = make_input_device_proxy_and_struct();
let mut input_device_fut = input_device.flush();
assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
#[test]
fn even_if_get_device_descriptor_has_been_called() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
let mut input_device_fut = input_device.flush();
let _get_descriptor_fut = input_device_proxy.get_descriptor();
assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
}
mod is_pending_if_peer_has_not_read_any_reports_when_a_report_is_available {
use super::*;
use assert_matches::assert_matches;
#[test]
fn if_device_request_channel_is_open() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let _input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let mut input_device_fut = input_device.flush();
assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
#[test]
fn even_if_device_channel_is_closed() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let _input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
input_device
.key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
.expect("queuing input report");
let mut input_device_fut = input_device.flush();
std::mem::drop(input_device_proxy); assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
}
mod is_pending_if_peer_did_not_read_all_reports {
use super::*;
use assert_matches::assert_matches;
use fidl_fuchsia_input_report::MAX_DEVICE_REPORT_COUNT;
#[test]
fn if_device_request_channel_is_open() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
(0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
input_device
.key_press(
KeyboardReport { pressed_keys: vec![] },
DEFAULT_REPORT_TIMESTAMP,
)
.expect("queuing input report");
});
let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
let mut input_device_fut = input_device.flush();
assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
#[test]
fn even_if_device_request_channel_is_closed() {
let mut executor = fasync::TestExecutor::new();
let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
let input_reports_reader_proxy =
make_input_reports_reader_proxy(&input_device_proxy);
(0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
input_device
.key_press(
KeyboardReport { pressed_keys: vec![] },
DEFAULT_REPORT_TIMESTAMP,
)
.expect("queuing input report");
});
let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
let mut input_device_fut = input_device.flush();
std::mem::drop(input_device_proxy); assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
}
}
}
mod unsupported_use_cases {
use super::utils::make_input_device_proxy_and_struct;
use super::*;
use assert_matches::assert_matches;
#[fasync::run_until_stalled(test)]
async fn multiple_get_input_reports_reader_requests_yield_error() -> Result<(), Error> {
let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
let (_input_reports_reader_proxy, input_reports_reader_server_end) =
endpoints::create_proxy::<InputReportsReaderMarker>();
input_device_proxy
.get_input_reports_reader(input_reports_reader_server_end)
.expect("sending first get_input_reports_reader request");
let (_input_reports_reader_proxy, input_reports_reader_server_end) =
endpoints::create_proxy::<InputReportsReaderMarker>();
input_device_proxy
.get_input_reports_reader(input_reports_reader_server_end)
.expect("sending second get_input_reports_reader request");
let input_device_fut = input_device.flush();
assert_matches!(input_device_fut.await, Err(_));
Ok(())
}
}
mod utils {
use super::*;
use fidl_fuchsia_input_report::{InputDeviceProxy, InputReportsReaderProxy};
pub(super) fn make_keyboard_descriptor(keys: Vec<Key>) -> DeviceDescriptor {
DeviceDescriptor {
keyboard: Some(KeyboardDescriptor {
input: Some(KeyboardInputDescriptor {
keys3: Some(keys),
..Default::default()
}),
..Default::default()
}),
..Default::default()
}
}
pub(super) fn make_input_device_proxy_and_struct() -> (InputDeviceProxy, Box<InputDevice>) {
let (input_device_proxy, input_device_request_stream) =
endpoints::create_proxy_and_stream::<InputDeviceMarker>();
let input_device = Box::new(InputDevice::new(
input_device_request_stream,
DeviceDescriptor::default(),
));
(input_device_proxy, input_device)
}
pub(super) fn make_input_reports_reader_proxy(
input_device_proxy: &InputDeviceProxy,
) -> InputReportsReaderProxy {
let (input_reports_reader_proxy, input_reports_reader_server_end) =
endpoints::create_proxy::<InputReportsReaderMarker>();
input_device_proxy
.get_input_reports_reader(input_reports_reader_server_end)
.expect("sending get_input_reports_reader request");
input_reports_reader_proxy
}
pub(super) async fn get_input_reports(
input_device: Box<InputDevice>,
input_device_proxy: InputDeviceProxy,
) -> Vec<InputReport> {
let input_reports_reader_proxy = make_input_reports_reader_proxy(&input_device_proxy);
let input_device_server_fut = input_device.flush();
let input_reports_fut = input_reports_reader_proxy.read_input_reports();
std::mem::drop(input_reports_reader_proxy); std::mem::drop(input_device_proxy); future::join(input_device_server_fut, input_reports_fut)
.await
.1
.expect("fidl error")
.map_err(zx::Status::from_raw)
.expect("service error")
}
}
}