1use crate::app::{InternalSender, MessageInternal};
6use crate::geometry::{IntPoint, IntSize};
7use anyhow::{Error, format_err};
8use euclid::default::Transform2D;
9use fidl::endpoints::create_proxy;
10use fidl_fuchsia_input_report as hid_input_report;
11use fuchsia_async::{self as fasync, MonotonicInstant, TimeoutExt};
12use futures::{TryFutureExt, TryStreamExt};
13use keymaps::usages::input3_key_to_hid_usage;
14use std::collections::HashSet;
15use std::fs;
16use std::hash::{Hash, Hasher};
17use std::path::{Path, PathBuf};
18use zx::{self as zx, MonotonicDuration};
19
20#[derive(Debug)]
21pub(crate) enum UserInputMessage {
22 ScenicKeyEvent(fidl_fuchsia_ui_input3::KeyEvent),
23 FlatlandMouseEvents(Vec<fidl_fuchsia_ui_pointer::MouseEvent>),
24 FlatlandTouchEvents(Vec<fidl_fuchsia_ui_pointer::TouchEvent>),
25}
26
27#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
29pub struct Button(pub u8);
30
31const PRIMARY_BUTTON: u8 = 1;
32
33impl Button {
34 pub fn is_primary(&self) -> bool {
37 self.0 == PRIMARY_BUTTON
38 }
39}
40
41#[derive(Clone, Debug, Default, PartialEq)]
43pub struct ButtonSet {
44 buttons: HashSet<Button>,
45}
46
47impl ButtonSet {
48 pub fn new(buttons: &HashSet<u8>) -> ButtonSet {
50 ButtonSet { buttons: buttons.iter().map(|button| Button(*button)).collect() }
51 }
52
53 pub fn new_from_flags(flags: u32) -> ButtonSet {
55 let buttons: HashSet<u8> = (0..2)
56 .filter_map(|index| {
57 let mask = 1 << index;
58 if flags & mask != 0 { Some(index + 1) } else { None }
59 })
60 .collect();
61 ButtonSet::new(&buttons)
62 }
63
64 pub fn primary_button_is_down(&self) -> bool {
66 self.buttons.contains(&Button(PRIMARY_BUTTON))
67 }
68}
69
70#[derive(Debug, Default, PartialEq, Clone, Copy)]
72pub struct Modifiers {
73 pub shift: bool,
75 pub alt: bool,
77 pub control: bool,
79 pub caps_lock: bool,
81}
82
83impl Modifiers {
84 pub(crate) fn from_pressed_keys_3(pressed_keys: &HashSet<fidl_fuchsia_input::Key>) -> Self {
85 Self {
86 shift: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftShift)
87 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightShift),
88 alt: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftAlt)
89 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightAlt),
90 control: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftCtrl)
91 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightCtrl),
92 caps_lock: pressed_keys.contains(&fidl_fuchsia_input::Key::CapsLock),
93 }
94 }
95
96 pub(crate) fn is_modifier(key: &fidl_fuchsia_input::Key) -> bool {
97 match key {
98 fidl_fuchsia_input::Key::LeftShift
99 | fidl_fuchsia_input::Key::RightShift
100 | fidl_fuchsia_input::Key::LeftAlt
101 | fidl_fuchsia_input::Key::RightAlt
102 | fidl_fuchsia_input::Key::LeftCtrl
103 | fidl_fuchsia_input::Key::RightCtrl
104 | fidl_fuchsia_input::Key::CapsLock => true,
105 _ => false,
106 }
107 }
108}
109
110pub mod mouse {
112 use super::*;
113 use crate::geometry::IntVector;
114
115 #[derive(Debug, PartialEq, Clone)]
117 pub enum Phase {
118 Down(Button),
120 Up(Button),
122 Moved,
124 Wheel(IntVector),
126 }
127
128 #[derive(Debug, PartialEq, Clone)]
130 pub struct Event {
131 pub buttons: ButtonSet,
133 pub phase: Phase,
135 pub location: IntPoint,
137 }
138
139 pub(crate) fn create_event(
140 event_time: u64,
141 device_id: &DeviceId,
142 button_set: &ButtonSet,
143 cursor_position: IntPoint,
144 transform: &Transform2D<f32>,
145 phase: mouse::Phase,
146 ) -> super::Event {
147 let cursor_position = transform.transform_point(cursor_position.to_f32()).to_i32();
148 let mouse_event =
149 mouse::Event { buttons: button_set.clone(), phase, location: cursor_position };
150 super::Event {
151 event_time,
152 device_id: device_id.clone(),
153 event_type: EventType::Mouse(mouse_event),
154 }
155 }
156}
157
158pub mod keyboard {
160 use super::*;
161
162 #[derive(Clone, Copy, Debug, PartialEq)]
164 pub enum Phase {
165 Pressed,
167 Released,
169 Cancelled,
171 Repeat,
173 }
174
175 #[derive(Debug, PartialEq, Clone)]
177 pub struct Event {
178 pub phase: Phase,
180 pub code_point: Option<u32>,
182 pub hid_usage: u32,
184 pub modifiers: Modifiers,
187 }
188}
189
190pub mod touch {
192 use super::*;
193
194 #[derive(Debug, Eq)]
195 pub(crate) struct RawContact {
196 pub contact_id: u32,
197 pub position: IntPoint,
198 #[allow(unused)]
200 pub pressure: Option<i64>,
201 pub contact_size: Option<IntSize>,
202 }
203
204 impl PartialEq for RawContact {
205 fn eq(&self, rhs: &Self) -> bool {
206 self.contact_id == rhs.contact_id
207 }
208 }
209
210 impl Hash for RawContact {
211 fn hash<H: Hasher>(&self, state: &mut H) {
212 self.contact_id.hash(state);
213 }
214 }
215
216 #[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
218 pub struct ContactId(pub u32);
219
220 #[derive(Debug, PartialEq, Clone)]
222 pub enum Phase {
223 Down(IntPoint, IntSize),
225 Moved(IntPoint, IntSize),
227 Up,
229 Remove,
231 Cancel,
233 }
234
235 #[derive(Debug, Clone, PartialEq)]
237 pub struct Contact {
238 pub contact_id: ContactId,
240 pub phase: Phase,
242 }
243
244 #[derive(Debug, PartialEq, Clone)]
246 pub struct Event {
247 pub contacts: Vec<Contact>,
249 pub buttons: HashSet<hid_input_report::TouchButton>,
252 }
253}
254
255pub mod pointer {
260 use super::*;
261
262 #[derive(Debug, PartialEq, Clone)]
264 pub enum Phase {
265 Down(IntPoint),
267 Moved(IntPoint),
269 Up,
271 Remove,
273 Cancel,
275 }
276
277 #[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
279 pub enum PointerId {
280 Mouse(DeviceId),
282 Contact(touch::ContactId),
284 }
285
286 #[derive(Debug, PartialEq, Clone)]
288 pub struct Event {
289 pub phase: Phase,
291 pub pointer_id: PointerId,
293 }
294
295 impl Event {
296 pub fn new_from_mouse_event(
298 device_id: &DeviceId,
299 mouse_event: &mouse::Event,
300 ) -> Option<Self> {
301 match &mouse_event.phase {
302 mouse::Phase::Down(button) => {
303 if button.is_primary() {
304 Some(pointer::Phase::Down(mouse_event.location))
305 } else {
306 None
307 }
308 }
309 mouse::Phase::Moved => {
310 if mouse_event.buttons.primary_button_is_down() {
311 Some(pointer::Phase::Moved(mouse_event.location))
312 } else {
313 None
314 }
315 }
316 mouse::Phase::Up(button) => {
317 if button.is_primary() {
318 Some(pointer::Phase::Up)
319 } else {
320 None
321 }
322 }
323 mouse::Phase::Wheel(_) => None,
324 }
325 .and_then(|phase| Some(Self { phase, pointer_id: PointerId::Mouse(device_id.clone()) }))
326 }
327
328 pub fn new_from_contact(contact: &touch::Contact) -> Self {
330 let phase = match contact.phase {
331 touch::Phase::Down(location, ..) => pointer::Phase::Down(location),
332 touch::Phase::Moved(location, ..) => pointer::Phase::Moved(location),
333 touch::Phase::Up => pointer::Phase::Up,
334 touch::Phase::Remove => pointer::Phase::Remove,
335 touch::Phase::Cancel => pointer::Phase::Cancel,
336 };
337 Self { phase, pointer_id: PointerId::Contact(contact.contact_id) }
338 }
339 }
340}
341
342pub mod consumer_control {
347 use super::*;
348
349 #[derive(Debug, PartialEq, Clone, Copy)]
351 pub enum Phase {
352 Down,
354 Up,
356 }
357
358 #[derive(Debug, PartialEq, Clone)]
360 pub struct Event {
361 pub phase: Phase,
363 pub button: hid_input_report::ConsumerControlButton,
365 }
366}
367
368#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)]
370pub struct DeviceId(pub String);
371
372#[derive(Debug, PartialEq, Clone)]
374pub enum EventType {
375 Mouse(mouse::Event),
377 Keyboard(keyboard::Event),
379 Touch(touch::Event),
381 ConsumerControl(consumer_control::Event),
383}
384
385#[derive(Debug, PartialEq, Clone)]
387pub struct Event {
388 pub event_time: u64,
390 pub device_id: DeviceId,
392 pub event_type: EventType,
394}
395
396async fn listen_to_path(device_path: &Path, internal_sender: &InternalSender) -> Result<(), Error> {
397 let (client, server) = zx::Channel::create();
398 fdio::service_connect(device_path.to_str().expect("bad path"), server)?;
399 let client = fasync::Channel::from_channel(client);
400 let device = hid_input_report::InputDeviceProxy::new(client);
401 let descriptor = device
402 .get_descriptor()
403 .map_err(|err| format_err!("FIDL error on get_descriptor: {:?}", err))
404 .on_timeout(MonotonicInstant::after(MonotonicDuration::from_millis(200)), || {
405 Err(format_err!("FIDL timeout on get_descriptor"))
406 })
407 .await?;
408 let device_id = device_path.file_name().expect("file_name").to_string_lossy().to_string();
409 internal_sender
410 .unbounded_send(MessageInternal::RegisterDevice(
411 DeviceId(device_id.clone()),
412 Box::new(descriptor),
413 ))
414 .expect("unbounded_send");
415 let input_report_sender = internal_sender.clone();
416 let (input_reports_reader_proxy, input_reports_reader_request) = create_proxy();
417 device.get_input_reports_reader(input_reports_reader_request)?;
418 fasync::Task::local(async move {
419 let _device = device;
420 loop {
421 let reports_res = input_reports_reader_proxy.read_input_reports().await;
422 match reports_res {
423 Ok(r) => match r {
424 Ok(reports) => {
425 for report in reports {
426 input_report_sender
427 .unbounded_send(MessageInternal::InputReport(
428 DeviceId(device_id.clone()),
429 report,
430 ))
431 .expect("unbounded_send");
432 }
433 }
434 Err(err) => {
435 eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
436 break;
437 }
438 },
439 Err(err) => {
440 eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
441 break;
442 }
443 }
444 }
445 })
446 .detach();
447 Ok(())
448}
449
450pub(crate) async fn listen_for_user_input(internal_sender: InternalSender) -> Result<(), Error> {
451 let input_devices_directory = "/dev/class/input-report";
452 let watcher_sender = internal_sender.clone();
453 let path = std::path::Path::new(input_devices_directory);
454 let entries = fs::read_dir(path)?;
455 for entry in entries {
456 let entry = entry?;
457 match listen_to_path(&entry.path(), &internal_sender).await {
458 Err(err) => {
459 eprintln!("Error: {}: {}", entry.file_name().to_string_lossy(), err)
460 }
461 _ => (),
462 }
463 }
464 let dir_proxy = fuchsia_fs::directory::open_in_namespace(
465 input_devices_directory,
466 fuchsia_fs::PERM_READABLE,
467 )?;
468 let mut watcher = fuchsia_fs::directory::Watcher::new(&dir_proxy).await?;
469 fasync::Task::local(async move {
470 let input_devices_directory_path = PathBuf::from("/dev/class/input-report");
471 while let Some(msg) = (watcher.try_next()).await.expect("msg") {
472 match msg.event {
473 fuchsia_fs::directory::WatchEvent::ADD_FILE => {
474 let device_path = input_devices_directory_path.join(msg.filename);
475 match listen_to_path(&device_path, &watcher_sender).await {
476 Err(err) => {
477 eprintln!("Error: {:?}: {}", device_path, err)
478 }
479 _ => (),
480 };
481 }
482 _ => (),
483 }
484 }
485 })
486 .detach();
487
488 Ok(())
489}
490
491pub(crate) mod flatland;
492pub(crate) mod key3;
493pub(crate) mod report;
494
495#[cfg(test)]
496mod tests;