1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

mod pointer;

#[cfg(test)]
mod tests;

use fidl_fuchsia_ui_pointer as fptr;
use fuchsia_zircon as zx;
use futures::{
    channel::mpsc::{self, UnboundedSender},
    stream, Stream, StreamExt,
};

use crate::pointer::PointerFusionState;

#[derive(Clone, Default, Debug, PartialEq)]
pub enum DeviceKind {
    #[default]
    Touch,
    Mouse,
    Stylus,
    InvertedStylus,
    Trackpad,
}

#[derive(Clone, Default, Debug, PartialEq)]
pub enum Phase {
    #[default]
    Cancel,
    Add,
    Remove,
    Hover,
    Down,
    Move,
    Up,
}

#[derive(Clone, Default, Debug, PartialEq)]
pub enum SignalKind {
    #[default]
    None,
    Scroll,
}

#[derive(Clone, Default, Debug, PartialEq)]
pub enum Status {
    #[default]
    None,
    Entered,
    Exited,
}

pub const POINTER_BUTTON_1: i64 = 1 << 0;
pub const POINTER_BUTTON_2: i64 = 1 << 1;
pub const POINTER_BUTTON_3: i64 = 1 << 2;
pub const POINTER_BUTTON_4: i64 = 1 << 3;
pub const POINTER_BUTTON_5: i64 = 1 << 4;

/// Information about the state of a pointer.
#[derive(Clone, Default, Debug)]
pub struct PointerEvent {
    /// The monotonically increasing identifier that is present only on 'Down' events and
    /// is 0 otherwise.
    pub id: i64,
    /// The kind of input device.
    pub kind: DeviceKind,
    /// The timestamp when the event originated. This is monotonically increasing for the same
    /// [DeviceKind]. Timestamp for synthesized events is same as event synthesized from.
    pub timestamp: zx::Time,
    /// The current [Phase] of pointer event.
    pub phase: Phase,
    /// The unique device identifier.
    pub device_id: u32,
    /// The identifier for the pointer that issued this event when [DeviceKind] is [Touch].
    pub pointer_id: Option<u32>,
    /// The x position of the device, in the viewport's coordinate system, as reported by the raw
    /// device event.
    pub physical_x: f32,
    /// The y position of the device, in the viewport's coordinate system, as reported by the raw
    /// device event.
    pub physical_y: f32,
    /// The relative change in x position of the device from previous event in sequence.
    pub physical_delta_x: f32,
    /// The relative change in y position of the device from previous event in sequence.
    pub physical_delta_y: f32,
    /// The x position of the device, in the view's logical coordinate system.
    pub logical_x: f32,
    /// The y position of the device, in the view's logical coordinate system.
    pub logical_y: f32,
    /// The relative change in x position of the device from previous event in sequence, in the
    /// view's logical coordinate system.
    pub logical_delta_x: f32,
    /// The relative change in y position of the device from previous event in sequence, in the
    /// view's logical coordinate system.
    pub logical_delta_y: f32,
    /// The buttons pressed on the device represented as bitflags.
    pub buttons: i64,
    /// The event [SignalKind] for scroll events.
    pub signal_kind: SignalKind,
    /// The amount of scroll in x direction, in physical pixels.
    pub physical_scroll_delta_y: f64,
    /// The amount of scroll in y direction, in physical pixels.
    pub physical_scroll_delta_x: f64,
    /// The amount of scroll in x direction, in logical pixels.
    pub logical_scroll_delta_y: f64,
    /// The amount of scroll in y direction, in logical pixels.
    pub logical_scroll_delta_x: f64,
    /// Set if this [PointerEvent] was synthesized for maintaining legal input sequence.
    pub synthesized: bool,
    /// The status of pointer if it has entered or exited the viewport. None for touch source.
    pub status: Status,
}

#[derive(Debug)]
pub enum InputEvent {
    MouseEvent(fptr::MouseEvent),
    TouchEvent(fptr::TouchEvent),
}

/// Provides a stream of [PointerEvent] fused from [InputEvent::MouseEvent] and
/// [InputEvent::TouchEvent].
///
/// * `pixel_ratio` -  The device pixel ratio used to convert from logical to physical coordinates.
///
/// Returns a tuple of [UnboundedSender] to send [InputEvent]s to and a [Stream] to read fused
/// [PointerEvent]s from.
pub fn pointer_fusion(
    pixel_ratio: f32,
) -> (UnboundedSender<InputEvent>, impl Stream<Item = PointerEvent>) {
    let mut state = PointerFusionState::new(pixel_ratio);
    let (input_sender, receiver) = mpsc::unbounded::<InputEvent>();
    let pointer_stream = receiver.map(move |input| stream::iter(state.fuse_input(input))).flatten();

    (input_sender, pointer_stream)
}