Skip to main content

carnelian/
input.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// A button on a mouse
27#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
28pub struct Button(pub u8);
29
30const PRIMARY_BUTTON: u8 = 1;
31
32impl Button {
33    /// Is this the primary button, usually the leftmost button on
34    /// a mouse.
35    pub fn is_primary(&self) -> bool {
36        self.0 == PRIMARY_BUTTON
37    }
38}
39
40/// A set of buttons.
41#[derive(Clone, Debug, Default, PartialEq)]
42pub struct ButtonSet {
43    buttons: HashSet<Button>,
44}
45
46impl ButtonSet {
47    /// Create a new set of buttons from input report flags.
48    pub fn new(buttons: &HashSet<u8>) -> ButtonSet {
49        ButtonSet { buttons: buttons.iter().map(|button| Button(*button)).collect() }
50    }
51
52    /// Create a new set of buttons from scenic flags.
53    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    /// Convenience function for checking if the primary button is down.
64    pub fn primary_button_is_down(&self) -> bool {
65        self.buttons.contains(&Button(PRIMARY_BUTTON))
66    }
67}
68
69/// Keyboard modifier keys.
70#[derive(Debug, Default, PartialEq, Clone, Copy)]
71pub struct Modifiers {
72    /// A shift key is down.
73    pub shift: bool,
74    /// An alt or option key is down.
75    pub alt: bool,
76    /// A control key is down.
77    pub control: bool,
78    /// A caps lock key is down.
79    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
109/// Mouse-related items
110pub mod mouse {
111    use super::*;
112    use crate::geometry::IntVector;
113
114    /// Phase of a mouse event.
115    #[derive(Debug, PartialEq, Clone)]
116    pub enum Phase {
117        /// A particular button went down.
118        Down(Button),
119        /// A particular button came up.
120        Up(Button),
121        /// The mouse moved, with or without a change in button state.
122        Moved,
123        /// The mouse wheel changed position.
124        Wheel(IntVector),
125    }
126
127    /// A mouse event.
128    #[derive(Debug, PartialEq, Clone)]
129    pub struct Event {
130        /// Pressed buttons.
131        pub buttons: ButtonSet,
132        /// Event phase.
133        pub phase: Phase,
134        /// Location of the mouse cursor during this event.
135        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
157/// Keyboard-related items.
158pub mod keyboard {
159    use super::*;
160
161    /// Phase of a keyboard event.
162    #[derive(Clone, Copy, Debug, PartialEq)]
163    pub enum Phase {
164        /// A key is pressed.
165        Pressed,
166        /// A key is released.
167        Released,
168        /// A key is no longer pressed without being released.
169        Cancelled,
170        /// A key has been held down long enough to start repeating.
171        Repeat,
172    }
173
174    /// A keyboard event.
175    #[derive(Debug, PartialEq, Clone)]
176    pub struct Event {
177        /// Event phase.
178        pub phase: Phase,
179        /// Unicode code point of the key causing the event, if any.
180        pub code_point: Option<u32>,
181        /// USB HID usage of the key causing the event.
182        pub hid_usage: u32,
183        /// Modifier keys being pressed or held in addition to the key
184        /// causing the event.
185        pub modifiers: Modifiers,
186    }
187}
188
189/// Touch-related items.
190pub 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        // TODO(https://fxbug.dev/42165549)
198        #[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    /// ID of a touch contact.
216    #[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
217    pub struct ContactId(pub u32);
218
219    /// Phase of a touch event.
220    #[derive(Debug, PartialEq, Clone)]
221    pub enum Phase {
222        /// A contact began.
223        Down(IntPoint, IntSize),
224        /// A contact moved.
225        Moved(IntPoint, IntSize),
226        /// A contact ended.
227        Up,
228        /// A contact was removed.
229        Remove,
230        /// A contact was cancelled.
231        Cancel,
232    }
233
234    /// A single contact found in a touch event.
235    #[derive(Debug, Clone, PartialEq)]
236    pub struct Contact {
237        /// ID of this contact
238        pub contact_id: ContactId,
239        /// Phase of this contact
240        pub phase: Phase,
241    }
242
243    /// A touch event.
244    #[derive(Debug, PartialEq, Clone)]
245    pub struct Event {
246        /// All the current contact in this event
247        pub contacts: Vec<Contact>,
248        /// Buttons in this touch event, possible if the touch comes
249        /// from a stylus with buttons.
250        pub buttons: HashSet<fidl_input_report::TouchButton>,
251    }
252}
253
254/// Pointer event
255///
256/// Carnelian provides a least-common-denominator pointer event that can be created from
257/// either touch events or mouse events.
258pub mod pointer {
259    use super::*;
260
261    /// Pointer phase.
262    #[derive(Debug, PartialEq, Clone)]
263    pub enum Phase {
264        /// A pointer has gone down.
265        Down(IntPoint),
266        /// A pointer has moved.
267        Moved(IntPoint),
268        /// A pointer has come up.
269        Up,
270        /// A pointer has been removed without coming up.
271        Remove,
272        /// A pointer has been cancelled.
273        Cancel,
274    }
275
276    /// Pointer ID.
277    #[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, Hash)]
278    pub enum PointerId {
279        /// ID from a mouse event.
280        Mouse(DeviceId),
281        /// ID from a contact in a touch event.
282        Contact(touch::ContactId),
283    }
284
285    /// Pointer event.
286    #[derive(Debug, PartialEq, Clone)]
287    pub struct Event {
288        /// Pointer event phase.
289        pub phase: Phase,
290        /// Pointer event pointer ID.
291        pub pointer_id: PointerId,
292    }
293
294    impl Event {
295        /// Create a pointer event from a mouse event.
296        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        /// Create a pointer event from a single contact in a touch event.
328        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
341/// Events related to "consumer control" buttons, like volume controls.
342///
343/// These events are separated because they are different devices at the driver
344/// level, but it's not clear this is the right abstraction for Carnelian.
345pub mod consumer_control {
346
347    /// Phase of a consumer control event.
348    #[derive(Debug, PartialEq, Clone, Copy)]
349    pub enum Phase {
350        /// Button went down.
351        Down,
352        /// Button came up.
353        Up,
354    }
355
356    /// A consumer control event.
357    #[derive(Debug, PartialEq, Clone)]
358    pub struct Event {
359        /// Phase of event.
360        pub phase: Phase,
361        /// USB HID for key being pressed or released.
362        pub button: fidl_fuchsia_input::ConsumerControlButton,
363    }
364}
365
366/// Unique identifier for an input device.
367#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)]
368pub struct DeviceId(pub String);
369
370/// Enum of all supported user-input events.
371#[derive(Debug, PartialEq, Clone)]
372pub enum EventType {
373    /// Mouse event.
374    Mouse(mouse::Event),
375    /// Keyboard event.
376    Keyboard(keyboard::Event),
377    /// Touch event.
378    Touch(touch::Event),
379    /// Consumer control event.
380    ConsumerControl(consumer_control::Event),
381}
382
383/// Over user-input struct.
384#[derive(Debug, PartialEq, Clone)]
385pub struct Event {
386    /// Time of event.
387    pub event_time: u64,
388    /// Id of device producting this event.
389    pub device_id: DeviceId,
390    /// The event.
391    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;