From bf42bbfc5d477955370d42bb02979341fb569929 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Sun, 14 Apr 2024 21:17:02 +0800 Subject: [PATCH] support cache request --- CHANGELOG.md | 4 + crates/uiautomation/Cargo.toml | 2 +- crates/uiautomation/src/core.rs | 318 +++++++++++++++++++++++++++++++- 3 files changed, 317 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ace367..be40d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,3 +122,7 @@ ## v0.8.3 + update to `windows v0.56.0` + +## v0.9.0 + ++ support cache request. diff --git a/crates/uiautomation/Cargo.toml b/crates/uiautomation/Cargo.toml index 9e4f1f7..d83a965 100644 --- a/crates/uiautomation/Cargo.toml +++ b/crates/uiautomation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uiautomation" -version = "0.8.3" +version = "0.9.0" edition = "2021" license = "Apache-2.0" authors = ["Steven Lee "] diff --git a/crates/uiautomation/src/core.rs b/crates/uiautomation/src/core.rs index 45a5841..0af8fac 100644 --- a/crates/uiautomation/src/core.rs +++ b/crates/uiautomation/src/core.rs @@ -335,6 +335,14 @@ pub struct UIElement { } impl UIElement { + /// Retrieves a new UI Automation element with an updated cache. + pub fn build_updated_cache(&self, cache_request: &UICacheRequest) -> Result { + let element = unsafe { + self.element.BuildUpdatedCache(cache_request)? + }; + Ok(element.into()) + } + /// Retrieves the first child or descendant element that matches the specified condition. pub fn find_first(&self, scope: TreeScope, condition: &UICondition) -> Result { let result = unsafe { @@ -343,6 +351,14 @@ impl UIElement { Ok(result.into()) } + /// Retrieves the first child or descendant element that matches the specified condition, prefetches the requested properties and control patterns, and stores the prefetched items in the cache. + pub fn find_first_build_cache(&self, scope: TreeScope, condition: &UICondition, cache_request: &UICacheRequest) -> Result { + let element = unsafe { + self.element.FindFirstBuildCache(scope.into(), condition, cache_request)? + }; + Ok(element.into()) + } + /// Returns all UI Automation elements that satisfy the specified condition. pub fn find_all(&self, scope: TreeScope, condition: &UICondition) -> Result> { let elements = unsafe { @@ -351,6 +367,14 @@ impl UIElement { Self::to_elements(elements) } + /// Returns all UI Automation elements that satisfy the specified condition, prefetches the requested properties and control patterns, and stores the prefetched items in the cache. + pub fn find_all_build_cache(&self, scope: TreeScope, condition: &UICondition, cache_request: &UICacheRequest) -> Result> { + let elements = unsafe { + self.element.FindAllBuildCache(scope.into(), condition, cache_request)? + }; + Self::to_elements(elements) + } + /// Receives the runtime ID as a vec of integers. pub fn get_runtime_id(&self) -> Result> { let id = unsafe { @@ -370,6 +394,14 @@ impl UIElement { Ok(name.to_string()) } + /// Retrieves the cached name of the element. + pub fn get_cached_name(&self) -> Result { + let name = unsafe { + self.element.CachedName()? + }; + Ok(name.to_string()) + } + /// Retrieves the Microsoft UI Automation identifier of the element. pub fn get_automation_id(&self) -> Result { let automation_id = unsafe { @@ -379,6 +411,14 @@ impl UIElement { Ok(automation_id.to_string()) } + /// Retrieves the cached Microsoft UI Automation identifier of the element. + pub fn get_cached_automation_id(&self) -> Result { + let automation_id = unsafe { + self.element.CachedAutomationId()? + }; + Ok(automation_id.to_string()) + } + /// Retrieves the identifier of the process that hosts the element. pub fn get_process_id(&self) -> Result { let id = unsafe { @@ -388,6 +428,14 @@ impl UIElement { Ok(id) } + /// Retrieves the cached ID of the process that hosts the element. + pub fn get_cached_process_id(&self) -> Result { + let id = unsafe { + self.element.CachedProcessId()? + }; + Ok(id) + } + /// Retrieves the class name of the element. pub fn get_classname(&self) -> Result { let classname = unsafe { @@ -397,6 +445,14 @@ impl UIElement { Ok(classname.to_string()) } + /// Retrieves the cached class name of the element. + pub fn get_cached_classname(&self) -> Result { + let classname = unsafe { + self.element.CachedClassName()? + }; + Ok(classname.to_string()) + } + /// Retrieves the control type of the element. pub fn get_control_type(&self) -> Result { let control_type = unsafe { @@ -406,6 +462,14 @@ impl UIElement { Ok(ControlType::from(control_type)) } + /// Retrieves the cached control type of the element. + pub fn get_cached_control_type(&self) -> Result { + let control_type = unsafe { + self.element.CachedControlType()? + }; + Ok(control_type.into()) + } + /// Retrieves a localized description of the control type of the element. pub fn get_localized_control_type(&self) -> Result { let control_type = unsafe { @@ -415,6 +479,14 @@ impl UIElement { Ok(control_type.to_string()) } + /// Retrieves cached localized description of the control type of the element. + pub fn get_cached_localized_control_type(&self) -> Result { + let control_type = unsafe { + self.element.CachedLocalizedControlType()? + }; + Ok(control_type.to_string()) + } + /// Retrieves the accelerator key for the element. pub fn get_accelerator_key(&self) -> Result { let accelerator_key = unsafe { @@ -424,6 +496,15 @@ impl UIElement { Ok(accelerator_key.to_string()) } + /// Retrieves the cached accelerator key for the element. + pub fn get_cached_accelerator_key(&self) -> Result { + let accelerator_key = unsafe { + self.element.CachedAcceleratorKey()? + }; + + Ok(accelerator_key.to_string()) + } + /// Retrieves the access key character for the element. pub fn get_access_key(&self) -> Result { let access_key = unsafe { @@ -433,6 +514,15 @@ impl UIElement { Ok(access_key.to_string()) } + /// Retrieves the cached access key character for the element. + pub fn get_cached_access_key(&self) -> Result { + let access_key = unsafe { + self.element.CachedAccessKey()? + }; + + Ok(access_key.to_string()) + } + /// Indicates whether the element has keyboard focus. pub fn has_keyboard_focus(&self) -> Result { let has_focus = unsafe { @@ -442,6 +532,15 @@ impl UIElement { Ok(has_focus.as_bool()) } + /// A cached value that indicates whether the element has keyboard focus. + pub fn has_cached_keyboard_focus(&self) -> Result { + let has_focus = unsafe { + self.element.CachedHasKeyboardFocus()? + }; + + Ok(has_focus.as_bool()) + } + /// Indicates whether the element can accept keyboard focus. pub fn is_keyboard_focusable(&self) -> Result { let focusable = unsafe { @@ -451,6 +550,15 @@ impl UIElement { Ok(focusable.as_bool()) } + /// A cached value that indicates whether the element can accept keyboard focus. + pub fn is_cached_keyboard_focusable(&self) -> Result { + let focusable = unsafe { + self.element.CachedIsKeyboardFocusable()? + }; + + Ok(focusable.as_bool()) + } + /// Indicates whether the element is enabled. pub fn is_enabled(&self) -> Result { let enabled = unsafe { @@ -460,6 +568,15 @@ impl UIElement { Ok(enabled.as_bool()) } + /// A cached value that indicates whether the element is enabled. + pub fn is_cached_enabled(&self) -> Result { + let enabled = unsafe { + self.element.CachedIsEnabled()? + }; + + Ok(enabled.as_bool()) + } + /// Retrieves the help text for the element. pub fn get_help_text(&self) -> Result { let text = unsafe { @@ -469,6 +586,15 @@ impl UIElement { Ok(text.to_string()) } + /// Retrieves the cached help text for the element. + pub fn get_cached_help_text(&self) -> Result { + let text = unsafe { + self.element.CachedHelpText()? + }; + + Ok(text.to_string()) + } + /// Retrieves the culture identifier for the element. pub fn get_culture(&self) -> Result { let culture = unsafe { @@ -478,6 +604,15 @@ impl UIElement { Ok(culture) } + /// Retrieves the cached culture identifier for the element. + pub fn get_cached_culture(&self) -> Result { + let culture = unsafe { + self.element.CachedCulture()? + }; + + Ok(culture) + } + /// Indicates whether the element is a control element. pub fn is_control_element(&self) -> Result { let is_control = unsafe { @@ -487,6 +622,15 @@ impl UIElement { Ok(is_control.as_bool()) } + /// A cached value that indicates whether the element is a control element. + pub fn is_cached_control_element(&self) -> Result { + let is_control = unsafe { + self.element.CachedIsControlElement()? + }; + + Ok(is_control.as_bool()) + } + /// Indicates whether the element is a content element. pub fn is_content_element(&self) -> Result { let is_content = unsafe { @@ -496,6 +640,15 @@ impl UIElement { Ok(is_content.as_bool()) } + /// A cached value that indicates whether the element is a content element. + pub fn is_cached_content_element(&self) -> Result { + let is_content = unsafe { + self.element.CachedIsContentElement()? + }; + + Ok(is_content.as_bool()) + } + /// Indicates whether the element contains a disguised password. pub fn is_password(&self) -> Result { let is_password = unsafe { @@ -505,6 +658,15 @@ impl UIElement { Ok(is_password.as_bool()) } + /// A cached value that indicates whether the element contains a disguised password. + pub fn is_cached_password(&self) -> Result { + let is_password = unsafe { + self.element.CachedIsPassword()? + }; + + Ok(is_password.as_bool()) + } + /// Retrieves the window handle of the element. pub fn get_native_window_handle(&self) -> Result { let handle = unsafe { @@ -514,6 +676,15 @@ impl UIElement { Ok(handle.into()) } + /// Retrieves the cached window handle of the element. + pub fn get_cached_native_window_handle(&self) -> Result { + let handle = unsafe { + self.element.CachedNativeWindowHandle()? + }; + + Ok(handle.into()) + } + /// Retrieves a description of the type of UI item represented by the element. pub fn get_item_type(&self) -> Result { let item_type = unsafe { @@ -523,6 +694,15 @@ impl UIElement { Ok(item_type.to_string()) } + /// Retrieves a cached description of the type of UI item represented by the element. + pub fn get_cached_item_type(&self) -> Result { + let item_type = unsafe { + self.element.CachedItemType()? + }; + + Ok(item_type.to_string()) + } + /// Indicates whether the element is off-screen. pub fn is_offscreen(&self) -> Result { let off_screen = unsafe { @@ -532,6 +712,15 @@ impl UIElement { Ok(off_screen.as_bool()) } + /// A cached value that indicates whether the element is off-screen. + pub fn is_cached_offscreen(&self) -> Result { + let off_screen = unsafe { + self.element.CachedIsOffscreen()? + }; + + Ok(off_screen.as_bool()) + } + /// Retrieves a value that indicates the orientation of the element. pub fn get_orientation(&self) -> Result { let orientation = unsafe { @@ -541,6 +730,15 @@ impl UIElement { Ok(orientation.into()) } + /// Retrieves a cached value that indicates the orientation of the element. + pub fn get_cached_orientation(&self) -> Result { + let orientation = unsafe { + self.element.CachedOrientation()? + }; + + Ok(orientation.into()) + } + /// Retrieves the name of the underlying UI framework. pub fn get_framework_id(&self) -> Result { let id = unsafe { @@ -550,6 +748,15 @@ impl UIElement { Ok(id.to_string()) } + /// Retrieves the cached name of the underlying UI framework. + pub fn get_cached_framework_id(&self) -> Result { + let id = unsafe { + self.element.CachedFrameworkId()? + }; + + Ok(id.to_string()) + } + /// Indicates whether the element is required to be filled out on a form. pub fn is_required_for_form(&self) -> Result { let required = unsafe { @@ -559,6 +766,15 @@ impl UIElement { Ok(required.as_bool()) } + /// A cached value that indicates whether the element is required to be filled out on a form. + pub fn is_cached_required_for_form(&self) -> Result { + let required = unsafe { + self.element.CachedIsRequiredForForm()? + }; + + Ok(required.as_bool()) + } + /// Indicates whether the element contains valid data for a form. pub fn is_data_valid_for_form(&self) -> Result { let valid = unsafe { @@ -568,6 +784,15 @@ impl UIElement { Ok(valid.as_bool()) } + /// A cached value that indicates whether the element contains valid data for a form. + pub fn is_cached_data_valid_for_form(&self) -> Result { + let valid = unsafe { + self.element.CachedIsDataValidForForm()? + }; + + Ok(valid.as_bool()) + } + /// Retrieves the description of the status of an item in an element. pub fn get_item_status(&self) -> Result { let status = unsafe { @@ -577,6 +802,15 @@ impl UIElement { Ok(status.to_string()) } + /// Retrieves the cached description of the status of an item in an element. + pub fn get_cached_item_status(&self) -> Result { + let status = unsafe { + self.element.CachedItemStatus()? + }; + + Ok(status.to_string()) + } + /// Retrieves the coordinates of the rectangle that completely encloses the element. pub fn get_bounding_rectangle(&self) -> Result { let rect = unsafe { @@ -586,6 +820,15 @@ impl UIElement { Ok(rect.into()) } + /// Retrieves the cached coordinates of the rectangle that completely encloses the element. + pub fn get_cached_bounding_rectangle(&self) -> Result { + let rect = unsafe { + self.element.CachedBoundingRectangle()? + }; + + Ok(rect.into()) + } + /// Retrieves the element that contains the text label for this element. pub fn get_labeled_by(&self) -> Result { let labeled_by = unsafe { @@ -595,6 +838,15 @@ impl UIElement { Ok(UIElement::from(labeled_by)) } + /// Retrieves the cached element that contains the text label for this element. + pub fn get_cached_labeled_by(&self) -> Result { + let labeled_by = unsafe { + self.element.CachedLabeledBy()? + }; + + Ok(UIElement::from(labeled_by)) + } + /// Retrieves an array of elements for which this element serves as the controller. pub fn get_controller_for(&self) -> Result> { let elements = unsafe { @@ -604,6 +856,15 @@ impl UIElement { Self::to_elements(elements) } + /// Retrieves a cached array of elements for which this element serves as the controller. + pub fn get_cached_controller_for(&self) -> Result> { + let elements = unsafe { + self.element.CachedControllerFor()? + }; + + Self::to_elements(elements) + } + /// Retrieves an array of elements that describe this element. pub fn get_described_by(&self) -> Result> { let elements = unsafe { @@ -613,6 +874,15 @@ impl UIElement { Self::to_elements(elements) } + /// Retrieves a cached array of elements that describe this element. + pub fn get_cached_described_by(&self) -> Result> { + let elements = unsafe { + self.element.CachedDescribedBy()? + }; + + Self::to_elements(elements) + } + /// Retrieves an array of elements that indicates the reading order after the current element. pub fn get_flows_to(&self) -> Result> { let elements = unsafe { @@ -622,6 +892,15 @@ impl UIElement { Self::to_elements(elements) } + /// Retrieves a cached array of elements that indicates the reading order after the current element. + pub fn get_cached_flows_to(&self) -> Result> { + let elements = unsafe { + self.element.CachedFlowsTo()? + }; + + Self::to_elements(elements) + } + /// Retrieves a description of the provider for this element. pub fn get_provider_description(&self) -> Result { let descr = unsafe { @@ -631,6 +910,15 @@ impl UIElement { Ok(descr.to_string()) } + /// Retrieves a cached description of the provider for this element. + pub fn get_cached_provider_description(&self) -> Result { + let descr = unsafe { + self.element.CachedProviderDescription()? + }; + + Ok(descr.to_string()) + } + /// Sets the keyboard focus to this UI Automation element. pub fn set_focus(&self) -> Result<()> { unsafe { @@ -654,6 +942,15 @@ impl UIElement { T::try_from(pattern) } + /// Retrieves the cached control pattern interface of the specified pattern `` from this UI Automation element. + pub fn get_cached_pattern>(&self) -> Result { + let pattern = unsafe { + self.element.GetCachedPattern(T::TYPE.into())? + }; + + T::try_from(pattern) + } + /// Retrieves a point on the element that can be clicked. pub fn get_clickable_point(&self) -> Result> { let mut point = Point::default(); @@ -677,6 +974,15 @@ impl UIElement { Ok(value.into()) } + /// Retrieves the cached value of a property for this UI Automation element. + pub fn get_cached_property_value(&self, property: UIProperty) -> Result { + let value = unsafe { + self.element.GetCachedPropertyValue(property.into())? + }; + + Ok(value.into()) + } + /// Programmatically invokes a context menu on the target element. pub fn show_context_menu(&self) -> Result<()> { let element3: IUIAutomationElement3 = self.element.cast()?; @@ -1471,18 +1777,18 @@ impl AsRef for UICondition { } } -// impl IntoParam for UICondition { -// unsafe fn into_param(self) -> windows::core::Param { -// windows::core::Param::Owned(self.0) -// } -// } - impl Param for UICondition { unsafe fn param(self) -> windows::core::ParamValue { windows::core::ParamValue::Owned(self.0) } } +impl Param for &UICondition { + unsafe fn param(self) -> windows::core::ParamValue { + windows::core::ParamValue::Borrowed(self.0.as_raw()) + } +} + /// Represents a condition that can be either TRUE (selects all elements) or FALSE (selects no elements). #[derive(Debug, Clone)] pub struct UIBoolCondition(IUIAutomationBoolCondition);