1mod hook;
2mod input;
3mod vkcode;
4
5use hook::HookHandler;
6use input::Input;
7use windows::Win32::Foundation::{LPARAM, LRESULT, WPARAM};
8use windows::Win32::UI::WindowsAndMessaging::HHOOK;
9
10use crate::button::{Button, ButtonAction};
11use crate::event::{self, EventReceiver, NativeEventOperation};
12
13use std::sync::atomic::{AtomicBool, Ordering};
14
15use once_cell::sync::Lazy;
16use windows::Win32::UI::{HiDpi, WindowsAndMessaging};
17
18const SHOULD_BE_IGNORED_FLAG: usize = 0x1;
19const INJECTED_FLAG: usize = 0x2;
20
21#[derive(Debug)]
22struct ButtonState([AtomicBool; Button::VARIANT_COUNT]);
23
24impl ButtonState {
25 const fn new() -> Self {
26 let inner = unsafe {
27 std::mem::transmute([false; Button::VARIANT_COUNT])
30 };
31 ButtonState(inner)
32 }
33
34 #[inline]
35 fn press(&self, button: Button, order: Ordering) {
36 self.0[button as usize].store(true, order);
37 }
38
39 #[inline]
40 fn release(&self, button: Button, order: Ordering) {
41 self.0[button as usize].store(false, order)
42 }
43
44 #[inline]
45 fn is_pressed(&self, button: Button, order: Ordering) -> bool {
46 self.0[button as usize].load(order)
47 }
48
49 #[inline]
50 fn is_released(&self, button: Button, order: Ordering) -> bool {
51 !self.0[button as usize].load(order)
52 }
53}
54
55static BUTTON_STATE: ButtonState = ButtonState::new();
56
57static INPUT: Lazy<Input> = Lazy::new(Input::new);
58
59#[inline]
60fn send_input(button: Button, action: ButtonAction, recursive: bool, assume: fn(Button)) {
61 let left_and_right_modifier = match button {
62 Button::Shift => Some((Button::LShift, Button::RShift)),
63 Button::Ctrl => Some((Button::LCtrl, Button::RCtrl)),
64 Button::Alt => Some((Button::LAlt, Button::RAlt)),
65 Button::Super => Some((Button::LSuper, Button::RSuper)),
66 _ => None,
67 };
68 if let Some((left, right)) = left_and_right_modifier {
69 assume(left);
70 assume(right);
71 assume(button);
72 INPUT.button_input(left, action, recursive);
73 INPUT.button_input(right, action, recursive);
74 } else {
75 assume(button);
76 INPUT.button_input(button, action, recursive);
77 }
78}
79
80impl Button {
81 #[inline]
83 pub fn press(self) {
84 send_input(self, ButtonAction::Press, false, Button::assume_pressed);
85 }
86
87 #[inline]
90 pub fn press_recursive(self) {
91 send_input(self, ButtonAction::Press, true, Button::assume_pressed);
92 }
93
94 #[inline]
96 pub fn release(self) {
97 send_input(self, ButtonAction::Release, false, Button::assume_released);
98 }
99
100 #[inline]
103 pub fn release_recursive(self) {
104 send_input(self, ButtonAction::Release, true, Button::assume_released);
105 }
106
107 #[inline]
109 pub fn click(self) {
110 self.press();
111 self.release();
112 }
113
114 #[inline]
117 pub fn click_recursive(self) {
118 self.press_recursive();
119 self.release_recursive();
120 }
121
122 #[inline]
124 pub fn is_pressed(self) -> bool {
125 BUTTON_STATE.is_pressed(self, Ordering::SeqCst)
126 }
127
128 #[inline]
130 pub fn is_released(self) -> bool {
131 BUTTON_STATE.is_released(self, Ordering::SeqCst)
132 }
133
134 #[inline]
135 fn assume_pressed(self) {
136 BUTTON_STATE.press(self, Ordering::SeqCst);
137 }
138
139 #[inline]
140 fn assume_released(self) {
141 BUTTON_STATE.release(self, Ordering::SeqCst);
142 }
143}
144
145pub mod mouse {
146 use super::INPUT;
149
150 #[inline]
152 pub fn get_position() -> (i32, i32) {
153 INPUT.cursor_position()
154 }
155
156 #[inline]
158 pub fn move_absolute(x: i32, y: i32) {
159 INPUT.move_absolute(x, y, false);
160 }
161
162 #[inline]
165 pub fn move_absolute_recursive(x: i32, y: i32) {
166 INPUT.move_absolute(x, y, true);
167 }
168
169 #[inline]
171 pub fn move_relative(dx: i32, dy: i32) {
172 INPUT.move_relative(dx, dy, false);
173 }
174
175 #[inline]
178 pub fn move_relative_recursive(dx: i32, dy: i32) {
179 INPUT.move_relative(dx, dy, true);
180 }
181
182 #[inline]
184 pub fn rotate(speed: i32) {
185 INPUT.rotate_wheel(speed, false);
186 }
187
188 #[inline]
191 pub fn rotate_recursive(speed: i32) {
192 INPUT.rotate_wheel(speed, true);
193 }
194}
195
196static HOOK_HANDLER: Lazy<HookHandler> = Lazy::new(HookHandler::new);
197
198extern "system" fn keyboard_hook_proc(n_code: i32, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
199 match hook::keyboard_hook_proc_inner(&HOOK_HANDLER, n_code, l_param) {
200 NativeEventOperation::Block => LRESULT(1),
201 NativeEventOperation::Dispatch => unsafe {
202 WindowsAndMessaging::CallNextHookEx(HHOOK(0), n_code, w_param, l_param)
203 },
204 }
205}
206
207extern "system" fn mouse_hook_proc(n_code: i32, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
208 match hook::mouse_hook_proc_inner(&HOOK_HANDLER, &INPUT, n_code, w_param, l_param) {
209 NativeEventOperation::Block => LRESULT(1),
210 NativeEventOperation::Dispatch => unsafe {
211 WindowsAndMessaging::CallNextHookEx(HHOOK(0), n_code, w_param, l_param)
212 },
213 }
214}
215
216pub fn install_hook() -> EventReceiver {
229 unsafe {
230 HiDpi::SetProcessDpiAwarenessContext(HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
232 }
233
234 INPUT.update_cursor_position();
235
236 let (tx, rx) = event::channel();
237 HOOK_HANDLER.install(tx, keyboard_hook_proc, mouse_hook_proc);
238
239 rx
240}
241
242pub fn uninstall_hook() {
261 HOOK_HANDLER.uninstall();
262}