use std::ptr::null_mut;
use windows_sys::Win32::Foundation::{GetLastError, LPARAM, LRESULT, WPARAM};
use windows_sys::Win32::UI::WindowsAndMessaging::{
CallNextHookEx, GetMessageA, HC_ACTION, MSLLHOOKSTRUCT, SetWindowsHookExA, WH_MOUSE_LL,
WM_MOUSEMOVE,
};
use crate::{GLOBAL_CALLBACK, ListenError, MouseMoveEvent};
unsafe extern "system" fn raw_callback(code: i32, param: WPARAM, lpdata: LPARAM) -> LRESULT {
if code == HC_ACTION as i32 && param as u32 == WM_MOUSEMOVE {
let mouse = unsafe { *(lpdata as *const MSLLHOOKSTRUCT) };
let event = MouseMoveEvent {
x: mouse.pt.x as f64,
y: mouse.pt.y as f64,
};
GLOBAL_CALLBACK.with(|cell| {
if let Some(callback) = cell.borrow_mut().as_mut() {
callback(event);
}
});
}
unsafe { CallNextHookEx(null_mut(), code, param, lpdata) }
}
pub fn listen<T>(callback: T) -> Result<(), ListenError>
where
T: FnMut(MouseMoveEvent) + 'static,
{
GLOBAL_CALLBACK.with(|cell| {
*cell.borrow_mut() = Some(Box::new(callback));
});
unsafe {
let hook = SetWindowsHookExA(WH_MOUSE_LL, Some(raw_callback), null_mut(), 0);
if hook.is_null() {
let e = GetLastError();
return Err(ListenError::WHMouseHook(e));
}
GetMessageA(null_mut(), null_mut(), 0, 0);
}
Ok(())
}