2020-12-16 04:18:01 +09:00

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)
}
}