Skip to content

Conversation

@acoates-ms
Copy link
Contributor

@acoates-ms acoates-ms commented Aug 26, 2020

There are several things wrong with this implementation.

  • isTouchExplorationEnabled always returns false. As far as I know windows does not expose a hook to know if someone is running narrator or similar tools. Open question, should we default to true instead of false? Using UiaClientsAreListening for now)

  • setAccessibilityFocus is unimplemented. - Turns out this method on this native module isn't called by RN. The AccessibilityInfo.setAccessibilityFocus method calls directly into UIManager.sendAccessibilityEvent (which we also need to implement) (Implement UIManager.sendAccessibilityEvent #5907)

  • announceForAccessibility Tries to find an element to raise the event from. All the elements I tried do not seem to return anything in the call FrameworkElementAutomationPeer::FromElement, so the method ends up being a no-op. Someone with more XAML expertise should see if they can come up with something better. -- We might want to look into adding an argument to the core function to allow users to specify which element should do the announce, since in desktop environments that might make more difference. (AccessibilityInfo::announceForAccessibility fails to announce #5908)

I expect to open an issue to track all the unresolved issues above when this goes in. But having this implementation does provide a good impl for isReduceMotionEnabled, and fixes the Redbox on the existing AccessibilityExample test page.

Microsoft Reviewers: Open in CodeFlow

@acoates-ms acoates-ms requested a review from a team as a code owner August 26, 2020 18:33
@NickGerleman
Copy link
Contributor

I think there might be some issues openaround api completion for AccessibilityInfo. Feel free to have this PR close them if you're wanting to track specific implementation issues.

onSuccess(false);
}

void AccessibilityInfo::setAccessibilityFocus(double reactTag) noexcept {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't remember if we generate warnings for unused params or not, but consider commenting out the name.


void AccessibilityInfo::isTouchExplorationEnabled(
std::function<void(React::JSValue const &)> const &onSuccess) noexcept {
onSuccess(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false [](start = 12, length = 5)

Re: - isTouchExplorationEnabled always returns false. As far as I know windows does not expose a hook to know if someone is running narrator or similar tools. Open question, should we default to true instead of false?

Idk what "touch exploration" means & how it's used, but as far as telling whether an a11y tool is running goes: There's UiaClientsAreListening (https://docs.microsoft.com/en-us/windows/win32/api/uiautomationcoreapi/nf-uiautomationcoreapi-uiaclientsarelistening). This is about events which is a subset of UIA functionality, but I'd assume that any "real" a11y tool would do that. If you should decide to use UiaClientsAreListening, do a sanity check on its returns; I vaguely recall that on earlier Win10 versions this returned true even if there was no real a11y tool running.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that API safe for UWP usage?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also IRawElementProviderAdviseEvents (https://docs.microsoft.com/en-us/windows/win32/api/uiautomationcore/nn-uiautomationcore-irawelementprovideradviseevents). This is something that needs to be implemented in the UI framework, and we'd have to connect to that - probably too complicated for what we want to achieve here.


In reply to: 478625704 [](ancestors = 478625704)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so (we're using it in WinRT platform adaptors in FastAcc). Forrest would know for sure.


In reply to: 478626922 [](ancestors = 478626922)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per otools/bin/mox/mosdk-shaped-fullanno.xml, it looks like UiaClientsAreListening is allowed.


In reply to: 478626922 [](ancestors = 478626922)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still seems to return true even if nothing is running. Not sure how useful that hook up is then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in-box XAML uses UiaClientsAreListening for this purpose, and I am pretty sure this is working reliably there (ie it returns true only when an AT like Narrator is running).


In reply to: 478640914 [](ancestors = 478640914,478626922)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kmelmon it returns true if there is a UIA client that is subscribed to events - but UIA clients don't have to do that, instead they can just poll properties every N seconds. Narrator does subscribe to UIA events, so if the intent is to only get this working with narrator and maybe not support other UIA clients then that API is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a long time since I looked at this API, but IIRC it could return false positives. For example, I think it returns true on touch devices even if there no ATs listening.

onSuccess(false);
}

void AccessibilityInfo::setAccessibilityFocus(double /*reactTag*/) noexcept {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AccessibilityInfo::setAccessibilityFocus [](start = 5, length = 40)

We can use AutomationPeer::SetFocusCore() to implement this. See:
https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.automation.peers.automationpeer.setfocuscore?view=winrt-19041
Also see XAML code that implements it here:
%SDXROOT%\onecoreuap\windows\dxaml\xcp\dxaml\lib\winrtgeneratedclasses\AutomationPeer.g.cpp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That moves actual focus to that element. This API is just trying to move the narrator focus. -- So, when running narrator, it would move the blue rectangle without moving keyboard focus.

(Otherwise, this API is pointless, since there is a similar API that sets normal focus)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I didn't realize it's just supposed to move narrator focus. I'm asking around, meanwhile I see some hits in Windows that suggest raising the AutomationFocusChanged event might work (eg %SDXROOT%\xbox\shellapps\Shared\Xbox.Foundation.UI\Narrator\NarratorReader.cpp line 125)

        // Raise the focus changed automation event, to ensure that this element receives narrator focus so that it reads the element and textToRead together.
        auto automationPeer = FrameworkElementAutomationPeer::FromElement(focusedElement);
        if (automationPeer != nullptr)
        {
            automationPeer.RaiseAutomationEvent(AutomationEvents::AutomationFocusChanged);
        }

In reply to: 481482991 [](ancestors = 481482991)

return;
}

auto peer = xaml::Automation::Peers::FrameworkElementAutomationPeer::FromElement(element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto peer = xaml::Automation::Peers::FrameworkElementAutomationPeer::FromElement(element); [](start = 4, length = 90)

Is this still returning null in all cases? If so feel free to file an issue and assign to me, I can look into it.

@acoates-ms acoates-ms added the AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity) label Sep 2, 2020
@ghost
Copy link

ghost commented Sep 2, 2020

Hello @acoates-ms!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

m_context = reactContext;
}

void AccessibilityInfo::isReduceMotionEnabled(std::function<void(React::JSValue const &)> const &onSuccess) noexcept {
Copy link

@NikoAri NikoAri Sep 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[](start = 88, length = 1)

(nit) can this be && to avoid std::function copy here and while passing into further lambdas?

}

void AccessibilityInfo::isReduceMotionEnabled(std::function<void(React::JSValue const &)> const &onSuccess) noexcept {
auto jsDispatcher = m_context.JSDispatcher();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jsDispatcher [](start = 7, length = 12)

std::move?

// no-op - This appears to be unused in RN
}

void AccessibilityInfo::announceForAccessibility(std::string announcement) noexcept {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 54, length = 6)

Similar comment, can this be either && or const& to avoid accidental copying?

Copy link

@NikoAri NikoAri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@ghost ghost merged commit d391879 into microsoft:master Sep 2, 2020
@acoates-ms acoates-ms deleted the accessinfo branch July 23, 2021 16:07
rozele pushed a commit to rozele/react-native-windows that referenced this pull request Oct 6, 2021
Summary:
Cherry picks:
microsoft#5849
microsoft#7220
microsoft#7290

Test Plan: See D29689294 Test Plan

Reviewers: ericroz

Reviewed By: ericroz

Subscribers: eliwhite

Differential Revision: https://phabricator.intern.facebook.com/D30940769

Tasks: T85606613

Signature: 30940769:1631724353:41db1d978132f06502803cfb4df0323f6da84732
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity)

Projects

None yet

8 participants