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 fidl_input_report;
11use fuchsia_async::{self as fasync, MonotonicInstant, TimeoutExt};
12use fuchsia_component::client::Service;
13use futures::{StreamExt, TryFutureExt};
14use keymaps::usages::input3_key_to_hid_usage;
15use std::cell::RefCell;
16use std::collections::{HashMap, HashSet};
17use std::hash::{Hash, Hasher};
18use std::rc::{Rc, Weak};
19use zx::{self as zx, MonotonicDuration};
20
21#[derive(Debug)]
22pub(crate) enum UserInputMessage {
23 ScenicKeyEvent(fidl_fuchsia_ui_input3::KeyEvent),
24 FlatlandMouseEvents(Vec<fidl_fuchsia_ui_pointer::MouseEvent>),
25 FlatlandTouchEvents(Vec<fidl_fuchsia_ui_pointer::TouchEvent>),
26}
27
28#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
30pub struct Button(pub u8);
31
32const PRIMARY_BUTTON: u8 = 1;
33
34impl Button {
35 pub fn is_primary(&self) -> bool {
38 self.0 == PRIMARY_BUTTON
39 }
40}
41
42#[derive(Clone, Debug, Default, PartialEq)]
44pub struct ButtonSet {
45 buttons: HashSet<Button>,
46}
47
48impl ButtonSet {
49 pub fn new(buttons: &HashSet<u8>) -> ButtonSet {
51 ButtonSet { buttons: buttons.iter().map(|button| Button(*button)).collect() }
52 }
53
54 pub fn new_from_flags(flags: u32) -> ButtonSet {
56 let buttons: HashSet<u8> = (0..2)
57 .filter_map(|index| {
58 let mask = 1 << index;
59 if flags & mask != 0 { Some(index + 1) } else { None }
60 })
61 .collect();
62 ButtonSet::new(&buttons)
63 }
64
65 pub fn primary_button_is_down(&self) -> bool {
67 self.buttons.contains(&Button(PRIMARY_BUTTON))
68 }
69}
70
71#[derive(Debug, Default, PartialEq, Clone, Copy)]
73pub struct Modifiers {
74 pub shift: bool,
76 pub alt: bool,
78 pub control: bool,
80 pub caps_lock: bool,
82}
83
84impl Modifiers {
85 pub(crate) fn from_pressed_keys_3(pressed_keys: &HashSet<fidl_fuchsia_input::Key>) -> Self {
86 Self {
87 shift: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftShift)
88 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightShift),
89 alt: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftAlt)
90 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightAlt),
91 control: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftCtrl)
92 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightCtrl),
93 caps_lock: pressed_keys.contains(&fidl_fuchsia_input::Key::CapsLock),
94 }
95 }
96
97 pub(crate) fn is_modifier(key: &fidl_fuchsia_input::Key) -> bool {
98 match key {
99 fidl_fuchsia_input::Key::LeftShift
100 | fidl_fuchsia_input::Key::RightShift
101 | fidl_fuchsia_input::Key::LeftAlt
102 | fidl_fuchsia_input::Key::RightAlt
103 | fidl_fuchsia_input::Key::LeftCtrl
104 | fidl_fuchsia_input::Key::RightCtrl
105 | fidl_fuchsia_input::Key::CapsLock => true,
106 _ => false,
107 }
108 }
109}
110
111pub mod mouse {
113 use super::*;
114 use crate::geometry::IntVector;
115
116 #[derive(Debug, PartialEq, Clone)]
118 pub enum Phase {
119 Down(Button),
121 Up(Button),
123 Moved,
125 Wheel(IntVector),
127 }
128
129 #[derive(Debug, PartialEq, Clone)]
131 pub struct Event {
132 pub buttons: ButtonSet,
134 pub phase: Phase,
136 pub location: IntPoint,
138 }
139
140 pub(crate) fn create_event(
141 event_time: u64,
142 device_id: &DeviceId,
143 button_set: &ButtonSet,
144 cursor_position: IntPoint,
145 transform: &Transform2D<f32>,
146 phase: mouse::Phase,
147 ) -> super::Event {
148 let cursor_position = transform.transform_point(cursor_position.to_f32()).to_i32();
149 let mouse_event =
150 mouse::Event { buttons: button_set.clone(), phase, location: cursor_position };
151 super::Event {
152 event_time,
153 device_id: device_id.clone(),
154 event_type: EventType::Mouse(mouse_event),
155 }
156 }
157}
158
159pub mod keyboard {
161 use super::*;
162
163 #[derive(Clone, Copy, Debug, PartialEq)]
165 pub enum Phase {
166 Pressed,
168 Released,
170 Cancelled,
172 Repeat,
174 }
175
176 #[derive(Debug, PartialEq, Clone)]
178 pub struct Event {
179 pub phase: Phase,
181 pub code_point: Option<u32>,
183 pub hid_usage: u32,
185 pub modifiers: Modifiers,
188 }
189}
190
191pub mod touch {
193 use super::*;
194
195 #[derive(Debug, Eq)]
196 pub(crate) struct RawContact {
197 pub contact_id: u32,
198 pub position: IntPoint,
199 #[allow(unused)]
201 pub pressure: Option<i64>,
202 pub contact_size: Option<IntSize>,
203 }
204
205 impl PartialEq for RawContact {
206 fn eq(&self, rhs: &Self) -> bool {
207 self.contact_id == rhs.contact_id
208 }
209 }
210
211 impl Hash for RawContact {
212 fn hash<H: Hasher>(&self, state: &mut H) {
213 self.contact_id.hash(state);
214 }
215 }
216
217 #[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
219 pub struct ContactId(pub u32);
220
221 #[derive(Debug, PartialEq, Clone)]
223 pub enum Phase {
224 Down(IntPoint, IntSize),
226 Moved(IntPoint, IntSize),
228 Up,
230 Remove,
232 Cancel,
234 }
235
236 #[derive(Debug, Clone, PartialEq)]
238 pub struct Contact {
239 pub contact_id: ContactId,
241 pub phase: Phase,
243 }
244
245 #[derive(Debug, PartialEq, Clone)]
247 pub struct Event {
248 pub contacts: Vec<Contact>,
250 pub buttons: HashSet<fidl_input_report::TouchButton>,
253 }
254}
255
256pub mod pointer {
261 use super::*;
262
263 #[derive(Debug, PartialEq, Clone)]
265 pub enum Phase {
266 Down(IntPoint),
268 Moved(IntPoint),
270 Up,
272 Remove,
274 Cancel,
276 }
277
278 #[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
280 pub enum PointerId {
281 Mouse(DeviceId),
283 Contact(touch::ContactId),
285 }
286
287 #[derive(Debug, PartialEq, Clone)]
289 pub struct Event {
290 pub phase: Phase,
292 pub pointer_id: PointerId,
294 }
295
296 impl Event {
297 pub fn new_from_mouse_event(
299 device_id: &DeviceId,
300 mouse_event: &mouse::Event,
301 ) -> Option<Self> {
302 match &mouse_event.phase {
303 mouse::Phase::Down(button) => {
304 if button.is_primary() {
305 Some(pointer::Phase::Down(mouse_event.location))
306 } else {
307 None
308 }
309 }
310 mouse::Phase::Moved => {
311 if mouse_event.buttons.primary_button_is_down() {
312 Some(pointer::Phase::Moved(mouse_event.location))
313 } else {
314 None
315 }
316 }
317 mouse::Phase::Up(button) => {
318 if button.is_primary() {
319 Some(pointer::Phase::Up)
320 } else {
321 None
322 }
323 }
324 mouse::Phase::Wheel(_) => None,
325 }
326 .and_then(|phase| Some(Self { phase, pointer_id: PointerId::Mouse(device_id.clone()) }))
327 }
328
329 pub fn new_from_contact(contact: &touch::Contact) -> Self {
331 let phase = match contact.phase {
332 touch::Phase::Down(location, ..) => pointer::Phase::Down(location),
333 touch::Phase::Moved(location, ..) => pointer::Phase::Moved(location),
334 touch::Phase::Up => pointer::Phase::Up,
335 touch::Phase::Remove => pointer::Phase::Remove,
336 touch::Phase::Cancel => pointer::Phase::Cancel,
337 };
338 Self { phase, pointer_id: PointerId::Contact(contact.contact_id) }
339 }
340 }
341}
342
343pub mod consumer_control {
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: fidl_fuchsia_input::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
396pub(crate) fn spawn_input_report_reader(
397 device_id: DeviceId,
398 device: fidl_input_report::InputDeviceProxy,
399 input_reports_reader_proxy: fidl_input_report::InputReportsReaderV2Proxy,
400 input_report_sender: InternalSender,
401 weak_tasks: Weak<RefCell<HashMap<DeviceId, fasync::Task<()>>>>,
402) -> fasync::Task<()> {
403 let mut event_stream = input_reports_reader_proxy.take_event_stream();
404 fasync::Task::local(async move {
405 #[expect(unused)]
407 let device = device;
408
409 while let Some(event) = event_stream.next().await {
410 match event {
411 Ok(fidl_input_report::InputReportsReaderV2Event::OnInputReports {
412 reports,
413 last_report_stamp,
414 }) => {
415 if let Err(err) =
416 input_reports_reader_proxy.acknowledge_reports(last_report_stamp)
417 {
418 eprintln!("Error acknowledging reports for {}: {}", device_id.0, err);
419 }
420 for report in reports {
421 input_report_sender
423 .unbounded_send(MessageInternal::InputReport(device_id.clone(), report))
424 .expect("unbounded_send");
425 }
426 }
427 Ok(fidl_input_report::InputReportsReaderV2Event::_UnknownEvent {
428 ordinal, ..
429 }) => {
430 eprintln!("Unknown event (ordinal {}) for device {}", ordinal, device_id.0);
431 }
432 Err(err) => {
433 eprintln!(
434 "Error from input reports reader event stream for {}: {}",
435 device_id.0, err
436 );
437 break;
438 }
439 }
440 }
441
442 if let Some(tasks) = weak_tasks.upgrade() {
443 tasks.borrow_mut().remove(&device_id);
444 }
445 })
446}
447
448async fn listen_to_device(
449 device_id: DeviceId,
450 device: fidl_input_report::InputDeviceProxy,
451 internal_sender: &InternalSender,
452 weak_tasks: Weak<RefCell<HashMap<DeviceId, fasync::Task<()>>>>,
453) -> Result<fasync::Task<()>, Error> {
454 let descriptor = device
455 .get_descriptor()
456 .map_err(|err| format_err!("FIDL error on get_descriptor: {:?}", err))
457 .on_timeout(MonotonicInstant::after(MonotonicDuration::from_millis(200)), || {
458 Err(format_err!("FIDL timeout on get_descriptor"))
459 })
460 .await?;
461
462 internal_sender
463 .unbounded_send(MessageInternal::RegisterDevice(device_id.clone(), Box::new(descriptor)))
464 .expect("unbounded_send");
465 let input_report_sender = internal_sender.clone();
466 let (input_reports_reader_proxy, input_reports_reader_request) =
467 create_proxy::<fidl_input_report::InputReportsReaderV2Marker>();
468
469 const MAX_UNACKNOWLEDGED_REPORTS_LIMIT: u16 = 120;
470 device
471 .get_input_reports_reader_v2(input_reports_reader_request, MAX_UNACKNOWLEDGED_REPORTS_LIMIT)
472 .await
473 .map_err(|err| format_err!("failed to get InputReportsReaderV2: {:?}", err))?;
474
475 Ok(spawn_input_report_reader(
476 device_id,
477 device,
478 input_reports_reader_proxy,
479 input_report_sender,
480 weak_tasks,
481 ))
482}
483
484async fn listen_to_instance(
485 instance: &fidl_input_report::ServiceProxy,
486 internal_sender: &InternalSender,
487 reader_tasks: &Rc<RefCell<HashMap<DeviceId, fasync::Task<()>>>>,
488) -> Result<(), Error> {
489 let device = instance.connect_to_input_device()?;
490 let device_id = DeviceId(instance.instance_name().to_string());
491 let task =
492 listen_to_device(device_id.clone(), device, internal_sender, Rc::downgrade(reader_tasks))
493 .await?;
494 reader_tasks.borrow_mut().insert(device_id, task);
495 Ok(())
496}
497
498pub(crate) struct UserInputListener {
504 watcher_task: Option<fasync::Task<()>>,
505 reader_tasks: Rc<RefCell<HashMap<DeviceId, fasync::Task<()>>>>,
506}
507
508impl Drop for UserInputListener {
509 fn drop(&mut self) {
510 self.abort();
511 }
512}
513
514impl UserInputListener {
515 pub(crate) fn new(
516 watcher_task: Option<fasync::Task<()>>,
517 reader_tasks: Rc<RefCell<HashMap<DeviceId, fasync::Task<()>>>>,
518 ) -> Self {
519 Self { watcher_task, reader_tasks }
520 }
521
522 pub(crate) fn start(internal_sender: InternalSender) -> Result<Self, Error> {
523 let service = Service::open(fidl_input_report::ServiceMarker)
524 .map_err(|err| format_err!("failed to open fuchsia.input.report.Service: {:?}", err))?;
525 let reader_tasks = Rc::new(RefCell::new(HashMap::new()));
526 let reader_tasks_clone = reader_tasks.clone();
527
528 let watcher_task = fasync::Task::local(async move {
529 let mut watcher = match service.watch().await {
530 Ok(watcher) => watcher,
531 Err(err) => {
532 eprintln!("failed to watch fuchsia.input.report.Service: {:?}", err);
533 return;
534 }
535 };
536 while let Some(instance) = watcher.next().await {
537 match instance {
538 Ok(instance) => {
539 if let Err(err) =
540 listen_to_instance(&instance, &internal_sender, &reader_tasks_clone)
541 .await
542 {
543 eprintln!("Error: {}: {}", instance.instance_name(), err);
544 }
545 }
546 Err(err) => {
547 eprintln!("Error watching input report service: {}", err);
548 break;
549 }
550 }
551 }
552 });
553
554 Ok(Self::new(Some(watcher_task), reader_tasks))
555 }
556
557 pub(crate) fn abort(&mut self) {
558 self.watcher_task = None;
559 self.reader_tasks.borrow_mut().clear();
560 }
561
562 #[cfg(test)]
563 pub(crate) fn active_reader_count(&self) -> usize {
564 self.reader_tasks.borrow().len()
565 }
566
567 #[cfg(test)]
568 pub(crate) fn has_device(&self, device_id: &DeviceId) -> bool {
569 self.reader_tasks.borrow().contains_key(device_id)
570 }
571
572 #[cfg(test)]
573 pub(crate) fn new_for_testing() -> (Self, Rc<RefCell<HashMap<DeviceId, fasync::Task<()>>>>) {
574 let reader_tasks = Rc::new(RefCell::new(HashMap::new()));
575 let listener = Self::new(None, reader_tasks.clone());
576 (listener, reader_tasks)
577 }
578}
579
580pub(crate) mod flatland;
581pub(crate) mod key3;
582pub(crate) mod report;
583
584#[cfg(test)]
585mod tests;