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) = create_proxy();
416 device.get_input_reports_reader(input_reports_reader_request)?;
417 fasync::Task::local(async move {
418 let _device = device;
419 loop {
420 let reports_res = input_reports_reader_proxy.read_input_reports().await;
421 match reports_res {
422 Ok(r) => match r {
423 Ok(reports) => {
424 for report in reports {
425 input_report_sender
426 .unbounded_send(MessageInternal::InputReport(
427 DeviceId(device_id.clone()),
428 report,
429 ))
430 .expect("unbounded_send");
431 }
432 }
433 Err(err) => {
434 eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
435 break;
436 }
437 },
438 Err(err) => {
439 eprintln!("Error report from read_input_reports: {}: {}", device_id, err);
440 break;
441 }
442 }
443 }
444 })
445 .detach();
446 Ok(())
447}
448
449pub(crate) async fn listen_for_user_input(internal_sender: InternalSender) -> Result<(), Error> {
450 let watcher_sender = internal_sender.clone();
451
452 let service = Service::open(fidl_input_report::ServiceMarker)
453 .map_err(|err| format_err!("failed to open fuchsia.input.report.Service: {:?}", err))?;
454 let mut watcher = service
455 .watch()
456 .await
457 .map_err(|err| format_err!("failed to watch fuchsia.input.report.Service: {:?}", err))?;
458
459 fasync::Task::local(async move {
460 while let Some(instance) = watcher.next().await {
461 match instance {
462 Ok(instance) => {
463 match listen_to_instance(&instance, &watcher_sender).await {
464 Err(err) => {
465 eprintln!("Error: {}: {}", instance.instance_name(), err)
466 }
467 _ => (),
468 };
469 }
470 Err(err) => {
471 eprintln!("Error watching input report service: {}", err);
472 break;
473 }
474 }
475 }
476 })
477 .detach();
478
479 Ok(())
480}
481
482pub(crate) mod flatland;
483pub(crate) mod key3;
484pub(crate) mod report;
485
486#[cfg(test)]
487mod tests;