1
2
3
4
5
6 import locale
7 import sys
8 import comtypes.client
9 import struct
10 import ctypes
11 import pythoncom
12 import win32clipboard
13 import oleTypes
14 import colors
15 import globalVars
16 import eventHandler
17 import comInterfaces.tom
18 from logHandler import log
19 import config
20 import speech
21 import winKernel
22 import api
23 import winUser
24 import textInfos.offsets
25 from keyboardHandler import KeyboardInputGesture
26 from scriptHandler import isScriptWaiting
27 import IAccessibleHandler
28 import controlTypes
29 from . import Window
30 from .. import NVDAObjectTextInfo
31 from ..behaviors import EditableTextWithAutoSelectDetection
32 import braille
33 import watchdog
34
35 selOffsetsAtLastCaretEvent=None
36
37
38 EM_GETSEL=176
39 EM_SETSEL=177
40 EM_SCROLLCARET=0xb7
41 EM_GETLINE=196
42 EM_GETLINECOUNT=186
43 EM_LINEFROMCHAR=201
44 EM_LINEINDEX=187
45 EM_LINELENGTH=193
46 EM_POSFROMCHAR=214
47 EM_CHARFROMPOS=215
48 EM_GETFIRSTVISIBLELINE=0x0ce
49
50 EM_EXGETSEL=winUser.WM_USER+52
51 EM_EXLINEFROMCHAR=winUser.WM_USER+54
52 EM_EXSETSEL=winUser.WM_USER+55
53 EM_GETCHARFORMAT=winUser.WM_USER+58
54 EM_GETPARAFORMAT=winUser.WM_USER+61
55 EM_GETTEXTRANGE=winUser.WM_USER+75
56 EM_FINDWORDBREAK=winUser.WM_USER+76
57
58 EM_GETTEXTEX=winUser.WM_USER+94
59 EM_GETTEXTLENGTHEX=winUser.WM_USER+95
60
61 EM_GETPAGE=winUser.WM_USER+228
62
63 LF_FACESIZE=32
64
65
66
68 _fields_=[
69 ('x',ctypes.c_long),
70 ('y',ctypes.c_long),
71 ]
72
74 _fields_=[
75 ('cpMin',ctypes.c_long),
76 ('cpMax',ctypes.c_long),
77 ]
78
80 _fields_=[
81 ('chrg',CharRangeStruct),
82 ('lpstrText',ctypes.c_wchar_p),
83 ]
84
86 _fields_=[
87 ('chrg',CharRangeStruct),
88 ('lpstrText',ctypes.c_char_p),
89 ]
90
91 CFM_LINK=0x20
92 CFE_AUTOBACKCOLOR=0x4000000
93 CFE_AUTOCOLOR=0x40000000
94 CFE_BOLD=1
95 CFE_ITALIC=2
96 CFE_UNDERLINE=4
97 CFE_STRIKEOUT=8
98 CFE_PROTECTED=16
99 CFE_SUBSCRIPT=0x00010000
100 CFE_SUPERSCRIPT=0x00020000
101
102 SCF_SELECTION=0x1
103
127
131
132 -class getTextExStruct(ctypes.Structure):
133 _fields_=[
134 ('cb',ctypes.wintypes.DWORD),
135 ('flags',ctypes.wintypes.DWORD),
136 ('codepage',ctypes.c_uint),
137 ('lpDefaultChar',ctypes.wintypes.LPCSTR),
138 ('lpUsedDefChar',ctypes.c_void_p),
139 ]
140
141 -class getTextLengthExStruct(ctypes.Structure):
142 _fields_=[
143 ('flags',ctypes.wintypes.DWORD),
144 ('codepage',ctypes.c_uint),
145 ]
146
147
148 GT_DEFAULT=0
149 GT_USECRLF=1
150 GT_SELECTION=2
151 GT_RAWTEXT=4
152 GT_NOHIDDENTEXT=8
153
154
155 GTL_DEFAULT=0
156 GTL_USECRLF=1
157 GTL_PRECISE=2
158 GTL_CLOSE=4
159 GTL_NUMCHARS=8
160 GTL_NUMBYTES=16
161
162
163 WB_CLASSIFY=3
164 WB_MOVEWORDLEFT=4
165 WB_MOVEWORDRIGHT=5
166 WB_LEFTBREAK=6
167 WB_RIGHTBREAK=7
168
169 -class EditTextInfo(textInfos.offsets.OffsetsTextInfo):
170
171 - def _getPointFromOffset(self,offset):
172 if self.obj.editAPIVersion==1:
173 processHandle=self.obj.processHandle
174 internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
175 try:
176 p=PointLStruct(0,0)
177 winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None)
178 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_POSFROMCHAR,internalP,offset)
179 winKernel.readProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None)
180 finally:
181 winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE)
182 point=textInfos.Point(p.x,p.y)
183 else:
184 res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_POSFROMCHAR,offset,None)
185 point=textInfos.Point(winUser.LOWORD(res),winUser.HIWORD(res))
186 (left,top,width,height)=self.obj.location
187 if point.x and point.y:
188 point.x=point.x+left
189 point.y=point.y+top
190 return point
191 else:
192 raise NotImplementedError
193
194 - def _getOffsetFromPoint(self,x,y):
195 (left,top,width,height)=self.obj.location
196 if self.obj.editAPIVersion>=1:
197 processHandle=self.obj.processHandle
198 internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
199 try:
200 p=PointLStruct(x-left,y-top)
201 winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None)
202 offset=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_CHARFROMPOS,0,internalP)
203 finally:
204 winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE)
205 else:
206 p=(x-left)+((y-top)<<16)
207 offset=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_CHARFROMPOS,0,p)&0xffff
208 return offset
209
211 oldSel=self._getSelectionOffsets()
212 if oldSel!=(offset,offset+1):
213 self._setSelectionOffsets(offset,offset+1)
214 if self.obj.isWindowUnicode:
215 charFormatStruct=CharFormat2WStruct
216 else:
217 charFormatStruct=CharFormat2AStruct
218 charFormat=charFormatStruct()
219 charFormat.cbSize=ctypes.sizeof(charFormatStruct)
220 processHandle=self.obj.processHandle
221 internalCharFormat=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charFormat),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
222 try:
223 winKernel.writeProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None)
224 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETCHARFORMAT,SCF_SELECTION, internalCharFormat)
225 winKernel.readProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None)
226 finally:
227 winKernel.virtualFreeEx(processHandle,internalCharFormat,0,winKernel.MEM_RELEASE)
228 if oldSel!=(offset,offset+1):
229 self._setSelectionOffsets(oldSel[0],oldSel[1])
230 return charFormat
231
233
234 if self.obj.editAPIVersion<1:
235 return super(EditTextInfo,self)._getFormatFieldAndOffsets(offset,formatConfig,calculateOffsets=calculateOffsets)
236 if calculateOffsets:
237 startOffset,endOffset=self._getWordOffsets(offset)
238 else:
239 startOffset,endOffset=self._startOffset,self._endOffset
240 formatField=textInfos.FormatField()
241 charFormat=None
242 if formatConfig["reportFontName"]:
243 if charFormat is None: charFormat=self._getCharFormat(offset)
244 formatField["font-name"]=charFormat.szFaceName
245 if formatConfig["reportFontSize"]:
246 if charFormat is None: charFormat=self._getCharFormat(offset)
247 formatField["font-size"]="%spt"%(charFormat.yHeight/20)
248 if formatConfig["reportFontAttributes"]:
249 if charFormat is None: charFormat=self._getCharFormat(offset)
250 formatField["bold"]=bool(charFormat.dwEffects&CFE_BOLD)
251 formatField["italic"]=bool(charFormat.dwEffects&CFE_ITALIC)
252 formatField["underline"]=bool(charFormat.dwEffects&CFE_UNDERLINE)
253 formatField["strikethrough"]=bool(charFormat.dwEffects&CFE_STRIKEOUT)
254 if charFormat.dwEffects&CFE_SUBSCRIPT:
255 formatField["text-position"]="sub"
256 elif charFormat.dwEffects&CFE_SUPERSCRIPT:
257 formatField["text-position"]="super"
258 if formatConfig["reportColor"]:
259 if charFormat is None: charFormat=self._getCharFormat(offset)
260 formatField["color"]=colors.RGB.fromCOLORREF(charFormat.crTextColor) if not charFormat.dwEffects&CFE_AUTOCOLOR else _("default color")
261 formatField["background-color"]=colors.RGB.fromCOLORREF(charFormat.crBackColor) if not charFormat.dwEffects&CFE_AUTOBACKCOLOR else _("default color")
262 if formatConfig["reportLineNumber"]:
263 formatField["line-number"]=self._getLineNumFromOffset(offset)+1
264 if formatConfig["reportLinks"]:
265 if charFormat is None: charFormat=self._getCharFormat(offset)
266 formatField["link"]=bool(charFormat.dwEffects&CFM_LINK)
267 return formatField,(startOffset,endOffset)
268
270 if self.obj.editAPIVersion>=1:
271 charRange=CharRangeStruct()
272 processHandle=self.obj.processHandle
273 internalCharRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
274 try:
275 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_EXGETSEL,0, internalCharRange)
276 winKernel.readProcessMemory(processHandle,internalCharRange,ctypes.byref(charRange),ctypes.sizeof(charRange),None)
277 finally:
278 winKernel.virtualFreeEx(processHandle,internalCharRange,0,winKernel.MEM_RELEASE)
279 return (charRange.cpMin,charRange.cpMax)
280 else:
281 start=ctypes.c_uint()
282 end=ctypes.c_uint()
283 res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETSEL,ctypes.byref(start),ctypes.byref(end))
284 return start.value,end.value
285
286 - def _setSelectionOffsets(self,start,end):
287 if self.obj.editAPIVersion>=1:
288 charRange=CharRangeStruct()
289 charRange.cpMin=start
290 charRange.cpMax=end
291 processHandle=self.obj.processHandle
292 internalCharRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
293 try:
294 winKernel.writeProcessMemory(processHandle,internalCharRange,ctypes.byref(charRange),ctypes.sizeof(charRange),None)
295 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_EXSETSEL,0, internalCharRange)
296 finally:
297 winKernel.virtualFreeEx(processHandle,internalCharRange,0,winKernel.MEM_RELEASE)
298 else:
299 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_SETSEL,start,end)
300
301 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_SCROLLCARET,0,0)
302
303 - def _getCaretOffset(self):
304 return self._getSelectionOffsets()[0]
305
306 - def _setCaretOffset(self,offset):
307 return self._setSelectionOffsets(offset,offset)
308
309 - def _getStoryText(self):
310 if controlTypes.STATE_PROTECTED in self.obj.states:
311 return '*'*(self._getStoryLength()-1)
312 return self.obj.windowText
313
314 - def _getStoryLength(self):
315 if self.obj.editAPIVersion>=2:
316 info=getTextLengthExStruct()
317 info.flags=GTL_NUMCHARS
318 if self.obj.isWindowUnicode:
319 info.codepage=1200
320 else:
321 info.codepage=0
322 processHandle=self.obj.processHandle
323 internalInfo=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(info),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
324 try:
325 winKernel.writeProcessMemory(processHandle,internalInfo,ctypes.byref(info),ctypes.sizeof(info),None)
326 textLen=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETTEXTLENGTHEX,internalInfo,0)
327 finally:
328 winKernel.virtualFreeEx(processHandle,internalInfo,0,winKernel.MEM_RELEASE)
329 return textLen+1
330 else:
331 return watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)+1
332
333 - def _getLineCount(self):
335
337 if self.obj.editAPIVersion>=2:
338 bufLen=((end-start)+1)*2
339 if self.obj.isWindowUnicode:
340 textRange=TextRangeUStruct()
341 else:
342 textRange=TextRangeAStruct()
343 textRange.chrg.cpMin=start
344 textRange.chrg.cpMax=end
345 processHandle=self.obj.processHandle
346 internalBuf=winKernel.virtualAllocEx(processHandle,None,bufLen,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
347 try:
348 textRange.lpstrText=internalBuf
349 internalTextRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(textRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
350 try:
351 winKernel.writeProcessMemory(processHandle,internalTextRange,ctypes.byref(textRange),ctypes.sizeof(textRange),None)
352 res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETTEXTRANGE,0,internalTextRange)
353 finally:
354 winKernel.virtualFreeEx(processHandle,internalTextRange,0,winKernel.MEM_RELEASE)
355 buf=(ctypes.c_byte*bufLen)()
356 winKernel.readProcessMemory(processHandle,internalBuf,buf,bufLen,None)
357 finally:
358 winKernel.virtualFreeEx(processHandle,internalBuf,0,winKernel.MEM_RELEASE)
359 if self.obj.isWindowUnicode or (res>1 and (buf[res]!=0 or buf[res+1]!=0)):
360 return ctypes.cast(buf,ctypes.c_wchar_p).value
361 else:
362 return unicode(ctypes.cast(buf,ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1])
363 else:
364 return self._getStoryText()[start:end]
365
366 - def _getWordOffsets(self,offset):
367 if self.obj.editAPIVersion>=2:
368 start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDLEFT,offset)
369 end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,start)
370 if end<=offset:
371 start=end
372 end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,offset)
373 return (start,end)
374 elif sys.getwindowsversion().major<6:
375 lineStart,lineEnd=self._getLineOffsets(offset)
376 if offset>=lineEnd:
377 return offset,offset+1
378 lineText=self._getTextRange(lineStart,lineEnd)
379 lineTextLen=len(lineText)
380 relativeOffset=offset-lineStart
381 if relativeOffset>=lineTextLen:
382 return offset,offset+1
383
384 if lineText[relativeOffset] in ['\r','\n']:
385 return offset,offset+1
386
387 tempOffset=relativeOffset
388 while tempOffset>=0 and lineText[tempOffset].isspace():
389 tempOffset-=1
390 while tempOffset>=0 and not lineText[tempOffset].isspace():
391 tempOffset-=1
392 tempOffset+=1
393 start=lineStart+tempOffset
394 startOnSpace=True if tempOffset<lineTextLen and lineText[tempOffset].isspace() else False
395
396 tempOffset=relativeOffset
397 if startOnSpace:
398 while tempOffset<lineTextLen and lineText[tempOffset].isspace():
399 tempOffset+=1
400 while tempOffset<lineTextLen and not lineText[tempOffset].isspace():
401 tempOffset+=1
402 while tempOffset<lineTextLen and lineText[tempOffset].isspace():
403 tempOffset+=1
404 end=lineStart+tempOffset
405 return start,end
406 else:
407 if self._getTextRange(offset,offset+1) in ['\r','\n']:
408 return offset,offset+1
409 else:
410 return super(EditTextInfo,self)._getWordOffsets(offset)
411
412
413 - def _getLineNumFromOffset(self,offset):
414 if self.obj.editAPIVersion>=1:
415 res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_EXLINEFROMCHAR,0,offset)
416 return res
417 else:
418 return watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEFROMCHAR,offset,0)
419
420 - def _getLineOffsets(self,offset):
421 lineNum=self._getLineNumFromOffset(offset)
422 start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEINDEX,lineNum,0)
423 length=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINELENGTH,offset,0)
424 end=start+length
425
426 if start<=0 and end<=0 and lineNum<=0 and self._getLineCount()<=0 and self._getStoryLength()>0:
427 return super(EditTextInfo,self)._getLineOffsets(offset)
428
429 if end<=offset:
430 end=offset+1
431
432 limit=self._getStoryLength()
433 while self._getLineNumFromOffset(end)==lineNum and end<limit:
434 end+=1
435 return (start,end)
436
437 - def _getParagraphOffsets(self,offset):
438 return self._getLineOffsets(offset)
439
440 ITextDocumentUnitsToNVDAUnits={
441 comInterfaces.tom.tomCharacter:textInfos.UNIT_CHARACTER,
442 comInterfaces.tom.tomWord:textInfos.UNIT_WORD,
443 comInterfaces.tom.tomLine:textInfos.UNIT_LINE,
444 comInterfaces.tom.tomSentence:textInfos.UNIT_SENTENCE,
445 comInterfaces.tom.tomParagraph:textInfos.UNIT_PARAGRAPH,
446 comInterfaces.tom.tomStory:textInfos.UNIT_STORY,
447 }
448
449 NVDAUnitsToITextDocumentUnits={
450 textInfos.UNIT_CHARACTER:comInterfaces.tom.tomCharacter,
451 textInfos.UNIT_WORD:comInterfaces.tom.tomWord,
452 textInfos.UNIT_LINE:comInterfaces.tom.tomLine,
453 textInfos.UNIT_SENTENCE:comInterfaces.tom.tomSentence,
454 textInfos.UNIT_PARAGRAPH:comInterfaces.tom.tomParagraph,
455 textInfos.UNIT_STORY:comInterfaces.tom.tomStory,
456 textInfos.UNIT_READINGCHUNK:comInterfaces.tom.tomSentence,
457 }
458
459 -class ITextDocumentTextInfo(textInfos.TextInfo):
460
462 p=textInfos.Point(0,0)
463 (p.x,p.y)=self._rangeObj.GetPoint(comInterfaces.tom.tomStart)
464 if p.x and p.y:
465 return p
466 else:
467 raise NotImplementedError
468
470 oldSel=self.obj.ITextSelectionObject.duplicate
471 if not (oldSel.start==range.start and oldSel.end==range.end):
472 self.obj.ITextSelectionObject.start=range.start
473 self.obj.ITextSelectionObject.end=range.end
474 if self.obj.isWindowUnicode:
475 charFormatStruct=CharFormat2WStruct
476 else:
477 charFormatStruct=CharFormat2AStruct
478 charFormat=charFormatStruct()
479 charFormat.cbSize=ctypes.sizeof(charFormatStruct)
480 processHandle=self.obj.processHandle
481 internalCharFormat=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charFormat),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
482 try:
483 winKernel.writeProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None)
484 watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETCHARFORMAT,SCF_SELECTION, internalCharFormat)
485 winKernel.readProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None)
486 finally:
487 winKernel.virtualFreeEx(processHandle,internalCharFormat,0,winKernel.MEM_RELEASE)
488 if not (oldSel.start==range.start and oldSel.end==range.end):
489 self.obj.ITextSelectionObject.start=oldSel.start
490 self.obj.ITextSelectionObject.end=oldSel.end
491 return charFormat
492
494 formatField=textInfos.FormatField()
495 fontObj=None
496 paraFormatObj=None
497 charFormat=None
498 if formatConfig["reportAlignment"]:
499 if not paraFormatObj: paraFormatObj=range.para
500 alignment=paraFormatObj.alignment
501 if alignment==comInterfaces.tom.tomAlignLeft:
502 formatField["text-align"]="left"
503 elif alignment==comInterfaces.tom.tomAlignCenter:
504 formatField["text-align"]="center"
505 elif alignment==comInterfaces.tom.tomAlignRight:
506 formatField["text-align"]="right"
507 elif alignment==comInterfaces.tom.tomAlignJustify:
508 formatField["text-align"]="justify"
509 if formatConfig["reportLineNumber"]:
510 formatField["line-number"]=range.getIndex(comInterfaces.tom.tomLine)
511 if formatConfig["reportFontName"]:
512 if not fontObj: fontObj=range.font
513 formatField["font-name"]=fontObj.name
514 if formatConfig["reportFontSize"]:
515 if not fontObj: fontObj=range.font
516 formatField["font-size"]="%spt"%fontObj.size
517 if formatConfig["reportFontAttributes"]:
518 if not fontObj: fontObj=range.font
519 formatField["bold"]=bool(fontObj.bold)
520 formatField["italic"]=bool(fontObj.italic)
521 formatField["underline"]=bool(fontObj.underline)
522 formatField["strikethrough"]=bool(fontObj.StrikeThrough)
523 if fontObj.superscript:
524 formatField["text-position"]="super"
525 elif fontObj.subscript:
526 formatField["text-position"]="sub"
527 if formatConfig["reportLinks"]:
528 if charFormat is None: charFormat=self._getCharFormat(range)
529 formatField["link"]=bool(charFormat.dwEffects&CFM_LINK)
530 return formatField
531
533 startLimit=self._rangeObj.start
534 endLimit=self._rangeObj.end
535 chunkRange=range.duplicate
536 if formatConfig["reportLineNumber"]:
537 chunkRange.expand(comInterfaces.tom.tomLine)
538 else:
539 chunkRange.expand(comInterfaces.tom.tomParagraph)
540 chunkStart=chunkRange.start
541 chunkEnd=chunkRange.end
542 if startLimit<chunkStart:
543 startLimit=chunkStart
544 if endLimit>chunkEnd:
545 endLimit=chunkEnd
546
547 range.expand(comInterfaces.tom.tomCharFormat)
548 if range.end>endLimit:
549 range.end=endLimit
550 if range.start<startLimit:
551 range.start=startLimit
552
553 - def _getEmbeddedObjectLabel(self,embedRangeObj):
554 label=None
555 try:
556 o=embedRangeObj.GetEmbeddedObject()
557 except comtypes.COMError:
558 o=None
559 if not o:
560 return None
561 import oleacc
562 try:
563 label=o.QueryInterface(oleacc.IAccessible).accName(0);
564 except comtypes.COMError:
565 pass
566 if label:
567 return label
568 left,top=embedRangeObj.GetPoint(comInterfaces.tom.tomStart)
569 right,bottom=embedRangeObj.GetPoint(comInterfaces.tom.tomEnd)
570 import displayModel
571 label=displayModel.getWindowTextInRect(self.obj.appModule.helperLocalBindingHandle, self.obj.windowHandle, left, top, right, bottom+10,1,1)[0]
572 if label and not label.isspace():
573 return label
574 try:
575 dataObj=o.QueryInterface(oleTypes.IDataObject)
576 except comtypes.COMError:
577 dataObj=None
578 if dataObj:
579 try:
580 dataObj=pythoncom._univgw.interface(hash(dataObj),pythoncom.IID_IDataObject)
581 format=(win32clipboard.CF_UNICODETEXT, None, pythoncom.DVASPECT_CONTENT, -1, pythoncom.TYMED_HGLOBAL)
582 medium=dataObj.GetData(format)
583 buf=ctypes.create_string_buffer(medium.data)
584 buf=ctypes.cast(buf,ctypes.c_wchar_p)
585 label=buf.value
586 except:
587 pass
588 if label:
589 return label
590 try:
591 oleObj=o.QueryInterface(oleTypes.IOleObject)
592 label=oleObj.GetUserType(1)
593 except comtypes.COMError:
594 pass
595 return label
596
597 - def _getTextAtRange(self,rangeObj):
598 embedRangeObj=None
599 bufText=rangeObj.text
600 if bufText is None:
601 bufText=""
602 newTextList=[]
603 start=rangeObj.start
604 for offset in range(len(bufText)):
605 if ord(bufText[offset])==0xfffc:
606 if embedRangeObj is None: embedRangeObj=rangeObj.duplicate
607 embedRangeObj.setRange(start+offset,start+offset+1)
608 label=self._getEmbeddedObjectLabel(embedRangeObj)
609 if label:
610 newTextList.append(label)
611 else:
612 newTextList.append(_("embedded object"))
613 else:
614 newTextList.append(bufText[offset])
615 return "".join(newTextList)
616
617 - def __init__(self,obj,position,_rangeObj=None):
618 super(ITextDocumentTextInfo,self).__init__(obj,position)
619 if _rangeObj:
620 self._rangeObj=_rangeObj.Duplicate
621 return
622 if isinstance(position,textInfos.Point):
623 self._rangeObj=self.obj.ITextDocumentObject.rangeFromPoint(position.x,position.y)
624 elif position==textInfos.POSITION_ALL:
625 self._rangeObj=self.obj.ITextDocumentObject.range(0,0)
626 self._rangeObj.expand(comInterfaces.tom.tomStory)
627 elif position==textInfos.POSITION_SELECTION:
628 self._rangeObj=self.obj.ITextSelectionObject.duplicate
629 elif position==textInfos.POSITION_CARET:
630 self._rangeObj=self.obj.ITextSelectionObject.duplicate
631 self._rangeObj.Collapse(True)
632 elif position==textInfos.POSITION_FIRST:
633 self._rangeObj=self.obj.ITextDocumentObject.range(0,0)
634 elif position==textInfos.POSITION_LAST:
635 self._rangeObj=self.obj.ITextDocumentObject.range(0,0)
636 self._rangeObj.move(comInterfaces.tom.tomStory,1)
637 self._rangeObj.moveStart(comInterfaces.tom.tomCharacter,-1)
638 elif isinstance(position,textInfos.offsets.Offsets):
639 self._rangeObj=self.obj.ITextDocumentObject.range(position.startOffset,position.endOffset)
640 else:
641 raise NotImplementedError("position: %s"%position)
642
643 - def getTextWithFields(self,formatConfig=None):
644 if not formatConfig:
645 formatConfig=config.conf["documentFormatting"]
646 range=self._rangeObj.duplicate
647 range.collapse(True)
648 if not formatConfig["detectFormatAfterCursor"]:
649 range.expand(comInterfaces.tom.tomCharacter)
650 return [textInfos.FieldCommand("formatChange",self._getFormatFieldAtRange(range,formatConfig)),
651 self._getTextAtRange(self._rangeObj)]
652 commandList=[]
653 endLimit=self._rangeObj.end
654 while range.end<endLimit:
655 self._expandFormatRange(range,formatConfig)
656 commandList.append(textInfos.FieldCommand("formatChange",self._getFormatFieldAtRange(range,formatConfig)))
657 commandList.append(self._getTextAtRange(range))
658 end=range.end
659 range.start=end
660
661 if range.end<end:
662 break
663 return commandList
664
665 - def expand(self,unit):
666 if unit in NVDAUnitsToITextDocumentUnits:
667 self._rangeObj.Expand(NVDAUnitsToITextDocumentUnits[unit])
668 else:
669 raise NotImplementedError("unit: %s"%unit)
670
671 - def compareEndPoints(self,other,which):
672 if which=="startToStart":
673 diff=self._rangeObj.Start-other._rangeObj.Start
674 elif which=="startToEnd":
675 diff=self._rangeObj.Start-other._rangeObj.End
676 elif which=="endToStart":
677 diff=self._rangeObj.End-other._rangeObj.Start
678 elif which=="endToEnd":
679 diff=self._rangeObj.End-other._rangeObj.End
680 else:
681 raise ValueError("bad argument - which: %s"%which)
682 if diff<0:
683 diff=-1
684 elif diff>0:
685 diff=1
686 return diff
687
688 - def setEndPoint(self,other,which):
689 if which=="startToStart":
690 self._rangeObj.Start=other._rangeObj.Start
691 elif which=="startToEnd":
692 self._rangeObj.Start=other._rangeObj.End
693 elif which=="endToStart":
694 self._rangeObj.End=other._rangeObj.Start
695 elif which=="endToEnd":
696 self._rangeObj.End=other._rangeObj.End
697 else:
698 raise ValueError("bad argument - which: %s"%which)
699
701 if self._rangeObj.Start==self._rangeObj.End:
702 return True
703 else:
704 return False
705
706 - def collapse(self,end=False):
707 a=self._rangeObj.Start
708 b=self._rangeObj.end
709 startOffset=min(a,b)
710 endOffset=max(a,b)
711 if not end:
712 offset=startOffset
713 else:
714 offset=endOffset
715 self._rangeObj.SetRange(offset,offset)
716
718 return ITextDocumentTextInfo(self.obj,None,_rangeObj=self._rangeObj)
719
720 - def _get_text(self):
721 return self._getTextAtRange(self._rangeObj)
722
723 - def move(self,unit,direction,endPoint=None):
724 if unit in NVDAUnitsToITextDocumentUnits:
725 unit=NVDAUnitsToITextDocumentUnits[unit]
726 else:
727 raise NotImplementedError("unit: %s"%unit)
728 if endPoint=="start":
729 moveFunc=self._rangeObj.MoveStart
730 elif endPoint=="end":
731 moveFunc=self._rangeObj.MoveEnd
732 else:
733 moveFunc=self._rangeObj.Move
734 res=moveFunc(unit,direction)
735 return res
736
737 - def _get_bookmark(self):
738 return textInfos.offsets.Offsets(self._rangeObj.start,self._rangeObj.end)
739
740 - def updateCaret(self):
741 self.obj.ITextSelectionObject.start=self.obj.ITextSelectionObject.end=self._rangeObj.start
742
743 - def updateSelection(self):
744 self.obj.ITextSelectionObject.start=self._rangeObj.start
745 self.obj.ITextSelectionObject.end=self._rangeObj.end
746
747 -class Edit(EditableTextWithAutoSelectDetection, Window):
809
812
815
818
821