use crate::app::strategies::framebuffer::{AutoRepeatContext, AutoRepeatTimer};
use crate::app::Config;
use crate::drawing::DisplayRotation;
use crate::geometry::{IntVector, LimitToBounds};
use crate::input::{
consumer_control, input3_key_to_hid_usage, keyboard, mouse, touch, Button, ButtonSet, DeviceId,
Event, EventType, Modifiers,
};
use crate::{IntPoint, IntRect, IntSize};
use euclid::{point2, size2, vec2};
use fidl_fuchsia_input_report as hid_input_report;
use keymaps::Keymap;
use std::collections::HashSet;
#[derive(Debug)]
pub struct TouchScale {
pub target_size: IntSize,
pub x: hid_input_report::Range,
pub x_span: f32,
pub y: hid_input_report::Range,
pub 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)
}
}
fn create_keyboard_event(
event_time: u64,
device_id: &DeviceId,
phase: keyboard::Phase,
key: fidl_fuchsia_input::Key,
modifiers: &Modifiers,
keymap: &Keymap<'_>,
) -> Event {
let hid_usage = input3_key_to_hid_usage(key);
let code_point =
keymap.hid_usage_to_code_point_for_mods(hid_usage, modifiers.shift, modifiers.caps_lock);
let keyboard_event = keyboard::Event { phase, code_point, hid_usage, modifiers: *modifiers };
Event {
event_time,
device_id: device_id.clone(),
event_type: EventType::Keyboard(keyboard_event),
}
}
pub(crate) struct InputReportHandler<'a> {
device_id: DeviceId,
view_size: IntSize,
display_rotation: DisplayRotation,
touch_scale: Option<TouchScale>,
keymap: &'a Keymap<'a>,
repeating: Option<fidl_fuchsia_input::Key>,
cursor_position: IntPoint,
pressed_mouse_buttons: HashSet<u8>,
pressed_keys: HashSet<fidl_fuchsia_input::Key>,
raw_contacts: HashSet<touch::RawContact>,
pressed_consumer_control_buttons: HashSet<hid_input_report::ConsumerControlButton>,
}
impl<'a> InputReportHandler<'a> {
pub fn new(
device_id: DeviceId,
size: IntSize,
display_rotation: DisplayRotation,
device_descriptor: &hid_input_report::DeviceDescriptor,
keymap: &'a Keymap<'a>,
) -> Self {
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_y").range,
))
} else {
None
}
});
Self::new_with_scale(device_id, size, display_rotation, touch_scale, keymap)
}
pub fn new_with_scale(
device_id: DeviceId,
size: IntSize,
display_rotation: DisplayRotation,
touch_scale: Option<TouchScale>,
keymap: &'a Keymap<'a>,
) -> Self {
Self {
device_id: device_id,
view_size: size,
display_rotation,
keymap,
repeating: None,
touch_scale,
cursor_position: IntPoint::zero(),
pressed_mouse_buttons: HashSet::new(),
pressed_keys: HashSet::new(),
raw_contacts: HashSet::new(),
pressed_consumer_control_buttons: HashSet::new(),
}
}
fn handle_mouse_input_report(
&mut self,
event_time: u64,
device_id: &DeviceId,
mouse: &hid_input_report::MouseInputReport,
) -> Vec<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 = mouse::create_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| {
mouse::create_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| {
mouse::create_event(
event_time,
device_id,
&button_set,
new_cursor_position,
&transform,
mouse::Phase::Up(Button(*button)),
)
});
let wheel_v = mouse.scroll_v.unwrap_or(0) as i32;
let wheel_h = mouse.scroll_h.unwrap_or(0) as i32;
let wheel = if wheel_v != 0 || wheel_h != 0 {
Some(mouse::create_event(
event_time,
device_id,
&button_set,
new_cursor_position,
&transform,
mouse::Phase::Wheel(IntVector::new(wheel_h, wheel_v)),
))
} else {
None
};
let events = newly_pressed.chain(move_event).chain(wheel).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,
context: &mut dyn AutoRepeatTimer,
) -> Vec<Event> {
let pressed_keys: HashSet<fidl_fuchsia_input::Key> =
if let Some(ref pressed_keys) = keyboard.pressed_keys3 {
HashSet::from_iter(pressed_keys.iter().map(|key| *key))
} else {
HashSet::new()
};
let modifiers = Modifiers::from_pressed_keys_3(&pressed_keys);
let mut first_non_modifier: Option<fidl_fuchsia_input::Key> = None;
let newly_pressed = pressed_keys.difference(&self.pressed_keys).map(|key| {
if first_non_modifier.is_none() && !Modifiers::is_modifier(key) {
first_non_modifier = Some(*key);
}
create_keyboard_event(
event_time,
device_id,
keyboard::Phase::Pressed,
*key,
&modifiers,
self.keymap,
)
});
let mut repeating: Option<fidl_fuchsia_input::Key> = self.repeating.clone();
let released = self.pressed_keys.difference(&pressed_keys).map(|key| {
if repeating.as_ref() == Some(key) {
repeating = None;
}
create_keyboard_event(
event_time,
device_id,
keyboard::Phase::Released,
*key,
&modifiers,
self.keymap,
)
});
let events = newly_pressed.chain(released).collect();
self.pressed_keys = pressed_keys;
self.repeating = first_non_modifier.or(repeating);
if Config::get().keyboard_autorepeat && self.repeating.is_some() {
context.schedule_autorepeat_timer(&self.device_id);
}
events
}
pub fn handle_keyboard_autorepeat(
&mut self,
device_id: &DeviceId,
context: &mut AutoRepeatContext,
) -> Vec<Event> {
if let Some(key) = self.repeating.as_ref() {
let repeat_time = zx::MonotonicInstant::get();
let modifiers = Modifiers::from_pressed_keys_3(&self.pressed_keys);
context.continue_autorepeat_timer(&self.device_id);
let repeat = create_keyboard_event(
repeat_time.into_nanos() as u64,
device_id,
keyboard::Phase::Repeat,
*key,
&modifiers,
self.keymap,
);
vec![repeat]
} else {
context.cancel_autorepeat_timer();
Vec::new()
}
}
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,
context: &mut dyn AutoRepeatTimer,
) -> 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, context),
);
}
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
}
}