use windows::Win32::Foundation::{HWND, LPARAM, WPARAM};
use windows::Win32::UI::WindowsAndMessaging::{
PostMessageW, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP,
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL,
};
#[inline]
pub fn make_lparam(x: i32, y: i32) -> LPARAM {
LPARAM(((y as u32) << 16 | (x as u32 & 0xFFFF)) as isize)
}
#[inline]
pub fn post_click_left_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_LBUTTONDOWN, WPARAM(1), lparam);
let _ = PostMessageW(Some(hwnd), WM_LBUTTONUP, WPARAM(0), lparam);
}
}
#[inline]
pub fn post_click_right_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_RBUTTONDOWN, WPARAM(1), lparam);
let _ = PostMessageW(Some(hwnd), WM_RBUTTONUP, WPARAM(0), lparam);
}
}
#[inline]
pub fn post_click_middle_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_MBUTTONDOWN, WPARAM(1), lparam);
let _ = PostMessageW(Some(hwnd), WM_MBUTTONUP, WPARAM(0), lparam);
}
}
#[inline]
pub fn post_press_left_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_LBUTTONDOWN, WPARAM(1), lparam);
}
}
#[inline]
pub fn post_release_left_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_LBUTTONUP, WPARAM(0), lparam);
}
}
#[inline]
pub fn post_move_atomic(hwnd: HWND, x: i32, y: i32) {
let lparam = make_lparam(x, y);
unsafe {
let _ = PostMessageW(Some(hwnd), WM_MOUSEMOVE, WPARAM(0), lparam);
}
}
#[inline]
pub fn post_scroll_up_atomic(hwnd: HWND, x: i32, y: i32, delta: i32) {
let lparam = make_lparam(x, y);
let wparam = ((delta as u32) << 16) as usize;
unsafe {
let _ = PostMessageW(Some(hwnd), WM_MOUSEWHEEL, WPARAM(wparam), lparam);
}
}
#[inline]
pub fn post_scroll_down_atomic(hwnd: HWND, x: i32, y: i32, delta: i32) {
post_scroll_up_atomic(hwnd, x, y, -delta)
}
#[derive(Debug)]
pub enum PostMessageMouseError {
InvalidWindow,
SendMessageFailed,
}
impl std::fmt::Display for PostMessageMouseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PostMessageMouseError::InvalidWindow => write!(f, "Invalid window handle"),
PostMessageMouseError::SendMessageFailed => write!(f, "Failed to send message"),
}
}
}
impl std::error::Error for PostMessageMouseError {}
pub struct PostMessageMouse {
hwnd: HWND,
}
impl PostMessageMouse {
pub fn new(hwnd: HWND) -> Self {
Self { hwnd }
}
pub fn hwnd(&self) -> HWND {
self.hwnd
}
pub fn click_left(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_click_left_atomic(self.hwnd, x, y);
Ok(())
}
pub fn click_right(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_click_right_atomic(self.hwnd, x, y);
Ok(())
}
pub fn click_middle(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_click_middle_atomic(self.hwnd, x, y);
Ok(())
}
pub fn press_left(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_press_left_atomic(self.hwnd, x, y);
Ok(())
}
pub fn release_left(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_release_left_atomic(self.hwnd, x, y);
Ok(())
}
pub fn move_to(&self, x: i32, y: i32) -> Result<(), PostMessageMouseError> {
post_move_atomic(self.hwnd, x, y);
Ok(())
}
pub fn scroll_up(&self, x: i32, y: i32, delta: i32) -> Result<(), PostMessageMouseError> {
post_scroll_up_atomic(self.hwnd, x, y, delta);
Ok(())
}
pub fn scroll_down(&self, x: i32, y: i32, delta: i32) -> Result<(), PostMessageMouseError> {
post_scroll_down_atomic(self.hwnd, x, y, delta);
Ok(())
}
}