Rust for windows uiautomation
The uiatomation-rs crate is a wrapper for windows uiautomation. This crate can help you make windows uiautoamtion API calls conveniently.
Usages
Start by adding the dependency of this crate to your Cargo.toml file. Make use of any windows uiautomation calls as needed.
Features
Supported Features
| Feature | Description | Default |
|---|---|---|
process |
Support process operations and filter by process id | False |
dialog |
Enable message boxes to show message | False |
input |
Support keyboard inputs | True |
clipboard |
Support clipboard operations | False |
pattern |
Support Microsoft UI Automation control patterns | - |
control |
Enable to wrapper ui element as control to simplify operations | True |
event |
Support Microsoft UI Automation events | False |
log |
Use log crate to print debug message | False |
screenshot |
Support screen capture with BMP/PNG output | False |
all |
Enable all the above features | False |
patternis a feature thatcontroldepends on.
Default Features
input,control,pattern(introduced by thecontroldependency)
In order to be compatible with the version before
v0.19.0, you should addprocess,dialog,eventandclipboardfeatures.
Examples
Print All UIElements
use uiautomation::Result;
use uiautomation::UIAutomation;
use uiautomation::UIElement;
use uiautomation::UITreeWalker;
fn main() {
let automation = UIAutomation::new().unwrap();
let walker = automation.get_control_view_walker().unwrap();
let root = automation.get_root_element().unwrap();
print_element(&walker, &root, 0).unwrap();
}
fn print_element(walker: &UITreeWalker, element: &UIElement, level: usize) -> Result<()> {
for _ in 0..level {
print!(" ")
}
println!("{} - {}", element.get_classname()?, element.get_name()?);
if let Ok(child) = walker.get_first_child(&element) {
print_element(walker, &child, level + 1)?;
let mut next = child;
while let Ok(sibling) = walker.get_next_sibling(&next) {
print_element(walker, &sibling, level + 1)?;
next = sibling;
}
}
Ok(())
}
Open Notepad and Input Text
use uiautomation::core::UIAutomation;
use uiautomation::processes::Process;
fn main() {
Process::create("notepad.exe").unwrap();
let automation = UIAutomation::new().unwrap();
let root = automation.get_root_element().unwrap();
let matcher = automation.create_matcher().from(root).timeout(10000).classname("Notepad");
if let Ok(notepad) = matcher.find_first() {
println!("Found: {} - {}", notepad.get_name().unwrap(), notepad.get_classname().unwrap());
notepad.send_keys("Hello,Rust UIAutomation!{enter}", 10).unwrap();
let window: WindowControl = notepad.try_into().unwrap();
window.maximize().unwrap();
}
}
Get Properties As Variant
use uiautomation::UIAutomation;
use uiautomation::types::UIProperty;
use uiautomation::variants::Variant;
fn main() {
let automation = UIAutomation::new().unwrap();
let root = automation.get_root_element().unwrap();
let name: Variant = root.get_property_value(UIProperty::Name).unwrap();
println!("name = {}", name.get_string().unwrap());
let ctrl_type: Variant = root.get_property_value(UIProperty::ControlType).unwrap();
let ctrl_type_id: i32 = ctrl_type.try_into().unwrap();
println!("control type = {}", ctrl_type_id);
let enabled: Variant = root.get_property_value(UIProperty::IsEnabled).unwrap();
let enabled_str: String = enabled.try_into().unwrap();
println!("enabled = {}", enabled_str);
}
Simulate Keyboard Input
use uiautomation::core::UIAutomation;
fn main() {
let automation = UIAutomation::new().unwrap();
let root = automation.get_root_element().unwrap();
root.send_keys("{Win}D", 10).unwrap();
}
Add Event Handler
struct MyFocusChangedEventHandler{}
impl CustomFocusChangedEventHandler for MyFocusChangedEventHandler {
fn handle(&self, sender: &uiautomation::UIElement) -> uiautomation::Result<()> {
println!("Focus changed: {}", sender);
Ok(())
}
}
fn main() {
let note_proc = Process::create("notepad.exe").unwrap();
let automation = UIAutomation::new().unwrap();
let root = automation.get_root_element().unwrap();
let matcher = automation.create_matcher().from(root).timeout(10000).classname("Notepad");
if let Ok(notepad) = matcher.find_first() {
let focus_changed_handler = MyFocusChangedEventHandler {};
let focus_changed_handler = UIFocusChangedEventHandler::from(focus_changed_handler);
automation.add_focus_changed_event_handler(None, &focus_changed_handler).unwrap();
let text_changed_handler: Box<CustomPropertyChangedEventHandlerFn> = Box::new(|sender, property, value| {
println!("Property changed: {}.{:?} = {}", sender, property, value);
Ok(())
});
let text_changed_handler = UIPropertyChangedEventHandler::from(text_changed_handler);
automation.add_property_changed_event_handler(¬epad, uiautomation::types::TreeScope::Subtree, None, &text_changed_handler, &[UIProperty::ValueValue]).unwrap();
}
println!("waiting for notepad.exe...");
note_proc.wait().unwrap();
}
Capture Screenshot
use uiautomation::screenshots::Screenshot;
use uiautomation::UIAutomation;
fn main() {
// Capture the entire desktop (multi-monitor supported)
let shot = Screenshot::capture_desktop().unwrap();
shot.save_png("desktop.png").unwrap();
// Capture a specific region
use uiautomation::types::Rect;
let shot = Screenshot::capture_rect(Rect::new(0, 0, 800, 600)).unwrap();
shot.save_bmp("region.bmp").unwrap();
// Capture a UI element directly
let automation = UIAutomation::new().unwrap();
let matcher = automation.create_matcher().classname("Notepad");
if let Ok(notepad) = matcher.find_first() {
let shot = notepad.screenshot().unwrap();
shot.save_png("notepad.png").unwrap();
}
}