~stomato463/+junk/nvdajp

« back to all changes in this revision

Viewing changes to source/NVDAObjects/window/__init__.py

  • Committer: Masataka Shinke
  • Date: 2011-10-25 12:35:26 UTC
  • mfrom: (4185 jpmain)
  • mto: This revision was merged to the branch mainline in revision 4211.
  • Revision ID: mshinke@users.sourceforge.jp-20111025123526-ze527a2rl3z0g2ky
lp:~nishimotz/nvdajp/main : 4185 をマージ

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
from logHandler import log
13
13
import controlTypes
14
14
import api
 
15
import displayModel
15
16
import eventHandler
16
17
from NVDAObjects import NVDAObject
 
18
from NVDAObjects.behaviors import EditableText, LiveText
 
19
import watchdog
17
20
 
18
21
re_WindowsForms=re.compile(r'^WindowsForms[0-9]*\.(.*)\.app\..*$')
19
22
re_ATL=re.compile(r'^ATL:(.*)$')
20
23
 
 
24
try:
 
25
        GhostWindowFromHungWindow=ctypes.windll.user32.GhostWindowFromHungWindow
 
26
except AttributeError:
 
27
        GhostWindowFromHungWindow=None
 
28
 
 
29
def isUsableWindow(windowHandle):
 
30
        if not ctypes.windll.user32.IsWindowEnabled(windowHandle):
 
31
                return False
 
32
        if not ctypes.windll.user32.IsWindowVisible(windowHandle):
 
33
                return False
 
34
        if GhostWindowFromHungWindow and ctypes.windll.user32.GhostWindowFromHungWindow(windowHandle):
 
35
                return False
 
36
        return True
21
37
 
22
38
class WindowProcessHandleContainer(object):
23
39
        """
62
78
                #The desktop window should stay as a window
63
79
                if windowClassName=="#32769":
64
80
                        return
 
81
                #If this window has a ghost window its too dangerous to try any higher APIs 
 
82
                if GhostWindowFromHungWindow and GhostWindowFromHungWindow(windowHandle):
 
83
                        return
65
84
                if windowClassName=="EXCEL7" and (relation=='focus' or isinstance(relation,tuple)): 
66
85
                        from . import excel
67
86
                        yield excel.ExcelCell 
78
97
 
79
98
        def findOverlayClasses(self,clsList):
80
99
                windowClassName=self.normalizeWindowClassName(self.windowClassName)
81
 
                newCls=Window
 
100
                newCls=None
82
101
                if windowClassName=="#32769":
83
102
                        newCls=Desktop
84
103
                elif windowClassName=="Edit":
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)
103
 
                if newCls!=Window:
104
 
                        clsList.append(Window)
 
121
                if newCls:
 
122
                        clsList.append(newCls)
 
123
 
 
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)
 
131
 
 
132
                clsList.append(Window)
105
133
                super(Window,self).findOverlayClasses(clsList)
106
134
 
107
135
        @classmethod
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)
155
183
 
 
184
        def _get_displayText(self):
 
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
 
 
195
        def redraw(self):
 
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
 
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)
 
208
                return textBuf.value
161
209
 
162
210
        def _get_processID(self):
163
211
                if hasattr(self,"_processIDThreadID"):
173
221
 
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)
178
226
                if nextWindow:
179
227
                        return Window(windowHandle=nextWindow)
180
228
 
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)
185
233
                if prevWindow:
186
234
                        return Window(windowHandle=prevWindow)
187
235
 
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)
192
240
                if childWindow:
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)
203
251
                if childWindow:
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
213
261
 
214
262
        def _get_isInForeground(self):
215
263
                fg=winUser.getForegroundWindow()
235
283
        def correctAPIForRelation(self,obj,relation=None):
236
284
                if not obj:
237
285
                        return 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)
247
294
                return obj
248
295
 
249
 
 
250
296
        def _get_processHandle(self):
251
297
                if not hasattr(self,'_processHandleContainer'):
252
298
                        self._processHandleContainer=WindowProcessHandleContainer(self.windowHandle)
281
327
 
282
328
        normalizedWindowClassNameCache={}
283
329
 
 
330
        def _get_devInfo(self):
 
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
 
284
364
class Desktop(Window):
285
365
 
286
366
        isPresentableFocusAncestor = False
288
368
        def _get_name(self):
289
369
                return _("Desktop")
290
370
 
 
371
class DisplayModelEditableText(EditableText, Window):
 
372
 
 
373
        role=controlTypes.ROLE_EDITABLETEXT
 
374
        TextInfo = displayModel.EditableTextDisplayModelTextInfo
 
375
 
 
376
        def event_valueChange(self):
 
377
                # Don't report value changes for editable text fields.
 
378
                pass
 
379
 
 
380
class DisplayModelLiveText(LiveText, Window):
 
381
        TextInfo = displayModel.EditableTextDisplayModelTextInfo
 
382
 
 
383
        def startMonitoring(self):
 
384
                # Force the window to be redrawn, as our display model might be out of date.
 
385
                self.redraw()
 
386
                displayModel.requestTextChangeNotifications(self, True)
 
387
                super(DisplayModelLiveText, self).startMonitoring()
 
388
 
 
389
        def stopMonitoring(self):
 
390
                super(DisplayModelLiveText, self).stopMonitoring()
 
391
                displayModel.requestTextChangeNotifications(self, False)
 
392
 
 
393
        def _getTextLines(self):
 
394
                return self.displayText.splitlines()
 
395
 
291
396
windowClassMap={
292
397
        "EDIT":"Edit",
293
398
        "TTntEdit.UnicodeClass":"Edit",
302
407
        "TSpinEdit":"Edit",
303
408
        "ThunderRT6TextBox":"Edit",
304
409
        "TMemo":"Edit",
305
 
        "RICHEDIT":"Edit",
 
410
        "RICHEDIT":"RichEdit",
306
411
        "TPasswordEdit":"Edit",
307
412
        "THppEdit.UnicodeClass":"Edit",
308
413
        "TUnicodeTextEdit.UnicodeClass":"Edit",
328
433
        "RichTextWndClass":"RichEdit20",
329
434
        "TSRichEdit":"RichEdit20",
330
435
        "ScintillaWindowImpl":"Scintilla",
 
436
        "RICHEDIT60W_WLXPRIVATE":"RICHEDIT50W",
331
437
}