uiautomation 0.23.0

UI Automation Framework for Windows
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
mod handlers;
mod functions;

use uiautomation_derive::map_as;
use uiautomation_derive::EnumConvert;
use windows::Win32::UI::Accessibility::IUIAutomationEventHandler;
use windows::Win32::UI::Accessibility::IUIAutomationFocusChangedEventHandler;
use windows::Win32::UI::Accessibility::IUIAutomationPropertyChangedEventHandler;
use windows::Win32::UI::Accessibility::IUIAutomationStructureChangedEventHandler;
use windows_core::Param;

use crate::types::StructureChangeType;
use crate::types::UIProperty;
use crate::variants::SafeArray;
use crate::variants::Variant;
use crate::Result;
use crate::UIElement;

/// `UIEventType` is an enum wrapper for `windows::Win32::UI::Accessibility::UIA_EVENT_ID`.
/// 
/// Describes  the named constants used to identify Microsoft UI Automation events.
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumConvert)]
#[map_as(windows::Win32::UI::Accessibility::UIA_EVENT_ID)]
#[allow(non_camel_case_types)]
pub enum UIEventType {
    /// Identifies the event that is raised when a tooltip is opened.
    ToolTipOpened = 20000i32,
    /// Identifies the event that is raised when a tooltip is closed.
    ToolTipClosed = 20001i32,
    /// Identifies the event that is raised when the UI Automation tree structure is changed.
    StructureChanged = 20002i32,
    /// Identifies the event that is raised when a menu is opened.
    MenuOpened = 20003i32,
    /// Identifies the event that is raised when the value of a property has changed.
    AutomationPropertyChanged = 20004i32,
    /// Identifies the event that is raised when the focus has changed from one element to another.
    AutomationFocusChanged = 20005i32,
    /// Identifies the event that is raised when asynchronous content is being loaded. This event is used mainly by providers to indicate that asynchronous content-loading events have occurred.
    AsyncContentLoaded = 20006i32,
    /// Identifies the event that is raised when a menu is closed.
    MenuClosed = 20007i32,
    /// Identifies the event that is raised when the layout of child items within a control has changed. This event is also used for Auto-suggest accessibility.
    LayoutInvalidated = 20008i32,
    /// Identifies the event that is raised when a control is invoked or activated.
    Invoke_Invoked = 20009i32,
    /// Identifies the event raised when an item is added to a collection of selected items.
    SelectionItem_ElementAddedToSelection = 20010i32,
    /// Identifies the event raised when an item is removed from a collection of selected items.
    SelectionItem_ElementRemovedFromSelection = 20011i32,
    /// Identifies the event that is raised when a call to the Select, AddToSelection, or RemoveFromSelection method results in a single item being selected.
    SelectionItem_ElementSelected = 20012i32,
    /// Identifies the event that is raised when a selection in a container has changed significantly.
    Selection_Invalidated = 20013i32,
    /// Identifies the event that is raised when the text selection is modified.
    Text_TextSelectionChanged = 20014i32,
    /// Identifies the event that is raised whenever textual content is modified.
    Text_TextChanged = 20015i32,
    /// Identifies the event that is raised when a window is opened.
    Window_WindowOpened = 20016i32,
    /// Identifies the event that is raised when a window is closed.
    Window_WindowClosed = 20017i32,
    /// Identifies the event that is raised when a menu mode is started.
    MenuModeStart = 20018i32,
    /// Identifies the event that is raised when a menu mode is ended.
    MenuModeEnd = 20019i32,
    /// Identifies the event that is raised when the specified mouse or keyboard input reaches the element for which the StartListening method was called.
    InputReachedTarget = 20020i32,
    /// Identifies the event that is raised when the specified input reached an element other than the element for which the StartListening method was called.
    InputReachedOtherElement = 20021i32,
    /// Identifies the event that is raised when the specified input was discarded or otherwise failed to reach any element.
    InputDiscarded = 20022i32,
    /// Identifies the event that is raised when a provider issues a system alert. 
    /// 
    /// Supported starting with Windows 8.
    SystemAlert = 20023i32,
    /// Identifies the event that is raised when the content of a live region has changed. 
    /// 
    /// Supported starting with Windows 8.
    LiveRegionChanged = 20024i32,
    /// Identifies the event that is raised when a change is made to the root node of a UI Automation fragment that is hosted in another element. 
    /// 
    /// Supported starting with Windows 8.
    HostedFragmentRootsInvalidated = 20025i32,
    /// Identifies the event that is raised when the user starts to drag an element. This event is raised by the element being dragged. 
    /// 
    /// Supported starting with Windows 8.
    Drag_DragStart = 20026i32,
    /// Identifies the event that is raised when the user ends a drag operation before dropping an element on a drop target. This event is raised by the element being dragged. 
    /// 
    /// Supported starting with Windows 8.
    Drag_DragCancel = 20027i32,
    /// Identifies the event that is raised when the user drops an element on a drop target. This event is raised by the element being dragged. 
    /// Supported starting with Windows 8.
    Drag_DragComplete = 20028i32,
    /// Identifies the event that is raised when the user drags an element into a drop target's boundary. This event is raised by the drop target element. 
    /// 
    /// Supported starting with Windows 8.
    DropTarget_DragEnter = 20029i32,
    /// Identifies the event that is raised when the user drags an element out of a drop target's boundary. This event is raised by the drop target element. 
    /// 
    /// Supported starting with Windows 8.
    DropTarget_DragLeave = 20030i32,
    /// Identifies the event that is raised when the user drops an element on a drop target. This event is raised by the drop target element. 
    /// 
    /// Supported starting with Windows 8.
    DropTarget_Dropped = 20031i32,
    /// Identifies the event that is raised whenever text auto-correction is performed by a control. 
    /// 
    /// Supported starting with Windows 8.1.
    TextEdit_TextChanged = 20032i32,
    /// Identifies the event that is raised whenever a composition replacement is performed by a control. 
    /// 
    /// Supported starting with Windows 8.1.
    TextEdit_ConversionTargetChanged = 20033i32,
    /// Identifies the event that is raised when a provider calls the UiaRaiseChangesEvent function.
    Changes = 20034i32,
    /// Identifies the event that is raised when a provider calls the UiaRaiseNotificationEvent method.
    Notification = 20035i32,
    /// Identifies the event that is raised when the active text position changes, indicated by a navigation event within or between read-only text elements 
    /// (such as web browsers, PDF documents, or EPUB documents) using bookmarks (fragment identifiers that refer to a location within a resource).
    ActiveTextPositionChanged = 20036i32,
}

