Skip to main content

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}