diff --git a/Cargo.toml b/Cargo.toml index 9b575aa..4a31c70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] serde = { version = "1.0.117", optional = true } serde_derive = { version = "1.0.117", optional = true } -lazy_static = "1.4.0" +once_cell = "1.5.2" [features] with_serde = ["serde", "serde_derive"] diff --git a/src/windows/keyboard.rs b/src/windows/keyboard.rs index 09ce404..c8c287a 100644 --- a/src/windows/keyboard.rs +++ b/src/windows/keyboard.rs @@ -1,280 +1,277 @@ use crate::windows; use crate::{Event, EventType, HookCallback, Key, Robot}; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use std::collections::HashMap; -use std::convert::TryInto; use std::mem::{size_of, transmute_copy}; use std::ptr::null_mut; +use std::sync::atomic::{AtomicPtr, Ordering}; use std::time::SystemTime; use winapi::ctypes::c_int; use winapi::shared::minwindef::{LPARAM, LRESULT, WORD, WPARAM}; -use winapi::shared::windef::HHOOK; +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, + CallNextHookEx, GetAsyncKeyState, GetKeyState, 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 = { - 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 KEY_2_VK_MAP: Lazy> = Lazy::new(|| { + 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 = { - 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 - }; -} +static VK_2_KEY_MAP: Lazy> = Lazy::new(|| { + 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 KEYBOARD_HHOOK: Lazy> = Lazy::new(AtomicPtr::default); 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 KEYBOARD_HHOOK.load(Ordering::Relaxed).is_null() { + let r = windows::hook(WH_KEYBOARD_LL, &*KEYBOARD_HHOOK, Self::key_raw_callback); if r.is_err() { return Err(windows::HookError::Keyboard(r.err().unwrap())); } - HOOK = r.ok().unwrap(); } HOOK_CALLBACK = callback; @@ -283,12 +280,11 @@ impl Robot { } pub unsafe fn key_unlisten() -> Result<(), windows::HookError> { - if !HOOK.is_null() { - let r = windows::unhook(HOOK); + if !KEYBOARD_HHOOK.load(Ordering::Relaxed).is_null() { + let r = windows::unhook(&*KEYBOARD_HHOOK); if r.is_err() { return Err(windows::HookError::Keyboard(r.err().unwrap())); } - HOOK = null_mut(); } HOOK_CALLBACK = default_callback; @@ -299,37 +295,13 @@ impl Robot { 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::() as c_int) }; + Self::keyboard_event(0, Self::key_to_scancode(key), dw_flags); } 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::() as c_int) }; + Self::keyboard_event(0, Self::key_to_scancode(key), dw_flags); } pub fn key_pressed(key: Key) -> bool { @@ -339,6 +311,29 @@ impl Robot { } } + pub fn key_toggled(key: Key) -> bool { + match Self::key_2_virtual_key(key) { + Some(vk) => (unsafe { GetKeyState(vk as i32) & 15 != 0 }), + None => false, + } + } + + fn keyboard_event(vk: u16, scan: u16, dw_flags: u32) { + let mut input = INPUT { + type_: INPUT_KEYBOARD, + u: unsafe { + transmute_copy(&KEYBDINPUT { + wVk: vk, + wScan: scan, + dwFlags: dw_flags, + time: 0, + dwExtraInfo: 0, + }) + }, + }; + unsafe { SendInput(1, &mut input as LPINPUT, size_of::() as c_int) }; + } + fn key_to_scancode(key: Key) -> u16 { match Self::key_2_virtual_key(key) { Some(vk) => unsafe { MapVirtualKeyW(vk as u32, 0) as u16 }, @@ -353,11 +348,28 @@ impl Robot { unsafe extern "system" fn key_raw_callback( code: c_int, - param: WPARAM, - lpdata: LPARAM, + w_param: WPARAM, + l_param: LPARAM, ) -> LRESULT { if code == HC_ACTION { - let opt = Self::key_convert(param, lpdata); + let opt = match w_param as u32 { + WM_KEYDOWN => { + let code = Self::get_virtual_key(l_param); + match Self::virtual_key_2_key(code as u16) { + Some(k) => Some(EventType::KeyPress(k)), + None => None, + } + } + WM_KEYUP => { + let code = Self::get_virtual_key(l_param); + match Self::virtual_key_2_key(code as u16) { + Some(k) => Some(EventType::KeyRelease(k)), + None => None, + } + } + _ => None, + }; + if let Some(event_type) = opt { let event = Event { event_type, @@ -366,27 +378,7 @@ impl Robot { HOOK_CALLBACK(event); } } - CallNextHookEx(HOOK, code, param, lpdata) - } - - unsafe fn key_convert(wparam: WPARAM, lparam: LPARAM) -> Option { - 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, - } + CallNextHookEx(null_mut(), code, w_param, l_param) } fn key_2_virtual_key(key: Key) -> Option { diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 32a378b..eccf620 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -1,10 +1,10 @@ use std::ptr::null_mut; +use std::sync::atomic::{AtomicPtr, Ordering}; use winapi::ctypes::c_int; -use winapi::shared::minwindef::{DWORD, LPARAM, LRESULT, WPARAM}; -use winapi::shared::windef::HHOOK; +use winapi::shared::minwindef::{DWORD, HINSTANCE, LPARAM, LRESULT, WPARAM}; +use winapi::shared::windef::HHOOK__; use winapi::um::errhandlingapi::GetLastError; -use winapi::um::winuser::{SetWindowsHookExA, UnhookWindowsHookEx}; - +use winapi::um::winuser::{SetWindowsHookExW, UnhookWindowsHookEx}; pub mod keyboard; pub mod mouse; @@ -16,22 +16,28 @@ pub enum HookError { Keyboard(DWORD), } -pub unsafe fn hook(id_hook: c_int, callback: HookCallback) -> Result { - let hook = SetWindowsHookExA(id_hook, Some(callback), null_mut(), 0); +pub unsafe fn hook( + hook_id: c_int, + hook_ptr: &AtomicPtr, + callback: HookCallback, +) -> Result<(), DWORD> { + hook_ptr.store( + SetWindowsHookExW(hook_id, Some(callback), 0 as HINSTANCE, 0), + Ordering::Relaxed, + ); - if hook.is_null() { + if hook_ptr.load(Ordering::Relaxed).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(()) +} + +pub unsafe fn unhook(hook_ptr: &AtomicPtr) -> Result<(), DWORD> { + if !hook_ptr.load(Ordering::Relaxed).is_null() { + UnhookWindowsHookEx(hook_ptr.load(Ordering::Relaxed)); + hook_ptr.store(null_mut(), Ordering::Relaxed); + } Ok(()) } diff --git a/src/windows/mouse.rs b/src/windows/mouse.rs index dc9b4b6..fac6b6d 100644 --- a/src/windows/mouse.rs +++ b/src/windows/mouse.rs @@ -1,37 +1,39 @@ use crate::windows; use crate::{Button, Event, EventType, HookCallback, Robot}; -use std::convert::TryInto; +use once_cell::sync::Lazy; use std::mem::{size_of, transmute}; use std::ptr::null_mut; +use std::sync::atomic::{AtomicPtr, Ordering}; use std::time::SystemTime; use winapi::ctypes::c_int; -use winapi::shared::minwindef::{DWORD, LPARAM, LRESULT, WPARAM}; -use winapi::shared::windef::HHOOK; +use winapi::shared::minwindef::{DWORD, HIWORD, LPARAM, LRESULT, WPARAM}; +use winapi::shared::windef::{HHOOK__, POINT}; 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, + CallNextHookEx, GetAsyncKeyState, GetCursorPos, GetSystemMetrics, SendInput, HC_ACTION, INPUT, + INPUT_MOUSE, LPINPUT, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, + MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, + MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK, MOUSEEVENTF_WHEEL, + 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, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_RBUTTONDOWN, + WM_RBUTTONUP, WM_XBUTTONDOWN, WM_XBUTTONUP, XBUTTON1, XBUTTON2, }; fn default_callback(event: Event) { println!("Default : Event {:?}", event); } -static mut HOOK: HHOOK = null_mut(); +static MOUSE_HHOOK: Lazy> = Lazy::new(AtomicPtr::default); 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 MOUSE_HHOOK.load(Ordering::Relaxed).is_null() { + let r = windows::hook(WH_MOUSE_LL, &*MOUSE_HHOOK, Self::mouse_raw_callback); if r.is_err() { return Err(windows::HookError::Mouse(r.err().unwrap())); } - HOOK = r.ok().unwrap(); } HOOK_CALLBACK = callback; @@ -40,12 +42,11 @@ impl Robot { } pub unsafe fn mouse_unlisten() -> Result<(), windows::HookError> { - if !HOOK.is_null() { - let r = windows::unhook(HOOK); + if !MOUSE_HHOOK.load(Ordering::Relaxed).is_null() { + let r = windows::unhook(&*MOUSE_HHOOK); if r.is_err() { return Err(windows::HookError::Mouse(r.err().unwrap())); } - HOOK = null_mut(); } HOOK_CALLBACK = default_callback; @@ -53,6 +54,17 @@ impl Robot { Ok(()) } + 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) + } + } + pub fn mouse_move_to(dx: i32, dy: i32) { let width = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) }; let height = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) }; @@ -74,24 +86,14 @@ impl Robot { 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::() as c_int) }; + Self::mouse_event( + (dx - unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) }) * 65535 + / unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) }, + (dy - unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) }) * 65535 + / unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) }, + 0, + dw_flags, + ); } pub fn mouse_press(button: Button) { @@ -99,20 +101,7 @@ impl Robot { 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::() as c_int) }; + Self::mouse_event(0, 0, 0, dw_flags); } pub fn mouse_release(button: Button) { @@ -120,13 +109,31 @@ impl Robot { let dw_flags = btn; + Self::mouse_event(0, 0, 0, dw_flags); + } + + pub fn mouse_pressed(button: Button) -> bool { + (unsafe { GetAsyncKeyState(Self::mouse_button_virtual_key(button)) } >> 15) != 0 + } + + pub fn mouse_wheel_x(length: i32) { + let dw_flags = MOUSEEVENTF_HWHEEL; + Self::mouse_event(0, 0, unsafe { transmute(length * 120) }, dw_flags); + } + + pub fn mouse_wheel_y(length: i32) { + let dw_flags = MOUSEEVENTF_WHEEL; + Self::mouse_event(0, 0, unsafe { transmute(length * 120) }, dw_flags); + } + + fn mouse_event(dx: i32, dy: i32, mouse_data: u32, dw_flags: u32) { let mut input = INPUT { type_: INPUT_MOUSE, u: unsafe { transmute(MOUSEINPUT { - dx: 0, - dy: 0, - mouseData: 0, + dx, + dy, + mouseData: mouse_data, dwFlags: dw_flags, time: 0, dwExtraInfo: 0, @@ -136,10 +143,6 @@ impl Robot { unsafe { SendInput(1, &mut input as LPINPUT, size_of::() 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 { @@ -174,13 +177,47 @@ impl Robot { (mouse.pt.x, mouse.pt.y) } + #[allow(non_snake_case)] unsafe extern "system" fn mouse_raw_callback( code: c_int, - param: WPARAM, - lpdata: LPARAM, + w_param: WPARAM, + l_param: LPARAM, ) -> LRESULT { if code == HC_ACTION { - let opt = Self::mouse_convert(param, lpdata); + let opt = match w_param as u32 { + WM_LBUTTONDOWN => Some(EventType::MousePress(Button::Left)), + WM_LBUTTONUP => Some(EventType::MouseRelease(Button::Left)), + WM_MBUTTONDOWN => Some(EventType::MousePress(Button::Middle)), + WM_MBUTTONUP => Some(EventType::MouseRelease(Button::Middle)), + WM_RBUTTONDOWN => Some(EventType::MousePress(Button::Right)), + WM_RBUTTONUP => Some(EventType::MouseRelease(Button::Right)), + WM_XBUTTONDOWN => { + let llhs = &*(l_param as *const MSLLHOOKSTRUCT); + + match HIWORD(llhs.mouseData) { + XBUTTON1 => Some(EventType::MousePress(Button::X1)), + XBUTTON2 => Some(EventType::MousePress(Button::X2)), + _ => None, + } + } + WM_XBUTTONUP => { + let llhs = &*(l_param as *const MSLLHOOKSTRUCT); + + match HIWORD(llhs.mouseData) { + XBUTTON1 => Some(EventType::MouseRelease(Button::X1)), + XBUTTON2 => Some(EventType::MouseRelease(Button::X2)), + _ => None, + } + } + WM_MOUSEMOVE => { + let (x, y) = Self::get_mouse_point(l_param); + Some(EventType::MouseMoveTo { + x: x as f64, + y: y as f64, + }) + } + _ => None, + }; if let Some(event_type) = opt { let event = Event { event_type, @@ -189,25 +226,6 @@ impl Robot { HOOK_CALLBACK(event); } } - CallNextHookEx(HOOK, code, param, lpdata) - } - - unsafe fn mouse_convert(wparam: WPARAM, lparam: LPARAM) -> Option { - 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, - } + CallNextHookEx(null_mut(), code, w_param, l_param) } }