/// A wrapper for windows `IUIAutomationEventHandler` interface. 
/// 
/// Exposes a method to handle Microsoft UI Automation events.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIEventHandler {
    handler: IUIAutomationEventHandler
}

impl UIEventHandler {
    /// Handles a Microsoft UI Automation event.
    pub fn handle_automation_event(&self, sender: &UIElement, event: UIEventType) -> Result<()> {
        unsafe {
            self.handler.HandleAutomationEvent(sender, event.into())?;
        }
        Ok(())
    }
}

impl From<IUIAutomationEventHandler> for UIEventHandler {
    fn from(handler: IUIAutomationEventHandler) -> Self {
        Self{
            handler
        }
    }
}

impl From<&IUIAutomationEventHandler> for UIEventHandler {
    fn from(value: &IUIAutomationEventHandler) -> Self {
        value.clone().into()
    }
}

impl Into<IUIAutomationEventHandler> for UIEventHandler {
    fn into(self) -> IUIAutomationEventHandler {
        self.handler
    }
}

impl AsRef<IUIAutomationEventHandler> for UIEventHandler {
    fn as_ref(&self) -> &IUIAutomationEventHandler {
        &self.handler
    }
}

impl Param<IUIAutomationEventHandler> for UIEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationEventHandler> { unsafe {
        self.handler.param()
    }}
}

