def _getCaretOffset(self): caretRect=getCaretRect(self.obj) objLocation=self.obj.location objRect=RECT(objLocation[0],objLocation[1],objLocation[0]+objLocation[2],objLocation[1]+objLocation[3]) objRect.left,objRect.top=windowUtils.physicalToLogicalPoint( self.obj.windowHandle,objRect.left,objRect.top) objRect.right,objRect.bottom=windowUtils.physicalToLogicalPoint( self.obj.windowHandle,objRect.right,objRect.bottom) caretRect.left=max(objRect.left,caretRect.left) caretRect.top=max(objRect.top,caretRect.top) caretRect.right=min(objRect.right,caretRect.right) caretRect.bottom=min(objRect.bottom,caretRect.bottom) # Find a character offset where the caret overlaps vertically, overlaps horizontally, overlaps the baseline and is totally within or on the correct side for the reading order try: return self._findCaretOffsetFromLocation(caretRect,validateBaseline=True,validateDirection=True) except LookupError: pass # Find a character offset where the caret overlaps vertically, overlaps horizontally, overlaps the baseline, but does not care about reading order (probably whitespace at beginning or end of a line) try: return self._findCaretOffsetFromLocation(caretRect,validateBaseline=True,validateDirection=False) except LookupError: pass # Find a character offset where the caret overlaps vertically, overlaps horizontally, but does not care about baseline or reading order (probably vertical whitespace -- blank lines) try: return self._findCaretOffsetFromLocation(caretRect,validateBaseline=False,validateDirection=False) except LookupError: raise RuntimeError
def _get__storyFieldsAndRects(self): # All returned coordinates are logical coordinates. if self._location: left, top, right, bottom = self._location else: try: left, top, width, height = self.obj.location except TypeError: # No location; nothing we can do. return [],[],[] right = left + width bottom = top + height bindingHandle=self.obj.appModule.helperLocalBindingHandle if not bindingHandle: log.debugWarning("AppModule does not have a binding handle") return [],[],[] left,top=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,left,top) right,bottom=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,right,bottom) text,rects=getWindowTextInRect(bindingHandle, self.obj.windowHandle, left, top, right, bottom, self.minHorizontalWhitespace, self.minVerticalWhitespace,self.stripOuterWhitespace,self.includeDescendantWindows) if not text: return [],[],[] text="<control>%s</control>"%text commandList=XMLFormatting.XMLTextParser().parse(text) curFormatField=None lastEndOffset=0 lineStartOffset=0 lineStartIndex=0 lineBaseline=None lineEndOffsets=[] for index in range(len(commandList)): item=commandList[index] if isinstance(item,str): lastEndOffset += textUtils.WideStringOffsetConverter(item).wideStringLength elif isinstance(item,textInfos.FieldCommand): if isinstance(item.field,textInfos.FormatField): curFormatField=item.field self._normalizeFormatField(curFormatField) else: curFormatField=None baseline=curFormatField['baseline'] if curFormatField else None if baseline!=lineBaseline: if lineBaseline is not None: processWindowChunksInLine(commandList,rects,lineStartIndex,lineStartOffset,index,lastEndOffset) #Convert the whitespace at the end of the line into a line feed item=commandList[index-1] if ( isinstance(item,str) # Since we're searching for white space, it is safe to # do this opperation on the length of the pythonic string and len(item)==1 and item.isspace() ): commandList[index-1]=u'\n' lineEndOffsets.append(lastEndOffset) if baseline is not None: lineStartIndex=index lineStartOffset=lastEndOffset lineBaseline=baseline return commandList,rects,lineEndOffsets
def physicalRectToLogicalLocation(hwnd, rect, margin=15): if physicalToLogicalPoint: left, top = physicalToLogicalPoint(hwnd, rect.left - margin, rect.top - margin) right, bottom = physicalToLogicalPoint(hwnd, rect.right + margin, rect.bottom + margin) return left, top, right - left, bottom - top return ((rect.left - margin), (rect.top - margin), (rect.right - rect.left + margin * 2), (rect.bottom - rect.top + margin * 2))
def physicalRectToLogicalLocation(hwnd, rect, margin=15): if physicalToLogicalPoint: left, top = physicalToLogicalPoint(hwnd, rect.left - margin, rect.top - margin) right, bottom = physicalToLogicalPoint(hwnd, rect.right + margin, rect.bottom + margin) return left, top, right - left, bottom - top return ( (rect.left - margin), (rect.top - margin), (rect.right - rect.left + margin * 2), (rect.bottom - rect.top + margin * 2) )
def _get__storyFieldsAndRects(self): # All returned coordinates are logical coordinates. if self._location: left, top, right, bottom = self._location else: try: left, top, width, height = self.obj.location except TypeError: # No location; nothing we can do. return [],[],[] right = left + width bottom = top + height bindingHandle=self.obj.appModule.helperLocalBindingHandle if not bindingHandle: log.debugWarning("AppModule does not have a binding handle") return [],[],[] left,top=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,left,top) right,bottom=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,right,bottom) text,rects=getWindowTextInRect(bindingHandle, self.obj.windowHandle, left, top, right, bottom, self.minHorizontalWhitespace, self.minVerticalWhitespace,self.stripOuterWhitespace,self.includeDescendantWindows) if not text: return [],[],[] text="<control>%s</control>"%text commandList=XMLFormatting.XMLTextParser().parse(text) curFormatField=None lastEndOffset=0 lineStartOffset=0 lineStartIndex=0 lineBaseline=None lineEndOffsets=[] for index in xrange(len(commandList)): item=commandList[index] if isinstance(item,basestring): lastEndOffset+=len(item) elif isinstance(item,textInfos.FieldCommand): if isinstance(item.field,textInfos.FormatField): curFormatField=item.field self._normalizeFormatField(curFormatField) else: curFormatField=None baseline=curFormatField['baseline'] if curFormatField else None if baseline!=lineBaseline: if lineBaseline is not None: processWindowChunksInLine(commandList,rects,lineStartIndex,lineStartOffset,index,lastEndOffset) #Convert the whitespace at the end of the line into a line feed item=commandList[index-1] if isinstance(item,basestring) and len(item)==1 and item.isspace(): commandList[index-1]=u'\n' lineEndOffsets.append(lastEndOffset) if baseline is not None: lineStartIndex=index lineStartOffset=lastEndOffset lineBaseline=baseline return commandList,rects,lineEndOffsets
def _getOffsetFromPoint(self, x, y): # Accepts physical coordinates. x,y=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,x,y) for charOffset, (charLeft, charTop, charRight, charBottom) in enumerate(self._storyFieldsAndRects[1]): if charLeft<=x<charRight and charTop<=y<charBottom: return charOffset raise LookupError
def _getClosestOffsetFromPoint(self,x,y): # Accepts physical coordinates. x,y=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,x,y) #Enumerate the character rectangles a=enumerate(self._storyFieldsAndRects[1]) #Convert calculate center points for all the rectangles b=((charOffset,(charLeft+(charRight-charLeft)/2,charTop+(charBottom-charTop)/2)) for charOffset,(charLeft,charTop,charRight,charBottom) in a) #Calculate distances from all center points to the given x and y #But place the distance before the character offset, to make sorting by distance easier c=((math.sqrt(abs(x-cx)**2+abs(y-cy)**2),charOffset) for charOffset,(cx,cy) in b) #produce a static list of distances and character offsets, sorted by distance d=sorted(c) #Return the lowest offset with the shortest distance return d[0][1] if len(d)>0 else 0
def _getClosestOffsetFromPoint(self, x, y): # Accepts physical coordinates. try: x, y = windowUtils.physicalToLogicalPoint(self.obj.windowHandle, x, y) except RuntimeError: raise LookupError("physicalToLogicalPoint failed") #Enumerate the character rectangles a = enumerate(self._storyFieldsAndRects[1]) #Convert calculate center points for all the rectangles b = ((charOffset, rect.center) for charOffset, rect in a) # Calculate distances from all center points to the given x and y # But place the distance before the character offset, to make sorting by distance easier c = ((math.sqrt(abs(x - center.x)**2 + abs(y - center.y)**2), charOffset) for charOffset, center in b) #produce a static list of distances and character offsets, sorted by distance d = sorted(c) #Return the lowest offset with the shortest distance return d[0][1] if len(d) > 0 else 0
def toLogical(self, hwnd): """Converts self from physical to logical coordinates and returns a new L{Point}.""" return Point(*windowUtils.physicalToLogicalPoint(hwnd, *self))