NVDA with Japanese branch
Révision | 3dfccae8115ce0c927f518bdb7704a84b70408c5 (tree) |
---|---|
l'heure | 2014-03-05 14:18:24 |
Auteur | Takuya Nishimoto <nishimotz@gmai...> |
Commiter | Takuya Nishimoto |
Merge branch 'jpnext' into jp2014.1
@@ -419,10 +419,31 @@ class EditTextInfo(textInfos.offsets.OffsetsTextInfo): | ||
419 | 419 | return watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEFROMCHAR,offset,0) |
420 | 420 | |
421 | 421 | def _getLineOffsets(self,offset): |
422 | + if not self.obj.isWindowUnicode: | |
423 | + # offset in unicode chars to offset in bytes | |
424 | + s = self._getStoryText()[0:offset] | |
425 | + offset = len(s.encode('mbcs', 'replace')) | |
422 | 426 | lineNum=self._getLineNumFromOffset(offset) |
423 | 427 | start=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINEINDEX,lineNum,0) |
424 | 428 | length=watchdog.cancellableSendMessage(self.obj.windowHandle,EM_LINELENGTH,offset,0) |
425 | 429 | end=start+length |
430 | + if not self.obj.isWindowUnicode: | |
431 | + # start/end in bytes to start/end in unicode chars | |
432 | + story_text = self._getStoryText() | |
433 | + start_new = end_new = -1 | |
434 | + bytepos = 0 | |
435 | + for charpos, ch in enumerate(story_text): | |
436 | + cb = len(ch.encode('mbcs', 'replace')) | |
437 | + if bytepos == start: | |
438 | + start_new = charpos | |
439 | + if bytepos == end: | |
440 | + end_new = charpos | |
441 | + break | |
442 | + bytepos += cb | |
443 | + if end_new == -1: | |
444 | + end_new = len(story_text) | |
445 | + 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)) | |
446 | + return (start_new, end_new) | |
426 | 447 | #If we just seem to get invalid line info, calculate manually |
427 | 448 | if start<=0 and end<=0 and lineNum<=0 and self._getLineCount()<=0 and self._getStoryLength()>0: |
428 | 449 | return super(EditTextInfo,self)._getLineOffsets(offset) |
@@ -118,6 +118,55 @@ UIAEventIdsToNVDAEventNames={ | ||
118 | 118 | #UIA_ToolTipClosedEventId:"hide", |
119 | 119 | } |
120 | 120 | |
121 | +class MsaaProxyFactory(COMObject): | |
122 | + """Overrides the default MSAA proxy so it only handles windows for which NVDA uses UIA. | |
123 | + Generally, the MSAA proxy isn't needed, as NVDA uses MSAA directly, | |
124 | + so UIA proxying is redundant. | |
125 | + However, some native UIA implementations depend on the MSAA proxy. | |
126 | + """ | |
127 | + _com_interfaces_ = [IUIAutomationProxyFactoryEntry, IUIAutomationProxyFactory] | |
128 | + | |
129 | + def __init__(self, baseEntry): | |
130 | + self.baseEntry = baseEntry | |
131 | + self.baseFactory = baseEntry.ProxyFactory | |
132 | + super(MsaaProxyFactory, self).__init__() | |
133 | + self.factory = self.QueryInterface(IUIAutomationProxyFactory) | |
134 | + | |
135 | + # Forward most methods. | |
136 | + def IUIAutomationProxyFactoryEntry__get_AllowSubstringMatch(self): | |
137 | + return self.baseEntry.AllowSubstringMatch | |
138 | + def IUIAutomationProxyFactoryEntry__get_CanCheckBaseClass(self): | |
139 | + return self.baseEntry.CanCheckBaseClass | |
140 | + def IUIAutomationProxyFactoryEntry__get_ClassName(self): | |
141 | + return self.baseEntry.ClassName | |
142 | + def IUIAutomationProxyFactoryEntry__get_ImageName(self): | |
143 | + return self.baseEntry.ImageName | |
144 | + def IUIAutomationProxyFactoryEntry__get_NeedsAdviseEvents(self): | |
145 | + return self.baseEntry.NeedsAdviseEvents | |
146 | + | |
147 | + def IUIAutomationProxyFactoryEntry_GetWinEventsForAutomationEvent(self, eventId, propertyId): | |
148 | + try: | |
149 | + return self.baseEntry.GetWinEventsForAutomationEvent(eventId, propertyId) | |
150 | + except IndexError: | |
151 | + # comtypes can't seem to handle a NULL safearray pointer. | |
152 | + return () | |
153 | + | |
154 | + def IUIAutomationProxyFactoryEntry__get_ProxyFactory(self): | |
155 | + return self.factory | |
156 | + | |
157 | + def IUIAutomationProxyFactory__get_ProxyFactoryId(self): | |
158 | + return u"NVDA: MSAA Proxy" | |
159 | + | |
160 | + def IUIAutomationProxyFactory_CreateProvider(self, hwnd, idObject, idChild): | |
161 | + from UIAHandler import handler | |
162 | + if not handler: | |
163 | + # Still initialising. | |
164 | + return None | |
165 | + if not handler.isUIAWindow(hwnd): | |
166 | + # NVDA won't use UIA for this window at all, so don't proxy for it. | |
167 | + return None | |
168 | + return self.baseFactory.CreateProvider(hwnd, idObject, idChild) | |
169 | + | |
121 | 170 | class UIAHandler(COMObject): |
122 | 171 | _com_interfaces_=[IUIAutomationEventHandler,IUIAutomationFocusChangedEventHandler,IUIAutomationPropertyChangedEventHandler] |
123 | 172 |
@@ -142,10 +191,27 @@ class UIAHandler(COMObject): | ||
142 | 191 | windll.kernel32.CloseHandle(MTAThreadHandle) |
143 | 192 | del self.MTAThread |
144 | 193 | |
194 | + def setUIAProxies(self): | |
195 | + neededProxyIDs={'Microsoft: TreeView Proxy'} | |
196 | + mapping=self.clientObject.proxyFactoryMapping | |
197 | + msaaEntry = None | |
198 | + for index in reversed(xrange(mapping.count)): | |
199 | + entry=mapping.getEntry(index) | |
200 | + pfId = entry.proxyFactory.proxyFactoryId | |
201 | + if pfId=="Microsoft: MSAA Proxy": | |
202 | + msaaEntry = entry | |
203 | + if pfId not in neededProxyIDs: | |
204 | + mapping.removeEntry(index) | |
205 | + | |
206 | + if not msaaEntry: | |
207 | + return | |
208 | + mapping.InsertEntry(mapping.Count, MsaaProxyFactory(msaaEntry)) | |
209 | + | |
145 | 210 | def MTAThreadFunc(self): |
146 | 211 | try: |
147 | 212 | oledll.ole32.CoInitializeEx(None,comtypes.COINIT_MULTITHREADED) |
148 | 213 | self.clientObject=CoCreateInstance(CUIAutomation._reg_clsid_,interface=IUIAutomation,clsctx=CLSCTX_INPROC_SERVER) |
214 | + self.setUIAProxies() | |
149 | 215 | self.windowTreeWalker=self.clientObject.createTreeWalker(self.clientObject.CreateNotCondition(self.clientObject.CreatePropertyCondition(UIA_NativeWindowHandlePropertyId,0))) |
150 | 216 | self.windowCacheRequest=self.clientObject.CreateCacheRequest() |
151 | 217 | self.windowCacheRequest.AddProperty(UIA_NativeWindowHandlePropertyId) |