impl Param<IUIAutomationEventHandler> for &UIEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationEventHandler> { unsafe {
        (&self.handler).param()
    }}
}

/// A wrapper for windows `IUIAutomationPropertyChangedEventHandler` interface. 
/// 
/// Exposes a method to handle Microsoft UI Automation events that occur when a property is changed.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIPropertyChangedEventHandler {
    handler: IUIAutomationPropertyChangedEventHandler
}

impl UIPropertyChangedEventHandler {
    /// Handles a Microsoft UI Automation property-changed event.
    pub fn handle_property_changed_event(&self, sender: &UIElement, property_id: UIProperty, new_value: Variant) -> Result<()> {
        unsafe {
            self.handler.HandlePropertyChangedEvent(sender, property_id.into(), new_value.as_ref())?
        };
        Ok(())
    }
}

impl From<IUIAutomationPropertyChangedEventHandler> for UIPropertyChangedEventHandler {
    fn from(handler: IUIAutomationPropertyChangedEventHandler) -> Self {
        Self { 
            handler
        }
    }
}

impl From<&IUIAutomationPropertyChangedEventHandler> for UIPropertyChangedEventHandler {
    fn from(value: &IUIAutomationPropertyChangedEventHandler) -> Self {
        value.clone().into()
    }
}

impl Into<IUIAutomationPropertyChangedEventHandler> for UIPropertyChangedEventHandler {
    fn into(self) -> IUIAutomationPropertyChangedEventHandler {
        self.handler
    }
}

impl AsRef<IUIAutomationPropertyChangedEventHandler> for UIPropertyChangedEventHandler {
    fn as_ref(&self) -> &IUIAutomationPropertyChangedEventHandler {
        &self.handler
    }
}

impl Param<IUIAutomationPropertyChangedEventHandler> for UIPropertyChangedEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationPropertyChangedEventHandler> { unsafe {
        self.handler.param()
    }}
}

impl Param<IUIAutomationPropertyChangedEventHandler> for &UIPropertyChangedEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationPropertyChangedEventHandler> { unsafe {
        (&self.handler).param()
    }}
}

/// A wrapper for windows `IUIAutomationStructureChangedEventHandler` interface. 
/// 
/// Handles an event that is raised when the Microsoft UI Automation tree structure has changed.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIStructureChangeEventHandler {
    handler: IUIAutomationStructureChangedEventHandler
}

impl UIStructureChangeEventHandler {
    /// Handles an event that is raised when the Microsoft UI Automation tree structure has changed.
    pub fn handle_structure_changed_event(&self, sender: &UIElement, change_type: StructureChangeType, runtime_id: Option<&[i32]>) -> Result<()> {
        let runtime_id = if let Some(arr) = runtime_id {
            arr.try_into()?
        } else {
            SafeArray::default()
        };

        unsafe {
            self.handler.HandleStructureChangedEvent(sender, change_type.into(), runtime_id.get_array())?
        }

        Ok(())
    }
}

impl From<IUIAutomationStructureChangedEventHandler> for UIStructureChangeEventHandler {
    fn from(handler: IUIAutomationStructureChangedEventHandler) -> Self {
        Self { 
            handler 
        }
    }
}

impl From<&IUIAutomationStructureChangedEventHandler> for UIStructureChangeEventHandler {
    fn from(value: &IUIAutomationStructureChangedEventHandler) -> Self {
        value.clone().into()
    }
}

impl Into<IUIAutomationStructureChangedEventHandler> for UIStructureChangeEventHandler {
    fn into(self) -> IUIAutomationStructureChangedEventHandler {
        self.handler
    }
}

impl AsRef<IUIAutomationStructureChangedEventHandler> for UIStructureChangeEventHandler {
    fn as_ref(&self) -> &IUIAutomationStructureChangedEventHandler {
        &self.handler
    }
}

impl Param<IUIAutomationStructureChangedEventHandler> for UIStructureChangeEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationStructureChangedEventHandler> { unsafe {
        self.handler.param()
    }}
}

