def _getOffsetFromPoint(self,x,y): x, y = winUser.ScreenToClient(self.obj.windowHandle, x, y) if self.obj.editAPIVersion>=1: processHandle=self.obj.processHandle internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: p=PointLStruct(x,y) winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) offset=watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.EM_CHARFROMPOS,0,internalP) finally: winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE) else: p=x+(y<<16) res=watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.EM_CHARFROMPOS,0,p) offset=winUser.LOWORD(res) lineNum=winUser.HIWORD(res) if offset==0xFFFF and lineNum==0xFFFF: raise LookupError("Point outside client area") if self._getStoryLength() > 0xFFFF: # Returned offsets are 16 bits, therefore for large documents, we need to make sure that the correct offset is returned. # We can calculate this by using the start offset of the line with the retrieved line number. lineStart=watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.EM_LINEINDEX,lineNum,0) # Get the last 16 bits of the line number lineStart16=lineStart&0xFFFF if lineStart16 > offset: # There are cases where the last 16 bits of the line start are greather than the 16 bits offset. # For example, this happens when the line start offset is 65534 (0xFFFE) # and the offset we need ought to be 65537 (0x10001), which is a 17 bits number # In that case, add 0x10000 to the offset, which will make the eventual formula return the correct offset, # unless a line has more than 65535 characters, in which case we can't get a reliable offset. offset+=0x10000 offset = (offset - lineStart16) + lineStart return offset
def _getTextRange(self, start, end): bufLen = (end - start) + 1 textRange = TextRangeStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx( processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE ) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx( processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE ) try: winKernel.writeProcessMemory( processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None ) watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = ctypes.create_string_buffer(bufLen) winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) cp = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETCODEPAGE, 0, 0) if cp == SC_CP_UTF8: return unicode(buf.value, errors="replace", encoding="utf-8") else: return unicode(buf.value, errors="replace", encoding=locale.getlocale()[1])
def _get_role(self): hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) iType=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETITEMTYPE,hItem,0) if iType==CLCIT_DIVIDER or iType==CLCIT_INVALID: #some clists treat invalid as divider return controlTypes.ROLE_SEPARATOR else: return controlTypes.ROLE_TREEVIEWITEM
def _getWordOffsets(self,offset): start=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDSTARTPOSITION,offset,0) end=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDENDPOSITION,start,0) if end<=offset: start=end end=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDENDPOSITION,offset,0) return [start,end]
def _get_columnCount(self): if not self.isMultiColumn: return 0 headerHwnd= watchdog.cancellableSendMessage(self.windowHandle,LVM_GETHEADER,0,0) count = watchdog.cancellableSendMessage(headerHwnd, HDM_GETITEMCOUNT, 0, 0) if not count: return 1 return count
def _get_states(self): newStates=super(mirandaIMContactList,self)._get_states() hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) state=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETEXPAND,hItem,0) if state==CLE_EXPAND: newStates.add(controlTypes.STATE_EXPANDED) elif state==CLE_COLLAPSE: newStates.add(controlTypes.STATE_COLLAPSED) return newStates
def _getPointFromOffset(self,offset): point=textInfos.Point( watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POINTXFROMPOSITION,None,offset), watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POINTYFROMPOSITION,None,offset) ) if point.x and point.y: return point else: raise NotImplementedError
def _getStoryLength(self): ciChar=AECHARINDEX() processHandle=self.obj.processHandle internalCiChar=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(ciChar),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_GETINDEX,AEGI_LASTCHAR,internalCiChar) end=watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_INDEXTORICHOFFSET,0,internalCiChar) finally: winKernel.virtualFreeEx(processHandle,internalCiChar,0,winKernel.MEM_RELEASE) return end+1
def _getLineNumFromOffset(self,offset): ciChar=AECHARINDEX() processHandle=self.obj.processHandle internalCiChar=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(ciChar),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_RICHOFFSETTOINDEX,offset,internalCiChar) winKernel.readProcessMemory(processHandle,internalCiChar,ctypes.byref(ciChar),ctypes.sizeof(ciChar),None) finally: winKernel.virtualFreeEx(processHandle,internalCiChar,0,winKernel.MEM_RELEASE) return ciChar.nLine
def _getPointFromOffset(self,offset): x, y = winUser.ClientToScreen(self.obj.windowHandle, watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POINTXFROMPOSITION,None,offset), watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POINTYFROMPOSITION,None,offset) ) point=textInfos.Point(x, y) if point.x is not None and point.y is not None: return point else: raise NotImplementedError
def _get_childCount(self): hItem=self.treeview_hItem if not hItem: return 0 childItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_CHILD,hItem) if childItem<=0: return 0 numItems=0 while childItem>0: numItems+=1 childItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_NEXT,childItem) return numItems
def _getWordOffsets(self,offset): if self.obj.editAPIVersion>=2: start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDLEFT,offset) end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,start) if end<=offset: start=end end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,offset) return (start,end) else: if self._getTextRange(offset,offset+1) in ['\r','\n']: return offset,offset+1 else: return super(EditTextInfo,self)._getWordOffsets(offset)
def _getColumnImageIDRaw(self, index): processHandle=self.processHandle internalItem=winKernel.virtualAllocEx(processHandle,None,sizeof(self.LVITEM),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: item=self.LVITEM(iItem=self.IAccessibleChildID-1,mask=LVIF_IMAGE|LVIF_COLUMNS,iSubItem=index) winKernel.writeProcessMemory(processHandle,internalItem,byref(item),sizeof(self.LVITEM),None) item.mask=LVIF_IMAGE|LVIF_COLUMNS winKernel.writeProcessMemory(processHandle,internalItem,byref(item),sizeof(self.LVITEM),None) watchdog.cancellableSendMessage(self.windowHandle,LVM_GETITEMW, 0, internalItem) winKernel.readProcessMemory(processHandle,internalItem,byref(item),sizeof(item),None) finally: winKernel.virtualFreeEx(processHandle,internalItem,0,winKernel.MEM_RELEASE) return item.iImage
def _getColumnLocationRaw(self,index): processHandle=self.processHandle localRect=RECT(left=2,top=index) internalRect=winKernel.virtualAllocEx(processHandle,None,sizeof(localRect),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalRect,byref(localRect),sizeof(localRect),None) watchdog.cancellableSendMessage(self.windowHandle,LVM_GETSUBITEMRECT, (self.IAccessibleChildID-1), internalRect) winKernel.readProcessMemory(processHandle,internalRect,byref(localRect),sizeof(localRect),None) finally: winKernel.virtualFreeEx(processHandle,internalRect,0,winKernel.MEM_RELEASE) windll.user32.ClientToScreen(self.windowHandle,byref(localRect)) windll.user32.ClientToScreen(self.windowHandle,byref(localRect,8)) return (localRect.left,localRect.top,localRect.right-localRect.left,localRect.bottom-localRect.top)
def _get_parent(self): if self.IAccessibleChildID==0: return super(TreeViewItem,self)._get_parent() hItem=self.treeview_hItem if not hItem: return super(TreeViewItem,self)._get_parent() parentItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_PARENT,hItem) if parentItem<=0: return super(TreeViewItem,self)._get_parent() newID=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPHTREEITEMTOACCID,parentItem,0) if not newID: # Tree views from comctl < 6.0 use the hItem as the child ID. newID=parentItem return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=newID)
def _get_name(self): curIndex=watchdog.cancellableSendMessage(hwndWinamp,WM_WA_IPC,-1,IPC_PLAYLIST_GET_NEXT_SELECTED) if curIndex <0: return None info=fileinfo2() info.fileindex=curIndex internalInfo=winKernel.virtualAllocEx(self.processHandle,None,sizeof(info),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(self.processHandle,internalInfo,byref(info),sizeof(info),None) watchdog.cancellableSendMessage(self.windowHandle,WM_WA_IPC,IPC_PE_GETINDEXTITLE,internalInfo) winKernel.readProcessMemory(self.processHandle,internalInfo,byref(info),sizeof(info),None) finally: winKernel.virtualFreeEx(self.processHandle,internalInfo,0,winKernel.MEM_RELEASE) return unicode("%d.\t%s\t%s"%(curIndex+1,info.filetitle,info.filelength), errors="replace", encoding=locale.getlocale()[1])
def _getLineOffsets(self,offset): (start,end)=super(AkelEditTextInfo,self)._getLineOffsets(offset) if end == self._getStoryLength(): return (start,end) ciChar=AECHARINDEX() processHandle=self.obj.processHandle internalCiChar=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(ciChar),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_RICHOFFSETTOINDEX,offset,internalCiChar) watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_GETINDEX,AEGI_NEXTLINE,internalCiChar) end=watchdog.cancellableSendMessage(self.obj.windowHandle,AEM_INDEXTORICHOFFSET,0,internalCiChar) finally: winKernel.virtualFreeEx(processHandle,internalCiChar,0,winKernel.MEM_RELEASE) return (start,end)
def _getCharacterOffsets(self,offset): if offset>=self._getStoryLength(): return offset,offset+1 end=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POSITIONAFTER,offset,0) start=offset tempOffset=offset-1 while True: start=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_POSITIONAFTER,tempOffset,0) if start<end: break elif tempOffset==0: start=tempOffset break else: tempOffset-=1 return [start,end]
def _getOffsetFromPoint(self,x,y): (left,top,width,height)=self.obj.location if self.obj.editAPIVersion>=1: processHandle=self.obj.processHandle internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: p=PointLStruct(x-left,y-top) winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) offset=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_CHARFROMPOS,0,internalP) finally: winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE) else: p=(x-left)+((y-top)<<16) offset=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_CHARFROMPOS,0,p)&0xffff return offset
def _getTextRange(self,start,end): if self.obj.editAPIVersion>=2: bufLen=((end-start)+1)*2 if self.obj.isWindowUnicode: textRange=TextRangeUStruct() else: textRange=TextRangeAStruct() textRange.chrg.cpMin=start textRange.chrg.cpMax=end processHandle=self.obj.processHandle internalBuf=winKernel.virtualAllocEx(processHandle,None,bufLen,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: textRange.lpstrText=internalBuf internalTextRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(textRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalTextRange,ctypes.byref(textRange),ctypes.sizeof(textRange),None) res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETTEXTRANGE,0,internalTextRange) finally: winKernel.virtualFreeEx(processHandle,internalTextRange,0,winKernel.MEM_RELEASE) buf=(ctypes.c_byte*bufLen)() winKernel.readProcessMemory(processHandle,internalBuf,buf,bufLen,None) finally: winKernel.virtualFreeEx(processHandle,internalBuf,0,winKernel.MEM_RELEASE) if self.obj.isWindowUnicode or (res>1 and (buf[res]!=0 or buf[res+1]!=0)): text=ctypes.cast(buf,ctypes.c_wchar_p).value else: text=unicode(ctypes.cast(buf,ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1]) # #4095: Some protected richEdit controls do not hide their password characters. # We do this specifically. # Note that protected standard edit controls get characters hidden in _getStoryText. if text and controlTypes.STATE_PROTECTED in self.obj.states: text=u'*'*len(text) else: text=self._getStoryText()[start:end] return text
def _get_treeview_hItem(self): if not hasattr(self,'_treeview_hItem'): self._treeview_hItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPACCIDTOHTREEITEM,self.IAccessibleChildID,0) if not self._treeview_hItem: # Tree views from comctl < 6.0 use the hItem as the child ID. self._treeview_hItem=self.IAccessibleChildID return self._treeview_hItem
def _get_name(self): hItem=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSELECTION,0,0) internalBuf=winKernel.virtualAllocEx(self.processHandle,None,MAXITEMTEXTLEN,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.windowHandle,CLM_GETITEMTEXT,hItem,internalBuf) buf=create_unicode_buffer(MAXITEMTEXTLEN) winKernel.readProcessMemory(self.processHandle,internalBuf,buf,MAXITEMTEXTLEN,None) text=buf.value statusMsgPtr=watchdog.cancellableSendMessage(self.windowHandle,CLM_GETSTATUSMSG,hItem,0) if statusMsgPtr>0: buf2=create_unicode_buffer(MAXSTATUSMSGLEN) winKernel.readProcessMemory(self.processHandle,statusMsgPtr,buf2,MAXSTATUSMSGLEN,None) text="%s %s"%(text,buf2.value) finally: winKernel.virtualFreeEx(self.processHandle,internalBuf,0,winKernel.MEM_RELEASE) return text
def _getLineOffsets(self,offset): lineNum=self._getLineNumFromOffset(offset) start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEINDEX,lineNum,0) length=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINELENGTH,offset,0) end=start+length #If we just seem to get invalid line info, calculate manually if start<=0 and end<=0 and lineNum<=0 and self._getLineCount()<=0 and self._getStoryLength()>0: return super(EditTextInfo,self)._getLineOffsets(offset) #Some edit controls that show both line feed and carage return can give a length not including the line feed if end<=offset: end=offset+1 #edit controls lye about their line length limit=self._getStoryLength() while self._getLineNumFromOffset(end)==lineNum and end<limit: end+=1 return (start,end)
def _getTextRange(self,start,end): if self.obj.editAPIVersion>=2: bufLen=((end-start)+1)*2 if self.obj.isWindowUnicode: textRange=TextRangeUStruct() else: textRange=TextRangeAStruct() textRange.chrg.cpMin=start textRange.chrg.cpMax=end processHandle=self.obj.processHandle internalBuf=winKernel.virtualAllocEx(processHandle,None,bufLen,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: textRange.lpstrText=internalBuf internalTextRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(textRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalTextRange,ctypes.byref(textRange),ctypes.sizeof(textRange),None) res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETTEXTRANGE,0,internalTextRange) finally: winKernel.virtualFreeEx(processHandle,internalTextRange,0,winKernel.MEM_RELEASE) buf=(ctypes.c_byte*bufLen)() winKernel.readProcessMemory(processHandle,internalBuf,buf,bufLen,None) finally: winKernel.virtualFreeEx(processHandle,internalBuf,0,winKernel.MEM_RELEASE) if self.obj.isWindowUnicode or (res>1 and (buf[res]!=0 or buf[res+1]!=0)): text=ctypes.cast(buf,ctypes.c_wchar_p).value else: text=unicode(ctypes.cast(buf,ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1]) else: text=self._getStoryText()[start:end] return text
def _getSelectionOffsets(self): if self.obj.editAPIVersion>=1: charRange=CharRangeStruct() processHandle=self.obj.processHandle internalCharRange=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charRange),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle,EM_EXGETSEL,0, internalCharRange) winKernel.readProcessMemory(processHandle,internalCharRange,ctypes.byref(charRange),ctypes.sizeof(charRange),None) finally: winKernel.virtualFreeEx(processHandle,internalCharRange,0,winKernel.MEM_RELEASE) return (charRange.cpMin,charRange.cpMax) else: start=ctypes.c_uint() end=ctypes.c_uint() res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETSEL,ctypes.byref(start),ctypes.byref(end)) return start.value,end.value
def _getFormatFieldAndOffsets(self, offset, formatConfig, calculateOffsets=True): style = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETSTYLEAT, offset, 0) if calculateOffsets: # we need to manually see how far the style goes, limit to line lineStart, lineEnd = self._getLineOffsets(offset) startOffset = offset while startOffset > lineStart: curStyle = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETSTYLEAT, startOffset - 1, 0) if curStyle == style: startOffset -= 1 else: break endOffset = offset + 1 while endOffset < lineEnd: curStyle = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETSTYLEAT, endOffset, 0) if curStyle == style: endOffset += 1 else: break else: startOffset, endOffset = (self._startOffset, self._endOffset) formatField = textInfos.FormatField() if formatConfig["reportFontName"]: # To get font name, We need to allocate memory with in Scintilla's process, and then copy it out fontNameBuf = ctypes.create_string_buffer(32) internalBuf = winKernel.virtualAllocEx( self.obj.processHandle, None, len(fontNameBuf), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE ) try: watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_STYLEGETFONT, style, internalBuf) winKernel.readProcessMemory(self.obj.processHandle, internalBuf, fontNameBuf, len(fontNameBuf), None) finally: winKernel.virtualFreeEx(self.obj.processHandle, internalBuf, 0, winKernel.MEM_RELEASE) formatField["font-name"] = fontNameBuf.value if formatConfig["reportFontSize"]: formatField["font-size"] = "%spt" % watchdog.cancellableSendMessage( self.obj.windowHandle, SCI_STYLEGETSIZE, style, 0 ) if formatConfig["reportLineNumber"]: formatField["line-number"] = self._getLineNumFromOffset(offset) + 1 if formatConfig["reportFontAttributes"]: formatField["bold"] = bool( watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_STYLEGETBOLD, style, 0) ) formatField["italic"] = bool( watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_STYLEGETITALIC, style, 0) ) formatField["underline"] = bool( watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_STYLEGETUNDERLINE, style, 0) ) return formatField, (startOffset, endOffset)
def _getWordOffsets(self,offset): if self.obj.editAPIVersion>=2: start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDLEFT,offset) end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,start) if end<=offset: start=end end=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_FINDWORDBREAK,WB_MOVEWORDRIGHT,offset) return (start,end) elif sys.getwindowsversion().major<6: #Implementation of standard edit field wordbreak behaviour (only breaks on space) lineStart,lineEnd=self._getLineOffsets(offset) if offset>=lineEnd: return offset,offset+1 lineText=self._getTextRange(lineStart,lineEnd) lineTextLen=len(lineText) relativeOffset=offset-lineStart if relativeOffset>=lineTextLen: return offset,offset+1 #cariage returns are always treeted as a word by themselves if lineText[relativeOffset] in ['\r','\n']: return offset,offset+1 #Find the start of the word (possibly moving through space to get to the word first) tempOffset=relativeOffset while tempOffset>=0 and lineText[tempOffset].isspace(): tempOffset-=1 while tempOffset>=0 and not lineText[tempOffset].isspace(): tempOffset-=1 tempOffset+=1 start=lineStart+tempOffset startOnSpace=True if tempOffset<lineTextLen and lineText[tempOffset].isspace() else False #Find the end of the word and trailing space tempOffset=relativeOffset if startOnSpace: while tempOffset<lineTextLen and lineText[tempOffset].isspace(): tempOffset+=1 while tempOffset<lineTextLen and not lineText[tempOffset].isspace(): tempOffset+=1 while tempOffset<lineTextLen and lineText[tempOffset].isspace(): tempOffset+=1 end=lineStart+tempOffset return start,end else: if self._getTextRange(offset,offset+1) in ['\r','\n']: return offset,offset+1 else: return super(EditTextInfo,self)._getWordOffsets(offset)
def _getStoryLength(self): if self.obj.editAPIVersion>=2: info=getTextLengthExStruct() info.flags=GTL_NUMCHARS if self.obj.isWindowUnicode: info.codepage=1200 else: info.codepage=0 processHandle=self.obj.processHandle internalInfo=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(info),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalInfo,ctypes.byref(info),ctypes.sizeof(info),None) textLen=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETTEXTLENGTHEX,internalInfo,0) finally: winKernel.virtualFreeEx(processHandle,internalInfo,0,winKernel.MEM_RELEASE) return textLen+1 else: return watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)+1
def _get_isMultiColumn(self): view = watchdog.cancellableSendMessage(self.windowHandle, LVM_GETVIEW, 0, 0) if view in (LV_VIEW_DETAILS, LV_VIEW_TILE): return True elif view == 0: # #2673: This could indicate that LVM_GETVIEW is not supported (comctl32 < 6.0). # Unfortunately, it could also indicate LV_VIEW_ICON. # Hopefully, no one sets LVS_REPORT and then LV_VIEW_ICON. return self.windowStyle & LVS_TYPEMASK == LVS_REPORT return False
def _getPointFromOffset(self,offset): if self.obj.editAPIVersion==1 or self.obj.editAPIVersion>=3: processHandle=self.obj.processHandle internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: p=PointLStruct(0,0) winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) watchdog.cancellableSendMessage(self.obj.windowHandle,EM_POSFROMCHAR,internalP,offset) winKernel.readProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) finally: winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE) point=textInfos.Point(p.x,p.y) else: res=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_POSFROMCHAR,offset,None) point=textInfos.Point(winUser.LOWORD(res),winUser.HIWORD(res)) (left,top,width,height)=self.obj.location point.x=point.x+left point.y=point.y+top return point
def _get_next(self): if self.IAccessibleChildID == 0: return super(TreeViewItem, self)._get_next() hItem = self.treeview_hItem if not hItem: return None nextItem = watchdog.cancellableSendMessage(self.windowHandle, TVM_GETNEXTITEM, TVGN_NEXT, hItem) if nextItem <= 0: return None newID = watchdog.cancellableSendMessage(self.windowHandle, TVM_MAPHTREEITEMTOACCID, nextItem, 0) if not newID: # Tree views from comctl < 6.0 use the hItem as the child ID. newID = nextItem return IAccessible(windowHandle=self.windowHandle, IAccessibleObject=self.IAccessibleObject, IAccessibleChildID=newID)
def _getCharFormat(self,offset): oldSel=self._getSelectionOffsets() if oldSel!=(offset,offset+1): self._setSelectionOffsets(offset,offset+1) if self.obj.isWindowUnicode: charFormatStruct=CharFormat2WStruct else: charFormatStruct=CharFormat2AStruct charFormat=charFormatStruct() charFormat.cbSize=ctypes.sizeof(charFormatStruct) processHandle=self.obj.processHandle internalCharFormat=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(charFormat),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) watchdog.cancellableSendMessage(self.obj.windowHandle,EM_GETCHARFORMAT,SCF_SELECTION, internalCharFormat) winKernel.readProcessMemory(processHandle,internalCharFormat,ctypes.byref(charFormat),ctypes.sizeof(charFormat),None) finally: winKernel.virtualFreeEx(processHandle,internalCharFormat,0,winKernel.MEM_RELEASE) if oldSel!=(offset,offset+1): self._setSelectionOffsets(oldSel[0],oldSel[1]) return charFormat
def _get_positionInfo(self): if self.IAccessibleChildID==0: return super(TreeViewItem,self)._get_positionInfo() info={} info['level']=self.treeview_level hItem=self.treeview_hItem if not hItem: return info newItem=hItem index=0 while newItem>0: index+=1 newItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_PREVIOUS,newItem) newItem=hItem numItems=index-1 while newItem>0: numItems+=1 newItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_NEXT,newItem) info['indexInGroup']=index info['similarItemsInGroup']=numItems return info
def _getLineOffsets(self, offset): lineNum = self._getLineNumFromOffset(offset) start = watchdog.cancellableSendMessage(self.obj.windowHandle, winUser.EM_LINEINDEX, lineNum, 0) length = watchdog.cancellableSendMessage(self.obj.windowHandle, winUser.EM_LINELENGTH, offset, 0) end = start + length #If we just seem to get invalid line info, calculate manually if start <= 0 and end <= 0 and lineNum <= 0 and self._getLineCount( ) <= 0 and self._getStoryLength() > 0: return super(EditTextInfo, self)._getLineOffsets(offset) #Some edit controls that show both line feed and carage return can give a length not including the line feed if end <= offset: end = offset + 1 #edit controls lye about their line length limit = self._getStoryLength() while self._getLineNumFromOffset(end) == lineNum and end < limit: end += 1 return (start, end)
def _get_states(self): states=super(TreeViewItem,self)._get_states() hItem=self.treeview_hItem itemStates=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETITEMSTATE,hItem,TVIS_STATEIMAGEMASK) ch=(itemStates>>12)&3 if ch>0: states.add(controlTypes.STATE_CHECKABLE) if ch==2: states.add(controlTypes.STATE_CHECKED) elif ch==3: states.add(controlTypes.STATE_HALFCHECKED) return states
def _get__columnOrderArray(self): coa=(c_int *self.columnCount)() processHandle=self.processHandle internalCoa=winKernel.virtualAllocEx(processHandle,None,sizeof(coa),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None) res = watchdog.cancellableSendMessage(self.windowHandle,LVM_GETCOLUMNORDERARRAY, self.columnCount, internalCoa) if res: winKernel.readProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None) finally: winKernel.virtualFreeEx(processHandle,internalCoa,0,winKernel.MEM_RELEASE) return coa
def _setSelectionOffsets(self, start, end): if self.obj.editAPIVersion >= 1: charRange = CharRangeStruct() charRange.cpMin = start charRange.cpMax = end processHandle = self.obj.processHandle internalCharRange = winKernel.virtualAllocEx( processHandle, None, ctypes.sizeof(charRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalCharRange, ctypes.byref(charRange), ctypes.sizeof(charRange), None) watchdog.cancellableSendMessage(self.obj.windowHandle, EM_EXSETSEL, 0, internalCharRange) finally: winKernel.virtualFreeEx(processHandle, internalCharRange, 0, winKernel.MEM_RELEASE) else: watchdog.cancellableSendMessage(self.obj.windowHandle, EM_SETSEL, start, end) #Make sure the Window is always scrolled to the caret watchdog.cancellableSendMessage(self.obj.windowHandle, EM_SCROLLCARET, 0, 0)
def _getLineOffsets(self, offset): if watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETWRAPMODE, None, None) != SC_WRAP_NONE: # Lines in Scintilla refer to document lines, not wrapped lines. # There's no way to retrieve wrapped lines, so use screen coordinates. y = self._getPointFromOffset(offset).y location = self.obj.location start = self._getOffsetFromPoint(location.left, y) end = self._getOffsetFromPoint(location.right, y) # If this line wraps to the next line, # end is the first offset of the next line. if watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_POINTYFROMPOSITION, None, end) == y: # This is the end of the document line. # Include the EOL characters in the returned offsets. end = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_POSITIONAFTER, end, None) return (start, end) line = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_LINEFROMPOSITION, offset, 0) start = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_POSITIONFROMLINE, line, 0) end = start + watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_LINELENGTH, line, 0) return (start, end)
def _getTextRange(self, start, end): if self.obj.editAPIVersion >= 2: bufLen = ((end - start) + 1) * 2 if self.obj.isWindowUnicode: textRange = TextRangeUStruct() else: textRange = TextRangeAStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx( processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None) res = watchdog.cancellableSendMessage( self.obj.windowHandle, EM_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = (ctypes.c_byte * bufLen)() winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) if self.obj.isWindowUnicode or ( res > 1 and (buf[res] != 0 or buf[res + 1] != 0)): text = ctypes.cast(buf, ctypes.c_wchar_p).value else: text = unicode(ctypes.cast(buf, ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1]) # #4095: Some protected richEdit controls do not hide their password characters. # We do this specifically. # Note that protected standard edit controls get characters hidden in _getStoryText. if text and controlTypes.STATE_PROTECTED in self.obj.states: text = u'*' * len(text) else: text = self._getStoryText()[start:end] return text
def _getTextRange(self, start, end): bufLen = (end - start) + 1 textRange = TextRangeStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx( processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None) watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = ctypes.create_string_buffer(bufLen) winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) cp = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETCODEPAGE, 0, 0) if cp == SC_CP_UTF8: return unicode(buf.value, errors="replace", encoding="utf-8") else: return unicode(buf.value, errors="replace", encoding=locale.getlocale()[1])
def event_gainFocus(self): #See if this object is the focus and the focus is on a group item. #if so, then morph this object to a groupingItem object if self is api.getFocusObject(): groupIndex=watchdog.cancellableSendMessage(self.windowHandle,LVM_GETFOCUSEDGROUP,0,0) if groupIndex>=0: info=self.getListGroupInfo(groupIndex) if info is not None: ancestors=api.getFocusAncestors() if api.getFocusDifferenceLevel()==len(ancestors)-1: self.event_focusEntered() groupingObj=GroupingItem(windowHandle=self.windowHandle,parentNVDAObject=self,groupInfo=info) return eventHandler.queueEvent("gainFocus",groupingObj) return super(List,self).event_gainFocus()
def _get_name(self): nameList=[] imageState=watchdog.cancellableSendMessage(self.windowHandle,sysListView32.LVM_GETITEMSTATE,self.IAccessibleChildID-1,sysListView32.LVIS_STATEIMAGEMASK)>>12 if imageState==5: nameList.append(controlTypes.State.COLLAPSED.displayString) elif imageState==6: nameList.append(controlTypes.State.EXPANDED.displayString) if self.isUnread: # Translators: Displayed in outlook or live mail to indicate an email is unread nameList.append(_("unread")) name=super(MessageListItem,self).name if name: nameList.append(name) return " ".join(nameList)
def _getOffsetFromPoint(self, x, y): (left, top, width, height) = self.obj.location if self.obj.editAPIVersion >= 1: processHandle = self.obj.processHandle internalP = winKernel.virtualAllocEx(processHandle, None, ctypes.sizeof(PointLStruct), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: p = PointLStruct(x - left, y - top) winKernel.writeProcessMemory(processHandle, internalP, ctypes.byref(p), ctypes.sizeof(p), None) offset = watchdog.cancellableSendMessage( self.obj.windowHandle, EM_CHARFROMPOS, 0, internalP) finally: winKernel.virtualFreeEx(processHandle, internalP, 0, winKernel.MEM_RELEASE) else: p = (x - left) + ((y - top) << 16) offset = watchdog.cancellableSendMessage( self.obj.windowHandle, EM_CHARFROMPOS, 0, p) & 0xffff return offset
def _getPointFromOffset(self,offset): if self.obj.editAPIVersion==1 or self.obj.editAPIVersion>=3: processHandle=self.obj.processHandle internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: p=PointLStruct(0,0) winKernel.writeProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.EM_POSFROMCHAR,internalP,offset) winKernel.readProcessMemory(processHandle,internalP,ctypes.byref(p),ctypes.sizeof(p),None) finally: winKernel.virtualFreeEx(processHandle,internalP,0,winKernel.MEM_RELEASE) point=locationHelper.Point(p.x,p.y) else: res=watchdog.cancellableSendMessage(self.obj.windowHandle,winUser.EM_POSFROMCHAR,offset,None) point=locationHelper.Point(winUser.GET_X_LPARAM(res),winUser.GET_Y_LPARAM(res)) # A returned coordinate can be a negative value if # the specified character is not displayed in the edit control's client area. # If the specified index is greater than the index of the last character in the control, # the control returns -1. if point.x <0 or point.y <0: raise LookupError("Point with client coordinates x=%d, y=%d not within client area of object" % (point.x, point.y)) return point.toScreen(self.obj.windowHandle)
def onPaste (self, evt): # Simulates typing the block of text in the edit area. self.Hide() evt.Skip() config = ConfigObj(_ffIniFile, list_values = True, encoding = "utf-8") blocks = config[Catg] index=self.listBox.GetFocusedItem() name = self.listBox.GetItemText(index) paste = blocks[name] pasteStr = "\r\n".join(paste) if len(paste) >= 2: pasteStr += "\r\n" try: clipboardBackup = api.getClipData() except OSError: api.copyToClip(pasteStr) time.sleep(0.1) api.processPendingEvents(False) focus = api.getFocusObject() if focus.windowClassName == "ConsoleWindowClass": # Windows console window - Control+V doesn't work here, so using an alternative method here WM_COMMAND = 0x0111 watchdog.cancellableSendMessage(focus.windowHandle, WM_COMMAND, 0xfff1, 0) else: KeyboardInputGesture.fromName("Control+v").send() else: api.copyToClip(pasteStr) time.sleep(0.1) api.processPendingEvents(False) focus = api.getFocusObject() if focus.windowClassName == "ConsoleWindowClass": # Windows console window - Control+V doesn't work here, so using an alternative method here WM_COMMAND = 0x0111 watchdog.cancellableSendMessage(focus.windowHandle, WM_COMMAND, 0xfff1, 0) else: KeyboardInputGesture.fromName("Control+v").send() core.callLater(300, lambda: api.copyToClip(clipboardBackup))
def _getWordOffsets(self,offset): start=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDSTARTPOSITION,offset,0) end=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDENDPOSITION,start,0) if end<=offset: start=end end=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_WORDENDPOSITION,offset,0) # #8295: When calculating offsets with Scintilla messages spaces are considered to be words. # Therefore check if character at offset is a space, and if so calculate it again. if watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETCHARAT, end, 0) == space: end = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_WORDENDPOSITION, end, 0) if watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETCHARAT, start, 0) == space: start = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_WORDSTARTPOSITION, start, 0) return [start,end]
def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True): style=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_GETSTYLEAT,offset,0) if calculateOffsets: #we need to manually see how far the style goes, limit to line lineStart,lineEnd=self._getLineOffsets(offset) startOffset=offset while startOffset>lineStart: curStyle=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_GETSTYLEAT,startOffset-1,0) if curStyle==style: startOffset-=1 else: break endOffset=offset+1 while endOffset<lineEnd: curStyle=watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_GETSTYLEAT,endOffset,0) if curStyle==style: endOffset+=1 else: break else: startOffset,endOffset=(self._startOffset,self._endOffset) formatField=textInfos.FormatField() if formatConfig["reportFontName"]: #To get font name, We need to allocate memory with in Scintilla's process, and then copy it out fontNameBuf=ctypes.create_string_buffer(32) internalBuf=winKernel.virtualAllocEx(self.obj.processHandle,None,len(fontNameBuf),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_STYLEGETFONT,style, internalBuf) winKernel.readProcessMemory(self.obj.processHandle,internalBuf,fontNameBuf,len(fontNameBuf),None) finally: winKernel.virtualFreeEx(self.obj.processHandle,internalBuf,0,winKernel.MEM_RELEASE) formatField["font-name"]=fontNameBuf.value.decode("utf-8") if formatConfig["reportFontSize"]: formatField["font-size"]="%spt"%watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_STYLEGETSIZE,style,0) if formatConfig["reportLineNumber"]: formatField["line-number"]=self._getLineNumFromOffset(offset)+1 if formatConfig["reportFontAttributes"]: formatField["bold"]=bool(watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_STYLEGETBOLD,style,0)) formatField["italic"]=bool(watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_STYLEGETITALIC,style,0)) formatField["underline"]=bool(watchdog.cancellableSendMessage(self.obj.windowHandle,SCI_STYLEGETUNDERLINE,style,0)) return formatField,(startOffset,endOffset)
def _getLineOffsets(self, offset): (start, end) = super(AkelEditTextInfo, self)._getLineOffsets(offset) if end == self._getStoryLength(): return (start, end) ciChar = AECHARINDEX() processHandle = self.obj.processHandle internalCiChar = winKernel.virtualAllocEx(processHandle, None, ctypes.sizeof(ciChar), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: watchdog.cancellableSendMessage(self.obj.windowHandle, AEM_RICHOFFSETTOINDEX, offset, internalCiChar) watchdog.cancellableSendMessage(self.obj.windowHandle, AEM_GETINDEX, AEGI_NEXTLINE, internalCiChar) end = watchdog.cancellableSendMessage(self.obj.windowHandle, AEM_INDEXTORICHOFFSET, 0, internalCiChar) finally: winKernel.virtualFreeEx(processHandle, internalCiChar, 0, winKernel.MEM_RELEASE) return (start, end)
def _getLineOffsets(self,offset): if self._needsWorkAroundEncoding(): # offset in unicode chars to offset in bytes s = self._getStoryText()[0:offset] offset = len(s.encode('mbcs', 'replace')) lineNum=self._getLineNumFromOffset(offset) start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEINDEX,lineNum,0) length=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINELENGTH,offset,0) end=start+length if self._needsWorkAroundEncoding(): start_new, end_new = self._startEndInBytesToStartEndInUnicodeChars(start, end) log.debug("offset %d lineNum %d start %d length %d end %d start_new %d end_new %d" % (offset, lineNum, start, length, end, start_new, end_new)) return (start_new, end_new) #If we just seem to get invalid line info, calculate manually if start<=0 and end<=0 and lineNum<=0 and self._getLineCount()<=0 and self._getStoryLength()>0: return super(EditTextInfo,self)._getLineOffsets(offset) #Some edit controls that show both line feed and carage return can give a length not including the line feed if end<=offset: end=offset+1 #edit controls lye about their line length limit=self._getStoryLength() while self._getLineNumFromOffset(end)==lineNum and end<limit: end+=1 return (start,end)
def _getTextRange(self,start,end): if self.obj.editAPIVersion >= 2: # Calculate a buffer size that is twice the size of the text range and a NULL terminating character. # As unicode characters are two bytes in size, # this ensures that our buffer can hold both ANSI and unicode character strings. bufLen = ((end - start) + 1) * 2 # Even though this can return unicode text, we use the ANSI version of the structure. # Using the unicode structure isn't strictly necessary and saves us some confusion textRange = TextRangeStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx(processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None) # EM_GETTEXTRANGE returns the number of characters copied, # not including the terminating null character. # See https://docs.microsoft.com/en-us/windows/desktop/controls/em-gettextrange numChars = watchdog.cancellableSendMessage(self.obj.windowHandle, EM_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = ctypes.create_string_buffer(bufLen) # Copy the text in the text range to our own buffer. winKernel.readProcessMemory(processHandle,internalBuf,buf,bufLen,None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) # Find out which encoding to use to decode the bytes in the buffer. if ( # The window is unicode, the text range contains multi byte characters. self.obj.isWindowUnicode ): encoding = textUtils.WCHAR_ENCODING else: # De encoding will be determined by L{textUtils.getTextFromRawBytes} encoding = None text = textUtils.getTextFromRawBytes(buf.raw, numChars, encoding) # #4095: Some protected richEdit controls do not hide their password characters. # We do this specifically. # Note that protected standard edit controls get characters hidden in _getStoryText. if text and controlTypes.State.PROTECTED in self.obj.states: text=u'*'*len(text) else: text = super(EditTextInfo, self)._getTextRange(start, end) return text
def _getTextRange(self, start, end): if self.obj.editAPIVersion >= 2: bufLen = ((end - start) + 1) * 2 if self.obj.isWindowUnicode: textRange = TextRangeUStruct() else: textRange = TextRangeAStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx( processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None) res = watchdog.cancellableSendMessage( self.obj.windowHandle, EM_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = (ctypes.c_byte * bufLen)() winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) if self.obj.isWindowUnicode or ( res > 1 and (buf[res] != 0 or buf[res + 1] != 0)): text = ctypes.cast(buf, ctypes.c_wchar_p).value else: text = unicode(ctypes.cast(buf, ctypes.c_char_p).value, errors="replace", encoding=locale.getlocale()[1]) else: text = self._getStoryText()[start:end] return text
def _getColumnLocationRaw(self, index): processHandle = self.processHandle # LVM_GETSUBITEMRECT requires a pointer to a RECT structure that will receive the subitem bounding rectangle information. localRect = RECT( # Returns the bounding rectangle of the entire item, including the icon and label. left=LVIR_LABEL, # According to Microsoft, top should be the one-based index of the subitem. # However, indexes coming from LVM_GETCOLUMNORDERARRAY are zero based. top=index) internalRect = winKernel.virtualAllocEx(processHandle, None, sizeof(localRect), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalRect, byref(localRect), sizeof(localRect), None) res = watchdog.cancellableSendMessage(self.windowHandle, LVM_GETSUBITEMRECT, self.IAccessibleChildID - 1, internalRect) if res: winKernel.readProcessMemory(processHandle, internalRect, ctypes.byref(localRect), ctypes.sizeof(localRect), None) finally: winKernel.virtualFreeEx(processHandle, internalRect, 0, winKernel.MEM_RELEASE) if res == 0: log.debugWarning( f"LVM_GETSUBITEMRECT failed for index {index} in list") return None # #8268: this might be a malformed rectangle # (i.e. with a left coordinate that is greater than the right coordinate). # This happens in Becky! Internet Mail, # as well in applications that expose zero width columns. left = localRect.left top = localRect.top right = localRect.right bottom = localRect.bottom if left > right: left = right if top > bottom: top = bottom return RectLTRB(left, top, right, bottom).toScreen(self.windowHandle).toLTWH()
def _getColumnContentRawOutProc(self, index: int) -> Optional[str]: """Retrieves text for a given column. Note that this method operates out of process and has to reserve memory inside a given application. As a consequence it may fail when reserved memory is above the range available for 32-bit processes. Use only when in process injection is not possible. """ buffer = None processHandle = self.processHandle internalItem = winKernel.virtualAllocEx(processHandle, None, sizeof(self.LVITEM), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: internalText = winKernel.virtualAllocEx(processHandle, None, CBEMAXSTRLEN * 2, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: item = self.LVITEM(iItem=self.IAccessibleChildID - 1, mask=LVIF_TEXT | LVIF_COLUMNS, iSubItem=index, pszText=internalText, cchTextMax=CBEMAXSTRLEN) winKernel.writeProcessMemory(processHandle, internalItem, byref(item), sizeof(self.LVITEM), None) len = watchdog.cancellableSendMessage( self.windowHandle, LVM_GETITEMTEXTW, (self.IAccessibleChildID - 1), internalItem) if len: winKernel.readProcessMemory(processHandle, internalItem, byref(item), sizeof(self.LVITEM), None) buffer = create_unicode_buffer(len) winKernel.readProcessMemory(processHandle, item.pszText, buffer, sizeof(buffer), None) finally: winKernel.virtualFreeEx(processHandle, internalText, 0, winKernel.MEM_RELEASE) finally: winKernel.virtualFreeEx(processHandle, internalItem, 0, winKernel.MEM_RELEASE) return buffer.value if buffer else None
def _getColumnOrderArrayRawOutProc(self, columnCount: int) -> Optional[ctypes.Array]: coa = (ctypes.c_int * columnCount)() processHandle=self.processHandle internalCoa=winKernel.virtualAllocEx(processHandle,None,sizeof(coa),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None) res = watchdog.cancellableSendMessage( self.windowHandle, LVM_GETCOLUMNORDERARRAY, columnCount, internalCoa ) if res: winKernel.readProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None) else: log.debugWarning("LVM_GETCOLUMNORDERARRAY failed for list") finally: winKernel.virtualFreeEx(processHandle,internalCoa,0,winKernel.MEM_RELEASE) return coa
def _getColumnHeaderRaw(self,index): buffer=None processHandle=self.processHandle internalColumn=winKernel.virtualAllocEx(processHandle,None,sizeof(self.LVCOLUMN),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: internalText=winKernel.virtualAllocEx(processHandle,None,CBEMAXSTRLEN*2,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: column=self.LVCOLUMN(mask=LVCF_TEXT,iSubItem=index,pszText=internalText,cchTextMax=CBEMAXSTRLEN) winKernel.writeProcessMemory(processHandle,internalColumn,byref(column),sizeof(self.LVCOLUMN),None) res = watchdog.cancellableSendMessage(self.windowHandle,LVM_GETCOLUMNW, index, internalColumn) if res: winKernel.readProcessMemory(processHandle,internalColumn,byref(column),sizeof(self.LVCOLUMN),None) buffer=create_unicode_buffer(column.cchTextMax) winKernel.readProcessMemory(processHandle,column.pszText,buffer,sizeof(buffer),None) finally: winKernel.virtualFreeEx(processHandle,internalText,0,winKernel.MEM_RELEASE) finally: winKernel.virtualFreeEx(processHandle,internalColumn,0,winKernel.MEM_RELEASE) return buffer.value if buffer else None
def _getColumnContentRaw(self, index): buffer=None processHandle=self.processHandle internalItem=winKernel.virtualAllocEx(processHandle,None,sizeof(self.LVITEM),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: internalText=winKernel.virtualAllocEx(processHandle,None,CBEMAXSTRLEN*2,winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE) try: item=self.LVITEM(iItem=self.IAccessibleChildID-1,mask=LVIF_TEXT|LVIF_COLUMNS,iSubItem=index,pszText=internalText,cchTextMax=CBEMAXSTRLEN) winKernel.writeProcessMemory(processHandle,internalItem,byref(item),sizeof(self.LVITEM),None) len = watchdog.cancellableSendMessage(self.windowHandle,LVM_GETITEMTEXTW, (self.IAccessibleChildID-1), internalItem) if len: winKernel.readProcessMemory(processHandle,internalItem,byref(item),sizeof(self.LVITEM),None) buffer=create_unicode_buffer(len) winKernel.readProcessMemory(processHandle,item.pszText,buffer,sizeof(buffer),None) finally: winKernel.virtualFreeEx(processHandle,internalText,0,winKernel.MEM_RELEASE) finally: winKernel.virtualFreeEx(processHandle,internalItem,0,winKernel.MEM_RELEASE) return buffer.value if buffer else None
def _getColumnHeaderRawOutProc(self, index: int) -> Optional[str]: """Retrieves text of the header for the given column. Note that this method operates out of process and has to reserve memory inside a given application. As a consequence it may fail when reserved memory is above the range available for 32-bit processes. Use only when in process injection is not possible. """ buffer = None processHandle = self.processHandle internalColumn = winKernel.virtualAllocEx(processHandle, None, sizeof(self.LVCOLUMN), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: internalText = winKernel.virtualAllocEx(processHandle, None, CBEMAXSTRLEN * 2, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: column = self.LVCOLUMN(mask=LVCF_TEXT, iSubItem=index, pszText=internalText, cchTextMax=CBEMAXSTRLEN) winKernel.writeProcessMemory(processHandle, internalColumn, byref(column), sizeof(self.LVCOLUMN), None) res = watchdog.cancellableSendMessage(self.windowHandle, LVM_GETCOLUMNW, index, internalColumn) if res: winKernel.readProcessMemory(processHandle, internalColumn, byref(column), sizeof(self.LVCOLUMN), None) buffer = create_unicode_buffer(column.cchTextMax) winKernel.readProcessMemory(processHandle, column.pszText, buffer, sizeof(buffer), None) finally: winKernel.virtualFreeEx(processHandle, internalText, 0, winKernel.MEM_RELEASE) finally: winKernel.virtualFreeEx(processHandle, internalColumn, 0, winKernel.MEM_RELEASE) return buffer.value if buffer else None
def _getTextRange(self,start,end): bufLen = (end - start) + 1 textRange = TextRangeStruct() textRange.chrg.cpMin = start textRange.chrg.cpMax = end processHandle = self.obj.processHandle internalBuf = winKernel.virtualAllocEx(processHandle, None, bufLen, winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: textRange.lpstrText = internalBuf internalTextRange = winKernel.virtualAllocEx(processHandle, None, ctypes.sizeof(textRange), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalTextRange, ctypes.byref(textRange), ctypes.sizeof(textRange), None) numBytes = watchdog.cancellableSendMessage(self.obj.windowHandle, SCI_GETTEXTRANGE, 0, internalTextRange) finally: winKernel.virtualFreeEx(processHandle, internalTextRange, 0, winKernel.MEM_RELEASE) buf = ctypes.create_string_buffer(bufLen) winKernel.readProcessMemory(processHandle, internalBuf, buf, bufLen, None) finally: winKernel.virtualFreeEx(processHandle, internalBuf, 0, winKernel.MEM_RELEASE) return textUtils.getTextFromRawBytes(buf.raw, numChars=numBytes, encoding=self.encoding, errorsFallback="surrogateescape")
def _getColumnLocationRawOutProc(self, index: int) -> ctypes.wintypes.RECT: """Retrieves rectangle containing coordinates for a given column. Note that this method operates out of process and has to reserve memory inside a given application. As a consequence it may fail when reserved memory is above the range available for 32-bit processes. Use only when in process injection is not possible. """ processHandle = self.processHandle # LVM_GETSUBITEMRECT requires a pointer to a RECT structure that will receive the subitem bounding rectangle information. localRect = RECT( # Returns the bounding rectangle of the entire item, including the icon and label. left=LVIR_LABEL, # According to Microsoft, top should be the one-based index of the subitem. # However, indexes coming from LVM_GETCOLUMNORDERARRAY are zero based. top=index) internalRect = winKernel.virtualAllocEx(processHandle, None, sizeof(localRect), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalRect, byref(localRect), sizeof(localRect), None) res = watchdog.cancellableSendMessage(self.windowHandle, LVM_GETSUBITEMRECT, self.IAccessibleChildID - 1, internalRect) if res: winKernel.readProcessMemory(processHandle, internalRect, ctypes.byref(localRect), ctypes.sizeof(localRect), None) finally: winKernel.virtualFreeEx(processHandle, internalRect, 0, winKernel.MEM_RELEASE) if res == 0: log.debugWarning( f"LVM_GETSUBITEMRECT failed for index {index} in list") return None return localRect
def _getColumnOrderArrayRawOutProc( self, columnCount: int) -> Optional[ctypes.Array]: """Retrieves a list of column indexes for a given list control. See `_getColumnOrderArrayRaw` for more comments. Note that this method operates out of process and has to reserve memory inside a given application. As a consequence it may fail when reserved memory is above the range available for 32-bit processes. Use only when in process injection is not possible. """ coa = (ctypes.c_int * columnCount)() processHandle = self.processHandle internalCoa = winKernel.virtualAllocEx(processHandle, None, sizeof(coa), winKernel.MEM_COMMIT, winKernel.PAGE_READWRITE) try: winKernel.writeProcessMemory(processHandle, internalCoa, byref(coa), sizeof(coa), None) # The meaning of the return value depends on the message sent, for LVM_GETCOLUMNORDERARRAY, # it returns nonzero if successful, or 0 otherwise. # https://docs.microsoft.com/en-us/windows/win32/controls/lvm-getcolumnorderarray#return-value res = watchdog.cancellableSendMessage(self.windowHandle, LVM_GETCOLUMNORDERARRAY, columnCount, internalCoa) if res: winKernel.readProcessMemory(processHandle, internalCoa, byref(coa), sizeof(coa), None) else: coa = None log.debugWarning( f"LVM_GETCOLUMNORDERARRAY failed for list. " f"Windows Error: {ctypes.GetLastError()}, Handle: {self.windowHandle}" ) finally: winKernel.virtualFreeEx(processHandle, internalCoa, 0, winKernel.MEM_RELEASE) return coa