6

How to detect if screen reader is running (JAWS)?

As I understand in .NET 4 we can use AutomationInteropProvider.ClientsAreListening from System.Windows.Automation.Provider namespace, but what if I have to do it for .NET 2.0?

I tried to inspect ClientsAreListening source code, it calls external RawUiaClientsAreListening method from UIAutomationCore.dll library.

Do you have any ideas how to implement JAWS detection in .NET 2.0?

avalancha
  • 1,457
  • 1
  • 22
  • 41
Jevgenij Nekrasov
  • 2,690
  • 3
  • 30
  • 51
  • Curious - what do you intend to do differently if you determine that a screenreader is running? Note that some non-screenreader apps may set the SPI_SCREENREADER flag, so you can get false positives or negatives. Ideally your app should work without needing to check this flag. Are you really checking for screenreaders in general, or JAWS specifically? – BrendanMcK Nov 12 '11 at 10:00

1 Answers1

4

Use the SystemParametersInfo function passing a uiAction of SPI_GETSCREENREADER.

You will need to use P/Invoke for this, for example:

internal class UnsafeNativeMethods
{
    public const uint SPI_GETSCREENREADER = 0x0046;

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref bool pvParam, uint fWinIni);
}

public static class ScreenReader
{
    public static bool IsRunning
    {
        get
        {
            bool returnValue = false;
            if (!UnsafeNativeMethods.SystemParametersInfo(UnsafeNativeMethods.SPI_GETSCREENREADER, 0, ref returnValue, 0))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "error calling SystemParametersInfo");
            }
            return returnValue;
        }
    }
}

This is possibly better than using the ClientsAreListening property as this property appears to return true for any automation client, not just screen readers.

Also see:

You should also listen for the WM_SETTINGCHANGE message to detect if a screen reader starts / stops running.


Update (in response to BrendanMcK's comments):

Although this is never explicitly documented in as many words, looking at the description of the flag I think the purpose of this flag is relatively clear:

Determines whether a screen reviewer utility is running. A screen reviewer utility directs textual information to an output device, such as a speech synthesizer or Braille display. When this flag is set, an application should provide textual information in situations where it would otherwise present the information graphically.

What this is saying is that applications set this flag whenever an application wishes the UI to behave as if a screen reader is running, regardless of whether or not that application is actually a screen reader or not.

Suitable things to do in response to this flag is to add text in order to "read" otherwise intuitive UI state to the user. If radical changes are needed to make your UI screen reader accessible then the chances are that your UI also isn't that intuitive to sigted users and could probably do with a re-think.

Community
  • 1
  • 1
Justin
  • 84,773
  • 49
  • 224
  • 367
  • 1
    Note that ClientsAreListening only tells you about accessibility clients that actively listen for accessibility events. There could be others that still use accessibility - eg. to scrape the UI for verbs for speech recognition - but use some other means to determine when to scrape, and don't listen for accessibility events. In short, this API only lets you know that you need to send events; not whether an accessibility client is running. – BrendanMcK Nov 12 '11 at 10:01
  • @BrendanMcK Conversely the `SPI_GETSCREENREADER` is simply a flag that is set by screen readers to indicate to others that they are running (regardless of the method used) – Justin Nov 14 '11 at 09:59
  • @Justin: Right; but SPI_GETSCREENREADER does have some issues. I'm somewhat worried about what the OP wants to do in response to the flag; non-screenreaders often set this flag too (eg magnifiers or speech input apps), so you can't assume that the client setting this is an actual screenreader, or some other type of accessibility client. And there are some accessibility clients that may not set this. (...) – BrendanMcK Nov 15 '11 at 07:28
  • (...) The main issue with this flag is that it's not well defined either (a) what a screenreader is (vs other accessibility aids), or (b) what exactly an app should or shouldn't do if they detect that the flag is set. And my concern with the original qu is that ideally accessibility should 'just work', and not rely on a flag; the flag should only be used in 'last resort' scenarios. – BrendanMcK Nov 15 '11 at 07:30
  • (...) Example of bad use of this flag: dropping graphics outright or changing the UI significantly. A partially sighted user might be using a screenreader *in addition to* a magnifier, and may still want to use the app's original visuals in addition to using screenreader functionality. – BrendanMcK Nov 15 '11 at 07:31
  • 1
    Final comment - if using this flag, don't forget to recheck it when the top-level HWND gets a WM_SETTINGCHANGE; a user could start the app and then start the screenreader *after* the app is running. Most screenreader user likely have the reader running for entire session - you shouldn't assume that *all* users will do this. (eg. user might be sharing machines with a sighted colleague, and starting reader as needed, or could have moderate vision, and only using reader intermittently.) – BrendanMcK Nov 15 '11 at 12:14
  • "Suitable things to do in response to this flag is to add text in order to "read" otherwise intuitive UI state to the user." - actually disagree here; this technique dates from w95 and predates the adoption of MSAA by the shell and screenreaders. The preferred technique these days is to use a suitable API to indicate the state of the UI to the screenreader; a screenreader will then read out the right UI state, and sighted users (fully, partially, or users using magnifiers) won't see mysterious extra text. Techiques like those in the article should be a total last resort. – BrendanMcK Nov 15 '11 at 13:20
  • Strangely when I execute this under Windows 11, VS 2022, .Net 6, it does not ever seem to detect Microsoft Narrator. – WiredWiz Aug 30 '22 at 16:25