diff --git a/Cargo.toml b/Cargo.toml index daeb4dac..401b5633 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,13 @@ epoll = {version = "4.1.0", optional=true} inotify = {version = "0.8.2", default-features=false, optional=true} [target.'cfg(target_os = "windows")'.dependencies] -winapi = { version = "0.3", features = ["winuser", "errhandlingapi", "processthreadsapi"] } +windows-sys = { version = "0.45.0", features = [ + "Win32_UI_WindowsAndMessaging", + "Win32_Foundation", + "Win32_System_Threading", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_TextServices" +] } [dev-dependencies] serde_json = "1.0" diff --git a/src/windows/common.rs b/src/windows/common.rs index a7579c52..b613585f 100644 --- a/src/windows/common.rs +++ b/src/windows/common.rs @@ -1,25 +1,30 @@ use crate::rdev::{Button, EventType}; use crate::windows::keyboard::Keyboard; use crate::windows::keycodes::key_from_code; +use crate::windows::{DWORD, LONG, WORD}; use lazy_static::lazy_static; use std::convert::TryInto; -use std::os::raw::{c_int, c_short}; -use std::ptr::null_mut; +use std::os::raw::c_int; use std::sync::Mutex; -use winapi::shared::minwindef::{DWORD, HIWORD, LPARAM, LRESULT, WORD, WPARAM}; -use winapi::shared::ntdef::LONG; -use winapi::shared::windef::HHOOK; -use winapi::um::errhandlingapi::GetLastError; -use winapi::um::winuser::{ +use windows_sys::Win32::Foundation::{GetLastError, WPARAM}; +use windows_sys::Win32::Foundation::{HINSTANCE, LPARAM, LRESULT}; +use windows_sys::Win32::UI::WindowsAndMessaging::HHOOK; +use windows_sys::Win32::UI::WindowsAndMessaging::{ SetWindowsHookExA, KBDLLHOOKSTRUCT, MSLLHOOKSTRUCT, WHEEL_DELTA, WH_KEYBOARD_LL, WH_MOUSE_LL, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_XBUTTONDOWN, WM_XBUTTONUP, }; + pub const TRUE: i32 = 1; pub const FALSE: i32 = 0; -pub static mut HOOK: HHOOK = null_mut(); +#[inline] +fn hiword(l: u32) -> u16 { + ((l >> 16) & 0xffff) as u16 +} + +pub static mut HOOK: HHOOK = 0; lazy_static! { pub(crate) static ref KEYBOARD: Mutex = Mutex::new(Keyboard::new().unwrap()); } @@ -28,24 +33,28 @@ pub unsafe fn get_code(lpdata: LPARAM) -> DWORD { let kb = *(lpdata as *const KBDLLHOOKSTRUCT); kb.vkCode } + pub unsafe fn get_scan_code(lpdata: LPARAM) -> DWORD { let kb = *(lpdata as *const KBDLLHOOKSTRUCT); kb.scanCode } + pub unsafe fn get_point(lpdata: LPARAM) -> (LONG, LONG) { let mouse = *(lpdata as *const MSLLHOOKSTRUCT); (mouse.pt.x, mouse.pt.y) } + // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644986(v=vs.85) /// confusingly, this function returns a WORD (unsigned), but may be /// interpreted as either signed or unsigned depending on context pub unsafe fn get_delta(lpdata: LPARAM) -> WORD { let mouse = *(lpdata as *const MSLLHOOKSTRUCT); - HIWORD(mouse.mouseData) + hiword(mouse.mouseData) } + pub unsafe fn get_button_code(lpdata: LPARAM) -> WORD { let mouse = *(lpdata as *const MSLLHOOKSTRUCT); - HIWORD(mouse.mouseData) + hiword(mouse.mouseData) } pub unsafe fn convert(param: WPARAM, lpdata: LPARAM) -> Option { @@ -82,16 +91,16 @@ pub unsafe fn convert(param: WPARAM, lpdata: LPARAM) -> Option { }) } Ok(WM_MOUSEWHEEL) => { - let delta = get_delta(lpdata) as c_short; + let delta = get_delta(lpdata); Some(EventType::Wheel { delta_x: 0, - delta_y: (delta / WHEEL_DELTA) as i64, + delta_y: (delta / hiword(WHEEL_DELTA)) as i64, }) } Ok(WM_MOUSEHWHEEL) => { - let delta = get_delta(lpdata) as c_short; + let delta = get_delta(lpdata); Some(EventType::Wheel { - delta_x: (delta / WHEEL_DELTA) as i64, + delta_x: (delta / hiword(WHEEL_DELTA)) as i64, delta_y: 0, }) } @@ -100,15 +109,17 @@ pub unsafe fn convert(param: WPARAM, lpdata: LPARAM) -> Option { } type RawCallback = unsafe extern "system" fn(code: c_int, param: WPARAM, lpdata: LPARAM) -> LRESULT; + pub enum HookError { Mouse(DWORD), Key(DWORD), } pub unsafe fn set_key_hook(callback: RawCallback) -> Result<(), HookError> { - let hook = SetWindowsHookExA(WH_KEYBOARD_LL, Some(callback), null_mut(), 0); + let hmod: HINSTANCE = 0; + let hook = SetWindowsHookExA(WH_KEYBOARD_LL, Some(callback), hmod, 0); - if hook.is_null() { + if hook == 0 { let error = GetLastError(); return Err(HookError::Key(error)); } @@ -117,8 +128,9 @@ pub unsafe fn set_key_hook(callback: RawCallback) -> Result<(), HookError> { } pub unsafe fn set_mouse_hook(callback: RawCallback) -> Result<(), HookError> { - let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(callback), null_mut(), 0); - if hook.is_null() { + let hmod: HINSTANCE = 0; + let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(callback), hmod, 0); + if hook == 0 { let error = GetLastError(); return Err(HookError::Mouse(error)); } diff --git a/src/windows/display.rs b/src/windows/display.rs index c7db82f6..3ab721c6 100644 --- a/src/windows/display.rs +++ b/src/windows/display.rs @@ -1,6 +1,6 @@ use crate::rdev::DisplayError; use std::convert::TryInto; -use winapi::um::winuser::{GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN}; +use windows_sys::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN}; pub fn display_size() -> Result<(u64, u64), DisplayError> { let w = unsafe { diff --git a/src/windows/grab.rs b/src/windows/grab.rs index cd1930f2..ffa2aa47 100644 --- a/src/windows/grab.rs +++ b/src/windows/grab.rs @@ -2,12 +2,13 @@ use crate::rdev::{Event, EventType, GrabError}; use crate::windows::common::{convert, set_key_hook, set_mouse_hook, HookError, HOOK, KEYBOARD}; use std::ptr::null_mut; use std::time::SystemTime; -use winapi::um::winuser::{CallNextHookEx, GetMessageA, HC_ACTION}; +use windows_sys::Win32::Foundation::HWND; +use windows_sys::Win32::UI::WindowsAndMessaging::{CallNextHookEx, GetMessageA, HC_ACTION}; static mut GLOBAL_CALLBACK: Option Option>> = None; unsafe extern "system" fn raw_callback(code: i32, param: usize, lpdata: isize) -> isize { - if code == HC_ACTION { + if code == HC_ACTION as i32 { let opt = convert(param, lpdata); if let Some(event_type) = opt { let name = match &event_type { @@ -48,12 +49,13 @@ pub fn grab(callback: T) -> Result<(), GrabError> where T: FnMut(Event) -> Option + 'static, { + let hwnd: HWND = 0; unsafe { GLOBAL_CALLBACK = Some(Box::new(callback)); set_key_hook(raw_callback)?; set_mouse_hook(raw_callback)?; - GetMessageA(null_mut(), null_mut(), 0, 0); + GetMessageA(null_mut(), hwnd, 0, 0); } Ok(()) } diff --git a/src/windows/keyboard.rs b/src/windows/keyboard.rs index 7eeb2753..82bea963 100644 --- a/src/windows/keyboard.rs +++ b/src/windows/keyboard.rs @@ -2,13 +2,14 @@ use crate::rdev::{EventType, Key, KeyboardState}; use crate::windows::common::{get_code, get_scan_code, FALSE, TRUE}; use crate::windows::keycodes::code_from_key; use std::ptr::null_mut; -use winapi::shared::minwindef::{BYTE, HKL, LPARAM, UINT}; -use winapi::um::processthreadsapi::GetCurrentThreadId; -use winapi::um::winuser; -use winapi::um::winuser::{ - GetForegroundWindow, GetKeyState, GetKeyboardLayout, GetKeyboardState, - GetWindowThreadProcessId, ToUnicodeEx, VK_CAPITAL, VK_LSHIFT, VK_RSHIFT, VK_SHIFT, +use windows_sys::Win32::Foundation::LPARAM; +use windows_sys::Win32::System::Threading::{AttachThreadInput, GetCurrentThreadId}; +use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ + GetKeyState, GetKeyboardLayout, GetKeyboardState, ToUnicodeEx, VK_CAPITAL, VK_LSHIFT, + VK_RSHIFT, VK_SHIFT, }; +use windows_sys::Win32::UI::TextServices::HKL; +use windows_sys::Win32::UI::WindowsAndMessaging::{GetForegroundWindow, GetWindowThreadProcessId}; const VK_SHIFT_: usize = VK_SHIFT as usize; const VK_CAPITAL_: usize = VK_CAPITAL as usize; @@ -16,6 +17,9 @@ const VK_LSHIFT_: usize = VK_LSHIFT as usize; const VK_RSHIFT_: usize = VK_RSHIFT as usize; const HIGHBIT: u8 = 0x80; +pub type UINT = u32; +pub type BYTE = u8; + pub struct Keyboard { last_code: UINT, last_scan_code: UINT, @@ -47,16 +51,16 @@ impl Keyboard { let mut state = [0_u8; 256]; let state_ptr = state.as_mut_ptr(); - let _shift = GetKeyState(VK_SHIFT); + let _shift = GetKeyState(VK_SHIFT as i32); let current_window_thread_id = GetWindowThreadProcessId(GetForegroundWindow(), null_mut()); let thread_id = GetCurrentThreadId(); // Attach to active thread so we can get that keyboard state - let status = if winuser::AttachThreadInput(thread_id, current_window_thread_id, TRUE) == 1 { + let status = if AttachThreadInput(thread_id, current_window_thread_id, TRUE) == 1 { // Current state of the modifiers in keyboard let status = GetKeyboardState(state_ptr); // Detach - winuser::AttachThreadInput(thread_id, current_window_thread_id, FALSE); + AttachThreadInput(thread_id, current_window_thread_id, FALSE); status } else { // Could not attach, perhaps it is this process? diff --git a/src/windows/keycodes.rs b/src/windows/keycodes.rs index c3707f76..e3a8627f 100644 --- a/src/windows/keycodes.rs +++ b/src/windows/keycodes.rs @@ -1,6 +1,6 @@ use crate::rdev::Key; +use crate::windows::WORD; use std::convert::TryInto; -use winapi::shared::minwindef::WORD; macro_rules! decl_keycodes { ($($key:ident, $code:literal),*) => { diff --git a/src/windows/listen.rs b/src/windows/listen.rs index bff00d2c..e240c684 100644 --- a/src/windows/listen.rs +++ b/src/windows/listen.rs @@ -3,8 +3,8 @@ use crate::windows::common::{convert, set_key_hook, set_mouse_hook, HookError, H use std::os::raw::c_int; use std::ptr::null_mut; use std::time::SystemTime; -use winapi::shared::minwindef::{LPARAM, LRESULT, WPARAM}; -use winapi::um::winuser::{CallNextHookEx, GetMessageA, HC_ACTION}; +use windows_sys::Win32::Foundation::{LPARAM, LRESULT, WPARAM}; +use windows_sys::Win32::UI::WindowsAndMessaging::{CallNextHookEx, GetMessageA, HC_ACTION}; static mut GLOBAL_CALLBACK: Option> = None; @@ -18,7 +18,7 @@ impl From for ListenError { } unsafe extern "system" fn raw_callback(code: c_int, param: WPARAM, lpdata: LPARAM) -> LRESULT { - if code == HC_ACTION { + if code == HC_ACTION as i32 { let opt = convert(param, lpdata); if let Some(event_type) = opt { let name = match &event_type { @@ -50,7 +50,7 @@ where set_key_hook(raw_callback)?; set_mouse_hook(raw_callback)?; - GetMessageA(null_mut(), null_mut(), 0, 0); + GetMessageA(null_mut(), 0, 0, 0); } Ok(()) } diff --git a/src/windows/mod.rs b/src/windows/mod.rs index 8ef404f3..6f8d7622 100644 --- a/src/windows/mod.rs +++ b/src/windows/mod.rs @@ -1,5 +1,3 @@ -extern crate winapi; - mod common; mod display; #[cfg(feature = "unstable_grab")] @@ -15,3 +13,8 @@ pub use crate::windows::grab::grab; pub use crate::windows::keyboard::Keyboard; pub use crate::windows::listen::listen; pub use crate::windows::simulate::simulate; + +// types not defined by windows-sys +pub type DWORD = u32; +pub type WORD = u16; +pub type LONG = i32; diff --git a/src/windows/simulate.rs b/src/windows/simulate.rs index cd62e220..8d449d7d 100644 --- a/src/windows/simulate.rs +++ b/src/windows/simulate.rs @@ -1,24 +1,28 @@ use crate::rdev::{Button, EventType, SimulateError}; use crate::windows::keycodes::code_from_key; use std::convert::TryFrom; +use std::ffi::c_int; use std::mem::size_of; -use winapi::ctypes::{c_int, c_short}; -use winapi::shared::minwindef::{DWORD, UINT, WORD}; -use winapi::shared::ntdef::LONG; -use winapi::um::winuser::{ - GetSystemMetrics, INPUT_u, SendInput, INPUT, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, - KEYEVENTF_KEYUP, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, - MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, - MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK, MOUSEEVENTF_WHEEL, - MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, - WHEEL_DELTA, +use windows_sys::Win32::UI::WindowsAndMessaging::{ + GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, WHEEL_DELTA, }; + +use crate::windows::keyboard::UINT; +use crate::windows::{DWORD, LONG, WORD}; +use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ + SendInput, INPUT, INPUT_0, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, KEYEVENTF_KEYUP, + MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, + MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, + MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK, MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, + MOUSEEVENTF_XUP, MOUSEINPUT, +}; + /// Not defined in win32 but define here for clarity -static KEYEVENTF_KEYDOWN: DWORD = 0; +static KEYEVENTF_KEYDOWN: u32 = 0; -fn sim_mouse_event(flags: DWORD, data: DWORD, dx: LONG, dy: LONG) -> Result<(), SimulateError> { - let mut union: INPUT_u = unsafe { std::mem::zeroed() }; - let inner_union = unsafe { union.mi_mut() }; +fn sim_mouse_event(flags: DWORD, data: LONG, dx: LONG, dy: LONG) -> Result<(), SimulateError> { + let mut union: INPUT_0 = unsafe { std::mem::zeroed() }; + let inner_union = unsafe { &mut union.mi }; *inner_union = MOUSEINPUT { dx, dy, @@ -28,8 +32,8 @@ fn sim_mouse_event(flags: DWORD, data: DWORD, dx: LONG, dy: LONG) -> Result<(), dwExtraInfo: 0, }; let mut input = [INPUT { - type_: INPUT_MOUSE, - u: union, + r#type: INPUT_MOUSE, + Anonymous: union, }; 1]; let value = unsafe { SendInput( @@ -46,8 +50,8 @@ fn sim_mouse_event(flags: DWORD, data: DWORD, dx: LONG, dy: LONG) -> Result<(), } fn sim_keyboard_event(flags: DWORD, vk: WORD, scan: WORD) -> Result<(), SimulateError> { - let mut union: INPUT_u = unsafe { std::mem::zeroed() }; - let inner_union = unsafe { union.ki_mut() }; + let mut union: INPUT_0 = unsafe { std::mem::zeroed() }; + let inner_union = unsafe { &mut union.ki }; *inner_union = KEYBDINPUT { wVk: vk, wScan: scan, @@ -56,8 +60,8 @@ fn sim_keyboard_event(flags: DWORD, vk: WORD, scan: WORD) -> Result<(), Simulate dwExtraInfo: 0, }; let mut input = [INPUT { - type_: INPUT_KEYBOARD, - u: union, + r#type: INPUT_KEYBOARD, + Anonymous: union, }; 1]; let value = unsafe { SendInput( @@ -99,7 +103,7 @@ pub fn simulate(event_type: &EventType) -> Result<(), SimulateError> { if *delta_x != 0 { sim_mouse_event( MOUSEEVENTF_HWHEEL, - (c_short::try_from(*delta_x).map_err(|_| SimulateError)? * WHEEL_DELTA) as u32, + (u32::try_from(*delta_x).map_err(|_| SimulateError)? * WHEEL_DELTA) as LONG, 0, 0, )?; @@ -108,7 +112,7 @@ pub fn simulate(event_type: &EventType) -> Result<(), SimulateError> { if *delta_y != 0 { sim_mouse_event( MOUSEEVENTF_WHEEL, - (c_short::try_from(*delta_y).map_err(|_| SimulateError)? * WHEEL_DELTA) as u32, + (u32::try_from(*delta_y).map_err(|_| SimulateError)? * WHEEL_DELTA) as LONG, 0, 0, )?;