def event_nameChange(self, obj, nextHandler): # On some systems, touch keyboard keys keeps firing name change event. # In build 17704, whenever skin tones are selected, name change is fired by emoji entries (GridViewItem). if ((obj.UIAElement.cachedClassName in ("CRootKey", "GridViewItem")) # Just ignore useless clipboard status. # Also top emoji search result must be announced for better user experience. or (obj.UIAElement.cachedAutomationID in ("TEMPLATE_PART_ClipboardItemsList", "TEMPLATE_PART_Search_TextBlock")) # And no, emoji entries should not be announced here. or (self._recentlySelected is not None and self._recentlySelected in obj.name)): return # The word "blank" is kept announced, so suppress this on build 17666 and later. if winVersion.winVersion.build > 17134: # In build 17672 and later, return immediatley when element selected event on clipboard item was fired just prior to this. # In some cases, parent will be None, as seen when emoji panel is closed in build 18267. try: if obj.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemIndex" or obj.parent.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemsList": return except AttributeError: return if not self._emojiPanelJustOpened or obj.UIAElement.cachedAutomationID != "TEMPLATE_PART_ExpressionGroupedFullView": speech.cancelSpeech() self._emojiPanelJustOpened = False # Don't forget to add "Microsoft Candidate UI" as something that should be suppressed. if obj.UIAElement.cachedAutomationID not in ( "TEMPLATE_PART_ExpressionFullViewItemsGrid", "TEMPLATE_PART_ClipboardItemIndex", "CandidateWindowControl"): ui.message(obj.name) nextHandler()
def sendCaptcha(self, **kwargs): kwargs['soft_id'] = 1665 kwargs['regsense'] = int(_config.conf['regsense']) kwargs['language'] = _config.conf['language'] response = requestAPI(**kwargs) speech.cancelSpeech() if not response.startswith('OK|'): errorHandler(response) return ui.message( _('Captcha successfully sent to the recognition. You will be notified when the result will be ready' )) time.sleep(3) while self._running: status = requestAPI(action='get', id=response[3:]) if (status != 'CAPCHA_NOT_READY') and self._running: break time.sleep(2) else: return if status.startswith('OK|'): api.copyToClip(status.decode('utf-8')[3:]) ui.message( _('Captcha solved successfully! The result copied to the clipboard' )) else: errorHandler(status)
def event_valueChange(self, obj, nextHandler): #log.info("valueChange %s" % self.getInfo(obj)) if obj.windowClassName == 'ComboBox' and obj.role == oleacc.ROLE_SYSTEM_TOOLTIP: api.setFocusObject(obj) speech.cancelSpeech() updateLocations() nextHandler()
def event_mouseMove(self,x,y): if not self._mouseEntered and config.conf['mouse']['reportObjectRoleOnMouseEnter']: speech.cancelSpeech() speech.speakObjectProperties(self,role=True) speechWasCanceled=True else: speechWasCanceled=False self._mouseEntered=True try: info=self.makeTextInfo(textInfos.Point(x,y)) except NotImplementedError: info=NVDAObjectTextInfo(self,textInfos.POSITION_FIRST) except LookupError: return if config.conf["reviewCursor"]["followMouse"]: api.setReviewPosition(info) info.expand(info.unit_mouseChunk) oldInfo=getattr(self,'_lastMouseTextInfoObject',None) self._lastMouseTextInfoObject=info if not oldInfo or info.__class__!=oldInfo.__class__ or info.compareEndPoints(oldInfo,"startToStart")!=0 or info.compareEndPoints(oldInfo,"endToEnd")!=0: text=info.text notBlank=False if text: for ch in text: if not ch.isspace() and ch!=u'\ufffc': notBlank=True if notBlank: if not speechWasCanceled: speech.cancelSpeech() speech.speakText(text)
def event_alert(self, obj, nextHandler): try: if obj.IA2Attributes["id"] == "customizationui-widget-panel": # Firefox add-on panel speech.cancelSpeech() api.setFocusObject(obj.simpleFirstChild) nextHandler() return except (KeyError, AttributeError): pass try: isNotification = "notification" in "".join(obj.IA2Attributes.values()).lower()\ or "alert" in "".join(obj.IA2Attributes.values()).lower() except: isNotification = False if isNotification: try: isPopup = obj.IA2Attributes["id"] == "notification-popup" except (KeyError, AttributeError): isPopup = False if self.inMainWindow() and isPopup: if shared.focusAlertPopup(obj): Timer(0.75, nextHandler) return alertText = "%s" % shared.getAlertText(obj) notificationLog = (datetime.now(), alertText.replace("\n", "\t")) if notificationLog not in self.notificationHistory: self.notificationHistory.append(notificationLog) nextHandler()
def handleWidgetSwitch(self, widget, reason): # log.info("Switching to widget %s" %(widget.name if widget is not None else "(none)")) if widget == self.webApp.activeWidget: return if self.webApp.activeWidget is not None: speech.speakMessage(u"Sortie de %s, %s" %(self.webApp.activeWidget.name, self.webApp.activeWidget.group)) self.sendWidgetEvent('widget_loseFocus', self.webApp.activeWidget) self.webApp.activeWidget = None if webAppHandler.useInternalBrowser is False and widget == None: #: We don't switch to another widget but returns to a browseMode presentation. self.webApp.presenter.restoreBrailleBuffer() ti = html.getTreeInterceptor() if ti and hasattr(ti, '_enteringFromOutside'): #: Set to L{True} to force the treeInterceptor to refresh itself. ti._enteringFromOutside = True ti._hasFirstGainFocus = True info = html.getCaretInfo() if info: html.speakLine(info) #: Switch from and back to browseMode to force braille output. html.formMode() html.browseMode() if widget is not None and (widget.autoEnter is True or reason is nodeHandler.REASON_SHORTCUT): self.webApp.activeWidget = widget speech.cancelSpeech() speech.speakMessage(u"Entrée dans %s, %s" %(widget.name, widget.group)) self.sendWidgetEvent('widget_gainFocus', widget) else: self.webApp.activeWidget = None
def event_gainFocus(self, obj, nextHandler): # Nyquist effects with an unspoken unit and an unnamed slider if obj and obj.role==8 and obj.windowControlID in range(12000,13000) \ and obj.next and obj.next.role==24 and obj.next.name==None \ and obj.next.next and obj.previous.location[0]!=obj.next.next.location[0]: try: obj.value += ' ' + obj.next.next.name except: pass #Mainly for the Compressor effect if ((obj.role==8 and not controlTypes.STATE_READONLY in obj.states)or \ obj.role==24 )and \ obj.location[3]<obj.location[2] and \ (obj.next and obj.next.name is not None) and \ obj.next.role==7 and \ (obj.next.next is None or \ obj.next.name not in (obj.next.next.name or '')): try: if not obj.next.name in obj.name: obj.name += ' ' + obj.next.name except: pass # suppress things like[Panel, Track View Table, TABLEROW...] if obj.windowText == 'Track Panel': speech.cancelSpeech() if obj.windowClassName == '#32768' and obj.role == controlTypes.ROLE_POPUPMENU: # focus on first item for context menu name, obj.name = obj.name, None if name == 'DropDown': KIGesture.fromName('downArrow').send() nextHandler()
def event_show(self, obj, nextHandler): global wsrAlternatesPanel, wsrSpellingPanel if isinstance(obj, WSRAlternatesPanel): wsrAlternatesPanel = obj speech.cancelSpeech() speech.speakText(obj.name) for descendant in obj.recursiveDescendants: if controlTypes.STATE_INVISIBLE in descendant.states or controlTypes.STATE_INVISIBLE in descendant.parent.states: continue if descendant.role == controlTypes.ROLE_STATICTEXT: speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LINK: speech.speakText("Or say") speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LISTITEM: speech.speakText(str(descendant.positionInfo["indexInGroup"])) speakWSRAlternatesPanelItem(descendant) return elif isinstance(obj, WSRSpellingPanel): if wsrSpellingPanel is not None: wsrSpellingPanel.cancelPoll() wsrSpellingPanel = obj wsrSpellingPanel.schedulePoll() speech.cancelSpeech() speech.speakText(obj.name) for descendant in obj.recursiveDescendants: if controlTypes.STATE_INVISIBLE in descendant.states or controlTypes.STATE_INVISIBLE in descendant.parent.states: continue if descendant.role == controlTypes.ROLE_STATICTEXT: speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LINK: speech.speakText("Or say") speech.speakText(descendant.name) return nextHandler()
def event_selection(self): if not self.appModule.selectedItem: api.getFocusObject().event_suggestionsOpened() # This is to ease finding the elp document if self.appModule.selectedItem != self: self.appModule.selectedItem = self # If autocompletion popup is open and you write some text in the # document, the selection event is not fired. For some reason, neither # nameChange, so we need this check: if self.appModule.selectedItemName != self.name: self.appModule.selectedItemName = self.name speech.cancelSpeech() # Reporting as focused should be sufficient self.reportFocus() # I picked up this from UIA SuggestionItem for rendering in braille. # Simply calling `reportFocus` doesn't outputs the text to braille devices # and reporting with `ui.message` needs an extra translation string when reporting position info braille.handler.message( braille.getBrailleTextForProperties( name=self.name, role=self.role, position=self.positionInfo))
def event_gainFocus(self): if mouseHandler.lastMouseEventTime < time.time() - 0.2: # This focus change was not caused by a mouse event. # If the mouse is on another toolbar control, the notification area toolbar will rudely # bounce the focus back to the object under the mouse after a brief pause. # Moving the mouse to the focus object isn't a good solution because # sometimes, the focus can't be moved away from the object under the mouse. # Therefore, move the mouse out of the way. winUser.setCursorPos(0, 0) if self.role == controlTypes.ROLE_TOOLBAR: # Sometimes, the toolbar itself receives the focus instead of the focused child. # However, the focused child still has the focused state. for child in self.children: if child.hasFocus: # Redirect the focus to the focused child. eventHandler.executeEvent("gainFocus", child) return # We've really landed on the toolbar itself. # This was probably caused by moving the mouse out of the way in a previous focus event. # This previous focus event is no longer useful, so cancel speech. speech.cancelSpeech() if eventHandler.isPendingEvents("gainFocus"): return super(NotificationArea, self).event_gainFocus()
def onEnter(self): type, name, text1 = self.sibi.tool_edit.getTextInfo() if text1 != "": type, name, text2 = self.sibi.tool_edit2.getTextInfo() speech.cancelSpeech() speech.speakMessage(text1 + " " + text2) return True
def processLine(self, ti): self.appModule.PrevStartOffset = ti._start._startOffset # Get the textInfo object for a current line TextInfo = MozillaCompoundTextInfo curr = self.makeTextInfo(textInfos.POSITION_SELECTION) curr.collapse() curr.expand(textInfos.UNIT_LINE) # Assign short variables for later conditions cs = curr._start._startOffset # Current line startOffset os = self.appModule.PrevStartOffset # startOffset from previous invocation # If old and current startOffsets are different we moved to a new line if not os == cs: # Prevent reading editor group info after moving to next line # Script does it only after recent completion. # Scrolling up and down through the code works well. self.name = "" # Update OldStartOffset variable to the current line's startOffset self.appModule.PrevStartOffset = curr._start._startOffset elif os == cs: # We are in the same line, so read only suggested items. # Do not read the line from the beginning. # Read back what was inserted by the user TextInfo = MozillaCompoundTextInfo line = self.makeTextInfo(textInfos.POSITION_SELECTION) line.collapse() line.expand(textInfos.UNIT_WORD) speech.cancelSpeech() speech.speakTextInfo(line,textInfos.UNIT_WORD, reason=controlTypes.REASON_CHANGE, suppressBlanks=True)
def event_gainFocus(self): NotificationArea.lastKnownLocation = self.location if mouseHandler.lastMouseEventTime < time.time() - 0.2: # This focus change was not caused by a mouse event. # If the mouse is on another systray control, the notification area toolbar will rudely # bounce the focus back to the object under the mouse after a brief pause. # Moving the mouse to the focus object isn't a good solution because # sometimes, the focus can't be moved away from the object under the mouse. # Therefore, move the mouse out of the way. if self.location: systrayLeft, systrayTop, systrayWidth, systrayHeight = self.location mouseLeft, mouseTop = winUser.getCursorPos() if (systrayLeft <= mouseLeft <= systrayLeft + systrayWidth and systrayTop <= mouseTop <= systrayTop + systrayHeight): winUser.setCursorPos(0, 0) if self.role == controlTypes.ROLE_TOOLBAR: # Sometimes, the toolbar itself receives the focus instead of the focused child. # However, the focused child still has the focused state. for child in self.children: if child.hasFocus: # Redirect the focus to the focused child. eventHandler.executeEvent("gainFocus", child) return # We've really landed on the toolbar itself. # This was probably caused by moving the mouse out of the way in a previous focus event. # This previous focus event is no longer useful, so cancel speech. speech.cancelSpeech() if eventHandler.isPendingEvents("gainFocus"): return super(NotificationArea, self).event_gainFocus()
def move(): speech.cancelSpeech() # #8831: Report before moving because moving might change the focus, which # might mutate the document, potentially invalidating info if it is # offset-based. item.report() item.moveTo()
def callback(obj, oldspeechMode): api.processPendingEvents() speech.cancelSpeech() speech.speechMode = oldSpeechMode api.setNavigatorObject(obj) api.moveMouseToNVDAObject(obj) speech.speakObject(obj)
def event_gainFocus(self): speech.cancelSpeech() self.roleText = str('\0') # An empty string. self.roleTextBraille = str('\0') # An empty string. super(CustomListItem, self).event_gainFocus() # Set the flag that additionally informs we are in the same line. self.appModule.fromCompletion = True
def event_UIA_elementSelected(self): focusControllerFor = api.getFocusObject().controllerFor if len(focusControllerFor) > 0 and focusControllerFor[ 0].appModule is self.appModule and self.name: speech.cancelSpeech() api.setNavigatorObject(self) self.reportFocus()
def event_UIA_elementSelected(self, obj, nextHandler): # #7273: When this is fired on categories, the first emoji from the new category is selected but not announced. # Therefore, move the navigator object to that item if possible. # However, in recent builds, name change event is also fired. # For consistent experience, report the new category first by traversing through controls. speech.cancelSpeech() # And no, if running on build 17040 and if this is typing suggestion, do not announce candidate window changes, as it is duplicate announcement and is anoying. if obj.UIAElement.cachedAutomationID == "IME_Candidate_Window": return candidate = obj if obj.UIAElement.cachedClassName == "ListViewItem": # The difference between emoji panel and suggestions list is absence of categories/emoji separation. # If dealing with keyboard entry suggestions (build 17040 and later), return immediately. candidate = obj.parent.previous if candidate is None: return ui.message(candidate.name) obj = candidate.firstChild if obj is not None: api.setNavigatorObject(obj) obj.reportFocus() braille.handler.message( braille.getBrailleTextForProperties( name=obj.name, role=obj.role, positionInfo=obj.positionInfo)) else: # Translators: presented when there is no emoji when searching for one in Windows 10 Fall Creators Update and later. ui.message(_("No emoji")) nextHandler()
def checkAutoAction(self): countMoveto = 0 with self.lock: if not self.isReady: return i = 0 for result in self.markerResults: i += 1 if result.markerQuery.autoAction: controlIdentifier = result.node.controlIdentifier if not controlIdentifier in self.triggeredIdentifiers: self.triggeredIdentifiers.append(controlIdentifier) speechOn() speech.cancelSpeech() autoActionName = result.markerQuery.autoAction func = getattr(result, "script_%s" % autoActionName) if autoActionName == "speak": playWebAppSound("errorMessage") #sleep(0.5) elif autoActionName == "moveto": countMoveto += 1 if countMoveto > 1: func = None if func: func(None)
def doFindText(self, text, reverse=False, caseSensitive=False): if not text: return info = self.makeTextInfo(textInfos.POSITION_CARET) res = info.find(text, reverse=reverse, caseSensitive=caseSensitive) if res: self.selection = info speech.cancelSpeech() info.move(textInfos.UNIT_LINE, 1, endPoint="end") speech.speakTextInfo(info, reason=controlTypes.REASON_CARET) elif self.webAccess.zone: def ask(): if gui.messageBox( "\n".join((_('text "%s" not found') % text, "", _("Cancel zone restriction and retry?"))), caption=_("Find Error"), style=wx.OK | wx.CANCEL | wx.ICON_ERROR) == wx.OK: self.webAccess.zone = None self.doFindText(text, reverse=reverse, caseSensitive=caseSensitive) wx.CallAfter(ask) else: wx.CallAfter(gui.messageBox, _('text "%s" not found') % text, caption=_("Find Error"), style=wx.OK | wx.ICON_ERROR) cursorManager.CursorManager._lastFindText = text cursorManager.CursorManager._lastCaseSensitivity = caseSensitive
def event_UIA_elementSelected(self, obj, nextHandler): # #7273: When this is fired on categories, the first emoji from the new category is selected but not announced. # Therefore, move the navigator object to that item if possible. # However, in recent builds, name change event is also fired. # For consistent experience, report the new category first by traversing through controls. # #8189: do not announce candidates list itself (not items), as this is repeated each time candidate items are selected. if obj.UIAElement.cachedAutomationID == "CandidateList": return speech.cancelSpeech() # Sometimes clipboard candidates list gets selected, so ask NvDA to descend one more level. if obj.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemsList": obj = obj.firstChild candidate = obj # Sometimes, due to bad tree traversal, something other than the selected item sees this event. parent = obj.parent if obj.UIAElement.cachedClassName == "ListViewItem" and isinstance(parent, UIA) and parent.UIAElement.cachedAutomationID != "TEMPLATE_PART_ClipboardItemsList": # The difference between emoji panel and suggestions list is absence of categories/emoji separation. # Turns out automation ID for the container is different, observed in build 17666 when opening clipboard copy history. candidate = obj.parent.previous if candidate is not None: # Emoji categories list. ui.message(candidate.name) obj = candidate.firstChild if obj is not None: api.setNavigatorObject(obj) obj.reportFocus() braille.handler.message(braille.getBrailleTextForProperties(name=obj.name, role=obj.role, positionInfo=obj.positionInfo)) # Cache selected item. self._recentlySelected = obj.name else: # Translators: presented when there is no emoji when searching for one in Windows 10 Fall Creators Update and later. ui.message(_("No emoji")) nextHandler()
def event_focusEntered(self): if self.role in (controlTypes.ROLE_MENUBAR, controlTypes.ROLE_POPUPMENU, controlTypes.ROLE_MENUITEM): speech.cancelSpeech() return if self.isPresentableFocusAncestor: speech.speakObject(self, reason=controlTypes.REASON_FOCUSENTERED)
def script_disconnectAll(self, gesture): ui.message(_("Disconnecting...")) speechMode = speech.speechMode speech.speechMode = 0 wx.CallAfter(self._samContextMenu, 8) time.sleep(0.5) speech.speechMode = speechMode speech.cancelSpeech()
def _metadataAnnouncerInternal(status): import nvwave, queueHandler, speech speech.cancelSpeech() queueHandler.queueFunction(queueHandler.eventQueue, ui.message, status) nvwave.playWaveFile(os.path.join(os.path.dirname(__file__), "SPL_Metadata.wav")) # #51 (18.03/15.14-LTS): close link to metadata announcer thread when finished. global _earlyMetadataAnnouncer _earlyMetadataAnnouncer = None
def _metadataAnnouncerInternal(status, startup=False): import nvwave, queueHandler, speech if not startup: speech.cancelSpeech() queueHandler.queueFunction(queueHandler.eventQueue, ui.message, status) nvwave.playWaveFile(os.path.join(os.path.dirname(__file__), "SPL_Metadata.wav")) # #51 (18.03/15.14-LTS): close link to metadata announcer thread when finished. global _earlyMetadataAnnouncer _earlyMetadataAnnouncer = None
def event_stateChange(self): states = self.states focus = api.getFocusObject() if ( focus.role == controlTypes.ROLE_EDITABLETEXT or focus.role == controlTypes.ROLE_BUTTON ) and controlTypes.STATE_SELECTED in states and controlTypes.STATE_INVISIBLE not in states and controlTypes.STATE_UNAVAILABLE not in states and controlTypes.STATE_OFFSCREEN not in states: speech.cancelSpeech() ui.message(self.name)
def script_volume_changed(self, gesture): gesture.send() cancelSpeech() ui.message( str( int( round( round(self.master_volume.GetMasterVolume(), 2) * 100, 0))) + '%')
def l(self, args): "Speak a single character (or set of characters) immediately." res = [] res.extend(self._header) if "character_scale" in self._state: res.append(speech.RateCommand(multiplier=self._state["character_scale"])) res.extend(list(speech.getSpellingSpeech("".join(args)))) speech.cancelSpeech() # Flush NVDA's speech queue speech.speak(res, priority=speech.priorities.SpeechPriority.NOW)
def systemShutdown(self, shutdownTime): if shutdownTime == u"": speech.cancelSpeech() ui.message(u'값을 잘못 입력하셨습니다.') else: value = int(shutdownTime) speech.cancelSpeech() ui.message(shutdownTime + u'초 후 시스템이 종료됩니다.') win32api.InitiateSystemShutdown("127.0.0.1", None, value, 1, 0)
def event_stateChange(self): states=self.states focus=api.getFocusObject() if (focus.role==controlTypes.ROLE_EDITABLETEXT or focus.role==controlTypes.ROLE_BUTTON) and controlTypes.STATE_SELECTED in states and controlTypes.STATE_INVISIBLE not in states and controlTypes.STATE_UNAVAILABLE not in states and controlTypes.STATE_OFFSCREEN not in states: speech.cancelSpeech() text=self.name # Some newer versions of Outlook don't put the contact as the name of the listItem, rather it is on the parent if not text: text=self.parent.name ui.message(text)
def click(self): speech.cancelSpeech() left, top, width, height = self.location x = left + (width / 2) y = top + (height / 2) #click the middle of the screen after moving to this location. winUser.setCursorPos(x, y) winUser.mouse_event(winUser.MOUSEEVENTF_LEFTDOWN, 0, 0, None, None) winUser.mouse_event(winUser.MOUSEEVENTF_LEFTUP, 0, 0, None, None) speech.cancelSpeech()
def event_UIA_elementSelected(self): # Build 17600 series introduces Sets, a way to group apps into tabs. # #45: unfortunately, the start page for this (an embedded searchui process inside Edge) says controller for list is empty when in fact it isn't. # Thankfully, it is easy to spot them: if a link is next to results list, then this is the embedded searchui results list. focusControllerFor=api.getFocusObject().controllerFor announceSuggestions = ((len(focusControllerFor)>0 and focusControllerFor[0].appModule is self.appModule and self.name) or self.parent.next is not None) if announceSuggestions: speech.cancelSpeech() api.setNavigatorObject(self) self.reportFocus()
def onEndSession(evt): # NVDA will be terminated as soon as this function returns, so save configuration if appropriate. config.saveOnExit() speech.cancelSpeech() if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass log.info("Windows session ending")
def event_stateChange(self): states=self.states focus=api.getFocusObject() if (focus.role==controlTypes.Role.EDITABLETEXT or focus.role==controlTypes.Role.BUTTON) and controlTypes.State.SELECTED in states and controlTypes.State.INVISIBLE not in states and controlTypes.State.UNAVAILABLE not in states and controlTypes.State.OFFSCREEN not in states: speech.cancelSpeech() text=self.name # Some newer versions of Outlook don't put the contact as the name of the listItem, rather it is on the parent if not text: text=self.parent.name ui.message(text)
def goTo(self): printDebug("ReportDialog goTo") index = self.entriesList.GetFocusedItem() self.collection[index].goTo() wx.CallAfter(self.parent.Close) self.Close() speech.cancelSpeech() oldSpeechMode = speech.speechMode speech.speechMode = speech.speechMode_off core.callLater(500, self.collectionObject.speakContext, oldSpeechMode)
def event_stateChange(self, obj, nextHandler): if obj.role == controlTypes.ROLE_DOCUMENT and controlTypes.STATE_BUSY in obj.states and winUser.isWindowVisible(obj.windowHandle) and obj.isInForeground: statusBar = api.getStatusBar() if statusBar: statusText = api.getStatusBarText(statusBar) speech.cancelSpeech() speech.speakMessage(controlTypes.speechStateLabels[controlTypes.STATE_BUSY]) speech.speakMessage(statusText) return nextHandler()
def moveToBookmark(position): obj = api.getFocusObject() treeInterceptor=obj.treeInterceptor if isinstance(treeInterceptor, BrowseModeDocumentTreeInterceptor) and not treeInterceptor.passThrough: obj = treeInterceptor bookmark = Offsets(position, position) info = obj.makeTextInfo(bookmark) info.updateSelection() review.handleCaretMove(info) speech.cancelSpeech() info.move(textInfos.UNIT_LINE,1,endPoint="end") speech.speakTextInfo(info,reason=controlTypes.REASON_CARET)
def script_speechMode(self,gesture): curMode=speech.speechMode speech.speechMode=speech.speechMode_talk newMode=(curMode+1)%3 if newMode==speech.speechMode_off: name=_("off") elif newMode==speech.speechMode_beeps: name=_("beeps") elif newMode==speech.speechMode_talk: name=_("talk") speech.cancelSpeech() ui.message(_("speech mode %s")%name) speech.speechMode=newMode
def event_stateChange(self): # iTunes has indicated that a page has died and been replaced by a new one. focus = api.getFocusObject() if not winUser.isDescendantWindow(self.windowHandle, focus.windowHandle): return # The new page has the same event params, so we must bypass NVDA's IAccessible caching. obj = NVDAObjects.IAccessible.getNVDAObjectFromEvent(focus.windowHandle, winUser.OBJID_CLIENT, 0) if not obj: return if focus.treeInterceptor: speech.cancelSpeech() treeInterceptorHandler.killTreeInterceptor(focus.treeInterceptor) eventHandler.queueEvent("gainFocus",obj)
def doFindText(self,text,reverse=False): if not text: return info=self.makeTextInfo(textInfos.POSITION_CARET) res=info.find(text,reverse=reverse) if res: self.selection=info speech.cancelSpeech() info.move(textInfos.UNIT_LINE,1,endPoint="end") speech.speakTextInfo(info,reason=controlTypes.REASON_CARET) else: wx.CallAfter(gui.messageBox,_('text "%s" not found')%text,_("Find Error"),wx.OK|wx.ICON_ERROR) CursorManager._lastFindText=text
def doFindText(self,text,reverse=False): if not text: return info=self.makeTextInfo(textInfos.POSITION_CARET) res=info.find(text,reverse=reverse) if res: self.selection=info speech.cancelSpeech() info.move(textInfos.UNIT_LINE,1,endPoint="end") speech.speakTextInfo(info,reason=speech.REASON_CARET) else: errorDialog=gui.scriptUI.MessageDialog(_("text \"%s\" not found")%text,title=_("Find Error"),style=gui.scriptUI.wx.OK|gui.scriptUI.wx.ICON_ERROR) errorDialog.run() CursorManager._lastFindText=text
def event_stateChange(self): # iTunes has indicated that a page has died and been replaced by a new one. # #5191: This is actually fired on the "iTunesWebViewControl" parent, # but AccessibleObjectFromEvent on this window returns the WebKit document as of iTunes 12. focus = api.getFocusObject() if self.windowHandle != focus.windowHandle: return # The new page has the same event params, so we must bypass NVDA's IAccessible caching. obj = NVDAObjects.IAccessible.getNVDAObjectFromEvent(focus.windowHandle, winUser.OBJID_CLIENT, 0) if not obj: return if focus.treeInterceptor: speech.cancelSpeech() treeInterceptorHandler.killTreeInterceptor(focus.treeInterceptor) eventHandler.queueEvent("gainFocus",obj)
def moveTo(self,x,y,new=False,unit=textInfos.UNIT_LINE): obj=api.getDesktopObject().objectFromPoint(x,y) prevObj=None while obj and obj.beTransparentToMouse: prevObj=obj obj=obj.parent if not obj or (obj.presentationType!=obj.presType_content and obj.role!=controlTypes.ROLE_PARAGRAPH): obj=prevObj if not obj: return hasNewObj=False if obj!=self._obj: self._obj=obj hasNewObj=True if self.updateReview: api.setNavigatorObject(obj) else: obj=self._obj pos=None if obj.treeInterceptor: try: pos=obj.treeInterceptor.makeTextInfo(obj) except LookupError: pos=None if pos: obj=obj.treeInterceptor.rootNVDAObject if hasNewObj and self._obj and obj.treeInterceptor is self._obj.treeInterceptor: hasNewObj=False if not pos: try: pos=obj.makeTextInfo(textInfos.Point(x,y)) except (NotImplementedError,LookupError): pass if pos: pos.expand(unit) if pos and self.updateReview: api.setReviewPosition(pos) speechCanceled=False if hasNewObj: speech.cancelSpeech() speechCanceled=True speech.speakObject(obj) if pos and (new or not self._pos or pos.__class__!=self._pos.__class__ or pos.compareEndPoints(self._pos,"startToStart")!=0 or pos.compareEndPoints(self._pos,"endToEnd")!=0): self._pos=pos if not speechCanceled: speech.cancelSpeech() speech.speakTextInfo(pos,reason=controlTypes.REASON_CARET)
def doFindText(text, reverse=False, caseSensitive=False): if not text: return obj=api.getFocusObject() treeInterceptor=obj.treeInterceptor if isinstance(treeInterceptor, BrowseModeDocumentTreeInterceptor) and not treeInterceptor.passThrough: obj=treeInterceptor obj.doFindText(text=text, reverse=reverse, caseSensitive=caseSensitive) elif obj.role != controlTypes.ROLE_EDITABLETEXT: return else: CursorManager._lastFindText = text CursorManager._lastCaseSensitivity = caseSensitive try: info=obj.makeTextInfo(textInfos.POSITION_CARET) except (NotImplementedError, RuntimeError): info=obj.makeTextInfo(textInfos.POSITION_FIRST) try: res=info.find(text,reverse=reverse, caseSensitive=caseSensitive) except WindowsError: wx.CallAfter(gui.messageBox, # Message translated in NVDA core. translate('text "%s" not found') % text, # Message translated in NVDA core. translate("Find Error"), wx.OK|wx.ICON_ERROR) except: if api.copyToClip(text): # Translators: message presented when a string of text has been copied to the clipboard. ui.message(_("%s copied to clipboard") % text) return if res: if hasattr(obj,'selection'): obj.selection=info else: info.updateCaret() speech.cancelSpeech() info.move(textInfos.UNIT_LINE,1,endPoint="end") speech.speakTextInfo(info,reason=controlTypes.REASON_CARET) else: wx.CallAfter(gui.messageBox, # Message translated in NVDA core. translate('text "%s" not found') % text, # Message translated in NVDA core. translate("Find Error"), wx.OK|wx.ICON_ERROR)
def event_show(self, obj, nextHandler): global wsrAlternatesPanel, wsrSpellingPanel #Phrases which need translated in this function: # Translators: The text for "or say," Which is telling the user that they can say the next phrase. orSay = _("Or say") if isinstance(obj, WSRAlternatesPanel): wsrAlternatesPanel = obj speech.cancelSpeech() speech.speakText(obj.name) for descendant in obj.recursiveDescendants: if controlTypes.STATE_INVISIBLE in descendant.states or controlTypes.STATE_INVISIBLE in descendant.parent.states: continue if descendant.role == controlTypes.ROLE_STATICTEXT: speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LINK: speech.speakText(orSay) speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LISTITEM: speech.speakText(str(descendant.positionInfo["indexInGroup"])) speakWSRAlternatesPanelItem(descendant) return elif isinstance(obj, WSRSpellingPanel): if wsrSpellingPanel is not None: wsrSpellingPanel.cancelPoll() wsrSpellingPanel = obj wsrSpellingPanel.schedulePoll() speech.cancelSpeech() speech.speakText(obj.name) for descendant in obj.recursiveDescendants: if controlTypes.STATE_INVISIBLE in descendant.states or controlTypes.STATE_INVISIBLE in descendant.parent.states: continue if descendant.role == controlTypes.ROLE_STATICTEXT: speech.speakText(descendant.name) elif descendant.role == controlTypes.ROLE_LINK: speech.speakText(orSay) speech.speakText(descendant.name) return nextHandler()
def event_selection(self): if not self.appModule.selectedItem: api.getFocusObject().event_suggestionsOpened() # This is to ease finding the elp document if self.appModule.selectedItem != self: self.appModule.selectedItem = self # If autocompletion popup is open and you write some text in the # document, the selection event is not fired. For some reason, neither # nameChange, so we need this check: if self.appModule.selectedItemName != self.name: self.appModule.selectedItemName = self.name speech.cancelSpeech() # Reporting as focused should be sufficient self.reportFocus() # I picked up this from UIA SuggestionItem for rendering in braille. # Simply calling `reportFocus` doesn't outputs the text to braille devices # and reporting with `ui.message` needs an extra translation string when reporting position info braille.handler.message( braille.getBrailleTextForProperties(name=self.name, role=self.role, position=self.positionInfo))
def event_stateChange(self): states=self.states focus=api.getFocusObject() if (focus.role==controlTypes.ROLE_EDITABLETEXT or focus.role==controlTypes.ROLE_BUTTON) and controlTypes.STATE_SELECTED in states and controlTypes.STATE_INVISIBLE not in states and controlTypes.STATE_UNAVAILABLE not in states and controlTypes.STATE_OFFSCREEN not in states: speech.cancelSpeech() ui.message(self.name)
def main(): """NVDA's core main loop. This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI. Then it initialises the wx application object and sets up the core pump, which checks the queues and executes functions when requested. Finally, it starts the wx main loop. """ log.debug("Core starting") try: # Windows >= Vista ctypes.windll.user32.SetProcessDPIAware() except AttributeError: pass import config if not globalVars.appArgs.configPath: globalVars.appArgs.configPath=config.getUserDefaultConfigPath(useInstalledPathIfExists=globalVars.appArgs.launcher) #Initialize the config path (make sure it exists) config.initConfigPath() log.info("Config dir: %s"%os.path.abspath(globalVars.appArgs.configPath)) log.debug("loading config") import config config.initialize() if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\start.wav") except: pass logHandler.setLogLevelFromConfig() try: lang = config.conf["general"]["language"] import languageHandler log.debug("setting language to %s"%lang) languageHandler.setLanguage(lang) except: log.warning("Could not set language to %s"%lang) import versionInfo log.info("NVDA version %s" % versionInfo.version) log.info("Using Windows version %s" % winVersion.winVersionText) log.info("Using Python version %s"%sys.version) log.info("Using comtypes version %s"%comtypes.__version__) # Set a reasonable timeout for any socket connections NVDA makes. import socket socket.setdefaulttimeout(10) log.debug("Initializing add-ons system") addonHandler.initialize() if globalVars.appArgs.disableAddons: log.info("Add-ons are disabled. Restart NVDA to enable them.") import appModuleHandler log.debug("Initializing appModule Handler") appModuleHandler.initialize() import NVDAHelper log.debug("Initializing NVDAHelper") NVDAHelper.initialize() import speechDictHandler log.debug("Speech Dictionary processing") speechDictHandler.initialize() import speech log.debug("Initializing speech") speech.initialize() if not globalVars.appArgs.minimal and (time.time()-globalVars.startTime)>5: log.debugWarning("Slow starting core (%.2f sec)" % (time.time()-globalVars.startTime)) # Translators: This is spoken when NVDA is starting. speech.speakMessage(_("Loading NVDA. Please wait...")) import wx log.info("Using wx version %s"%wx.version()) class App(wx.App): def OnAssert(self,file,line,cond,msg): message="{file}, line {line}:\nassert {cond}: {msg}".format(file=file,line=line,cond=cond,msg=msg) log.debugWarning(message,codepath="WX Widgets",stack_info=True) app = App(redirect=False) # We do support QueryEndSession events, but we don't want to do anything for them. app.Bind(wx.EVT_QUERY_END_SESSION, lambda evt: None) def onEndSession(evt): # NVDA will be terminated as soon as this function returns, so save configuration if appropriate. config.saveOnExit() speech.cancelSpeech() if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass log.info("Windows session ending") app.Bind(wx.EVT_END_SESSION, onEndSession) import braille log.debug("Initializing braille") braille.initialize() log.debug("Initializing braille input") import brailleInput brailleInput.initialize() import displayModel log.debug("Initializing displayModel") displayModel.initialize() log.debug("Initializing GUI") import gui gui.initialize() import audioDucking if audioDucking.isAudioDuckingSupported(): # the GUI mainloop must be running for this to work so delay it wx.CallAfter(audioDucking.initialize) # #3763: In wxPython 3, the class name of frame windows changed from wxWindowClassNR to wxWindowNR. # NVDA uses the main frame to check for and quit another instance of NVDA. # To remain compatible with older versions of NVDA, create our own wxWindowClassNR. # We don't need to do anything else because wx handles WM_QUIT for all windows. import windowUtils class MessageWindow(windowUtils.CustomWindow): className = u"wxWindowClassNR" messageWindow = MessageWindow(unicode(versionInfo.name)) # initialize wxpython localization support locale = wx.Locale() lang=languageHandler.getLanguage() wxLang=locale.FindLanguageInfo(lang) if not wxLang and '_' in lang: wxLang=locale.FindLanguageInfo(lang.split('_')[0]) if hasattr(sys,'frozen'): locale.AddCatalogLookupPathPrefix(os.path.join(os.getcwdu(),"locale")) if wxLang: try: locale.Init(wxLang.Language) except: log.error("Failed to initialize wx locale",exc_info=True) else: log.debugWarning("wx does not support language %s" % lang) import api import winUser import NVDAObjects.window desktopObject=NVDAObjects.window.Window(windowHandle=winUser.getDesktopWindow()) api.setDesktopObject(desktopObject) api.setFocusObject(desktopObject) api.setNavigatorObject(desktopObject) api.setMouseObject(desktopObject) import JABHandler log.debug("initializing Java Access Bridge support") try: JABHandler.initialize() except NotImplementedError: log.warning("Java Access Bridge not available") except: log.error("Error initializing Java Access Bridge support", exc_info=True) import winConsoleHandler log.debug("Initializing winConsole support") winConsoleHandler.initialize() import UIAHandler log.debug("Initializing UIA support") try: UIAHandler.initialize() except NotImplementedError: log.warning("UIA not available") except: log.error("Error initializing UIA support", exc_info=True) import IAccessibleHandler log.debug("Initializing IAccessible support") IAccessibleHandler.initialize() log.debug("Initializing input core") import inputCore inputCore.initialize() import keyboardHandler log.debug("Initializing keyboard handler") keyboardHandler.initialize() import mouseHandler log.debug("initializing mouse handler") mouseHandler.initialize() import touchHandler log.debug("Initializing touchHandler") try: touchHandler.initialize() except NotImplementedError: pass import globalPluginHandler log.debug("Initializing global plugin handler") globalPluginHandler.initialize() if globalVars.appArgs.install or globalVars.appArgs.installSilent: import wx import gui.installerGui wx.CallAfter(gui.installerGui.doSilentInstall,startAfterInstall=not globalVars.appArgs.installSilent) elif not globalVars.appArgs.minimal: try: # Translators: This is shown on a braille display (if one is connected) when NVDA starts. braille.handler.message(_("NVDA started")) except: log.error("", exc_info=True) if globalVars.appArgs.launcher: gui.LauncherDialog.run() # LauncherDialog will call doStartupDialogs() afterwards if required. else: wx.CallAfter(doStartupDialogs) import queueHandler # Queue the handling of initial focus, # as API handlers might need to be pumped to get the first focus event. queueHandler.queueFunction(queueHandler.eventQueue, _setInitialFocus) import watchdog import baseObject # Doing this here is a bit ugly, but we don't want these modules imported # at module level, including wx. log.debug("Initializing core pump") class CorePump(wx.Timer): "Checks the queues and executes functions." def Notify(self): global _isPumpPending _isPumpPending = False watchdog.alive() try: if touchHandler.handler: touchHandler.handler.pump() JABHandler.pumpAll() IAccessibleHandler.pumpAll() queueHandler.pumpAll() mouseHandler.pumpAll() braille.pumpAll() except: log.exception("errors in this core pump cycle") baseObject.AutoPropertyObject.invalidateCaches() watchdog.asleep() if _isPumpPending and not _pump.IsRunning(): # #3803: A pump was requested, but the timer was ignored by a modal loop # because timers aren't re-entrant. # Therefore, schedule another pump. _pump.Start(PUMP_MAX_DELAY, True) global _pump _pump = CorePump() requestPump() log.debug("Initializing watchdog") watchdog.initialize() try: import updateCheck except RuntimeError: updateCheck=None log.debug("Update checking not supported") else: log.debug("initializing updateCheck") updateCheck.initialize() log.info("NVDA initialized") log.debug("entering wx application main loop") app.MainLoop() log.info("Exiting") if updateCheck: _terminate(updateCheck) _terminate(watchdog) _terminate(globalPluginHandler, name="global plugin handler") _terminate(gui) config.saveOnExit() try: if globalVars.focusObject and hasattr(globalVars.focusObject,"event_loseFocus"): log.debug("calling lose focus on object with focus") globalVars.focusObject.event_loseFocus() except: log.exception("Lose focus error") try: speech.cancelSpeech() except: pass import treeInterceptorHandler _terminate(treeInterceptorHandler) _terminate(IAccessibleHandler, name="IAccessible support") _terminate(UIAHandler, name="UIA support") _terminate(winConsoleHandler, name="winConsole support") _terminate(JABHandler, name="Java Access Bridge support") _terminate(appModuleHandler, name="app module handler") _terminate(NVDAHelper) _terminate(touchHandler) _terminate(keyboardHandler, name="keyboard handler") _terminate(mouseHandler) _terminate(inputCore) _terminate(brailleInput) _terminate(braille) _terminate(speech) _terminate(addonHandler) if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass # #5189: Destroy the message window as late as possible # so new instances of NVDA can find this one even if it freezes during exit. messageWindow.destroy() log.debug("core done")
def main(): """NVDA's core main loop. This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI. Then it initialises the wx application object and installs the core pump timer, which checks the queues and executes functions every 1 ms. Finally, it starts the wx main loop. """ log.debug("Core starting") import config if not globalVars.appArgs.configPath: globalVars.appArgs.configPath=config.getUserDefaultConfigPath(useInstalledPathIfExists=globalVars.appArgs.launcher) #Initialize the config path (make sure it exists) config.initConfigPath() log.info("Config dir: %s"%os.path.abspath(globalVars.appArgs.configPath)) log.debug("loading config") import config config.load() if not globalVars.appArgs.minimal: try: nvwave.playWaveFile("waves\\start.wav") except: pass logHandler.setLogLevelFromConfig() try: lang = config.conf["general"]["language"] import languageHandler log.debug("setting language to %s"%lang) languageHandler.setLanguage(lang) except: log.warning("Could not set language to %s"%lang) import versionInfo log.info("NVDA version %s" % versionInfo.version) log.info("Using Windows version %r" % (sys.getwindowsversion(),)) log.info("Using Python version %s"%sys.version) log.info("Using comtypes version %s"%comtypes.__version__) # Set a reasonable timeout for any socket connections NVDA makes. import socket socket.setdefaulttimeout(10) log.debug("Initializing addons system.") addonHandler.initialize() import appModuleHandler log.debug("Initializing appModule Handler") appModuleHandler.initialize() import NVDAHelper log.debug("Initializing NVDAHelper") NVDAHelper.initialize() import speechDictHandler log.debug("Speech Dictionary processing") speechDictHandler.initialize() import speech log.debug("Initializing speech") speech.initialize() if not globalVars.appArgs.minimal and (time.time()-globalVars.startTime)>5: log.debugWarning("Slow starting core (%.2f sec)" % (time.time()-globalVars.startTime)) # Translators: This is spoken when NVDA is starting. speech.speakMessage(_("Loading NVDA. Please wait...")) import wx log.info("Using wx version %s"%wx.version()) app = wx.App(redirect=False) # HACK: wx currently raises spurious assertion failures when a timer is stopped but there is already an event in the queue for that timer. # Unfortunately, these assertion exceptions are raised in the middle of other code, which causes problems. # Therefore, disable assertions for now. app.SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS) # We do support QueryEndSession events, but we don't want to do anything for them. app.Bind(wx.EVT_QUERY_END_SESSION, lambda evt: None) def onEndSession(evt): # NVDA will be terminated as soon as this function returns, so save configuration if appropriate. config.saveOnExit() speech.cancelSpeech() if not globalVars.appArgs.minimal: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass log.info("Windows session ending") app.Bind(wx.EVT_END_SESSION, onEndSession) import braille log.debug("Initializing braille") braille.initialize() log.debug("Initializing braille input") import brailleInput brailleInput.initialize() import displayModel log.debug("Initializing displayModel") displayModel.initialize() log.debug("Initializing GUI") import gui gui.initialize() # initialize wxpython localization support locale = wx.Locale() lang=languageHandler.getLanguage() if '_' in lang: wxLang=lang.split('_')[0] else: wxLang=lang if hasattr(sys,'frozen'): locale.AddCatalogLookupPathPrefix(os.path.join(os.getcwdu(),"locale")) try: locale.Init(lang,wxLang) except: pass import api import winUser import NVDAObjects.window desktopObject=NVDAObjects.window.Window(windowHandle=winUser.getDesktopWindow()) api.setDesktopObject(desktopObject) api.setFocusObject(desktopObject) api.setNavigatorObject(desktopObject) api.setMouseObject(desktopObject) import JABHandler log.debug("initializing Java Access Bridge support") try: JABHandler.initialize() except NotImplementedError: log.warning("Java Access Bridge not available") except: log.error("Error initializing Java Access Bridge support", exc_info=True) import winConsoleHandler log.debug("Initializing winConsole support") winConsoleHandler.initialize() import UIAHandler log.debug("Initializing UIA support") try: UIAHandler.initialize() except NotImplementedError: log.warning("UIA not available") except: log.error("Error initializing UIA support", exc_info=True) import IAccessibleHandler log.debug("Initializing IAccessible support") IAccessibleHandler.initialize() log.debug("Initializing input core") import inputCore inputCore.initialize() import keyboardHandler log.debug("Initializing keyboard handler") keyboardHandler.initialize() import mouseHandler log.debug("initializing mouse handler") mouseHandler.initialize() import touchHandler log.debug("Initializing touchHandler") try: touchHandler.initialize() except NotImplementedError: pass import globalPluginHandler log.debug("Initializing global plugin handler") globalPluginHandler.initialize() if globalVars.appArgs.install: import wx import gui.installerGui wx.CallAfter(gui.installerGui.doSilentInstall) elif not globalVars.appArgs.minimal: try: # Translators: This is shown on a braille display (if one is connected) when NVDA starts. braille.handler.message(_("NVDA started")) except: log.error("", exc_info=True) if globalVars.appArgs.launcher: gui.LauncherDialog.run() # LauncherDialog will call doStartupDialogs() afterwards if required. else: wx.CallAfter(doStartupDialogs) import queueHandler # Queue the handling of initial focus, # as API handlers might need to be pumped to get the first focus event. queueHandler.queueFunction(queueHandler.eventQueue, _setInitialFocus) import watchdog import baseObject class CorePump(wx.Timer): "Checks the queues and executes functions." def __init__(self,*args,**kwargs): log.debug("Core pump starting") super(CorePump,self).__init__(*args,**kwargs) def Notify(self): try: JABHandler.pumpAll() IAccessibleHandler.pumpAll() queueHandler.pumpAll() mouseHandler.pumpAll() braille.pumpAll() except: log.exception("errors in this core pump cycle") baseObject.AutoPropertyObject.invalidateCaches() watchdog.alive() log.debug("starting core pump") pump = CorePump() pump.Start(1) log.debug("Initializing watchdog") watchdog.initialize() try: import updateCheck except RuntimeError: updateCheck=None log.debug("Update checking not supported") else: log.debug("initializing updateCheck") updateCheck.initialize() log.info("NVDA initialized") log.debug("entering wx application main loop") app.MainLoop() log.info("Exiting") if updateCheck: log.debug("Terminating updateCheck") updateCheck.terminate() log.debug("Terminating watchdog") watchdog.terminate() log.debug("Terminating global plugin handler") globalPluginHandler.terminate() log.debug("Terminating GUI") gui.terminate() config.saveOnExit() try: if globalVars.focusObject and hasattr(globalVars.focusObject,"event_loseFocus"): log.debug("calling lose focus on object with focus") globalVars.focusObject.event_loseFocus() except: log.error("Lose focus error",exc_info=True) try: speech.cancelSpeech() except: pass log.debug("Cleaning up running treeInterceptors") try: import treeInterceptorHandler treeInterceptorHandler.terminate() except: log.error("Error cleaning up treeInterceptors",exc_info=True) log.debug("Terminating IAccessible support") try: IAccessibleHandler.terminate() except: log.error("Error terminating IAccessible support",exc_info=True) log.debug("Terminating UIA support") try: UIAHandler.terminate() except: log.error("Error terminating UIA support",exc_info=True) log.debug("Terminating winConsole support") try: winConsoleHandler.terminate() except: log.error("Error terminating winConsole support",exc_info=True) log.debug("Terminating Java Access Bridge support") try: JABHandler.terminate() except: log.error("Error terminating Java Access Bridge support",exc_info=True) log.debug("Terminating app module handler") appModuleHandler.terminate() log.debug("Terminating NVDAHelper") try: NVDAHelper.terminate() except: log.error("Error terminating NVDAHelper",exc_info=True) log.debug("Terminating touchHandler") try: touchHandler.terminate() except: log.error("Error terminating touchHandler") log.debug("Terminating keyboard handler") try: keyboardHandler.terminate() except: log.error("Error terminating keyboard handler") log.debug("Terminating mouse handler") try: mouseHandler.terminate() except: log.error("error terminating mouse handler",exc_info=True) log.debug("Terminating input core") inputCore.terminate() log.debug("Terminating brailleInput") brailleInput.terminate() log.debug("Terminating braille") try: braille.terminate() except: log.error("Error terminating braille",exc_info=True) log.debug("Terminating speech") try: speech.terminate() except: log.error("Error terminating speech",exc_info=True) try: addonHandler.terminate() except: log.error("Error terminating addonHandler",exc_info=True) if not globalVars.appArgs.minimal: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass log.debug("core done")
def event_focusEntered(self): if self.role in (controlTypes.ROLE_MENUBAR,controlTypes.ROLE_POPUPMENU,controlTypes.ROLE_MENUITEM): speech.cancelSpeech() return if self.isPresentableFocusAncestor: speech.speakObject(self,reason=speech.REASON_FOCUSENTERED)
def main(): """NVDA's core main loop. This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI. Then it initialises the wx application object and sets up the core pump, which checks the queues and executes functions when requested. Finally, it starts the wx main loop. """ log.debug("Core starting") ctypes.windll.user32.SetProcessDPIAware() import config if not globalVars.appArgs.configPath: globalVars.appArgs.configPath=config.getUserDefaultConfigPath(useInstalledPathIfExists=globalVars.appArgs.launcher) #Initialize the config path (make sure it exists) config.initConfigPath() log.info("Config dir: %s"%os.path.abspath(globalVars.appArgs.configPath)) log.debug("loading config") import config config.initialize() if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\start.wav") except: pass logHandler.setLogLevelFromConfig() try: lang = config.conf["general"]["language"] import languageHandler log.debug("setting language to %s"%lang) languageHandler.setLanguage(lang) except: log.warning("Could not set language to %s"%lang) import versionInfo log.info("NVDA version %s" % versionInfo.version) log.info("Using Windows version %s" % winVersion.winVersionText) log.info("Using Python version %s"%sys.version) log.info("Using comtypes version %s"%comtypes.__version__) import configobj log.info("Using configobj version %s with validate version %s"%(configobj.__version__,configobj.validate.__version__)) # Set a reasonable timeout for any socket connections NVDA makes. import socket socket.setdefaulttimeout(10) log.debug("Initializing add-ons system") addonHandler.initialize() if globalVars.appArgs.disableAddons: log.info("Add-ons are disabled. Restart NVDA to enable them.") import appModuleHandler log.debug("Initializing appModule Handler") appModuleHandler.initialize() import NVDAHelper log.debug("Initializing NVDAHelper") NVDAHelper.initialize() import speechDictHandler log.debug("Speech Dictionary processing") speechDictHandler.initialize() import speech log.debug("Initializing speech") speech.initialize() if not globalVars.appArgs.minimal and (time.time()-globalVars.startTime)>5: log.debugWarning("Slow starting core (%.2f sec)" % (time.time()-globalVars.startTime)) # Translators: This is spoken when NVDA is starting. speech.speakMessage(_("Loading NVDA. Please wait...")) import wx # wxPython 4 no longer has either of these constants (despite the documentation saying so), some add-ons may rely on # them so we add it back into wx. https://wxpython.org/Phoenix/docs/html/wx.Window.html#wx.Window.Centre wx.CENTER_ON_SCREEN = wx.CENTRE_ON_SCREEN = 0x2 log.info("Using wx version %s"%wx.version()) class App(wx.App): def OnAssert(self,file,line,cond,msg): message="{file}, line {line}:\nassert {cond}: {msg}".format(file=file,line=line,cond=cond,msg=msg) log.debugWarning(message,codepath="WX Widgets",stack_info=True) app = App(redirect=False) # We support queryEndSession events, but in general don't do anything for them. # However, when running as a Windows Store application, we do want to request to be restarted for updates def onQueryEndSession(evt): if config.isAppX: # Automatically restart NVDA on Windows Store update ctypes.windll.kernel32.RegisterApplicationRestart(None,0) app.Bind(wx.EVT_QUERY_END_SESSION, onQueryEndSession) def onEndSession(evt): # NVDA will be terminated as soon as this function returns, so save configuration if appropriate. config.saveOnExit() speech.cancelSpeech() if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass log.info("Windows session ending") app.Bind(wx.EVT_END_SESSION, onEndSession) log.debug("Initializing braille input") import brailleInput brailleInput.initialize() import braille log.debug("Initializing braille") braille.initialize() import displayModel log.debug("Initializing displayModel") displayModel.initialize() log.debug("Initializing GUI") import gui gui.initialize() import audioDucking if audioDucking.isAudioDuckingSupported(): # the GUI mainloop must be running for this to work so delay it wx.CallAfter(audioDucking.initialize) # #3763: In wxPython 3, the class name of frame windows changed from wxWindowClassNR to wxWindowNR. # NVDA uses the main frame to check for and quit another instance of NVDA. # To remain compatible with older versions of NVDA, create our own wxWindowClassNR. # We don't need to do anything else because wx handles WM_QUIT for all windows. import windowUtils class MessageWindow(windowUtils.CustomWindow): className = u"wxWindowClassNR" #Just define these constants here, so we don't have to import win32con WM_POWERBROADCAST = 0x218 WM_DISPLAYCHANGE = 0x7e PBT_APMPOWERSTATUSCHANGE = 0xA UNKNOWN_BATTERY_STATUS = 0xFF AC_ONLINE = 0X1 NO_SYSTEM_BATTERY = 0X80 #States for screen orientation ORIENTATION_NOT_INITIALIZED = 0 ORIENTATION_PORTRAIT = 1 ORIENTATION_LANDSCAPE = 2 def __init__(self, windowName=None): super(MessageWindow, self).__init__(windowName) self.oldBatteryStatus = None self.orientationStateCache = self.ORIENTATION_NOT_INITIALIZED self.orientationCoordsCache = (0,0) self.handlePowerStatusChange() def windowProc(self, hwnd, msg, wParam, lParam): post_windowMessageReceipt.notify(msg=msg, wParam=wParam, lParam=lParam) if msg == self.WM_POWERBROADCAST and wParam == self.PBT_APMPOWERSTATUSCHANGE: self.handlePowerStatusChange() elif msg == self.WM_DISPLAYCHANGE: self.handleScreenOrientationChange(lParam) def handleScreenOrientationChange(self, lParam): import ui import winUser # Resolution detection comes from an article found at https://msdn.microsoft.com/en-us/library/ms812142.aspx. #The low word is the width and hiword is height. width = winUser.LOWORD(lParam) height = winUser.HIWORD(lParam) self.orientationCoordsCache = (width,height) if width > height: # If the height and width are the same, it's actually a screen flip, and we do want to alert of those! if self.orientationStateCache == self.ORIENTATION_LANDSCAPE and self.orientationCoordsCache != (width,height): return #Translators: The screen is oriented so that it is wider than it is tall. ui.message(_("Landscape" )) self.orientationStateCache = self.ORIENTATION_LANDSCAPE else: if self.orientationStateCache == self.ORIENTATION_PORTRAIT and self.orientationCoordsCache != (width,height): return #Translators: The screen is oriented in such a way that the height is taller than it is wide. ui.message(_("Portrait")) self.orientationStateCache = self.ORIENTATION_PORTRAIT def handlePowerStatusChange(self): #Mostly taken from script_say_battery_status, but modified. import ui import winKernel sps = winKernel.SYSTEM_POWER_STATUS() if not winKernel.GetSystemPowerStatus(sps) or sps.BatteryFlag is self.UNKNOWN_BATTERY_STATUS: return if sps.BatteryFlag & self.NO_SYSTEM_BATTERY: return if self.oldBatteryStatus is None: #Just initializing the cache, do not report anything. self.oldBatteryStatus = sps.ACLineStatus return if sps.ACLineStatus == self.oldBatteryStatus: #Sometimes, this double fires. This also fires when the battery level decreases by 3%. return self.oldBatteryStatus = sps.ACLineStatus if sps.ACLineStatus & self.AC_ONLINE: #Translators: Reported when the battery is plugged in, and now is charging. ui.message(_("Charging battery. %d percent") % sps.BatteryLifePercent) else: #Translators: Reported when the battery is no longer plugged in, and now is not charging. ui.message(_("Not charging battery. %d percent") %sps.BatteryLifePercent) messageWindow = MessageWindow(unicode(versionInfo.name)) # initialize wxpython localization support locale = wx.Locale() lang=languageHandler.getLanguage() wxLang=locale.FindLanguageInfo(lang) if not wxLang and '_' in lang: wxLang=locale.FindLanguageInfo(lang.split('_')[0]) if hasattr(sys,'frozen'): locale.AddCatalogLookupPathPrefix(os.path.join(os.getcwdu(),"locale")) # #8064: Wx might know the language, but may not actually contain a translation database for that language. # If we try to initialize this language, wx will show a warning dialog. # Therefore treat this situation like wx not knowing the language at all. if not locale.IsAvailable(wxLang.Language): wxLang=None if wxLang: try: locale.Init(wxLang.Language) except: log.error("Failed to initialize wx locale",exc_info=True) else: log.debugWarning("wx does not support language %s" % lang) import api import winUser import NVDAObjects.window desktopObject=NVDAObjects.window.Window(windowHandle=winUser.getDesktopWindow()) api.setDesktopObject(desktopObject) api.setFocusObject(desktopObject) api.setNavigatorObject(desktopObject) api.setMouseObject(desktopObject) import JABHandler log.debug("initializing Java Access Bridge support") try: JABHandler.initialize() except NotImplementedError: log.warning("Java Access Bridge not available") except: log.error("Error initializing Java Access Bridge support", exc_info=True) import winConsoleHandler log.debug("Initializing winConsole support") winConsoleHandler.initialize() import UIAHandler log.debug("Initializing UIA support") try: UIAHandler.initialize() except NotImplementedError: log.warning("UIA not available") except: log.error("Error initializing UIA support", exc_info=True) import IAccessibleHandler log.debug("Initializing IAccessible support") IAccessibleHandler.initialize() log.debug("Initializing input core") import inputCore inputCore.initialize() import keyboardHandler log.debug("Initializing keyboard handler") keyboardHandler.initialize() import mouseHandler log.debug("initializing mouse handler") mouseHandler.initialize() import touchHandler log.debug("Initializing touchHandler") try: touchHandler.initialize() except NotImplementedError: pass import globalPluginHandler log.debug("Initializing global plugin handler") globalPluginHandler.initialize() if globalVars.appArgs.install or globalVars.appArgs.installSilent: import gui.installerGui wx.CallAfter(gui.installerGui.doSilentInstall,startAfterInstall=not globalVars.appArgs.installSilent) elif globalVars.appArgs.portablePath and (globalVars.appArgs.createPortable or globalVars.appArgs.createPortableSilent): import gui.installerGui wx.CallAfter(gui.installerGui.doCreatePortable,portableDirectory=globalVars.appArgs.portablePath, silent=globalVars.appArgs.createPortableSilent,startAfterCreate=not globalVars.appArgs.createPortableSilent) elif not globalVars.appArgs.minimal: try: # Translators: This is shown on a braille display (if one is connected) when NVDA starts. braille.handler.message(_("NVDA started")) except: log.error("", exc_info=True) if globalVars.appArgs.launcher: gui.LauncherDialog.run() # LauncherDialog will call doStartupDialogs() afterwards if required. else: wx.CallAfter(doStartupDialogs) import queueHandler # Queue the handling of initial focus, # as API handlers might need to be pumped to get the first focus event. queueHandler.queueFunction(queueHandler.eventQueue, _setInitialFocus) import watchdog import baseObject # Doing this here is a bit ugly, but we don't want these modules imported # at module level, including wx. log.debug("Initializing core pump") class CorePump(gui.NonReEntrantTimer): "Checks the queues and executes functions." def run(self): global _isPumpPending _isPumpPending = False watchdog.alive() try: if touchHandler.handler: touchHandler.handler.pump() JABHandler.pumpAll() IAccessibleHandler.pumpAll() queueHandler.pumpAll() mouseHandler.pumpAll() braille.pumpAll() except: log.exception("errors in this core pump cycle") baseObject.AutoPropertyObject.invalidateCaches() watchdog.asleep() if _isPumpPending and not _pump.IsRunning(): # #3803: Another pump was requested during this pump execution. # As our pump is not re-entrant, schedule another pump. _pump.Start(PUMP_MAX_DELAY, True) global _pump _pump = CorePump() requestPump() log.debug("Initializing watchdog") watchdog.initialize() try: import updateCheck except RuntimeError: updateCheck=None log.debug("Update checking not supported") else: log.debug("initializing updateCheck") updateCheck.initialize() log.info("NVDA initialized") postNvdaStartup.notify() log.debug("entering wx application main loop") app.MainLoop() log.info("Exiting") if updateCheck: _terminate(updateCheck) _terminate(watchdog) _terminate(globalPluginHandler, name="global plugin handler") _terminate(gui) config.saveOnExit() try: if globalVars.focusObject and hasattr(globalVars.focusObject,"event_loseFocus"): log.debug("calling lose focus on object with focus") globalVars.focusObject.event_loseFocus() except: log.exception("Lose focus error") try: speech.cancelSpeech() except: pass import treeInterceptorHandler _terminate(treeInterceptorHandler) _terminate(IAccessibleHandler, name="IAccessible support") _terminate(UIAHandler, name="UIA support") _terminate(winConsoleHandler, name="winConsole support") _terminate(JABHandler, name="Java Access Bridge support") _terminate(appModuleHandler, name="app module handler") _terminate(NVDAHelper) _terminate(touchHandler) _terminate(keyboardHandler, name="keyboard handler") _terminate(mouseHandler) _terminate(inputCore) _terminate(brailleInput) _terminate(braille) _terminate(speech) _terminate(addonHandler) if not globalVars.appArgs.minimal and config.conf["general"]["playStartAndExitSounds"]: try: nvwave.playWaveFile("waves\\exit.wav",async=False) except: pass # #5189: Destroy the message window as late as possible # so new instances of NVDA can find this one even if it freezes during exit. messageWindow.destroy() log.debug("core done")
def event_nameChange(self, obj, nextHandler): # #49: reported by a user: on some systems, touch keyboard keys keeps firing name change event. # Argh, in build 17704, whenever skin tones are selected, name change is fired by emoji entries (GridViewItem). if ((obj.UIAElement.cachedClassName in ("CRootKey", "GridViewItem")) or (obj.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemsList") # And no, emoji entries should not be announced here. or (self._recentlySelected is not None and self._recentlySelected in obj.name)): return # The word "blank" is kept announced, so suppress this on build 17666 and later. if winVersion.winVersion.build > 17134: # In build 17672 and later, return immediatley when element selected event on clipboard item was fired just prior to this. if obj.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemIndex" or obj.parent.UIAElement.cachedAutomationID == "TEMPLATE_PART_ClipboardItemsList": return if not self._emojiPanelJustOpened or obj.UIAElement.cachedAutomationID != "TEMPLATE_PART_ExpressionGroupedFullView": speech.cancelSpeech() self._emojiPanelJustOpened = False # Don't forget to add "Microsoft Candidate UI" as something that should be suppressed. if obj.UIAElement.cachedAutomationID not in ("TEMPLATE_PART_ExpressionFullViewItemsGrid", "TEMPLATE_PART_ClipboardItemIndex", "CandidateWindowControl"): ui.message(obj.name) nextHandler()
def event_UIA_elementSelected(self): speech.cancelSpeech() api.setNavigatorObject(self, isFocus=True) self.reportFocus() super(SuggestionListItem,self).event_UIA_elementSelected()
def event_gainFocus(self): # In Windows XP, the Start button will get focus first, so silence this. speech.cancelSpeech() super(ClassicStartMenu, self).event_gainFocus()
def event_foreground(self): """Called when the foreground window changes. This method should only perform tasks specific to the foreground window changing. L{event_focusEntered} or L{event_gainFocus} will be called for this object, so this method should not speak/braille the object, etc. """ speech.cancelSpeech()
def handle_nvda_not_connected(self): speech.cancelSpeech() ui.message(_("Remote NVDA not connected."))