def _isUIAWindowHelper(self,hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID=winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId()==processID: return False import NVDAObjects.window windowClass=NVDAObjects.window.Window.normalizeWindowClassName(winUser.getClassName(hwnd)) # A WDAG (Windows Defender Application Guard) Window is always native UIA, even if it doesn't report as such. if windowClass=='RAIL_WINDOW': return True # 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 appModule=appModuleHandler.getAppModuleFromProcessID(processID) 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 return bool(res)
def _shouldGetEvents(): global _deferUntilForegroundWindow, _foregroundDefers if _deferUntilForegroundWindow: # #3831: Sometimes, a foreground event is fired, # but GetForegroundWindow() takes a short while to return this new foreground. curForegroundWindow = winUser.getForegroundWindow() curForegroundClassName = winUser.getClassName(curForegroundWindow) futureForegroundClassName = winUser.getClassName( _deferUntilForegroundWindow) if (_foregroundDefers < MAX_FOREGROUND_DEFERS and curForegroundWindow != _deferUntilForegroundWindow): # Wait a core cycle before handling events to give the foreground window time to update. core.requestPump() _foregroundDefers += 1 if isMSAADebugLoggingEnabled(): log.debugWarning( f"Foreground still {curForegroundWindow} ({curForegroundClassName}). " f"Deferring until foreground is {_deferUntilForegroundWindow} ({futureForegroundClassName}), " f"defer count {_foregroundDefers}") return False else: # Either the foreground window is now correct # or we've already had the maximum number of defers. # (Sometimes, foreground events are fired even when the foreground hasn't actually changed.) if curForegroundWindow != _deferUntilForegroundWindow: log.debugWarning( "Foreground took too long to change. " f"Foreground still {curForegroundWindow} ({curForegroundClassName}). " f"Should be {_deferUntilForegroundWindow} ({futureForegroundClassName})" ) _deferUntilForegroundWindow = None return True
def isGoodUIAWindow(self, hwnd): currentWinVer = winVersion.getWinVer() # #9204: shell raises window open event for emoji panel in build 18305 and later. if (currentWinVer >= winVersion.WIN10_1903 and winUser.getClassName(hwnd) == "ApplicationFrameWindow"): return True # #13506: Windows 11 UI elements such as Taskbar should be reclassified as UIA windows, # letting NVDA announce shell elements when navigating with mouse and/or touch, # notably when interacting with windows labeled "DesktopWindowXamlSource". # WORKAROUND UNTIL A PERMANENT FIX IS FOUND ACROSS APPS if (currentWinVer >= winVersion.WIN11 # Traverse parents until arriving at the top-level window with the below class names. # This is more so for the shell root (first class name), and for others, class name check would work # since they are top-level windows for windows shown on screen such as Task View. # However, look for the ancestor for consistency. and winUser.getClassName( winUser.getAncestor(hwnd, winUser.GA_ROOT)) in ( # Windows 11 shell UI root, housing various shell elements shown on screen if enabled. "Shell_TrayWnd", # Start, Search, Widgets, other shell elements # Top-level window class names from Windows 11 shell features "Shell_InputSwitchTopLevelWindow", # Language switcher "XamlExplorerHostIslandWindow", # Task View and Snap Layouts ) # #13717: on some systems, Windows 11 shell elements are reported as IAccessible, # notably Start button, causing IAccessible handler to report attribute error when handling events. and winUser.getClassName(hwnd) != "Start"): return True return False
def _isUIAWindowHelper(self,hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID=winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId()==processID: return False import NVDAObjects.window windowClass=NVDAObjects.window.Window.normalizeWindowClassName(winUser.getClassName(hwnd)) # For certain window classes, we always want to use UIA. if windowClass in goodUIAWindowClassNames: return True # allow the appModule for the window to also choose if this window is good # An appModule should be able to override bad UIA class names as prescribed by core appModule=appModuleHandler.getAppModuleFromProcessID(processID) if appModule and appModule.isGoodUIAWindow(hwnd): return True # 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 return bool(res)
def _isUIAWindowHelper(self, hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID = winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId() == processID: return False import NVDAObjects.window windowClass = NVDAObjects.window.Window.normalizeWindowClassName( winUser.getClassName(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 appModule = appModuleHandler.getAppModuleFromProcessID(processID) if appModule and appModule.isBadUIAWindow(hwnd): return False # Ask the window if it supports UIA natively return windll.UIAutomationCore.UiaHasServerSideProvider(hwnd)
def processFocusWinEvent(window, objectID, childID, force=False): """checks to see if the focus win event is not the same as the existing focus, then converts the win event to an NVDA event (instantiating an NVDA Object) then calls processFocusNVDAEvent. If all is ok it returns True. @type window: integer @param objectID: a win event's object ID @type objectID: integer @param childID: a win event's child ID @type childID: integer @param force: If True, the shouldAllowIAccessibleFocusEvent property of the object is ignored. @type force: boolean @returns: True if the focus is valid and was handled, False otherwise. @rtype: boolean """ windowClassName = winUser.getClassName(window) # Generally, we must ignore focus on child windows of SDM windows as we only want the SDM MSAA events. # However, we don't want to ignore focus if the child ID isn't 0, # as this is a child control and the SDM MSAA events don't handle child controls. if (childID == 0 and not windowClassName.startswith('bosa_sdm') and winUser.getClassName( winUser.getAncestor( window, winUser.GA_PARENT)).startswith('bosa_sdm')): return False # Notify appModuleHandler of this new foreground window appModuleHandler.update(winUser.getWindowThreadProcessID(window)[0]) # If Java access bridge is running, and this is a java window, then pass it to java and forget about it if (childID == 0 and objectID == winUser.OBJID_CLIENT and JABHandler.isRunning and JABHandler.isJavaWindow(window)): JABHandler.event_enterJavaWindow(window) return True # Convert the win event to an NVDA event NVDAEvent = winEventToNVDAEvent(winUser.EVENT_OBJECT_FOCUS, window, objectID, childID, useCache=False) if not NVDAEvent: return False eventName, obj = NVDAEvent if ((childID == 0 and obj.IAccessibleRole == oleacc.ROLE_SYSTEM_LIST) or (objectID == winUser.OBJID_CLIENT and "SysListView32" in obj.windowClassName)): # Some controls incorrectly fire focus on child ID 0, even when there is a child with focus. try: realChildID = obj.IAccessibleObject.accFocus except: # noqa: E722 Bare except realChildID = None if isinstance(realChildID, int) and realChildID > 0 and realChildID != childID: realObj = NVDAObjects.IAccessible.IAccessible( IAccessibleObject=obj.IAccessibleObject, IAccessibleChildID=realChildID, event_windowHandle=window, event_objectID=objectID, event_childID=realChildID) if realObj: obj = realObj return processFocusNVDAEvent(obj, force=force)
def winEventCallback(handle,eventID,window,objectID,childID,threadID,timestamp): try: #Ignore all object IDs from alert onwards (sound, nativeom etc) as we don't support them if objectID<=winUser.OBJID_ALERT: return #Ignore all locationChange events except ones for the caret if eventID==winUser.EVENT_OBJECT_LOCATIONCHANGE and objectID!=winUser.OBJID_CARET: return if eventID==winUser.EVENT_OBJECT_DESTROY: processDestroyWinEvent(window,objectID,childID) return #Change window objIDs to client objIDs for better reporting of objects if (objectID==0) and (childID==0): objectID=winUser.OBJID_CLIENT #Ignore events with invalid window handles isWindow = winUser.isWindow(window) if window else 0 if window==0 or (not isWindow and eventID in (winUser.EVENT_SYSTEM_SWITCHSTART,winUser.EVENT_SYSTEM_SWITCHEND,winUser.EVENT_SYSTEM_MENUEND,winUser.EVENT_SYSTEM_MENUPOPUPEND)): window=winUser.getDesktopWindow() elif not isWindow: return if childID<0: tempWindow=window while tempWindow and not winUser.getWindowStyle(tempWindow)&winUser.WS_POPUP and winUser.getClassName(tempWindow)=="MozillaWindowClass": tempWindow=winUser.getAncestor(tempWindow,winUser.GA_PARENT) if tempWindow and winUser.getClassName(tempWindow).startswith('Mozilla'): window=tempWindow windowClassName=winUser.getClassName(window) # Modern IME candidate list windows fire menu events which confuse us # and can't be used properly in conjunction with input composition support. if windowClassName=="Microsoft.IME.UIManager.CandidateWindow.Host" and eventID in MENU_EVENTIDS: return #At the moment we can't handle show, hide or reorder events on Mozilla Firefox Location bar,as there are just too many of them #Ignore show, hide and reorder on MozillaDropShadowWindowClass windows. if windowClassName.startswith('Mozilla') and eventID in (winUser.EVENT_OBJECT_SHOW,winUser.EVENT_OBJECT_HIDE,winUser.EVENT_OBJECT_REORDER) and childID<0: #Mozilla Gecko can sometimes fire win events on a catch-all window which isn't really the real window #Move up the ancestry to find the real mozilla Window and use that if winUser.getClassName(window)=='MozillaDropShadowWindowClass': return if eventID==winUser.EVENT_SYSTEM_FOREGROUND: #We never want to see foreground events for the Program Manager or Shell (task bar) if windowClassName in ("Progman","Shell_TrayWnd"): return # #3831: Event handling can be deferred if Windows takes a while to change the foreground window. # See pumpAll for details. global _deferUntilForegroundWindow,_foregroundDefers _deferUntilForegroundWindow=window _foregroundDefers=0 if windowClassName=="MSNHiddenWindowClass": # HACK: Events get fired by this window in Windows Live Messenger 2009 when it starts. # If we send a WM_NULL to this window at this point (which happens in accessibleObjectFromEvent), Messenger will silently exit (#677). # Therefore, completely ignore these events, which is useless to us anyway. return if winEventLimiter.addEvent(eventID,window,objectID,childID,threadID): core.requestPump() except: log.error("winEventCallback", exc_info=True)
def winEventCallback(handle,eventID,window,objectID,childID,threadID,timestamp): try: #Ignore all object IDs from alert onwards (sound, nativeom etc) as we don't support them if objectID<=winUser.OBJID_ALERT: return #Ignore all locationChange events except ones for the caret if eventID==winUser.EVENT_OBJECT_LOCATIONCHANGE and objectID!=winUser.OBJID_CARET: return if eventID==winUser.EVENT_OBJECT_DESTROY: processDestroyWinEvent(window,objectID,childID) return #Change window objIDs to client objIDs for better reporting of objects if (objectID==0) and (childID==0): objectID=winUser.OBJID_CLIENT #Ignore events with invalid window handles isWindow = winUser.isWindow(window) if window else 0 if window==0 or (not isWindow and eventID in (winUser.EVENT_SYSTEM_SWITCHSTART,winUser.EVENT_SYSTEM_SWITCHEND,winUser.EVENT_SYSTEM_MENUEND,winUser.EVENT_SYSTEM_MENUPOPUPEND)): window=winUser.getDesktopWindow() elif not isWindow: return if childID<0: tempWindow=window while tempWindow and not winUser.getWindowStyle(tempWindow)&winUser.WS_POPUP and winUser.getClassName(tempWindow)=="MozillaWindowClass": tempWindow=winUser.getAncestor(tempWindow,winUser.GA_PARENT) if tempWindow and winUser.getClassName(tempWindow).startswith('Mozilla'): window=tempWindow windowClassName=winUser.getClassName(window) #At the moment we can't handle show, hide or reorder events on Mozilla Firefox Location bar,as there are just too many of them #Ignore show, hide and reorder on MozillaDropShadowWindowClass windows. if windowClassName.startswith('Mozilla') and eventID in (winUser.EVENT_OBJECT_SHOW,winUser.EVENT_OBJECT_HIDE,winUser.EVENT_OBJECT_REORDER) and childID<0: #Mozilla Gecko can sometimes fire win events on a catch-all window which isn't really the real window #Move up the ancestry to find the real mozilla Window and use that if winUser.getClassName(window)=='MozillaDropShadowWindowClass': return if eventID==winUser.EVENT_SYSTEM_FOREGROUND: #We never want to see foreground events for the Program Manager or Shell (task bar) if windowClassName in ("Progman","Shell_TrayWnd"): return # #3831: Event handling can be deferred if Windows takes a while to change the foreground window. # See pumpAll for details. global _deferUntilForegroundWindow,_foregroundDefers _deferUntilForegroundWindow=window _foregroundDefers=0 if windowClassName=="MSNHiddenWindowClass": # HACK: Events get fired by this window in Windows Live Messenger 2009 when it starts. # If we send a WM_NULL to this window at this point (which happens in accessibleObjectFromEvent), Messenger will silently exit (#677). # Therefore, completely ignore these events, which is useless to us anyway. return if winEventLimiter.addEvent(eventID,window,objectID,childID,threadID): core.requestPump() except: log.error("winEventCallback", exc_info=True)
def isBadUIAWindow(self,hwnd): windowClass=winUser.getClassName(hwnd) # #2816: Outlook versions before 2016 auto complete does not fire enough UIA events, IAccessible is better. if windowClass=="NetUIHWND": 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
def shouldAcceptEvent(eventName, windowHandle=None): """Check whether an event should be accepted from a platform API. Creating NVDAObjects and executing events can be expensive and might block the main thread noticeably if the object is slow to respond. Therefore, this should be used before NVDAObject creation to filter out any unnecessary events. A platform API handler may do its own filtering before this. """ if not windowHandle: # We can't filter without a window handle. return True key = (eventName, winUser.getWindowThreadProcessID(windowHandle)[0], winUser.getClassName(windowHandle)) if key in _acceptEvents: return True if eventName == "valueChange" and config.conf["presentation"]["progressBarUpdates"]["reportBackgroundProgressBars"]: return True if eventName == "show": # Only accept 'show' events for specific cases, as otherwise we get flooded. return winUser.getClassName(windowHandle) in ( "Frame Notification Bar", # notification bars "tooltips_class32", # tooltips "mscandui21.candidate", "mscandui40.candidate", "MSCandUIWindow_Candidate", # IMM candidates "TTrayAlert", # 5405: Skype ) if eventName == "reorder": # Prevent another flood risk. return winUser.getClassName(windowHandle) == "TTrayAlert" # #4841: Skype if eventName == "alert" and winUser.getClassName(winUser.getAncestor(windowHandle, winUser.GA_PARENT)) == "ToastChildWindowClass": # Toast notifications. return True if eventName in ("menuEnd", "switchEnd", "desktopSwitch"): # #5302, #5462: These events can be fired on the desktop window # or windows that would otherwise be blocked. # Platform API handlers will translate these events to focus events anyway, # so we must allow them here. return True if windowHandle == winUser.getDesktopWindow(): # #5595: Events for the cursor get mapped to the desktop window. return True fg = winUser.getForegroundWindow() if (winUser.isDescendantWindow(fg, windowHandle) # #3899, #3905: Covers cases such as the Firefox Page Bookmarked window and OpenOffice/LibreOffice context menus. or winUser.isDescendantWindow(fg, winUser.getAncestor(windowHandle, winUser.GA_ROOTOWNER))): # This is for the foreground application. return True if (winUser.user32.GetWindowLongW(windowHandle, winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST or winUser.user32.GetWindowLongW(winUser.getAncestor(windowHandle, winUser.GA_ROOT), winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST): # This window or its root is a topmost window. # This includes menus, combo box pop-ups and the task switching list. return True return False
def shouldAcceptEvent(eventName, windowHandle=None): """Check whether an event should be accepted from a platform API. Creating NVDAObjects and executing events can be expensive and might block the main thread noticeably if the object is slow to respond. Therefore, this should be used before NVDAObject creation to filter out any unnecessary events. A platform API handler may do its own filtering before this. """ if not windowHandle: # We can't filter without a window handle. return True key = (eventName, winUser.getWindowThreadProcessID(windowHandle)[0], winUser.getClassName(windowHandle)) if key in _acceptEvents: return True if eventName == "valueChange" and config.conf["presentation"]["progressBarUpdates"]["reportBackgroundProgressBars"]: return True if eventName == "show": # Only accept 'show' events for specific cases, as otherwise we get flooded. return winUser.getClassName(windowHandle) in ( "Frame Notification Bar", # notification bars "tooltips_class32", # tooltips "mscandui21.candidate", "mscandui40.candidate", "MSCandUIWindow_Candidate", # IMM candidates "TTrayAlert", # 5405: Skype ) if eventName == "reorder": # Prevent another flood risk. return winUser.getClassName(windowHandle) == "TTrayAlert" # #4841: Skype if eventName == "alert" and winUser.getClassName(winUser.getAncestor(windowHandle, winUser.GA_PARENT)) == "ToastChildWindowClass": # Toast notifications. return True if eventName in ("menuEnd", "switchEnd", "desktopSwitch"): # #5302, #5462: These events can be fired on the desktop window # or windows that would otherwise be blocked. # Platform API handlers will translate these events to focus events anyway, # so we must allow them here. return True fg = winUser.getForegroundWindow() if (winUser.isDescendantWindow(fg, windowHandle) # #3899, #3905: Covers cases such as the Firefox Page Bookmarked window and OpenOffice/LibreOffice context menus. or winUser.isDescendantWindow(fg, winUser.getAncestor(windowHandle, winUser.GA_ROOTOWNER))): # This is for the foreground application. return True if (winUser.user32.GetWindowLongW(windowHandle, winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST or winUser.user32.GetWindowLongW(winUser.getAncestor(windowHandle, winUser.GA_ROOT), winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST): # This window or its root is a topmost window. # This includes menus, combo box pop-ups and the task switching list. return True return False
def callback(window, data): if ((visible is None or winUser.isWindowVisible(window) == visible) and (not controlID or winUser.getControlID(window) == controlID) and (not className or winUser.getClassName(window) == className)): result.append(window) return False return True
def processShowWinEvent(window,objectID,childID): className=winUser.getClassName(window) #For now we only support 'show' event for tooltips as otherwize we get flooded if className=="tooltips_class32" and objectID==winUser.OBJID_CLIENT: NVDAEvent=winEventToNVDAEvent(winUser.EVENT_OBJECT_SHOW,window,objectID,childID) if NVDAEvent: eventHandler.queueEvent(*NVDAEvent)
def processShowWinEvent(window,objectID,childID): className=winUser.getClassName(window) #For now we only support 'show' event for tooltips, IMM candidates and notification bars as otherwize we get flooded if className in ("Frame Notification Bar","tooltips_class32","mscandui21.candidate","mscandui40.candidate","MSCandUIWindow_Candidate") and objectID==winUser.OBJID_CLIENT: NVDAEvent=winEventToNVDAEvent(winUser.EVENT_OBJECT_SHOW,window,objectID,childID) if NVDAEvent: eventHandler.queueEvent(*NVDAEvent)
def findGroupboxObject(obj): prevWindow = winUser.getPreviousWindow(obj.windowHandle) while prevWindow: if (winUser.getClassName(prevWindow) == "Button" and winUser.getWindowStyle(prevWindow) & winUser.BS_GROUPBOX and winUser.isWindowVisible(prevWindow)): groupObj = NVDAObjects.IAccessible.getNVDAObjectFromEvent( prevWindow, winUser.OBJID_CLIENT, 0) try: (left, top, width, height) = obj.location (groupLeft, groupTop, groupWidth, groupHeight) = groupObj.location except: # noqa: E722 Bare except return if (groupObj.IAccessibleRole == oleacc.ROLE_SYSTEM_GROUPING and left >= groupLeft and (left + width) <= (groupLeft + groupWidth) and top >= groupTop and (top + height) <= (groupTop + groupHeight)): return groupObj tempWindow = winUser.getPreviousWindow(prevWindow) if tempWindow == prevWindow: # In rare cases (e.g. HWND 65554 "Message"), getPreviousWindow can return # the window passed to it, causing an infinite loop. break prevWindow = tempWindow
def _isNetUIEmbeddedInWordDoc(self, element: UIA.IUIAutomationElement) -> bool: """ Detects if the given UIA element represents a control in a NetUI container embedded within a MS Word document window. E.g. the Modern Comments side track pane. This method also caches the answer on the element itself to both speed up checking later and to allow checking on an already dead element E.g. a previous focus. """ if getattr(element, '_isNetUIEmbeddedInWordDoc', False): return True windowHandle = self.getNearestWindowHandle(element) if winUser.getClassName(windowHandle) != MS_WORD_DOCUMENT_WINDOW_CLASS: return False condition = utils.createUIAMultiPropertyCondition( {UIA.UIA_ClassNamePropertyId: 'NetUIHWNDElement'}, {UIA.UIA_NativeWindowHandlePropertyId: windowHandle}) walker = self.clientObject.createTreeWalker(condition) cacheRequest = self.clientObject.createCacheRequest() cacheRequest.AddProperty(UIA.UIA_ClassNamePropertyId) cacheRequest.AddProperty(UIA.UIA_NativeWindowHandlePropertyId) ancestor = walker.NormalizeElementBuildCache(element, cacheRequest) # ancestor will either be the embedded NetUIElement, or just hit the root of the MS Word document window if ancestor.CachedClassName != 'NetUIHWNDElement': return False element._isNetUIEmbeddedInWordDoc = True return True
def event_NVDAObject_init(self,obj): if controlTypes.STATE_FOCUSED in obj.states: obj.windowHandle=winUser.getGUIThreadInfo(None).hwndFocus obj.windowClassName=winUser.getClassName(obj.windowHandle) if obj.value and obj.windowClassName in ["TMainUserList", "TConversationList", "TInboxList", "TActiveConversationList", "TConversationsControl"] and not obj.role in [controlTypes.ROLE_MENUBAR, controlTypes.ROLE_MENUITEM, controlTypes.ROLE_POPUPMENU]: obj.name=obj.value obj.value=None
def isNativeUIAElement(self, UIAElement): #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable. #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze. try: processID = UIAElement.cachedProcessId except COMError: return False if processID == windll.kernel32.GetCurrentProcessId(): return False # Whether this is a native element depends on whether its window natively supports UIA. windowHandle = self.getNearestWindowHandle(UIAElement) if windowHandle: if self.isUIAWindow(windowHandle): return True # #12982: although NVDA by default may not treat this element's window as native UIA, # E.g. it is proxied from MSAA, or NVDA has specifically black listed it, # It may be an element from a NetUIcontainer embedded in a Word document, # such as the MS Word Modern Comments side track pane. # These elements are only exposed via UIA, and not MSAA, # thus we must treat these elements as native UIA. if self._isNetUIEmbeddedInWordDoc(UIAElement): return True if winUser.getClassName( windowHandle ) == "DirectUIHWND" and "IEFRAME.dll" in UIAElement.cachedProviderDescription and UIAElement.currentClassName in ( "DownloadBox", "accessiblebutton", "DUIToolbarButton", "PushButton"): # This is the IE 9 downloads list. # #3354: UiaHasServerSideProvider returns false for the IE 9 downloads list window, # so we'd normally use MSAA for this control. # However, its MSAA implementation is broken (fires invalid events) if UIA is initialised, # whereas its UIA implementation works correctly. # Therefore, we must use UIA here. return True return False
def isNativeUIAElement(self, UIAElement): #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable. #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze. try: processID = UIAElement.cachedProcessId except COMError: return False if processID == windll.kernel32.GetCurrentProcessId(): return False # Whether this is a native element depends on whether its window natively supports UIA. windowHandle = self.getNearestWindowHandle(UIAElement) if windowHandle: if self.isUIAWindow(windowHandle): return True if winUser.getClassName( windowHandle ) == "DirectUIHWND" and "IEFRAME.dll" in UIAElement.cachedProviderDescription and UIAElement.currentClassName in ( "DownloadBox", "accessiblebutton", "DUIToolbarButton", "PushButton"): # This is the IE 9 downloads list. # #3354: UiaHasServerSideProvider returns false for the IE 9 downloads list window, # so we'd normally use MSAA for this control. # However, its MSAA implementation is broken (fires invalid events) if UIA is initialised, # whereas its UIA implementation works correctly. # Therefore, we must use UIA here. return True return False
def getPossibleAPIClasses(cls,kwargs,relation=None): windowHandle=kwargs['windowHandle'] windowClassName=winUser.getClassName(windowHandle) #The desktop window should stay as a window if windowClassName=="#32769": return #If this window has a ghost window its too dangerous to try any higher APIs if GhostWindowFromHungWindow and GhostWindowFromHungWindow(windowHandle): return if windowClassName=="EXCEL7" and (relation=='focus' or isinstance(relation,tuple)): from . import excel yield excel.ExcelCell if windowClassName=="EXCEL:": from .excel import ExcelDropdown as newCls yield newCls import JABHandler if JABHandler.isJavaWindow(windowHandle): import NVDAObjects.JAB yield NVDAObjects.JAB.JAB import UIAHandler if UIAHandler.handler and UIAHandler.handler.isUIAWindow(windowHandle): import NVDAObjects.UIA yield NVDAObjects.UIA.UIA import NVDAObjects.IAccessible yield NVDAObjects.IAccessible.IAccessible
def event_NVDAObject_init(self, obj): windowClass = obj.windowClassName role = obj.role if windowClass == "ToolbarWindow32" and role == controlTypes.ROLE_POPUPMENU: parent = obj.parent if parent and parent.windowClassName == "SysPager" and not (obj.windowStyle & 0x80): # This is the menu for a group of icons on the task bar, which Windows stupidly names "Application". obj.name = None return if windowClass == "#32768": # Standard menu. parent = obj.parent if parent and not parent.parent: # Context menu. # We don't trust the names that Explorer gives to context menus, so better to have no name at all. obj.name = None return if windowClass == "DV2ControlHost" and role == controlTypes.ROLE_PANE: # Windows Vista/7 start menu. obj.presentationType=obj.presType_content obj.isPresentableFocusAncestor = True # In Windows 7, the description of this pane is extremely verbose help text, so nuke it. obj.description = None return # The Address bar is embedded inside a progressbar, how strange. # Lets hide that if windowClass=="msctls_progress32" and winUser.getClassName(winUser.getAncestor(obj.windowHandle,winUser.GA_PARENT))=="Address Band Root": obj.presentationType=obj.presType_layout
def isNativeUIAElement(self,UIAElement): #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable. #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze. try: processID=UIAElement.cachedProcessId except COMError: return False if processID==windll.kernel32.GetCurrentProcessId(): return False # Whether this is a native element depends on whether its window natively supports UIA. try: windowHandle=UIAElement.cachedNativeWindowHandle except COMError: windowHandle=None if not windowHandle: # Some elements report no window handle, so use the nearest ancestor window handle in this case. windowHandle=self.getNearestWindowHandle(UIAElement) if windowHandle: if self.isUIAWindow(windowHandle): return True if winUser.getClassName(windowHandle)=="DirectUIHWND" and "IEFRAME.dll" in UIAElement.cachedProviderDescription and UIAElement.currentClassName in ("DownloadBox", "accessiblebutton", "DUIToolbarButton", "PushButton"): # This is the IE 9 downloads list. # #3354: UiaHasServerSideProvider returns false for the IE 9 downloads list window, # so we'd normally use MSAA for this control. # However, its MSAA implementation is broken (fires invalid events) if UIA is initialised, # whereas its UIA implementation works correctly. # Therefore, we must use UIA here. return True return False
def processFocusWinEvent(window,objectID,childID,force=False): """checks to see if the focus win event is not the same as the existing focus, then converts the win event to an NVDA event (instanciating an NVDA Object) then calls processFocusNVDAEvent. If all is ok it returns True. @type window: integer @param objectID: a win event's object ID @type objectID: integer @param childID: a win event's child ID @type childID: integer @param force: If True, the shouldAllowIAccessibleFocusEvent property of the object is ignored. @type force: boolean @returns: True if the focus is valid and was handled, False otherwise. @rtype: boolean """ windowClassName=winUser.getClassName(window) # Generally, we must ignore focus on child windows of SDM windows as we only want the SDM MSAA events. # However, we don't want to ignore focus if the child ID isn't 0, # as this is a child control and the SDM MSAA events don't handle child controls. if childID==0 and not windowClassName.startswith('bosa_sdm') and winUser.getClassName(winUser.getAncestor(window,winUser.GA_PARENT)).startswith('bosa_sdm'): return False rootWindow=winUser.getAncestor(window,winUser.GA_ROOT) # If this window is not within the foreground window and this window or its root window is not a popup window, and this window's root window is not the highest in the z-order if not winUser.isDescendantWindow(winUser.getForegroundWindow(),window) and not (winUser.getWindowStyle(window) & winUser.WS_POPUP or winUser.getWindowStyle(rootWindow)&winUser.WS_POPUP) and winUser.getPreviousWindow(rootWindow)!=0: # This is a focus event from a background window, so ignore it. return False #Notify appModuleHandler of this new foreground window appModuleHandler.update(winUser.getWindowThreadProcessID(window)[0]) #If Java access bridge is running, and this is a java window, then pass it to java and forget about it if JABHandler.isRunning and JABHandler.isJavaWindow(window): JABHandler.event_enterJavaWindow(window) return True #Convert the win event to an NVDA event NVDAEvent=winEventToNVDAEvent(winUser.EVENT_OBJECT_FOCUS,window,objectID,childID,useCache=False) if not NVDAEvent: return False eventName,obj=NVDAEvent if (childID==0 and obj.IAccessibleRole==oleacc.ROLE_SYSTEM_LIST) or (objectID==winUser.OBJID_CLIENT and "SysListView32" in obj.windowClassName): # Some controls incorrectly fire focus on child ID 0, even when there is a child with focus. try: realChildID=obj.IAccessibleObject.accFocus except: realChildID=None if isinstance(realChildID,int) and realChildID>0 and realChildID!=childID: realObj=NVDAObjects.IAccessible.IAccessible(IAccessibleObject=obj.IAccessibleObject,IAccessibleChildID=realChildID,event_windowHandle=window,event_objectID=objectID,event_childID=realChildID) if realObj: obj=realObj return processFocusNVDAEvent(obj,force=force)
def callback(window, data): if ( (visible is None or winUser.isWindowVisible(window) == visible) and (not controlID or winUser.getControlID(window) == controlID) and (not className or winUser.getClassName(window) == className) ): result.append(window) return False return True
def _isUIAWindowHelper(self, hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID = winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId() == processID: return False import NVDAObjects.window windowClass = NVDAObjects.window.Window.normalizeWindowClassName( winUser.getClassName(hwnd)) # For certain window classes, we always want to use UIA. if windowClass in goodUIAWindowClassNames: return True # allow the appModule for the window to also choose if this window is good # An appModule should be able to override bad UIA class names as prescribed by core appModule = appModuleHandler.getAppModuleFromProcessID(processID) if appModule and appModule.isGoodUIAWindow(hwnd): return True # There are certain window classes that just had bad UIA implementations if windowClass in badUIAWindowClassNames: 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 # 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, as we know their versioning scheme. # But if the Word Document control is used in other unknown apps we should just use UIA if it has been implemented. 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 version information %s, %s" % (appModule.productVersion, e)) return True if (versionMajor < minMSWordUIAVersion.major or versionMajor == minMSWordUIAVersion.major and versionMinor == minMSWordUIAVersion.minor and versionBuild < minMSWordUIAVersion.build): return False return bool(res)
def canBeHidden(self): if self.windowText == "Start": return False elif winUser.getClassName( self.handle) in ("WorkerW", "Progman", "Shell_TrayWnd", "DV2ControlHost", "Windows.UI.Core.CoreWindow"): return False else: return True
def _get_SDMChild(self): if controlTypes.STATE_FOCUSED in self.states: hwndFocus=winUser.getGUIThreadInfo(0).hwndFocus if hwndFocus and hwndFocus!=self.windowHandle and not winUser.getClassName(hwndFocus).startswith('bosa_sdm'): obj=getNVDAObjectFromEvent(hwndFocus,winUser.OBJID_CLIENT,0) if not obj: return None if getattr(obj,'parentSDMCanOverrideName',True): obj.name=self.name return obj return None
def event_NVDAObject_init(self,obj): controlID=obj.windowControlID windowHandle=obj.windowHandle parentWindow=winUser.getAncestor(windowHandle,winUser.GA_PARENT) parentClassName=winUser.getClassName(parentWindow) #If this object is an email header field, and we have a custom label for it, #Then set the object's name to the label if parentClassName=="OE_Envelope" and obj.IAccessibleChildID==0 and envelopeNames.has_key(controlID): obj.name=envelopeNames[controlID] obj.useITextDocumentSupport=True obj.editValueUnit=textInfos.UNIT_STORY
def _fetchPpObjectModelHelper(self,windowHandle=None): m=None # Its only safe to get the object model from PowerPoint 2003 to 2010 windows. # In PowerPoint 2013 protected mode it causes security/stability issues if windowHandle and winUser.getClassName(windowHandle)=="paneClassDC": m=self._getPpObjectModelFromWindow(windowHandle) if not m: m=self._getPpObjectModelFromROT(useRPC=True) if not m: m=self._getPpObjectModelFromROT() return m
def _isUIAWindowHelper(self,hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID=winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId()==processID: return False import NVDAObjects.window windowClass=NVDAObjects.window.Window.normalizeWindowClassName(winUser.getClassName(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. if winUser.getClassName(parentHwnd)=="Net UI Tool Window": return False # allow the appModule for the window to also choose if this window is bad appModule=appModuleHandler.getAppModuleFromProcessID(processID) if appModule and appModule.isBadUIAWindow(hwnd): return False # Ask the window if it supports UIA natively return windll.UIAutomationCore.UiaHasServerSideProvider(hwnd)
def event_NVDAObject_init(self,obj): if not isinstance(obj,Window): return controlID=obj.windowControlID windowHandle=obj.windowHandle parentWindow=winUser.getAncestor(windowHandle,winUser.GA_PARENT) parentClassName=winUser.getClassName(parentWindow) #If this object is an email header field, and we have a custom label for it, #Then set the object's name to the label if parentClassName=="OE_Envelope" and isinstance(obj,IAccessible) and obj.IAccessibleChildID==0 and controlID in envelopeNames: obj.name=envelopeNames[controlID] obj.useITextDocumentSupport=True obj.editValueUnit=textInfos.UNIT_STORY
def processShowWinEvent(window,objectID,childID): # eventHandler.shouldAcceptEvent only accepts show events for a few specific cases. # Narrow this further to only accept events for clients or custom objects. if objectID==winUser.OBJID_CLIENT or objectID>0: NVDAEvent=winEventToNVDAEvent(winUser.EVENT_OBJECT_SHOW,window,objectID,childID) if NVDAEvent: eventHandler.queueEvent(*NVDAEvent) #nvdajp begin if winUser.getClassName(window)[:5] in ('ATOK2', 'ATOK3'): NVDAEvent=winEventToNVDAEvent(winUser.EVENT_OBJECT_SHOW,window,objectID,childID) if NVDAEvent: eventHandler.queueEvent(*NVDAEvent)
def event_NVDAObject_init(self,obj): #The root document of HTML Metro Apps must be treeted as an application. if isinstance(obj,Body) and obj.windowClassName=="Internet Explorer_Server": try: paccParent=obj.IAccessibleObject.accParent.accParent identity=IAccessibleHandler.getIAccIdentity(paccParent,0) except (COMError,AttributeError): identity=None if identity: windowHandle=identity.get('windowHandle') if windowHandle and winUser.getClassName(windowHandle)=="Web Platform Embedding": obj.role=controlTypes.ROLE_APPLICATION
def chooseNVDAObjectOverlayClasses(self, obj, clsList): if UIAWordDocument in clsList: # Overlay class for Outlook message viewer when UI Automation for MS Word is enabled. clsList.insert(0, OutlookUIAWordDocument) if isinstance(obj, UIA) and obj.UIAElement.cachedClassName in ( "LeafRow", "ThreadItem", "ThreadHeader"): clsList.insert(0, UIAGridRow) 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. # Therefore remove the Dialog behavior for these imbedded dialog forms so as to not announce junk as the caption if Dialog in clsList: parentWindow = winUser.getAncestor(obj.windowHandle, winUser.GA_PARENT) if parentWindow and winUser.getClassName( parentWindow) == "AfxWndW": clsList.remove(Dialog) if WordDocument in clsList: clsList.insert(0, OutlookWordDocument) states = obj.states controlID = obj.windowControlID # Support the date picker in Outlook Meeting / Appointment creation forms if controlID == 4352 and role == controlTypes.ROLE_BUTTON: clsList.insert(0, DatePickerButton) elif role == controlTypes.ROLE_TABLECELL and windowClassName == "rctrl_renwnd32": clsList.insert(0, DatePickerCell) elif windowClassName == "REListBox20W" and role == controlTypes.ROLE_CHECKBOX: clsList.insert(0, REListBox20W_CheckBox) if role == controlTypes.ROLE_LISTITEM and windowClassName == "OUTEXVLB": clsList.insert(0, AddressBookEntry) return if (windowClassName == "SUPERGRID" and controlID == 4704) or (windowClassName == "rctrl_renwnd32" and controlID == 109): outlookVersion = self.outlookVersion if (outlookVersion and outlookVersion > 9 and obj.event_objectID == winUser.OBJID_CLIENT and obj.event_childID == 0): clsList.insert(0, SuperGridClient2010) if (windowClassName == "AfxWndW" and controlID == 109) or (windowClassName in ("WeekViewWnd", "DayViewWnd")): clsList.insert(0, CalendarView)
def findGroupboxObject(obj): prevWindow=winUser.getPreviousWindow(obj.windowHandle) while prevWindow: if winUser.getClassName(prevWindow)=="Button" and winUser.getWindowStyle(prevWindow)&winUser.BS_GROUPBOX and winUser.isWindowVisible(prevWindow): groupObj=NVDAObjects.IAccessible.getNVDAObjectFromEvent(prevWindow,winUser.OBJID_CLIENT,0) try: (left,top,width,height)=obj.location (groupLeft,groupTop,groupWidth,groupHeight)=groupObj.location except: return if groupObj.IAccessibleRole==oleacc.ROLE_SYSTEM_GROUPING and left>=groupLeft and (left+width)<=(groupLeft+groupWidth) and top>=groupTop and (top+height)<=(groupTop+groupHeight): return groupObj prevWindow=winUser.getPreviousWindow(prevWindow)
def isUIAWindow(self,hwnd): now=time.time() v=self.UIAWindowHandleCache.get(hwnd,None) if not v or (now-v[1])>0.5: if windll.kernel32.GetCurrentProcessId()==winUser.getWindowThreadProcessID(hwnd)[0]: isUIA=False elif winUser.getClassName(hwnd) in badUIAWindowClassNames: isUIA=False else: isUIA=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd) self.UIAWindowHandleCache[hwnd]=(isUIA,now) return isUIA return v[0]
def getTopWindow(obj=None): if obj is None: obj = api.getFocusObject() i = 10 while i and obj: i = i - 1 if winUser.getClassName(obj.windowHandle) == "#32770": return obj.windowHandle try: obj = obj.parent except Exception: return None return None
def event_NVDAObject_init(self,obj): if isinstance(obj, NVDAObjects.IAccessible.IAccessible) and obj.event_objectID is None and controlTypes.STATE_FOCUSED in obj.states and obj.role not in (controlTypes.ROLE_POPUPMENU,controlTypes.ROLE_MENUITEM,controlTypes.ROLE_MENUBAR): # The window handle reported by Skype accessibles is sometimes incorrect. # This object is focused, so we can override with the focus window. obj.windowHandle=winUser.getGUIThreadInfo(None).hwndFocus obj.windowClassName=winUser.getClassName(obj.windowHandle) if obj.value and obj.windowClassName in ("TMainUserList", "TConversationList", "TInboxList", "TActiveConversationList", "TConversationsControl"): # The name and value both include the user's name, so kill the value to avoid doubling up. # The value includes the Skype name, # but we care more about the additional info (e.g. new event count) included in the name. obj.value=None elif isinstance(obj, NVDAObjects.IAccessible.IAccessible) and obj.IAccessibleRole == oleacc.ROLE_SYSTEM_PANE and not obj.name: # Prevent extraneous reporting of pane when tabbing through a conversation form. obj.shouldAllowIAccessibleFocusEvent = False
def event_NVDAObject_init(self, obj): windowClass = obj.windowClassName role = obj.role if windowClass == "ToolbarWindow32" and role == controlTypes.Role.POPUPMENU: parent = obj.parent if parent and parent.windowClassName == "SysPager" and not ( obj.windowStyle & 0x80): # This is the menu for a group of icons on the task bar, which Windows stupidly names "Application". obj.name = None return if windowClass == "#32768": # Standard menu. parent = obj.parent if parent and not parent.parent: # Context menu. # We don't trust the names that Explorer gives to context menus, so better to have no name at all. obj.name = None return if windowClass == "DV2ControlHost" and role == controlTypes.Role.PANE: # Windows 7 start menu. obj.presentationType = obj.presType_content obj.isPresentableFocusAncestor = True # In Windows 7, the description of this pane is extremely verbose help text, so nuke it. obj.description = None return # The Address bar is embedded inside a progressbar, how strange. # Lets hide that if windowClass == "msctls_progress32" and winUser.getClassName( winUser.getAncestor(obj.windowHandle, winUser.GA_PARENT)) == "Address Band Root": obj.presentationType = obj.presType_layout return if windowClass == "DirectUIHWND" and role == controlTypes.Role.LIST: # Is this a list containing search results in Windows 7 start menu? isWin7SearchResultsList = False try: if obj.parent and obj.parent.parent: parent = obj.parent.parent.parent isWin7SearchResultsList = parent is not None and parent.windowClassName == "Desktop Search Open View" except AttributeError: isWin7SearchResultsList = False if isWin7SearchResultsList: # Namae of this list is not useful and should be discarded. obj.name = None return
def event_NVDAObject_init(self, obj): if controlTypes.STATE_FOCUSED in obj.states and obj.role not in ( controlTypes.ROLE_POPUPMENU, controlTypes.ROLE_MENUITEM): obj.windowHandle = winUser.getGUIThreadInfo(None).hwndFocus obj.windowClassName = winUser.getClassName(obj.windowHandle) if obj.value and obj.windowClassName in [ "TMainUserList", "TConversationList", "TInboxList", "TActiveConversationList", "TConversationsControl" ] and not obj.role in [ controlTypes.ROLE_MENUBAR, controlTypes.ROLE_MENUITEM, controlTypes.ROLE_POPUPMENU ]: obj.name = obj.value obj.value = None
def isUIAWindow(self,hwnd): now=time.time() v=self.UIAWindowHandleCache.get(hwnd,None) if not v or (now-v[1])>0.5: import NVDAObjects.window if windll.kernel32.GetCurrentProcessId()==winUser.getWindowThreadProcessID(hwnd)[0]: isUIA=False elif NVDAObjects.window.Window.normalizeWindowClassName(winUser.getClassName(hwnd)) in badUIAWindowClassNames: isUIA=False else: isUIA=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd) self.UIAWindowHandleCache[hwnd]=(isUIA,now) return isUIA return v[0]
def event_NVDAObject_init(self, obj): #The root document of HTML Metro Apps must be treeted as an application. if isinstance( obj, Body) and obj.windowClassName == "Internet Explorer_Server": try: paccParent = obj.IAccessibleObject.accParent.accParent identity = IAccessibleHandler.getIAccIdentity(paccParent, 0) except (COMError, AttributeError): identity = None if identity: windowHandle = identity.get('windowHandle') if windowHandle and winUser.getClassName( windowHandle) == "Web Platform Embedding": obj.role = controlTypes.ROLE_APPLICATION
def event_NVDAObject_init(self, obj): if not isinstance(obj, Window): return role = obj.role if role == controlTypes.ROLE_WINDOW: return wclass = Window.normalizeWindowClassName(obj.windowClassName) if wclass == "Window.8" and role == controlTypes.ROLE_PANE: # optimisation: There are quite a lot of these, so let's not instantiate parent NVDAObjects unnecessarily. parentWindow = winUser.getAncestor(obj.windowHandle, winUser.GA_PARENT) if parentWindow and Window.normalizeWindowClassName(winUser.getClassName(parentWindow)) == "SysTabControl32": obj.role = controlTypes.ROLE_PROPERTYPAGE elif wclass == "SysTabControl32": obj.isPresentableFocusAncestor = False
def _shouldRecoverAfterMinTimeout(): info=winUser.getGUIThreadInfo(0) #If hwndFocus is 0, then the OS is clearly busy and we don't want to timeout prematurely. if not info.hwndFocus: return False # Import late to avoid circular import. import api #If a system menu has been activated but NVDA's focus is not yet in the menu then use min timeout if info.flags&winUser.GUI_SYSTEMMENUMODE and info.hwndMenuOwner and api.getFocusObject().windowClassName!='#32768': return True if winUser.getClassName(info.hwndFocus) in safeWindowClassSet: return False if not winUser.isDescendantWindow(info.hwndActive, api.getFocusObject().windowHandle): # The foreground window has changed. return True newHwnd=info.hwndFocus newThreadID=winUser.getWindowThreadProcessID(newHwnd)[1] return newThreadID!=api.getFocusObject().windowThreadID
def focusWebViewDocument(self, retry=5): user32 = ctypes.windll.user32 GW_CHILD = 5 hwnd = self.webView.Handle try: while True: hwnd = user32.GetWindow(hwnd, GW_CHILD) if not hwnd: if retry >= 0: wx.CallLater(1, self.focusWebViewDocument, retry - 1) return className = winUser.getClassName(hwnd) if className == u"Internet Explorer_Server": winUser.setFocus(hwnd) return except: log.exception()
def _shouldRecoverAfterMinTimeout(): info=winUser.getGUIThreadInfo(0) if not info.hwndFocus: # The foreground thread is frozen or there is no foreground thread (probably due to a freeze elsewhere). return True # Import late to avoid circular import. import api #If a system menu has been activated but NVDA's focus is not yet in the menu then use min timeout if info.flags&winUser.GUI_SYSTEMMENUMODE and info.hwndMenuOwner and api.getFocusObject().windowClassName!='#32768': return True if winUser.getClassName(info.hwndFocus) in safeWindowClassSet: return False if not winUser.isDescendantWindow(info.hwndActive, api.getFocusObject().windowHandle): # The foreground window has changed. return True newHwnd=info.hwndFocus newThreadID=winUser.getWindowThreadProcessID(newHwnd)[1] return newThreadID!=api.getFocusObject().windowThreadID
def chooseNVDAObjectOverlayClasses(self, obj, clsList): if UIAWordDocument in clsList: # Overlay class for Outlook message viewer when UI Automation for MS Word is enabled. clsList.insert(0,OutlookUIAWordDocument) if isinstance(obj,UIA) and obj.UIAElement.cachedClassName in ("LeafRow","ThreadItem","ThreadHeader"): clsList.insert(0,UIAGridRow) 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. # Therefore remove the Dialog behavior for these imbedded dialog forms so as to not announce junk as the caption if Dialog in clsList: parentWindow=winUser.getAncestor(obj.windowHandle,winUser.GA_PARENT) if parentWindow and winUser.getClassName(parentWindow)=="AfxWndW": clsList.remove(Dialog) if WordDocument in clsList: clsList.insert(0,OutlookWordDocument) states=obj.states controlID=obj.windowControlID # Support the date picker in Outlook Meeting / Appointment creation forms if controlID==4352 and role==controlTypes.ROLE_BUTTON: clsList.insert(0,DatePickerButton) elif role==controlTypes.ROLE_TABLECELL and windowClassName=="rctrl_renwnd32": clsList.insert(0,DatePickerCell) elif windowClassName=="REListBox20W" and role==controlTypes.ROLE_CHECKBOX: clsList.insert(0,REListBox20W_CheckBox) if role==controlTypes.ROLE_LISTITEM and windowClassName=="OUTEXVLB": clsList.insert(0, AddressBookEntry) return if (windowClassName=="SUPERGRID" and controlID==4704) or (windowClassName=="rctrl_renwnd32" and controlID==109): outlookVersion=self.outlookVersion if outlookVersion and outlookVersion<=9: clsList.insert(0, MessageList_pre2003) elif obj.event_objectID==winUser.OBJID_CLIENT and obj.event_childID==0: clsList.insert(0,SuperGridClient2010) if (windowClassName == "AfxWndW" and controlID==109) or (windowClassName in ("WeekViewWnd","DayViewWnd")): clsList.insert(0,CalendarView)
def getPossibleAPIClasses(cls,kwargs,relation=None): windowHandle=kwargs['windowHandle'] windowClassName=winUser.getClassName(windowHandle) #The desktop window should stay as a window if windowClassName=="#32769": return if windowClassName=="EXCEL7" and (relation=='focus' or isinstance(relation,tuple)): from . import excel yield excel.ExcelCell import JABHandler if JABHandler.isJavaWindow(windowHandle): import NVDAObjects.JAB yield NVDAObjects.JAB.JAB import UIAHandler if UIAHandler.handler and UIAHandler.handler.isUIAWindow(windowHandle): import NVDAObjects.UIA yield NVDAObjects.UIA.UIA import NVDAObjects.IAccessible yield NVDAObjects.IAccessible.IAccessible
def _isUIAWindowHelper(self,hwnd): # UIA in NVDA's process freezes in Windows 7 and below processID=winUser.getWindowThreadProcessID(hwnd)[0] if windll.kernel32.GetCurrentProcessId()==processID: return False import NVDAObjects.window windowClass=NVDAObjects.window.Window.normalizeWindowClassName(winUser.getClassName(hwnd)) # For certain window classes, we always want to use UIA. if windowClass in goodUIAWindowClassNames: return True # allow the appModule for the window to also choose if this window is good # An appModule should be able to override bad UIA class names as prescribed by core appModule=appModuleHandler.getAppModuleFromProcessID(processID) if appModule and appModule.isGoodUIAWindow(hwnd): return True # There are certain window classes that just had bad UIA implementations if windowClass in badUIAWindowClassNames: 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 # MS Word documents now have a fairly usable UI Automation implementation. However, # Builds of MS Office 2016 before build 9000 or so had bugs which we cannot work around. # And even current builds of Office 2016 are still missing enough info from UIA that it is still impossible to switch to UIA completely. # Therefore, if we can inject in-process, refuse to use UIA and instead fall back to the MS Word object model. 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'] ): return False return bool(res)
def isBadUIAWindow(self,hwnd): if winUser.getClassName(hwnd) in ("WeekViewWnd","DayViewWnd"): return True return False
def isBadUIAWindow(self,hwnd): # PowerPoint 2013 implements UIA support for its slides etc on an mdiClass window. However its far from complete. # We must disable it in order to fall back to our own code. if winUser.getClassName(hwnd) in objectModelWindowClasses: return True return super(AppModule,self).isBadUIAWindow(hwnd)
def _get_windowClassName(self): if hasattr(self,"_windowClassName"): return self._windowClassName name=winUser.getClassName(self.windowHandle) self._windowClassName=name return name
def shouldAcceptEvent(eventName, windowHandle=None): """Check whether an event should be accepted from a platform API. Creating NVDAObjects and executing events can be expensive and might block the main thread noticeably if the object is slow to respond. Therefore, this should be used before NVDAObject creation to filter out any unnecessary events. A platform API handler may do its own filtering before this. """ if not windowHandle: # We can't filter without a window handle. return True wClass = winUser.getClassName(windowHandle) key = (eventName, winUser.getWindowThreadProcessID(windowHandle)[0], wClass) if key in _acceptEvents: return True if eventName == "valueChange" and config.conf["presentation"]["progressBarUpdates"]["reportBackgroundProgressBars"]: return True if eventName == "show": # Only accept 'show' events for specific cases, as otherwise we get flooded. return wClass in ( "Frame Notification Bar", # notification bars "tooltips_class32", # tooltips "mscandui21.candidate", "mscandui40.candidate", "MSCandUIWindow_Candidate", # IMM candidates "TTrayAlert", # 5405: Skype ) if eventName == "reorder": # Prevent another flood risk. return wClass == "TTrayAlert" # #4841: Skype if eventName == "alert" and winUser.getClassName(winUser.getAncestor(windowHandle, winUser.GA_PARENT)) == "ToastChildWindowClass": # Toast notifications. return True if eventName in ("menuEnd", "switchEnd", "desktopSwitch"): # #5302, #5462: These events can be fired on the desktop window # or windows that would otherwise be blocked. # Platform API handlers will translate these events to focus events anyway, # so we must allow them here. return True if windowHandle == winUser.getDesktopWindow(): # #5595: Events for the cursor get mapped to the desktop window. return True # #6713: Edge (and soon all UWP apps) will no longer have windows as descendants of the foreground window. # However, it does look like they are always equal to or descendants of the "active" window of the input thread. if wClass.startswith('Windows.UI.Core'): gi=winUser.getGUIThreadInfo(0) if winUser.isDescendantWindow(gi.hwndActive,windowHandle): return True fg = winUser.getForegroundWindow() if wClass == "NetUIHWND" and winUser.getClassName(fg) == "Net UI Tool Window Layered": # #5504: In Office >= 2013 with the ribbon showing only tabs, # when a tab is expanded, the window we get from the focus object is incorrect. # This window isn't beneath the foreground window, # so our foreground application checks fail. # Just compare the root owners. if winUser.getAncestor(windowHandle, winUser.GA_ROOTOWNER) == winUser.getAncestor(fg, winUser.GA_ROOTOWNER): return True if (winUser.isDescendantWindow(fg, windowHandle) # #3899, #3905: Covers cases such as the Firefox Page Bookmarked window and OpenOffice/LibreOffice context menus. or winUser.isDescendantWindow(fg, winUser.getAncestor(windowHandle, winUser.GA_ROOTOWNER))): # This is for the foreground application. return True if (winUser.user32.GetWindowLongW(windowHandle, winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST or winUser.user32.GetWindowLongW(winUser.getAncestor(windowHandle, winUser.GA_ROOT), winUser.GWL_EXSTYLE) & winUser.WS_EX_TOPMOST): # This window or its root is a topmost window. # This includes menus, combo box pop-ups and the task switching list. return True return False