zng_app/view_process/
raw_device_events.rs

1//! Events directly from view-process not targeting any windows.
2//!
3//! These events get emitted only if the app [`APP.device_events_filter`] allows. When enabled they
4//! can be used like [`raw_events`].
5//!
6//! [`APP.device_events_filter`]: crate::APP::device_events_filter
7//! [`raw_events`]: crate::view_process::raw_events
8
9use std::{collections::HashMap, fmt};
10
11use crate::event::*;
12
13use zng_layout::unit::euclid;
14use zng_var::{Var, var};
15use zng_view_api::{
16    keyboard::{KeyCode, KeyState},
17    mouse::{ButtonId, ButtonState, MouseScrollDelta},
18};
19
20pub use zng_view_api::AxisId;
21pub use zng_view_api::raw_input::{InputDeviceCapability, InputDeviceInfo};
22
23use once_cell::sync::Lazy;
24
25zng_unique_id::unique_id_64! {
26    /// Unique identifier of an input device event source.
27    pub struct InputDeviceId;
28}
29zng_unique_id::impl_unique_id_bytemuck!(InputDeviceId);
30impl InputDeviceId {
31    /// Virtual keyboard ID used in keyboard events generated by code.
32    pub fn virtual_keyboard() -> InputDeviceId {
33        static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
34        *ID
35    }
36
37    /// Virtual mouse ID used in mouse events generated by code.
38    pub fn virtual_mouse() -> InputDeviceId {
39        static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
40        *ID
41    }
42
43    /// Virtual generic device ID used in device events generated by code.
44    pub fn virtual_generic() -> InputDeviceId {
45        static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
46        *ID
47    }
48}
49impl fmt::Debug for InputDeviceId {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        if f.alternate() {
52            f.debug_struct("InputDeviceId")
53                .field("id", &self.get())
54                .field("sequential", &self.sequential())
55                .finish()
56        } else {
57            write!(f, "InputDeviceId({})", self.sequential())
58        }
59    }
60}
61impl fmt::Display for InputDeviceId {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "InputDeviceId({})", self.get())
64    }
65}
66
67event_args! {
68    /// Arguments for [`INPUT_DEVICES_CHANGED_EVENT`].
69    pub struct InputDevicesChangedArgs {
70        /// New list of available devices.
71        pub devices: HashMap<InputDeviceId, InputDeviceInfo>,
72
73        ..
74
75        /// Broadcast to all widgets.
76        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
77            list.search_all()
78        }
79    }
80
81    /// Arguments for [`POINTER_MOTION_EVENT`].
82    pub struct PointerMotionArgs {
83        /// Device that generated the event.
84        pub device_id: InputDeviceId,
85
86        /// Motion (x, y) delta.
87        pub delta: euclid::Vector2D<f64, ()>,
88
89        ..
90
91        /// Broadcast to all widgets.
92        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
93            list.search_all()
94        }
95    }
96
97    /// Arguments for [`SCROLL_MOTION_EVENT`].
98    pub struct ScrollMotionArgs {
99        /// Device that generated the event.
100        pub device_id: InputDeviceId,
101
102        /// Wheel motion delta, value is in pixels if the *wheel* is a touchpad.
103        pub delta: MouseScrollDelta,
104
105        ..
106
107        /// Broadcast to all widgets.
108        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
109            list.search_all()
110        }
111    }
112
113    /// Arguments for [`AXIS_MOTION_EVENT`].
114    pub struct AxisMotionArgs {
115        /// Device that generated the event.
116        pub device_id: InputDeviceId,
117
118        /// Analog axis.
119        pub axis: AxisId,
120
121        /// Motion amount.
122        pub value: f64,
123
124        ..
125
126        /// Broadcast to all widgets.
127        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
128            list.search_all()
129        }
130    }
131
132    /// Arguments for the [`BUTTON_EVENT`].
133    pub struct ButtonArgs {
134        /// Device that generated the event.
135        pub device_id: InputDeviceId,
136
137        /// Button raw id.
138        pub button: ButtonId,
139
140        /// If the button was pressed or released.
141        pub state: ButtonState,
142
143        ..
144
145        /// Broadcast to all widgets.
146        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
147            list.search_all()
148        }
149    }
150
151    /// Arguments for the [`KEY_EVENT`].
152    pub struct KeyArgs {
153        /// Keyboard device that generated the event.
154        pub device_id: InputDeviceId,
155
156        /// Physical key.
157        pub key_code: KeyCode,
158
159        /// If the key was pressed or released.
160        pub state: KeyState,
161
162        ..
163
164        /// Broadcast to all widgets.
165        fn delivery_list(&self, list: &mut UpdateDeliveryList) {
166            list.search_all()
167        }
168    }
169}
170
171event! {
172    /// Raw input devices have been added or removed from the system.
173    pub static INPUT_DEVICES_CHANGED_EVENT: InputDevicesChangedArgs;
174
175    /// Device unfiltered 2D move delta.
176    pub static POINTER_MOTION_EVENT: PointerMotionArgs;
177
178    /// Mouse device unfiltered wheel motion delta.
179    pub static SCROLL_MOTION_EVENT: ScrollMotionArgs;
180
181    /// Motion on some analog axis.
182    ///
183    /// This event will be reported for all arbitrary input devices that the view-process supports on this platform,
184    /// including mouse devices. If the device is a mouse device then this will be reported alongside the [`POINTER_MOTION_EVENT`].
185    pub static AXIS_MOTION_EVENT: AxisMotionArgs;
186
187    /// Button press/release from a device, probably a mouse.
188    pub static BUTTON_EVENT: ButtonArgs;
189
190    /// Keyboard device key press.
191    pub static KEY_EVENT: KeyArgs;
192}
193
194/// Input devices info service.
195///
196/// Note that this service data will depend on what [`APP.device_events_filter`] is set.
197///
198/// [`APP.device_events_filter`]: crate::APP::device_events_filter
199#[allow(non_camel_case_types)]
200pub struct INPUT_DEVICES;
201
202impl INPUT_DEVICES {
203    /// Read-only variable that tracks the current input devices.
204    pub fn available_devices(&self) -> Var<HashMap<InputDeviceId, InputDeviceInfo>> {
205        INPUT_DEVICES_SV.read().devices.read_only()
206    }
207
208    /// Read-only variable that tracks the input device info.
209    ///
210    /// If the `id` is unknown returns an "Unknown Input Device" info.
211    pub fn device(&self, id: InputDeviceId) -> Var<InputDeviceInfo> {
212        INPUT_DEVICES_SV.read().devices.map(move |m| {
213            m.get(&id)
214                .cloned()
215                .unwrap_or_else(|| InputDeviceInfo::new("Unknown Input Device", InputDeviceCapability::empty()))
216        })
217    }
218
219    pub(crate) fn update(&self, devices: HashMap<InputDeviceId, InputDeviceInfo>) {
220        INPUT_DEVICES_SV.read().devices.set(devices);
221    }
222}
223
224struct InputDevicesSv {
225    devices: Var<HashMap<InputDeviceId, InputDeviceInfo>>,
226}
227app_local! {
228    static INPUT_DEVICES_SV: InputDevicesSv = InputDevicesSv {
229        devices: var(HashMap::new()),
230    };
231}