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    use super::*;
347
348    /// Phase of a consumer control event.
349    #[derive(Debug, PartialEq, Clone, Copy)]
350    pub enum Phase {
351        /// Button went down.
352        Down,
353        /// Button came up.
354        Up,
355    }
356
357    /// A consumer control event.
358    #[derive(Debug, PartialEq, Clone)]
359    pub struct Event {
360        /// Phase of event.
361        pub phase: Phase,
362        /// USB HID for key being pressed or released.
363        pub button: fidl_input_report::ConsumerControlButton,
364    }
365}
366
367/// Unique identifier for an input device.
368#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord)]
369pub struct DeviceId(pub String);
370
371/// Enum of all supported user-input events.
372#[derive(Debug, PartialEq, Clone)]
373pub enum EventType {
374    /// Mouse event.
375    Mouse(mouse::Event),
376    /// Keyboard event.
377    Keyboard(keyboard::Event),
378    /// Touch event.
379    Touch(touch::Event),
380    /// Consumer control event.
381    ConsumerControl(consumer_control::Event),
382}
383
384/// Over user-input struct.
385#[derive(Debug, PartialEq, Clone)]
386pub struct Event {
387    /// Time of event.
388    pub event_time: u64,
389    /// Id of device producting this event.
390    pub device_id: DeviceId,
391    /// The event.
392    pub event_type: EventType,
393}
394
395async fn listen_to_instance(
396    instance: &fidl_input_report::ServiceProxy,
397    internal_sender: &InternalSender,
398) -> Result<(), Error> {
399    let device = instance.connect_to_input_device()?;
400    let descriptor = device
401        .get_descriptor()
402        .map_err(|err| format_err!("FIDL error on get_descriptor: {:?}", err))
403        .on_timeout(MonotonicInstant::after(MonotonicDuration::from_millis(200)), || {
404            Err(format_err!("FIDL timeout on get_descriptor"))
405        })
406        .await?;
407
408    let device_id = instance.instance_name().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 watcher_sender = internal_sender.clone();
452
453    let service = Service::open(fidl_input_report::ServiceMarker)
454        .map_err(|err| format_err!("failed to open fuchsia.input.report.Service: {:?}", err))?;
455    let mut watcher = service
456        .watch()
457        .await
458        .map_err(|err| format_err!("failed to watch fuchsia.input.report.Service: {:?}", err))?;
459
460    fasync::Task::local(async move {
461        while let Some(instance) = watcher.next().await {
462            match instance {
463                Ok(instance) => {
464                    match listen_to_instance(&instance, &watcher_sender).await {
465                        Err(err) => {
466                            eprintln!("Error: {}: {}", instance.instance_name(), err)
467                        }
468                        _ => (),
469                    };
470                }
471                Err(err) => {
472                    eprintln!("Error watching input report service: {}", err);
473                    break;
474                }
475            }
476        }
477    })
478    .detach();
479
480    Ok(())
481}
482
483pub(crate) mod flatland;
484pub(crate) mod key3;
485pub(crate) mod report;
486
487#[cfg(test)]
488mod tests;