impl Param<IUIAutomationStructureChangedEventHandler> for &UIStructureChangeEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationStructureChangedEventHandler> { unsafe {
        (&self.handler).param()
    }}
}

/// A wrapper for windows `IUIAutomationFocusChangedEventHandler` interface. 
/// 
/// Exposes a method to handle events that are raised when the keyboard focus moves to another UI Automation element.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIFocusChangedEventHandler {
    handler: IUIAutomationFocusChangedEventHandler
}

impl UIFocusChangedEventHandler {
    /// Handles the event raised when the keyboard focus moves to a different UI Automation element.
    pub fn handle_focus_changed_event(&self, sender: &UIElement) -> Result<()> {
        unsafe {
            self.handler.HandleFocusChangedEvent(sender)?
        };
        Ok(())
    }
}

impl From<IUIAutomationFocusChangedEventHandler> for UIFocusChangedEventHandler {
    fn from(handler: IUIAutomationFocusChangedEventHandler) -> Self {
        Self {
            handler
        }
    }
}

impl From<&IUIAutomationFocusChangedEventHandler> for UIFocusChangedEventHandler {
    fn from(value: &IUIAutomationFocusChangedEventHandler) -> Self {
        value.clone().into()
    }
}

impl Into<IUIAutomationFocusChangedEventHandler> for UIFocusChangedEventHandler {
    fn into(self) -> IUIAutomationFocusChangedEventHandler {
        self.handler
    }
}

impl AsRef<IUIAutomationFocusChangedEventHandler> for UIFocusChangedEventHandler {
    fn as_ref(&self) -> &IUIAutomationFocusChangedEventHandler {
        &self.handler
    }
}

impl Param<IUIAutomationFocusChangedEventHandler> for UIFocusChangedEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationFocusChangedEventHandler> { unsafe {
        self.handler.param()
    }}
}

impl Param<IUIAutomationFocusChangedEventHandler> for &UIFocusChangedEventHandler {
    unsafe fn param(self) -> windows::core::ParamValue<IUIAutomationFocusChangedEventHandler> { unsafe {
        (&self.handler).param()
    }}
}

/// Defines a custom handler for `IUIAutomationEventHandler`.
pub trait CustomEventHandler {
    fn handle(&self, sender: &UIElement, event_type: UIEventType) -> Result<()>;
}

