global-mousemove 0.1.1

A minimal library to listen for global mousemove events.
Documentation
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(())
}