#A part of NonVisual Desktop Access (NVDA) #Copyright (C) 2006-2008 NVDA Contributors #This file is covered by the GNU General Public License. #See the file COPYING for more details. import edit import winUser import winKernel import ctypes import watchdog # Messages AEM_GETINDEX =(winUser.WM_USER + 2106) AEM_CHARFROMPOS =(winUser.WM_USER + 2151) AEM_POSFROMCHAR =(winUser.WM_USER + 2152) AEM_INDEXTORICHOFFSET =(winUser.WM_USER + 2112) AEM_RICHOFFSETTOINDEX =(winUser.WM_USER + 2113) AEM_CONTROLVERSION =(winUser.WM_USER + 2200) #AEM_GETINDEX flags AEGI_LASTCHAR =2 AEGI_CARETCHAR =5 AEGI_NEXTLINE =24 #Structures class AELINEDATA(ctypes.Structure): pass AELINEDATA._fields_=[ ('next',ctypes.POINTER(AELINEDATA)), ('prev',ctypes.POINTER(AELINEDATA)), ('wpLine',ctypes.c_wchar), ('nLineLen',ctypes.c_int), ('nLineBreak',ctypes.c_int), ('nLineWidth',ctypes.c_int), ('nSelStart',ctypes.c_int), ('nSelEnd',ctypes.c_int), ] class AECHARINDEX(ctypes.Structure): _fields_=[ ('nLine',ctypes.c_int), ('lpLine',AELINEDATA), ('nCharInLine',ctypes.c_int), ] class AkelEditTextInfo(edit.EditTextInfo): 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 _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 _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) class AkelEdit(edit.RichEdit20): TextInfo=AkelEditTextInfo def initOverlayClass(self): global AEGI_NEXTLINE version=self._getControlVersion() if version <1.6: AEGI_NEXTLINE =8 else: AEGI_NEXTLINE =24 for gesture in ("kb:control+upArrow", "kb:control+downArrow"): self.bindGesture(gesture, "caret_moveByLine") def _getControlVersion(self): res=watchdog.cancellableSendMessage(self.windowHandle,AEM_CONTROLVERSION,None,None) major=winUser.LOBYTE(winUser.LOWORD(res)) minor=winUser.HIBYTE(winUser.LOWORD(res)) version=major+(0.1*minor) return version