win_wrap/msaa/
event.rs

1/*
2 * Copyright (c) 2024. The RigelA open source project team and
3 * its contributors reserve all rights.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and limitations under the License.
12 */
13
14use 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
63//noinspection SpellCheckingInspection
64/**
65为一系列事件设置事件挂钩函数。
66`event_min` 指定挂钩函数处理的事件范围中最低事件值的事件常量。此参数可以设置为EVENT_MIN,以指示可能的最低事件值。
67`event_max` 指定由挂钩函数处理的事件范围中最高事件值的事件常量。此参数可以设置为EVENT_MAX,以指示可能的最高事件值。
68`h_mod_win_event_proc` 如果在flags参数中指定了WINEVENT_INCONTEXT标志,则为包含fn_win_event_proc 中的挂钩函数的DLL的句柄。如果挂钩函数不位于DLL中,或者指定了WINEVENT_OUTOFCONTEXT标志,则此参数为NULL。
69`fn_win_event_proc` 指向事件挂钩函数的指针。有关此函数的详细信息,请参阅WinEventProc。
70`id_process` 指定挂钩函数从中接收事件的进程的ID。指定零 (0) 从当前桌面上的所有进程接收事件。
71`id_thread` 指定挂钩函数从中接收事件的线程的ID。如果此参数为零,则挂钩函数与当前桌面上的所有现有线程相关联。
72`flags` 标记值,用于指定要跳过的挂钩函数和事件的位置。
73以下标志有效:
74- WINEVENT_INCONTEXT 包含回调函数的DLL映射到生成事件的进程的地址空间中。使用此标志,系统会在事件通知发生时向回调函数发送事件通知。指定此标志时,挂钩函数必须位于DLL中。当调用进程和生成进程都不是32位或64位进程,或者生成进程是控制台应用程序时,此标志不起作用。有关详细信息,请参阅上下文中挂钩函数。
75- WINEVENT_OUTOFCONTEXT 回调函数不会映射到生成事件的进程的地址空间中。由于挂钩函数是跨进程边界调用的,因此系统必须对事件进行排队。虽然此方法是异步的,但事件保证按顺序排列。有关详细信息,请参阅上下文外挂钩函数。
76- WINEVENT_SKIPOWNPROCESS 防止挂钩的此实例接收此进程中线程生成的事件。此标志不会阻止线程生成事件。
77- WINEVENT_SKIPOWNTHREAD 防止此挂钩实例接收注册此挂钩的线程生成的事件。
78以下标志组合有效:
79• WINEVENT_INCONTEXT |WINEVENT_SKIPOWNPROCESS
80• WINEVENT_INCONTEXT |WINEVENT_SKIPOWNTHREAD
81• WINEVENT_OUTOFCONTEXT |WINEVENT_SKIPOWNPROCESS
82• WINEVENT_OUTOFCONTEXT |WINEVENT_SKIPOWNTHREAD
83此外,客户端应用程序可以指定WINEVENT_INCONTEXT或单独WINEVENT_OUTOFCONTEXT。
84*/
85pub 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
107/**
108删除由上一次调用 set_win_event_hook 创建的事件挂钩函数。
109`h_win_event_hook` 在上一次调用 set_win_event_hook 时返回的事件挂钩的句柄。
110*/
111pub 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    /**
133    获取事件对应的可访问性对象。
134    */
135    pub fn get_object(&self) -> Result<(AccessibleObject, i32)> {
136        AccessibleObject::from_event(self.h_wnd, self.id_object, self.id_child)
137    }
138
139    /**
140    获取事件对应窗口的类名。
141    */
142    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    /**
190    创建一个事件钩子实例。
191    `event` 事件类型。
192    `func` 接收事件的函数。
193    */
194    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}