1use std::{
15 fmt::{Debug, Display, Formatter},
16 sync::Weak,
17};
18
19use windows::{
20 core::BSTR,
21 Win32::{
22 Foundation::{HWND, RECT},
23 UI::Accessibility::{
24 IUIAutomation6, IUIAutomationElement, IUIAutomationElementArray, TreeScope_Children,
25 UIA_AppBarControlTypeId, UIA_ButtonControlTypeId, UIA_CalendarControlTypeId,
26 UIA_CheckBoxControlTypeId, UIA_ComboBoxControlTypeId, UIA_CustomControlTypeId,
27 UIA_DataGridControlTypeId, UIA_DataItemControlTypeId, UIA_DocumentControlTypeId,
28 UIA_EditControlTypeId, UIA_GroupControlTypeId, UIA_HeaderControlTypeId,
29 UIA_HeaderItemControlTypeId, UIA_HyperlinkControlTypeId, UIA_ImageControlTypeId,
30 UIA_ListControlTypeId, UIA_ListItemControlTypeId, UIA_MenuBarControlTypeId,
31 UIA_MenuControlTypeId, UIA_MenuItemControlTypeId, UIA_PaneControlTypeId,
32 UIA_ProgressBarControlTypeId, UIA_RadioButtonControlTypeId, UIA_ScrollBarControlTypeId,
33 UIA_SemanticZoomControlTypeId, UIA_SeparatorControlTypeId, UIA_SliderControlTypeId,
34 UIA_SpinnerControlTypeId, UIA_SplitButtonControlTypeId, UIA_StatusBarControlTypeId,
35 UIA_TabControlTypeId, UIA_TabItemControlTypeId, UIA_TableControlTypeId,
36 UIA_TextControlTypeId, UIA_ThumbControlTypeId, UIA_TitleBarControlTypeId,
37 UIA_ToolBarControlTypeId, UIA_ToolTipControlTypeId, UIA_TreeControlTypeId,
38 UIA_TreeItemControlTypeId, UIA_WindowControlTypeId, UIA_CONTROLTYPE_ID,
39 },
40 },
41};
42
43use crate::{common::Result, ext::VecExt};
44
45#[derive(Clone)]
47pub struct UiAutomationElement {
48 _automation: Weak<IUIAutomation6>,
49 _current: IUIAutomationElement,
50}
51
52impl UiAutomationElement {
53 pub(crate) fn get_raw(&self) -> &IUIAutomationElement {
57 &self._current
58 }
59 pub fn get_aut(&self) -> Weak<IUIAutomation6> {
60 self._automation.clone()
61 }
62
63 pub(crate) fn get_aut_ref(&self) -> &IUIAutomation6 {
64 unsafe { &*self._automation.as_ptr() }
65 }
66
67 pub(crate) fn obtain(automation: Weak<IUIAutomation6>, element: IUIAutomationElement) -> Self {
68 Self {
69 _automation: automation,
70 _current: element,
71 }
72 }
73
74 pub fn get_name(&self) -> String {
79 unsafe { self._current.CurrentName() }
80 .unwrap_or(BSTR::new())
82 .to_string()
83 }
84
85 pub fn get_localized_control_type(&self) -> String {
89 unsafe { self._current.CurrentLocalizedControlType() }
90 .unwrap_or(BSTR::new())
91 .to_string()
92 }
93
94 pub fn native_window_handle(&self) -> HWND {
98 unsafe { self._current.CurrentNativeWindowHandle() }.unwrap_or(HWND::default())
99 }
100
101 pub fn get_parent(&self) -> Result<UiAutomationElement> {
105 match unsafe { self._current.GetCachedParent() } {
106 Ok(p) => Ok(UiAutomationElement::obtain(self._automation.clone(), p)),
107 Err(e) => Err(e),
108 }
109 }
110
111 pub fn get_control_type(&self) -> ControlType {
115 unsafe {
116 match self._current.CurrentControlType() {
117 Ok(x) => ControlType::from(x),
118 Err(_) => ControlType::Custom,
119 }
120 }
121 }
122
123 pub fn get_supported_patterns(&self) -> Result<(Vec<i32>, Vec<String>)> {
127 unsafe {
128 let (mut ids, mut names) = std::mem::zeroed();
129 if let Err(e) = self.get_aut_ref().PollForPotentialSupportedPatterns(
130 &self._current,
131 &mut ids,
132 &mut names,
133 ) {
134 return Err(e);
135 }
136 let names: Vec<BSTR> = names.to_vec();
137 Ok((ids.to_vec(), names.iter().map(|i| i.to_string()).collect()))
138 }
139 }
140
141 pub fn get_provider_description(&self) -> String {
145 unsafe { self._current.CurrentProviderDescription() }
146 .unwrap_or(BSTR::new())
147 .to_string()
148 }
149
150 pub fn get_child_count(&self) -> i32 {
154 if let Ok(children) = unsafe {
155 self._current.FindAll(
156 TreeScope_Children,
157 &self.get_aut_ref().CreateTrueCondition().unwrap(),
158 )
159 } {
160 return unsafe { children.Length() }.unwrap();
161 }
162 0
163 }
164
165 pub fn get_child(&self, index: i32) -> Option<UiAutomationElement> {
170 if let Ok(children) = unsafe {
171 self._current.FindAll(
172 TreeScope_Children,
173 &self.get_aut_ref().CreateTrueCondition().unwrap(),
174 )
175 } {
176 if let Ok(el) = unsafe { children.GetElement(index) } {
177 return Some(UiAutomationElement::obtain(self._automation.clone(), el));
178 }
179 }
180 None
181 }
182
183 pub fn get_bounding_rectangle(&self) -> RECT {
187 unsafe { self._current.CurrentBoundingRectangle() }
188 .expect("Can't get the location of element.")
189 }
190
191 pub fn get_automation_id(&self) -> String {
195 unsafe { self._current.CurrentAutomationId() }
196 .unwrap_or(BSTR::new())
197 .to_string()
198 }
199
200 #[allow(dead_code)]
204 pub fn get_class_name(&self) -> String {
205 unsafe { self._current.CurrentClassName() }
206 .unwrap_or(BSTR::new())
207 .to_string()
208 }
209
210 pub fn get_item_status(&self) -> String {
214 unsafe { self._current.CurrentItemStatus() }
215 .unwrap_or(BSTR::new())
216 .to_string()
217 }
218
219 pub fn get_accelerator_key(&self) -> String {
223 unsafe { self._current.CurrentAcceleratorKey() }
224 .unwrap_or(BSTR::new())
225 .to_string()
226 }
227
228 pub fn get_access_key(&self) -> String {
232 unsafe { self._current.CurrentAccessKey() }
233 .unwrap_or(BSTR::new())
234 .to_string()
235 }
236}
237
238unsafe impl Send for UiAutomationElement {}
239
240unsafe impl Sync for UiAutomationElement {}
241
242impl Debug for UiAutomationElement {
243 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
244 Display::fmt(self, f)
245 }
246}
247
248impl Display for UiAutomationElement {
249 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
250 write!(f, "UiAutomationElement(name:{})", self.get_name())
251 }
252}
253
254impl VecExt<IUIAutomationElement> for &IUIAutomationElementArray {
255 fn to_vec(self) -> Vec<IUIAutomationElement> {
256 unsafe {
257 let mut v = vec![];
258 for i in 0..self.Length().unwrap() {
259 v.push(self.GetElement(i).unwrap());
260 }
261 v
262 }
263 }
264}
265
266#[derive(PartialEq)]
267pub enum ControlType {
268 AppBar,
269 Button,
270 Calendar,
271 CheckBox,
272 ComboBox,
273 Custom,
274 DataGrid,
275 DataItem,
276 Document,
277 Edit,
278 Group,
279 Header,
280 HeaderItem,
281 Hyperlink,
282 Image,
283 List,
284 ListItem,
285 MenuBar,
286 Menu,
287 MenuItem,
288 Pane,
289 ProgressBar,
290 RadioButton,
291 ScrollBar,
292 SemanticZoom,
293 Separator,
294 Slider,
295 Spinner,
296 SplitButton,
297 StatusBar,
298 Tab,
299 TabItem,
300 Table,
301 Text,
302 Thumb,
303 TitleBar,
304 ToolBar,
305 ToolTip,
306 Tree,
307 TreeItem,
308 Window,
309}
310
311impl From<UIA_CONTROLTYPE_ID> for ControlType {
312 #[allow(non_upper_case_globals)]
313 fn from(value: UIA_CONTROLTYPE_ID) -> Self {
314 match value {
315 UIA_AppBarControlTypeId => Self::AppBar,
316 UIA_ButtonControlTypeId => Self::Button,
317 UIA_CalendarControlTypeId => Self::Calendar,
318 UIA_CheckBoxControlTypeId => Self::CheckBox,
319 UIA_ComboBoxControlTypeId => Self::ComboBox,
320 UIA_CustomControlTypeId => Self::Custom,
321 UIA_DataGridControlTypeId => Self::DataGrid,
322 UIA_DataItemControlTypeId => Self::DataItem,
323 UIA_DocumentControlTypeId => Self::Document,
324 UIA_EditControlTypeId => Self::Edit,
325 UIA_GroupControlTypeId => Self::Group,
326 UIA_HeaderControlTypeId => Self::Header,
327 UIA_HeaderItemControlTypeId => Self::HeaderItem,
328 UIA_HyperlinkControlTypeId => Self::Hyperlink,
329 UIA_ImageControlTypeId => Self::Image,
330 UIA_ListControlTypeId => Self::List,
331 UIA_ListItemControlTypeId => Self::ListItem,
332 UIA_MenuBarControlTypeId => Self::MenuBar,
333 UIA_MenuControlTypeId => Self::Menu,
334 UIA_MenuItemControlTypeId => Self::MenuItem,
335 UIA_PaneControlTypeId => Self::Pane,
336 UIA_ProgressBarControlTypeId => Self::ProgressBar,
337 UIA_RadioButtonControlTypeId => Self::RadioButton,
338 UIA_ScrollBarControlTypeId => Self::ScrollBar,
339 UIA_SemanticZoomControlTypeId => Self::SemanticZoom,
340 UIA_SeparatorControlTypeId => Self::Separator,
341 UIA_SliderControlTypeId => Self::Slider,
342 UIA_SpinnerControlTypeId => Self::Spinner,
343 UIA_SplitButtonControlTypeId => Self::SplitButton,
344 UIA_StatusBarControlTypeId => Self::StatusBar,
345 UIA_TabControlTypeId => Self::Tab,
346 UIA_TabItemControlTypeId => Self::TabItem,
347 UIA_TableControlTypeId => Self::Table,
348 UIA_TextControlTypeId => Self::Text,
349 UIA_ThumbControlTypeId => Self::Thumb,
350 UIA_TitleBarControlTypeId => Self::TitleBar,
351 UIA_ToolBarControlTypeId => Self::ToolBar,
352 UIA_ToolTipControlTypeId => Self::ToolTip,
353 UIA_TreeControlTypeId => Self::Tree,
354 UIA_TreeItemControlTypeId => Self::TreeItem,
355 UIA_WindowControlTypeId => Self::Window,
356 _ => Self::Custom,
357 }
358 }
359}