#[cfg(feature = "ia2_lib")]
#[doc(hidden)]
pub(crate) mod ia2_lib;
pub mod object;
pub mod relation;
pub mod text;
use crate::ia2::{
ia2_lib::AccessibleEventID::IA2EventID::{
IA2_EVENT_ACTION_CHANGED, IA2_EVENT_ACTIVE_DESCENDANT_CHANGED,
IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED, IA2_EVENT_DOCUMENT_CONTENT_CHANGED,
IA2_EVENT_DOCUMENT_LOAD_COMPLETE, IA2_EVENT_DOCUMENT_LOAD_STOPPED,
IA2_EVENT_DOCUMENT_RELOAD, IA2_EVENT_HYPERLINK_END_INDEX_CHANGED,
IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED, IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED,
IA2_EVENT_HYPERLINK_START_INDEX_CHANGED, IA2_EVENT_HYPERTEXT_CHANGED,
IA2_EVENT_HYPERTEXT_LINK_ACTIVATED, IA2_EVENT_HYPERTEXT_LINK_SELECTED,
IA2_EVENT_HYPERTEXT_NLINKS_CHANGED, IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED,
IA2_EVENT_PAGE_CHANGED, IA2_EVENT_ROLE_CHANGED, IA2_EVENT_SECTION_CHANGED,
IA2_EVENT_TABLE_CAPTION_CHANGED, IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,
IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED, IA2_EVENT_TABLE_MODEL_CHANGED,
IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED, IA2_EVENT_TABLE_ROW_HEADER_CHANGED,
IA2_EVENT_TABLE_SUMMARY_CHANGED, IA2_EVENT_TEXT_ATTRIBUTE_CHANGED,
IA2_EVENT_TEXT_CARET_MOVED, IA2_EVENT_TEXT_COLUMN_CHANGED, IA2_EVENT_TEXT_INSERTED,
IA2_EVENT_TEXT_REMOVED, IA2_EVENT_TEXT_SELECTION_CHANGED, IA2_EVENT_TEXT_UPDATED,
IA2_EVENT_VISIBLE_DATA_CHANGED,
},
object::Accessible2Object,
text::AccessibleText,
};
use std::sync::RwLock;
use win_wrap::{
common::Result,
msaa::event::{WinEventHook, WinEventSource},
};
pub trait WinEventSourceExt {
fn get_object2(&self) -> Result<Accessible2Object>;
fn get_text(&self) -> Result<AccessibleText>;
}
impl WinEventSourceExt for WinEventSource {
fn get_object2(&self) -> Result<Accessible2Object> {
let obj = match self.get_object() {
Ok((obj, _)) => obj,
Err(e) => return Err(e),
};
Accessible2Object::from_accessible_object(obj)
}
fn get_text(&self) -> Result<AccessibleText> {
let obj = match self.get_object() {
Ok((obj, _)) => obj,
Err(e) => return Err(e),
};
AccessibleText::from_accessible_object(obj)
}
}
#[derive(Debug)]
pub struct Ia2 {
events: RwLock<Vec<WinEventHook>>,
}
impl Ia2 {
pub fn new() -> Self {
Self {
events: vec![].into(),
}
}
pub fn add_on_action_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_ACTION_CHANGED as u32, func));
}
pub fn add_on_active_descendant_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_ACTIVE_DESCENDANT_CHANGED as u32,
func,
));
}
pub fn add_on_document_attribute_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED as u32,
func,
));
}
pub fn add_on_document_content_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_DOCUMENT_CONTENT_CHANGED as u32,
func,
));
}
pub fn add_on_document_load_complete_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_DOCUMENT_LOAD_COMPLETE as u32,
func,
));
}
pub fn add_on_document_load_stopped_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_DOCUMENT_LOAD_STOPPED as u32,
func,
));
}
pub fn add_on_document_reload_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_DOCUMENT_RELOAD as u32, func));
}
pub fn add_on_hyperlink_end_index_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERLINK_END_INDEX_CHANGED as u32,
func,
));
}
pub fn add_on_hyperlink_number_of_anchors_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED as u32,
func,
));
}
pub fn add_on_hyperlink_selected_link_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED as u32,
func,
));
}
pub fn add_on_hypertext_link_activated_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERTEXT_LINK_ACTIVATED as u32,
func,
));
}
pub fn add_on_hypertext_link_selected_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERTEXT_LINK_SELECTED as u32,
func,
));
}
pub fn add_on_hyperlink_start_index_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERLINK_START_INDEX_CHANGED as u32,
func,
));
}
pub fn add_on_hypertext_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_HYPERTEXT_CHANGED as u32, func));
}
pub fn add_on_hypertext_nlinks_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_HYPERTEXT_NLINKS_CHANGED as u32,
func,
));
}
pub fn add_on_object_attribute_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED as u32,
func,
));
}
pub fn add_on_page_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_PAGE_CHANGED as u32, func));
}
pub fn add_on_section_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_SECTION_CHANGED as u32, func));
}
pub fn add_on_table_caption_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_CAPTION_CHANGED as u32,
func,
));
}
pub fn add_on_table_column_description_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED as u32,
func,
));
}
pub fn add_on_table_column_header_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED as u32,
func,
));
}
pub fn add_on_table_model_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_MODEL_CHANGED as u32,
func,
));
}
pub fn add_on_table_row_description_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED as u32,
func,
));
}
pub fn add_on_table_row_header_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_ROW_HEADER_CHANGED as u32,
func,
));
}
pub fn add_on_table_summary_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TABLE_SUMMARY_CHANGED as u32,
func,
));
}
pub fn add_on_text_attribute_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TEXT_ATTRIBUTE_CHANGED as u32,
func,
));
}
pub fn add_on_text_caret_moved_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_TEXT_CARET_MOVED as u32, func));
}
pub fn add_on_text_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TEXT_ATTRIBUTE_CHANGED as u32,
func,
));
}
pub fn add_on_text_column_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TEXT_COLUMN_CHANGED as u32,
func,
));
}
pub fn add_on_text_inserted_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_TEXT_INSERTED as u32, func));
}
pub fn add_on_text_removed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_TEXT_REMOVED as u32, func));
}
pub fn add_on_text_updated_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_TEXT_UPDATED as u32, func));
}
pub fn add_on_text_selection_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_TEXT_SELECTION_CHANGED as u32,
func,
));
}
pub fn add_on_visible_data_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events.write().unwrap().push(WinEventHook::new(
IA2_EVENT_VISIBLE_DATA_CHANGED as u32,
func,
));
}
pub fn add_on_role_changed_listener(
&self,
func: impl Fn(WinEventSource) + Sync + Send + 'static,
) {
self.events
.write()
.unwrap()
.push(WinEventHook::new(IA2_EVENT_ROLE_CHANGED as u32, func));
}
pub fn remove_all_listeners(&self) {
let mut lock = self.events.write().unwrap();
for i in lock.iter() {
i.unhook();
}
lock.clear();
}
}
#[cfg(test)]
mod test_ia2 {
use crate::ia2::{
ia2_lib::IA2CommonTypes::IA2CoordinateType, object::Accessible2Object, Ia2,
WinEventSourceExt,
};
use win_wrap::{com::co_initialize_multi_thread, common::beep};
#[test]
fn main() {
co_initialize_multi_thread().unwrap();
let ia2 = Ia2::new();
ia2.add_on_text_caret_moved_listener(|src| {
beep(500, 50);
let (obj, child) = src.get_object().unwrap();
dbg!(child);
let obj = Accessible2Object::from_accessible_object(obj).unwrap();
let group_position = obj.group_position();
dbg!(group_position);
let h_wnd = obj.window_handle();
assert_eq!(h_wnd, src.h_wnd);
let index_in_parent = obj.index_in_parent();
dbg!(index_in_parent);
dbg!(obj);
let text = src.get_text().unwrap();
dbg!(text.character_extents(0, IA2CoordinateType::IA2_COORDTYPE_PARENT_RELATIVE));
dbg!(text);
});
std::thread::sleep(std::time::Duration::from_millis(20000));
dbg!(ia2);
}
}