akelEdit.py
3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2006-2008 NVDA Contributors <http://www.nvda-project.org/>
#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