use crate::display;
use crate::display::DisplayInfo;
use std::mem::{size_of, zeroed, MaybeUninit};
use virtual_input::mouse::{Mouse, MouseButton, MousePosition};
use winapi::shared::windef::POINT;
use winapi::um::winuser::{
GetAsyncKeyState, GetCursorPos, SendInput, SetCursorPos, INPUT, INPUT_MOUSE,
MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEINPUT, VK_LBUTTON, VK_MBUTTON, VK_RBUTTON,
};
pub struct WinApiMouse {
primary_display_info: DisplayInfo,
displays_info: Vec<DisplayInfo>,
}
impl WinApiMouse {
pub fn init() -> Self {
let displays_info = display::get_displays_info();
let primary_display_info = *displays_info.iter().find(|d| d.primary).unwrap();
WinApiMouse {
primary_display_info,
displays_info,
}
}
}
impl Mouse for WinApiMouse {
fn press(&self, button: MouseButton) -> bool {
send_mouse_button_input(button, false)
}
fn release(&self, button: MouseButton) -> bool {
send_mouse_button_input(button, true)
}
fn is_pressed(&self, button: MouseButton) -> bool {
let virtual_key_code = get_virtual_key_code(button);
let key_state = unsafe { GetAsyncKeyState(virtual_key_code) } as u16;
key_state >> 15 == 1
}
fn move_to(&self, x: u16, y: u16, display_index: Option<usize>) -> bool {
let display_info = match display_index {
Some(display_index) => self
.displays_info
.get(display_index)
.unwrap_or_else(|| &self.primary_display_info),
_ => &self.primary_display_info,
};
let offset_x = self
.displays_info
.iter()
.filter(|d| d.position.right < display_info.position.right)
.map(|d| d.width as i32)
.sum::<i32>();
let offset_y = self
.displays_info
.iter()
.filter(|d| d.position.top < display_info.position.top)
.map(|d| d.height as i32)
.sum::<i32>();
unsafe { SetCursorPos(x as i32 + offset_x, y as i32 + offset_y) == 1 }
}
fn get_position(&self) -> MousePosition {
let mut maybe_point = MaybeUninit::<POINT>::uninit();
unsafe {
GetCursorPos(maybe_point.as_mut_ptr());
}
let point = unsafe { maybe_point.assume_init() };
let global_x = point.x;
let global_y = point.y;
let (display_index, x) = self
.displays_info
.iter()
.enumerate()
.map(|(index, info)| (index, &info.position))
.find(|(_, position)| global_x >= position.left && global_x <= position.right)
.map(|(index, position)| (index, (global_x - position.left) as u16))
.unwrap();
let y = global_y as u16;
MousePosition {
display_index,
x,
y,
}
}
}
fn send_mouse_button_input(button: MouseButton, release: bool) -> bool {
unsafe {
let mut input = INPUT {
type_: INPUT_MOUSE,
u: zeroed(),
};
let flags = if release {
match button {
MouseButton::Left => MOUSEEVENTF_LEFTUP,
MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
MouseButton::Right => MOUSEEVENTF_RIGHTUP,
}
} else {
match button {
MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
}
};
*input.u.mi_mut() = MOUSEINPUT {
dx: 0,
dy: 0,
mouseData: 0,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
};
SendInput(1, &mut input, size_of::<INPUT>() as i32) == 1
}
}
fn get_virtual_key_code(button: MouseButton) -> i32 {
match button {
MouseButton::Left => VK_LBUTTON,
MouseButton::Middle => VK_MBUTTON,
MouseButton::Right => VK_RBUTTON,
}
}