New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce IUIAutomation5 interface and ability to announce notifications in Windows 10 Fall Creators Update and later #8045
Conversation
…ported. Re nvaccess#8009. Also includes nvaccess#7984: in Windows 10 Version 1709 (Fall Creators Update), UIA notification event is introduced for the benefit of screen readers so they can announct needed text. This is part of UIA 5 interface, which NVDA does not support yet. The UIA notification event accepts additional parameters such as notification kind, notification processing constant and activit ID. This is useful for controlling how things should be announced and when. For now, the handler will do nothing. Also, when initializing UIA handler, use UIA 5, and then fall back to UIA 4.
…or additional kwargs for event execution. Re nvaccess#8009. Treat UIA notification event just like others except for two things: * A new UIA_notification event will be fired. * The new event will populate kwargs based on arguments for the actual event handling function (sender, displayString, etc.). This means app modules, global plugins, objects and others must include these kwargs when defining this event.
…ndows release. Re nvaccess#8009. A new function named getIUIAInterface (along with a private companion for Windows 10) is introduced to obtain highest supported IUIAutomation interface. Depending on Windows release, it'll return various interfaces. In case of Windows 10, a companion function will return appropriate interface based on build ranges.
nvaccess#7984. If IUIAutomation5 is in use, add notificaiton event handler, otherwise COM error is thrown. Also, instead of relying solely on Python MRO to retrieve UIA interface, save the string somewhere for reference purposes and for future use.
…vaccess#8009. The base implementation for UIA notification handler will just speak whatever notification it receives. Subclasses are more than welcome to add further processing routines.
Hey Joseph,
|
Querying interfaces on the CUIAutomation client object should be very
fast as the UI automation client COM interfaces run entirely within
NVDA's process.
Also, this will only be done once, on NVDA start anyway I'm assuming.
|
Do you know if this causes any double speaking where Microsoft may have fired both liveRegionChange and notification for the same thing? |
Hi, yes, but apps I came across so far raises one of these at runtime, or prefers the newer events. For example, I expected Microsoft Store app to fire either live region change or notification event in Creators Update (Version 1703), but it raised only notification event in that version. But I would imagine third-party apps may raise both events (perhaps due to oversight), but I guess preparing for that might be in order somehow. Thanks.
From: Michael Curran [mailto:notifications@github.com]
Sent: Tuesday, February 27, 2018 10:16 PM
To: nvaccess/nvda <nvda@noreply.github.com>
Cc: Joseph Lee <joseph.lee22590@gmail.com>; Author <author@noreply.github.com>
Subject: Re: [nvaccess/nvda] Introduce IUIAutomation5 interface and ability to announce notifications in Windows 10 Fall Creators Update and later (#8045)
Do you know if this causes any double speaking where Microsoft may have fired both liveRegionChange and notification for the same thing?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub <#8045 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AHgLkPHs4jSUrVFkBixQQAr01tdROGpqks5tZO8EgaJpZM4SV6jq> .
|
Hi, @LeonarddeR: the Win10 version is the one to be used from binary builds and eventually from source once we move to Python 3. The generic version is meant for add-ons and to show that NVDA still supports Windows 7 SP1. The reason for this design is to keep it compatible with what we have at the moment: falling back to IUIAutomation2 if newer versions are not available. As @michaelDCurran pointed out, this is meant to be used at startup (both for Core and add-ons). Thanks. |
As all IUIAutomationX interfaces inherit from the one before, there is
no issue with compatibility. I.e. code written for windows 7 can
interact with an IUIAutomation5 object just as it was an IUIAutomation2
object.
At start-up, NVDA should simply QueryInterface from IUIAutomation5 down
to IUIAutomation until one succeeds.
Thus UIAHandler.handler.clientObject will always be the highest one the
Operating System happens to support.
|
Hi, In the end, the getIUIAInterface function won't be added, as a for loop will be used to try various versions (modifying specs accordingly). Thanks. |
…8009. Comments from @LeonarddeR and @michaelDCurran: build ranges aren't useful, subsequently proven to be true. As an alternative, query interfaces from newest to oldest, which does allow NVDA to use IUIAutomation5 interface from source. Also, this means getIUIAInterface function is no longer necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you didn't ask for my review, but I'm trying to update my UIA knowledge, so that's why I looked into this.
source/NVDAObjects/UIA/__init__.py
Outdated
@@ -1368,6 +1369,16 @@ def event_UIA_systemAlert(self): | |||
# Ideally, we wouldn't use getBrailleTextForProperties directly. | |||
braille.handler.message(braille.getBrailleTextForProperties(name=self.name, role=self.role)) | |||
|
|||
def event_UIA_notification(self, sender=None, notificationKind=None, notificationProcessing=None, displayString=None, activityId=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could leave out the sender kwarg. See my comment below.
source/_UIAHandler.py
Outdated
return | ||
import NVDAObjects.UIA | ||
obj=NVDAObjects.UIA.UIA(UIAElement=sender) | ||
eventHandler.queueEvent("UIA_notification",obj, sender=sender, notificationKind=NotificationKind, notificationProcessing=NotificationProcessing, displayString=displayString, activityId=activityId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the sender is equal to obj.UIAElement, I think it is a redundant kwarg. For consistency reasons, if one whould like to access the UIAElement for this event within a subclass, people can use the UIAElement property on the object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @LeonarddeR here. Sender should not be explicitly provided to the notification event as it is redundant.
source/_UIAHandler.py
Outdated
self.clientObject=self.clientObject.QueryInterface(IUIAutomation2) | ||
log.info("UIAutomation: %s"%self.clientObject.__class__.__mro__[1].__name__) | ||
# #8009: use appropriate interface based on highest supported interface. | ||
for interface in (IUIAutomation5, IUIAutomation4, IUIAutomation3, IUIAutomation2): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be put these interfaces in a constant?
source/_UIAHandler.py
Outdated
except COMError: | ||
pass | ||
# Have this handy because we want to add things corresponding to the interface version. | ||
IUIAVersion = self.clientObject.__class__.__mro__[1].__name__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now you loop through these interfaces (which I think is a good thing to do), you might as well do something like this, avoiding digging into the mro:
for interface in interfaces:
QueryInterface
except:
pass # Or continue? I guess they are identical in result here
else:
IUIAVersion = interface.__name__
...
Since you just left the loop, you can even leave out the else statement, but using an else for the try statement looks somewhat cleaner to me. It's a matter of preference, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UiaVersion would also have to be set to IUIAutomation when isUIA8 is false. if you do it the way @LeonarddeR suggests
source/_UIAHandler.py
Outdated
@@ -206,6 +211,9 @@ def MTAThreadFunc(self): | |||
self.clientObject.AddPropertyChangedEventHandler(self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self,UIAPropertyIdsToNVDAEventNames.keys()) | |||
for x in UIAEventIdsToNVDAEventNames.iterkeys(): | |||
self.clientObject.addAutomationEventHandler(x,self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self) | |||
# #7984: add support for notification event (IUIAutomation5, part of Windows 10 build 16299 and later). | |||
if IUIAVersion >= "IUIAutomation5": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, even though Python uses lexicographical comparison for strings and therefore this is code that does the write thing, I'd feel safer if you'd avoid this. As @michaelDCurran pointed out in #8045 (comment), all UIA interfaces inherit from the one before, so you could do an instance check on the client object for IUIAutomation5.
self.clientObject=self.clientObject.QueryInterface(interface) | ||
break | ||
except COMError: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps an else on the for loop that raises RuntimeError("No UIAutomation client interface supported")
source/_UIAHandler.py
Outdated
except COMError: | ||
pass | ||
# Have this handy because we want to add things corresponding to the interface version. | ||
IUIAVersion = self.clientObject.__class__.__mro__[1].__name__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UiaVersion would also have to be set to IUIAutomation when isUIA8 is false. if you do it the way @LeonarddeR suggests
…s#8009. Commented by @LeonarddeR and @michaelDCurran: check isinstance instead of keeping an eye on IUIA interface string.
Hi, In the end, isinstance checking will be done. I don't think an "else" is necessary except if we need to break out of the loop with that method. Additional testing done by running the launcher (based on source code commits) on a Windows 8.1 system, and things work as expected. Thanks. |
Does this mean that if Microsoft bring out an even higher number this will
need to be added or are they now finished twiddling about with the versions?
|
Hi, If the new interface includes useful features that screen reader users need to see/hear, then yes, we need to add support for it. Thanks. |
source/_UIAHandler.py
Outdated
return | ||
import NVDAObjects.UIA | ||
obj=NVDAObjects.UIA.UIA(UIAElement=sender) | ||
eventHandler.queueEvent("UIA_notification",obj, sender=sender, notificationKind=NotificationKind, notificationProcessing=NotificationProcessing, displayString=displayString, activityId=activityId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @LeonarddeR here. Sender should not be explicitly provided to the notification event as it is redundant.
Reviewed by @michaelDCurran (NV Access): sender argument is redundant.
# Conflicts: # source/NVDAObjects/UIA/__init__.py # source/_UIAHandler.py
Link to issue number:
#7984, #8009
Summary of the issue:
Introduce IUIAutomation5 interface and ability to announce notifications in Windows 10 Fall Creators Update an later
Description of how this pull request fixes the issue:
In Windows 10 Fall Creators Update and later, apps can inform screen readers to announce specific notification text. This is done via IUIAutomationNotificationEventHandler::HandleNotificationEvent, which is part of IUIAutomation5 interface. Since NVDA only uses IUIAutomation3, update UIA subsystem to use IUIAutomation5. Also, introduce ability to use more recent IUIAutomation interfaces on various Windows 10 releases (such as IUIAutomation4 in Anniversary Update/build 14393).
Testing performed:
Testing done via Windows 10 App Essentials add-on: using recent versions of various app (such as Calculator, Microsoft Store and others) that uses this new event to announce texts.
Known issues with pull request:
None so far.
Change log entry:
New feature: In Windows 10 Fall Creators Update and later, NVDA can announce notifications from apps such as Calculator and Windows Store.