-from ctypes import *\r
-from ctypes.wintypes import *\r
-import comtypes.client\r
-from comtypes import *\r
-import weakref\r
import sys\r
-import threading\r
-import time\r
+import comtypes\r
import config\r
-import api\r
-import queueHandler\r
-import controlTypes\r
-import winKernel\r
-import winUser\r
-import eventHandler\r
from logHandler import log\r
\r
-from comtypes.gen.UIAutomationClient import *\r
-\r
-badUIAWindowClassNames=[\r
- "SysTreeView32",\r
- "WuDuiListView",\r
- "ComboBox",\r
- "msctls_progress32",\r
- "Edit",\r
- "CommonPlacesWrapperWndClass",\r
-]\r
-\r
-UIAControlTypesToNVDARoles={\r
- UIA_ButtonControlTypeId:controlTypes.ROLE_BUTTON,\r
- UIA_CalendarControlTypeId:controlTypes.ROLE_CALENDAR,\r
- UIA_CheckBoxControlTypeId:controlTypes.ROLE_CHECKBOX,\r
- UIA_ComboBoxControlTypeId:controlTypes.ROLE_COMBOBOX,\r
- UIA_EditControlTypeId:controlTypes.ROLE_EDITABLETEXT,\r
- UIA_HyperlinkControlTypeId:controlTypes.ROLE_LINK,\r
- UIA_ImageControlTypeId:controlTypes.ROLE_GRAPHIC,\r
- UIA_ListItemControlTypeId:controlTypes.ROLE_LISTITEM,\r
- UIA_ListControlTypeId:controlTypes.ROLE_LIST,\r
- UIA_MenuControlTypeId:controlTypes.ROLE_POPUPMENU,\r
- UIA_MenuBarControlTypeId:controlTypes.ROLE_MENUBAR,\r
- UIA_MenuItemControlTypeId:controlTypes.ROLE_MENUITEM,\r
- UIA_ProgressBarControlTypeId:controlTypes.ROLE_PROGRESSBAR,\r
- UIA_RadioButtonControlTypeId:controlTypes.ROLE_RADIOBUTTON,\r
- UIA_ScrollBarControlTypeId:controlTypes.ROLE_SCROLLBAR,\r
- UIA_SliderControlTypeId:controlTypes.ROLE_SLIDER,\r
- UIA_SpinnerControlTypeId:controlTypes.ROLE_SPINBUTTON,\r
- UIA_StatusBarControlTypeId:controlTypes.ROLE_STATUSBAR,\r
- UIA_TabControlTypeId:controlTypes.ROLE_TABCONTROL,\r
- UIA_TabItemControlTypeId:controlTypes.ROLE_TAB,\r
- UIA_TextControlTypeId:controlTypes.ROLE_STATICTEXT,\r
- UIA_ToolBarControlTypeId:controlTypes.ROLE_TOOLBAR,\r
- UIA_ToolTipControlTypeId:controlTypes.ROLE_TOOLTIP,\r
- UIA_TreeControlTypeId:controlTypes.ROLE_TREEVIEW,\r
- UIA_TreeItemControlTypeId:controlTypes.ROLE_TREEVIEWITEM,\r
- UIA_CustomControlTypeId:controlTypes.ROLE_UNKNOWN,\r
- UIA_GroupControlTypeId:controlTypes.ROLE_GROUPING,\r
- UIA_ThumbControlTypeId:controlTypes.ROLE_THUMB,\r
- UIA_DataGridControlTypeId:controlTypes.ROLE_DATAGRID,\r
- UIA_DataItemControlTypeId:controlTypes.ROLE_DATAITEM,\r
- UIA_DocumentControlTypeId:controlTypes.ROLE_DOCUMENT,\r
- UIA_SplitButtonControlTypeId:controlTypes.ROLE_SPLITBUTTON,\r
- UIA_WindowControlTypeId:controlTypes.ROLE_WINDOW,\r
- UIA_PaneControlTypeId:controlTypes.ROLE_PANE,\r
- UIA_HeaderControlTypeId:controlTypes.ROLE_HEADER,\r
- UIA_HeaderItemControlTypeId:controlTypes.ROLE_HEADERITEM,\r
- UIA_TableControlTypeId:controlTypes.ROLE_TABLE,\r
- UIA_TitleBarControlTypeId:controlTypes.ROLE_TITLEBAR,\r
- UIA_SeparatorControlTypeId:controlTypes.ROLE_SEPARATOR,\r
-}\r
-\r
-UIAPropertyIdsToNVDAEventNames={\r
- UIA_NamePropertyId:"nameChange",\r
- UIA_HelpTextPropertyId:"descriptionChange",\r
- UIA_ExpandCollapseExpandCollapseStatePropertyId:"stateChange",\r
- UIA_ToggleToggleStatePropertyId:"stateChange",\r
- UIA_IsEnabledPropertyId:"stateChange",\r
- UIA_ValueValuePropertyId:"valueChange",\r
- UIA_RangeValueValuePropertyId:"valueChange",\r
-}\r
-\r
-UIAEventIdsToNVDAEventNames={\r
- #UIA_Text_TextChangedEventId:"textChanged",\r
- UIA_SelectionItem_ElementSelectedEventId:"stateChange",\r
- #UIA_MenuOpenedEventId:"gainFocus",\r
- UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange",\r
- UIA_SelectionItem_ElementRemovedFromSelectionEventId:"stateChange",\r
- #UIA_MenuModeEndEventId:"menuModeEnd",\r
- #UIA_Text_TextSelectionChangedEventId:"caret",\r
- #UIA_ToolTipOpenedEventId:"show",\r
- #UIA_AsyncContentLoadedEventId:"documentLoadComplete",\r
- #UIA_ToolTipClosedEventId:"hide",\r
-}\r
-\r
-class UIAHandler(COMObject):\r
- _com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler]\r
-\r
- def __init__(self):\r
- super(UIAHandler,self).__init__()\r
- self.MTAThreadInitEvent=threading.Event()\r
- self.MTAThreadStopEvent=threading.Event()\r
- self.MTAThreadInitException=None\r
- self.MTAThread=threading.Thread(target=self.MTAThreadFunc)\r
- self.MTAThread.start()\r
- self.MTAThreadInitEvent.wait(2)\r
- if self.MTAThreadInitException:\r
- raise self.MTAThreadInitException\r
-\r
- def terminate(self):\r
- MTAThreadHandle=HANDLE(windll.kernel32.OpenThread(self.MTAThread.ident,False,winKernel.SYNCHRONIZE))\r
- self.MTAThreadStopEvent.set()\r
- index=c_int()\r
- #Wait for the MTAA thread to die (while still message pumping)\r
- windll.user32.MsgWaitForMultipleObjects(1,byref(MTAThreadHandle),False,5000,0)\r
- del self.MTAThread\r
-\r
- def MTAThreadFunc(self):\r
- try:\r
- oledll.ole32.CoInitializeEx(None,comtypes.COINIT_MULTITHREADED) \r
- self.clientObject=CoCreateInstance(CUIAutomation._reg_clsid_,interface=IUIAutomation,clsctx=CLSCTX_INPROC_SERVER)\r
- self.windowTreeWalker=self.clientObject.createTreeWalker(self.clientObject.CreateNotCondition(self.clientObject.CreatePropertyCondition(UIA_NativeWindowHandlePropertyId,0)))\r
- self.windowCacheRequest=self.clientObject.CreateCacheRequest()\r
- self.windowCacheRequest.AddProperty(UIA_NativeWindowHandlePropertyId)\r
- self.UIAWindowHandleCache={}\r
- self.baseTreeWalker=self.clientObject.RawViewWalker\r
- self.baseCacheRequest=self.windowCacheRequest.Clone()\r
- for propertyId in (UIA_ClassNamePropertyId,UIA_ControlTypePropertyId,UIA_IsKeyboardFocusablePropertyId,UIA_IsPasswordPropertyId,UIA_ProviderDescriptionPropertyId,UIA_ProcessIdPropertyId,UIA_IsSelectionItemPatternAvailablePropertyId,UIA_IsTextPatternAvailablePropertyId):\r
- self.baseCacheRequest.addProperty(propertyId)\r
- self.rootElement=self.clientObject.getRootElementBuildCache(self.baseCacheRequest)\r
- self.reservedNotSupportedValue=self.clientObject.ReservedNotSupportedValue\r
- self.clientObject.AddFocusChangedEventHandler(self.baseCacheRequest,self)\r
- self.clientObject.AddPropertyChangedEventHandler(self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self,UIAPropertyIdsToNVDAEventNames.keys())\r
- for x in UIAEventIdsToNVDAEventNames.iterkeys(): \r
- self.clientObject.addAutomationEventHandler(x,self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self)\r
- except Exception as e:\r
- self.MTAThreadInitException=e\r
- finally:\r
- self.MTAThreadInitEvent.set()\r
- self.MTAThreadStopEvent.wait()\r
- self.clientObject.RemoveAllEventHandlers()\r
-\r
- def IUIAutomationEventHandler_HandleAutomationEvent(self,sender,eventID):\r
- if not self.MTAThreadInitEvent.isSet:\r
- # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
- return\r
- NVDAEventName=UIAEventIdsToNVDAEventNames.get(eventID,None)\r
- if not NVDAEventName:\r
- return\r
- if not self.isNativeUIAElement(sender):\r
- return\r
- import NVDAObjects.UIA\r
- obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
- if not obj:\r
- return\r
- eventHandler.queueEvent(NVDAEventName,obj)\r
-\r
- def IUIAutomationFocusChangedEventHandler_HandleFocusChangedEvent(self,sender):\r
- if not self.MTAThreadInitEvent.isSet:\r
- # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
- return\r
- if not self.isNativeUIAElement(sender):\r
- return\r
- try:\r
- hasFocus=sender.currentHasKeyboardFocus\r
- except COMError:\r
- return\r
- if not hasFocus: \r
- return\r
- import NVDAObjects.UIA\r
- if isinstance(eventHandler.lastQueuedFocusObject,NVDAObjects.UIA.UIA):\r
- lastFocus=eventHandler.lastQueuedFocusObject.UIAElement\r
- # Ignore duplicate focus events.\r
- # It seems that it is possible for compareElements to return True, even though the objects are different.\r
- # Therefore, don't ignore the event if the last focus object has lost its hasKeyboardFocus state.\r
- if self.clientObject.compareElements(sender,lastFocus) and lastFocus.currentHasKeyboardFocus:\r
- return\r
- obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
- eventHandler.queueEvent("gainFocus",obj)\r
-\r
- def IUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent(self,sender,propertyId,newValue):\r
- if not self.MTAThreadInitEvent.isSet:\r
- # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
- return\r
- NVDAEventName=UIAPropertyIdsToNVDAEventNames.get(propertyId,None)\r
- if not NVDAEventName:\r
- return\r
- if not self.isNativeUIAElement(sender):\r
- return\r
- import NVDAObjects.UIA\r
- obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
- if not obj:\r
- return\r
- eventHandler.queueEvent(NVDAEventName,obj)\r
-\r
- def isUIAWindow(self,hwnd):\r
- now=time.time()\r
- v=self.UIAWindowHandleCache.get(hwnd,None)\r
- if not v or (now-v[1])>0.5:\r
- if windll.kernel32.GetCurrentProcessId()==winUser.getWindowThreadProcessID(hwnd)[0]:\r
- isUIA=False\r
- elif winUser.getClassName(hwnd) in badUIAWindowClassNames:\r
- isUIA=False\r
- else:\r
- isUIA=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd)\r
- self.UIAWindowHandleCache[hwnd]=(isUIA,now)\r
- return isUIA\r
- return v[0]\r
-\r
- def getNearestWindowHandle(self,UIAElement):\r
- try:\r
- UIAElement=self.windowTreeWalker.NormalizeElementBuildCache(UIAElement,self.windowCacheRequest)\r
- except COMError:\r
- return None\r
- try:\r
- return UIAElement.cachedNativeWindowHandle\r
- except COMError:\r
- return None\r
-\r
- def isNativeUIAElement(self,UIAElement):\r
- #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable.\r
- #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze.\r
- try:\r
- processID=UIAElement.cachedProcessId\r
- except COMError:\r
- return False\r
- if processID==windll.kernel32.GetCurrentProcessId():\r
- return False\r
- #If the element has a window handle, and the window natively supports UIA, then its a native element\r
- try:\r
- windowHandle=UIAElement.cachedNativeWindowHandle\r
- except COMError:\r
- windowHandle=None\r
- if windowHandle:\r
- return self.isUIAWindow(windowHandle)\r
- #The element does not have a window, but we can class it as native if the element is not an MSAA proxy (according to provider description)\r
- try:\r
- providerDescription=UIAElement.cachedProviderDescription\r
- except COMError:\r
- return True\r
- return "Microsoft: MSAA Proxy (unmanaged:uiautomationcore.dll)" not in providerDescription\r
-\r
-\r
handler=None\r
isUIAAvailable=False\r
\r
-def initialize():\r
- global handler, isUIAAvailable\r
- if not config.conf["UIA"]["enabled"]:\r
- isUIAAvailable=False\r
- return\r
+if config.conf and config.conf["UIA"]["enabled"]:\r
winver=sys.getwindowsversion()\r
winver=winver.major+(winver.minor/10.0)\r
- if winver<config.conf["UIA"]["minWindowsVersion"]:\r
- isUIAAvailable=False\r
- return\r
+ if winver>=config.conf["UIA"]["minWindowsVersion"]:\r
+ try:\r
+ from _UIAHandler import *\r
+ isUIAAvailable=True\r
+ except ImportError:\r
+ pass\r
+\r
+def initialize():\r
+ global handler\r
+ if not isUIAAvailable:\r
+ raise NotImplementedError\r
try:\r
handler=UIAHandler()\r
except COMError:\r
- isUIAAvailable=False\r
handler=None\r
raise RuntimeError("UIA not available")\r
\r
def terminate():\r
- global handler, isUIAAvailable\r
+ global handler\r
if handler:\r
handler.terminate()\r
handler=None\r
- isUIAAvailable=False\r
--- /dev/null
+from ctypes import *\r
+from ctypes.wintypes import *\r
+import comtypes.client\r
+from comtypes import *\r
+import weakref\r
+import threading\r
+import time\r
+import api\r
+import queueHandler\r
+import controlTypes\r
+import winKernel\r
+import winUser\r
+import eventHandler\r
+from logHandler import log\r
+\r
+from comtypes.gen.UIAutomationClient import *\r
+\r
+badUIAWindowClassNames=[\r
+ "SysTreeView32",\r
+ "WuDuiListView",\r
+ "ComboBox",\r
+ "msctls_progress32",\r
+ "Edit",\r
+ "CommonPlacesWrapperWndClass",\r
+]\r
+\r
+UIAControlTypesToNVDARoles={\r
+ UIA_ButtonControlTypeId:controlTypes.ROLE_BUTTON,\r
+ UIA_CalendarControlTypeId:controlTypes.ROLE_CALENDAR,\r
+ UIA_CheckBoxControlTypeId:controlTypes.ROLE_CHECKBOX,\r
+ UIA_ComboBoxControlTypeId:controlTypes.ROLE_COMBOBOX,\r
+ UIA_EditControlTypeId:controlTypes.ROLE_EDITABLETEXT,\r
+ UIA_HyperlinkControlTypeId:controlTypes.ROLE_LINK,\r
+ UIA_ImageControlTypeId:controlTypes.ROLE_GRAPHIC,\r
+ UIA_ListItemControlTypeId:controlTypes.ROLE_LISTITEM,\r
+ UIA_ListControlTypeId:controlTypes.ROLE_LIST,\r
+ UIA_MenuControlTypeId:controlTypes.ROLE_POPUPMENU,\r
+ UIA_MenuBarControlTypeId:controlTypes.ROLE_MENUBAR,\r
+ UIA_MenuItemControlTypeId:controlTypes.ROLE_MENUITEM,\r
+ UIA_ProgressBarControlTypeId:controlTypes.ROLE_PROGRESSBAR,\r
+ UIA_RadioButtonControlTypeId:controlTypes.ROLE_RADIOBUTTON,\r
+ UIA_ScrollBarControlTypeId:controlTypes.ROLE_SCROLLBAR,\r
+ UIA_SliderControlTypeId:controlTypes.ROLE_SLIDER,\r
+ UIA_SpinnerControlTypeId:controlTypes.ROLE_SPINBUTTON,\r
+ UIA_StatusBarControlTypeId:controlTypes.ROLE_STATUSBAR,\r
+ UIA_TabControlTypeId:controlTypes.ROLE_TABCONTROL,\r
+ UIA_TabItemControlTypeId:controlTypes.ROLE_TAB,\r
+ UIA_TextControlTypeId:controlTypes.ROLE_STATICTEXT,\r
+ UIA_ToolBarControlTypeId:controlTypes.ROLE_TOOLBAR,\r
+ UIA_ToolTipControlTypeId:controlTypes.ROLE_TOOLTIP,\r
+ UIA_TreeControlTypeId:controlTypes.ROLE_TREEVIEW,\r
+ UIA_TreeItemControlTypeId:controlTypes.ROLE_TREEVIEWITEM,\r
+ UIA_CustomControlTypeId:controlTypes.ROLE_UNKNOWN,\r
+ UIA_GroupControlTypeId:controlTypes.ROLE_GROUPING,\r
+ UIA_ThumbControlTypeId:controlTypes.ROLE_THUMB,\r
+ UIA_DataGridControlTypeId:controlTypes.ROLE_DATAGRID,\r
+ UIA_DataItemControlTypeId:controlTypes.ROLE_DATAITEM,\r
+ UIA_DocumentControlTypeId:controlTypes.ROLE_DOCUMENT,\r
+ UIA_SplitButtonControlTypeId:controlTypes.ROLE_SPLITBUTTON,\r
+ UIA_WindowControlTypeId:controlTypes.ROLE_WINDOW,\r
+ UIA_PaneControlTypeId:controlTypes.ROLE_PANE,\r
+ UIA_HeaderControlTypeId:controlTypes.ROLE_HEADER,\r
+ UIA_HeaderItemControlTypeId:controlTypes.ROLE_HEADERITEM,\r
+ UIA_TableControlTypeId:controlTypes.ROLE_TABLE,\r
+ UIA_TitleBarControlTypeId:controlTypes.ROLE_TITLEBAR,\r
+ UIA_SeparatorControlTypeId:controlTypes.ROLE_SEPARATOR,\r
+}\r
+\r
+UIAPropertyIdsToNVDAEventNames={\r
+ UIA_NamePropertyId:"nameChange",\r
+ UIA_HelpTextPropertyId:"descriptionChange",\r
+ UIA_ExpandCollapseExpandCollapseStatePropertyId:"stateChange",\r
+ UIA_ToggleToggleStatePropertyId:"stateChange",\r
+ UIA_IsEnabledPropertyId:"stateChange",\r
+ UIA_ValueValuePropertyId:"valueChange",\r
+ UIA_RangeValueValuePropertyId:"valueChange",\r
+}\r
+\r
+UIAEventIdsToNVDAEventNames={\r
+ #UIA_Text_TextChangedEventId:"textChanged",\r
+ UIA_SelectionItem_ElementSelectedEventId:"stateChange",\r
+ #UIA_MenuOpenedEventId:"gainFocus",\r
+ UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange",\r
+ UIA_SelectionItem_ElementRemovedFromSelectionEventId:"stateChange",\r
+ #UIA_MenuModeEndEventId:"menuModeEnd",\r
+ #UIA_Text_TextSelectionChangedEventId:"caret",\r
+ #UIA_ToolTipOpenedEventId:"show",\r
+ #UIA_AsyncContentLoadedEventId:"documentLoadComplete",\r
+ #UIA_ToolTipClosedEventId:"hide",\r
+}\r
+\r
+class UIAHandler(COMObject):\r
+ _com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler]\r
+\r
+ def __init__(self):\r
+ super(UIAHandler,self).__init__()\r
+ self.MTAThreadInitEvent=threading.Event()\r
+ self.MTAThreadStopEvent=threading.Event()\r
+ self.MTAThreadInitException=None\r
+ self.MTAThread=threading.Thread(target=self.MTAThreadFunc)\r
+ self.MTAThread.start()\r
+ self.MTAThreadInitEvent.wait(2)\r
+ if self.MTAThreadInitException:\r
+ raise self.MTAThreadInitException\r
+\r
+ def terminate(self):\r
+ MTAThreadHandle=HANDLE(windll.kernel32.OpenThread(self.MTAThread.ident,False,winKernel.SYNCHRONIZE))\r
+ self.MTAThreadStopEvent.set()\r
+ index=c_int()\r
+ #Wait for the MTAA thread to die (while still message pumping)\r
+ windll.user32.MsgWaitForMultipleObjects(1,byref(MTAThreadHandle),False,5000,0)\r
+ del self.MTAThread\r
+\r
+ def MTAThreadFunc(self):\r
+ try:\r
+ oledll.ole32.CoInitializeEx(None,comtypes.COINIT_MULTITHREADED) \r
+ self.clientObject=CoCreateInstance(CUIAutomation._reg_clsid_,interface=IUIAutomation,clsctx=CLSCTX_INPROC_SERVER)\r
+ self.windowTreeWalker=self.clientObject.createTreeWalker(self.clientObject.CreateNotCondition(self.clientObject.CreatePropertyCondition(UIA_NativeWindowHandlePropertyId,0)))\r
+ self.windowCacheRequest=self.clientObject.CreateCacheRequest()\r
+ self.windowCacheRequest.AddProperty(UIA_NativeWindowHandlePropertyId)\r
+ self.UIAWindowHandleCache={}\r
+ self.baseTreeWalker=self.clientObject.RawViewWalker\r
+ self.baseCacheRequest=self.windowCacheRequest.Clone()\r
+ for propertyId in (UIA_ClassNamePropertyId,UIA_ControlTypePropertyId,UIA_IsKeyboardFocusablePropertyId,UIA_IsPasswordPropertyId,UIA_ProviderDescriptionPropertyId,UIA_ProcessIdPropertyId,UIA_IsSelectionItemPatternAvailablePropertyId,UIA_IsTextPatternAvailablePropertyId):\r
+ self.baseCacheRequest.addProperty(propertyId)\r
+ self.rootElement=self.clientObject.getRootElementBuildCache(self.baseCacheRequest)\r
+ self.reservedNotSupportedValue=self.clientObject.ReservedNotSupportedValue\r
+ self.clientObject.AddFocusChangedEventHandler(self.baseCacheRequest,self)\r
+ self.clientObject.AddPropertyChangedEventHandler(self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self,UIAPropertyIdsToNVDAEventNames.keys())\r
+ for x in UIAEventIdsToNVDAEventNames.iterkeys(): \r
+ self.clientObject.addAutomationEventHandler(x,self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self)\r
+ except Exception as e:\r
+ self.MTAThreadInitException=e\r
+ finally:\r
+ self.MTAThreadInitEvent.set()\r
+ self.MTAThreadStopEvent.wait()\r
+ self.clientObject.RemoveAllEventHandlers()\r
+\r
+ def IUIAutomationEventHandler_HandleAutomationEvent(self,sender,eventID):\r
+ if not self.MTAThreadInitEvent.isSet:\r
+ # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
+ return\r
+ NVDAEventName=UIAEventIdsToNVDAEventNames.get(eventID,None)\r
+ if not NVDAEventName:\r
+ return\r
+ if not self.isNativeUIAElement(sender):\r
+ return\r
+ import NVDAObjects.UIA\r
+ obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
+ if not obj:\r
+ return\r
+ eventHandler.queueEvent(NVDAEventName,obj)\r
+\r
+ def IUIAutomationFocusChangedEventHandler_HandleFocusChangedEvent(self,sender):\r
+ if not self.MTAThreadInitEvent.isSet:\r
+ # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
+ return\r
+ if not self.isNativeUIAElement(sender):\r
+ return\r
+ try:\r
+ hasFocus=sender.currentHasKeyboardFocus\r
+ except COMError:\r
+ return\r
+ if not hasFocus: \r
+ return\r
+ import NVDAObjects.UIA\r
+ if isinstance(eventHandler.lastQueuedFocusObject,NVDAObjects.UIA.UIA):\r
+ lastFocus=eventHandler.lastQueuedFocusObject.UIAElement\r
+ # Ignore duplicate focus events.\r
+ # It seems that it is possible for compareElements to return True, even though the objects are different.\r
+ # Therefore, don't ignore the event if the last focus object has lost its hasKeyboardFocus state.\r
+ if self.clientObject.compareElements(sender,lastFocus) and lastFocus.currentHasKeyboardFocus:\r
+ return\r
+ obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
+ eventHandler.queueEvent("gainFocus",obj)\r
+\r
+ def IUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent(self,sender,propertyId,newValue):\r
+ if not self.MTAThreadInitEvent.isSet:\r
+ # UIAHandler hasn't finished initialising yet, so just ignore this event.\r
+ return\r
+ NVDAEventName=UIAPropertyIdsToNVDAEventNames.get(propertyId,None)\r
+ if not NVDAEventName:\r
+ return\r
+ if not self.isNativeUIAElement(sender):\r
+ return\r
+ import NVDAObjects.UIA\r
+ obj=NVDAObjects.UIA.UIA(UIAElement=sender)\r
+ if not obj:\r
+ return\r
+ eventHandler.queueEvent(NVDAEventName,obj)\r
+\r
+ def isUIAWindow(self,hwnd):\r
+ now=time.time()\r
+ v=self.UIAWindowHandleCache.get(hwnd,None)\r
+ if not v or (now-v[1])>0.5:\r
+ if windll.kernel32.GetCurrentProcessId()==winUser.getWindowThreadProcessID(hwnd)[0]:\r
+ isUIA=False\r
+ elif winUser.getClassName(hwnd) in badUIAWindowClassNames:\r
+ isUIA=False\r
+ else:\r
+ isUIA=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd)\r
+ self.UIAWindowHandleCache[hwnd]=(isUIA,now)\r
+ return isUIA\r
+ return v[0]\r
+\r
+ def getNearestWindowHandle(self,UIAElement):\r
+ try:\r
+ UIAElement=self.windowTreeWalker.NormalizeElementBuildCache(UIAElement,self.windowCacheRequest)\r
+ except COMError:\r
+ return None\r
+ try:\r
+ return UIAElement.cachedNativeWindowHandle\r
+ except COMError:\r
+ return None\r
+\r
+ def isNativeUIAElement(self,UIAElement):\r
+ #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable.\r
+ #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze.\r
+ try:\r
+ processID=UIAElement.cachedProcessId\r
+ except COMError:\r
+ return False\r
+ if processID==windll.kernel32.GetCurrentProcessId():\r
+ return False\r
+ #If the element has a window handle, and the window natively supports UIA, then its a native element\r
+ try:\r
+ windowHandle=UIAElement.cachedNativeWindowHandle\r
+ except COMError:\r
+ windowHandle=None\r
+ if windowHandle:\r
+ return self.isUIAWindow(windowHandle)\r
+ #The element does not have a window, but we can class it as native if the element is not an MSAA proxy (according to provider description)\r
+ try:\r
+ providerDescription=UIAElement.cachedProviderDescription\r
+ except COMError:\r
+ return True\r
+ return "Microsoft: MSAA Proxy (unmanaged:uiautomationcore.dll)" not in providerDescription\r
+\r