impl <T> From<T> for UIEventHandler where T: CustomEventHandler + 'static {
    fn from(value: T) -> Self {
        let handler = handlers::AutomationEventHandler::from(value);
        let handler: IUIAutomationEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler function for `IUIAutomationEventHandler`.
pub type CustomEventHandlerFn = dyn Fn(&UIElement, UIEventType) -> Result<()>;

impl From<Box<CustomEventHandlerFn>> for UIEventHandler {
    fn from(value: Box<CustomEventHandlerFn>) -> Self {
        let handler = functions::AutomationEventHandler::from(value);
        let handler: IUIAutomationEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler for `IUIAutomationPropertyChangedEventHandler`.
pub trait CustomPropertyChangedEventHandler {
    fn handle(&self, sender: &UIElement, property: UIProperty, new_value: Variant) -> Result<()>;
}

impl <T> From<T> for UIPropertyChangedEventHandler where T: CustomPropertyChangedEventHandler + 'static {
    fn from(value: T) -> Self {
        let handler = handlers::AutomationPropertyChangedHandler::from(value);
        let handler: IUIAutomationPropertyChangedEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler function for `IUIAutomationPropertyChangedEventHandler`.
pub type CustomPropertyChangedEventHandlerFn = dyn Fn(&UIElement, UIProperty, Variant) -> Result<()>;

impl From<Box<CustomPropertyChangedEventHandlerFn>> for UIPropertyChangedEventHandler {
    fn from(value: Box<CustomPropertyChangedEventHandlerFn>) -> Self {
        let handler = functions::AutomationPropertyChangedEventHandler::from(value);
        let handler: IUIAutomationPropertyChangedEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler for `IUIAutomationStructureChangedEventHandler`.
pub trait CustomStructureChangedEventHandler {
    fn handle(&self, sender: &UIElement, change_type: StructureChangeType, runtime_id: Option<&[i32]>) -> Result<()>;
}

impl <T> From<T> for UIStructureChangeEventHandler where T: CustomStructureChangedEventHandler + 'static {
    fn from(value: T) -> Self {
        let handler = handlers::AutomationStructureChangedEventHandler::from(value);
        let handler: IUIAutomationStructureChangedEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler function for `IUIAutomationStructureChangedEventHandler`.
pub type CustomStructureChangedEventHandlerFn = dyn Fn(&UIElement, StructureChangeType, Option<&[i32]>) -> Result<()>;

impl From<Box<CustomStructureChangedEventHandlerFn>> for UIStructureChangeEventHandler {
    fn from(value: Box<CustomStructureChangedEventHandlerFn>) -> Self {
        let handler = functions::AutomationStructureChangedEventHandler::from(value);
        let handler: IUIAutomationStructureChangedEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler for `IUIAutomationFocusChangedEventHandler`.
pub trait CustomFocusChangedEventHandler {
    fn handle(&self, sender: &UIElement) -> Result<()>;
}

impl <T> From<T> for UIFocusChangedEventHandler where T: CustomFocusChangedEventHandler + 'static {
    fn from(value: T) -> Self {
        let handler = handlers::AutomationFocusChangedEventHandler::from(value);
        let handler: IUIAutomationFocusChangedEventHandler = handler.into();
        handler.into()
    }
}

/// Defines a custom handler function for `IUIAutomationFocusChangedEventHandler`.
pub type CustomFocusChangedEventHandlerFn = dyn Fn(&UIElement) -> Result<()>;

impl From<Box<CustomFocusChangedEventHandlerFn>> for UIFocusChangedEventHandler {
    fn from(value: Box<CustomFocusChangedEventHandlerFn>) -> Self {
        let handler = functions::AutomationFocusChangedEventHandler::from(value);
        let handler: IUIAutomationFocusChangedEventHandler = handler.into();
        handler.into()
    }
}

#[cfg(test)]
mod tests {
    use windows::Win32::UI::Accessibility::UIA_DropTarget_DroppedEventId;

    use crate::types::TreeScope;
    use crate::UIAutomation;

    use super::CustomEventHandler;
    use super::CustomEventHandlerFn;
    use super::UIEventHandler;
    use super::UIEventType;

    #[test]
    fn test_uievent_types() {
        let t = UIEventType::try_from(UIA_DropTarget_DroppedEventId.0).unwrap();
        assert_eq!(t, UIEventType::DropTarget_Dropped);
    }

    struct MyEventHandler {
    }

    impl CustomEventHandler for MyEventHandler {
        fn handle(&self, sender: &crate::UIElement, event_type: UIEventType) -> crate::Result<()> {
            println!("event: {:?}, element: {}", event_type, sender);
            Ok(())
        }
    }

    #[test]
    fn test_event_handler_trait() {
        let automation = UIAutomation::new().unwrap();

        let root = automation.get_root_element().unwrap();

        let handler = UIEventHandler::from(MyEventHandler {});
        automation.add_automation_event_handler(UIEventType::TextEdit_TextChanged, &root, TreeScope::Subtree, None, &handler).unwrap();
        automation.remove_automation_event_handler(UIEventType::TextEdit_TextChanged, &root, &handler).unwrap();

        let handle_fn: Box<CustomEventHandlerFn> = Box::new(|sender, event_type| {
            println!("event: {:?}, element: {}", event_type, sender);
            Ok(())
        });

        let handler = UIEventHandler::from(handle_fn);
        automation.add_automation_event_handler(UIEventType::Text_TextChanged, &root, TreeScope::Subtree, None, &handler).unwrap();
        automation.remove_automation_event_handler(UIEventType::Text_TextChanged, &root, &handler).unwrap();
    }
}