ing
This commit is contained in:
parent
9638e5cac6
commit
ea09dc582d
|
@ -9,12 +9,13 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.117", optional = true }
|
serde = { version = "1.0.117", optional = true }
|
||||||
serde_derive = { version = "1.0.117", optional = true }
|
serde_derive = { version = "1.0.117", optional = true }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
with_serde = ["serde", "serde_derive"]
|
with_serde = ["serde", "serde_derive"]
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = ["winuser"] }
|
winapi = { version = "0.3.9", features = ["winuser", "errhandlingapi"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pkg-config = "0.3.19"
|
pkg-config = "0.3.19"
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
#[cfg(target_os = "windows")]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
mod windows;
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub use crate::keyboard::windows::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
Escape,
|
Escape,
|
||||||
Digit0,
|
Digit0,
|
||||||
|
@ -123,10 +119,3 @@ pub enum Key {
|
||||||
MetaLeft,
|
MetaLeft,
|
||||||
MetaRight,
|
MetaRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum KeyboardState {
|
|
||||||
Press,
|
|
||||||
Release,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Keyboard;
|
|
|
@ -1,153 +0,0 @@
|
||||||
// // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
|
|
||||||
|
|
||||||
// pub const VK_LBUTTON: u16 = 0x01; // Left mouse button
|
|
||||||
// pub const VK_RBUTTON: u16 = 0x02; // Right mouse button
|
|
||||||
// pub const VK_CANCEL: u16 = 0x03; // Control-break processing
|
|
||||||
// pub const VK_MBUTTON: u16 = 0x04; // Middle mouse button (three-button mouse)
|
|
||||||
// pub const VK_XBUTTON1: u16 = 0x05; // X1 mouse button
|
|
||||||
// pub const VK_XBUTTON2: u16 = 0x06; // X2 mouse button
|
|
||||||
// pub const VK_BACK: u16 = 0x08; // BACKSPACE key
|
|
||||||
// pub const VK_TAB: u16 = 0x09; // TAB key
|
|
||||||
// pub const VK_CLEAR: u16 = 0x0C; // CLEAR key
|
|
||||||
// pub const VK_RETURN: u16 = 0x0D; // ENTER key
|
|
||||||
// pub const VK_SHIFT: u16 = 0x10; // SHIFT key
|
|
||||||
// pub const VK_CONTROL: u16 = 0x11; // CTRL key
|
|
||||||
// pub const VK_MENU: u16 = 0x12; // ALT key
|
|
||||||
// pub const VK_PAUSE: u16 = 0x13; // PAUSE key
|
|
||||||
// pub const VK_CAPITAL: u16 = 0x14; // CAPS LOCK key
|
|
||||||
// pub const VK_KANA: u16 = 0x15; // IME Kana mode
|
|
||||||
// pub const VK_HANGUEL: u16 = 0x15; // IME Hanguel mode (maintained for compatibility; use VK_HANGUL)
|
|
||||||
// pub const VK_HANGUL: u16 = 0x15; // IME Hangul mode
|
|
||||||
// pub const VK_IME_ON: u16 = 0x16; // IME On
|
|
||||||
// pub const VK_JUNJA: u16 = 0x17; // IME Junja mode
|
|
||||||
// pub const VK_FINAL: u16 = 0x18; // IME final mode
|
|
||||||
// pub const VK_HANJA: u16 = 0x19; // IME Hanja mode
|
|
||||||
// pub const VK_KANJI: u16 = 0x19; // IME Kanji mode
|
|
||||||
// pub const VK_IME_OFF: u16 = 0x1A; // IME Off
|
|
||||||
// pub const VK_ESCAPE: u16 = 0x1B; // ESC key
|
|
||||||
// pub const VK_CONVERT: u16 = 0x1C; // IME convert
|
|
||||||
// pub const VK_NONCONVERT: u16 = 0x1D; // IME nonconvert
|
|
||||||
// pub const VK_ACCEPT: u16 = 0x1E; // IME accept
|
|
||||||
// pub const VK_MODECHANGE: u16 = 0x1F; // IME mode change request
|
|
||||||
// pub const VK_SPACE: u16 = 0x20; // SPACEBAR
|
|
||||||
// pub const VK_PRIOR: u16 = 0x21; // PAGE UP key
|
|
||||||
// pub const VK_NEXT: u16 = 0x22; // PAGE DOWN key
|
|
||||||
// pub const VK_END: u16 = 0x23; // END key
|
|
||||||
// pub const VK_HOME: u16 = 0x24; // HOME key
|
|
||||||
// pub const VK_LEFT: u16 = 0x25; // LEFT ARROW key
|
|
||||||
// pub const VK_UP: u16 = 0x26; // UP ARROW key
|
|
||||||
// pub const VK_RIGHT: u16 = 0x27; // RIGHT ARROW key
|
|
||||||
// pub const VK_DOWN: u16 = 0x28; // DOWN ARROW key
|
|
||||||
// pub const VK_SELECT: u16 = 0x29; // SELECT key
|
|
||||||
// pub const VK_PRINT: u16 = 0x2A; // PRINT key
|
|
||||||
// pub const VK_EXECUTE: u16 = 0x2B; // EXECUTE key
|
|
||||||
// pub const VK_SNAPSHOT: u16 = 0x2C; // PRINT SCREEN key
|
|
||||||
// pub const VK_INSERT: u16 = 0x2D; // INS key
|
|
||||||
// pub const VK_DELETE: u16 = 0x2E; // DEL key
|
|
||||||
// pub const VK_HELP: u16 = 0x2F; // HELP key
|
|
||||||
// pub const VK_DIGIT_0: u16 = 0x30; // 0 key
|
|
||||||
// pub const VK_DIGIT_1: u16 = 0x31; // 1 key
|
|
||||||
// pub const VK_DIGIT_2: u16 = 0x32; // 2 key
|
|
||||||
// pub const VK_DIGIT_3: u16 = 0x33; // 3 key
|
|
||||||
// pub const VK_DIGIT_4: u16 = 0x34; // 4 key
|
|
||||||
// pub const VK_DIGIT_5: u16 = 0x35; // 5 key
|
|
||||||
// pub const VK_DIGIT_6: u16 = 0x36; // 6 key
|
|
||||||
// pub const VK_DIGIT_7: u16 = 0x37; // 7 key
|
|
||||||
// pub const VK_DIGIT_8: u16 = 0x38; // 8 key
|
|
||||||
// pub const VK_DIGIT_9: u16 = 0x39; // 9 key
|
|
||||||
// pub const VK_KEY_A: u16 = 0x41; // A key
|
|
||||||
// pub const VK_KEY_B: u16 = 0x42; // B key
|
|
||||||
// pub const VK_KEY_C: u16 = 0x43; // C key
|
|
||||||
// pub const VK_KEY_D: u16 = 0x44; // D key
|
|
||||||
// pub const VK_KEY_E: u16 = 0x45; // E key
|
|
||||||
// pub const VK_KEY_F: u16 = 0x46; // F key
|
|
||||||
// pub const VK_KEY_G: u16 = 0x47; // G key
|
|
||||||
// pub const VK_KEY_H: u16 = 0x48; // H key
|
|
||||||
// pub const VK_KEY_I: u16 = 0x49; // I key
|
|
||||||
// pub const VK_KEY_J: u16 = 0x4A; // J key
|
|
||||||
// pub const VK_KEY_K: u16 = 0x4B; // K key
|
|
||||||
// pub const VK_KEY_L: u16 = 0x4C; // L key
|
|
||||||
// pub const VK_KEY_M: u16 = 0x4D; // M key
|
|
||||||
// pub const VK_KEY_N: u16 = 0x4E; // N key
|
|
||||||
// pub const VK_KEY_O: u16 = 0x4F; // O key
|
|
||||||
// pub const VK_KEY_P: u16 = 0x50; // P key
|
|
||||||
// pub const VK_KEY_Q: u16 = 0x51; // Q key
|
|
||||||
// pub const VK_KEY_R: u16 = 0x52; // R key
|
|
||||||
// pub const VK_KEY_S: u16 = 0x53; // S key
|
|
||||||
// pub const VK_KEY_T: u16 = 0x54; // T key
|
|
||||||
// pub const VK_KEY_U: u16 = 0x55; // U key
|
|
||||||
// pub const VK_KEY_V: u16 = 0x56; // V key
|
|
||||||
// pub const VK_KEY_W: u16 = 0x57; // W key
|
|
||||||
// pub const VK_KEY_X: u16 = 0x58; // X key
|
|
||||||
// pub const VK_KEY_Y: u16 = 0x59; // Y key
|
|
||||||
// pub const VK_KEY_Z: u16 = 0x5A; // Z key
|
|
||||||
// pub const VK_LWIN: u16 = 0x5B; // Left Windows key (Natural keyboard)
|
|
||||||
// pub const VK_RWIN: u16 = 0x5C; // Right Windows key (Natural keyboard)
|
|
||||||
// pub const VK_APPS: u16 = 0x5D; // Applications key (Natural keyboard)
|
|
||||||
// pub const VK_SLEEP: u16 = 0x5F; // Computer Sleep key
|
|
||||||
// pub const VK_NUMPAD0: u16 = 0x60; // Numeric keypad 0 key
|
|
||||||
// pub const VK_NUMPAD1: u16 = 0x61; // Numeric keypad 1 key
|
|
||||||
// pub const VK_NUMPAD2: u16 = 0x62; // Numeric keypad 2 key
|
|
||||||
// pub const VK_NUMPAD3: u16 = 0x63; // Numeric keypad 3 key
|
|
||||||
// pub const VK_NUMPAD4: u16 = 0x64; // Numeric keypad 4 key
|
|
||||||
// pub const VK_NUMPAD5: u16 = 0x65; // Numeric keypad 5 key
|
|
||||||
// pub const VK_NUMPAD6: u16 = 0x66; // Numeric keypad 6 key
|
|
||||||
// pub const VK_NUMPAD7: u16 = 0x67; // Numeric keypad 7 key
|
|
||||||
// pub const VK_NUMPAD8: u16 = 0x68; // Numeric keypad 8 key
|
|
||||||
// pub const VK_NUMPAD9: u16 = 0x69; // Numeric keypad 9 key
|
|
||||||
// pub const VK_MULTIPLY: u16 = 0x6A; // Multiply key
|
|
||||||
// pub const VK_ADD: u16 = 0x6B; // Add key
|
|
||||||
// pub const VK_SEPARATOR: u16 = 0x6C; // Separator key
|
|
||||||
// pub const VK_SUBTRACT: u16 = 0x6D; // Subtract key
|
|
||||||
// pub const VK_DECIMAL: u16 = 0x6E; // Decimal key
|
|
||||||
// pub const VK_DIVIDE: u16 = 0x6F; // Divide key
|
|
||||||
// pub const VK_F1: u16 = 0x70; // F1 key
|
|
||||||
// pub const VK_F2: u16 = 0x71; // F2 key
|
|
||||||
// pub const VK_F3: u16 = 0x72; // F3 key
|
|
||||||
// pub const VK_F4: u16 = 0x73; // F4 key
|
|
||||||
// pub const VK_F5: u16 = 0x74; // F5 key
|
|
||||||
// pub const VK_F6: u16 = 0x75; // F6 key
|
|
||||||
// pub const VK_F7: u16 = 0x76; // F7 key
|
|
||||||
// pub const VK_F8: u16 = 0x77; // F8 key
|
|
||||||
// pub const VK_F9: u16 = 0x78; // F9 key
|
|
||||||
// pub const VK_F10: u16 = 0x79; // F10 key
|
|
||||||
// pub const VK_F11: u16 = 0x7A; // F11 key
|
|
||||||
// pub const VK_F12: u16 = 0x7B; // F12 key
|
|
||||||
// pub const VK_F13: u16 = 0x7C; // F13 key
|
|
||||||
// pub const VK_F14: u16 = 0x7D; // F14 key
|
|
||||||
// pub const VK_F15: u16 = 0x7E; // F15 key
|
|
||||||
// pub const VK_F16: u16 = 0x7F; // F16 key
|
|
||||||
// pub const VK_F17: u16 = 0x80; // F17 key
|
|
||||||
// pub const VK_F18: u16 = 0x81; // F18 key
|
|
||||||
// pub const VK_F19: u16 = 0x82; // F19 key
|
|
||||||
// pub const VK_F20: u16 = 0x83; // F20 key
|
|
||||||
// pub const VK_F21: u16 = 0x84; // F21 key
|
|
||||||
// pub const VK_F22: u16 = 0x85; // F22 key
|
|
||||||
// pub const VK_F23: u16 = 0x86; // F23 key
|
|
||||||
// pub const VK_F24: u16 = 0x87; // F24 key
|
|
||||||
// pub const VK_NUMLOCK: u16 = 0x90; // NUM LOCK key
|
|
||||||
// pub const VK_SCROLL: u16 = 0x91; // SCROLL LOCK key
|
|
||||||
// pub const VK_LSHIFT: u16 = 0xA0; // Left SHIFT key
|
|
||||||
// pub const VK_RSHIFT: u16 = 0xA1; // Right SHIFT key
|
|
||||||
// pub const VK_LCONTROL: u16 = 0xA2; // Left CONTROL key
|
|
||||||
// pub const VK_RCONTROL: u16 = 0xA3; // Right CONTROL key
|
|
||||||
// pub const VK_LMENU: u16 = 0xA4; // Left MENU key
|
|
||||||
// pub const VK_RMENU: u16 = 0xA5; // Right MENU key
|
|
||||||
// pub const VK_BROWSER_BACK: u16 = 0xA6; // Browser Back key
|
|
||||||
// pub const VK_BROWSER_FORWARD: u16 = 0xA7; // Browser Forward key
|
|
||||||
// pub const VK_BROWSER_REFRESH: u16 = 0xA8; // Browser Refresh key
|
|
||||||
// pub const VK_BROWSER_STOP: u16 = 0xA9; // Browser Stop key
|
|
||||||
// pub const VK_BROWSER_SEARCH: u16 = 0xAA; // Browser Search key
|
|
||||||
// pub const VK_BROWSER_FAVORITES: u16 = 0xAB; // Browser Favorites key
|
|
||||||
// pub const VK_BROWSER_HOME: u16 = 0xAC; // Browser Start and Home key
|
|
||||||
// pub const VK_VOLUME_MUTE: u16 = 0xAD; // Volume Mute key
|
|
||||||
// pub const VK_VOLUME_DOWN: u16 = 0xAE; // Volume Down key
|
|
||||||
// pub const VK_VOLUME_UP: u16 = 0xAF; // Volume Up key
|
|
||||||
// pub const VK_MEDIA_NEXT_TRACK: u16 = 0xB0; // Next Track key
|
|
||||||
// pub const VK_MEDIA_PREV_TRACK: u16 = 0xB1; // Previous Track key
|
|
||||||
// pub const VK_MEDIA_STOP: u16 = 0xB2; // Stop Media key
|
|
||||||
// pub const VK_MEDIA_PLAY_PAUSE: u16 = 0xB3; // Play/Pause Media key
|
|
||||||
// pub const VK_LAUNCH_MAIL: u16 = 0xB4; // Start Mail key
|
|
||||||
// pub const VK_LAUNCH_MEDIA_SELECT: u16 = 0xB5; // Select Media key
|
|
||||||
// pub const VK_LAUNCH_APP1: u16 = 0xB6; // Start Application 1 key
|
|
||||||
// pub const VK_LAUNCH_APP2: u16 = 0xB7; // Start Application 2 key
|
|
|
@ -1,178 +0,0 @@
|
||||||
use std::mem::{size_of, transmute_copy};
|
|
||||||
use winapi::ctypes::c_int;
|
|
||||||
use winapi::shared::minwindef::WORD;
|
|
||||||
use winapi::um::winuser::{
|
|
||||||
GetAsyncKeyState, MapVirtualKeyW, SendInput, INPUT, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_KEYUP,
|
|
||||||
KEYEVENTF_SCANCODE, LPINPUT,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::keyboard::{Key, Keyboard};
|
|
||||||
|
|
||||||
impl Keyboard {
|
|
||||||
pub fn press(key: Key) {
|
|
||||||
let dw_flags = KEYEVENTF_SCANCODE;
|
|
||||||
|
|
||||||
let mut input = INPUT {
|
|
||||||
type_: INPUT_KEYBOARD,
|
|
||||||
u: unsafe {
|
|
||||||
transmute_copy(&KEYBDINPUT {
|
|
||||||
wVk: 0,
|
|
||||||
wScan: Self::key_to_scancode(key),
|
|
||||||
dwFlags: dw_flags,
|
|
||||||
time: 0,
|
|
||||||
dwExtraInfo: 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release(key: Key) {
|
|
||||||
let dw_flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
|
|
||||||
|
|
||||||
let mut input = INPUT {
|
|
||||||
type_: INPUT_KEYBOARD,
|
|
||||||
u: unsafe {
|
|
||||||
transmute_copy(&KEYBDINPUT {
|
|
||||||
wVk: 0,
|
|
||||||
wScan: Self::key_to_scancode(key),
|
|
||||||
dwFlags: dw_flags,
|
|
||||||
time: 0,
|
|
||||||
dwExtraInfo: 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pressed(key: Key) -> bool {
|
|
||||||
(unsafe { GetAsyncKeyState(Self::key_2_virtual_key(key) as i32) } >> 15) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_to_scancode(key: Key) -> u16 {
|
|
||||||
let vk = Self::key_2_virtual_key(key);
|
|
||||||
unsafe { MapVirtualKeyW(vk as u32, 0) as u16 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_2_virtual_key(key: Key) -> WORD {
|
|
||||||
match key {
|
|
||||||
Key::Digit0 => 0x30,
|
|
||||||
Key::Digit1 => 0x31,
|
|
||||||
Key::Digit2 => 0x32,
|
|
||||||
Key::Digit3 => 0x33,
|
|
||||||
Key::Digit4 => 0x34,
|
|
||||||
Key::Digit5 => 0x35,
|
|
||||||
Key::Digit6 => 0x36,
|
|
||||||
Key::Digit7 => 0x37,
|
|
||||||
Key::Digit8 => 0x38,
|
|
||||||
Key::Digit9 => 0x39,
|
|
||||||
Key::KeyA => 0x41,
|
|
||||||
Key::KeyB => 0x42,
|
|
||||||
Key::KeyC => 0x43,
|
|
||||||
Key::KeyD => 0x44,
|
|
||||||
Key::KeyE => 0x45,
|
|
||||||
Key::KeyF => 0x46,
|
|
||||||
Key::KeyG => 0x47,
|
|
||||||
Key::KeyH => 0x48,
|
|
||||||
Key::KeyI => 0x49,
|
|
||||||
Key::KeyJ => 0x4A,
|
|
||||||
Key::KeyK => 0x4B,
|
|
||||||
Key::KeyL => 0x4C,
|
|
||||||
Key::KeyM => 0x4D,
|
|
||||||
Key::KeyN => 0x4E,
|
|
||||||
Key::KeyO => 0x4F,
|
|
||||||
Key::KeyP => 0x50,
|
|
||||||
Key::KeyQ => 0x51,
|
|
||||||
Key::KeyR => 0x52,
|
|
||||||
Key::KeyS => 0x53,
|
|
||||||
Key::KeyT => 0x54,
|
|
||||||
Key::KeyU => 0x55,
|
|
||||||
Key::KeyV => 0x56,
|
|
||||||
Key::KeyW => 0x57,
|
|
||||||
Key::KeyX => 0x58,
|
|
||||||
Key::KeyY => 0x59,
|
|
||||||
Key::KeyZ => 0x5A,
|
|
||||||
Key::F1 => 0x70,
|
|
||||||
Key::F2 => 0x71,
|
|
||||||
Key::F3 => 0x72,
|
|
||||||
Key::F4 => 0x73,
|
|
||||||
Key::F5 => 0x74,
|
|
||||||
Key::F6 => 0x75,
|
|
||||||
Key::F7 => 0x76,
|
|
||||||
Key::F8 => 0x77,
|
|
||||||
Key::F9 => 0x78,
|
|
||||||
Key::F10 => 0x79,
|
|
||||||
Key::F11 => 0x7A,
|
|
||||||
Key::F12 => 0x7B,
|
|
||||||
Key::F13 => 0x7C,
|
|
||||||
Key::F14 => 0x7D,
|
|
||||||
Key::F15 => 0x7E,
|
|
||||||
Key::F16 => 0x7F,
|
|
||||||
Key::F17 => 0x80,
|
|
||||||
Key::F18 => 0x81,
|
|
||||||
Key::F19 => 0x82,
|
|
||||||
Key::F20 => 0x83,
|
|
||||||
Key::F21 => 0x84,
|
|
||||||
Key::F22 => 0x85,
|
|
||||||
Key::F23 => 0x86,
|
|
||||||
Key::F24 => 0x87,
|
|
||||||
Key::Numpad0 => 0x60,
|
|
||||||
Key::Numpad1 => 0x61,
|
|
||||||
Key::Numpad2 => 0x62,
|
|
||||||
Key::Numpad3 => 0x63,
|
|
||||||
Key::Numpad4 => 0x64,
|
|
||||||
Key::Numpad5 => 0x65,
|
|
||||||
Key::Numpad6 => 0x66,
|
|
||||||
Key::Numpad7 => 0x67,
|
|
||||||
Key::Numpad8 => 0x68,
|
|
||||||
Key::Numpad9 => 0x69,
|
|
||||||
Key::NumpadAdd => 0x6B, // Add
|
|
||||||
Key::NumpadSubtract => 0x6D, // Subtract
|
|
||||||
Key::NumpadMultiply => 0x6A, // Multiply
|
|
||||||
Key::NumpadDivide => 0x6F, // Divide
|
|
||||||
Key::NumpadDecimal => 0x6E, // Decimal
|
|
||||||
Key::NumpadEqual => '=' as u16,
|
|
||||||
Key::NumpadComma => ',' as u16,
|
|
||||||
Key::NumpadEnter => 0x0D,
|
|
||||||
Key::NumLock => 0x90,
|
|
||||||
Key::Minus => '-' as u16,
|
|
||||||
Key::Equal => '=' as u16,
|
|
||||||
Key::BracketLeft => '{' as u16,
|
|
||||||
Key::BracketRight => '}' as u16,
|
|
||||||
Key::Semicolon => ';' as u16,
|
|
||||||
Key::Quote => '\'' as u16,
|
|
||||||
Key::Backquote => '`' as u16,
|
|
||||||
Key::Backslash => '\\' as u16,
|
|
||||||
Key::Comma => ',' as u16,
|
|
||||||
Key::Period => '~' as u16,
|
|
||||||
Key::Slash => '/' as u16,
|
|
||||||
Key::Escape => 0x1B,
|
|
||||||
Key::Enter => 0x0D,
|
|
||||||
Key::Backspace => 0x08,
|
|
||||||
Key::Tab => 0x09,
|
|
||||||
Key::Space => 0x20,
|
|
||||||
Key::CapsLock => 0x14,
|
|
||||||
Key::ShiftLeft => 0xA0,
|
|
||||||
Key::ShiftRight => 0xA1,
|
|
||||||
Key::ControlLeft => 0xA2,
|
|
||||||
Key::ControlRight => 0xA3,
|
|
||||||
Key::AltLeft => 0xA4,
|
|
||||||
Key::AltRight => 0xA5,
|
|
||||||
Key::Pause => 0x13,
|
|
||||||
Key::ScrollLock => 0x91,
|
|
||||||
Key::PrintScreen => 0x2C,
|
|
||||||
Key::ArrowLeft => 0x25,
|
|
||||||
Key::ArrowUp => 0x26,
|
|
||||||
Key::ArrowRight => 0x27,
|
|
||||||
Key::ArrowDown => 0x28,
|
|
||||||
Key::PageUp => 0x21,
|
|
||||||
Key::PageDown => 0x22,
|
|
||||||
Key::Home => 0x24,
|
|
||||||
Key::End => 0x23,
|
|
||||||
Key::Insert => 0x2D,
|
|
||||||
Key::Delete => 0x2E,
|
|
||||||
Key::MetaLeft => 0x5B,
|
|
||||||
Key::MetaRight => 0x5C,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
30
src/lib.rs
30
src/lib.rs
|
@ -1,2 +1,32 @@
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod windows;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use crate::windows::*;
|
||||||
|
|
||||||
|
use crate::keyboard::Key;
|
||||||
|
use crate::mouse::Button;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod mouse;
|
pub mod mouse;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub enum EventType {
|
||||||
|
KeyPress(Key),
|
||||||
|
KeyRelease(Key),
|
||||||
|
MousePress(Button),
|
||||||
|
MouseRelease(Button),
|
||||||
|
MouseMoveTo { x: f64, y: f64 },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct Event {
|
||||||
|
pub time: SystemTime,
|
||||||
|
pub event_type: EventType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HookCallback = fn(event: Event);
|
||||||
|
|
||||||
|
pub struct Robot;
|
||||||
|
|
10
src/mouse.rs
Normal file
10
src/mouse.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub enum Button {
|
||||||
|
Left,
|
||||||
|
Middle,
|
||||||
|
Right,
|
||||||
|
X1,
|
||||||
|
X2,
|
||||||
|
Other(u32),
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod windows;
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub use crate::mouse::windows::*;
|
|
||||||
|
|
||||||
pub enum Button {
|
|
||||||
Left,
|
|
||||||
Middle,
|
|
||||||
Right,
|
|
||||||
X1,
|
|
||||||
X2,
|
|
||||||
Other(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ButtonState {
|
|
||||||
Press,
|
|
||||||
Release,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Mouse;
|
|
|
@ -1,129 +0,0 @@
|
||||||
use std::mem::{size_of, transmute};
|
|
||||||
use winapi::ctypes::c_int;
|
|
||||||
use winapi::shared::minwindef::DWORD;
|
|
||||||
use winapi::um::winuser::{
|
|
||||||
GetAsyncKeyState, GetSystemMetrics, SendInput, INPUT, INPUT_MOUSE, LPINPUT, MOUSEEVENTF_ABSOLUTE,
|
|
||||||
MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
|
|
||||||
MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
|
|
||||||
MOUSEINPUT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN,
|
|
||||||
VK_LBUTTON, VK_MBUTTON, VK_RBUTTON, VK_XBUTTON1, VK_XBUTTON2,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::mouse::{Button, ButtonState, Mouse};
|
|
||||||
|
|
||||||
impl Mouse {
|
|
||||||
pub fn move_to(dx: i32, dy: i32) {
|
|
||||||
let width = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
|
|
||||||
let height = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };
|
|
||||||
if width == 0 || height == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let pressed_left = Self::pressed(Button::Left);
|
|
||||||
let pressed_right = Self::pressed(Button::Right);
|
|
||||||
let pressed_middle = Self::pressed(Button::Middle);
|
|
||||||
let mut dw_flags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
|
|
||||||
|
|
||||||
if pressed_left {
|
|
||||||
dw_flags = dw_flags | MOUSEEVENTF_LEFTDOWN;
|
|
||||||
}
|
|
||||||
if pressed_right {
|
|
||||||
dw_flags = dw_flags | MOUSEEVENTF_RIGHTDOWN;
|
|
||||||
}
|
|
||||||
if pressed_middle {
|
|
||||||
dw_flags = dw_flags | MOUSEEVENTF_MIDDLEDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut input = INPUT {
|
|
||||||
type_: INPUT_MOUSE,
|
|
||||||
u: unsafe {
|
|
||||||
transmute(MOUSEINPUT {
|
|
||||||
dx: (dx - { GetSystemMetrics(SM_XVIRTUALSCREEN) }) * 65535 / {
|
|
||||||
GetSystemMetrics(SM_CXVIRTUALSCREEN)
|
|
||||||
},
|
|
||||||
dy: (dy - { GetSystemMetrics(SM_YVIRTUALSCREEN) }) * 65535 / {
|
|
||||||
GetSystemMetrics(SM_CYVIRTUALSCREEN)
|
|
||||||
},
|
|
||||||
mouseData: 0,
|
|
||||||
dwFlags: dw_flags,
|
|
||||||
time: 0,
|
|
||||||
dwExtraInfo: 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn press(button: Button) {
|
|
||||||
let btn = Self::button_event(button, ButtonState::Press);
|
|
||||||
|
|
||||||
let dw_flags = btn;
|
|
||||||
|
|
||||||
let mut input = INPUT {
|
|
||||||
type_: INPUT_MOUSE,
|
|
||||||
u: unsafe {
|
|
||||||
transmute(MOUSEINPUT {
|
|
||||||
dx: 0,
|
|
||||||
dy: 0,
|
|
||||||
mouseData: 0,
|
|
||||||
dwFlags: dw_flags,
|
|
||||||
time: 0,
|
|
||||||
dwExtraInfo: 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release(button: Button) {
|
|
||||||
let btn = Self::button_event(button, ButtonState::Release);
|
|
||||||
|
|
||||||
let dw_flags = btn;
|
|
||||||
|
|
||||||
let mut input = INPUT {
|
|
||||||
type_: INPUT_MOUSE,
|
|
||||||
u: unsafe {
|
|
||||||
transmute(MOUSEINPUT {
|
|
||||||
dx: 0,
|
|
||||||
dy: 0,
|
|
||||||
mouseData: 0,
|
|
||||||
dwFlags: dw_flags,
|
|
||||||
time: 0,
|
|
||||||
dwExtraInfo: 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
};
|
|
||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pressed(button: Button) -> bool {
|
|
||||||
(unsafe { GetAsyncKeyState(Self::button_virtual_key(button)) } >> 15) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn button_event(button: Button, state: ButtonState) -> DWORD {
|
|
||||||
match state {
|
|
||||||
ButtonState::Press => match button {
|
|
||||||
Button::Left => MOUSEEVENTF_LEFTDOWN,
|
|
||||||
Button::Middle => MOUSEEVENTF_MIDDLEDOWN,
|
|
||||||
Button::Right => MOUSEEVENTF_RIGHTDOWN,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
},
|
|
||||||
ButtonState::Release => match button {
|
|
||||||
Button::Left => MOUSEEVENTF_LEFTUP,
|
|
||||||
Button::Middle => MOUSEEVENTF_MIDDLEUP,
|
|
||||||
Button::Right => MOUSEEVENTF_RIGHTUP,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn button_virtual_key(button: Button) -> c_int {
|
|
||||||
match button {
|
|
||||||
Button::Left => VK_LBUTTON,
|
|
||||||
Button::Middle => VK_MBUTTON,
|
|
||||||
Button::Right => VK_RBUTTON,
|
|
||||||
Button::X1 => VK_XBUTTON1,
|
|
||||||
Button::X2 => VK_XBUTTON2,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
use crate::mouse::Mouse;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn mouse_moto_to() {
|
|
||||||
Mouse::move_to(true, 500, 30);
|
|
||||||
}
|
|
||||||
}
|
|
405
src/windows/keyboard.rs
Normal file
405
src/windows/keyboard.rs
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
use crate::windows;
|
||||||
|
use crate::{Event, EventType, HookCallback, Key, Robot};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::mem::{size_of, transmute_copy};
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
use winapi::ctypes::c_int;
|
||||||
|
use winapi::shared::minwindef::{LPARAM, LRESULT, WORD, WPARAM};
|
||||||
|
use winapi::shared::windef::HHOOK;
|
||||||
|
use winapi::um::winuser::{
|
||||||
|
CallNextHookEx, GetAsyncKeyState, MapVirtualKeyW, SendInput, HC_ACTION, INPUT, INPUT_KEYBOARD,
|
||||||
|
KBDLLHOOKSTRUCT, KEYBDINPUT, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, LPINPUT, WH_KEYBOARD_LL,
|
||||||
|
WM_KEYDOWN, WM_KEYUP,
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref KEY_2_VK_MAP: HashMap<Key, WORD> = {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(Key::Digit0 , 0x30);
|
||||||
|
m.insert(Key::Digit1 , 0x31);
|
||||||
|
m.insert(Key::Digit2 , 0x32);
|
||||||
|
m.insert(Key::Digit3 , 0x33);
|
||||||
|
m.insert(Key::Digit4 , 0x34);
|
||||||
|
m.insert(Key::Digit5 , 0x35);
|
||||||
|
m.insert(Key::Digit6 , 0x36);
|
||||||
|
m.insert(Key::Digit7 , 0x37);
|
||||||
|
m.insert(Key::Digit8 , 0x38);
|
||||||
|
m.insert(Key::Digit9 , 0x39);
|
||||||
|
m.insert(Key::KeyA , 0x41);
|
||||||
|
m.insert(Key::KeyB , 0x42);
|
||||||
|
m.insert(Key::KeyC , 0x43);
|
||||||
|
m.insert(Key::KeyD , 0x44);
|
||||||
|
m.insert(Key::KeyE , 0x45);
|
||||||
|
m.insert(Key::KeyF , 0x46);
|
||||||
|
m.insert(Key::KeyG , 0x47);
|
||||||
|
m.insert(Key::KeyH , 0x48);
|
||||||
|
m.insert(Key::KeyI , 0x49);
|
||||||
|
m.insert(Key::KeyJ , 0x4A);
|
||||||
|
m.insert(Key::KeyK , 0x4B);
|
||||||
|
m.insert(Key::KeyL , 0x4C);
|
||||||
|
m.insert(Key::KeyM , 0x4D);
|
||||||
|
m.insert(Key::KeyN , 0x4E);
|
||||||
|
m.insert(Key::KeyO , 0x4F);
|
||||||
|
m.insert(Key::KeyP , 0x50);
|
||||||
|
m.insert(Key::KeyQ , 0x51);
|
||||||
|
m.insert(Key::KeyR , 0x52);
|
||||||
|
m.insert(Key::KeyS , 0x53);
|
||||||
|
m.insert(Key::KeyT , 0x54);
|
||||||
|
m.insert(Key::KeyU , 0x55);
|
||||||
|
m.insert(Key::KeyV , 0x56);
|
||||||
|
m.insert(Key::KeyW , 0x57);
|
||||||
|
m.insert(Key::KeyX , 0x58);
|
||||||
|
m.insert(Key::KeyY , 0x59);
|
||||||
|
m.insert(Key::KeyZ , 0x5A);
|
||||||
|
m.insert(Key::F1 , 0x70);
|
||||||
|
m.insert(Key::F2 , 0x71);
|
||||||
|
m.insert(Key::F3 , 0x72);
|
||||||
|
m.insert(Key::F4 , 0x73);
|
||||||
|
m.insert(Key::F5 , 0x74);
|
||||||
|
m.insert(Key::F6 , 0x75);
|
||||||
|
m.insert(Key::F7 , 0x76);
|
||||||
|
m.insert(Key::F8 , 0x77);
|
||||||
|
m.insert(Key::F9 , 0x78);
|
||||||
|
m.insert(Key::F10 , 0x79);
|
||||||
|
m.insert(Key::F11 , 0x7A);
|
||||||
|
m.insert(Key::F12 , 0x7B);
|
||||||
|
m.insert(Key::F13 , 0x7C);
|
||||||
|
m.insert(Key::F14 , 0x7D);
|
||||||
|
m.insert(Key::F15 , 0x7E);
|
||||||
|
m.insert(Key::F16 , 0x7F);
|
||||||
|
m.insert(Key::F17 , 0x80);
|
||||||
|
m.insert(Key::F18 , 0x81);
|
||||||
|
m.insert(Key::F19 , 0x82);
|
||||||
|
m.insert(Key::F20 , 0x83);
|
||||||
|
m.insert(Key::F21 , 0x84);
|
||||||
|
m.insert(Key::F22 , 0x85);
|
||||||
|
m.insert(Key::F23 , 0x86);
|
||||||
|
m.insert(Key::F24 , 0x87);
|
||||||
|
m.insert(Key::Numpad0 , 0x60);
|
||||||
|
m.insert(Key::Numpad1 , 0x61);
|
||||||
|
m.insert(Key::Numpad2 , 0x62);
|
||||||
|
m.insert(Key::Numpad3 , 0x63);
|
||||||
|
m.insert(Key::Numpad4 , 0x64);
|
||||||
|
m.insert(Key::Numpad5 , 0x65);
|
||||||
|
m.insert(Key::Numpad6 , 0x66);
|
||||||
|
m.insert(Key::Numpad7 , 0x67);
|
||||||
|
m.insert(Key::Numpad8 , 0x68);
|
||||||
|
m.insert(Key::Numpad9 , 0x69);
|
||||||
|
m.insert(Key::NumpadAdd , 0x6B); // Add
|
||||||
|
m.insert(Key::NumpadSubtract , 0x6D); // Subtract
|
||||||
|
m.insert(Key::NumpadMultiply , 0x6A); // Multiply
|
||||||
|
m.insert(Key::NumpadDivide , 0x6F); // Divide
|
||||||
|
m.insert(Key::NumpadDecimal , 0x6E); // Decimal
|
||||||
|
m.insert(Key::NumpadEqual , '=' as u16);
|
||||||
|
m.insert(Key::NumpadComma , ',' as u16);
|
||||||
|
m.insert(Key::NumpadEnter , 0x0D);
|
||||||
|
m.insert(Key::NumLock , 0x90);
|
||||||
|
m.insert(Key::Minus , '-' as u16);
|
||||||
|
m.insert(Key::Equal , '=' as u16);
|
||||||
|
m.insert(Key::BracketLeft , '{' as u16);
|
||||||
|
m.insert(Key::BracketRight , '}' as u16);
|
||||||
|
m.insert(Key::Semicolon , ';' as u16);
|
||||||
|
m.insert(Key::Quote , '\'' as u16);
|
||||||
|
m.insert(Key::Backquote , '`' as u16);
|
||||||
|
m.insert(Key::Backslash , '\\' as u16);
|
||||||
|
m.insert(Key::Comma , ',' as u16);
|
||||||
|
m.insert(Key::Period , '~' as u16);
|
||||||
|
m.insert(Key::Slash , '/' as u16);
|
||||||
|
m.insert(Key::Escape , 0x1B);
|
||||||
|
m.insert(Key::Enter , 0x0D);
|
||||||
|
m.insert(Key::Backspace , 0x08);
|
||||||
|
m.insert(Key::Tab , 0x09);
|
||||||
|
m.insert(Key::Space , 0x20);
|
||||||
|
m.insert(Key::CapsLock , 0x14);
|
||||||
|
m.insert(Key::ShiftLeft , 0xA0);
|
||||||
|
m.insert(Key::ShiftRight , 0xA1);
|
||||||
|
m.insert(Key::ControlLeft , 0xA2);
|
||||||
|
m.insert(Key::ControlRight , 0xA3);
|
||||||
|
m.insert(Key::AltLeft , 0xA4);
|
||||||
|
m.insert(Key::AltRight , 0xA5);
|
||||||
|
m.insert(Key::Pause , 0x13);
|
||||||
|
m.insert(Key::ScrollLock , 0x91);
|
||||||
|
m.insert(Key::PrintScreen , 0x2C);
|
||||||
|
m.insert(Key::ArrowLeft , 0x25);
|
||||||
|
m.insert(Key::ArrowUp , 0x26);
|
||||||
|
m.insert(Key::ArrowRight , 0x27);
|
||||||
|
m.insert(Key::ArrowDown , 0x28);
|
||||||
|
m.insert(Key::PageUp , 0x21);
|
||||||
|
m.insert(Key::PageDown , 0x22);
|
||||||
|
m.insert(Key::Home , 0x24);
|
||||||
|
m.insert(Key::End , 0x23);
|
||||||
|
m.insert(Key::Insert , 0x2D);
|
||||||
|
m.insert(Key::Delete , 0x2E);
|
||||||
|
m.insert(Key::MetaLeft , 0x5B);
|
||||||
|
m.insert(Key::MetaRight , 0x5C);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
|
||||||
|
static ref VK_2_KEY_MAP: HashMap<WORD, Key> = {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert(0x30, Key::Digit0);
|
||||||
|
m.insert(0x31, Key::Digit1);
|
||||||
|
m.insert(0x32, Key::Digit2);
|
||||||
|
m.insert(0x33, Key::Digit3);
|
||||||
|
m.insert(0x34, Key::Digit4);
|
||||||
|
m.insert(0x35, Key::Digit5);
|
||||||
|
m.insert(0x36, Key::Digit6);
|
||||||
|
m.insert(0x37, Key::Digit7);
|
||||||
|
m.insert(0x38, Key::Digit8);
|
||||||
|
m.insert(0x39, Key::Digit9);
|
||||||
|
m.insert(0x41, Key::KeyA);
|
||||||
|
m.insert(0x42, Key::KeyB);
|
||||||
|
m.insert(0x43, Key::KeyC);
|
||||||
|
m.insert(0x44, Key::KeyD);
|
||||||
|
m.insert(0x45, Key::KeyE);
|
||||||
|
m.insert(0x46, Key::KeyF);
|
||||||
|
m.insert(0x47, Key::KeyG);
|
||||||
|
m.insert(0x48, Key::KeyH);
|
||||||
|
m.insert(0x49, Key::KeyI);
|
||||||
|
m.insert(0x4A, Key::KeyJ);
|
||||||
|
m.insert(0x4B, Key::KeyK);
|
||||||
|
m.insert(0x4C, Key::KeyL);
|
||||||
|
m.insert(0x4D, Key::KeyM);
|
||||||
|
m.insert(0x4E, Key::KeyN);
|
||||||
|
m.insert(0x4F, Key::KeyO);
|
||||||
|
m.insert(0x50, Key::KeyP);
|
||||||
|
m.insert(0x51, Key::KeyQ);
|
||||||
|
m.insert(0x52, Key::KeyR);
|
||||||
|
m.insert(0x53, Key::KeyS);
|
||||||
|
m.insert(0x54, Key::KeyT);
|
||||||
|
m.insert(0x55, Key::KeyU);
|
||||||
|
m.insert(0x56, Key::KeyV);
|
||||||
|
m.insert(0x57, Key::KeyW);
|
||||||
|
m.insert(0x58, Key::KeyX);
|
||||||
|
m.insert(0x59, Key::KeyY);
|
||||||
|
m.insert(0x5A, Key::KeyZ);
|
||||||
|
m.insert(0x70, Key::F1);
|
||||||
|
m.insert(0x71, Key::F2);
|
||||||
|
m.insert(0x72, Key::F3);
|
||||||
|
m.insert(0x73, Key::F4);
|
||||||
|
m.insert(0x74, Key::F5);
|
||||||
|
m.insert(0x75, Key::F6);
|
||||||
|
m.insert(0x76, Key::F7);
|
||||||
|
m.insert(0x77, Key::F8);
|
||||||
|
m.insert(0x78, Key::F9);
|
||||||
|
m.insert(0x79, Key::F10);
|
||||||
|
m.insert(0x7A, Key::F11);
|
||||||
|
m.insert(0x7B, Key::F12);
|
||||||
|
m.insert(0x7C, Key::F13);
|
||||||
|
m.insert(0x7D, Key::F14);
|
||||||
|
m.insert(0x7E, Key::F15);
|
||||||
|
m.insert(0x7F, Key::F16);
|
||||||
|
m.insert(0x80, Key::F17);
|
||||||
|
m.insert(0x81, Key::F18);
|
||||||
|
m.insert(0x82, Key::F19);
|
||||||
|
m.insert(0x83, Key::F20);
|
||||||
|
m.insert(0x84, Key::F21);
|
||||||
|
m.insert(0x85, Key::F22);
|
||||||
|
m.insert(0x86, Key::F23);
|
||||||
|
m.insert(0x87, Key::F24);
|
||||||
|
m.insert(0x60, Key::Numpad0);
|
||||||
|
m.insert(0x61, Key::Numpad1);
|
||||||
|
m.insert(0x62, Key::Numpad2);
|
||||||
|
m.insert(0x63, Key::Numpad3);
|
||||||
|
m.insert(0x64, Key::Numpad4);
|
||||||
|
m.insert(0x65, Key::Numpad5);
|
||||||
|
m.insert(0x66, Key::Numpad6);
|
||||||
|
m.insert(0x67, Key::Numpad7);
|
||||||
|
m.insert(0x68, Key::Numpad8);
|
||||||
|
m.insert(0x69, Key::Numpad9);
|
||||||
|
m.insert(0x6B, Key::NumpadAdd); // Add
|
||||||
|
m.insert(0x6D, Key::NumpadSubtract); // Subtract
|
||||||
|
m.insert(0x6A, Key::NumpadMultiply); // Multiply
|
||||||
|
m.insert(0x6F, Key::NumpadDivide); // Divide
|
||||||
|
m.insert(0x6E, Key::NumpadDecimal); // Decimal
|
||||||
|
m.insert( 0x0D, Key::NumpadEnter);
|
||||||
|
m.insert( 0x90, Key::NumLock);
|
||||||
|
m.insert('-' as u16, Key::Minus);
|
||||||
|
m.insert('=' as u16, Key::Equal);
|
||||||
|
m.insert('{' as u16, Key::BracketLeft);
|
||||||
|
m.insert('}' as u16, Key::BracketRight);
|
||||||
|
m.insert(';' as u16, Key::Semicolon);
|
||||||
|
m.insert('\'' as u16, Key::Quote);
|
||||||
|
m.insert('`' as u16, Key::Backquote);
|
||||||
|
m.insert('\\' as u16, Key::Backslash);
|
||||||
|
m.insert(',' as u16, Key::Comma);
|
||||||
|
m.insert('~' as u16, Key::Period);
|
||||||
|
m.insert('/' as u16, Key::Slash);
|
||||||
|
m.insert(0x1B, Key::Escape);
|
||||||
|
m.insert( 0x0D, Key::Enter);
|
||||||
|
m.insert( 0x08, Key::Backspace);
|
||||||
|
m.insert( 0x09, Key::Tab);
|
||||||
|
m.insert( 0x20, Key::Space);
|
||||||
|
m.insert(0x14, Key::CapsLock);
|
||||||
|
m.insert(0xA0, Key::ShiftLeft);
|
||||||
|
m.insert(0xA1, Key::ShiftRight);
|
||||||
|
m.insert( 0xA2, Key::ControlLeft);
|
||||||
|
m.insert( 0xA3, Key::ControlRight);
|
||||||
|
m.insert( 0xA4, Key::AltLeft);
|
||||||
|
m.insert(0xA5, Key::AltRight);
|
||||||
|
m.insert(0x13, Key::Pause);
|
||||||
|
m.insert(0x91, Key::ScrollLock);
|
||||||
|
m.insert(0x2C, Key::PrintScreen);
|
||||||
|
m.insert(0x25, Key::ArrowLeft);
|
||||||
|
m.insert(0x26, Key::ArrowUp);
|
||||||
|
m.insert(0x27, Key::ArrowRight);
|
||||||
|
m.insert(0x28, Key::ArrowDown);
|
||||||
|
m.insert(0x21, Key::PageUp);
|
||||||
|
m.insert(0x22, Key::PageDown);
|
||||||
|
m.insert( 0x24, Key::Home);
|
||||||
|
m.insert( 0x23, Key::End);
|
||||||
|
m.insert(0x2D, Key::Insert);
|
||||||
|
m.insert(0x2E, Key::Delete);
|
||||||
|
m.insert(0x5B, Key::MetaLeft);
|
||||||
|
m.insert(0x5C, Key::MetaRight);
|
||||||
|
m
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_callback(event: Event) {
|
||||||
|
println!("Default : Event {:?}", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut HOOK: HHOOK = null_mut();
|
||||||
|
static mut HOOK_CALLBACK: HookCallback = default_callback;
|
||||||
|
|
||||||
|
impl Robot {
|
||||||
|
pub unsafe fn key_listen(callback: HookCallback) -> Result<(), windows::HookError> {
|
||||||
|
if HOOK.is_null() {
|
||||||
|
let r = windows::hook(WH_KEYBOARD_LL, Self::key_raw_callback);
|
||||||
|
|
||||||
|
if r.is_err() {
|
||||||
|
return Err(windows::HookError::Keyboard(r.err().unwrap()));
|
||||||
|
}
|
||||||
|
HOOK = r.ok().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
HOOK_CALLBACK = callback;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn key_unlisten() -> Result<(), windows::HookError> {
|
||||||
|
if !HOOK.is_null() {
|
||||||
|
let r = windows::unhook(HOOK);
|
||||||
|
if r.is_err() {
|
||||||
|
return Err(windows::HookError::Keyboard(r.err().unwrap()));
|
||||||
|
}
|
||||||
|
HOOK = null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
HOOK_CALLBACK = default_callback;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key_press(key: Key) {
|
||||||
|
let dw_flags = KEYEVENTF_SCANCODE;
|
||||||
|
|
||||||
|
let mut input = INPUT {
|
||||||
|
type_: INPUT_KEYBOARD,
|
||||||
|
u: unsafe {
|
||||||
|
transmute_copy(&KEYBDINPUT {
|
||||||
|
wVk: 0,
|
||||||
|
wScan: Self::key_to_scancode(key),
|
||||||
|
dwFlags: dw_flags,
|
||||||
|
time: 0,
|
||||||
|
dwExtraInfo: 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key_release(key: Key) {
|
||||||
|
let dw_flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
|
||||||
|
|
||||||
|
let mut input = INPUT {
|
||||||
|
type_: INPUT_KEYBOARD,
|
||||||
|
u: unsafe {
|
||||||
|
transmute_copy(&KEYBDINPUT {
|
||||||
|
wVk: 0,
|
||||||
|
wScan: Self::key_to_scancode(key),
|
||||||
|
dwFlags: dw_flags,
|
||||||
|
time: 0,
|
||||||
|
dwExtraInfo: 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key_pressed(key: Key) -> bool {
|
||||||
|
match Self::key_2_virtual_key(key) {
|
||||||
|
Some(vk) => (unsafe { GetAsyncKeyState(vk as i32) } >> 15) != 0,
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_to_scancode(key: Key) -> u16 {
|
||||||
|
match Self::key_2_virtual_key(key) {
|
||||||
|
Some(vk) => unsafe { MapVirtualKeyW(vk as u32, 0) as u16 },
|
||||||
|
None => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_virtual_key(lpdata: isize) -> u32 {
|
||||||
|
let kb = *(lpdata as *const KBDLLHOOKSTRUCT);
|
||||||
|
kb.vkCode
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn key_raw_callback(
|
||||||
|
code: c_int,
|
||||||
|
param: WPARAM,
|
||||||
|
lpdata: LPARAM,
|
||||||
|
) -> LRESULT {
|
||||||
|
if code == HC_ACTION {
|
||||||
|
let opt = Self::key_convert(param, lpdata);
|
||||||
|
if let Some(event_type) = opt {
|
||||||
|
let event = Event {
|
||||||
|
event_type,
|
||||||
|
time: SystemTime::now(),
|
||||||
|
};
|
||||||
|
HOOK_CALLBACK(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CallNextHookEx(HOOK, code, param, lpdata)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn key_convert(wparam: WPARAM, lparam: LPARAM) -> Option<EventType> {
|
||||||
|
match wparam.try_into() {
|
||||||
|
Ok(WM_KEYDOWN) => {
|
||||||
|
let code = Self::get_virtual_key(lparam);
|
||||||
|
match Self::virtual_key_2_key(code as u16) {
|
||||||
|
Some(k) => Some(EventType::KeyPress(k)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(WM_KEYUP) => {
|
||||||
|
let code = Self::get_virtual_key(lparam);
|
||||||
|
match Self::virtual_key_2_key(code as u16) {
|
||||||
|
Some(k) => Some(EventType::KeyRelease(k)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_2_virtual_key(key: Key) -> Option<WORD> {
|
||||||
|
match KEY_2_VK_MAP.get(&key) {
|
||||||
|
Some(v) => Some(*v),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn virtual_key_2_key(virtual_key: WORD) -> Option<Key> {
|
||||||
|
match VK_2_KEY_MAP.get(&virtual_key) {
|
||||||
|
Some(v) => Some(*v),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/windows/mod.rs
Normal file
37
src/windows/mod.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use winapi::ctypes::c_int;
|
||||||
|
use winapi::shared::minwindef::{DWORD, LPARAM, LRESULT, WPARAM};
|
||||||
|
use winapi::shared::windef::HHOOK;
|
||||||
|
use winapi::um::errhandlingapi::GetLastError;
|
||||||
|
use winapi::um::winuser::{SetWindowsHookExA, UnhookWindowsHookEx};
|
||||||
|
|
||||||
|
pub mod keyboard;
|
||||||
|
pub mod mouse;
|
||||||
|
|
||||||
|
pub type HookCallback =
|
||||||
|
unsafe extern "system" fn(code: c_int, param: WPARAM, lpdata: LPARAM) -> LRESULT;
|
||||||
|
|
||||||
|
pub enum HookError {
|
||||||
|
Mouse(DWORD),
|
||||||
|
Keyboard(DWORD),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn hook(id_hook: c_int, callback: HookCallback) -> Result<HHOOK, DWORD> {
|
||||||
|
let hook = SetWindowsHookExA(id_hook, Some(callback), null_mut(), 0);
|
||||||
|
|
||||||
|
if hook.is_null() {
|
||||||
|
let error = GetLastError();
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn unhook(hook: HHOOK) -> Result<(), DWORD> {
|
||||||
|
if hook.is_null() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
UnhookWindowsHookEx(hook);
|
||||||
|
Ok(())
|
||||||
|
}
|
213
src/windows/mouse.rs
Normal file
213
src/windows/mouse.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
use crate::windows;
|
||||||
|
use crate::{Button, Event, EventType, HookCallback, Robot};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::mem::{size_of, transmute};
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
use winapi::ctypes::c_int;
|
||||||
|
use winapi::shared::minwindef::{DWORD, LPARAM, LRESULT, WPARAM};
|
||||||
|
use winapi::shared::windef::HHOOK;
|
||||||
|
use winapi::um::winuser::{
|
||||||
|
CallNextHookEx, GetAsyncKeyState, GetSystemMetrics, SendInput, HC_ACTION, INPUT, INPUT_MOUSE,
|
||||||
|
LPINPUT, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN,
|
||||||
|
MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP,
|
||||||
|
MOUSEEVENTF_VIRTUALDESK, MOUSEINPUT, MSLLHOOKSTRUCT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN,
|
||||||
|
SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, VK_LBUTTON, VK_MBUTTON, VK_RBUTTON, VK_XBUTTON1,
|
||||||
|
VK_XBUTTON2, WH_MOUSE_LL, WM_LBUTTONDOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn default_callback(event: Event) {
|
||||||
|
println!("Default : Event {:?}", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut HOOK: HHOOK = null_mut();
|
||||||
|
static mut HOOK_CALLBACK: HookCallback = default_callback;
|
||||||
|
|
||||||
|
impl Robot {
|
||||||
|
pub unsafe fn mouse_listen(callback: HookCallback) -> Result<(), windows::HookError> {
|
||||||
|
if HOOK.is_null() {
|
||||||
|
let r = windows::hook(WH_MOUSE_LL, Self::mouse_raw_callback);
|
||||||
|
|
||||||
|
if r.is_err() {
|
||||||
|
return Err(windows::HookError::Mouse(r.err().unwrap()));
|
||||||
|
}
|
||||||
|
HOOK = r.ok().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
HOOK_CALLBACK = callback;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn mouse_unlisten() -> Result<(), windows::HookError> {
|
||||||
|
if !HOOK.is_null() {
|
||||||
|
let r = windows::unhook(HOOK);
|
||||||
|
if r.is_err() {
|
||||||
|
return Err(windows::HookError::Mouse(r.err().unwrap()));
|
||||||
|
}
|
||||||
|
HOOK = null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
HOOK_CALLBACK = default_callback;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_move_to(dx: i32, dy: i32) {
|
||||||
|
let width = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
|
||||||
|
let height = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };
|
||||||
|
if width == 0 || height == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let pressed_left = Self::mouse_pressed(Button::Left);
|
||||||
|
let pressed_right = Self::mouse_pressed(Button::Right);
|
||||||
|
let pressed_middle = Self::mouse_pressed(Button::Middle);
|
||||||
|
let mut dw_flags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
|
||||||
|
|
||||||
|
if pressed_left {
|
||||||
|
dw_flags = dw_flags | MOUSEEVENTF_LEFTDOWN;
|
||||||
|
}
|
||||||
|
if pressed_right {
|
||||||
|
dw_flags = dw_flags | MOUSEEVENTF_RIGHTDOWN;
|
||||||
|
}
|
||||||
|
if pressed_middle {
|
||||||
|
dw_flags = dw_flags | MOUSEEVENTF_MIDDLEDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut input = INPUT {
|
||||||
|
type_: INPUT_MOUSE,
|
||||||
|
u: unsafe {
|
||||||
|
transmute(MOUSEINPUT {
|
||||||
|
dx: (dx - { GetSystemMetrics(SM_XVIRTUALSCREEN) }) * 65535 / {
|
||||||
|
GetSystemMetrics(SM_CXVIRTUALSCREEN)
|
||||||
|
},
|
||||||
|
dy: (dy - { GetSystemMetrics(SM_YVIRTUALSCREEN) }) * 65535 / {
|
||||||
|
GetSystemMetrics(SM_CYVIRTUALSCREEN)
|
||||||
|
},
|
||||||
|
mouseData: 0,
|
||||||
|
dwFlags: dw_flags,
|
||||||
|
time: 0,
|
||||||
|
dwExtraInfo: 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_press(button: Button) {
|
||||||
|
let btn = Self::mouse_button_event(EventType::MousePress(button));
|
||||||
|
|
||||||
|
let dw_flags = btn;
|
||||||
|
|
||||||
|
let mut input = INPUT {
|
||||||
|
type_: INPUT_MOUSE,
|
||||||
|
u: unsafe {
|
||||||
|
transmute(MOUSEINPUT {
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
mouseData: 0,
|
||||||
|
dwFlags: dw_flags,
|
||||||
|
time: 0,
|
||||||
|
dwExtraInfo: 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_release(button: Button) {
|
||||||
|
let btn = Self::mouse_button_event(EventType::MouseRelease(button));
|
||||||
|
|
||||||
|
let dw_flags = btn;
|
||||||
|
|
||||||
|
let mut input = INPUT {
|
||||||
|
type_: INPUT_MOUSE,
|
||||||
|
u: unsafe {
|
||||||
|
transmute(MOUSEINPUT {
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
mouseData: 0,
|
||||||
|
dwFlags: dw_flags,
|
||||||
|
time: 0,
|
||||||
|
dwExtraInfo: 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_pressed(button: Button) -> bool {
|
||||||
|
(unsafe { GetAsyncKeyState(Self::mouse_button_virtual_key(button)) } >> 15) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_button_event(ev: EventType) -> DWORD {
|
||||||
|
match ev {
|
||||||
|
EventType::MousePress(button) => match button {
|
||||||
|
Button::Left => MOUSEEVENTF_LEFTDOWN,
|
||||||
|
Button::Middle => MOUSEEVENTF_MIDDLEDOWN,
|
||||||
|
Button::Right => MOUSEEVENTF_RIGHTDOWN,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
EventType::MouseRelease(button) => match button {
|
||||||
|
Button::Left => MOUSEEVENTF_LEFTUP,
|
||||||
|
Button::Middle => MOUSEEVENTF_MIDDLEUP,
|
||||||
|
Button::Right => MOUSEEVENTF_RIGHTUP,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_button_virtual_key(button: Button) -> c_int {
|
||||||
|
match button {
|
||||||
|
Button::Left => VK_LBUTTON,
|
||||||
|
Button::Middle => VK_MBUTTON,
|
||||||
|
Button::Right => VK_RBUTTON,
|
||||||
|
Button::X1 => VK_XBUTTON1,
|
||||||
|
Button::X2 => VK_XBUTTON2,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_mouse_point(lpdata: isize) -> (i32, i32) {
|
||||||
|
let mouse = *(lpdata as *const MSLLHOOKSTRUCT);
|
||||||
|
(mouse.pt.x, mouse.pt.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn mouse_raw_callback(
|
||||||
|
code: c_int,
|
||||||
|
param: WPARAM,
|
||||||
|
lpdata: LPARAM,
|
||||||
|
) -> LRESULT {
|
||||||
|
if code == HC_ACTION {
|
||||||
|
let opt = Self::mouse_convert(param, lpdata);
|
||||||
|
if let Some(event_type) = opt {
|
||||||
|
let event = Event {
|
||||||
|
event_type,
|
||||||
|
time: SystemTime::now(),
|
||||||
|
};
|
||||||
|
HOOK_CALLBACK(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CallNextHookEx(HOOK, code, param, lpdata)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn mouse_convert(wparam: WPARAM, lparam: LPARAM) -> Option<EventType> {
|
||||||
|
match wparam.try_into() {
|
||||||
|
Ok(WM_LBUTTONDOWN) => Some(EventType::MousePress(Button::Left)),
|
||||||
|
Ok(WM_LBUTTONUP) => Some(EventType::MouseRelease(Button::Left)),
|
||||||
|
Ok(WM_MBUTTONDOWN) => Some(EventType::MousePress(Button::Middle)),
|
||||||
|
Ok(WM_MBUTTONUP) => Some(EventType::MouseRelease(Button::Middle)),
|
||||||
|
Ok(WM_RBUTTONDOWN) => Some(EventType::MousePress(Button::Right)),
|
||||||
|
Ok(WM_RBUTTONUP) => Some(EventType::MouseRelease(Button::Right)),
|
||||||
|
Ok(WM_MOUSEMOVE) => {
|
||||||
|
let (x, y) = Self::get_mouse_point(lparam);
|
||||||
|
Some(EventType::MouseMoveTo {
|
||||||
|
x: x as f64,
|
||||||
|
y: y as f64,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user