1
2
3
4
5
6
7 import re
8 import ctypes
9 import ctypes.wintypes
10 import winKernel
11 import winUser
12 from logHandler import log
13 import controlTypes
14 import api
15 import displayModel
16 import eventHandler
17 from NVDAObjects import NVDAObject
18 from NVDAObjects.behaviors import EditableText, LiveText
19 import watchdog
20
21 re_WindowsForms=re.compile(r'^WindowsForms[0-9]*\.(.*)\.app\..*$')
22 re_ATL=re.compile(r'^ATL:(.*)$')
23
24 try:
25 GhostWindowFromHungWindow=ctypes.windll.user32.GhostWindowFromHungWindow
26 except AttributeError:
27 GhostWindowFromHungWindow=None
37
39 """
40 Manages a Windows process handle. On instanciation it retreaves an open process handle from the process of the provided window, and closes the handle on deletion.
41 @ivar windowHandle: the handle of the window the whos process handle was requested
42 @type windowHandle: int
43 @ivar processHandle: The actual handle which can be used in any win32 calls that need it.
44 @type processHandle: int
45 """
46
48 """
49 @param windowHandle: the handle of the window whos process handle should be retreaved.
50 @type windowHandle: int
51 """
52 self.windowHandle=windowHandle
53 import oleacc
54 self.processHandle=oleacc.GetProcessHandleFromHwnd(self.windowHandle)
55
58
60 """
61 An NVDAObject for a window
62 @ivar windowHandle: The window's handle
63 @type windowHandle: int
64 @ivar windowClassName: the window's class
65 @type windowClassName: string
66 @ivar windowControlID: the window's control ID
67 @type windowControlID: int
68 @ivar windowText: The window's text (using winUser.WM_GETTEXT)
69 @type windowText: string
70 @ivar windowProcessID: The window's [processID,threadID]
71 @type windowProcessID: list of two ints
72 """
73
74 @classmethod
97
134
135 @classmethod
151
153 if not windowHandle:
154 raise ValueError("invalid or not specified window handle")
155 self.windowHandle=windowHandle
156 super(Window,self).__init__()
157
159 return super(Window,self)._isEqual(other) and other.windowHandle==self.windowHandle
160
163
166
168 if hasattr(self,"_windowClassName"):
169 return self._windowClassName
170 name=winUser.getClassName(self.windowHandle)
171 self._windowClassName=name
172 return name
173
175 if not hasattr(self,"_windowControlID"):
176 self._windowControlID=winUser.getControlID(self.windowHandle)
177 return self._windowControlID
178
180 r=ctypes.wintypes.RECT()
181 ctypes.windll.user32.GetWindowRect(self.windowHandle,ctypes.byref(r))
182 return (r.left,r.top,r.right-r.left,r.bottom-r.top)
183
185 """The text at this object's location according to the display model for this object's window."""
186 try:
187 left,top,width,height=self.location
188 except TypeError:
189 log.debugWarning("No location, returning no text")
190 return ""
191 import displayModel
192 text,rects=displayModel.getWindowTextInRect(self.appModule.helperLocalBindingHandle,self.windowHandle,left,top,left+width,top+height,8,32)
193 return text or ""
194
196 """Redraw the display for this object.
197 """
198 left, top, width, height = self.location
199 left, top = winUser.ScreenToClient(self.windowHandle, left, top)
200 winUser.RedrawWindow(self.windowHandle,
201 winUser.RECT(left, top, left + width, top + height), None,
202 winUser.RDW_INVALIDATE | winUser.RDW_UPDATENOW)
203
204 - def _get_windowText(self):
205 textLength=watchdog.cancellableSendMessage(self.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)
206 textBuf=ctypes.create_unicode_buffer(textLength+2)
207 watchdog.cancellableSendMessage(self.windowHandle,winUser.WM_GETTEXT,textLength+1,textBuf)
208 return textBuf.value
209
211 if hasattr(self,"_processIDThreadID"):
212 return self._processIDThreadID[0]
213 self._processIDThreadID=winUser.getWindowThreadProcessID(self.windowHandle)
214 return self._processIDThreadID[0]
215
217 if hasattr(self,"_processIDThreadID"):
218 return self._processIDThreadID[1]
219 self._processIDThreadID=winUser.getWindowThreadProcessID(self.windowHandle)
220 return self._processIDThreadID[1]
221
228
235
242
253
261
265
274
277
279 if not hasattr(self,'_isWindowUnicode'):
280 self._isWindowUnicode=bool(ctypes.windll.user32.IsWindowUnicode(self.windowHandle))
281 return self._isWindowUnicode
282
284 if not obj:
285 return None
286 newWindowHandle=obj.windowHandle
287 oldWindowHandle=self.windowHandle
288 if newWindowHandle and oldWindowHandle and newWindowHandle!=oldWindowHandle:
289 kwargs=dict(windowHandle=newWindowHandle)
290 newAPIClass=Window.findBestAPIClass(kwargs,relation=relation)
291 oldAPIClass=self.APIClass
292 if newAPIClass and newAPIClass!=oldAPIClass:
293 return newAPIClass(chooseBestAPI=False,**kwargs)
294 return obj
295
297 if not hasattr(self,'_processHandleContainer'):
298 self._processHandleContainer=WindowProcessHandleContainer(self.windowHandle)
299 return self._processHandleContainer.processHandle
300
301 @classmethod
303 """
304 Removes unneeded information from a window class name (e.g. ATL: and windows forms info), and or maps it to a much more well-known compatible class name.
305 Conversions are also cached for future normalizations.
306 @param name: the window class name to normalize
307 @type name: string
308 @returns: the normalized window class name
309 @rtype: string
310 """
311 try:
312 return cls.normalizedWindowClassNameCache[name]
313 except KeyError:
314 pass
315 newName=windowClassMap.get(name,None)
316 if not newName:
317 for r in (re_WindowsForms,re_ATL):
318 m=re.match(r,name)
319 if m:
320 newName=m.group(1)
321 newName=windowClassMap.get(newName,newName)
322 break
323 if not newName:
324 newName=name
325 cls.normalizedWindowClassNameCache[name]=newName
326 return newName
327
328 normalizedWindowClassNameCache={}
329
331 info = super(Window, self).devInfo
332 info.append("windowHandle: %r" % self.windowHandle)
333 try:
334 ret = repr(self.windowClassName)
335 except Exception as e:
336 ret = "exception: %s" % e
337 info.append("windowClassName: %s" % ret)
338 try:
339 ret = repr(self.windowControlID)
340 except Exception as e:
341 ret = "exception: %s" % e
342 info.append("windowControlID: %s" % ret)
343 try:
344 ret = repr(self.windowStyle)
345 except Exception as e:
346 ret = "exception: %s" % e
347 info.append("windowStyle: %s" % ret)
348 try:
349 ret = repr(self.windowThreadID)
350 except Exception as e:
351 ret = "exception: %s" % e
352 info.append("windowThreadID: %s" % ret)
353 try:
354 ret = self.windowText
355 if isinstance(ret, basestring) and len(ret) > 100:
356 ret = "%r (truncated)" % ret[:100]
357 else:
358 ret = repr(ret)
359 except Exception as e:
360 ret = "exception: %s" % e
361 info.append("windowText: %s" % ret)
362 return info
363
370
371 -class DisplayModelEditableText(EditableText, Window):
379
380 -class DisplayModelLiveText(LiveText, Window):
381 TextInfo = displayModel.EditableTextDisplayModelTextInfo
382
383 - def startMonitoring(self):
388
389 - def stopMonitoring(self):
392
393 - def _getTextLines(self):
394 return self.displayText.splitlines()
395
396 windowClassMap={
397 "EDIT":"Edit",
398 "TTntEdit.UnicodeClass":"Edit",
399 "TMaskEdit":"Edit",
400 "TTntMemo.UnicodeClass":"Edit",
401 "TRichEdit":"Edit",
402 "TRichViewEdit":"Edit",
403 "TInEdit.UnicodeClass":"Edit",
404 "TInEdit":"Edit",
405 "TEdit":"Edit",
406 "TFilenameEdit":"Edit",
407 "TSpinEdit":"Edit",
408 "ThunderRT6TextBox":"Edit",
409 "TMemo":"Edit",
410 "RICHEDIT":"RichEdit",
411 "TPasswordEdit":"Edit",
412 "THppEdit.UnicodeClass":"Edit",
413 "TUnicodeTextEdit.UnicodeClass":"Edit",
414 "TTextEdit":"Edit",
415 "TPropInspEdit":"Edit",
416 "TFilterbarEdit.UnicodeClass":"Edit",
417 "EditControl":"Edit",
418 "TNavigableTntMemo.UnicodeClass":"Edit",
419 "TNavigableTntEdit.UnicodeClass":"Edit",
420 "TAltEdit.UnicodeClass":"Edit",
421 "TAltEdit":"Edit",
422 "TDefEdit":"Edit",
423 "TRichEditViewer":"RichEdit",
424 "WFMAINRE":"RichEdit20",
425 "RichEdit20A":"RichEdit20",
426 "RichEdit20W":"RichEdit20",
427 "TskRichEdit.UnicodeClass":"RichEdit20",
428 "RichEdit20WPT":"RichEdit20",
429 "RICHEDIT60W":"RICHEDIT50W",
430 "TChatRichEdit.UnicodeClass":"RichEdit20",
431 "TMyRichEdit":"RichEdit20",
432 "TExRichEdit":"RichEdit20",
433 "RichTextWndClass":"RichEdit20",
434 "TSRichEdit":"RichEdit20",
435 "ScintillaWindowImpl":"Scintilla",
436 "RICHEDIT60W_WLXPRIVATE":"RICHEDIT50W",
437 }
438