-
-
Notifications
You must be signed in to change notification settings - Fork 627
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
Uia in ms word by default #8919
Changes from 2 commits
c0156ca
935d29b
a7607ef
e809aca
11460c3
16df286
76f77e6
2db8e46
bacf85e
db7d429
03883f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -351,22 +351,39 @@ def _isUIAWindowHelper(self,hwnd): | |
# There are certain window classes that just had bad UIA implementations | ||
if windowClass in badUIAWindowClassNames: | ||
return False | ||
if windowClass=="NetUIHWND": | ||
parentHwnd=winUser.getAncestor(hwnd,winUser.GA_ROOT) | ||
# #2816: Outlook 2010 auto complete does not fire enough UIA events, IAccessible is better. | ||
# #4056: Combo boxes in Office 2010 Options dialogs don't expose a name via UIA, but do via MSAA. | ||
if winUser.getClassName(parentHwnd) in {"Net UI Tool Window","NUIDialog"}: | ||
return False | ||
# allow the appModule for the window to also choose if this window is bad | ||
if appModule and appModule.isBadUIAWindow(hwnd): | ||
return False | ||
# Ask the window if it supports UIA natively | ||
res=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd) | ||
if res: | ||
# the window does support UIA natively, but | ||
# Microsoft Word should not use UIA unless we can't inject or the user explicitly chose to use UIA with Microsoft word | ||
if windowClass=="_WwG" and not (config.conf['UIA']['useInMSWordWhenAvailable'] or not appModule.helperLocalBindingHandle): | ||
return False | ||
# MS Word documents now have a very usable UI Automation implementation. However, | ||
# Builds of MS Office 2016 before build 9000 or so had bugs which we cannot work around. | ||
# Therefore refuse to use UIA for builds earlier than this, if we can inject in-process. | ||
if ( | ||
# An MS Word document window | ||
windowClass=="_WwG" | ||
# Disabling is only useful if we can inject in-process (and use our older code) | ||
and appModule.helperLocalBindingHandle | ||
# Allow the user to explisitly force UIA support for MS Word documents no matter the Office version | ||
and not config.conf['UIA']['useInMSWordWhenAvailable'] | ||
): | ||
# We can only safely check the version of known Office apps using the Word document control. | ||
# Other uses for now we just need to assume the implementation is good. | ||
if appModule.appName not in ('outlook','winword','excel'): | ||
log.debugWarning("Unknown application using MS Word document control: %s"%appModule.appName) | ||
return True | ||
try: | ||
versionMajor,versionMinor,versionBuild,versionPatch=[int(x) for x in appModule.productVersion.split('.')] | ||
except Exception as e: | ||
log.error("Error parsing versioninformation %s, %s"%(appModule.productVersion,e)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing space between version and information There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This space is still missing. |
||
return True | ||
if ( | ||
versionMajor<16 | ||
or versionMajor==16 and versionMinor==0 and versionBuild<9000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I would prefer to see these values (16, 0, 9000) put in a named constant. |
||
): | ||
return False | ||
return bool(res) | ||
|
||
def isUIAWindow(self,hwnd): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,7 +133,15 @@ def _get_outlookVersion(self): | |
return outlookVersion | ||
|
||
def isBadUIAWindow(self,hwnd): | ||
if winUser.getClassName(hwnd) in ("WeekViewWnd","DayViewWnd"): | ||
windowClass=winUser.getClassName(hwnd) | ||
# #2816: Outlook versions before 2016 auto complete does not fire enough UIA events, IAccessible is better. | ||
if windowClass=="NetUIHWND": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few usages of this "NetUIHWnd" can you put them in a named constant, perhaps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't believe this would improve things. A window class string is as gooder constant from my point of view. Something like OutlookWindowClass does not addiquitly describe the string as this NetUIHWND class is used in more than just Outlook. It seems to be some kind of generic window class for Ribbons. But to be clear, not the only one though, there is also NetUIToolWindow. Personally I think the strings are good enough. However, I guess we could convert them in to constants I.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. My hope was that we could describe the string better. As someone unfamiliar with the value, it doesn't tell you any of the things you just mentioned. Having a constant with comment you just wrote would be helpful in my opinion. Ideally a name that describes it well, it seems like that is difficult. |
||
parentHwnd=winUser.getAncestor(hwnd,winUser.GA_ROOT) | ||
if winUser.getClassName(parentHwnd)=="Net UI Tool Window": | ||
versionMajor=int(self.productVersion.split('.')[0]) | ||
if versionMajor<16: | ||
return True | ||
if windowClass in ("WeekViewWnd","DayViewWnd"): | ||
return True | ||
return False | ||
|
||
|
@@ -156,9 +164,15 @@ def event_NVDAObject_init(self,obj): | |
obj.role=controlTypes.ROLE_LISTITEM | ||
|
||
def chooseNVDAObjectOverlayClasses(self, obj, clsList): | ||
# Currently all our custom classes are IAccessible | ||
if isinstance(obj,UIA) and obj.UIAElement.cachedClassName in ("LeafRow","ThreadItem","ThreadHeader"): | ||
clsList.insert(0,UIAGridRow) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you might one to return in this block, otherwise the logic under it is needlessly executed (i.e. fetching the role) |
||
role=obj.role | ||
windowClassName=obj.windowClassName | ||
# AutoComplete listItems. | ||
# This class is abstract enough to support both UIA and MSAA | ||
if role==controlTypes.ROLE_LISTITEM and (windowClassName.startswith("REListBox") or windowClassName.startswith("NetUIHWND")): | ||
clsList.insert(0,AutoCompleteListItem) | ||
# all remaining classes are IAccessible | ||
if not isinstance(obj,IAccessible): | ||
return | ||
# Outlook uses dialogs for many forms such as appointment / meeting creation. In these cases, there is no sane dialog caption that can be calculated as the dialog inly contains controls. | ||
|
@@ -169,8 +183,6 @@ def chooseNVDAObjectOverlayClasses(self, obj, clsList): | |
clsList.remove(Dialog) | ||
if WordDocument in clsList: | ||
clsList.insert(0,OutlookWordDocument) | ||
role=obj.role | ||
windowClassName=obj.windowClassName | ||
states=obj.states | ||
controlID=obj.windowControlID | ||
# Support the date picker in Outlook Meeting / Appointment creation forms | ||
|
@@ -180,8 +192,6 @@ def chooseNVDAObjectOverlayClasses(self, obj, clsList): | |
clsList.insert(0,DatePickerCell) | ||
elif windowClassName=="REListBox20W" and role==controlTypes.ROLE_CHECKBOX: | ||
clsList.insert(0,REListBox20W_CheckBox) | ||
elif role==controlTypes.ROLE_LISTITEM and (windowClassName.startswith("REListBox") or windowClassName.startswith("NetUIHWND")): | ||
clsList.insert(0,AutoCompleteListItem) | ||
if role==controlTypes.ROLE_LISTITEM and windowClassName=="OUTEXVLB": | ||
clsList.insert(0, AddressBookEntry) | ||
return | ||
|
@@ -335,14 +345,18 @@ def initOverlayClass(self): | |
for gesture in self.__moveByEntryGestures: | ||
self.bindGesture(gesture, "moveByEntry") | ||
|
||
class AutoCompleteListItem(IAccessible): | ||
class AutoCompleteListItem(Window): | ||
|
||
def event_stateChange(self): | ||
states=self.states | ||
focus=api.getFocusObject() | ||
if (focus.role==controlTypes.ROLE_EDITABLETEXT or focus.role==controlTypes.ROLE_BUTTON) and controlTypes.STATE_SELECTED in states and controlTypes.STATE_INVISIBLE not in states and controlTypes.STATE_UNAVAILABLE not in states and controlTypes.STATE_OFFSCREEN not in states: | ||
speech.cancelSpeech() | ||
ui.message(self.name) | ||
text=self.name | ||
# Some newer versions of Outlook don't put the contact as the name of the listItem, rather it is on the parent | ||
if not text: | ||
text=self.parent.name | ||
ui.message(text) | ||
|
||
class CalendarView(IAccessible): | ||
"""Support for announcing time slots and appointments in Outlook Calendar. | ||
|
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.
This comment is not clear to me yet.
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 this comment could be reworded. Are you saying that "for unknown office apps, which we can not safely check the version using the Word document control, we must just assume the implementation is good"?
Are we assuming that the UIA implementation is good?