blob: e771d13506460a7524614723587a548fbf8a067f [file] [log] [blame]
// Copyright 2020 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::{
app::{InternalSender, MessageInternal},
drawing::DisplayRotation,
geometry::{IntPoint, IntRect, IntSize, LimitToBounds, Size},
view::ViewKey,
};
use anyhow::{format_err, Error};
use euclid::{default::Transform2D, point2, size2, vec2};
use fidl::endpoints::create_proxy;
use fidl_fuchsia_input_report as hid_input_report;
use fuchsia_async::{self as fasync, Time, TimeoutExt};
use fuchsia_zircon::{self as zx, Duration};
use futures::TryFutureExt;
use input_synthesis::{
keymaps::QWERTY_MAP,
usages::{input3_key_to_hid_usage, key_to_hid_usage},
};
use std::{
collections::{HashMap, HashSet},
fs::{self, DirEntry},
hash::{Hash, Hasher},
iter::FromIterator,
};
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
pub struct Button(pub u8);
const PRIMARY_BUTTON: u8 = 1;
impl Button {
pub fn is_primary(&self) -> bool {
self.0 == PRIMARY_BUTTON
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ButtonSet {
buttons: HashSet<Button>,
}
impl ButtonSet {
pub fn new(buttons: &HashSet<u8>) -> ButtonSet {
ButtonSet { buttons: buttons.iter().map(|button| Button(*button)).collect() }
}
pub fn new_from_flags(flags: u32) -> ButtonSet {
let buttons: HashSet<u8> = (0..2)
.filter_map(|index| {
let mask = 1 << index;
if flags & mask != 0 {
Some(index + 1)
} else {
None
}
})
.collect();
ButtonSet::new(&buttons)
}
pub fn primary_button_is_down(&self) -> bool {
self.buttons.contains(&Button(PRIMARY_BUTTON))
}
}
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub struct Modifiers {
pub shift: bool,
pub alt: bool,
pub control: bool,
pub caps_lock: bool,
}
impl Modifiers {
pub(crate) fn from_pressed_keys(pressed_keys: &HashSet<fidl_fuchsia_ui_input2::Key>) -> Self {
Self {
shift: pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::LeftShift)
|| pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::RightShift),
alt: pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::LeftAlt)
|| pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::RightAlt),
control: pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::LeftCtrl)
|| pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::RightCtrl),
caps_lock: pressed_keys.contains(&fidl_fuchsia_ui_input2::Key::CapsLock),
}
}
pub(crate) fn from_pressed_keys_3(pressed_keys: &HashSet<fidl_fuchsia_input::Key>) -> Self {
Self {
shift: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftShift)
|| pressed_keys.contains(&fidl_fuchsia_input::Key::RightShift),
alt: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftAlt)
|| pressed_keys.contains(&fidl_fuchsia_input::Key::RightAlt),
control: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftCtrl)
|| pressed_keys.contains(&fidl_fuchsia_input::Key::RightCtrl),
caps_lock: pressed_keys.contains(&fidl_fuchsia_input::Key::CapsLock),
}
}
}
pub mod mouse {
use super::*;
#[derive(Debug, PartialEq, Clone)]
pub enum Phase {
Down(Button),
Up(Button),
Moved,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub buttons: ButtonSet,
pub phase: Phase,
pub location: IntPoint,
}
}
#[cfg(test)]
mod mouse_tests {
use super::*;
pub fn create_test_mouse_event(button: u8) -> Event {
let mouse_event = mouse::Event {
buttons: ButtonSet::default(),
phase: mouse::Phase::Down(Button(button)),
location: IntPoint::zero(),
};
Event {
event_time: 0,
device_id: device_id_tests::create_test_device_id(),
event_type: EventType::Mouse(mouse_event),
}
}
}
fn code_point_from_usage(hid_usage: usize, shift: bool) -> Option<u32> {
if hid_usage < QWERTY_MAP.len() {
if let Some(map_entry) = QWERTY_MAP[hid_usage] {
if shift {
map_entry.1.and_then(|shifted_char| Some(shifted_char as u32))
} else {
Some(map_entry.0 as u32)
}
} else {
None
}
} else {
None
}
}
pub mod keyboard {
use super::*;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Phase {
Pressed,
Released,
Cancelled,
Repeat,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub phase: Phase,
pub code_point: Option<u32>,
pub hid_usage: u32,
pub modifiers: Modifiers,
}
}
pub mod touch {
use super::*;
#[derive(Debug, Eq)]
pub(crate) struct RawContact {
pub contact_id: u32,
pub position: IntPoint,
pub pressure: Option<i64>,
pub contact_size: Option<IntSize>,
}
impl PartialEq for RawContact {
fn eq(&self, rhs: &Self) -> bool {
self.contact_id == rhs.contact_id
}
}
impl Hash for RawContact {
fn hash<H: Hasher>(&self, state: &mut H) {
self.contact_id.hash(state);
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
pub struct ContactId(pub u32);
#[derive(Debug, PartialEq, Clone)]
pub enum Phase {
Down(IntPoint, IntSize),
Moved(IntPoint, IntSize),
Up,
Remove,
Cancel,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Contact {
pub contact_id: ContactId,
pub phase: Phase,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub contacts: Vec<Contact>,
pub buttons: ButtonSet,
}
}
#[cfg(test)]
mod touch_tests {
use super::*;
pub fn create_test_contact() -> touch::Contact {
touch::Contact {
contact_id: touch::ContactId(100),
phase: touch::Phase::Down(IntPoint::zero(), IntSize::zero()),
}
}
}
pub mod pointer {
use super::*;
#[derive(Debug, PartialEq, Clone)]
pub enum Phase {
Down(IntPoint),
Moved(IntPoint),
Up,
Remove,
Cancel,
}
#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
pub enum PointerId {
Mouse(DeviceId),
Contact(touch::ContactId),
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub phase: Phase,
pub pointer_id: PointerId,
}
impl Event {
pub fn new_from_mouse_event(
device_id: &DeviceId,
mouse_event: &mouse::Event,
) -> Option<Self> {
match &mouse_event.phase {
mouse::Phase::Down(button) => {
if button.is_primary() {
Some(pointer::Phase::Down(mouse_event.location))
} else {
None
}
}
mouse::Phase::Moved => {
if mouse_event.buttons.primary_button_is_down() {
Some(pointer::Phase::Moved(mouse_event.location))
} else {
None
}
}
mouse::Phase::Up(button) => {
if button.is_primary() {
Some(pointer::Phase::Up)
} else {
None
}
}
}
.and_then(|phase| Some(Self { phase, pointer_id: PointerId::Mouse(device_id.clone()) }))
}
pub fn new_from_contact(contact: &touch::Contact) -> Self {
let phase = match contact.phase {
touch::Phase::Down(location, ..) => pointer::Phase::Down(location),
touch::Phase::Moved(location, ..) => pointer::Phase::Moved(location),
touch::Phase::Up => pointer::Phase::Up,
touch::Phase::Remove => pointer::Phase::Remove,
touch::Phase::Cancel => pointer::Phase::Cancel,
};
Self { phase, pointer_id: PointerId::Contact(contact.contact_id) }
}
}
}
#[cfg(test)]
mod pointer_tests {
use super::*;
#[test]
fn test_pointer_from_mouse() {
for button in 1..3 {
let event = mouse_tests::create_test_mouse_event(button);
match event.event_type {
EventType::Mouse(mouse_event) => {
let pointer_event =
pointer::Event::new_from_mouse_event(&event.device_id, &mouse_event);
assert_eq!(pointer_event.is_some(), button == 1);
}
_ => panic!("I asked for a mouse event"),
}
}
}
#[test]
fn test_pointer_from_contact() {
let contact = touch_tests::create_test_contact();
let pointer_event = pointer::Event::new_from_contact(&contact);
match pointer_event.phase {
pointer::Phase::Down(location) => {
assert_eq!(location, IntPoint::zero());
}
_ => panic!("This should have been a down pointer event"),
}
}
}
pub mod consumer_control {
use super::*;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Phase {
Down,
Up,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub phase: Phase,
pub button: hid_input_report::ConsumerControlButton,
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct DeviceId(pub String);
#[cfg(test)]
mod device_id_tests {
use super::*;
pub fn create_test_device_id() -> DeviceId {
DeviceId("test-device-id-1".to_string())
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum EventType {
Mouse(mouse::Event),
Keyboard(keyboard::Event),
Touch(touch::Event),
ConsumerControl(consumer_control::Event),
}
#[derive(Debug, PartialEq, Clone)]
pub struct Event {
pub event_time: u64,
pub device_id: DeviceId,
pub event_type: EventType,
}
fn device_id_for_event(event: &fidl_fuchsia_ui_input::PointerEvent) -> DeviceId {
let id_string = match event.type_ {
fidl_fuchsia_ui_input::PointerEventType::Touch => "touch",
fidl_fuchsia_ui_input::PointerEventType::Mouse => "mouse",
fidl_fuchsia_ui_input::PointerEventType::Stylus => "stylus",
fidl_fuchsia_ui_input::PointerEventType::InvertedStylus => "inverted-stylus",
};
DeviceId(format!("{}-{}", id_string, event.device_id))
}
async fn listen_to_entry(
entry: &DirEntry,
view_key: ViewKey,
internal_sender: &InternalSender,
) -> Result<(), Error> {
let (client, server) = zx::Channel::create()?;
fdio::service_connect(entry.path().to_str().expect("bad path"), server)?;
let client = fasync::Channel::from_channel(client)?;
let device = hid_input_report::InputDeviceProxy::new(client);
let descriptor = device
.get_descriptor()
.map_err(|err| format_err!("FIDL error on get_descriptor: {:?}", err))
.on_timeout(Time::after(Duration::from_millis(200)), || {
Err(format_err!("FIDL timeout on get_descriptor"))
})
.await?;
let device_id = entry.file_name().to_string_lossy().to_string();
internal_sender
.unbounded_send(MessageInternal::RegisterDevice(DeviceId(device_id.clone()), descriptor))
.expect("unbounded_send");
let input_report_sender = internal_sender.clone();
let (input_reports_reader_proxy, input_reports_reader_request) = create_proxy()?;
device.get_input_reports_reader(input_reports_reader_request)?;
fasync::Task::local(async move {
let _device = device;
loop {
let reports_res = input_reports_reader_proxy.read_input_reports().await;
match reports_res {
Ok(r) => match r {
Ok(reports) => {
for report in reports {
input_report_sender
.unbounded_send(MessageInternal::InputReport(
DeviceId(device_id.clone()),
view_key,
report,
))
.expect("unbounded_send");
}
}
Err(err) => {
eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
}
},
Err(err) => {
eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
}
}
}
})
.detach();
Ok(())
}
pub(crate) async fn listen_for_user_input(
view_key: ViewKey,
internal_sender: InternalSender,
) -> Result<(), Error> {
let input_devices_directory = "/dev/class/input-report";
let path = std::path::Path::new(input_devices_directory);
let entries = fs::read_dir(path)?;
for entry in entries {
let entry = entry?;
match listen_to_entry(&entry, view_key, &internal_sender).await {
Err(err) => {
eprintln!("Error: {}: {}", entry.file_name().to_string_lossy().to_string(), err)
}
_ => (),
}
}
Ok(())
}
#[derive(Debug)]
struct TouchScale {
target_size: IntSize,
x: hid_input_report::Range,
x_span: f32,
y: hid_input_report::Range,
y_span: f32,
}
fn restrict_to_range(value: i64, range: &hid_input_report::Range) -> i64 {
if value < range.min {
range.min
} else if value > range.max {
range.max
} else {
value
}
}
fn scale_value(value: i64, span: f32, range: &hid_input_report::Range, value_max: i32) -> i32 {
let value = restrict_to_range(value, range) - range.min;
let value_fraction = value as f32 / span;
(value_fraction * value_max as f32) as i32
}
impl TouchScale {
fn calculate_span(range: &hid_input_report::Range) -> f32 {
if range.max <= range.min {
1.0
} else {
(range.max - range.min) as f32
}
}
pub fn new(
target_size: &IntSize,
x: &hid_input_report::Range,
y: &hid_input_report::Range,
) -> Self {
Self {
target_size: *target_size,
x: *x,
x_span: Self::calculate_span(x),
y: *y,
y_span: Self::calculate_span(y),
}
}
pub fn scale(&self, pt: &IntPoint) -> IntPoint {
let x = scale_value(pt.x as i64, self.x_span, &self.x, self.target_size.width);
let y = scale_value(pt.y as i64, self.y_span, &self.y, self.target_size.height);
point2(x, y)
}
}
#[derive(Default)]
pub(crate) struct InputReportHandler {
view_size: IntSize,
display_rotation: DisplayRotation,
touch_scale: Option<TouchScale>,
cursor_position: IntPoint,
pressed_mouse_buttons: HashSet<u8>,
pressed_keys: HashSet<fidl_fuchsia_ui_input2::Key>,
raw_contacts: HashSet<touch::RawContact>,
pressed_consumer_control_buttons: HashSet<hid_input_report::ConsumerControlButton>,
}
impl InputReportHandler {
pub fn new(
size: IntSize,
display_rotation: DisplayRotation,
device_descriptor: &hid_input_report::DeviceDescriptor,
) -> InputReportHandler {
let touch_scale = device_descriptor
.touch
.as_ref()
.and_then(|touch| touch.input.as_ref())
.and_then(|input_descriptor| input_descriptor.contacts.as_ref())
.and_then(|contacts| contacts.first())
.and_then(|contact_input_descriptor| {
if contact_input_descriptor.position_x.is_some()
&& contact_input_descriptor.position_y.is_some()
{
Some(TouchScale::new(
&size,
&contact_input_descriptor.position_x.as_ref().expect("position_x").range,
&contact_input_descriptor.position_y.as_ref().expect("position_x").range,
))
} else {
None
}
});
Self::new_with_scale(size, display_rotation, touch_scale)
}
fn new_with_scale(
size: IntSize,
display_rotation: DisplayRotation,
touch_scale: Option<TouchScale>,
) -> Self {
Self { view_size: size, display_rotation, touch_scale, ..InputReportHandler::default() }
}
fn handle_mouse_input_report(
&mut self,
event_time: u64,
device_id: &DeviceId,
mouse: &hid_input_report::MouseInputReport,
) -> Vec<Event> {
fn create_mouse_event(
event_time: u64,
device_id: &DeviceId,
button_set: &ButtonSet,
cursor_position: IntPoint,
transform: &Transform2D<f32>,
phase: mouse::Phase,
) -> Event {
let cursor_position = transform.transform_point(cursor_position.to_f32()).to_i32();
let mouse_event =
mouse::Event { buttons: button_set.clone(), phase, location: cursor_position };
Event {
event_time,
device_id: device_id.clone(),
event_type: EventType::Mouse(mouse_event),
}
}
let transform = self.display_rotation.inv_transform(&self.view_size.to_f32());
let new_cursor_position = self.cursor_position
+ vec2(mouse.movement_x.unwrap_or(0) as i32, mouse.movement_y.unwrap_or(0) as i32);
let m = self.view_size;
let bounds = IntRect::new(IntPoint::zero(), m);
let new_cursor_position = bounds.limit_to_bounds(new_cursor_position);
let pressed_buttons: HashSet<u8> = if let Some(ref pressed_buttons) = mouse.pressed_buttons
{
let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
pressed_buttons_set
} else {
HashSet::new()
};
let button_set = ButtonSet::new(&pressed_buttons);
let move_event = if new_cursor_position != self.cursor_position {
let event = create_mouse_event(
event_time,
device_id,
&button_set,
new_cursor_position,
&transform,
mouse::Phase::Moved,
);
Some(event)
} else {
None
};
self.cursor_position = new_cursor_position;
let newly_pressed = pressed_buttons.difference(&self.pressed_mouse_buttons).map(|button| {
create_mouse_event(
event_time,
device_id,
&button_set,
new_cursor_position,
&transform,
mouse::Phase::Down(Button(*button)),
)
});
let released = self.pressed_mouse_buttons.difference(&pressed_buttons).map(|button| {
create_mouse_event(
event_time,
device_id,
&button_set,
new_cursor_position,
&transform,
mouse::Phase::Up(Button(*button)),
)
});
let events = newly_pressed.chain(move_event).chain(released).collect();
self.pressed_mouse_buttons = pressed_buttons;
events
}
fn handle_keyboard_input_report(
&mut self,
event_time: u64,
device_id: &DeviceId,
keyboard: &hid_input_report::KeyboardInputReport,
) -> Vec<Event> {
fn create_keyboard_event(
event_time: u64,
device_id: &DeviceId,
phase: keyboard::Phase,
key: fidl_fuchsia_ui_input2::Key,
modifiers: &Modifiers,
) -> Event {
let hid_usage = key_to_hid_usage(key);
let hid_usage_size = hid_usage as usize;
let code_point = code_point_from_usage(hid_usage_size, modifiers.shift);
let keyboard_event =
keyboard::Event { phase, code_point, hid_usage, modifiers: Modifiers::default() };
Event {
event_time,
device_id: device_id.clone(),
event_type: EventType::Keyboard(keyboard_event),
}
}
let pressed_keys: HashSet<fidl_fuchsia_ui_input2::Key> =
if let Some(ref pressed_keys) = keyboard.pressed_keys {
HashSet::from_iter(pressed_keys.iter().map(|key| *key))
} else {
HashSet::new()
};
let modifiers = Modifiers::from_pressed_keys(&pressed_keys);
let newly_pressed = pressed_keys.difference(&self.pressed_keys).map(|key| {
create_keyboard_event(event_time, device_id, keyboard::Phase::Pressed, *key, &modifiers)
});
let released = self.pressed_keys.difference(&pressed_keys).map(|key| {
create_keyboard_event(
event_time,
device_id,
keyboard::Phase::Released,
*key,
&modifiers,
)
});
let events = newly_pressed.chain(released).collect();
self.pressed_keys = pressed_keys;
events
}
fn handle_touch_input_report(
&mut self,
event_time: u64,
device_id: &DeviceId,
touch: &hid_input_report::TouchInputReport,
) -> Vec<Event> {
if self.touch_scale.is_none() {
return Vec::new();
}
let pressed_buttons: HashSet<u8> = if let Some(ref pressed_buttons) = touch.pressed_buttons
{
let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
pressed_buttons_set
} else {
HashSet::new()
};
let button_set = ButtonSet::new(&pressed_buttons);
let raw_contacts: HashSet<touch::RawContact> = if let Some(ref contacts) = touch.contacts {
let id_iter = contacts.iter().filter_map(|contact| {
if contact.position_x.is_none() || contact.position_y.is_none() {
return None;
}
let contact_id = contact.contact_id.expect("contact_id");
let contact_size =
if contact.contact_width.is_none() || contact.contact_height.is_none() {
None
} else {
Some(size2(
contact.contact_width.expect("contact_width") as i32,
contact.contact_height.expect("contact_height") as i32,
))
};
Some(touch::RawContact {
contact_id,
position: point2(
contact.position_x.expect("position_x") as i32,
contact.position_y.expect("position_y") as i32,
),
contact_size,
pressure: contact.pressure,
})
});
HashSet::from_iter(id_iter)
} else {
HashSet::new()
};
let transform = self.display_rotation.inv_transform(&self.view_size.to_f32());
let touch_scale = self.touch_scale.as_ref().expect("touch_scale");
let t = |point: IntPoint| transform.transform_point(point.to_f32()).to_i32();
let maintained_contacts =
self.raw_contacts.intersection(&raw_contacts).map(|raw_contact| touch::Contact {
contact_id: touch::ContactId(raw_contact.contact_id),
phase: touch::Phase::Moved(
t(touch_scale.scale(&raw_contact.position)),
raw_contact.contact_size.unwrap_or_else(|| IntSize::zero()),
),
});
let new_contacts =
raw_contacts.difference(&self.raw_contacts).map(|raw_contact| touch::Contact {
contact_id: touch::ContactId(raw_contact.contact_id),
phase: touch::Phase::Down(
t(touch_scale.scale(&raw_contact.position)),
raw_contact.contact_size.unwrap_or_else(|| IntSize::zero()),
),
});
let ended_contacts =
self.raw_contacts.difference(&raw_contacts).map(|raw_contact| touch::Contact {
contact_id: touch::ContactId(raw_contact.contact_id),
phase: touch::Phase::Up,
});
let contacts: Vec<touch::Contact> =
new_contacts.chain(maintained_contacts).chain(ended_contacts).collect();
self.raw_contacts = raw_contacts;
let touch_event = touch::Event { contacts: contacts, buttons: button_set };
let event = Event {
event_time,
device_id: device_id.clone(),
event_type: EventType::Touch(touch_event),
};
vec![event]
}
fn handle_consumer_control_report(
&mut self,
event_time: u64,
device_id: &DeviceId,
consumer_control: &hid_input_report::ConsumerControlInputReport,
) -> Vec<Event> {
fn create_consumer_control_event(
event_time: u64,
device_id: &DeviceId,
phase: consumer_control::Phase,
button: hid_input_report::ConsumerControlButton,
) -> Event {
let consumer_control_event = consumer_control::Event { phase, button };
Event {
event_time,
device_id: device_id.clone(),
event_type: EventType::ConsumerControl(consumer_control_event),
}
}
let pressed_consumer_control_buttons: HashSet<hid_input_report::ConsumerControlButton> =
if let Some(ref pressed_buttons) = consumer_control.pressed_buttons {
let pressed_buttons_set = pressed_buttons.iter().cloned().collect();
pressed_buttons_set
} else {
HashSet::new()
};
let newly_pressed = pressed_consumer_control_buttons
.difference(&self.pressed_consumer_control_buttons)
.map(|button| {
create_consumer_control_event(
event_time,
device_id,
consumer_control::Phase::Down,
*button,
)
});
let released = self
.pressed_consumer_control_buttons
.difference(&pressed_consumer_control_buttons)
.map(|button| {
create_consumer_control_event(
event_time,
device_id,
consumer_control::Phase::Up,
*button,
)
});
let events = newly_pressed.chain(released).collect();
self.pressed_consumer_control_buttons = pressed_consumer_control_buttons;
events
}
pub fn handle_input_report(
&mut self,
device_id: &DeviceId,
input_report: &hid_input_report::InputReport,
) -> Vec<Event> {
let mut events = Vec::new();
let event_time = input_report.event_time.unwrap_or(0) as u64;
if let Some(mouse) = input_report.mouse.as_ref() {
events.extend(self.handle_mouse_input_report(event_time, device_id, mouse));
}
if let Some(keyboard) = input_report.keyboard.as_ref() {
events.extend(self.handle_keyboard_input_report(event_time, &device_id, keyboard));
}
if let Some(touch) = input_report.touch.as_ref() {
events.extend(self.handle_touch_input_report(event_time, &device_id, touch));
}
if let Some(consumer_control) = input_report.consumer_control.as_ref() {
events.extend(self.handle_consumer_control_report(
event_time,
&device_id,
consumer_control,
));
}
events
}
}
#[cfg(test)]
mod input_report_tests {
use super::*;
use itertools::assert_equal;
fn make_input_handler() -> InputReportHandler {
let test_size = size2(1024, 768);
let touch_scale = TouchScale {
target_size: test_size,
x: fidl_fuchsia_input_report::Range { min: 0, max: 4095 },
x_span: 4095.0,
y: fidl_fuchsia_input_report::Range { min: 0, max: 4095 },
y_span: 4095.0,
};
InputReportHandler::new_with_scale(test_size, DisplayRotation::Deg0, Some(touch_scale))
}
#[test]
fn test_typed_string() {
let reports = test_data::hello_world_keyboard_reports();
let mut input_handler = make_input_handler();
let device_id = DeviceId("keyboard-1".to_string());
let chars_from_events = reports
.iter()
.map(|input_report| input_handler.handle_input_report(&device_id, input_report))
.flatten()
.filter_map(|event| match event.event_type {
EventType::Keyboard(keyboard_event) => match keyboard_event.phase {
keyboard::Phase::Pressed => keyboard_event
.code_point
.and_then(|code_point| Some(code_point as u8 as char)),
_ => None,
},
_ => None,
});
assert_equal("Hello World".chars(), chars_from_events);
}
#[test]
fn test_touch_drag() {
let reports = test_data::touch_drag_input_reports();
let device_id = DeviceId("touch-1".to_string());
let mut input_handler = make_input_handler();
let events = reports
.iter()
.map(|input_report| input_handler.handle_input_report(&device_id, input_report))
.flatten();
let mut start_point = IntPoint::zero();
let mut end_point = IntPoint::zero();
let mut move_count = 0;
for event in events {
match event.event_type {
EventType::Touch(touch_event) => {
let contact = touch_event.contacts.iter().nth(0).expect("first contact");
match contact.phase {
touch::Phase::Down(location, _) => {
start_point = location;
}
touch::Phase::Moved(location, _) => {
end_point = location;
move_count += 1;
}
_ => (),
}
}
_ => (),
}
}
assert_eq!(start_point, point2(302, 491));
assert_eq!(end_point, point2(637, 21));
assert_eq!(move_count, 15);
}
#[test]
fn test_mouse_drag() {
let reports = test_data::mouse_drag_input_reports();
let device_id = DeviceId("touch-1".to_string());
let mut input_handler = make_input_handler();
let events = reports
.iter()
.map(|input_report| input_handler.handle_input_report(&device_id, input_report))
.flatten();
let mut start_point = IntPoint::zero();
let mut end_point = IntPoint::zero();
let mut move_count = 0;
let mut down_button = None;
for event in events {
match event.event_type {
EventType::Mouse(mouse_event) => match mouse_event.phase {
mouse::Phase::Down(button) => {
assert!(down_button.is_none());
assert!(button.is_primary());
start_point = mouse_event.location;
down_button = Some(button);
}
mouse::Phase::Moved => {
end_point = mouse_event.location;
move_count += 1;
}
mouse::Phase::Up(button) => {
assert!(button.is_primary());
}
},
_ => (),
}
}
assert!(down_button.expect("down_button").is_primary());
assert_eq!(start_point, point2(129, 44));
assert_eq!(end_point, point2(616, 213));
assert_eq!(move_count, 181);
}
#[test]
fn test_consumer_control() {
use hid_input_report::ConsumerControlButton::{VolumeDown, VolumeUp};
let reports = test_data::consumer_control_input_reports();
let device_id = DeviceId("cc-1".to_string());
let mut input_handler = make_input_handler();
let events: Vec<(consumer_control::Phase, hid_input_report::ConsumerControlButton)> =
reports
.iter()
.map(|input_report| input_handler.handle_input_report(&device_id, input_report))
.flatten()
.filter_map(|event| match event.event_type {
EventType::ConsumerControl(consumer_control_event) => {
Some((consumer_control_event.phase, consumer_control_event.button))
}
_ => None,
})
.collect();
let expected = [
(consumer_control::Phase::Down, VolumeUp),
(consumer_control::Phase::Up, VolumeUp),
(consumer_control::Phase::Down, VolumeDown),
(consumer_control::Phase::Up, VolumeDown),
];
assert_eq!(events, expected);
}
}
// Scenic has a logical/physical coordinate system scheme that Carnelian does not currently
// want to expose.
fn to_physical_point(x: f32, y: f32, metrics: &Size) -> IntPoint {
let x = x * metrics.width;
let y = y * metrics.height;
point2(x as i32, y as i32)
}
#[derive(Default)]
pub(crate) struct ScenicInputHandler {
contacts: HashMap<u32, touch::Contact>,
keyboard_device_id: DeviceId,
pressed_keys: HashSet<fidl_fuchsia_input::Key>,
}
impl ScenicInputHandler {
pub fn new() -> Self {
Self {
keyboard_device_id: DeviceId("scenic-keyboard".to_string()),
contacts: HashMap::new(),
pressed_keys: HashSet::new(),
}
}
fn convert_scenic_mouse_phase(
&self,
event: &fidl_fuchsia_ui_input::PointerEvent,
) -> Option<mouse::Phase> {
let buttons = event.buttons;
let pressed_buttons: HashSet<u8> = (0..3)
.filter_map(|index| if buttons & 1 << index != 0 { Some(index + 1) } else { None })
.collect();
match event.phase {
fidl_fuchsia_ui_input::PointerEventPhase::Down => pressed_buttons
.iter()
.nth(0)
.and_then(|button| Some(mouse::Phase::Down(Button(*button)))),
fidl_fuchsia_ui_input::PointerEventPhase::Move => Some(mouse::Phase::Moved),
fidl_fuchsia_ui_input::PointerEventPhase::Up => pressed_buttons
.iter()
.nth(0)
.and_then(|button| Some(mouse::Phase::Up(Button(*button)))),
_ => None,
}
}
fn handle_touch_event(
&mut self,
metrics: &Size,
event: &fidl_fuchsia_ui_input::PointerEvent,
) -> Option<Event> {
let device_id = device_id_for_event(event);
let location = to_physical_point(event.x, event.y, metrics);
let phase = match event.phase {
fidl_fuchsia_ui_input::PointerEventPhase::Down => {
Some(touch::Phase::Down(location, IntSize::zero()))
}
fidl_fuchsia_ui_input::PointerEventPhase::Move => {
Some(touch::Phase::Moved(location, IntSize::zero()))
}
fidl_fuchsia_ui_input::PointerEventPhase::Up => Some(touch::Phase::Up),
fidl_fuchsia_ui_input::PointerEventPhase::Remove => Some(touch::Phase::Remove),
fidl_fuchsia_ui_input::PointerEventPhase::Cancel => Some(touch::Phase::Cancel),
_ => None,
};
if let Some(phase) = phase {
let contact = touch::Contact { contact_id: touch::ContactId(event.pointer_id), phase };
self.contacts.insert(event.pointer_id, contact);
let contacts: Vec<touch::Contact> = self.contacts.values().map(|v| v.clone()).collect();
self.contacts.retain(|_, contact| match contact.phase {
touch::Phase::Remove => false,
touch::Phase::Cancel => false,
_ => true,
});
let buttons = ButtonSet::new_from_flags(event.buttons);
let touch_event = touch::Event { buttons, contacts };
let new_event = Event {
event_type: EventType::Touch(touch_event),
device_id: device_id,
event_time: event.event_time,
};
Some(new_event)
} else {
None
}
}
fn handle_scenic_pointer_event(
&mut self,
metrics: &Size,
event: &fidl_fuchsia_ui_input::PointerEvent,
) -> Vec<Event> {
let mut events = Vec::new();
let location = to_physical_point(event.x, event.y, metrics);
match event.type_ {
fidl_fuchsia_ui_input::PointerEventType::Touch => {
let new_event = self.handle_touch_event(metrics, event);
events.extend(new_event);
}
fidl_fuchsia_ui_input::PointerEventType::Mouse => {
if let Some(phase) = self.convert_scenic_mouse_phase(&event) {
let device_id = device_id_for_event(event);
let mouse_input = mouse::Event {
location,
buttons: ButtonSet::new_from_flags(event.buttons),
phase: phase,
};
let new_event = Event {
event_type: EventType::Mouse(mouse_input),
device_id: device_id,
event_time: event.event_time,
};
events.push(new_event);
}
}
_ => (),
}
events
}
pub fn handle_scenic_input_event(
&mut self,
metrics: &Size,
event: &fidl_fuchsia_ui_input::InputEvent,
) -> Vec<Event> {
let mut events = Vec::new();
match event {
fidl_fuchsia_ui_input::InputEvent::Pointer(pointer_event) => {
events.extend(self.handle_scenic_pointer_event(metrics, &pointer_event));
}
_ => (),
}
events
}
pub fn handle_scenic_key_event(
&mut self,
event: &fidl_fuchsia_ui_input3::KeyEvent,
) -> Vec<Event> {
if event.type_.is_none() || event.timestamp.is_none() || event.key.is_none() {
println!("Malformed scenic key event {:?}", event);
return vec![];
}
let event_type = event.type_.unwrap();
let timestamp = event.timestamp.unwrap() as u64;
let key = event.key.unwrap();
let phase: Option<keyboard::Phase> = match event_type {
fidl_fuchsia_ui_input3::KeyEventType::Pressed => Some(keyboard::Phase::Pressed),
fidl_fuchsia_ui_input3::KeyEventType::Released => Some(keyboard::Phase::Released),
fidl_fuchsia_ui_input3::KeyEventType::Cancel => Some(keyboard::Phase::Cancelled),
// The input3 sync feature is not supported
fidl_fuchsia_ui_input3::KeyEventType::Sync => None,
};
if phase.is_none() {
return vec![];
}
let phase = phase.unwrap();
match phase {
keyboard::Phase::Pressed => {
self.pressed_keys.insert(key);
}
keyboard::Phase::Released | keyboard::Phase::Cancelled => {
self.pressed_keys.remove(&key);
}
_ => (),
}
let device_id = self.keyboard_device_id.clone();
let hid_usage = input3_key_to_hid_usage(key);
let modifiers = Modifiers::from_pressed_keys_3(&self.pressed_keys);
let code_point = code_point_from_usage(hid_usage as usize, modifiers.shift);
let keyboard_event = keyboard::Event { code_point, hid_usage, modifiers, phase };
let event = Event {
event_time: timestamp,
event_type: EventType::Keyboard(keyboard_event),
device_id,
};
vec![event]
}
}
#[cfg(test)]
mod scenic_input_tests {
use super::*;
use itertools::assert_equal;
#[test]
fn test_typed_string() {
let scenic_events = test_data::hello_world_scenic_input_events();
let mut scenic_input_handler = ScenicInputHandler::new();
let chars_from_events = scenic_events
.iter()
.map(|event| scenic_input_handler.handle_scenic_key_event(event))
.flatten()
.filter_map(|event| match event.event_type {
EventType::Keyboard(keyboard_event) => match keyboard_event.phase {
keyboard::Phase::Pressed => keyboard_event
.code_point
.and_then(|code_point| Some(code_point as u8 as char)),
_ => None,
},
_ => None,
});
assert_equal("Hello World".chars(), chars_from_events);
}
#[test]
fn test_control_r() {
let scenic_events = test_data::control_r_scenic_events();
// make sure there's one and only one keydown even of the r
// key with the control modifier set.
let mut scenic_input_handler = ScenicInputHandler::new();
let expected_event_count: usize = scenic_events
.iter()
.map(|event| scenic_input_handler.handle_scenic_key_event(event))
.flatten()
.filter_map(|event| match event.event_type {
EventType::Keyboard(keyboard_event) => match keyboard_event.phase {
keyboard::Phase::Pressed => {
if keyboard_event.hid_usage
== input_synthesis::usages::Usages::HidUsageKeyR as u32
&& keyboard_event.modifiers.control
{
Some(())
} else {
None
}
}
_ => None,
},
_ => None,
})
.count();
assert_eq!(expected_event_count, 1);
}
#[test]
fn test_touch_drag() {
let scenic_events = test_data::touch_drag_scenic_events();
let mut scenic_input_handler = ScenicInputHandler::new();
let metrics = size2(1.0, 1.0);
let input_events = scenic_events
.iter()
.map(|event| scenic_input_handler.handle_scenic_input_event(&metrics, event))
.flatten();
let mut start_point = IntPoint::zero();
let mut end_point = IntPoint::zero();
let mut move_count = 0;
for event in input_events {
match event.event_type {
EventType::Touch(touch_event) => {
let contact = touch_event.contacts.iter().nth(0).expect("first contact");
match contact.phase {
touch::Phase::Down(location, _) => {
start_point = location;
}
touch::Phase::Moved(location, _) => {
end_point = location;
move_count += 1;
}
_ => (),
}
}
_ => (),
}
}
assert_eq!(start_point, point2(193, 107));
assert_eq!(end_point, point2(269, 157));
assert_eq!(move_count, 8);
}
#[test]
fn test_mouse_drag() {
let scenic_events = test_data::mouse_drag_scenic_events();
let mut scenic_input_handler = ScenicInputHandler::new();
let metrics = size2(1.0, 1.0);
let input_events = scenic_events
.iter()
.map(|event| scenic_input_handler.handle_scenic_input_event(&metrics, event))
.flatten();
let mut start_point = IntPoint::zero();
let mut end_point = IntPoint::zero();
let mut move_count = 0;
let mut down_button = None;
for event in input_events {
match event.event_type {
EventType::Mouse(mouse_event) => match mouse_event.phase {
mouse::Phase::Down(button) => {
assert!(down_button.is_none());
assert!(button.is_primary());
start_point = mouse_event.location;
down_button = Some(button);
}
mouse::Phase::Moved => {
end_point = mouse_event.location;
move_count += 1;
}
mouse::Phase::Up(button) => {
assert!(button.is_primary());
}
},
_ => (),
}
}
assert!(down_button.expect("down_button").is_primary());
assert_eq!(start_point, point2(67, 62));
assert_eq!(end_point, point2(128, 136));
assert_eq!(move_count, 36);
}
}
#[cfg(test)]
mod test_data {
pub fn consumer_control_input_reports() -> Vec<fidl_fuchsia_input_report::InputReport> {
use fidl_fuchsia_input_report::{
ConsumerControlButton::{VolumeDown, VolumeUp},
ConsumerControlInputReport, InputReport,
};
vec![
InputReport {
event_time: Some(66268999833),
mouse: None,
trace_id: Some(2),
sensor: None,
touch: None,
keyboard: None,
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some([VolumeUp].to_vec()),
..ConsumerControlInputReport::EMPTY
}),
..InputReport::EMPTY
},
InputReport {
event_time: Some(66434561666),
mouse: None,
trace_id: Some(3),
sensor: None,
touch: None,
keyboard: None,
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some([].to_vec()),
..ConsumerControlInputReport::EMPTY
}),
..InputReport::EMPTY
},
InputReport {
event_time: Some(358153537000),
mouse: None,
trace_id: Some(4),
sensor: None,
touch: None,
keyboard: None,
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some([VolumeDown].to_vec()),
..ConsumerControlInputReport::EMPTY
}),
..InputReport::EMPTY
},
InputReport {
event_time: Some(358376260958),
mouse: None,
trace_id: Some(5),
sensor: None,
touch: None,
keyboard: None,
consumer_control: Some(ConsumerControlInputReport {
pressed_buttons: Some([].to_vec()),
..ConsumerControlInputReport::EMPTY
}),
..InputReport::EMPTY
},
]
}
pub fn hello_world_keyboard_reports() -> Vec<fidl_fuchsia_input_report::InputReport> {
use {
fidl_fuchsia_input_report::{InputReport, KeyboardInputReport},
fidl_fuchsia_ui_input2::Key::*,
};
vec![
InputReport {
event_time: Some(85446402710730),
mouse: None,
trace_id: Some(189),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![LeftShift]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85446650713601),
mouse: None,
trace_id: Some(191),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![LeftShift, H]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85446738712880),
mouse: None,
trace_id: Some(193),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![LeftShift]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85446794702907),
mouse: None,
trace_id: Some(195),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85446970709193),
mouse: None,
trace_id: Some(197),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![E]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447090710657),
mouse: None,
trace_id: Some(199),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447330708990),
mouse: None,
trace_id: Some(201),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![L]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447394712460),
mouse: None,
trace_id: Some(203),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447508813465),
mouse: None,
trace_id: Some(205),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![L]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447618712982),
mouse: None,
trace_id: Some(207),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447810705156),
mouse: None,
trace_id: Some(209),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![O]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85447898703263),
mouse: None,
trace_id: Some(211),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450082706011),
mouse: None,
trace_id: Some(213),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![Space]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450156060503),
mouse: None,
trace_id: Some(215),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450418710803),
mouse: None,
trace_id: Some(217),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![LeftShift]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450594712232),
mouse: None,
trace_id: Some(219),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![LeftShift, W]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450746707982),
mouse: None,
trace_id: Some(221),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![W]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450794706822),
mouse: None,
trace_id: Some(223),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85450962706591),
mouse: None,
trace_id: Some(225),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![O]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85451050703903),
mouse: None,
trace_id: Some(227),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85451282710803),
mouse: None,
trace_id: Some(229),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![R]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85451411293149),
mouse: None,
trace_id: Some(231),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85451842714565),
mouse: None,
trace_id: Some(233),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![L]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85451962704075),
mouse: None,
trace_id: Some(235),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85452906710709),
mouse: None,
trace_id: Some(237),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![D]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85453034711602),
mouse: None,
trace_id: Some(239),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85454778708461),
mouse: None,
trace_id: Some(241),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![Enter]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(85454858706151),
mouse: None,
trace_id: Some(243),
sensor: None,
touch: None,
keyboard: Some(KeyboardInputReport {
pressed_keys: Some(vec![]),
pressed_keys3: None,
..KeyboardInputReport::EMPTY
}),
consumer_control: None,
..InputReport::EMPTY
},
]
}
pub fn touch_drag_input_reports() -> Vec<fidl_fuchsia_input_report::InputReport> {
use fidl_fuchsia_input_report::{ContactInputReport, InputReport, TouchInputReport};
vec![
InputReport {
event_time: Some(2129689875195),
mouse: None,
trace_id: Some(294),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1211),
position_y: Some(2621),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129715875833),
mouse: None,
trace_id: Some(295),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1211),
position_y: Some(2621),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129741874822),
mouse: None,
trace_id: Some(296),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1223),
position_y: Some(2607),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129767876545),
mouse: None,
trace_id: Some(297),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1267),
position_y: Some(2539),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129793872236),
mouse: None,
trace_id: Some(298),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1391),
position_y: Some(2300),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129818875839),
mouse: None,
trace_id: Some(299),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1523),
position_y: Some(2061),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129844873276),
mouse: None,
trace_id: Some(300),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1675),
position_y: Some(1781),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129870884557),
mouse: None,
trace_id: Some(301),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1743),
position_y: Some(1652),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129896870474),
mouse: None,
trace_id: Some(302),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(1875),
position_y: Some(1399),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129922876931),
mouse: None,
trace_id: Some(303),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2015),
position_y: Some(1174),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129948875990),
mouse: None,
trace_id: Some(304),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2143),
position_y: Some(935),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129973877732),
mouse: None,
trace_id: Some(305),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2275),
position_y: Some(682),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2129998870634),
mouse: None,
trace_id: Some(306),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2331),
position_y: Some(566),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2130023872212),
mouse: None,
trace_id: Some(307),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2439),
position_y: Some(314),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2130048871365),
mouse: None,
trace_id: Some(308),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2551),
position_y: Some(116),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2130071873308),
mouse: None,
trace_id: Some(309),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![ContactInputReport {
contact_id: Some(0),
position_x: Some(2643),
position_y: Some(54),
pressure: None,
contact_width: None,
contact_height: None,
..ContactInputReport::EMPTY
}]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(2130110871653),
mouse: None,
trace_id: Some(310),
sensor: None,
touch: Some(TouchInputReport {
contacts: Some(vec![]),
pressed_buttons: Some(vec![]),
..TouchInputReport::EMPTY
}),
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
]
}
pub fn mouse_drag_input_reports() -> Vec<fidl_fuchsia_input_report::InputReport> {
use fidl_fuchsia_input_report::{InputReport, MouseInputReport};
vec![
InputReport {
event_time: Some(101114216676),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(-1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(1),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101122479286),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(3),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101130223338),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(4),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101139198674),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(-1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(5),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101154621806),
mouse: Some(MouseInputReport {
movement_x: Some(3),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(6),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101162221969),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(7),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101170222632),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(-1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(8),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101178218319),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(9),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101195538881),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(10),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101202218423),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(11),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101210236557),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(12),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101218244736),
mouse: Some(MouseInputReport {
movement_x: Some(3),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(13),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101226633284),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(14),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101235789939),
mouse: Some(MouseInputReport {
movement_x: Some(4),
movement_y: Some(3),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(15),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101242227234),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(16),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101250552651),
mouse: Some(MouseInputReport {
movement_x: Some(6),
movement_y: Some(3),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(17),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101258523666),
mouse: Some(MouseInputReport {
movement_x: Some(4),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(18),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101266879375),
mouse: Some(MouseInputReport {
movement_x: Some(4),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(19),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101279470078),
mouse: Some(MouseInputReport {
movement_x: Some(5),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(20),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101282237222),
mouse: Some(MouseInputReport {
movement_x: Some(5),
movement_y: Some(3),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(21),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101290229686),
mouse: Some(MouseInputReport {
movement_x: Some(5),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(22),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101298227434),
mouse: Some(MouseInputReport {
movement_x: Some(5),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(23),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101306236833),
mouse: Some(MouseInputReport {
movement_x: Some(3),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(24),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101314225440),
mouse: Some(MouseInputReport {
movement_x: Some(4),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(25),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101322221224),
mouse: Some(MouseInputReport {
movement_x: Some(4),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(26),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101330220567),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(27),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101338229995),
mouse: Some(MouseInputReport {
movement_x: Some(3),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(28),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101346226157),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(29),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101354223947),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(30),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101362223006),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(31),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101370218719),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(2),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(32),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101378220583),
mouse: Some(MouseInputReport {
movement_x: Some(2),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(33),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101386213038),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(1),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..MouseInputReport::EMPTY
}),
trace_id: Some(34),
sensor: None,
touch: None,
keyboard: None,
consumer_control: None,
..InputReport::EMPTY
},
InputReport {
event_time: Some(101394217453),
mouse: Some(MouseInputReport {
movement_x: Some(1),
movement_y: Some(0),
scroll_v: Some(0),
scroll_h: None,
pressed_buttons: Some(vec![]),
position_x: None,
position_y: None,
..<