openloaf_rdev/rdev.rs
1#[cfg(feature = "serialize")]
2use serde::{Deserialize, Serialize};
3use std::time::SystemTime;
4use std::{fmt, fmt::Display};
5
6// /// Callback type to send to listen function.
7// pub type Callback = dyn FnMut(Event) -> ();
8
9/// Callback type to send to grab function.
10pub type GrabCallback = fn(event: Event) -> Option<Event>;
11
12/// Errors that occur when trying to capture OS events.
13/// Be careful on Mac, not setting accessibility does not cause an error
14/// it justs ignores events.
15#[derive(Debug)]
16#[non_exhaustive]
17pub enum ListenError {
18 /// MacOS
19 EventTapError,
20 /// MacOS
21 LoopSourceError,
22 /// Linux
23 MissingDisplayError,
24 /// Linux
25 KeyboardError,
26 /// Linux
27 RecordContextEnablingError,
28 /// Linux
29 RecordContextError,
30 /// Linux
31 XRecordExtensionError,
32 /// Windows
33 KeyHookError(u32),
34 /// Windows
35 MouseHookError(u32),
36}
37
38/// Errors that occur when trying to grab OS events.
39/// Be careful on Mac, not setting accessibility does not cause an error
40/// it justs ignores events.
41#[derive(Debug)]
42#[non_exhaustive]
43pub enum GrabError {
44 ListenError,
45 /// MacOS
46 EventTapError,
47 /// MacOS
48 LoopSourceError,
49 /// Linux
50 MissingDisplayError,
51 /// Linux
52 MissingScreenError,
53 // Linux
54 InvalidFileDescriptor,
55 /// Linux
56 KeyboardError,
57 /// Windows
58 KeyHookError(u32),
59 /// Windows
60 MouseHookError(u32),
61 /// All
62 SimulateError,
63 /// All
64 ExitGrabError(String),
65
66 IoError(std::io::Error),
67}
68
69// impl From<std::io::Error> for GrabError {
70// fn from(err: std::io::Error) -> GrabError {
71// GrabError::IoError(err)
72// }
73// }
74
75/// Errors that occur when trying to get display size.
76#[non_exhaustive]
77#[derive(Debug)]
78pub enum DisplayError {
79 NoDisplay,
80 ConversionError,
81}
82
83impl From<SimulateError> for GrabError {
84 fn from(_: SimulateError) -> GrabError {
85 GrabError::SimulateError
86 }
87}
88
89/// Marking an error when we tried to simulate and event
90#[derive(Debug)]
91pub struct SimulateError;
92
93impl Display for SimulateError {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 write!(f, "Could not simulate event")
96 }
97}
98
99impl std::error::Error for SimulateError {}
100
101// Some keys from https://github.com/chromium/chromium/blob/main/ui/events/keycodes/dom/dom_code_data.inc
102
103/// Key names based on physical location on the device
104/// Merge Option(MacOS) and Alt(Windows, Linux) into Alt
105/// Merge Windows (Windows), Meta(Linux), Command(MacOS) into Meta
106/// Characters based on Qwerty layout, don't use this for characters as it WILL
107/// depend on the layout. Use Event.name instead. Key modifiers gives those keys
108/// a different value too.
109/// Careful, on Windows KpReturn does not exist, it' s strictly equivalent to Return, also Keypad keys
110/// get modified if NumLock is Off and ARE pagedown and so on.
111use strum_macros::EnumIter; // 0.17.1
112#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter)]
113#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
114pub enum Key {
115 /// Alt key on Linux and Windows (option key on macOS)
116 Alt,
117 AltGr,
118 Backspace,
119 CapsLock,
120 ControlLeft,
121 ControlRight,
122 Delete,
123 DownArrow,
124 End,
125 Escape,
126 F1,
127 F10,
128 F11,
129 F12,
130 F13,
131 F14,
132 F15,
133 F16,
134 F17,
135 F18,
136 F19,
137 F20,
138 F21,
139 F22,
140 F23,
141 F24,
142 F2,
143 F3,
144 F4,
145 F5,
146 F6,
147 F7,
148 F8,
149 F9,
150 Home,
151 LeftArrow,
152 /// also known as "windows", "super", and "command"
153 MetaLeft,
154 /// also known as "windows", "super", and "command"
155 MetaRight,
156 PageDown,
157 PageUp,
158 Return,
159 RightArrow,
160 ShiftLeft,
161 ShiftRight,
162 Space,
163 Tab,
164 UpArrow,
165 PrintScreen,
166 ScrollLock,
167 Pause,
168 NumLock,
169 BackQuote,
170 Num1,
171 Num2,
172 Num3,
173 Num4,
174 Num5,
175 Num6,
176 Num7,
177 Num8,
178 Num9,
179 Num0,
180 Minus,
181 Equal,
182 KeyQ,
183 KeyW,
184 KeyE,
185 KeyR,
186 KeyT,
187 KeyY,
188 KeyU,
189 KeyI,
190 KeyO,
191 KeyP,
192 LeftBracket,
193 RightBracket,
194 KeyA,
195 KeyS,
196 KeyD,
197 KeyF,
198 KeyG,
199 KeyH,
200 KeyJ,
201 KeyK,
202 KeyL,
203 SemiColon,
204 Quote,
205 BackSlash,
206 IntlBackslash,
207 IntlRo, // Brazilian /? and Japanese _ 'ro'
208 IntlYen, // Japanese Henkan (Convert) key.
209 KanaMode, // Japanese Hiragana/Katakana key.
210 KeyZ,
211 KeyX,
212 KeyC,
213 KeyV,
214 KeyB,
215 KeyN,
216 KeyM,
217 Comma,
218 Dot,
219 Slash,
220 Insert,
221 KpReturn,
222 KpMinus,
223 KpPlus,
224 KpMultiply,
225 KpDivide,
226 KpDecimal,
227 KpEqual,
228 KpComma,
229 Kp0,
230 Kp1,
231 Kp2,
232 Kp3,
233 Kp4,
234 Kp5,
235 Kp6,
236 Kp7,
237 Kp8,
238 Kp9,
239 VolumeUp,
240 VolumeDown,
241 VolumeMute,
242 Lang1, // Korean Hangul/English toggle key, and as the Kana key on the Apple Japanese keyboard.
243 Lang2, // Korean Hanja conversion key, and as the Eisu key on the Apple Japanese keyboard.
244 Lang3, // Japanese Katakana key.
245 Lang4, // Japanese Hiragana key.
246 Lang5, // Japanese Zenkaku/Hankaku (Fullwidth/halfwidth) key.
247 Function,
248 Apps,
249 Cancel,
250 Clear,
251 Kana,
252 Hangul,
253 Junja,
254 Final,
255 Hanja,
256 Hanji,
257 Print,
258 Select,
259 Execute,
260 Help,
261 Sleep,
262 Separator,
263 Unknown(u32),
264 RawKey(RawKey),
265}
266
267#[cfg(not(target_os = "macos"))]
268pub type KeyCode = u32;
269#[cfg(target_os = "macos")]
270pub type KeyCode = crate::CGKeyCode;
271
272#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumIter)]
273#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
274pub enum RawKey {
275 ScanCode(KeyCode),
276 WinVirtualKeycode(KeyCode),
277 LinuxXorgKeycode(KeyCode),
278 LinuxConsoleKeycode(KeyCode),
279 MacVirtualKeycode(KeyCode),
280}
281
282impl Default for RawKey {
283 fn default() -> Self {
284 Self::ScanCode(0)
285 }
286}
287
288/// Standard mouse buttons
289/// Some mice have more than 3 buttons. These are not defined, and different
290/// OSs will give different `Button::Unknown` values.
291#[derive(Debug, Copy, Clone, PartialEq, Eq)]
292#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
293pub enum Button {
294 Left,
295 Right,
296 Middle,
297 Unknown(u8),
298}
299
300/// In order to manage different OSs, the current EventType choices are a mix and
301/// match to account for all possible events.
302#[derive(Debug, Copy, Clone, PartialEq)]
303#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
304pub enum EventType {
305 /// The keys correspond to a standard qwerty layout, they don't correspond
306 /// To the actual letter a user would use, that requires some layout logic to be added.
307 KeyPress(Key),
308 KeyRelease(Key),
309 /// Mouse Button
310 ButtonPress(Button),
311 ButtonRelease(Button),
312 /// Values in pixels. `EventType::MouseMove{x: 0, y: 0}` corresponds to the
313 /// top left corner, with x increasing downward and y increasing rightward
314 MouseMove {
315 x: f64,
316 y: f64,
317 },
318 /// `delta_y` represents vertical scroll and `delta_x` represents horizontal scroll.
319 /// Positive values correspond to scrolling up or right and negative values
320 /// correspond to scrolling down or left
321 /// Note: Linux does not support horizontal scroll. When simulating scroll on Linux,
322 /// only the sign of delta_y is considered, and not the magnitude to determine wheelup or wheeldown.
323 Wheel {
324 delta_x: i64,
325 delta_y: i64,
326 },
327}
328
329/// The Unicode information of input.
330#[derive(Debug, Clone, PartialEq, Default)]
331pub struct UnicodeInfo {
332 pub name: Option<String>,
333 pub unicode: Vec<u16>,
334 pub is_dead: bool,
335}
336
337/// When events arrive from the OS they get some additional information added from
338/// EventType, which is the time when this event was received, and the name Option
339/// which contains what characters should be emmitted from that event. This relies
340/// on the OS layout and keyboard state machinery.
341/// Caveat: Dead keys don't function on Linux(X11) yet. You will receive None for
342/// a dead key, and the raw letter instead of accentuated letter.
343#[derive(Debug, Clone, PartialEq)]
344#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
345pub struct Event {
346 pub time: SystemTime,
347 pub unicode: Option<UnicodeInfo>,
348 pub event_type: EventType,
349 // Linux: keysym
350 // WIndows: vkcod
351 pub platform_code: u32,
352 pub position_code: u32,
353 pub usb_hid: u32,
354 #[cfg(target_os = "windows")]
355 pub extra_data: winapi::shared::basetsd::ULONG_PTR,
356 #[cfg(target_os = "macos")]
357 pub extra_data: i64,
358}
359
360/// We can define a dummy Keyboard, that we will use to detect
361/// what kind of EventType trigger some String. We get the currently used
362/// layout for now !
363/// Caveat : This is layout dependent. If your app needs to support
364/// layout switching don't use this !
365/// Caveat: On Linux, the dead keys mechanism is not implemented.
366/// Caveat: Only shift and dead keys are implemented, Alt+unicode code on windows
367/// won't work.
368///
369/// ```no_run
370/// use rdev::{Keyboard, EventType, Key, KeyboardState};
371///
372/// let mut keyboard = Keyboard::new().unwrap();
373/// let string = keyboard.add(&EventType::KeyPress(Key::KeyS)).unwrap().name.unwrap();
374/// // string == Some("s")
375/// ```
376pub trait KeyboardState {
377 /// Changes the keyboard state as if this event happened. we don't
378 /// really hit the OS here, which might come handy to test what should happen
379 /// if we were to hit said key.
380 fn add(&mut self, event_type: &EventType) -> Option<UnicodeInfo>;
381
382 // Resets the keyboard state as if we never touched it (no shift, caps_lock and so on)
383 // fn reset(&mut self);
384}