2021-03-29 15:59:14 +08:00
|
|
|
|
//! Enigo lets you simulate mouse and keyboard input-events as if they were
|
|
|
|
|
//! made by the actual hardware. The goal is to make it available on different
|
|
|
|
|
//! operating systems like Linux, macOS and Windows – possibly many more but
|
|
|
|
|
//! [Redox](https://redox-os.org/) and *BSD are planned. Please see the
|
|
|
|
|
//! [Repo](https://github.com/enigo-rs/enigo) for the current status.
|
|
|
|
|
//!
|
|
|
|
|
//! I consider this library in an early alpha status, the API will change in
|
|
|
|
|
//! in the future. The keyboard handling is far from being very usable. I plan
|
|
|
|
|
//! to build a simple
|
|
|
|
|
//! [DSL](https://en.wikipedia.org/wiki/Domain-specific_language)
|
|
|
|
|
//! that will resemble something like:
|
|
|
|
|
//!
|
|
|
|
|
//! `"hello {+SHIFT}world{-SHIFT} and break line{ENTER}"`
|
|
|
|
|
//!
|
|
|
|
|
//! The current status is that you can just print
|
|
|
|
|
//! [unicode](http://unicode.org/)
|
|
|
|
|
//! characters like [emoji](http://getemoji.com/) without the `{+SHIFT}`
|
|
|
|
|
//! [DSL](https://en.wikipedia.org/wiki/Domain-specific_language)
|
|
|
|
|
//! or any other "special" key on the Linux, macOS and Windows operating system.
|
|
|
|
|
//!
|
|
|
|
|
//! Possible use cases could be for testing user interfaces on different
|
|
|
|
|
//! plattforms,
|
|
|
|
|
//! building remote control applications or just automating tasks for user
|
|
|
|
|
//! interfaces unaccessible by a public API or scripting laguage.
|
|
|
|
|
//!
|
|
|
|
|
//! For the keyboard there are currently two modes you can use. The first mode
|
|
|
|
|
//! is represented by the [key_sequence]() function
|
|
|
|
|
//! its purpose is to simply write unicode characters. This is independent of
|
|
|
|
|
//! the keyboardlayout. Please note that
|
|
|
|
|
//! you're not be able to use modifier keys like Control
|
|
|
|
|
//! to influence the outcome. If you want to use modifier keys to e.g.
|
|
|
|
|
//! copy/paste
|
|
|
|
|
//! use the Layout variant. Please note that this is indeed layout dependent.
|
|
|
|
|
|
|
|
|
|
//! # Examples
|
|
|
|
|
//! ```no_run
|
|
|
|
|
//! use enigo::*;
|
|
|
|
|
//! let mut enigo = Enigo::new();
|
|
|
|
|
//! //paste
|
|
|
|
|
//! enigo.key_down(Key::Control);
|
|
|
|
|
//! enigo.key_click(Key::Layout('v'));
|
|
|
|
|
//! enigo.key_up(Key::Control);
|
|
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! ```no_run
|
|
|
|
|
//! use enigo::*;
|
|
|
|
|
//! let mut enigo = Enigo::new();
|
|
|
|
|
//! enigo.mouse_move_to(500, 200);
|
|
|
|
|
//! enigo.mouse_down(MouseButton::Left);
|
|
|
|
|
//! enigo.mouse_move_relative(100, 100);
|
|
|
|
|
//! enigo.mouse_up(MouseButton::Left);
|
|
|
|
|
//! enigo.key_sequence("hello world");
|
|
|
|
|
//! ```
|
|
|
|
|
#![deny(missing_docs)]
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
#[macro_use]
|
|
|
|
|
extern crate objc;
|
|
|
|
|
|
|
|
|
|
// TODO(dustin) use interior mutability not &mut self
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
mod win;
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
pub use win::Enigo;
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
mod macos;
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
pub use macos::Enigo;
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
mod linux;
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
pub use crate::linux::Enigo;
|
|
|
|
|
|
|
|
|
|
/// DSL parser module
|
|
|
|
|
pub mod dsl;
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "with_serde")]
|
|
|
|
|
#[macro_use]
|
|
|
|
|
extern crate serde_derive;
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "with_serde")]
|
|
|
|
|
extern crate serde;
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
pub type ResultType = std::result::Result<(), Box<dyn std::error::Error>>;
|
|
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "with_serde", derive(Serialize, Deserialize))]
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
/// MouseButton represents a mouse button,
|
|
|
|
|
/// and is used in for example
|
|
|
|
|
/// [mouse_click](trait.MouseControllable.html#tymethod.mouse_click).
|
|
|
|
|
/// WARNING: Types with the prefix Scroll
|
|
|
|
|
/// IS NOT intended to be used, and may not work on
|
|
|
|
|
/// all operating systems.
|
|
|
|
|
pub enum MouseButton {
|
|
|
|
|
/// Left mouse button
|
|
|
|
|
Left,
|
|
|
|
|
/// Middle mouse button
|
|
|
|
|
Middle,
|
|
|
|
|
/// Right mouse button
|
|
|
|
|
Right,
|
|
|
|
|
|
|
|
|
|
/// Scroll up button
|
|
|
|
|
ScrollUp,
|
|
|
|
|
/// Left right button
|
|
|
|
|
ScrollDown,
|
|
|
|
|
/// Left right button
|
|
|
|
|
ScrollLeft,
|
|
|
|
|
/// Left right button
|
|
|
|
|
ScrollRight,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Representing an interface and a set of mouse functions every
|
|
|
|
|
/// operating system implementation _should_ implement.
|
|
|
|
|
pub trait MouseControllable {
|
|
|
|
|
/// Lets the mouse cursor move to the specified x and y coordinates.
|
|
|
|
|
///
|
|
|
|
|
/// The topleft corner of your monitor screen is x=0 y=0. Move
|
|
|
|
|
/// the cursor down the screen by increasing the y and to the right
|
|
|
|
|
/// by increasing x coordinate.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_move_to(500, 200);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_move_to(&mut self, x: i32, y: i32);
|
|
|
|
|
|
|
|
|
|
/// Lets the mouse cursor move the specified amount in the x and y
|
|
|
|
|
/// direction.
|
|
|
|
|
///
|
|
|
|
|
/// The amount specified in the x and y parameters are added to the
|
|
|
|
|
/// current location of the mouse cursor. A positive x values lets
|
|
|
|
|
/// the mouse cursor move an amount of `x` pixels to the right. A negative
|
|
|
|
|
/// value for `x` lets the mouse cursor go to the left. A positive value
|
|
|
|
|
/// of y
|
|
|
|
|
/// lets the mouse cursor go down, a negative one lets the mouse cursor go
|
|
|
|
|
/// up.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_move_relative(100, 100);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_move_relative(&mut self, x: i32, y: i32);
|
|
|
|
|
|
|
|
|
|
/// Push down one of the mouse buttons
|
|
|
|
|
///
|
|
|
|
|
/// Push down the mouse button specified by the parameter `button` of
|
|
|
|
|
/// type [MouseButton](enum.MouseButton.html)
|
|
|
|
|
/// and holds it until it is released by
|
|
|
|
|
/// [mouse_up](trait.MouseControllable.html#tymethod.mouse_up).
|
|
|
|
|
/// Calls to [mouse_move_to](trait.MouseControllable.html#tymethod.
|
|
|
|
|
/// mouse_move_to) or
|
|
|
|
|
/// [mouse_move_relative](trait.MouseControllable.html#tymethod.
|
|
|
|
|
/// mouse_move_relative)
|
|
|
|
|
/// will work like expected and will e.g. drag widgets or highlight text.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_down(MouseButton::Left);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_down(&mut self, button: MouseButton) -> ResultType;
|
|
|
|
|
|
|
|
|
|
/// Lift up a pushed down mouse button
|
|
|
|
|
///
|
|
|
|
|
/// Lift up a previously pushed down button (by invoking
|
|
|
|
|
/// [mouse_down](trait.MouseControllable.html#tymethod.mouse_down)).
|
|
|
|
|
/// If the button was not pushed down or consecutive calls without
|
|
|
|
|
/// invoking [mouse_down](trait.MouseControllable.html#tymethod.mouse_down)
|
|
|
|
|
/// will emit lift up events. It depends on the
|
|
|
|
|
/// operating system whats actually happening – my guess is it will just
|
|
|
|
|
/// get ignored.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_up(MouseButton::Right);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_up(&mut self, button: MouseButton);
|
|
|
|
|
|
|
|
|
|
/// Click a mouse button
|
|
|
|
|
///
|
|
|
|
|
/// it's esentially just a consecutive invokation of
|
|
|
|
|
/// [mouse_down](trait.MouseControllable.html#tymethod.mouse_down) followed
|
|
|
|
|
/// by a [mouse_up](trait.MouseControllable.html#tymethod.mouse_up). Just
|
|
|
|
|
/// for
|
|
|
|
|
/// convenience.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_click(MouseButton::Right);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_click(&mut self, button: MouseButton);
|
|
|
|
|
|
|
|
|
|
/// Scroll the mouse (wheel) left or right
|
|
|
|
|
///
|
|
|
|
|
/// Positive numbers for length lets the mouse wheel scroll to the right
|
|
|
|
|
/// and negative ones to the left. The value that is specified translates
|
|
|
|
|
/// to `lines` defined by the operating system and is essentially one 15°
|
|
|
|
|
/// (click)rotation on the mouse wheel. How many lines it moves depends
|
|
|
|
|
/// on the current setting in the operating system.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_scroll_x(2);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_scroll_x(&mut self, length: i32);
|
|
|
|
|
|
|
|
|
|
/// Scroll the mouse (wheel) up or down
|
|
|
|
|
///
|
|
|
|
|
/// Positive numbers for length lets the mouse wheel scroll down
|
|
|
|
|
/// and negative ones up. The value that is specified translates
|
|
|
|
|
/// to `lines` defined by the operating system and is essentially one 15°
|
|
|
|
|
/// (click)rotation on the mouse wheel. How many lines it moves depends
|
|
|
|
|
/// on the current setting in the operating system.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.mouse_scroll_y(2);
|
|
|
|
|
/// ```
|
|
|
|
|
fn mouse_scroll_y(&mut self, length: i32);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A key on the keyboard.
|
|
|
|
|
/// For alphabetical keys, use Key::Layout for a system independent key.
|
|
|
|
|
/// If a key is missing, you can use the raw keycode with Key::Raw.
|
|
|
|
|
#[cfg_attr(feature = "with_serde", derive(Serialize, Deserialize))]
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
|
pub enum Key {
|
|
|
|
|
/// alt key on Linux and Windows (option key on macOS)
|
|
|
|
|
Alt,
|
|
|
|
|
/// backspace key
|
|
|
|
|
Backspace,
|
|
|
|
|
/// caps lock key
|
|
|
|
|
CapsLock,
|
|
|
|
|
#[deprecated(since = "0.0.12", note = "now renamed to Meta")]
|
|
|
|
|
/// command key on macOS (super key on Linux, windows key on Windows)
|
|
|
|
|
Command,
|
|
|
|
|
/// control key
|
|
|
|
|
Control,
|
|
|
|
|
/// delete key
|
|
|
|
|
Delete,
|
|
|
|
|
/// down arrow key
|
|
|
|
|
DownArrow,
|
|
|
|
|
/// end key
|
|
|
|
|
End,
|
|
|
|
|
/// escape key (esc)
|
|
|
|
|
Escape,
|
|
|
|
|
/// F1 key
|
|
|
|
|
F1,
|
|
|
|
|
/// F10 key
|
|
|
|
|
F10,
|
|
|
|
|
/// F11 key
|
|
|
|
|
F11,
|
|
|
|
|
/// F12 key
|
|
|
|
|
F12,
|
|
|
|
|
/// F2 key
|
|
|
|
|
F2,
|
|
|
|
|
/// F3 key
|
|
|
|
|
F3,
|
|
|
|
|
/// F4 key
|
|
|
|
|
F4,
|
|
|
|
|
/// F5 key
|
|
|
|
|
F5,
|
|
|
|
|
/// F6 key
|
|
|
|
|
F6,
|
|
|
|
|
/// F7 key
|
|
|
|
|
F7,
|
|
|
|
|
/// F8 key
|
|
|
|
|
F8,
|
|
|
|
|
/// F9 key
|
|
|
|
|
F9,
|
|
|
|
|
/// home key
|
|
|
|
|
Home,
|
|
|
|
|
/// left arrow key
|
|
|
|
|
LeftArrow,
|
|
|
|
|
/// meta key (also known as "windows", "super", and "command")
|
|
|
|
|
Meta,
|
|
|
|
|
/// option key on macOS (alt key on Linux and Windows)
|
2021-08-10 12:18:10 +08:00
|
|
|
|
Option, // deprecated, use Alt instead
|
2021-03-29 15:59:14 +08:00
|
|
|
|
/// page down key
|
|
|
|
|
PageDown,
|
|
|
|
|
/// page up key
|
|
|
|
|
PageUp,
|
|
|
|
|
/// return key
|
|
|
|
|
Return,
|
|
|
|
|
/// right arrow key
|
|
|
|
|
RightArrow,
|
|
|
|
|
/// shift key
|
|
|
|
|
Shift,
|
|
|
|
|
/// space key
|
|
|
|
|
Space,
|
|
|
|
|
#[deprecated(since = "0.0.12", note = "now renamed to Meta")]
|
|
|
|
|
/// super key on linux (command key on macOS, windows key on Windows)
|
|
|
|
|
Super,
|
|
|
|
|
/// tab key (tabulator)
|
|
|
|
|
Tab,
|
|
|
|
|
/// up arrow key
|
|
|
|
|
UpArrow,
|
|
|
|
|
#[deprecated(since = "0.0.12", note = "now renamed to Meta")]
|
|
|
|
|
/// windows key on Windows (super key on Linux, command key on macOS)
|
|
|
|
|
Windows,
|
|
|
|
|
///
|
|
|
|
|
Numpad0,
|
|
|
|
|
///
|
|
|
|
|
Numpad1,
|
|
|
|
|
///
|
|
|
|
|
Numpad2,
|
|
|
|
|
///
|
|
|
|
|
Numpad3,
|
|
|
|
|
///
|
|
|
|
|
Numpad4,
|
|
|
|
|
///
|
|
|
|
|
Numpad5,
|
|
|
|
|
///
|
|
|
|
|
Numpad6,
|
|
|
|
|
///
|
|
|
|
|
Numpad7,
|
|
|
|
|
///
|
|
|
|
|
Numpad8,
|
|
|
|
|
///
|
|
|
|
|
Numpad9,
|
|
|
|
|
///
|
|
|
|
|
Cancel,
|
|
|
|
|
///
|
|
|
|
|
Clear,
|
|
|
|
|
///
|
|
|
|
|
Pause,
|
|
|
|
|
///
|
|
|
|
|
Kana,
|
|
|
|
|
///
|
|
|
|
|
Hangul,
|
|
|
|
|
///
|
|
|
|
|
Junja,
|
|
|
|
|
///
|
|
|
|
|
Final,
|
|
|
|
|
///
|
|
|
|
|
Hanja,
|
|
|
|
|
///
|
|
|
|
|
Kanji,
|
|
|
|
|
///
|
|
|
|
|
Convert,
|
|
|
|
|
///
|
|
|
|
|
Select,
|
|
|
|
|
///
|
|
|
|
|
Print,
|
|
|
|
|
///
|
|
|
|
|
Execute,
|
|
|
|
|
///
|
|
|
|
|
Snapshot,
|
|
|
|
|
///
|
|
|
|
|
Insert,
|
|
|
|
|
///
|
|
|
|
|
Help,
|
|
|
|
|
///
|
|
|
|
|
Sleep,
|
|
|
|
|
///
|
|
|
|
|
Separator,
|
|
|
|
|
///
|
|
|
|
|
VolumeUp,
|
|
|
|
|
///
|
|
|
|
|
VolumeDown,
|
|
|
|
|
///
|
|
|
|
|
Mute,
|
|
|
|
|
///
|
|
|
|
|
Scroll,
|
|
|
|
|
/// scroll lock
|
|
|
|
|
NumLock,
|
|
|
|
|
///
|
|
|
|
|
RWin,
|
|
|
|
|
///
|
|
|
|
|
Apps,
|
|
|
|
|
///
|
|
|
|
|
Multiply,
|
|
|
|
|
///
|
|
|
|
|
Add,
|
|
|
|
|
///
|
|
|
|
|
Subtract,
|
|
|
|
|
///
|
|
|
|
|
Decimal,
|
|
|
|
|
///
|
|
|
|
|
Divide,
|
|
|
|
|
///
|
|
|
|
|
Equals,
|
|
|
|
|
///
|
|
|
|
|
NumpadEnter,
|
|
|
|
|
///
|
2021-05-26 12:42:21 +08:00
|
|
|
|
RightShift,
|
|
|
|
|
///
|
|
|
|
|
RightControl,
|
|
|
|
|
///
|
|
|
|
|
RightAlt,
|
|
|
|
|
///
|
2021-03-29 15:59:14 +08:00
|
|
|
|
/// Function, /// mac
|
|
|
|
|
/// keyboard layout dependent key
|
|
|
|
|
Layout(char),
|
|
|
|
|
/// raw keycode eg 0x38
|
|
|
|
|
Raw(u16),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Representing an interface and a set of keyboard functions every
|
|
|
|
|
/// operating system implementation _should_ implement.
|
|
|
|
|
pub trait KeyboardControllable {
|
|
|
|
|
/// Types the string parsed with DSL.
|
|
|
|
|
///
|
|
|
|
|
/// Typing {+SHIFT}hello{-SHIFT} becomes HELLO.
|
|
|
|
|
/// TODO: Full documentation
|
|
|
|
|
fn key_sequence_parse(&mut self, sequence: &str)
|
|
|
|
|
where
|
|
|
|
|
Self: Sized,
|
|
|
|
|
{
|
|
|
|
|
self.key_sequence_parse_try(sequence)
|
|
|
|
|
.expect("Could not parse sequence");
|
|
|
|
|
}
|
|
|
|
|
/// Same as key_sequence_parse except returns any errors
|
|
|
|
|
fn key_sequence_parse_try(&mut self, sequence: &str) -> Result<(), dsl::ParseError>
|
|
|
|
|
where
|
|
|
|
|
Self: Sized,
|
|
|
|
|
{
|
|
|
|
|
dsl::eval(self, sequence)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Types the string
|
|
|
|
|
///
|
|
|
|
|
/// Emits keystrokes such that the given string is inputted.
|
|
|
|
|
///
|
|
|
|
|
/// You can use many unicode here like: ❤️. This works
|
|
|
|
|
/// regadless of the current keyboardlayout.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// enigo.key_sequence("hello world ❤️");
|
|
|
|
|
/// ```
|
|
|
|
|
fn key_sequence(&mut self, sequence: &str);
|
|
|
|
|
|
|
|
|
|
/// presses a given key down
|
|
|
|
|
fn key_down(&mut self, key: Key) -> ResultType;
|
|
|
|
|
|
|
|
|
|
/// release a given key formally pressed down by
|
|
|
|
|
/// [key_down](trait.KeyboardControllable.html#tymethod.key_down)
|
|
|
|
|
fn key_up(&mut self, key: Key);
|
|
|
|
|
|
|
|
|
|
/// Much like the
|
|
|
|
|
/// [key_down](trait.KeyboardControllable.html#tymethod.key_down) and
|
|
|
|
|
/// [key_up](trait.KeyboardControllable.html#tymethod.key_up)
|
|
|
|
|
/// function they're just invoked consecutively
|
|
|
|
|
fn key_click(&mut self, key: Key);
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
fn get_key_state(&mut self, key: Key) -> bool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
|
struct Enigo;
|
|
|
|
|
|
|
|
|
|
impl Enigo {
|
|
|
|
|
/// Constructs a new `Enigo` instance.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use enigo::*;
|
|
|
|
|
/// let mut enigo = Enigo::new();
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
2021-05-26 12:42:21 +08:00
|
|
|
|
return Enigo {};
|
2021-03-29 15:59:14 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
Self::default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for Enigo {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
write!(f, "Enigo")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_get_key_state() {
|
|
|
|
|
let mut enigo = Enigo::new();
|
|
|
|
|
let keys = [Key::CapsLock, Key::NumLock];
|
|
|
|
|
for k in keys.iter() {
|
|
|
|
|
enigo.key_click(k.clone());
|
|
|
|
|
let a = enigo.get_key_state(k.clone());
|
|
|
|
|
enigo.key_click(k.clone());
|
|
|
|
|
let b = enigo.get_key_state(k.clone());
|
|
|
|
|
assert!(a != b);
|
|
|
|
|
}
|
|
|
|
|
let keys = [Key::Control, Key::Alt, Key::Shift];
|
|
|
|
|
for k in keys.iter() {
|
|
|
|
|
enigo.key_down(k.clone()).ok();
|
|
|
|
|
let a = enigo.get_key_state(k.clone());
|
|
|
|
|
enigo.key_up(k.clone());
|
|
|
|
|
let b = enigo.get_key_state(k.clone());
|
|
|
|
|
assert!(a != b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|