236 lines
7.2 KiB
Rust
236 lines
7.2 KiB
Rust
use crate::windows;
|
|
use crate::{Button, Event, EventType, HookCallback, Robot};
|
|
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, HIWORD, LPARAM, LRESULT, WPARAM};
|
|
use winapi::shared::windef::{HHOOK__, POINT};
|
|
use winapi::um::winuser::{
|
|
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 MOUSE_HHOOK: Lazy<AtomicPtr<HHOOK__>> = Lazy::new(AtomicPtr::default);
|
|
static mut HOOK_CALLBACK: HookCallback = default_callback;
|
|
|
|
impl Robot {
|
|
pub unsafe fn mouse_listen(callback: HookCallback) -> Result<(), windows::HookError> {
|
|
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_CALLBACK = callback;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub unsafe fn mouse_unlisten() -> Result<(), windows::HookError> {
|
|
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_CALLBACK = default_callback;
|
|
|
|
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) };
|
|
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;
|
|
}
|
|
|
|
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) {
|
|
let btn = Self::mouse_button_event(EventType::MousePress(button));
|
|
|
|
let dw_flags = btn;
|
|
|
|
Self::mouse_event(0, 0, 0, dw_flags);
|
|
}
|
|
|
|
pub fn mouse_release(button: Button) {
|
|
let btn = Self::mouse_button_event(EventType::MouseRelease(button));
|
|
|
|
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,
|
|
dy,
|
|
mouseData: mouse_data,
|
|
dwFlags: dw_flags,
|
|
time: 0,
|
|
dwExtraInfo: 0,
|
|
})
|
|
},
|
|
};
|
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
unsafe extern "system" fn mouse_raw_callback(
|
|
code: c_int,
|
|
w_param: WPARAM,
|
|
l_param: LPARAM,
|
|
) -> LRESULT {
|
|
if code == HC_ACTION {
|
|
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,
|
|
};
|
|
|
|
println!("mouse {:?}", opt);
|
|
|
|
if let Some(event_type) = opt {
|
|
let event = Event {
|
|
event_type,
|
|
time: SystemTime::now(),
|
|
};
|
|
|
|
HOOK_CALLBACK(event);
|
|
}
|
|
}
|
|
CallNextHookEx(null_mut(), code, w_param, l_param)
|
|
}
|
|
}
|