mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
source code
This commit is contained in:
73
libs/enigo/src/win/keycodes.rs
Normal file
73
libs/enigo/src/win/keycodes.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
|
||||
|
||||
pub const EVK_RETURN: u16 = 0x0D;
|
||||
pub const EVK_TAB: u16 = 0x09;
|
||||
pub const EVK_SPACE: u16 = 0x20;
|
||||
pub const EVK_BACK: u16 = 0x08;
|
||||
pub const EVK_ESCAPE: u16 = 0x1b;
|
||||
pub const EVK_LWIN: u16 = 0x5b;
|
||||
pub const EVK_SHIFT: u16 = 0x10;
|
||||
pub const EVK_CAPITAL: u16 = 0x14;
|
||||
pub const EVK_MENU: u16 = 0x12;
|
||||
pub const EVK_LCONTROL: u16 = 0xa2;
|
||||
pub const EVK_HOME: u16 = 0x24;
|
||||
pub const EVK_PRIOR: u16 = 0x21;
|
||||
pub const EVK_NEXT: u16 = 0x22;
|
||||
pub const EVK_END: u16 = 0x23;
|
||||
pub const EVK_LEFT: u16 = 0x25;
|
||||
pub const EVK_RIGHT: u16 = 0x27;
|
||||
pub const EVK_UP: u16 = 0x26;
|
||||
pub const EVK_DOWN: u16 = 0x28;
|
||||
pub const EVK_DELETE: u16 = 0x2E;
|
||||
pub const EVK_F1: u16 = 0x70;
|
||||
pub const EVK_F2: u16 = 0x71;
|
||||
pub const EVK_F3: u16 = 0x72;
|
||||
pub const EVK_F4: u16 = 0x73;
|
||||
pub const EVK_F5: u16 = 0x74;
|
||||
pub const EVK_F6: u16 = 0x75;
|
||||
pub const EVK_F7: u16 = 0x76;
|
||||
pub const EVK_F8: u16 = 0x77;
|
||||
pub const EVK_F9: u16 = 0x78;
|
||||
pub const EVK_F10: u16 = 0x79;
|
||||
pub const EVK_F11: u16 = 0x7a;
|
||||
pub const EVK_F12: u16 = 0x7b;
|
||||
pub const EVK_NUMPAD0: u16 = 0x60;
|
||||
pub const EVK_NUMPAD1: u16 = 0x61;
|
||||
pub const EVK_NUMPAD2: u16 = 0x62;
|
||||
pub const EVK_NUMPAD3: u16 = 0x63;
|
||||
pub const EVK_NUMPAD4: u16 = 0x64;
|
||||
pub const EVK_NUMPAD5: u16 = 0x65;
|
||||
pub const EVK_NUMPAD6: u16 = 0x66;
|
||||
pub const EVK_NUMPAD7: u16 = 0x67;
|
||||
pub const EVK_NUMPAD8: u16 = 0x68;
|
||||
pub const EVK_NUMPAD9: u16 = 0x69;
|
||||
pub const EVK_CANCEL: u16 = 0x03;
|
||||
pub const EVK_CLEAR: u16 = 0x0C;
|
||||
pub const EVK_PAUSE: u16 = 0x13;
|
||||
pub const EVK_KANA: u16 = 0x15;
|
||||
pub const EVK_HANGUL: u16 = 0x15;
|
||||
pub const EVK_JUNJA: u16 = 0x17;
|
||||
pub const EVK_FINAL: u16 = 0x18;
|
||||
pub const EVK_HANJA: u16 = 0x19;
|
||||
pub const EVK_KANJI: u16 = 0x19;
|
||||
pub const EVK_CONVERT: u16 = 0x1C;
|
||||
pub const EVK_SELECT: u16 = 0x29;
|
||||
pub const EVK_PRINT: u16 = 0x2A;
|
||||
pub const EVK_EXECUTE: u16 = 0x2B;
|
||||
pub const EVK_SNAPSHOT: u16 = 0x2C;
|
||||
pub const EVK_INSERT: u16 = 0x2D;
|
||||
pub const EVK_HELP: u16 = 0x2F;
|
||||
pub const EVK_SLEEP: u16 = 0x5F;
|
||||
pub const EVK_SEPARATOR: u16 = 0x6C;
|
||||
pub const EVK_VOLUME_MUTE: u16 = 0xAD;
|
||||
pub const EVK_VOLUME_DOWN: u16 = 0xAE;
|
||||
pub const EVK_VOLUME_UP: u16 = 0xAF;
|
||||
pub const EVK_NUMLOCK: u16 = 0x90;
|
||||
pub const EVK_SCROLL: u16 = 0x91;
|
||||
pub const EVK_RWIN: u16 = 0x5C;
|
||||
pub const EVK_APPS: u16 = 0x5D;
|
||||
pub const EVK_ADD: u16 = 0x6B;
|
||||
pub const EVK_MULTIPLY: u16 = 0x6A;
|
||||
pub const EVK_SUBTRACT: u16 = 0x6D;
|
||||
pub const EVK_DECIMAL: u16 = 0x6E;
|
||||
pub const EVK_DIVIDE: u16 = 0x6F;
|
||||
4
libs/enigo/src/win/mod.rs
Normal file
4
libs/enigo/src/win/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod win_impl;
|
||||
|
||||
pub mod keycodes;
|
||||
pub use self::win_impl::Enigo;
|
||||
366
libs/enigo/src/win/win_impl.rs
Normal file
366
libs/enigo/src/win/win_impl.rs
Normal file
@@ -0,0 +1,366 @@
|
||||
use winapi;
|
||||
|
||||
use self::winapi::ctypes::c_int;
|
||||
use self::winapi::shared::{minwindef::*, windef::*};
|
||||
use self::winapi::um::winbase::*;
|
||||
use self::winapi::um::winuser::*;
|
||||
|
||||
use crate::win::keycodes::*;
|
||||
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
|
||||
use std::mem::*;
|
||||
|
||||
extern "system" {
|
||||
pub fn GetLastError() -> DWORD;
|
||||
}
|
||||
|
||||
/// The main struct for handling the event emitting
|
||||
#[derive(Default)]
|
||||
pub struct Enigo;
|
||||
|
||||
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
|
||||
let mut input = INPUT {
|
||||
type_: INPUT_MOUSE,
|
||||
u: unsafe {
|
||||
transmute(MOUSEINPUT {
|
||||
dx,
|
||||
dy,
|
||||
mouseData: data,
|
||||
dwFlags: flags,
|
||||
time: 0,
|
||||
dwExtraInfo: 0,
|
||||
})
|
||||
},
|
||||
};
|
||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) }
|
||||
}
|
||||
|
||||
fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
|
||||
let mut input = INPUT {
|
||||
type_: INPUT_KEYBOARD,
|
||||
u: unsafe {
|
||||
transmute_copy(&KEYBDINPUT {
|
||||
wVk: vk,
|
||||
wScan: scan,
|
||||
dwFlags: flags,
|
||||
time: 0,
|
||||
dwExtraInfo: 0,
|
||||
})
|
||||
},
|
||||
};
|
||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) }
|
||||
}
|
||||
|
||||
fn get_error() -> String {
|
||||
unsafe {
|
||||
let buff_size = 256;
|
||||
let mut buff: Vec<u16> = Vec::with_capacity(buff_size);
|
||||
buff.resize(buff_size, 0);
|
||||
let errno = GetLastError();
|
||||
let chars_copied = FormatMessageW(
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
std::ptr::null(),
|
||||
errno,
|
||||
0,
|
||||
buff.as_mut_ptr(),
|
||||
(buff_size + 1) as u32,
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
if chars_copied == 0 {
|
||||
return "".to_owned();
|
||||
}
|
||||
let mut curr_char: usize = chars_copied as usize;
|
||||
while curr_char > 0 {
|
||||
let ch = buff[curr_char];
|
||||
|
||||
if ch >= ' ' as u16 {
|
||||
break;
|
||||
}
|
||||
curr_char -= 1;
|
||||
}
|
||||
let sl = std::slice::from_raw_parts(buff.as_ptr(), curr_char);
|
||||
let err_msg = String::from_utf16(sl);
|
||||
return err_msg.unwrap_or("".to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
impl MouseControllable for Enigo {
|
||||
fn mouse_move_to(&mut self, x: i32, y: i32) {
|
||||
mouse_event(
|
||||
MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK,
|
||||
0,
|
||||
(x - unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) }) * 65535
|
||||
/ unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) },
|
||||
(y - unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) }) * 65535
|
||||
/ unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) },
|
||||
);
|
||||
}
|
||||
|
||||
fn mouse_move_relative(&mut self, x: i32, y: i32) {
|
||||
mouse_event(MOUSEEVENTF_MOVE, 0, x, y);
|
||||
}
|
||||
|
||||
fn mouse_down(&mut self, button: MouseButton) -> crate::ResultType {
|
||||
let res = mouse_event(
|
||||
match button {
|
||||
MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
|
||||
MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
|
||||
MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
if res == 0 {
|
||||
let err = get_error();
|
||||
if !err.is_empty() {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mouse_up(&mut self, button: MouseButton) {
|
||||
mouse_event(
|
||||
match button {
|
||||
MouseButton::Left => MOUSEEVENTF_LEFTUP,
|
||||
MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
|
||||
MouseButton::Right => MOUSEEVENTF_RIGHTUP,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
fn mouse_click(&mut self, button: MouseButton) {
|
||||
self.mouse_down(button).ok();
|
||||
self.mouse_up(button);
|
||||
}
|
||||
|
||||
fn mouse_scroll_x(&mut self, length: i32) {
|
||||
mouse_event(MOUSEEVENTF_HWHEEL, unsafe { transmute(length * 120) }, 0, 0);
|
||||
}
|
||||
|
||||
fn mouse_scroll_y(&mut self, length: i32) {
|
||||
mouse_event(MOUSEEVENTF_WHEEL, unsafe { transmute(length * 120) }, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyboardControllable for Enigo {
|
||||
fn key_sequence(&mut self, sequence: &str) {
|
||||
let mut buffer = [0; 2];
|
||||
|
||||
for c in sequence.chars() {
|
||||
// Windows uses uft-16 encoding. We need to check
|
||||
// for variable length characters. As such some
|
||||
// characters can be 32 bit long and those are
|
||||
// encoded in such called hight and low surrogates
|
||||
// each 16 bit wide that needs to be send after
|
||||
// another to the SendInput function without
|
||||
// being interrupted by "keyup"
|
||||
let result = c.encode_utf16(&mut buffer);
|
||||
if result.len() == 1 {
|
||||
self.unicode_key_click(result[0]);
|
||||
} else {
|
||||
for utf16_surrogate in result {
|
||||
self.unicode_key_down(utf16_surrogate.clone());
|
||||
}
|
||||
// do i need to produce a keyup?
|
||||
// self.unicode_key_up(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn key_click(&mut self, key: Key) {
|
||||
let scancode = self.key_to_scancode(key);
|
||||
keybd_event(KEYEVENTF_SCANCODE, 0, scancode);
|
||||
keybd_event(KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE, 0, scancode);
|
||||
}
|
||||
|
||||
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
||||
let res = keybd_event(KEYEVENTF_SCANCODE, 0, self.key_to_scancode(key));
|
||||
if res == 0 {
|
||||
let err = get_error();
|
||||
if !err.is_empty() {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn key_up(&mut self, key: Key) {
|
||||
keybd_event(
|
||||
KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE,
|
||||
0,
|
||||
self.key_to_scancode(key),
|
||||
);
|
||||
}
|
||||
|
||||
fn get_key_state(&mut self, key: Key) -> bool {
|
||||
let keycode = self.key_to_keycode(key);
|
||||
let x = unsafe { GetKeyState(keycode as _) };
|
||||
if key == Key::CapsLock || key == Key::NumLock || key == Key::Scroll {
|
||||
return (x & 0x1) == 0x1;
|
||||
}
|
||||
return (x as u16 & 0x8000) == 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
impl Enigo {
|
||||
/// Gets the (width, height) of the main display in screen coordinates (pixels).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use enigo::*;
|
||||
/// let mut size = Enigo::main_display_size();
|
||||
/// ```
|
||||
pub fn main_display_size() -> (usize, usize) {
|
||||
let w = unsafe { GetSystemMetrics(SM_CXSCREEN) as usize };
|
||||
let h = unsafe { GetSystemMetrics(SM_CYSCREEN) as usize };
|
||||
(w, h)
|
||||
}
|
||||
|
||||
/// Gets the location of mouse in screen coordinates (pixels).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use enigo::*;
|
||||
/// let mut location = Enigo::mouse_location();
|
||||
/// ```
|
||||
pub fn mouse_location() -> (i32, i32) {
|
||||
let mut point = POINT { x: 0, y: 0 };
|
||||
let result = unsafe { GetCursorPos(&mut point) };
|
||||
if result != 0 {
|
||||
(point.x, point.y)
|
||||
} else {
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn unicode_key_click(&self, unicode_char: u16) {
|
||||
self.unicode_key_down(unicode_char);
|
||||
self.unicode_key_up(unicode_char);
|
||||
}
|
||||
|
||||
fn unicode_key_down(&self, unicode_char: u16) {
|
||||
keybd_event(KEYEVENTF_UNICODE, 0, unicode_char);
|
||||
}
|
||||
|
||||
fn unicode_key_up(&self, unicode_char: u16) {
|
||||
keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char);
|
||||
}
|
||||
|
||||
fn key_to_keycode(&self, key: Key) -> u16 {
|
||||
// do not use the codes from crate winapi they're
|
||||
// wrongly typed with i32 instead of i16 use the
|
||||
// ones provided by win/keycodes.rs that are prefixed
|
||||
// with an 'E' infront of the original name
|
||||
#[allow(deprecated)]
|
||||
// I mean duh, we still need to support deprecated keys until they're removed
|
||||
match key {
|
||||
Key::Alt => EVK_MENU,
|
||||
Key::Backspace => EVK_BACK,
|
||||
Key::CapsLock => EVK_CAPITAL,
|
||||
Key::Control => EVK_LCONTROL,
|
||||
Key::Delete => EVK_DELETE,
|
||||
Key::DownArrow => EVK_DOWN,
|
||||
Key::End => EVK_END,
|
||||
Key::Escape => EVK_ESCAPE,
|
||||
Key::F1 => EVK_F1,
|
||||
Key::F10 => EVK_F10,
|
||||
Key::F11 => EVK_F11,
|
||||
Key::F12 => EVK_F12,
|
||||
Key::F2 => EVK_F2,
|
||||
Key::F3 => EVK_F3,
|
||||
Key::F4 => EVK_F4,
|
||||
Key::F5 => EVK_F5,
|
||||
Key::F6 => EVK_F6,
|
||||
Key::F7 => EVK_F7,
|
||||
Key::F8 => EVK_F8,
|
||||
Key::F9 => EVK_F9,
|
||||
Key::Home => EVK_HOME,
|
||||
Key::LeftArrow => EVK_LEFT,
|
||||
Key::Option => EVK_MENU,
|
||||
Key::PageDown => EVK_NEXT,
|
||||
Key::PageUp => EVK_PRIOR,
|
||||
Key::Return => EVK_RETURN,
|
||||
Key::RightArrow => EVK_RIGHT,
|
||||
Key::Shift => EVK_SHIFT,
|
||||
Key::Space => EVK_SPACE,
|
||||
Key::Tab => EVK_TAB,
|
||||
Key::UpArrow => EVK_UP,
|
||||
Key::Numpad0 => EVK_NUMPAD0,
|
||||
Key::Numpad1 => EVK_NUMPAD1,
|
||||
Key::Numpad2 => EVK_NUMPAD2,
|
||||
Key::Numpad3 => EVK_NUMPAD3,
|
||||
Key::Numpad4 => EVK_NUMPAD4,
|
||||
Key::Numpad5 => EVK_NUMPAD5,
|
||||
Key::Numpad6 => EVK_NUMPAD6,
|
||||
Key::Numpad7 => EVK_NUMPAD7,
|
||||
Key::Numpad8 => EVK_NUMPAD8,
|
||||
Key::Numpad9 => EVK_NUMPAD9,
|
||||
Key::Cancel => EVK_CANCEL,
|
||||
Key::Clear => EVK_CLEAR,
|
||||
Key::Menu => EVK_MENU,
|
||||
Key::Pause => EVK_PAUSE,
|
||||
Key::Kana => EVK_KANA,
|
||||
Key::Hangul => EVK_HANGUL,
|
||||
Key::Junja => EVK_JUNJA,
|
||||
Key::Final => EVK_FINAL,
|
||||
Key::Hanja => EVK_HANJA,
|
||||
Key::Kanji => EVK_KANJI,
|
||||
Key::Convert => EVK_CONVERT,
|
||||
Key::Select => EVK_SELECT,
|
||||
Key::Print => EVK_PRINT,
|
||||
Key::Execute => EVK_EXECUTE,
|
||||
Key::Snapshot => EVK_SNAPSHOT,
|
||||
Key::Insert => EVK_INSERT,
|
||||
Key::Help => EVK_HELP,
|
||||
Key::Sleep => EVK_SLEEP,
|
||||
Key::Separator => EVK_SEPARATOR,
|
||||
Key::Mute => EVK_VOLUME_MUTE,
|
||||
Key::VolumeDown => EVK_VOLUME_DOWN,
|
||||
Key::VolumeUp => EVK_VOLUME_UP,
|
||||
Key::Scroll => EVK_SCROLL,
|
||||
Key::NumLock => EVK_NUMLOCK,
|
||||
Key::RWin => EVK_RWIN,
|
||||
Key::Apps => EVK_APPS,
|
||||
Key::Add => EVK_ADD,
|
||||
Key::Multiply => EVK_MULTIPLY,
|
||||
Key::Decimal => EVK_DECIMAL,
|
||||
Key::Subtract => EVK_SUBTRACT,
|
||||
Key::Divide => EVK_DIVIDE,
|
||||
Key::NumpadEnter => EVK_RETURN,
|
||||
Key::Equals => '=' as _,
|
||||
|
||||
Key::Raw(raw_keycode) => raw_keycode,
|
||||
Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
|
||||
Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN,
|
||||
}
|
||||
}
|
||||
|
||||
fn key_to_scancode(&self, key: Key) -> u16 {
|
||||
let keycode = self.key_to_keycode(key);
|
||||
unsafe { MapVirtualKeyW(keycode as u32, 0) as u16 }
|
||||
}
|
||||
|
||||
fn get_layoutdependent_keycode(&self, string: String) -> u16 {
|
||||
// get the first char from the string ignore the rest
|
||||
// ensure its not a multybyte char
|
||||
if let Some(chr) = string.chars().nth(0) {
|
||||
// NOTE VkKeyScanW uses the current keyboard layout
|
||||
// to specify a layout use VkKeyScanExW and GetKeyboardLayout
|
||||
// or load one with LoadKeyboardLayoutW
|
||||
let keycode_and_shiftstate = unsafe { VkKeyScanW(chr as _) };
|
||||
keycode_and_shiftstate as _
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user