12
12
from logHandler import log
13
13
import controlTypes
15
16
import eventHandler
16
17
from NVDAObjects import NVDAObject
18
from NVDAObjects.behaviors import EditableText, LiveText
18
21
re_WindowsForms=re.compile(r'^WindowsForms[0-9]*\.(.*)\.app\..*$')
19
22
re_ATL=re.compile(r'^ATL:(.*)$')
25
GhostWindowFromHungWindow=ctypes.windll.user32.GhostWindowFromHungWindow
26
except AttributeError:
27
GhostWindowFromHungWindow=None
29
def isUsableWindow(windowHandle):
30
if not ctypes.windll.user32.IsWindowEnabled(windowHandle):
32
if not ctypes.windll.user32.IsWindowVisible(windowHandle):
34
if GhostWindowFromHungWindow and ctypes.windll.user32.GhostWindowFromHungWindow(windowHandle):
22
38
class WindowProcessHandleContainer(object):
62
78
#The desktop window should stay as a window
63
79
if windowClassName=="#32769":
81
#If this window has a ghost window its too dangerous to try any higher APIs
82
if GhostWindowFromHungWindow and GhostWindowFromHungWindow(windowHandle):
65
84
if windowClassName=="EXCEL7" and (relation=='focus' or isinstance(relation,tuple)):
66
85
from . import excel
67
86
yield excel.ExcelCell
89
108
from .edit import RichEdit20 as newCls
90
109
elif windowClassName=="RICHEDIT50W":
91
110
from .edit import RichEdit50 as newCls
92
elif windowClassName=="Scintilla":
111
elif windowClassName in ("Scintilla","TScintilla"):
93
112
from .scintilla import Scintilla as newCls
94
113
elif windowClassName in ("AkelEditW", "AkelEditA"):
95
114
from .akelEdit import AkelEdit as newCls
99
118
from .winword import WordDocument as newCls
100
119
elif windowClassName=="EXCEL7":
101
120
from .excel import Excel7Window as newCls
102
clsList.append(newCls)
104
clsList.append(Window)
122
clsList.append(newCls)
124
#If none of the chosen classes seem to support text editing
125
#But there is a caret currently in the window
126
#Then use the displayModelEditableText class to emulate text editing capabilities
127
if not any(issubclass(cls,EditableText) for cls in clsList):
128
gi=winUser.getGUIThreadInfo(self.windowThreadID)
129
if gi.hwndCaret==self.windowHandle and gi.flags&winUser.GUI_CARETBLINKING:
130
clsList.append(DisplayModelEditableText)
132
clsList.append(Window)
105
133
super(Window,self).findOverlayClasses(clsList)
153
181
ctypes.windll.user32.GetWindowRect(self.windowHandle,ctypes.byref(r))
154
182
return (r.left,r.top,r.right-r.left,r.bottom-r.top)
184
def _get_displayText(self):
185
"""The text at this object's location according to the display model for this object's window."""
187
left,top,width,height=self.location
189
log.debugWarning("No location, returning no text")
192
text,rects=displayModel.getWindowTextInRect(self.appModule.helperLocalBindingHandle,self.windowHandle,left,top,left+width,top+height,8,32)
196
"""Redraw the display for this object.
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)
156
204
def _get_windowText(self):
157
textLength=winUser.sendMessage(self.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)
205
textLength=watchdog.cancellableSendMessage(self.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)
158
206
textBuf=ctypes.create_unicode_buffer(textLength+2)
159
winUser.sendMessage(self.windowHandle,winUser.WM_GETTEXT,textLength+1,textBuf)
160
return textBuf.value+u"\0"
207
watchdog.cancellableSendMessage(self.windowHandle,winUser.WM_GETTEXT,textLength+1,textBuf)
162
210
def _get_processID(self):
163
211
if hasattr(self,"_processIDThreadID"):
174
222
def _get_next(self):
175
223
nextWindow=winUser.getWindow(self.windowHandle,winUser.GW_HWNDNEXT)
176
while nextWindow and (not winUser.isWindowVisible(nextWindow) or not winUser.isWindowEnabled(nextWindow)):
224
while nextWindow and not isUsableWindow(nextWindow):
177
225
nextWindow=winUser.getWindow(nextWindow,winUser.GW_HWNDNEXT)
179
227
return Window(windowHandle=nextWindow)
181
229
def _get_previous(self):
182
230
prevWindow=winUser.getWindow(self.windowHandle,winUser.GW_HWNDPREV)
183
while prevWindow and (not winUser.isWindowVisible(prevWindow) or not winUser.isWindowEnabled(prevWindow)):
231
while prevWindow and not isUsableWindow(prevWindow):
184
232
prevWindow=winUser.getWindow(prevWindow,winUser.GW_HWNDPREV)
186
234
return Window(windowHandle=prevWindow)
188
236
def _get_firstChild(self):
189
237
childWindow=winUser.getTopWindow(self.windowHandle)
190
while childWindow and (not winUser.isWindowVisible(childWindow) or not winUser.isWindowEnabled(childWindow)):
238
while childWindow and not isUsableWindow(childWindow):
191
239
childWindow=winUser.getWindow(childWindow,winUser.GW_HWNDNEXT)
193
241
return Window(windowHandle=childWindow)
198
246
while nextWindow:
199
247
childWindow=nextWindow
200
248
nextWindow=winUser.getWindow(childWindow,winUser.GW_HWNDNEXT)
201
while childWindow and (not winUser.isWindowVisible(childWindow) or not winUser.isWindowEnabled(childWindow)):
249
while childWindow and not isUsableWindow(childWindow):
202
250
childWindow=winUser.getWindow(childWindow,winUser.GW_HWNDPREV)
204
252
return Window(windowHandle=childWindow)
209
257
#Because we, we need to get the APIclass manually need to set the relation as parent
210
258
kwargs=dict(windowHandle=parentHandle)
211
259
APIClass=Window.findBestAPIClass(kwargs,relation="parent")
212
return APIClass(**kwargs)
260
return APIClass(**kwargs) if APIClass else None
214
262
def _get_isInForeground(self):
215
263
fg=winUser.getForegroundWindow()
235
283
def correctAPIForRelation(self,obj,relation=None):
238
windowHandle=obj.windowHandle
239
286
newWindowHandle=obj.windowHandle
240
287
oldWindowHandle=self.windowHandle
241
288
if newWindowHandle and oldWindowHandle and newWindowHandle!=oldWindowHandle:
242
289
kwargs=dict(windowHandle=newWindowHandle)
243
290
newAPIClass=Window.findBestAPIClass(kwargs,relation=relation)
244
291
oldAPIClass=self.APIClass
245
if newAPIClass!=oldAPIClass:
292
if newAPIClass and newAPIClass!=oldAPIClass:
246
293
return newAPIClass(chooseBestAPI=False,**kwargs)
250
296
def _get_processHandle(self):
251
297
if not hasattr(self,'_processHandleContainer'):
252
298
self._processHandleContainer=WindowProcessHandleContainer(self.windowHandle)
282
328
normalizedWindowClassNameCache={}
330
def _get_devInfo(self):
331
info = super(Window, self).devInfo
332
info.append("windowHandle: %r" % self.windowHandle)
334
ret = repr(self.windowClassName)
335
except Exception as e:
336
ret = "exception: %s" % e
337
info.append("windowClassName: %s" % ret)
339
ret = repr(self.windowControlID)
340
except Exception as e:
341
ret = "exception: %s" % e
342
info.append("windowControlID: %s" % ret)
344
ret = repr(self.windowStyle)
345
except Exception as e:
346
ret = "exception: %s" % e
347
info.append("windowStyle: %s" % ret)
349
ret = repr(self.windowThreadID)
350
except Exception as e:
351
ret = "exception: %s" % e
352
info.append("windowThreadID: %s" % ret)
354
ret = self.windowText
355
if isinstance(ret, basestring) and len(ret) > 100:
356
ret = "%r (truncated)" % ret[:100]
359
except Exception as e:
360
ret = "exception: %s" % e
361
info.append("windowText: %s" % ret)
284
364
class Desktop(Window):
286
366
isPresentableFocusAncestor = False
288
368
def _get_name(self):
289
369
return _("Desktop")
371
class DisplayModelEditableText(EditableText, Window):
373
role=controlTypes.ROLE_EDITABLETEXT
374
TextInfo = displayModel.EditableTextDisplayModelTextInfo
376
def event_valueChange(self):
377
# Don't report value changes for editable text fields.
380
class DisplayModelLiveText(LiveText, Window):
381
TextInfo = displayModel.EditableTextDisplayModelTextInfo
383
def startMonitoring(self):
384
# Force the window to be redrawn, as our display model might be out of date.
386
displayModel.requestTextChangeNotifications(self, True)
387
super(DisplayModelLiveText, self).startMonitoring()
389
def stopMonitoring(self):
390
super(DisplayModelLiveText, self).stopMonitoring()
391
displayModel.requestTextChangeNotifications(self, False)
393
def _getTextLines(self):
394
return self.displayText.splitlines()
293
398
"TTntEdit.UnicodeClass":"Edit",
328
433
"RichTextWndClass":"RichEdit20",
329
434
"TSRichEdit":"RichEdit20",
330
435
"ScintillaWindowImpl":"Scintilla",
436
"RICHEDIT60W_WLXPRIVATE":"RICHEDIT50W",