blob: 7922a17896c9bbe9a344a31005212fc93c20fab5 [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, Handled, InputDeviceBinding, InputEvent},
crate::utils::{Position, Size},
anyhow::{format_err, Error},
async_trait::async_trait,
fidl_fuchsia_input_report as fidl_input_report,
fidl_fuchsia_input_report::{InputDeviceProxy, InputReport},
fidl_fuchsia_ui_input as fidl_ui_input, fidl_fuchsia_ui_pointerinjector as pointerinjector,
fuchsia_syslog::fx_log_err,
fuchsia_zircon as zx,
futures::channel::mpsc::Sender,
maplit::hashmap,
std::collections::HashMap,
std::iter::FromIterator,
};
/// A [`TouchEvent`] represents a set of contacts and the phase those contacts are in.
///
/// For example, when a user touches a touch screen with two fingers, there will be two
/// [`TouchContact`]s. When a user removes one finger, there will still be two contacts
/// but one will be reported as removed.
///
/// The expected sequence for any given contact is:
/// 1. [`fidl_fuchsia_ui_input::PointerEventPhase::Add`]
/// 2. [`fidl_fuchsia_ui_input::PointerEventPhase::Down`]
/// 3. 0 or more [`fidl_fuchsia_ui_input::PointerEventPhase::Move`]
/// 4. [`fidl_fuchsia_ui_input::PointerEventPhase::Up`]
/// 5. [`fidl_fuchsia_ui_input::PointerEventPhase::Remove`]
///
/// Additionally, a [`fidl_fuchsia_ui_input::PointerEventPhase::Cancel`] may be sent at any time
/// signalling that the event is no longer directed towards the receiver.
#[derive(Clone, Debug, PartialEq)]
pub struct TouchEvent {
/// Deprecated. To be removed with fxbug.dev/75817.
/// The contacts associated with the touch event. For example, a two-finger touch would result
/// in one touch event with two [`TouchContact`]s.
///
/// Contacts are grouped based on their current phase (e.g., down, move).
pub contacts: HashMap<fidl_ui_input::PointerEventPhase, Vec<TouchContact>>,
/// The contacts associated with the touch event. For example, a two-finger touch would result
/// in one touch event with two [`TouchContact`]s.
///
/// Contacts are grouped based on their current phase (e.g., add, change).
pub injector_contacts: HashMap<pointerinjector::EventPhase, Vec<TouchContact>>,
}
/// [`TouchDeviceType`] indicates the type of touch device. Both Touch Screen and Windows Precision
/// Touchpad send touch event from driver but need different process inside input pipeline.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TouchDeviceType {
TouchScreen,
WindowsPrecisionTouchpad,
}
/// A [`TouchContact`] represents a single contact (e.g., one touch of a multi-touch gesture) related
/// to a touch event.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct TouchContact {
/// The identifier of the contact. Unique per touch device.
pub id: u32,
/// The position of the touch event, in the units of the associated
/// [`ContactDeviceDescriptor`]'s `range`.
pub position: Position,
/// The pressure associated with the contact, in the units of the associated
/// [`ContactDeviceDescriptor`]'s `pressure_range`.
pub pressure: Option<i64>,
/// The size of the touch event, in the units of the associated
/// [`ContactDeviceDescriptor`]'s `range`.
pub contact_size: Option<Size>,
}
impl Eq for TouchContact {}
impl From<&fidl_fuchsia_input_report::ContactInputReport> for TouchContact {
fn from(fidl_contact: &fidl_fuchsia_input_report::ContactInputReport) -> TouchContact {
let contact_size =
if fidl_contact.contact_width.is_some() && fidl_contact.contact_height.is_some() {
Some(Size {
width: fidl_contact.contact_width.unwrap() as f32,
height: fidl_contact.contact_height.unwrap() as f32,
})
} else {
None
};
TouchContact {
id: fidl_contact.contact_id.unwrap_or_default(),
position: Position {
x: fidl_contact.position_x.unwrap_or_default() as f32,
y: fidl_contact.position_y.unwrap_or_default() as f32,
},
pressure: fidl_contact.pressure,
contact_size,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TouchDeviceDescriptor {
/// The id of the connected touch input device.
pub device_id: u32,
/// The descriptors for the possible contacts associated with the device.
pub contacts: Vec<ContactDeviceDescriptor>,
}
/// A [`ContactDeviceDescriptor`] describes the possible values touch contact properties can take on.
///
/// This descriptor can be used, for example, to determine where on a screen a touch made contact.
///
/// # Example
///
/// ```
/// // Determine the scaling factor between the display and the touch device's x range.
/// let scaling_factor =
/// display_width / (contact_descriptor._x_range.end - contact_descriptor._x_range.start);
/// // Use the scaling factor to scale the contact report's x position.
/// let hit_location =
/// scaling_factor * (contact_report.position_x - contact_descriptor._x_range.start);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ContactDeviceDescriptor {
/// The range of possible x values for this touch contact.
pub x_range: fidl_input_report::Range,
/// The range of possible y values for this touch contact.
pub y_range: fidl_input_report::Range,
/// The range of possible pressure values for this touch contact.
pub pressure_range: Option<fidl_input_report::Range>,
/// The range of possible widths for this touch contact.
pub width_range: Option<fidl_input_report::Range>,
/// The range of possible heights for this touch contact.
pub height_range: Option<fidl_input_report::Range>,
}
/// A [`TouchBinding`] represents a connection to a touch input device.
///
/// The [`TouchBinding`] parses and exposes touch descriptor properties (e.g., the range of
/// possible x values for touch contacts) 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 TouchBinding {
/// The channel to stream InputEvents to.
event_sender: Sender<InputEvent>,
/// Holds information about this device.
device_descriptor: TouchDeviceDescriptor,
/// Touch device type of the touch device.
/// TODO(fxb/99687): following CL will begin use this field and remove the underscore.
_touch_device_type: TouchDeviceType,
}
#[async_trait]
impl input_device::InputDeviceBinding for TouchBinding {
fn input_event_sender(&self) -> Sender<InputEvent> {
self.event_sender.clone()
}
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Touch(self.device_descriptor.clone())
}
}
impl TouchBinding {
/// 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.
/// - `device_id`: The id of the connected touch device.
/// - `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,
device_id: u32,
input_event_sender: Sender<input_device::InputEvent>,
) -> Result<Self, Error> {
let device_binding =
Self::bind_device(&device_proxy, device_id, 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)
}
/// Binds the provided input device to a new instance of `Self`.
///
/// # Parameters
/// - `device`: The device to use to initialize the binding.
/// - `device_id`: The id of the connected touch device.
/// - `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,
device_id: u32,
input_event_sender: Sender<input_device::InputEvent>,
) -> Result<Self, Error> {
let device_descriptor: fidl_fuchsia_input_report::DeviceDescriptor =
device.get_descriptor().await?;
match device_descriptor.touch {
Some(fidl_fuchsia_input_report::TouchDescriptor {
input:
Some(fidl_fuchsia_input_report::TouchInputDescriptor {
contacts: Some(contact_descriptors),
max_contacts: _,
touch_type: _,
buttons: _,
..
}),
..
}) => Ok(TouchBinding {
event_sender: input_event_sender,
device_descriptor: TouchDeviceDescriptor {
device_id,
contacts: contact_descriptors
.iter()
.map(TouchBinding::parse_contact_descriptor)
.filter_map(Result::ok)
.collect(),
},
_touch_device_type: get_device_type(device).await,
}),
descriptor => Err(format_err!("Touch Descriptor failed to parse: \n {:?}", 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<InputEvent>,
) -> Option<InputReport> {
fuchsia_trace::duration!("input", "touch-binding-process-report");
fuchsia_trace::flow_end!("input", "input_report", report.trace_id.unwrap_or(0));
// Input devices can have multiple types so ensure `report` is a TouchInputReport.
let touch_report: &fidl_fuchsia_input_report::TouchInputReport = match &report.touch {
Some(touch) => touch,
None => {
return previous_report;
}
};
let previous_contacts: HashMap<u32, TouchContact> = previous_report
.as_ref()
.and_then(|unwrapped_report| unwrapped_report.touch.as_ref())
.map(touch_contacts_from_touch_report)
.unwrap_or_default();
let current_contacts: HashMap<u32, TouchContact> =
touch_contacts_from_touch_report(touch_report);
// Don't send an event if there are no new contacts.
if previous_contacts.is_empty() && current_contacts.is_empty() {
return Some(report);
}
// Contacts which exist only in current.
let added_contacts: Vec<TouchContact> = Vec::from_iter(
current_contacts
.values()
.cloned()
.filter(|contact| !previous_contacts.contains_key(&contact.id)),
);
// Contacts which exist in both previous and current.
let moved_contacts: Vec<TouchContact> = Vec::from_iter(
current_contacts
.values()
.cloned()
.filter(|contact| previous_contacts.contains_key(&contact.id)),
);
// Contacts which exist only in previous.
let removed_contacts: Vec<TouchContact> = Vec::from_iter(
previous_contacts
.values()
.cloned()
.filter(|contact| !current_contacts.contains_key(&contact.id)),
);
let event_time: zx::Time = input_device::event_time_or_now(report.event_time);
let trace_id = fuchsia_trace::generate_nonce();
fuchsia_trace::flow_begin!("input", "report-to-event", trace_id);
send_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Add => added_contacts.clone(),
fidl_ui_input::PointerEventPhase::Down => added_contacts.clone(),
fidl_ui_input::PointerEventPhase::Move => moved_contacts.clone(),
fidl_ui_input::PointerEventPhase::Up => removed_contacts.clone(),
fidl_ui_input::PointerEventPhase::Remove => removed_contacts.clone(),
},
hashmap! {
pointerinjector::EventPhase::Add => added_contacts,
pointerinjector::EventPhase::Change => moved_contacts,
pointerinjector::EventPhase::Remove => removed_contacts,
},
device_descriptor,
event_time,
input_event_sender,
trace_id,
);
Some(report)
}
/// Parses a fidl_input_report contact descriptor into a [`ContactDeviceDescriptor`]
///
/// # Parameters
/// - `contact_device_descriptor`: The contact descriptor to parse.
///
/// # Errors
/// If the contact description fails to parse because required fields aren't present.
fn parse_contact_descriptor(
contact_device_descriptor: &fidl_input_report::ContactInputDescriptor,
) -> Result<ContactDeviceDescriptor, Error> {
match contact_device_descriptor {
fidl_input_report::ContactInputDescriptor {
position_x: Some(x_axis),
position_y: Some(y_axis),
pressure: pressure_axis,
contact_width: width_axis,
contact_height: height_axis,
..
} => Ok(ContactDeviceDescriptor {
x_range: x_axis.range,
y_range: y_axis.range,
pressure_range: pressure_axis.map(|axis| axis.range),
width_range: width_axis.map(|axis| axis.range),
height_range: height_axis.map(|axis| axis.range),
}),
descriptor => {
Err(format_err!("Touch Contact Descriptor failed to parse: \n {:?}", descriptor))
}
}
}
}
fn touch_contacts_from_touch_report(
touch_report: &fidl_fuchsia_input_report::TouchInputReport,
) -> HashMap<u32, TouchContact> {
// First unwrap all the optionals in the input report to get to the contacts.
let contacts: Vec<TouchContact> = touch_report
.contacts
.as_ref()
.and_then(|unwrapped_contacts| {
// Once the contacts are found, convert them into `TouchContact`s.
Some(unwrapped_contacts.iter().map(TouchContact::from).collect())
})
.unwrap_or_default();
contacts.into_iter().map(|contact| (contact.id, contact)).collect()
}
/// Sends a TouchEvent over `input_event_sender`.
///
/// # Parameters
/// - `contacts`: The contact points relevant to the new TouchEvent.
/// - `injector_contacts`: The contact points relevant to the new TouchEvent, used to send
/// pointer events into Scenic.
/// - `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_event(
contacts: HashMap<fidl_ui_input::PointerEventPhase, Vec<TouchContact>>,
injector_contacts: HashMap<pointerinjector::EventPhase, Vec<TouchContact>>,
device_descriptor: &input_device::InputDeviceDescriptor,
event_time: zx::Time,
input_event_sender: &mut Sender<input_device::InputEvent>,
trace_id: u64,
) {
match input_event_sender.try_send(input_device::InputEvent {
device_event: input_device::InputDeviceEvent::Touch(TouchEvent {
contacts,
injector_contacts,
}),
device_descriptor: device_descriptor.clone(),
event_time,
handled: Handled::No,
trace_id: Some(trace_id),
}) {
Err(e) => fx_log_err!("Failed to send TouchEvent with error: {:?}", e),
_ => {}
}
}
/// [`get_device_type`] check if the touch device is a touchscreen or Windows Precision Touchpad.
///
/// Windows Precision Touchpad reports `MouseCollection` or `WindowsPrecisionTouchpadCollection`
/// in `TouchFeatureReport`. Fallback all error responses on `get_feature_report` to TouchScreen
/// because some touch screen does not report this method.
async fn get_device_type(input_device: &fidl_input_report::InputDeviceProxy) -> TouchDeviceType {
match input_device.get_feature_report().await {
Ok(Ok(fidl_input_report::FeatureReport {
touch:
Some(fidl_input_report::TouchFeatureReport {
input_mode:
Some(
fidl_input_report::TouchConfigurationInputMode::MouseCollection
| fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection,
),
..
}),
..
})) => TouchDeviceType::WindowsPrecisionTouchpad,
_ => TouchDeviceType::TouchScreen,
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::testing_utilities::{
self, create_touch_contact, create_touch_event, create_touch_input_report,
},
crate::utils::Position,
assert_matches::assert_matches,
fidl::endpoints::spawn_stream_handler,
fuchsia_async as fasync,
futures::StreamExt,
pretty_assertions::assert_eq,
test_case::test_case,
};
#[fasync::run_singlethreaded(test)]
async fn process_empty_reports() {
let previous_report_time = fuchsia_zircon::Time::get_monotonic().into_nanos();
let previous_report = create_touch_input_report(vec![], previous_report_time);
let report_time = fuchsia_zircon::Time::get_monotonic().into_nanos();
let report = create_touch_input_report(vec![], report_time);
let descriptor = input_device::InputDeviceDescriptor::Touch(TouchDeviceDescriptor {
device_id: 1,
contacts: vec![],
});
let (mut event_sender, mut event_receiver) = futures::channel::mpsc::channel(1);
let returned_report = TouchBinding::process_reports(
report,
Some(previous_report),
&descriptor,
&mut event_sender,
);
assert!(returned_report.is_some());
assert_eq!(returned_report.unwrap().event_time, Some(report_time));
// Assert there are no pending events on the receiver.
let event = event_receiver.try_next();
assert!(event.is_err());
}
// Tests that a input report with a new contact generates an event with an add and a down.
#[fasync::run_singlethreaded(test)]
async fn add_and_down() {
const TOUCH_ID: u32 = 2;
let descriptor = input_device::InputDeviceDescriptor::Touch(TouchDeviceDescriptor {
device_id: 1,
contacts: vec![],
});
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let contact = fidl_fuchsia_input_report::ContactInputReport {
contact_id: Some(TOUCH_ID),
position_x: Some(0),
position_y: Some(0),
pressure: None,
contact_width: None,
contact_height: None,
..fidl_fuchsia_input_report::ContactInputReport::EMPTY
};
let reports = vec![create_touch_input_report(vec![contact], event_time_i64)];
let expected_events = vec![create_touch_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Add
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
fidl_ui_input::PointerEventPhase::Down
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
},
event_time_u64,
&descriptor,
)];
assert_input_report_sequence_generates_events!(
input_reports: reports,
expected_events: expected_events,
device_descriptor: descriptor,
device_type: TouchBinding,
);
}
// Tests that up and remove events are sent when a touch is released.
#[fasync::run_singlethreaded(test)]
async fn up_and_remove() {
const TOUCH_ID: u32 = 2;
let descriptor = input_device::InputDeviceDescriptor::Touch(TouchDeviceDescriptor {
device_id: 1,
contacts: vec![],
});
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let contact = fidl_fuchsia_input_report::ContactInputReport {
contact_id: Some(TOUCH_ID),
position_x: Some(0),
position_y: Some(0),
pressure: None,
contact_width: None,
contact_height: None,
..fidl_fuchsia_input_report::ContactInputReport::EMPTY
};
let reports = vec![
create_touch_input_report(vec![contact], event_time_i64),
create_touch_input_report(vec![], event_time_i64),
];
let expected_events = vec![
create_touch_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Add
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
fidl_ui_input::PointerEventPhase::Down
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
},
event_time_u64,
&descriptor,
),
create_touch_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Up
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
fidl_ui_input::PointerEventPhase::Remove
=> vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
},
event_time_u64,
&descriptor,
),
];
assert_input_report_sequence_generates_events!(
input_reports: reports,
expected_events: expected_events,
device_descriptor: descriptor,
device_type: TouchBinding,
);
}
// Tests that a move generates the correct event.
#[fasync::run_singlethreaded(test)]
async fn add_down_move() {
const TOUCH_ID: u32 = 2;
let first = Position { x: 10.0, y: 30.0 };
let second = Position { x: first.x * 2.0, y: first.y * 2.0 };
let descriptor = input_device::InputDeviceDescriptor::Touch(TouchDeviceDescriptor {
device_id: 1,
contacts: vec![],
});
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let first_contact = fidl_fuchsia_input_report::ContactInputReport {
contact_id: Some(TOUCH_ID),
position_x: Some(first.x as i64),
position_y: Some(first.y as i64),
pressure: None,
contact_width: None,
contact_height: None,
..fidl_fuchsia_input_report::ContactInputReport::EMPTY
};
let second_contact = fidl_fuchsia_input_report::ContactInputReport {
contact_id: Some(TOUCH_ID),
position_x: Some(first.x as i64 * 2),
position_y: Some(first.y as i64 * 2),
pressure: None,
contact_width: None,
contact_height: None,
..fidl_fuchsia_input_report::ContactInputReport::EMPTY
};
let reports = vec![
create_touch_input_report(vec![first_contact], event_time_i64),
create_touch_input_report(vec![second_contact], event_time_i64),
];
let expected_events = vec![
create_touch_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Add
=> vec![create_touch_contact(TOUCH_ID, first)],
fidl_ui_input::PointerEventPhase::Down
=> vec![create_touch_contact(TOUCH_ID, first)],
},
event_time_u64,
&descriptor,
),
create_touch_event(
hashmap! {
fidl_ui_input::PointerEventPhase::Move
=> vec![create_touch_contact(TOUCH_ID, second)],
},
event_time_u64,
&descriptor,
),
];
assert_input_report_sequence_generates_events!(
input_reports: reports,
expected_events: expected_events,
device_descriptor: descriptor,
device_type: TouchBinding,
);
}
#[fasync::run_singlethreaded(test)]
async fn sent_event_has_trace_id() {
let previous_report_time = fuchsia_zircon::Time::get_monotonic().into_nanos();
let previous_report = create_touch_input_report(vec![], previous_report_time);
let report_time = fuchsia_zircon::Time::get_monotonic().into_nanos();
let contact = fidl_fuchsia_input_report::ContactInputReport {
contact_id: Some(222),
position_x: Some(333),
position_y: Some(444),
..fidl_fuchsia_input_report::ContactInputReport::EMPTY
};
let report = create_touch_input_report(vec![contact], report_time);
let descriptor = input_device::InputDeviceDescriptor::Touch(TouchDeviceDescriptor {
device_id: 1,
contacts: vec![],
});
let (mut event_sender, mut event_receiver) = futures::channel::mpsc::channel(1);
let _: Option<InputReport> = TouchBinding::process_reports(
report,
Some(previous_report),
&descriptor,
&mut event_sender,
);
assert_matches!(event_receiver.try_next(), Ok(Some(InputEvent { trace_id: Some(_), .. })));
}
#[test_case(true, None, TouchDeviceType::TouchScreen; "touch screen")]
#[test_case(false, None, TouchDeviceType::TouchScreen; "no mouse descriptor, no touch_input_mode")]
#[test_case(true, Some(fidl_input_report::TouchConfigurationInputMode::MouseCollection), TouchDeviceType::WindowsPrecisionTouchpad; "touchpad in mouse mode")]
#[test_case(true, Some(fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection), TouchDeviceType::WindowsPrecisionTouchpad; "touchpad in touchpad mode")]
#[fasync::run_singlethreaded(test)]
async fn windows_precision_touchpad(
has_mouse_descriptor: bool,
touch_input_mode: Option<fidl_input_report::TouchConfigurationInputMode>,
expect_touch_device_type: TouchDeviceType,
) {
let input_device_proxy = spawn_stream_handler(move |input_device_request| async move {
match input_device_request {
fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
let _ = responder.send(fidl_input_report::DeviceDescriptor {
mouse: match has_mouse_descriptor {
true => Some(fidl_input_report::MouseDescriptor {
input: Some(fidl_input_report::MouseInputDescriptor {
movement_x: None,
movement_y: None,
position_x: None,
position_y: None,
scroll_v: None,
scroll_h: None,
buttons: None,
..fidl_input_report::MouseInputDescriptor::EMPTY
}),
..fidl_input_report::MouseDescriptor::EMPTY
}),
false => None,
},
touch: Some(fidl_input_report::TouchDescriptor {
input: Some(fidl_input_report::TouchInputDescriptor {
contacts: Some(vec![fidl_input_report::ContactInputDescriptor {
position_x: Some(fidl_input_report::Axis {
range: fidl_input_report::Range { min: 1, max: 2 },
unit: fidl_input_report::Unit {
type_: fidl_input_report::UnitType::None,
exponent: 0,
},
}),
position_y: Some(fidl_input_report::Axis {
range: fidl_input_report::Range { min: 2, max: 3 },
unit: fidl_input_report::Unit {
type_: fidl_input_report::UnitType::Other,
exponent: 100000,
},
}),
pressure: Some(fidl_input_report::Axis {
range: fidl_input_report::Range { min: 3, max: 4 },
unit: fidl_input_report::Unit {
type_: fidl_input_report::UnitType::Grams,
exponent: -991,
},
}),
contact_width: Some(fidl_input_report::Axis {
range: fidl_input_report::Range { min: 5, max: 6 },
unit: fidl_input_report::Unit {
type_:
fidl_input_report::UnitType::EnglishAngularVelocity,
exponent: 123,
},
}),
contact_height: Some(fidl_input_report::Axis {
range: fidl_input_report::Range { min: 7, max: 8 },
unit: fidl_input_report::Unit {
type_: fidl_input_report::UnitType::Pascals,
exponent: 100,
},
}),
..fidl_input_report::ContactInputDescriptor::EMPTY
}]),
..fidl_input_report::TouchInputDescriptor::EMPTY
}),
..fidl_input_report::TouchDescriptor::EMPTY
}),
..fidl_input_report::DeviceDescriptor::EMPTY
});
}
fidl_input_report::InputDeviceRequest::GetFeatureReport { responder } => {
let _ = responder.send(&mut Ok(fidl_input_report::FeatureReport {
touch: Some(fidl_input_report::TouchFeatureReport {
input_mode: touch_input_mode,
..fidl_input_report::TouchFeatureReport::EMPTY
}),
..fidl_input_report::FeatureReport::EMPTY
}));
}
_ => panic!("InputDevice handler received an unexpected request"),
}
})
.unwrap();
let (device_event_sender, _) =
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
let binding = TouchBinding::new(input_device_proxy, 0, device_event_sender).await.unwrap();
pretty_assertions::assert_eq!(binding._touch_device_type, expect_touch_device_type);
}
}