1use crate::{
15 common::{get_class_name, Result, HMODULE, HWND},
16 message::message_loop,
17 msaa::object::AccessibleObject,
18};
19use std::{
20 fmt::{Debug, Formatter},
21 sync::{Arc, RwLock},
22 thread,
23 time::SystemTime,
24};
25pub use windows::Win32::UI::Accessibility::{HWINEVENTHOOK, WINEVENTPROC};
26use windows::Win32::UI::{
27 Accessibility::{SetWinEventHook, UnhookWinEvent},
28 WindowsAndMessaging::{EVENT_MAX, EVENT_MIN, WINEVENT_OUTOFCONTEXT},
29};
30
31#[derive(Clone)]
32struct WinEventHookHandle(HWINEVENTHOOK);
33
34impl WinEventHookHandle {
35 pub const fn new() -> Self {
36 Self(HWINEVENTHOOK(std::ptr::null_mut()))
37 }
38}
39
40unsafe impl Sync for WinEventHookHandle {}
41unsafe impl Send for WinEventHookHandle {}
42
43impl From<HWINEVENTHOOK> for WinEventHookHandle {
44 fn from(value: HWINEVENTHOOK) -> Self {
45 Self(value)
46 }
47}
48
49impl std::ops::Deref for WinEventHookHandle {
50 type Target = HWINEVENTHOOK;
51
52 fn deref(&self) -> &Self::Target {
53 &self.0
54 }
55}
56
57impl Default for WinEventHookHandle {
58 fn default() -> Self {
59 Self(HWINEVENTHOOK::default())
60 }
61}
62
63pub fn set_win_event_hook(
86 event_min: u32,
87 event_max: u32,
88 h_mod_win_event_proc: Option<HMODULE>,
89 fn_win_event_proc: WINEVENTPROC,
90 id_process: u32,
91 id_thread: u32,
92 flags: u32,
93) -> HWINEVENTHOOK {
94 unsafe {
95 SetWinEventHook(
96 event_min,
97 event_max,
98 h_mod_win_event_proc,
99 fn_win_event_proc,
100 id_process,
101 id_thread,
102 flags,
103 )
104 }
105}
106
107pub fn unhook_win_event(h_win_event_hook: HWINEVENTHOOK) -> bool {
112 unsafe { UnhookWinEvent(h_win_event_hook) }.as_bool()
113}
114
115static H_WIN_EVENT: RwLock<WinEventHookHandle> = RwLock::new(WinEventHookHandle::new());
116static EVENTS: RwLock<Vec<WinEventHook>> = RwLock::new(vec![]);
117
118#[derive(Clone)]
119#[allow(dead_code)]
120pub struct WinEventSource {
121 pub h_wnd: HWND,
122 pub id_object: i32,
123 pub id_child: i32,
124 pub id_thread: u32,
125 pub ms_time: u32,
126}
127
128unsafe impl Send for WinEventSource {}
129unsafe impl Sync for WinEventSource {}
130
131impl WinEventSource {
132 pub fn get_object(&self) -> Result<(AccessibleObject, i32)> {
136 AccessibleObject::from_event(self.h_wnd, self.id_object, self.id_child)
137 }
138
139 pub fn get_class_name(&self) -> String {
143 get_class_name(self.h_wnd)
144 }
145}
146
147impl Debug for WinEventSource {
148 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
149 write!(
150 f,
151 "WinEventSource(window:[{:?}, {}], object:[{}, {}], time:{})",
152 self.h_wnd.0,
153 self.get_class_name(),
154 self.id_object,
155 self.id_child,
156 self.ms_time
157 )
158 }
159}
160
161unsafe extern "system" fn hook_proc(
162 _: HWINEVENTHOOK,
163 event: u32,
164 h_wnd: HWND,
165 id_object: i32,
166 id_child: i32,
167 id_event_thread: u32,
168 ms_event_time: u32,
169) {
170 let source = WinEventSource {
171 h_wnd,
172 id_object,
173 id_child,
174 id_thread: id_event_thread,
175 ms_time: ms_event_time,
176 };
177 let lock = EVENTS.read().unwrap();
178 for i in lock.iter() {
179 if event == i.2 {
180 (&*i.0)(source.clone())
181 }
182 }
183}
184
185#[derive(Clone)]
186pub struct WinEventHook(Arc<dyn Fn(WinEventSource) + Send + Sync>, SystemTime, u32);
187
188impl WinEventHook {
189 pub fn new(event: u32, func: impl Fn(WinEventSource) + Send + Sync + 'static) -> Self {
195 let h_win_event = { H_WIN_EVENT.read().unwrap().clone() };
196 if h_win_event.is_invalid() {
197 thread::spawn(|| {
198 let mut lock = H_WIN_EVENT.write().unwrap();
199 if !lock.is_invalid() {
200 return;
201 }
202 let handle = set_win_event_hook(
203 EVENT_MIN,
204 EVENT_MAX,
205 None,
206 Some(hook_proc),
207 0,
208 0,
209 WINEVENT_OUTOFCONTEXT,
210 );
211 *lock = WinEventHookHandle::from(handle);
212 drop(lock);
213 message_loop(|_| ());
214 unhook_win_event(handle);
215 *H_WIN_EVENT.write().unwrap() = WinEventHookHandle::default();
216 });
217 }
218 let self_ = Self(Arc::new(func), SystemTime::now(), event);
219 EVENTS.write().unwrap().push(self_.clone());
220
221 self_
222 }
223 pub fn unhook(&self) {
224 let mut lock = EVENTS.write().unwrap();
225 for i in 0..lock.len() {
226 if let Some(x) = lock.get(i) {
227 if x == self {
228 lock.remove(i);
229 }
230 }
231 }
232 if lock.is_empty() {
233 drop(lock);
234 let mut lock = H_WIN_EVENT.write().unwrap();
235 unhook_win_event(lock.0);
236 *lock = WinEventHookHandle(HWINEVENTHOOK::default());
237 }
238 }
239}
240
241impl Debug for WinEventHook {
242 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
243 write!(f, "WinEventHook({})", self.2)
244 }
245}
246
247impl PartialEq for WinEventHook {
248 fn eq(&self, other: &Self) -> bool {
249 self.1 == other.1
250 }
251}