inputComposition.py
5.34 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import eventHandler
import queueHandler
import controlTypes
import characterProcessing
import speech
import config
from NVDAObjects.window import Window
from behaviors import EditableTextWithAutoSelectDetection, CandidateItem as CandidateItemBehavior
from textInfos.offsets import OffsetsTextInfo
def calculateInsertedChars(oldComp,newComp):
oldLen=len(oldComp)
newLen=len(newComp)
minLen=min(oldLen,newLen)
diffStart=0
diffEnd=newLen
for index in xrange(minLen):
if newComp[index]!=oldComp[index]:
break
diffStart=index+1
for index in xrange(minLen,0,-1):
backIndex=index-minLen-1
if newComp[backIndex]!=oldComp[backIndex]:
break
diffEnd=newLen+backIndex
diffEnd=max(diffEnd,diffStart+(newLen-oldLen))
return newComp[diffStart:diffEnd]
class InputCompositionTextInfo(OffsetsTextInfo):
def _getSelectionOffsets(self):
return self.obj.readingSelectionOffsets if self.obj.isReading else self.obj.compositionSelectionOffsets
def _getCaretOffset(self):
return self._getSelectionOffsets()[0]
def _getStoryText(self):
return self.obj.readingString if self.obj.isReading else self.obj.compositionString
def _getStoryLength(self):
return len(self._getStoryText())
class InputComposition(EditableTextWithAutoSelectDetection,Window):
TextInfo=InputCompositionTextInfo
# Translators: The label for a 'composition' Window that appears when the user is typing one or more east-Asian characters into a document.
name=_("Composition")
role=controlTypes.ROLE_EDITABLETEXT
next=None
previous=None
firstChild=None
lastChild=None
states=set()
location=None
compositionString=""
readingString=""
compositionSelectionOffsets=(0,0)
readingSelectionOffsets=(0,0)
isReading=False
def __init__(self,parent=None):
self.parent=parent
super(InputComposition,self).__init__(windowHandle=parent.windowHandle)
def findOverlayClasses(self,clsList):
clsList.append(InputComposition)
clsList.append(InputComposition)
return clsList
def reportNewText(self,oldString,newString):
if (config.conf["keyboard"]["speakTypedCharacters"] or config.conf["keyboard"]["speakTypedWords"]):
newText=calculateInsertedChars(oldString.strip(u'\u3000'),newString.strip(u'\u3000'))
if newText:
queueHandler.queueFunction(queueHandler.eventQueue,speech.speakText,newText,symbolLevel=characterProcessing.SYMLVL_ALL)
def compositionUpdate(self,compositionString,selectionStart,selectionEnd,isReading,announce=True):
if isReading and not config.conf["inputComposition"]["reportReadingStringChanges"]: return
if not isReading and not config.conf["inputComposition"]["reportCompositionStringChanges"]: return
if announce: self.reportNewText((self.readingString if isReading else self.compositionString),compositionString)
hasChanged=False
if isReading:
self.readingString=compositionString
self.readingSelectionOffsets=(selectionStart,selectionEnd)
self.isReading=True
hasChanged=True
elif compositionString!=self.compositionString or (selectionStart,selectionEnd)!=self.compositionSelectionOffsets:
self.readingString=""
self.readingSelectionOffsets=(0,0)
self.isReading=False
self.compositionString=compositionString
self.compositionSelectionOffsets=(selectionStart,selectionEnd)
hasChanged=True
if hasChanged:
eventHandler.queueEvent("valueChange",self)
eventHandler.queueEvent("caret",self)
def reportFocus(self):
pass
class CandidateList(Window):
# Translators: The label for a 'candidate' list that shows a choice of symbols a user can choose from when typing east-Asian characters into a document.
name=_("Candidate")
role=controlTypes.ROLE_LIST
next=None
previous=None
firstChild=None
lastChild=None
states=set()
def __init__(self,parent=None):
self.parent=parent
super(CandidateList,self).__init__(windowHandle=parent.windowHandle)
def findOverlayClasses(self,clsList):
clsList.append(CandidateList)
return clsList
class CandidateItem(CandidateItemBehavior,Window):
role=controlTypes.ROLE_LISTITEM
firstChild=None
lastChild=None
states=set()
def __init__(self,parent=None,candidateStrings=[],candidateIndex=0,inputMethod=None):
self.parent=parent
self.candidateStrings=candidateStrings
self.candidateIndex=candidateIndex
self.inputMethod=inputMethod
super(CandidateItem,self).__init__(windowHandle=parent.windowHandle)
def findOverlayClasses(self,clsList):
clsList.append(CandidateItem)
return clsList
def _get_candidateNumber(self):
number=self.candidateIndex
#Most candidate lists start at 1, except for Boshiami which starts at 0.
if self.inputMethod!="LIUNT.IME":
number+=1
return number
def _get_name(self):
number=self.candidateNumber
candidate=self.candidateStrings[self.candidateIndex]
return self.getFormattedCandidateName(number,candidate)
def _get_basicText(self):
return self.candidateStrings[self.candidateIndex]
def _get_description(self):
candidate=self.candidateStrings[self.candidateIndex]
return self.getFormattedCandidateDescription(candidate)
def _get_next(self):
if self.candidateIndex<(len(self.candidateStrings)-1):
return CandidateItem(parent=self.parent,candidateStrings=self.candidateStrings,candidateIndex=self.candidateIndex+1,inputMethod=self.inputMethod)
def _get_previous(self):
if self.candidateIndex>0:
return CandidateItem(parent=self.parent,candidateStrings=self.candidateStrings,candidateIndex=self.candidateIndex-1,inputMethod=self.inputMethod)