leexgone / uiautomation-rs

The uiatomation-rs crate is a wrapper for windows uiautomation. This crate can help you make windows uiautomation API calls conveniently.
Apache License 2.0
87 stars 15 forks source link

How to click on button by it`s definition? #38

Closed valeriigamaley closed 1 year ago

valeriigamaley commented 1 year ago

Introduction:

Hello, guys) you did such a nice work and now i wanna try using your crate at my job. Now I have some dummy but important question: how I can make a click on element which is detected by that crate? I wanna install .NET SDK but i won`t click to button Next manually (such as an cursor position) and need to click on button by for it instance. How you will seen, if you try to run code example, Next button will be detect correctly and log inform about that.

Steps to reproduce:

  1. Get exe installer of NET 5 SDK
  2. Maybe change name properties for installer on english/another language version of OS
  3. Change path to .NET SDK file to actual on your local system

Code Example:

use uiautomation::core::UIAutomation;
use uiautomation::processes::Process;
use uiautomation::UIElement;
use uiautomation::controls::ControlType::Button;

fn main() {
    setup_dotnet_sdk("F:\\Different_Personal_Code_Projects\\Python_Education\\WindowsFatClientAutomation\\CIMbiozDistribution\\requirements\\dotnet-sdk-5.0.408-win-x64.exe")
}
fn setup_dotnet_sdk(path_to_dotnet_sdk_file: &str) {
    Process::create(path_to_dotnet_sdk_file);

    let dotnet_sdk_wizard = UIAutomation::new().unwrap();
    let dotnet_sdk_wizard_window = dotnet_sdk_wizard.create_matcher().filter_fn(Box::new(|elem: &UIElement| {
        let class_name = elem.get_classname()?;
        let name = elem.get_name()?;
        Ok(class_name == "WixStdBA" && name == "Установщик Microsoft .NET SDK 5.0.408 (x64)")
    })).timeout(0);
    if let Ok(dotnet_sdk_wizard_window) = dotnet_sdk_wizard_window.find_all() {
        println!("GUI-window {:?} have discovered", dotnet_sdk_wizard_window)
    } else {
        println!("GUI-window .NET SDK 5 has not discovered")
    }

    let dotnet_sdk_wizard_buttons = UIAutomation::new().unwrap();
    let dotnet_sdk_wizard_install_button = dotnet_sdk_wizard_buttons.create_matcher().filter_fn(Box::new(|elem: &UIElement| {
        let button_type = elem.get_control_type()?;
        let class_name = elem.get_classname()?;
        let name = elem.get_name()?;
        Ok(button_type == Button && class_name == "Button" && name == "Установить")
        })).timeout(0);
    if let Ok(install_button) = dotnet_sdk_wizard_install_button.find_all() {
        println!("Button for Installation of .NET SDK {:?} has been founded", install_button)
    } else {
        println!("Button for Installation of .NET SDK has not been founded")
    }

}

Software: Win10 x64, rustc 1.69, cargo 1.69, uiautomation 0.51

leexgone commented 1 year ago
  1. You should try to find the ui element correctly. Windows controls will show different properties and behaviors depending on the different ui framework used. Sometimes delays in loading the interface can also affect lookup. The inspect tool may help you to find properties for filtering element. And you also have to wait a while while you search.

  2. You need to choose the appropriate way to trigger the control's action. There are some encapsulated controls in uiautomation::controls*, such as ButtonControl, WindowControl, and so on. Each control supports one or more actions(defined in uiautomation::actions::*). You can triggle actions with some appropriate control. For example:

        let button: ButtonControl = element.try_into()?;
        button.invoke()?;

    Occasionally a control's action does not respond correctly. You may need to simulate mouse or keyboard operations to complete the operation. UIElement::click() and UIElement::send_keys() are simple ways to simulate mouse and keyboard events. You can do more by using uiautomation::inputs::Mouse and uiautomation::inputs::Keyboard.

This sample may be useful for you: win-update

Good luck!

valeriigamaley commented 1 year ago

@leexgone Thanks for advice, now i get a result through imitate mouse action like a UIElement::click() :)