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::collections::HashSet;
16use std::hash::{Hash, Hasher};
17use zx::{self as zx, MonotonicDuration};
18
19#[derive(Debug)]
20pub(crate) enum UserInputMessage {
21 ScenicKeyEvent(fidl_fuchsia_ui_input3::KeyEvent),
22 FlatlandMouseEvents(Vec<fidl_fuchsia_ui_pointer::MouseEvent>),
23 FlatlandTouchEvents(Vec<fidl_fuchsia_ui_pointer::TouchEvent>),
24}
25
26#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
28pub struct Button(pub u8);
29
30const PRIMARY_BUTTON: u8 = 1;
31
32impl Button {
33 pub fn is_primary(&self) -> bool {
36 self.0 == PRIMARY_BUTTON
37 }
38}
39
40#[derive(Clone, Debug, Default, PartialEq)]
42pub struct ButtonSet {
43 buttons: HashSet<Button>,
44}
45
46impl ButtonSet {
47 pub fn new(buttons: &HashSet<u8>) -> ButtonSet {
49 ButtonSet { buttons: buttons.iter().map(|button| Button(*button)).collect() }
50 }
51
52 pub fn new_from_flags(flags: u32) -> ButtonSet {
54 let buttons: HashSet<u8> = (0..2)
55 .filter_map(|index| {
56 let mask = 1 << index;
57 if flags & mask != 0 { Some(index + 1) } else { None }
58 })
59 .collect();
60 ButtonSet::new(&buttons)
61 }
62
63 pub fn primary_button_is_down(&self) -> bool {
65 self.buttons.contains(&Button(PRIMARY_BUTTON))
66 }
67}
68
69#[derive(Debug, Default, PartialEq, Clone, Copy)]
71pub struct Modifiers {
72 pub shift: bool,
74 pub alt: bool,
76 pub control: bool,
78 pub caps_lock: bool,
80}
81
82impl Modifiers {
83 pub(crate) fn from_pressed_keys_3(pressed_keys: &HashSet<fidl_fuchsia_input::Key>) -> Self {
84 Self {
85 shift: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftShift)
86 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightShift),
87 alt: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftAlt)
88 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightAlt),
89 control: pressed_keys.contains(&fidl_fuchsia_input::Key::LeftCtrl)
90 || pressed_keys.contains(&fidl_fuchsia_input::Key::RightCtrl),
91 caps_lock: pressed_keys.contains(&fidl_fuchsia_input::Key::CapsLock),
92 }
93 }
94
95 pub(crate) fn is_modifier(key: &fidl_fuchsia_input::Key) -> bool {
96 match key {
97 fidl_fuchsia_input::Key::LeftShift
98 | fidl_fuchsia_input::Key::RightShift
99 | fidl_fuchsia_input::Key::LeftAlt
100 | fidl_fuchsia_input::Key::RightAlt
101 | fidl_fuchsia_input::Key::LeftCtrl
102 | fidl_fuchsia_input::Key::RightCtrl
103 | fidl_fuchsia_input::Key::CapsLock => true,
104 _ => false,
105 }
106 }
107}
108
109pub mod mouse {
111 use super::*;
112 use crate::geometry::IntVector;
113
114 #[derive(Debug, PartialEq, Clone)]
116 pub enum Phase {
117 Down(Button),
119 Up(Button),
121 Moved,
123 Wheel(IntVector),
125 }
126
127 #[derive(Debug, PartialEq, Clone)]
129 pub struct Event {
130 pub buttons: ButtonSet,
132 pub phase: Phase,
134 pub location: IntPoint,
136 }
137
138 pub(crate) fn create_event(
139 event_time: u64,
140 device_id: &DeviceId,
141 button_set: &ButtonSet,
142 cursor_position: IntPoint,
143 transform: &Transform2D<f32>,
144 phase: mouse::Phase,
145 ) -> super::Event {
146 let cursor_position = transform.transform_point(cursor_position.to_f32()).to_i32();
147 let mouse_event =
148 mouse::Event { buttons: button_set.clone(), phase, location: cursor_position };
149 super::Event {
150 event_time,
151 device_id: device_id.clone(),
152 event_type: EventType::Mouse(mouse_event),
153 }
154 }
155}
156
157pub mod keyboard {
159 use super::*;
160
161 #[derive(Clone, Copy, Debug, PartialEq)]
163 pub enum Phase {
164 Pressed,
166 Released,
168 Cancelled,
170 Repeat,
172 }
173
174 #[derive(Debug, PartialEq, Clone)]
176 pub struct Event {
177 pub phase: Phase,
179 pub code_point: Option<u32>,
181 pub hid_usage: u32,
183 pub modifiers: Modifiers,
186 }
187}
188
189pub mod touch {
191 use super::*;
192
193 #[derive(Debug, Eq)]
194 pub(crate) struct RawContact {
195 pub contact_id: u32,
196 pub position: IntPoint,
197 #[allow(unused)]
199 pub pressure: Option<i64>,
200 pub contact_size: Option<IntSize>,
201 }
202
203 impl PartialEq for RawContact {
204 fn eq(&self, rhs: &Self) -> bool {
205 self.contact_id == rhs.contact_id
206 }
207 }
208
209 impl Hash for RawContact {
210 fn hash<H: Hasher>(&self, state: &mut H) {
211 self.contact_id.hash(state);
212 }
213 }
214
215 #[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
217 pub struct ContactId(pub u32);
218
219 #[derive(Debug, PartialEq, Clone)]
221 pub enum Phase {
222 Down(IntPoint, IntSize),
224 Moved(IntPoint, IntSize),
226 Up,
228 Remove,
230 Cancel,
232 }
233
234 #[derive(Debug, Clone, PartialEq)]
236 pub struct Contact {
237 pub contact_id: ContactId,
239 pub phase: Phase,
241 }
242
243 #[derive(Debug, PartialEq, Clone)]
245 pub struct Event {
246 pub contacts: Vec<Contact>,
248 pub buttons: HashSet<fidl_input_report::TouchButton>,
251 }
252}
253
254pub mod pointer {
259 use super::*;
260
261 #[derive(Debug, PartialEq, Clone)]
263 pub enum Phase {
264 Down(IntPoint),
266 Moved(IntPoint),
268 Up,
270 Remove,
272 Cancel,
274 }
275
276 #[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
278 pub enum PointerId {
279 Mouse(DeviceId),
281 Contact(touch::ContactId),
283 }
284
285 #[derive(Debug, PartialEq, Clone)]
287 pub struct Event {
288 pub phase: Phase,
290 pub pointer_id: PointerId,
292 }
293
294 impl Event {
295 pub fn new_from_mouse_event(
297 device_id: &DeviceId,
298 mouse_event: &mouse::Event,
299 ) -> Option<Self> {
300 match &mouse_event.phase {
301 mouse::Phase::Down(button) => {
302 if button.is_primary() {
303 Some(pointer::Phase::Down(mouse_event.location))
304 } else {
305 None
306 }
307 }
308 mouse::Phase::Moved => {
309 if mouse_event.buttons.primary_button_is_down() {
310 Some(pointer::Phase::Moved(mouse_event.location))
311 } else {
312 None
313 }
314 }
315 mouse::Phase::Up(button) => {
316 if button.is_primary() {
317 Some(pointer::Phase::Up)
318 } else {
319 None
320 }
321 }
322 mouse::Phase::Wheel(_) => None,
323 }
324 .and_then(|phase| Some(Self { phase, pointer_id: PointerId::Mouse(device_id.clone()) }))
325 }
326
327 pub fn new_from_contact(contact: &touch::Contact) -> Self {
329 let phase = match contact.phase {
330 touch::Phase::Down(location, ..) => pointer::Phase::Down(location),
331 touch::Phase::Moved(location, ..) => pointer::Phase::Moved(location),
332 touch::Phase::Up => pointer::Phase::Up,
333 touch::Phase::Remove => pointer::Phase::Remove,
334 touch::Phase::Cancel => pointer::Phase::Cancel,
335 };
336 Self { phase, pointer_id: PointerId::Contact(contact.contact_id) }
337 }
338 }
339}
340
341pub mod consumer_control {
346
347 #[derive(Debug, PartialEq, Clone, Copy)]
349 pub enum Phase {
350 Down,
352 Up,
354 }
355
356 #[derive(Debug, PartialEq, Clone)]
358 pub struct Event {
359 pub phase: Phase,
361 pub button: fidl_fuchsia_input::ConsumerControlButton,
363 }
364}
365
366#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)]
368pub struct DeviceId(pub String);
369
370#[derive(Debug, PartialEq, Clone)]
372pub enum EventType {
373 Mouse(mouse::Event),
375 Keyboard(keyboard::Event),
377 Touch(touch::Event),
379 ConsumerControl(consumer_control::Event),
381}
382
383#[derive(Debug, PartialEq, Clone)]
385pub struct Event {
386 pub event_time: u64,
388 pub device_id: DeviceId,
390 pub event_type: EventType,
392}
393
394async fn listen_to_instance(
395 instance: &fidl_input_report::ServiceProxy,
396 internal_sender: &InternalSender,
397) -> Result<(), Error> {
398 let device = instance.connect_to_input_device()?;
399 let descriptor = device
400 .get_descriptor()
401 .map_err(|err| format_err!("FIDL error on get_descriptor: {:?}", err))
402 .on_timeout(MonotonicInstant::after(MonotonicDuration::from_millis(200)), || {
403 Err(format_err!("FIDL timeout on get_descriptor"))
404 })
405 .await?;
406
407 let device_id = instance.instance_name().to_string();
408 internal_sender
409 .unbounded_send(MessageInternal::RegisterDevice(
410 DeviceId(device_id.clone()),
411 Box::new(descriptor),
412 ))
413 .expect("unbounded_send");
414 let input_report_sender = internal_sender.clone();
415 let (input_reports_reader_proxy, input_reports_reader_request) =
416 create_proxy::<fidl_input_report::InputReportsReaderV2Marker>();
417
418 const MAX_UNACKNOWLEDGED_REPORTS_LIMIT: u16 = 120;
419 device
420 .get_input_reports_reader_v2(input_reports_reader_request, MAX_UNACKNOWLEDGED_REPORTS_LIMIT)
421 .await
422 .expect("failed to get InputReportsReaderV2; v1 is no longer supported");
423
424 let mut event_stream = input_reports_reader_proxy.take_event_stream();
425 fasync::Task::local(async move {
426 #[expect(unused)]
428 let device = device;
429
430 while let Some(event) = event_stream.next().await {
431 match event {
432 Ok(fidl_input_report::InputReportsReaderV2Event::OnInputReports {
433 reports,
434 last_report_stamp,
435 }) => {
436 if let Err(err) =
437 input_reports_reader_proxy.acknowledge_reports(last_report_stamp)
438 {
439 eprintln!("Error acknowledging reports for {}: {}", device_id, err);
440 }
441 for report in reports {
442 input_report_sender
443 .unbounded_send(MessageInternal::InputReport(
444 DeviceId(device_id.clone()),
445 report,
446 ))
447 .expect("unbounded_send");
448 }
449 }
450 Ok(fidl_input_report::InputReportsReaderV2Event::_UnknownEvent {
451 ordinal, ..
452 }) => {
453 eprintln!("Unknown event (ordinal {}) for device {}", ordinal, device_id);
454 }
455 Err(err) => {
456 eprintln!(
457 "Error from input reports reader event stream for {}: {}",
458 device_id, err
459 );
460 break;
461 }
462 }
463 }
464 })
465 .detach();
466 Ok(())
467}
468
469pub(crate) async fn listen_for_user_input(internal_sender: InternalSender) -> Result<(), Error> {
470 let watcher_sender = internal_sender.clone();
471
472 let service = Service::open(fidl_input_report::ServiceMarker)
473 .map_err(|err| format_err!("failed to open fuchsia.input.report.Service: {:?}", err))?;
474 let mut watcher = service
475 .watch()
476 .await
477 .map_err(|err| format_err!("failed to watch fuchsia.input.report.Service: {:?}", err))?;
478
479 fasync::Task::local(async move {
480 while let Some(instance) = watcher.next().await {
481 match instance {
482 Ok(instance) => {
483 match listen_to_instance(&instance, &watcher_sender).await {
484 Err(err) => {
485 eprintln!("Error: {}: {}", instance.instance_name(), err)
486 }
487 _ => (),
488 };
489 }
490 Err(err) => {
491 eprintln!("Error watching input report service: {}", err);
492 break;
493 }
494 }
495 }
496 })
497 .detach();
498
499 Ok(())
500}
501
502pub(crate) mod flatland;
503pub(crate) mod key3;
504pub(crate) mod report;
505
506#[cfg(test)]
507mod tests;