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