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;
#[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 {
ToolTipOpened = 20000i32,
ToolTipClosed = 20001i32,
StructureChanged = 20002i32,
MenuOpened = 20003i32,
AutomationPropertyChanged = 20004i32,
AutomationFocusChanged = 20005i32,
AsyncContentLoaded = 20006i32,
MenuClosed = 20007i32,
LayoutInvalidated = 20008i32,
Invoke_Invoked = 20009i32,
SelectionItem_ElementAddedToSelection = 20010i32,
SelectionItem_ElementRemovedFromSelection = 20011i32,
SelectionItem_ElementSelected = 20012i32,
Selection_Invalidated = 20013i32,
Text_TextSelectionChanged = 20014i32,
Text_TextChanged = 20015i32,
Window_WindowOpened = 20016i32,
Window_WindowClosed = 20017i32,
MenuModeStart = 20018i32,
MenuModeEnd = 20019i32,
InputReachedTarget = 20020i32,
InputReachedOtherElement = 20021i32,
InputDiscarded = 20022i32,
SystemAlert = 20023i32,
LiveRegionChanged = 20024i32,
HostedFragmentRootsInvalidated = 20025i32,
Drag_DragStart = 20026i32,
Drag_DragCancel = 20027i32,
Drag_DragComplete = 20028i32,
DropTarget_DragEnter = 20029i32,
DropTarget_DragLeave = 20030i32,
DropTarget_Dropped = 20031i32,
TextEdit_TextChanged = 20032i32,
TextEdit_ConversionTargetChanged = 20033i32,
Changes = 20034i32,
Notification = 20035i32,
ActiveTextPositionChanged = 20036i32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIEventHandler {
handler: IUIAutomationEventHandler
}
impl UIEventHandler {
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()
}}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIPropertyChangedEventHandler {
handler: IUIAutomationPropertyChangedEventHandler
}
impl UIPropertyChangedEventHandler {
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()
}}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIStructureChangeEventHandler {
handler: IUIAutomationStructureChangedEventHandler
}
impl UIStructureChangeEventHandler {
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()
}}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UIFocusChangedEventHandler {
handler: IUIAutomationFocusChangedEventHandler
}
impl UIFocusChangedEventHandler {
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()
}}
}
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()
}
}
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()
}
}
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()
}
}
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()
}
}
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()
}
}
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()
}
}
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()
}
}
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();
}
}