def _reportErrorInPreviousWord(self): try: # self might be a descendant of the text control; e.g. Symphony. # We want to deal with the entire text, so use the caret object. info = api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) # This gets called for characters which might end a word; e.g. space. # The character before the caret is the word end. # The one before that is the last of the word, which is what we want. info.move(textInfos.UNIT_CHARACTER, -2) info.expand(textInfos.UNIT_CHARACTER) fields = info.getTextWithFields() except RuntimeError: return except: # Focus probably moved. log.debugWarning("Error fetching last character of previous word", exc_info=True) return for command in fields: if isinstance(command, textInfos.FieldCommand) and command.command == "formatChange" and command.field.get("invalid-spelling"): break else: # No error. return import nvwave nvwave.playWaveFile(r"waves\textError.wav")
def getCaretRect(obj: Optional[TextContainerObject] = None) -> locationHelper.RectLTRB: if obj is None: obj = api.getCaretObject() if api.isObjectInActiveTreeInterceptor(obj): obj = obj.treeInterceptor if api.isNVDAObject(obj): # Import late to avoid circular import from displayModel import getCaretRect # Check whether there is a caret in the window. # Note that, even windows that don't have navigable text could have a caret, such as in Excel. try: return locationHelper.RectLTRB.fromCompatibleType(getCaretRect(obj)) except RuntimeError: if not obj._hasNavigableText: raise LookupError try: caretInfo = obj.makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): # Try a selection try: caretInfo = obj.makeTextInfo(textInfos.POSITION_SELECTION) except (NotImplementedError, RuntimeError): # There is nothing to do here raise LookupError return getRectFromTextInfo(caretInfo)
def updateNamespaceSnapshotVars(self): """Update the console namespace with a snapshot of NVDA's current state. This creates/updates variables for the current focus, navigator object, etc. Typically, used before the NVDA python console is opened, after which, calls to the 'api' module will refer to this new focus. """ try: caretPos = api.getCaretPosition() except RuntimeError: log.debug( "Unable to set caretPos snapshot variable for python console.") caretPos = None self._namespaceSnapshotVars = { "focus": api.getFocusObject(), # Copy the focus ancestor list, as it gets mutated once it is replaced in api.setFocusObject. "focusAnc": list(api.getFocusAncestors()), "fdl": api.getFocusDifferenceLevel(), "fg": api.getForegroundObject(), "nav": api.getNavigatorObject(), "caretObj": api.getCaretObject(), "caretPos": caretPos, "review": api.getReviewPosition(), "mouse": api.getMouseObject(), "brlRegions": braille.handler.buffer.regions, } self.namespace.update(self._namespaceSnapshotVars)
def getSelectedText(self): obj = api.getCaretObject() try: info = obj.makeTextInfo(textInfos.POSITION_SELECTION) if info or not info.isCollapsed: return info.text except (RuntimeError, NotImplementedError): return None
def script_info(self, gesture): #ui.message(str(getPipeFile()['Channels'])) out = '' for x in menuFull: if x.role == 11 and not controlTypes.STATE_HASPOPUP in x.states: out += repr(x.name.partition('\x09')[0]) + ',\n' # ui.browseableMessage(out) ui.browseableMessage('\n'.join( (api.getCaretObject().name, api.getFocusObject().name, str(api.getForegroundObject().windowHandle), str(api.winUser.getForegroundWindow()))))
def getContextRect( context: Context, obj: Optional[TextContainerObject] = None ) -> Optional[locationHelper.RectLTRB]: """Gets a rectangle for the specified context.""" if context == Context.FOCUS: return getObjectRect(obj or api.getFocusObject()) elif context == Context.NAVIGATOR: return getObjectRect(obj or api.getNavigatorObject()) elif context == Context.REVIEW: return getReviewRect() elif context == Context.BROWSEMODE: caret = obj or api.getCaretObject() if api.isCursorManager(caret): return getCaretRect(obj=caret) return None elif context == Context.CARET: caret = obj or api.getCaretObject() if not api.isCursorManager(caret): return getCaretRect(obj=caret) return None elif context == Context.MOUSE: return getMouseRect()
def __init__(self, cursor): self.cursor = cursor self.trigger = SayAllProfileTrigger() self.trigger.enter() # Start at the cursor. if cursor == CURSOR_CARET: try: self.reader = api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): return else: self.reader = api.getReviewPosition() self.speakTextInfoState = speech.SpeakTextInfoState(self.reader.obj) self.numBufferedLines = 0
def __init__(self, cursor): self.cursor = cursor self.trigger = SayAllProfileTrigger() self.reader = None # Start at the cursor. if cursor == CURSOR_CARET: try: self.reader = api.getCaretObject().makeTextInfo( textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError) as e: raise NotImplementedError("Unable to make TextInfo: " + str(e)) else: self.reader = api.getReviewPosition() # #10899: SayAll profile can't be activated earlier because they may not be anything to read self.trigger.enter() self.speakTextInfoState = speech.SpeakTextInfoState(self.reader.obj) self.numBufferedLines = 0
def script_linkTitle(self, gesture): link = self.getFocusedLink() self.vlcProc.terminate() if self.vlcProc is not None else None if link is None or link.startswith("http") == False: selection = api.getCaretObject().makeTextInfo( textInfos.POSITION_SELECTION).text if selection.startswith("http"): link = selection else: ui.message("Not a link.") return if (re.match(".*.(aac|mp4).*", link)): self.vlcProc = subprocess.Popen( ["c:/program files/VideoLAN/vlc/vlc.exe", "-Idummy", link]) else: title = self.getTitle(link) ui.message(title)
def _reportErrorInPreviousWord(self): try: # self might be a descendant of the text control; e.g. Symphony. # We want to deal with the entire text, so use the caret object. info = api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) # This gets called for characters which might end a word; e.g. space. # The character before the caret is the word end. # The one before that is the last of the word, which is what we want. info.move(textInfos.UNIT_CHARACTER, -2) info.expand(textInfos.UNIT_CHARACTER) except Exception: # Focus probably moved. log.debugWarning("Error fetching last character of previous word", exc_info=True) return # Fetch the formatting for the last word to see if it is marked as a spelling error, # However perform the fetch and check in a future core cycle # To give the content control more time to detect and mark the error itself. # #12161: MS Word's UIA implementation certainly requires this delay. def _delayedDetection(): try: fields = info.getTextWithFields() except Exception: log.debugWarning( "Error fetching formatting for last character of previous word", exc_info=True) return for command in fields: if (isinstance(command, textInfos.FieldCommand) and command.command == "formatChange" and command.field.get("invalid-spelling")): break else: # No error. return nvwave.playWaveFile( os.path.join(globalVars.appDir, "waves", "textError.wav")) core.callLater(50, _delayedDetection)
def readTextHelper_generator(cursor): if cursor==CURSOR_CARET: try: reader=api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): return else: reader=api.getReviewPosition() lastSentIndex=0 lastReceivedIndex=0 cursorIndexMap={} keepReading=True speakTextInfoState=speech.SpeakTextInfoState(reader.obj) with SayAllProfileTrigger(): while True: if not reader.obj: # The object died, so we should too. return # lastReceivedIndex might be None if other speech was interspersed with this say all. # In this case, we want to send more text in case this was the last chunk spoken. if lastReceivedIndex is None or (lastSentIndex-lastReceivedIndex)<=10: if keepReading: bookmark=reader.bookmark index=lastSentIndex+1 delta=reader.move(textInfos.UNIT_READINGCHUNK,1,endPoint="end") if delta<=0: speech.speakWithoutPauses(None) keepReading=False continue speech.speakTextInfo(reader,unit=textInfos.UNIT_READINGCHUNK,reason=controlTypes.REASON_SAYALL,index=index,useCache=speakTextInfoState) lastSentIndex=index cursorIndexMap[index]=(bookmark,speakTextInfoState.copy()) try: reader.collapse(end=True) except RuntimeError: #MS Word when range covers end of document # Word specific: without this exception to indicate that further collapsing is not posible, say-all could enter an infinite loop. speech.speakWithoutPauses(None) keepReading=False else: # We'll wait for speech to catch up a bit before sending more text. if speech.speakWithoutPauses.lastSentIndex is None or (lastSentIndex-speech.speakWithoutPauses.lastSentIndex)>=10: # There is a large chunk of pending speech # Force speakWithoutPauses to send text to the synth so we can move on. speech.speakWithoutPauses(None) receivedIndex=speech.getLastSpeechIndex() if receivedIndex!=lastReceivedIndex and (lastReceivedIndex!=0 or receivedIndex!=None): lastReceivedIndex=receivedIndex bookmark,state=cursorIndexMap.get(receivedIndex,(None,None)) if state: state.updateObj() if bookmark is not None: updater=reader.obj.makeTextInfo(bookmark) if cursor==CURSOR_CARET: updater.updateCaret() if cursor!=CURSOR_CARET or config.conf["reviewCursor"]["followCaret"]: api.setReviewPosition(updater) elif not keepReading and lastReceivedIndex==lastSentIndex: # All text has been sent to the synth. # Turn the page and start again if the object supports it. if isinstance(reader.obj,textInfos.DocumentWithPageTurns): try: reader.obj.turnPage() except RuntimeError: break else: reader=reader.obj.makeTextInfo(textInfos.POSITION_FIRST) keepReading=True else: break while speech.isPaused: yield yield # Wait until the synth has actually finished speaking. # Otherwise, if there is a triggered profile with a different synth, # we will switch too early and truncate speech (even up to several lines). # Send another index and wait for it. index=lastSentIndex+1 speech.speak([speech.IndexCommand(index)]) while speech.getLastSpeechIndex()<index: yield yield # Some synths say they've handled the index slightly sooner than they actually have, # so wait a bit longer. for i in xrange(30): yield
def getInitialTextInfo(self) -> textInfos.TextInfo: try: return api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError) as e: raise NotImplementedError("Unable to make TextInfo: ", e)
def readTextHelper_generator(cursor): if cursor == CURSOR_CARET: try: reader = api.getCaretObject().makeTextInfo( textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): return else: reader = api.getReviewPosition() lastSentIndex = 0 lastReceivedIndex = 0 cursorIndexMap = {} keepReading = True speakTextInfoState = speech.SpeakTextInfoState(reader.obj) start = time.time() with SayAllProfileTrigger(): while True: if not reader.obj: # The object died, so we should too. return # lastReceivedIndex might be None if other speech was interspersed with this say all. # In this case, we want to send more text in case this was the last chunk spoken. if lastReceivedIndex is None or (lastSentIndex - lastReceivedIndex) <= 10: if keepReading: bookmark = reader.bookmark index = lastSentIndex + 1 delta = reader.move(textInfos.UNIT_READINGCHUNK, 1, endPoint="end") if delta <= 0: speech.speakWithoutPauses(None) keepReading = False continue speech.speakTextInfo(reader, unit=textInfos.UNIT_READINGCHUNK, reason=controlTypes.REASON_SAYALL, index=index, useCache=speakTextInfoState) lastSentIndex = index cursorIndexMap[index] = (bookmark, speakTextInfoState.copy()) try: reader.collapse(end=True) except RuntimeError: #MS Word when range covers end of document # Word specific: without this exception to indicate that further collapsing is not posible, say-all could enter an infinite loop. speech.speakWithoutPauses(None) keepReading = False else: # We'll wait for speech to catch up a bit before sending more text. if speech.speakWithoutPauses.lastSentIndex is None or ( lastSentIndex - speech.speakWithoutPauses.lastSentIndex) >= 10: # There is a large chunk of pending speech # Force speakWithoutPauses to send text to the synth so we can move on. speech.speakWithoutPauses(None) receivedIndex = speech.getLastSpeechIndex() if receivedIndex != lastReceivedIndex and ( lastReceivedIndex != 0 or receivedIndex != None): lastReceivedIndex = receivedIndex bookmark, state = cursorIndexMap.get(receivedIndex, (None, None)) if state: state.updateObj() if bookmark is not None: updater = reader.obj.makeTextInfo(bookmark) if cursor == CURSOR_CARET: updater.updateCaret() if cursor != CURSOR_CARET or config.conf["reviewCursor"][ "followCaret"]: api.setReviewPosition(updater, isCaret=cursor == CURSOR_CARET) elif not keepReading and lastReceivedIndex == lastSentIndex: # All text has been sent to the synth. # Turn the page and start again if the object supports it. if isinstance(reader.obj, textInfos.DocumentWithPageTurns): try: reader.obj.turnPage() except RuntimeError: break else: reader = reader.obj.makeTextInfo( textInfos.POSITION_FIRST) keepReading = True else: break while speech.isPaused: yield yield now = time.time() if (now - start) > int(min) * 60 + int(sec): speech.cancelSpeech() break # Wait until the synth has actually finished speaking. # Otherwise, if there is a triggered profile with a different synth, # we will switch too early and truncate speech (even up to several lines). # Send another index and wait for it. index = lastSentIndex + 1 speech.speak([speech.IndexCommand(index)]) while speech.getLastSpeechIndex() < index: yield yield # Some synths say they've handled the index slightly sooner than they actually have, # so wait a bit longer. for i in xrange(30): yield
def __init__(self): self.object = api.getCaretObject() self.textInfo = self.object.makeTextInfo(textInfos.POSITION_CARET) self.textInfo.expand(textInfos.UNIT_WORD)
def readTextHelper_generator(cursor): if cursor==CURSOR_CARET: try: reader=api.getCaretObject().makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): return else: reader=api.getReviewPosition() lastSentIndex=0 lastReceivedIndex=0 cursorIndexMap={} keepReading=True while True: if not reader.obj: # The object died, so we should too. return # lastReceivedIndex might be None if other speech was interspersed with this say all. # In this case, we want to send more text in case this was the last chunk spoken. if lastReceivedIndex is None or (lastSentIndex-lastReceivedIndex)<=10: if keepReading: bookmark=reader.bookmark index=lastSentIndex+1 delta=reader.move(textInfos.UNIT_READINGCHUNK,1,endPoint="end") if delta<=0: speech.speakWithoutPauses(None) keepReading=False continue speech.speakTextInfo(reader,unit=textInfos.UNIT_READINGCHUNK,reason=controlTypes.REASON_SAYALL,index=index) lastSentIndex=index cursorIndexMap[index]=bookmark try: reader.collapse(end=True) except RuntimeError: #MS Word when range covers end of document speech.speakWithoutPauses(None) keepReading=False else: # We'll wait for speech to catch up a bit before sending more text. if speech.speakWithoutPauses.lastSentIndex is None or (lastSentIndex-speech.speakWithoutPauses.lastSentIndex)>=10: # There is a large chunk of pending speech # Force speakWithoutPauses to send text to the synth so we can move on. speech.speakWithoutPauses(None) receivedIndex=speech.getLastSpeechIndex() if receivedIndex!=lastReceivedIndex and (lastReceivedIndex!=0 or receivedIndex!=None): lastReceivedIndex=receivedIndex bookmark=cursorIndexMap.get(receivedIndex,None) if bookmark is not None: updater=reader.obj.makeTextInfo(bookmark) if cursor==CURSOR_CARET: updater.updateCaret() if cursor!=CURSOR_CARET or config.conf["reviewCursor"]["followCaret"]: api.setReviewPosition(updater) elif not keepReading and lastReceivedIndex==lastSentIndex: # All text has been spoken. # Turn the page and start again if the object supports it. if isinstance(reader.obj,textInfos.DocumentWithPageTurns): try: reader.obj.turnPage() except RuntimeError: break else: reader=reader.obj.makeTextInfo(textInfos.POSITION_FIRST) keepReading=True else: break while speech.isPaused: yield yield