simulate/
lib.rs

1#[cfg(windows)]
2mod windows;
3#[cfg(windows)]
4static SIM: windows::WindowsSimulate = windows::WindowsSimulate;
5
6mod buf;
7pub use buf::EventBuffer;
8
9/// An action for a key.
10#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
11#[repr(u8)]
12pub enum Action {
13    /// Presses the key.
14    Press,
15    /// Releases the key.
16    Release,
17}
18
19/// The direction of a `Scroll` event.
20#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
21#[repr(u8)]
22pub enum ScrollDirection {
23    Horizontal,
24    Vertical,
25}
26
27/// A key that can be pressed.
28#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
29pub enum Key {
30    // Mouse buttons
31    MouseLeft,
32    MouseRight,
33    MouseMiddle,
34    MouseX(u8),
35
36    // Keyboard keys
37    /// Also named BACK
38    Backspace,
39    Tab,
40    Clear,
41    /// Also named RETURN
42    Enter,
43    Shift,
44    LeftShift,
45    RightShift,
46    Control,
47    LeftControl,
48    RightControl,
49    Menu,
50    LeftMenu,
51    RightMenu,
52    Home,
53    LeftWindows,
54    RightWindows,
55    Pause,
56    /// Also named CAPITAL
57    CapsLock,
58    Escape,
59    Space,
60    /// Also named PRIOR
61    PageUp,
62    /// Also named NEXT
63    PageDown,
64    End,
65    Select,
66    Print,
67    Execute,
68    /// Also named SNAPSHOT
69    PrintScreen,
70    Insert,
71    Delete,
72    Help,
73    Apps,
74    Sleep,
75    BrowserBack,
76    BrowserForward,
77    BrowserRefresh,
78    BrowserStop,
79    BrowserSearch,
80    BrowserFavorites,
81    BrowserHome,
82    VolumeMute,
83    VolumeDown,
84    VolumeUp,
85    MediaNextTrack,
86    MediaPreviousTrack,
87    MediaStop,
88    MediaPlayPause,
89    LaunchMail,
90    SelectMedia,
91    LaunchApp1,
92    LaunchApp2,
93
94    Attn,
95    Crsel,
96    Exsel,
97    Ereof,
98    Play,
99    Zoom,
100    NoName,
101
102    Left,
103    Up,
104    Right,
105    Down,
106
107    Kana,
108    Hangul,
109    Junja,
110    Final,
111    Kanji,
112    Convert,
113    Nonconvert,
114    Accept,
115    ModeChange,
116    /// The IME PROCESS key
117    ProcessKey,
118    ImeOn,
119    ImeOff,
120
121    /// On US keyboards, the ';:' key.
122    Oem1,
123    /// On US keyboards, the '+' key.
124    OemPlus,
125    /// On US keyboards, the ',' key.
126    OemComma,
127    /// On US keyboards, the '-' key.
128    OemMinus,
129    /// On US keyboards, the '.' key.
130    OemPeriod,
131    /// On US keyboards, the '/' key.
132    Oem2,
133    /// On US keyboards, the '~' key.
134    Oem3,
135    /// On US keyboards, the '[{' key.
136    Oem4,
137    /// On US keyboards, the '\|' key.
138    Oem5,
139    /// On US keyboards, the ']}'
140    Oem6,
141    /// On US keyboards, the ''"' key.
142    Oem7,
143    /// Miscellaneous characters; can vary by keyboard.
144    Oem8,
145    /// Either the angle backet key or the backslash on the RT 102-key keyboard.
146    Oem102,
147    OemClear,
148
149    _0,
150    _1,
151    _2,
152    _3,
153    _4,
154    _5,
155    _6,
156    _7,
157    _8,
158    _9,
159
160    Numpad0,
161    Numpad1,
162    Numpad2,
163    Numpad3,
164    Numpad4,
165    Numpad5,
166    Numpad6,
167    Numpad7,
168    Numpad8,
169    Numpad9,
170    Multiply,
171    Add,
172    Subtract,
173    Decimal,
174    Divide,
175    Separator,
176    NumLock,
177    ScrollLock,
178
179    A,
180    B,
181    C,
182    D,
183    E,
184    F,
185    G,
186    H,
187    I,
188    J,
189    K,
190    L,
191    M,
192    N,
193    O,
194    P,
195    Q,
196    R,
197    S,
198    T,
199    U,
200    V,
201    W,
202    X,
203    Y,
204    Z,
205
206    F1,
207    F2,
208    F3,
209    F4,
210    F5,
211    F6,
212    F7,
213    F8,
214    F9,
215    F10,
216    F11,
217    F12,
218    F13,
219    F14,
220    F15,
221    F16,
222    F17,
223    F18,
224    F19,
225    F20,
226    F21,
227    F22,
228    F23,
229    F24,
230}
231
232impl Key {
233    /// Checks if this `Key` is a mouse button.
234    #[inline(always)]
235    pub fn is_mouse_button(&self) -> bool {
236        matches!(self, Key::MouseLeft | Key::MouseMiddle | Key::MouseRight | Key::MouseX(_))
237    }
238}
239
240/// A trait for structures which can be turned into an event, given an action.
241pub trait Keylike: Copy {
242    /// Turns the keylike into an event.
243    fn into_event(self, action: Action) -> Event;
244
245    /// Creates an event that causes the keylike to be pressed.
246    #[inline(always)]
247    fn press(self) -> Event {
248        self.into_event(Action::Press)
249    }
250
251    /// Creates an event that causes the keylike to be released.
252    #[inline(always)]
253    fn release(self) -> Event {
254        self.into_event(Action::Release)
255    }
256
257    /// Creates an iterator that yield a `Press` event and a `Release` for this keylike.
258    #[inline]
259    fn press_release(self) -> std::iter::Chain<std::iter::Once<Event>, std::iter::Once<Event>> {
260        std::iter::once(self.press()).chain(std::iter::once(self.release()))
261    }
262}
263
264impl Keylike for Key {
265    #[inline(always)]
266    fn into_event(self, action: Action) -> Event {
267        Event::Key { key: self, action }
268    }
269}
270
271impl Keylike for char {
272    #[inline(always)]
273    fn into_event(self, action: Action) -> Event {
274        Event::Char {
275            character: self,
276            action,
277        }
278    }
279}
280
281/// An event that can be sent to a `Simulate`.
282#[derive(Clone, Debug)]
283pub enum Event {
284    Key {
285        key: Key,
286        action: Action,
287    },
288
289    Char {
290        character: char,
291        action: Action,
292    },
293
294    MoveMouseAbsolute {
295        x: f32,
296        y: f32,
297        /// Maps the given coordinates to the whole virtual desktop (if multiple monitors
298        /// are used). When this flag is off, the coordinates (1, 1) map to the lower-right
299        /// corner of the main monitor.
300        map_to_virtual_desktop: bool,
301    },
302
303    MoveMouseRelative {
304        dx: i32,
305        dy: i32,
306    },
307
308    Scroll {
309        /// One mouse clock is a `delta` of `1`.
310        /// A positive value means the wheel must be rotated forward (or to the right if
311        /// the direction is horizontal).
312        delta: f32,
313        direction: ScrollDirection,
314    },
315}
316
317#[derive(Clone, Debug)]
318pub enum Error {
319    /// A key was not supported by the platform.
320    UnsupportedKey(Key),
321
322    /// A character was not supported by the platform.
323    UnsupportedChar(char),
324
325    /// An event was not supported by the platform,
326    UnsupportedEvent(Event),
327
328    /// An error occured whilst simulating events.
329    OsError {
330        /// The code of the error.
331        code: u32,
332        /// A message describing the error.
333        message: String,
334    },
335}
336
337/// The result type of the crate.
338pub type Result<T> = std::result::Result<T, Error>;
339
340/// A trait to handle the input simulation.
341pub trait Simulate {
342    /// Simulates the specified events.
343    fn send_events(&self, events: impl IntoIterator<Item = Event>) -> Result<()>;
344}
345
346/// Sends the given events to the default simulator.
347#[inline(always)]
348pub fn send_events(events: impl IntoIterator<Item = Event>) -> Result<()> {
349    SIM.send_events(events)
350}
351
352/// Sends a single event.
353#[inline(always)]
354pub fn send_event(event: Event) -> Result<()> {
355    send_events(Some(event))
356}
357
358/// Sends `Press` and `Release` events for the given keylikes.
359#[inline]
360pub fn send_multiple<K: Keylike>(keys: impl IntoIterator<Item = K>) -> Result<()> {
361    let iter = keys.into_iter().flat_map(Keylike::press_release);
362    send_events(iter)
363}
364
365/// Sends an event for the given keylike.
366#[inline(always)]
367pub fn send(key: impl Keylike) -> Result<()> {
368    send_events(key.press_release())
369}
370
371/// Sends a `Press` event for the given keylike.
372#[inline(always)]
373pub fn press(key: impl Keylike) -> Result<()> {
374    send_events(Some(key.press()))
375}
376
377/// Sends a `Release` event for the given keylike.
378#[inline(always)]
379pub fn release(key: Key) -> Result<()> {
380    send_events(Some(key.release()))
381}
382
383/// Types the given string.
384#[inline(always)]
385pub fn type_str(s: &str) -> Result<()> {
386    send_multiple(s.chars())
387}
388
389/// Moves the mouse `dx` pixels to the right
390/// and `dy` pixels down.
391#[inline(always)]
392pub fn move_mouse_relative(dx: i32, dy: i32) -> Result<()> {
393    send_events(Some(Event::MoveMouseRelative { dx, dy }))
394}
395
396/// Moves the mouse, coordinates are normalized to the desktop: (0, 0) map to the top-left
397/// of the main monitor and (1, 1) maps to the bottom-right of the main monitor.
398#[inline(always)]
399pub fn move_mouse_absolute(x: f32, y: f32) -> Result<()> {
400    send_events(Some(Event::MoveMouseAbsolute {
401        x,
402        y,
403        map_to_virtual_desktop: false,
404    }))
405}
406
407/// Sends a scroll event to rotate the mouse wheel in the given direction.
408#[inline(always)]
409pub fn send_scroll_event(delta: f32, direction: ScrollDirection) -> Result<()> {
410    send_events(Some(Event::Scroll { delta, direction }))
411}
412
413/// Uses the mouse wheel vertically.
414#[inline(always)]
415pub fn scroll(delta: f32) -> Result<()> {
416    send_scroll_event(delta, ScrollDirection::Vertical)
417}
418
419/// Uses the mouse wheel horizontally.
420#[inline(always)]
421pub fn scroll_horizontal(delta: f32) -> Result<()> {
422    send_scroll_event(delta, ScrollDirection::Horizontal)
423}