1use std::sync::Weak;
15
16use windows::{
17 core::{implement, Ref},
18 Win32::{
19 System::Com::SAFEARRAY,
20 UI::Accessibility::{
21 IUIAutomation6, IUIAutomationActiveTextPositionChangedEventHandler,
22 IUIAutomationActiveTextPositionChangedEventHandler_Impl,
23 IUIAutomationChangesEventHandler, IUIAutomationChangesEventHandler_Impl,
24 IUIAutomationElement, IUIAutomationEventHandler, IUIAutomationEventHandlerGroup,
25 IUIAutomationEventHandler_Impl, IUIAutomationFocusChangedEventHandler,
26 IUIAutomationFocusChangedEventHandler_Impl,
27 IUIAutomationTextEditTextChangedEventHandler,
28 IUIAutomationTextEditTextChangedEventHandler_Impl, IUIAutomationTextRange,
29 TextEditChangeType, TextEditChangeType_None, TreeScope_Subtree,
30 UIA_Text_TextSelectionChangedEventId, UiaChangeInfo, UIA_EVENT_ID,
31 },
32 },
33};
34
35use crate::{
36 common::{beep, Result},
37 uia::{element::UiAutomationElement, pattern::text::UiAutomationTextRange},
38};
39
40pub struct UiAutomationEventHandlerGroup {
41 _automation: Weak<IUIAutomation6>,
42 _group: IUIAutomationEventHandlerGroup,
43}
44
45impl UiAutomationEventHandlerGroup {
46 pub(crate) fn get_raw(&self) -> &IUIAutomationEventHandlerGroup {
47 &self._group
48 }
49 pub(crate) fn obtain(
50 automation: Weak<IUIAutomation6>,
51 group: &IUIAutomationEventHandlerGroup,
52 ) -> Self {
53 Self {
54 _automation: automation.clone(),
55 _group: group.clone(),
56 }
57 }
58
59 pub fn add_active_text_position_changed_listener<CB>(&self, func: CB)
65 where
66 CB: Fn(UiAutomationElement, UiAutomationTextRange) -> () + 'static,
67 {
68 let handler: IUIAutomationActiveTextPositionChangedEventHandler =
69 OnActiveTextPositionChangedCallback::new(func, self._automation.clone()).into();
70 unsafe {
71 self._group
72 .AddActiveTextPositionChangedEventHandler(TreeScope_Subtree, None, &handler)
73 }
74 .expect("Can't add the active text position changed listener.");
75 }
76
77 pub fn add_text_edit_text_changed_listener<CB>(&self, func: CB)
83 where
84 CB: Fn(UiAutomationElement) -> () + 'static,
85 {
86 let handler: IUIAutomationTextEditTextChangedEventHandler =
87 OnTextEditTextChangedCallback::new(func, self._automation.clone()).into();
88 unsafe {
89 self._group.AddTextEditTextChangedEventHandler(
90 TreeScope_Subtree,
91 TextEditChangeType_None,
92 None,
93 &handler,
94 )
95 }
96 .expect("Can't add the active text position changed listener.");
97 }
98
99 pub fn add_changes_listener<CB>(&self, func: CB)
105 where
106 CB: Fn() -> () + 'static,
107 {
108 let handler: IUIAutomationChangesEventHandler =
109 OnChangesCallback::new(func, self._automation.clone()).into();
110 unsafe {
111 self._group
112 .AddChangesEventHandler(TreeScope_Subtree, &[0], None, &handler)
113 }
114 .expect("Can't add the changes listener.");
115 }
116
117 pub fn add_text_selection_changed_listener<CB>(&self, func: CB)
123 where
124 CB: Fn(UiAutomationElement) -> () + 'static,
125 {
126 let handler: IUIAutomationEventHandler =
127 OnCallback::new(func, self._automation.clone()).into();
128 unsafe {
129 self._group.AddAutomationEventHandler(
130 UIA_Text_TextSelectionChangedEventId,
131 TreeScope_Subtree,
132 None,
133 &handler,
134 )
135 }
136 .expect("Can't add the text selection changed listener.");
137 }
138}
139
140unsafe impl Send for UiAutomationEventHandlerGroup {}
141
142unsafe impl Sync for UiAutomationEventHandlerGroup {}
143
144#[implement(IUIAutomationFocusChangedEventHandler)]
145pub(crate) struct OnFocusChangedCallback<CB>
146where
147 CB: Fn(UiAutomationElement) -> () + 'static,
148{
149 _automation: Weak<IUIAutomation6>,
150 _cb: Box<CB>,
151}
152
153impl<CB> OnFocusChangedCallback<CB>
154where
155 CB: Fn(UiAutomationElement) -> () + 'static,
156{
157 pub(crate) fn new(func: CB, automation: Weak<IUIAutomation6>) -> Self {
158 Self {
159 _automation: automation,
160 _cb: func.into(),
161 }
162 }
163}
164
165impl<CB> IUIAutomationFocusChangedEventHandler_Impl for OnFocusChangedCallback_Impl<CB>
166where
167 CB: Fn(UiAutomationElement) -> () + 'static,
168{
169 #[allow(non_snake_case)]
170 fn HandleFocusChangedEvent(&self, sender: Ref<'_, IUIAutomationElement>) -> Result<()> {
171 let func = &*self._cb;
172 func(UiAutomationElement::obtain(
173 self._automation.clone(),
174 sender.unwrap().clone(),
175 ));
176 Ok(())
177 }
178}
179
180#[implement(IUIAutomationActiveTextPositionChangedEventHandler)]
181struct OnActiveTextPositionChangedCallback<CB>
182where
183 CB: Fn(UiAutomationElement, UiAutomationTextRange) -> () + 'static,
184{
185 _automation: Weak<IUIAutomation6>,
186 _cb: Box<CB>,
187}
188
189impl<CB> OnActiveTextPositionChangedCallback<CB>
190where
191 CB: Fn(UiAutomationElement, UiAutomationTextRange) -> () + 'static,
192{
193 fn new(func: CB, automation: Weak<IUIAutomation6>) -> Self {
194 Self {
195 _automation: automation,
196 _cb: func.into(),
197 }
198 }
199}
200
201impl<CB> IUIAutomationActiveTextPositionChangedEventHandler_Impl
202 for OnActiveTextPositionChangedCallback_Impl<CB>
203where
204 CB: Fn(UiAutomationElement, UiAutomationTextRange) -> () + 'static,
205{
206 #[allow(non_snake_case)]
207 fn HandleActiveTextPositionChangedEvent(
208 &self,
209 sender: Ref<'_, IUIAutomationElement>,
210 range: Ref<'_, IUIAutomationTextRange>,
211 ) -> Result<()> {
212 let func = &*self._cb;
213 let element =
214 UiAutomationElement::obtain(self._automation.clone(), sender.unwrap().clone());
215 let range = UiAutomationTextRange::obtain(range.unwrap());
216 func(element, range);
217 Ok(())
218 }
219}
220
221#[implement(IUIAutomationTextEditTextChangedEventHandler)]
222struct OnTextEditTextChangedCallback<CB>
223where
224 CB: Fn(UiAutomationElement) -> () + 'static,
225{
226 _automation: Weak<IUIAutomation6>,
227 _cb: Box<CB>,
228}
229
230impl<CB> OnTextEditTextChangedCallback<CB>
231where
232 CB: Fn(UiAutomationElement) -> () + 'static,
233{
234 fn new(func: CB, automation: Weak<IUIAutomation6>) -> Self {
235 Self {
236 _automation: automation,
237 _cb: func.into(),
238 }
239 }
240}
241
242impl<CB> IUIAutomationTextEditTextChangedEventHandler_Impl
243 for OnTextEditTextChangedCallback_Impl<CB>
244where
245 CB: Fn(UiAutomationElement) -> () + 'static,
246{
247 #[allow(non_snake_case)]
248 #[allow(unused_variables)]
249 fn HandleTextEditTextChangedEvent(
250 &self,
251 sender: Ref<'_, IUIAutomationElement>,
252 text_edit_change_type: TextEditChangeType,
253 event_strings: *const SAFEARRAY,
254 ) -> Result<()> {
255 beep(400, 40);
256 Ok(())
257 }
258}
259
260#[implement(IUIAutomationChangesEventHandler)]
262struct OnChangesCallback<CB>
263where
264 CB: Fn() -> () + 'static,
265{
266 _automation: Weak<IUIAutomation6>,
267 _cb: Box<CB>,
268}
269
270impl<CB> OnChangesCallback<CB>
271where
272 CB: Fn() -> () + 'static,
273{
274 fn new(func: CB, automation: Weak<IUIAutomation6>) -> Self {
275 Self {
276 _automation: automation,
277 _cb: func.into(),
278 }
279 }
280}
281
282impl<CB> IUIAutomationChangesEventHandler_Impl for OnChangesCallback_Impl<CB>
283where
284 CB: Fn() -> () + 'static,
285{
286 #[allow(non_snake_case)]
288 #[allow(unused_variables)]
289 fn HandleChangesEvent(
290 &self,
291 sender: Ref<'_, IUIAutomationElement>,
292 uiachanges: *const UiaChangeInfo,
293 changescount: i32,
294 ) -> Result<()> {
295 beep(400, 40);
296 Ok(())
297 }
298}
299
300#[implement(IUIAutomationEventHandler)]
301struct OnCallback<CB>
302where
303 CB: Fn(UiAutomationElement) -> () + 'static,
304{
305 _automation: Weak<IUIAutomation6>,
306 _cb: Box<CB>,
307}
308
309impl<CB> OnCallback<CB>
310where
311 CB: Fn(UiAutomationElement) -> () + 'static,
312{
313 fn new(func: CB, automation: Weak<IUIAutomation6>) -> Self {
314 Self {
315 _automation: automation,
316 _cb: func.into(),
317 }
318 }
319}
320
321impl<CB> IUIAutomationEventHandler_Impl for OnCallback_Impl<CB>
322where
323 CB: Fn(UiAutomationElement) -> () + 'static,
324{
325 #[allow(non_snake_case)]
326 #[allow(unused_variables)]
327 fn HandleAutomationEvent(
328 &self,
329 sender: Ref<'_, IUIAutomationElement>,
330 event_id: UIA_EVENT_ID,
331 ) -> Result<()> {
332 let func = &*self._cb;
333 func(UiAutomationElement::obtain(
334 self._automation.clone(),
335 sender.unwrap().clone(),
336 ));
337 Ok(())
338 }
339}