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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//! Events directly from view-process not targeting any windows.
//!
//! These events get emitted only if the app [`enable_device_events`]. When enabled they
//! can be used like [`raw_events`].
//!
//! [`enable_device_events`]: crate::AppExtended::enable_device_events
//! [`raw_events`]: crate::view_process::raw_events

use std::fmt;

use crate::event::*;

use zng_layout::unit::euclid;
use zng_view_api::{
    keyboard::{KeyCode, KeyState},
    mouse::{ButtonId, ButtonState, MouseScrollDelta},
    AxisId,
};

use once_cell::sync::Lazy;

zng_unique_id::unique_id_64! {
    /// Unique identifier of a device event source.
    pub struct DeviceId;
}
zng_unique_id::impl_unique_id_bytemuck!(DeviceId);
impl DeviceId {
    /// Virtual keyboard ID used in keyboard events generated by code.
    pub fn virtual_keyboard() -> DeviceId {
        static ID: Lazy<DeviceId> = Lazy::new(DeviceId::new_unique);
        *ID
    }

    /// Virtual mouse ID used in mouse events generated by code.
    pub fn virtual_mouse() -> DeviceId {
        static ID: Lazy<DeviceId> = Lazy::new(DeviceId::new_unique);
        *ID
    }

    /// Virtual generic device ID used in device events generated by code.
    pub fn virtual_generic() -> DeviceId {
        static ID: Lazy<DeviceId> = Lazy::new(DeviceId::new_unique);
        *ID
    }
}
impl fmt::Debug for DeviceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if f.alternate() {
            f.debug_struct("DeviceId")
                .field("id", &self.get())
                .field("sequential", &self.sequential())
                .finish()
        } else {
            write!(f, "DeviceId({})", self.sequential())
        }
    }
}
impl fmt::Display for DeviceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "DeviceId({})", self.get())
    }
}

event_args! {
    /// Arguments for [`DEVICE_ADDED_EVENT`] and [`DEVICE_REMOVED_EVENT`].
    pub struct DeviceArgs {
        /// Device that was added/removed.
        pub device_id: DeviceId,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for [`MOUSE_MOTION_EVENT`].
    pub struct MouseMotionArgs {
        /// Mouse device that generated the event.
        pub device_id: DeviceId,

        /// Motion (x, y) delta.
        pub delta: euclid::Vector2D<f64, ()>,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for [`MOUSE_WHEEL_EVENT`].
    pub struct MouseWheelArgs {
        /// Mouse device that generated the event.
        pub device_id: DeviceId,

        /// Wheel motion delta, value is in pixels if the *wheel* is a touchpad.
        pub delta: MouseScrollDelta,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for [`MOTION_EVENT`].
    pub struct MotionArgs {
        /// Device that generated the event.
        pub device_id: DeviceId,

        /// Analog axis.
        pub axis: AxisId,

        /// Motion amount.
        pub value: f64,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for the [`BUTTON_EVENT`].
    pub struct ButtonArgs {
        /// Device that generated the event.
        pub device_id: DeviceId,

        /// Button raw id.
        pub button: ButtonId,

        /// If the button was pressed or released.
        pub state: ButtonState,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for the [`KEY_EVENT`].
    pub struct KeyArgs {
        /// Keyboard device that generated the event.
        pub device_id: DeviceId,

        /// Physical key.
        pub key_code: KeyCode,

        /// If the key was pressed or released.
        pub state: KeyState,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }

    /// Arguments for the [`TEXT_EVENT`].
    pub struct TextArgs {
        /// Device that generated the event.
        pub device_id: DeviceId,

        /// Character received.
        pub code_point: char,

        ..

        /// Broadcast to all widgets.
        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
            list.search_all()
        }
    }
}

event! {
    /// A device event source was added/installed.
    pub static DEVICE_ADDED_EVENT: DeviceArgs;

    /// A device event source was removed/un-installed.
    pub static DEVICE_REMOVED_EVENT: DeviceArgs;

    /// Mouse device unfiltered move delta.
    pub static MOUSE_MOTION_EVENT: MouseMotionArgs;

    /// Mouse device unfiltered wheel motion delta.
    pub static MOUSE_WHEEL_EVENT: MouseWheelArgs;

    /// Motion on some analog axis.
    ///
    /// This event will be reported for all arbitrary input devices that the view-process supports on this platform,
    /// including mouse devices. If the device is a mouse device then this will be reported alongside the [`MOUSE_MOTION_EVENT`].
    pub static MOTION_EVENT: MotionArgs;

    /// Button press/release from a device, probably a mouse.
    pub static BUTTON_EVENT: ButtonArgs;

    /// Keyboard device key press.
    pub static KEY_EVENT: KeyArgs;

    /// Raw text input.
    pub static TEXT_EVENT: TextArgs;
}