use crate::vk::Vk;
use winapi::um::winuser;
#[derive(Clone)]
#[repr(transparent)]
pub struct Input(winuser::INPUT);
impl Input {
pub fn from_char(c: char, action: Action) -> Option<Input> {
let c_n = c as u32;
if c_n > 0x0000ffff {
return None;
}
unsafe {
let mut input: winuser::INPUT = std::mem::zeroed();
input.type_ = winuser::INPUT_KEYBOARD;
let ki = input.u.ki_mut();
ki.wVk = 0; ki.wScan = c as u16;
ki.dwFlags = match action {
Action::Release => winuser::KEYEVENTF_KEYUP | winuser::KEYEVENTF_UNICODE,
Action::Press => winuser::KEYEVENTF_UNICODE,
};
ki.time = 0;
Some(Self(input))
}
}
pub fn from_vk(vk: Vk, action: Action) -> Input {
unsafe {
let mut input: winuser::INPUT = std::mem::zeroed();
input.type_ = winuser::INPUT_KEYBOARD;
let ki = input.u.ki_mut();
ki.wVk = vk as u16;
ki.wScan = 0; ki.dwFlags = match action {
Action::Release => winuser::KEYEVENTF_KEYUP,
Action::Press => 0,
};
ki.time = 0;
Self(input)
}
}
pub fn from_button(button: Button, action: Action) -> Input {
unsafe {
let mut input: winuser::INPUT = std::mem::zeroed();
input.type_ = winuser::INPUT_MOUSE;
let mi = input.u.mi_mut();
mi.dx = 0; mi.dy = 0;
mi.mouseData = match button {
Button::X1 => 1,
Button::X2 => 2,
_ => 0,
};
mi.dwFlags = match button {
Button::Left => match action {
Action::Press => winuser::MOUSEEVENTF_LEFTDOWN,
Action::Release => winuser::MOUSEEVENTF_LEFTUP,
},
Button::Right => match action {
Action::Press => winuser::MOUSEEVENTF_RIGHTDOWN,
Action::Release => winuser::MOUSEEVENTF_RIGHTUP,
},
Button::Middle => match action {
Action::Press => winuser::MOUSEEVENTF_MIDDLEDOWN,
Action::Release => winuser::MOUSEEVENTF_MIDDLEUP,
},
Button::X1 | Button::X2 => match action {
Action::Press => winuser::MOUSEEVENTF_XDOWN,
Action::Release => winuser::MOUSEEVENTF_XUP,
},
};
mi.time = 0; mi.dwExtraInfo = 0;
Self(input)
}
}
pub fn from_motion(motion: MouseMotion) -> Self {
unsafe {
let mut input: winuser::INPUT = std::mem::zeroed();
input.type_ = winuser::INPUT_MOUSE;
let mi = input.u.mi_mut();
mi.mouseData = 0;
mi.dwFlags = winuser::MOUSEEVENTF_MOVE;
match motion {
MouseMotion::Relative { dx, dy } => {
mi.dx = dx;
mi.dy = dy;
}
MouseMotion::Absolute { x, y, virtual_desk } => {
const NORMAL_FACTOR: f32 = 65535.0;
mi.dx = (x * NORMAL_FACTOR) as i32;
mi.dy = (y * NORMAL_FACTOR) as i32;
if virtual_desk {
mi.dwFlags |= winuser::MOUSEEVENTF_VIRTUALDESK;
}
mi.dwFlags |= winuser::MOUSEEVENTF_ABSOLUTE;
}
}
mi.time = 0; mi.dwExtraInfo = 0;
Self(input)
}
}
pub fn from_wheel(motion: f32, direction: WheelDirection) -> Self {
unsafe {
let mut input: winuser::INPUT = std::mem::zeroed();
input.type_ = winuser::INPUT_MOUSE;
let mi = input.u.mi_mut();
mi.dx = 0; mi.dy = 0;
const MOUSE_DELTA: f32 = 120.0;
mi.mouseData = (motion * MOUSE_DELTA) as i32 as u32;
mi.dwFlags = match direction {
WheelDirection::Vertical => winuser::MOUSEEVENTF_WHEEL,
WheelDirection::Horizontal => winuser::MOUSEEVENTF_HWHEEL,
};
mi.time = 0; mi.dwExtraInfo = 0;
Self(input)
}
}
}
pub fn send_inputs(inputs: impl AsRef<[Input]>) -> u32 {
use std::mem;
unsafe {
winuser::SendInput(
inputs.as_ref().len() as _,
inputs.as_ref().as_ptr() as _,
mem::size_of::<winuser::INPUT>() as _,
)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Action {
Press,
Release,
}
impl Action {
pub fn from_press(is_press: bool) -> Self {
if is_press {
Self::Press
} else {
Self::Release
}
}
pub fn from_release(is_release: bool) -> Self {
if is_release {
Self::Release
} else {
Self::Press
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Button {
Left,
Right,
Middle,
X1,
X2,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MouseMotion {
Relative {
dx: i32,
dy: i32,
},
Absolute {
x: f32,
y: f32,
virtual_desk: bool,
},
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum WheelDirection {
Vertical,
Horizontal,
}