win_wrap/uia/
automation.rs

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
/*
 * Copyright (c) 2024. The RigelA open source project team and
 * its contributors reserve all rights.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

use crate::{
    common::Result,
    msaa::object::AccessibleObject,
    uia::{
        element::UiAutomationElement,
        event::{OnFocusChangedCallback, UiAutomationEventHandlerGroup},
    },
};
use std::sync::Arc;
use windows::Win32::{
    Foundation::{HWND, POINT},
    System::Com::{CoCreateInstance, CLSCTX_ALL},
    UI::Accessibility::{CUIAutomation8, IUIAutomation6, IUIAutomationFocusChangedEventHandler},
};

/// UIAutomation接口本地封装
#[derive(Clone, Debug)]
pub struct UiAutomation(Arc<IUIAutomation6>);

impl UiAutomation {
    /**
    创建一个UiAutomation对象。
    */
    pub fn new() -> Self {
        let automation =
            unsafe { CoCreateInstance::<_, IUIAutomation6>(&CUIAutomation8, None, CLSCTX_ALL) }
                .expect("Can't create the ui automation.");
        UiAutomation {
            0: automation.into(),
        }
    }

    /**
    从MSAA的Accessible对象获取UI元素。
    `obj` 一个MSAA的Accessible对象。
    */
    pub fn get_element_from_accessible_object(
        &self,
        obj: &AccessibleObject,
    ) -> Result<UiAutomationElement> {
        let element = match unsafe {
            self.0
                .ElementFromIAccessible(obj.get_raw(), obj.get_child_id())
        } {
            Ok(o) => o,
            Err(e) => return Err(e),
        };
        Ok(UiAutomationElement::obtain(
            Arc::downgrade(&self.0),
            element,
        ))
    }

    /**
    获取UI根元素。
    */
    pub fn get_root_element(&self) -> UiAutomationElement {
        let el = unsafe { self.0.GetRootElement() }.expect("Can't get the root element.");
        UiAutomationElement::obtain(Arc::downgrade(&self.0), el)
    }

    /**
    获取UI焦点元素。
    */
    pub fn get_focused_element(&self) -> Result<UiAutomationElement> {
        let el = match unsafe { self.0.GetFocusedElement() } {
            Err(e) => return Err(e),
            Ok(o) => o,
        };
        Ok(UiAutomationElement::obtain(Arc::downgrade(&self.0), el))
    }

    /// 根据窗口句柄获取ui元素
    pub fn element_from_handle(&self, h_wnd: HWND) -> Option<UiAutomationElement> {
        let el = unsafe { self.0.ElementFromHandle(h_wnd) };
        if el.is_err() {
            return None;
        }
        Some(UiAutomationElement::obtain(
            Arc::downgrade(&self.0),
            el.unwrap(),
        ))
    }

    /// 根据坐标获取ui元素
    pub fn element_from_point(&self, x: i32, y: i32) -> Option<UiAutomationElement> {
        let el = unsafe {
            self.0
                .ElementFromPoint(POINT { x, y })
                .expect("Can't get the element from point.")
        };
        Some(UiAutomationElement::obtain(Arc::downgrade(&self.0), el))
    }

    /**
    创建事件处理器组。
    */
    pub fn create_event_handler_group(&self) -> UiAutomationEventHandlerGroup {
        unsafe {
            UiAutomationEventHandlerGroup::obtain(
                Arc::downgrade(&self.0),
                &self.0.CreateEventHandlerGroup().unwrap(),
            )
        }
    }

    /**
    添加事件处理器组,以便于处理各种事件。
    `element` 要监听的元素。
    `group` 通过调用create_event_handler_group函数返回的事件处理器组。
    */
    pub fn add_event_handler_group(
        &self,
        element: &UiAutomationElement,
        group: &UiAutomationEventHandlerGroup,
    ) -> Result<()> {
        unsafe {
            self.0
                .AddEventHandlerGroup(element.get_raw(), group.get_raw())
        }
    }

    /**
    注册一个焦点改变时的通知函数。
    处理函数运行在单独的子线程中。
    `func` 用于接收事件的函数。
    */
    pub fn add_focus_changed_listener<CB>(&self, func: CB)
    where
        CB: Fn(UiAutomationElement) -> () + 'static,
    {
        let handler: IUIAutomationFocusChangedEventHandler =
            OnFocusChangedCallback::new(func, Arc::downgrade(&self.0)).into();
        unsafe { self.0.AddFocusChangedEventHandler(None, &handler) }
            .expect("Can't add the focus changed listener.")
    }

    /**
    移除已经注册的所有监听器。
    */
    pub fn remove_all_event_listeners(&self) {
        unsafe { self.0.RemoveAllEventHandlers() }.unwrap_or(());
    }

    /**
    移除一个事件处理器组。
    `group` 一个事件处理器组对象的引用。
    */
    pub fn remove_event_handler_group(
        &self,
        element: &UiAutomationElement,
        group: &UiAutomationEventHandlerGroup,
    ) {
        unsafe {
            self.0
                .RemoveEventHandlerGroup(element.get_raw(), group.get_raw())
        }
        .unwrap_or(())
    }
}

unsafe impl Sync for UiAutomation {}

unsafe impl Send for UiAutomation {}