OSDN Git Service

UI Automation support: make it again possible to run NVDA after preparing/building...
authorMichael Curran <mick@kulgan.net>
Tue, 7 Jun 2011 06:41:32 +0000 (16:41 +1000)
committerMichael Curran <mick@kulgan.net>
Tue, 7 Jun 2011 06:41:32 +0000 (16:41 +1000)
source/UIAHandler.py
source/_UIAHandler.py [new file with mode: 0644]

index 2533ea4..0978374 100644 (file)
-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
diff --git a/source/_UIAHandler.py b/source/_UIAHandler.py
new file mode 100644 (file)
index 0000000..1fb1919
--- /dev/null
@@ -0,0 +1,238 @@
+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