mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
source code
This commit is contained in:
525
libs/enigo/src/lib.rs
Normal file
525
libs/enigo/src/lib.rs
Normal file
@@ -0,0 +1,525 @@
|
||||
//! 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)
|
||||
Option,
|
||||
/// 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,
|
||||
///
|
||||
Menu,
|
||||
///
|
||||
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,
|
||||
///
|
||||
/// 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"))]
|
||||
return Enigo{};
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user