How to check a checkbox with microsoft uiautomation?

3.8k views Asked by At

I need to automate the madvr gui and enable smooth motion with uiautomation.
But can't find recent and easy working samples.

The madvr window identification:

The madvr smooth motion checkbox identification:

My actual code:

using System;
using System.Diagnostics;

namespace MadAutomation
{
    class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Enabling the madvr smooth motion feature...");

            EnableSmoothMotion();

            Console.Write("Press any key to continue...");
            Console.ReadKey(true);
        }

        public static void EnableSmoothMotion()
        {
            // Run madvr configuration.         
            Process p = new Process();
            p.StartInfo.FileName = @"C:\Users\Admin\Desktop\madVR\madHcCtrl.exe";
            p.StartInfo.Arguments = "editLocalSettingsDontWait";
            p.Start();

            // Enable smooth motion checkbox.
        }
    }
}
1

There are 1 answers

4
Simon Mourier On BEST ANSWER

Here is a program that does it. Note you must use the NuGet UIAComWrapper package (written by a Microsoft guy) instead of the standard UIAutomation*.dll provided out-of-the-box for it to work. The standard UIA .NET assemblies don't see all AutomationElement, don't know all properties (Aria, etc.).

Yes, it means they are bugged/obsolete and for some reason, Microsoft does not officially ship the newer ones with new .NET or Windows releases... Anyway the UIAComWrapper is a 100% source-compatible drop-in replacement, so that shouldn't be a problem.

If you want to see the differences between what's returned by UIAComWrapper vs UIA asssemblies, it's the same differences that you will see if you use Inspect (the official UIA tool) vs UISpy (the obsolete official UI tool), respectively. They look similar but are in fact quite different in the details or structure.

public static void EnableSmoothMotion()
{
    bool finished = false;
    // wait for the settings window to show
    Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
    {
        var window = (AutomationElement)sender;
        if (window.Current.ClassName != "TFMadVRSettings")
            return;

        // get the tree element
        var tree = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tree));

        // get the smooth motion element & select it
        var smoothMotion = tree.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "smooth motion"));
        ((SelectionItemPattern)smoothMotion.GetCurrentPattern(SelectionItemPattern.Pattern)).Select();

        // get the tab element
        var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab));

        // get the pane element
        var pane = tab.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane));

        // get the first checkbox & ensure it's clicked
        var cb = pane.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.CheckBox));
        TogglePattern tp = (TogglePattern)cb.GetCurrentPattern(TogglePattern.Pattern);
        if (tp.Current.ToggleState != ToggleState.On) // not on? click it
        {
            ((InvokePattern)cb.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
        }

        // NOTE: uncomment the two following line if you want to close the window directly
        // get the ok button & push it
        //var ok = window.FindFirst(TreeScope.Children, new AndCondition(
        //    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
        //    new PropertyCondition(AutomationElement.NameProperty, "OK")));
        //((InvokePattern)ok.GetCurrentPattern(InvokePattern.Pattern)).Invoke();

        finished = true;
    });

    // run the program
    Process p = new Process();
    p.StartInfo.FileName = @"C:\Users\Admin\Desktop\madVR\madHcCtrl.exe";
    p.StartInfo.Arguments = "editLocalSettingsDontWait";
    p.Start();

    while(!finished)
    {
        Thread.Sleep(100);
    }
    Automation.RemoveAllEventHandlers();
}

Note: I used the event handler here instead of process.MainWindowHandle because the main window for the process is not the settings window, and the settings window is not a child of the main window.