none
How to know UI automation client is listening to my WPF app RRS feed

  • Question

  • I want to make my app to be accessible (make my app exposed for screen readers, which are UI automation client, like "`Narrator`"). 

    I got some `ContentControl` that when it got keyboard focus, I'm showing a tooltip (taking it from the `Tooltip` property of this `ContentControl`). It's a control that used in many ways, for example it can be used like that: 
    the `Content` of this `ContentControl` is a question mark icon image, and the `ToolTip` is the help text...

    Here is a concept code:
        class AutoTooltipOnFocus : ContentControl
        {
            public AutoTooltipOnFocus()
            {
                this.GotKeyboardFocus += OnGotKeyboardFocus;
            }
    
            private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs keyboardFocusChangedEventArgs)
            {
                bool automationListens = AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged);
    
                if (automationListens)
                {
                    // don't show tooltip because GetNameCore of MyAutoPeer will represent the ToolTip value
                    return;
                }
    
                // show tooltip (by reading the ToolTip value of this AutoTooltipOnFocus)
            }
    
            protected override AutomationPeer OnCreateAutomationPeer()
            {
                return new MyAutoPeer(this);
            }
        }
    
        class MyAutoPeer : FrameworkElementAutomationPeer
        {
            private AutoTooltipOnFocus _owner;
    
            public MyAutoPeer(AutoTooltipOnFocus owner)
                : base(owner)
            {
    
            }
    
            protected override string GetNameCore()
            {
                return GetToolTipValueFromOwner();
            }
    
            private string GetToolTipValueFromOwner()
            {
                // just for the simplicity of the example, I return this:
                return ToolTipService.GetToolTip(_owner).ToString();
            }
        }




    `Narrator`, for example, reads the textual representation of the `Content` (let's say the property `AutomationProperties.Name` of the image is set to "help icon") and then says "Tooltip: some help text".

    I don't want to count on the tooltip been read by all the screen readers (correct me if I'm wrong thinking some of them don't read Tooltips), so I made my `GetNameCore` return the `ToolTip` content so that I know it would be read necessarily, and I prevented the appearance of the tooltip (at `OnGotKeyboardFocus` handler) in order to prevent double reading of the same help text. 

    The problem is that: I thought that asking `AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged)` tells me that UI automation is listening to my app, but when narrator is not running, this method returns "false" and the rest of the times it returns true, so no tooltip appears when no one using screen reader, so I need to know what is the way to indicate whether UI automation client is running and listening to my app.
    Maybe there is a workaround by adding some code to my custom `AutomationPeer`.

    Thanks for giving your time!
    Friday, May 18, 2018 12:30 PM

All replies

  • >>The problem is that: I thought that asking `AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged)` tells me that UI automation is listening to my app, but when narrator is not running, this method returns "false" and the rest of the times it returns true

    I'm a little confused on what you demonstrated. When the narrator is closed, the method should return "false", if it is running, "true" value should be returned. this is by design. And I noticed that you have tried to show tooltip when it returns false(the narrator is closed)

    Btw, please also check the Remark section in here

    This method is static and only answers if a delegate listens for the specified event in UI Automation, not for an event on a specific element. UI Automation can create broadcast listeners; therefore the per-element information is irrelevant.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, May 21, 2018 3:18 AM
    Moderator
  • Let me explain again...
    if the user will move the keyboard focus to my AutoTooltipOnFocus, a tooltip should appear (like the class name says - auto tooltip on focus). The problem is that there are screen readers like JAWS which don't read the value of a tooltip that has shown (on keyboard focus).
    So JAWS user won't know what is the element that got the focus after pressing the Tab key.
    So in order to solve that I've decided that I'll take the tooltip value and use it as the return value of GetCoreName. And that will make sure that there is an accessible name to my AutoTooltipOnFocus. Each screen reader will read the GetCoreName so I don't need to worry whether the user will use screen reader that reads tooltips.

    Now, after we understand that, if we look at Narrator which does reads tooltips, so now if the user will use Narrator he will hear the help text twice! (GetCoreName of AutoTooltipOnFocus and then the value of the tooltip that appeared on screen), so that's why I want to recognize if there is a UI automation client running to prevent from the tooltip from appearing, so it will read only the GetCoreName returned value.

    If you are a user who doesn't need screen readers, you need a tooltip to appear, so that's why I want to show tooltip when there are no screen readers running.



    I don't know what is the implementation of this method (and its class), but maybe it returns true because somehow the class AutomationPeer registered this event as listened. I only used the ListenerExists, and RaiseAutomationEvent (if there is a listener) methods from this class.




    • Edited by MarioBlanc Monday, May 21, 2018 7:31 PM
    Monday, May 21, 2018 7:18 PM