| Trees | Indices | Help |
|---|
|
|
1 from ctypes import *
2 from ctypes.wintypes import *
3 import comtypes.client
4 from comtypes import *
5 import weakref
6 import threading
7 import re
8 import time
9 import api
10 import queueHandler
11 import controlTypes
12 import winKernel
13 import winUser
14 import eventHandler
15 from logHandler import log
16
17 from comtypes.gen.UIAutomationClient import *
18
19 re_MSAAProxyProviderDescription=re.compile(r'Microsoft: (Annotation|MSAA) Proxy \(unmanaged:uiautomationcore.dll\)',re.IGNORECASE)
20
21 badUIAWindowClassNames=[
22 "SysTreeView32",
23 "WuDuiListView",
24 "ComboBox",
25 "msctls_progress32",
26 "Edit",
27 "CommonPlacesWrapperWndClass",
28 "SysMonthCal32",
29 "SUPERGRID", #Outlook 2010 message list
30 ]
31
32 UIAControlTypesToNVDARoles={
33 UIA_ButtonControlTypeId:controlTypes.ROLE_BUTTON,
34 UIA_CalendarControlTypeId:controlTypes.ROLE_CALENDAR,
35 UIA_CheckBoxControlTypeId:controlTypes.ROLE_CHECKBOX,
36 UIA_ComboBoxControlTypeId:controlTypes.ROLE_COMBOBOX,
37 UIA_EditControlTypeId:controlTypes.ROLE_EDITABLETEXT,
38 UIA_HyperlinkControlTypeId:controlTypes.ROLE_LINK,
39 UIA_ImageControlTypeId:controlTypes.ROLE_GRAPHIC,
40 UIA_ListItemControlTypeId:controlTypes.ROLE_LISTITEM,
41 UIA_ListControlTypeId:controlTypes.ROLE_LIST,
42 UIA_MenuControlTypeId:controlTypes.ROLE_POPUPMENU,
43 UIA_MenuBarControlTypeId:controlTypes.ROLE_MENUBAR,
44 UIA_MenuItemControlTypeId:controlTypes.ROLE_MENUITEM,
45 UIA_ProgressBarControlTypeId:controlTypes.ROLE_PROGRESSBAR,
46 UIA_RadioButtonControlTypeId:controlTypes.ROLE_RADIOBUTTON,
47 UIA_ScrollBarControlTypeId:controlTypes.ROLE_SCROLLBAR,
48 UIA_SliderControlTypeId:controlTypes.ROLE_SLIDER,
49 UIA_SpinnerControlTypeId:controlTypes.ROLE_SPINBUTTON,
50 UIA_StatusBarControlTypeId:controlTypes.ROLE_STATUSBAR,
51 UIA_TabControlTypeId:controlTypes.ROLE_TABCONTROL,
52 UIA_TabItemControlTypeId:controlTypes.ROLE_TAB,
53 UIA_TextControlTypeId:controlTypes.ROLE_STATICTEXT,
54 UIA_ToolBarControlTypeId:controlTypes.ROLE_TOOLBAR,
55 UIA_ToolTipControlTypeId:controlTypes.ROLE_TOOLTIP,
56 UIA_TreeControlTypeId:controlTypes.ROLE_TREEVIEW,
57 UIA_TreeItemControlTypeId:controlTypes.ROLE_TREEVIEWITEM,
58 UIA_CustomControlTypeId:controlTypes.ROLE_UNKNOWN,
59 UIA_GroupControlTypeId:controlTypes.ROLE_GROUPING,
60 UIA_ThumbControlTypeId:controlTypes.ROLE_THUMB,
61 UIA_DataGridControlTypeId:controlTypes.ROLE_DATAGRID,
62 UIA_DataItemControlTypeId:controlTypes.ROLE_DATAITEM,
63 UIA_DocumentControlTypeId:controlTypes.ROLE_DOCUMENT,
64 UIA_SplitButtonControlTypeId:controlTypes.ROLE_SPLITBUTTON,
65 UIA_WindowControlTypeId:controlTypes.ROLE_WINDOW,
66 UIA_PaneControlTypeId:controlTypes.ROLE_PANE,
67 UIA_HeaderControlTypeId:controlTypes.ROLE_HEADER,
68 UIA_HeaderItemControlTypeId:controlTypes.ROLE_HEADERITEM,
69 UIA_TableControlTypeId:controlTypes.ROLE_TABLE,
70 UIA_TitleBarControlTypeId:controlTypes.ROLE_TITLEBAR,
71 UIA_SeparatorControlTypeId:controlTypes.ROLE_SEPARATOR,
72 }
73
74 UIAPropertyIdsToNVDAEventNames={
75 UIA_NamePropertyId:"nameChange",
76 UIA_HelpTextPropertyId:"descriptionChange",
77 UIA_ExpandCollapseExpandCollapseStatePropertyId:"stateChange",
78 UIA_ToggleToggleStatePropertyId:"stateChange",
79 UIA_IsEnabledPropertyId:"stateChange",
80 UIA_ValueValuePropertyId:"valueChange",
81 UIA_RangeValueValuePropertyId:"valueChange",
82 }
83
84 UIAEventIdsToNVDAEventNames={
85 #UIA_Text_TextChangedEventId:"textChanged",
86 UIA_SelectionItem_ElementSelectedEventId:"stateChange",
87 #UIA_MenuOpenedEventId:"gainFocus",
88 UIA_SelectionItem_ElementAddedToSelectionEventId:"stateChange",
89 UIA_SelectionItem_ElementRemovedFromSelectionEventId:"stateChange",
90 #UIA_MenuModeEndEventId:"menuModeEnd",
91 #UIA_Text_TextSelectionChangedEventId:"caret",
92 #UIA_ToolTipOpenedEventId:"show",
93 #UIA_AsyncContentLoadedEventId:"documentLoadComplete",
94 #UIA_ToolTipClosedEventId:"hide",
95 }
96
98 _com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler]
99
101 super(UIAHandler,self).__init__()
102 self.MTAThreadInitEvent=threading.Event()
103 self.MTAThreadStopEvent=threading.Event()
104 self.MTAThreadInitException=None
105 self.MTAThread=threading.Thread(target=self.MTAThreadFunc)
106 self.MTAThread.daemon=True
107 self.MTAThread.start()
108 self.MTAThreadInitEvent.wait(2)
109 if self.MTAThreadInitException:
110 raise self.MTAThreadInitException
111
113 MTAThreadHandle=HANDLE(windll.kernel32.OpenThread(self.MTAThread.ident,False,winKernel.SYNCHRONIZE))
114 self.MTAThreadStopEvent.set()
115 index=c_int()
116 #Wait for the MTAA thread to die (while still message pumping)
117 windll.user32.MsgWaitForMultipleObjects(1,byref(MTAThreadHandle),False,5000,0)
118 windll.kernel32.CloseHandle(MTAThreadHandle)
119 del self.MTAThread
120
122 try:
123 oledll.ole32.CoInitializeEx(None,comtypes.COINIT_MULTITHREADED)
124 self.clientObject=CoCreateInstance(CUIAutomation._reg_clsid_,interface=IUIAutomation,clsctx=CLSCTX_INPROC_SERVER)
125 self.windowTreeWalker=self.clientObject.createTreeWalker(self.clientObject.CreateNotCondition(self.clientObject.CreatePropertyCondition(UIA_NativeWindowHandlePropertyId,0)))
126 self.windowCacheRequest=self.clientObject.CreateCacheRequest()
127 self.windowCacheRequest.AddProperty(UIA_NativeWindowHandlePropertyId)
128 self.UIAWindowHandleCache={}
129 self.baseTreeWalker=self.clientObject.RawViewWalker
130 self.baseCacheRequest=self.windowCacheRequest.Clone()
131 for propertyId in (UIA_ClassNamePropertyId,UIA_ControlTypePropertyId,UIA_IsKeyboardFocusablePropertyId,UIA_IsPasswordPropertyId,UIA_ProviderDescriptionPropertyId,UIA_ProcessIdPropertyId,UIA_IsSelectionItemPatternAvailablePropertyId,UIA_IsTextPatternAvailablePropertyId):
132 self.baseCacheRequest.addProperty(propertyId)
133 self.rootElement=self.clientObject.getRootElementBuildCache(self.baseCacheRequest)
134 self.reservedNotSupportedValue=self.clientObject.ReservedNotSupportedValue
135 self.clientObject.AddFocusChangedEventHandler(self.baseCacheRequest,self)
136 self.clientObject.AddPropertyChangedEventHandler(self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self,UIAPropertyIdsToNVDAEventNames.keys())
137 for x in UIAEventIdsToNVDAEventNames.iterkeys():
138 self.clientObject.addAutomationEventHandler(x,self.rootElement,TreeScope_Subtree,self.baseCacheRequest,self)
139 except Exception as e:
140 self.MTAThreadInitException=e
141 finally:
142 self.MTAThreadInitEvent.set()
143 self.MTAThreadStopEvent.wait()
144 self.clientObject.RemoveAllEventHandlers()
145
147 if not self.MTAThreadInitEvent.isSet:
148 # UIAHandler hasn't finished initialising yet, so just ignore this event.
149 return
150 NVDAEventName=UIAEventIdsToNVDAEventNames.get(eventID,None)
151 if not NVDAEventName:
152 return
153 if not self.isNativeUIAElement(sender):
154 return
155 import NVDAObjects.UIA
156 obj=NVDAObjects.UIA.UIA(UIAElement=sender)
157 if not obj:
158 return
159 eventHandler.queueEvent(NVDAEventName,obj)
160
162 if not self.MTAThreadInitEvent.isSet:
163 # UIAHandler hasn't finished initialising yet, so just ignore this event.
164 return
165 if not self.isNativeUIAElement(sender):
166 return
167 try:
168 hasFocus=sender.currentHasKeyboardFocus
169 except COMError:
170 return
171 if not hasFocus:
172 return
173 import NVDAObjects.UIA
174 if isinstance(eventHandler.lastQueuedFocusObject,NVDAObjects.UIA.UIA):
175 lastFocus=eventHandler.lastQueuedFocusObject.UIAElement
176 # Ignore duplicate focus events.
177 # It seems that it is possible for compareElements to return True, even though the objects are different.
178 # Therefore, don't ignore the event if the last focus object has lost its hasKeyboardFocus state.
179 if self.clientObject.compareElements(sender,lastFocus) and lastFocus.currentHasKeyboardFocus:
180 return
181 obj=NVDAObjects.UIA.UIA(UIAElement=sender)
182 if not obj:
183 return
184 eventHandler.queueEvent("gainFocus",obj)
185
186 - def IUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent(self,sender,propertyId,newValue):
187 if not self.MTAThreadInitEvent.isSet:
188 # UIAHandler hasn't finished initialising yet, so just ignore this event.
189 return
190 NVDAEventName=UIAPropertyIdsToNVDAEventNames.get(propertyId,None)
191 if not NVDAEventName:
192 return
193 if not self.isNativeUIAElement(sender):
194 return
195 import NVDAObjects.UIA
196 obj=NVDAObjects.UIA.UIA(UIAElement=sender)
197 if not obj:
198 return
199 eventHandler.queueEvent(NVDAEventName,obj)
200
202 now=time.time()
203 v=self.UIAWindowHandleCache.get(hwnd,None)
204 if not v or (now-v[1])>0.5:
205 if windll.kernel32.GetCurrentProcessId()==winUser.getWindowThreadProcessID(hwnd)[0]:
206 isUIA=False
207 elif winUser.getClassName(hwnd) in badUIAWindowClassNames:
208 isUIA=False
209 else:
210 isUIA=windll.UIAutomationCore.UiaHasServerSideProvider(hwnd)
211 self.UIAWindowHandleCache[hwnd]=(isUIA,now)
212 return isUIA
213 return v[0]
214
216 try:
217 UIAElement=self.windowTreeWalker.NormalizeElementBuildCache(UIAElement,self.windowCacheRequest)
218 except COMError:
219 return None
220 try:
221 return UIAElement.cachedNativeWindowHandle
222 except COMError:
223 return None
224
226 #Due to issues dealing with UIA elements coming from the same process, we do not class these UIA elements as usable.
227 #It seems to be safe enough to retreave the cached processID, but using tree walkers or fetching other properties causes a freeze.
228 try:
229 processID=UIAElement.cachedProcessId
230 except COMError:
231 return False
232 if processID==windll.kernel32.GetCurrentProcessId():
233 return False
234 #If the element has a window handle, whether it is a native element depends on whether the window natively supports UIA.
235 try:
236 windowHandle=UIAElement.cachedNativeWindowHandle
237 except COMError:
238 windowHandle=None
239 if windowHandle:
240 return self.isUIAWindow(windowHandle)
241 try:
242 providerDescription=UIAElement.cachedProviderDescription
243 except COMError:
244 return True
245 if re_MSAAProxyProviderDescription.search(providerDescription):
246 # This is an MSAA proxy.
247 # Whether this is a native element depends on whether the nearest window handle natively supports UIA.
248 windowHandle=self.getNearestWindowHandle(UIAElement)
249 if not windowHandle:
250 return False
251 return self.isUIAWindow(windowHandle)
252 return True
253
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Fri Nov 18 17:46:04 2011 | http://epydoc.sourceforge.net |