def onFocus(self, event): """Callback for focus: accessibility events.""" # NOTE: This event type is deprecated and Orca should no longer use it. # This callback remains just to handle bugs in applications and toolkits # that fail to reliably emit object:state-changed:focused events. if self.utilities.isLayoutOnly(event.source): return if self.utilities.isTypeahead(orca_state.locusOfFocus) \ and "Table" in pyatspi.listInterfaces(event.source) \ and not event.source.getState().contains(pyatspi.STATE_FOCUSED): return ancestor = pyatspi.findAncestor(orca_state.locusOfFocus, lambda x: x == event.source) if not ancestor: orca.setLocusOfFocus(event, event.source) return if ancestor and "Table" in pyatspi.listInterfaces(ancestor): return isMenu = lambda x: x and x.getRole() == pyatspi.ROLE_MENU if isMenu(ancestor) and not pyatspi.findAncestor(ancestor, isMenu): return orca.setLocusOfFocus(event, event.source)
def onFocus(self, event): """Callback for focus: accessibility events.""" # NOTE: This event type is deprecated and Orca should no longer use it. # This callback remains just to handle bugs in applications and toolkits # that fail to reliably emit object:state-changed:focused events. if self.utilities.eventIsCanvasNoise(event): return if self.utilities.isLayoutOnly(event.source): return if self.utilities.isTypeahead(orca_state.locusOfFocus) \ and "Table" in pyatspi.listInterfaces(event.source) \ and not event.source.getState().contains(pyatspi.STATE_FOCUSED): return ancestor = pyatspi.findAncestor(orca_state.locusOfFocus, lambda x: x == event.source) if not ancestor: orca.setLocusOfFocus(event, event.source) return if ancestor and "Table" in pyatspi.listInterfaces(ancestor): return isMenu = lambda x: x and x.getRole() == pyatspi.ROLE_MENU if isMenu(ancestor) and not pyatspi.findAncestor(ancestor, isMenu): return orca.setLocusOfFocus(event, event.source)
def isDocumentCell(self, cell): isCell = lambda x: x and x.getRole() == pyatspi.ROLE_TABLE_CELL if not isCell(cell): cell = pyatspi.findAncestor(cell, isCell) if not cell or self.isSpreadSheetCell(cell): return False isDocument = lambda x: x and x.getRole() == pyatspi.ROLE_DOCUMENT_FRAME return pyatspi.findAncestor(cell, isDocument) != None
def _on_mouse_moved(self, event): """Callback for mouse:abs events.""" screen, pX, pY = self._pointer.get_position() window = self._accessible_window_at_point(pX, pY) msg = "MOUSE REVIEW: Window at (%i, %i) is %s" % (pX, pY, window) debug.println(debug.LEVEL_INFO, msg, True) if not window: return script = orca_state.activeScript if not script: return isMenu = lambda x: x and x.getRole() == pyatspi.ROLE_MENU if isMenu(orca_state.locusOfFocus): menu = orca_state.locusOfFocus else: menu = pyatspi.findAncestor(orca_state.locusOfFocus, isMenu) obj = script.utilities.descendantAtPoint(menu, pX, pY) \ or script.utilities.descendantAtPoint(window, pX, pY) msg = "MOUSE REVIEW: Object at (%i, %i) is %s" % (pX, pY, obj) debug.println(debug.LEVEL_INFO, msg, True) script = _scriptManager.getScript(window.getApplication(), obj) new = _ItemContext(pX, pY, obj, window, script) new.present(self._currentMouseOver) self._currentMouseOver = new
def locateInputLine(self, obj): """Return the spread sheet input line. This only needs to be found the very first time a spread sheet table cell gets focus. We use the table cell to work back up the component hierarchy until we have found the common panel that both it and the input line reside in. We then use that as the base component to search for a component which has a paragraph role. This will be the input line. Arguments: - obj: the spread sheet table cell that has just got focus. Returns the spread sheet input line component. """ if self._script.inputLineForCell: return self._script.inputLineForCell isScrollPane = lambda x: x and x.getRole() == pyatspi.ROLE_SCROLL_PANE scrollPane = pyatspi.findAncestor(obj, isScrollPane) if not scrollPane: return None toolbar = None for child in scrollPane.parent: if child and child.getRole() == pyatspi.ROLE_TOOL_BAR: toolbar = child break isParagraph = lambda x: x and x.getRole() == pyatspi.ROLE_PARAGRAPH allParagraphs = pyatspi.findAllDescendants(toolbar, isParagraph) if len(allParagraphs) == 1: self._script.inputLineForCell = allParagraphs[0] return self._script.inputLineForCell
def _generateName(self, obj, **args): if not self._script.utilities.inDocumentContent(obj): return super()._generateName(obj, **args) brailleLabel = self._script.utilities.objectAttributes(obj).get( "braillelabel") if brailleLabel: return [brailleLabel] if self._script.utilities.preferDescriptionOverName(obj): return [obj.description] if obj.name and not self._script.utilities.hasValidName(obj): return [] result = super()._generateName(obj, **args) if result and result[0] and not self._script.utilities.hasExplicitName( obj): result[0] = result[0].strip() elif not result and obj.getRole() == pyatspi.ROLE_CHECK_BOX: gridCell = pyatspi.findAncestor(obj, self._script.utilities.isGridCell) if gridCell: return super()._generateName(gridCell, **args) return result
def _containingDocument(obj): roles = [pyatspi.ROLE_DOCUMENT_EMAIL, pyatspi.ROLE_DOCUMENT_FRAME, pyatspi.ROLE_DOCUMENT_PRESENTATION, pyatspi.ROLE_DOCUMENT_SPREADSHEET, pyatspi.ROLE_DOCUMENT_TEXT, pyatspi.ROLE_DOCUMENT_WEB] isDocument = lambda x: x and x.getRole() in roles document = pyatspi.findAncestor(obj, isDocument) while document: ancestor = pyatspi.findAncestor(document, isDocument) if not ancestor or ancestor == document: break document = ancestor return document
def locusOfFocusChanged(self, event, oldFocus, newFocus): """Handles changes of focus of interest to the script.""" if self.utilities.isToggleDescendantOfComboBox(newFocus): isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX newFocus = pyatspi.findAncestor(newFocus, isComboBox) or newFocus super().locusOfFocusChanged(event, oldFocus, newFocus)
def _getContainer(self): roles = [ pyatspi.ROLE_DIALOG, pyatspi.ROLE_FRAME, pyatspi.ROLE_LAYERED_PANE, pyatspi.ROLE_MENU, pyatspi.ROLE_PAGE_TAB, pyatspi.ROLE_TOOL_BAR, pyatspi.ROLE_WINDOW ] isContainer = lambda x: x and x.getRole() in roles return pyatspi.findAncestor(self._obj, isContainer)
def _isOrIsIn(self, child, parent): if not (child and parent): return False if child == parent: return True return pyatspi.findAncestor(child, lambda x: x == parent)
def isEntryCompletionPopupItem(self, obj): if obj.getRole() == pyatspi.ROLE_TABLE_CELL: isWindow = lambda x: x and x.getRole() == pyatspi.ROLE_WINDOW window = pyatspi.findAncestor(obj, isWindow) if window: return True return False
def locusOfFocusChanged(self, event, oldFocus, newFocus): """Handles changes of focus of interest to the script.""" if self.utilities.isToggleDescendantOfComboBox(newFocus): isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX newFocus = pyatspi.findAncestor(newFocus, isComboBox) or newFocus orca.setLocusOfFocus(event, newFocus, False) super().locusOfFocusChanged(event, oldFocus, newFocus)
def _generateRoleName(self, obj, **args): """Prevents some roles from being displayed.""" if not self._script.utilities.inDocumentContent(obj): return super()._generateRoleName(obj, **args) roledescription = self._script.utilities.getRoleDescription(obj, True) if roledescription: return [roledescription] doNotDisplay = [ pyatspi.ROLE_FORM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_STATIC, pyatspi.ROLE_SECTION, pyatspi.ROLE_REDUNDANT_OBJECT, pyatspi.ROLE_UNKNOWN ] state = obj.getState() if not state.contains(pyatspi.STATE_FOCUSABLE): doNotDisplay.extend([ pyatspi.ROLE_LIST, pyatspi.ROLE_LIST_ITEM, pyatspi.ROLE_COLUMN_HEADER, pyatspi.ROLE_ROW_HEADER, pyatspi.ROLE_TABLE_CELL, pyatspi.ROLE_PANEL ]) if args.get('startOffset') is not None and args.get( 'endOffset') is not None: doNotDisplay.append(pyatspi.ROLE_ALERT) result = [] role = args.get('role', obj.getRole()) if role == pyatspi.ROLE_HEADING: level = self._script.utilities.headingLevel(obj) result.append(object_properties.ROLE_HEADING_LEVEL_BRAILLE % level) elif self._script.utilities.isLink( obj) and obj == orca_state.locusOfFocus: if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) elif role not in doNotDisplay: label = self._script.utilities.labelForCellCoordinates(obj) if label: result.append(label) else: result = super()._generateRoleName(obj, **args) index = args.get('index', 0) total = args.get('total', 1) if index == total - 1 and role != pyatspi.ROLE_HEADING \ and (role == pyatspi.ROLE_IMAGE or self._script.utilities.queryNonEmptyText(obj)): isHeading = lambda x: x and x.getRole() == pyatspi.ROLE_HEADING heading = pyatspi.findAncestor(obj, isHeading) if heading: result.extend(self._generateRoleName(heading)) return result
def isFocusedChat(self, obj): """Returns True if we plan to treat this chat as focused.""" isPageTab = lambda x: x and x.getRole() == pyatspi.ROLE_PAGE_TAB pageTab = pyatspi.findAncestor(obj, isPageTab) if pageTab is None: return super().isFocusedChat(obj) return pageTab.getState().contains(pyatspi.STATE_SHOWING)
def _generateListBoxItemWidgets(self, obj, **args): # The list which descends from a combobox should be a menu, and its children # menuitems. We can remove this once that change is made in Chromium. if pyatspi.findAncestor(obj, lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX): msg = "CHROMIUM: Not generating listbox item widgets for combobox child %s" % obj debug.println(debug.LEVEL_INFO, msg, True) return [] return super()._generateListBoxItemWidgets(obj, **args)
def _findErrorWidget(self, root): isPanel = lambda x: x and x.getRole() == pyatspi.ROLE_PANEL panel = pyatspi.findAncestor(self._changeToEntry, isPanel) if not panel: return None isError = lambda x: x and x.getRole() == pyatspi.ROLE_LABEL \ and not ":" in x.name and not x.getRelationSet() return pyatspi.findDescendant(panel, isError)
def onFocus(self, event): """Callback for focus: accessibility events.""" # NOTE: This event type is deprecated and Orca should no longer use it. # This callback remains just to handle bugs in applications and toolkits # that fail to reliably emit object:state-changed:focused events. if self.utilities.eventIsCanvasNoise(event): return if self.utilities.isLayoutOnly(event.source): return if event.source == mouse_review.reviewer.getCurrentItem(): msg = "GTK: Event source is current mouse review item" debug.println(debug.LEVEL_INFO, msg, True) return if self.utilities.isTypeahead(orca_state.locusOfFocus) \ and "Table" in pyatspi.listInterfaces(event.source) \ and not event.source.getState().contains(pyatspi.STATE_FOCUSED): return if "Table" in pyatspi.listInterfaces(event.source): selectedChildren = self.utilities.selectedChildren(event.source) if selectedChildren: orca.setLocusOfFocus(event, selectedChildren[0]) return ancestor = pyatspi.findAncestor(orca_state.locusOfFocus, lambda x: x == event.source) if not ancestor: orca.setLocusOfFocus(event, event.source) return if ancestor and "Table" in pyatspi.listInterfaces(ancestor): return isMenu = lambda x: x and x.getRole() == pyatspi.ROLE_MENU if isMenu(ancestor) and not pyatspi.findAncestor(ancestor, isMenu): return orca.setLocusOfFocus(event, event.source)
def _getContainer(self): roles = [pyatspi.ROLE_DIALOG, pyatspi.ROLE_FRAME, pyatspi.ROLE_LAYERED_PANE, pyatspi.ROLE_MENU, pyatspi.ROLE_PAGE_TAB, pyatspi.ROLE_TOOL_BAR, pyatspi.ROLE_WINDOW] isContainer = lambda x: x and x.getRole() in roles return pyatspi.findAncestor(self._obj, isContainer)
def _get_win(self, event): if 'selenium-server/core/Blank.html' in event.source.name: frame = pyatspi.findAncestor( event.source, lambda x: x.getRole() == pyatspi.ROLE_FRAME) if frame: print 'TOP FRAME:', frame pyatspi.Registry.deregisterEventListener( self._get_win, 'document:load-complete') self._top_frame = frame
def _adjustObject(self, obj): """We want to treat text objects inside list items and table cells as list items and table cells. """ if obj.getState().contains(pyatspi.STATE_FOCUSED): return obj roles = [pyatspi.ROLE_TABLE_CELL, pyatspi.ROLE_LIST_ITEM] ancestor = pyatspi.findAncestor(obj, lambda x: x and x.getRole() in roles) if ancestor and not self._script.utilities.isLayoutOnly(ancestor.parent): obj = ancestor return obj
def _generateTableCellRow(self, obj, **args): if not self._script.inFocusMode(): return super()._generateTableCellRow(obj, **args) if not self._script.utilities.shouldReadFullRow(obj): return self._generateRealTableCell(obj, **args) isRow = lambda x: x and x.getRole() == pyatspi.ROLE_TABLE_ROW row = pyatspi.findAncestor(obj, isRow) if row and row.name: return self.generate(row) return super()._generateTableCellRow(obj, **args)
def _generateTableCellRow(self, obj, **args): if not self._script.inFocusMode(): return super()._generateTableCellRow(obj, **args) if not self._script.utilities.shouldReadFullRow(obj): return self._generateRealTableCell(obj, **args) isRow = lambda x: x and x.getRole() == pyatspi.ROLE_TABLE_ROW row = pyatspi.findAncestor(obj, isRow) if row and row.name and not self._script.utilities.isLayoutOnly(row): return self.generate(row) return super()._generateTableCellRow(obj, **args)
def __init__(self, script): """Create a new Context for script.""" self.script = script self.zones = [] self.lines = [] self.lineIndex = 0 self.zoneIndex = 0 self.wordIndex = 0 self.charIndex = 0 self.targetCharInfo = None self.focusZone = None self.container = None self.focusObj = orca_state.locusOfFocus self.topLevel = script.utilities.topLevelObject(self.focusObj) self.bounds = 0, 0, 0, 0 try: component = self.topLevel.queryComponent() self.bounds = component.getExtents(pyatspi.DESKTOP_COORDS) except: msg = "ERROR: Exception getting extents of %s" % self.topLevel debug.println(debug.LEVEL_INFO, msg, True) containerRoles = [pyatspi.ROLE_MENU] isContainer = lambda x: x and x.getRole() in containerRoles container = pyatspi.findAncestor(self.focusObj, isContainer) if not container and isContainer(self.focusObj): container = self.focusObj self.container = container or self.topLevel self.zones, self.focusZone = self.getShowingZones(self.container) self.lines = self.clusterZonesByLine(self.zones) if not (self.lines and self.focusZone): return for i, line in enumerate(self.lines): if self.focusZone in line.zones: self.lineIndex = i self.zoneIndex = line.zones.index(self.focusZone) word, offset = self.focusZone.wordWithCaret() if word: self.wordIndex = word.index self.charIndex = offset break msg = "FLAT REVIEW: On line %i, zone %i, word %i, char %i" % \ (self.lineIndex, self.zoneIndex, self.wordIndex, self.charIndex) debug.println(debug.LEVEL_INFO, msg, True)
def _generateRoleName(self, obj, **args): """Prevents some roles from being displayed.""" roledescription = self._script.utilities.getRoleDescription(obj) if roledescription: return [roledescription] doNotDisplay = [pyatspi.ROLE_FORM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_STATIC, pyatspi.ROLE_SECTION, pyatspi.ROLE_REDUNDANT_OBJECT, pyatspi.ROLE_UNKNOWN] state = obj.getState() if not state.contains(pyatspi.STATE_FOCUSABLE): doNotDisplay.extend([pyatspi.ROLE_LIST, pyatspi.ROLE_LIST_ITEM, pyatspi.ROLE_COLUMN_HEADER, pyatspi.ROLE_ROW_HEADER, pyatspi.ROLE_TABLE_CELL, pyatspi.ROLE_PANEL]) if args.get('startOffset') is not None and args.get('endOffset') is not None: doNotDisplay.append(pyatspi.ROLE_ALERT) result = [] role = args.get('role', obj.getRole()) if role == pyatspi.ROLE_HEADING: level = self._script.utilities.headingLevel(obj) result.append(object_properties.ROLE_HEADING_LEVEL_BRAILLE % level) elif self._script.utilities.isLink(obj) and obj == orca_state.locusOfFocus: if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) elif role not in doNotDisplay: result = super()._generateRoleName(obj, **args) index = args.get('index', 0) total = args.get('total', 1) if index == total - 1 and role != pyatspi.ROLE_HEADING \ and (role == pyatspi.ROLE_IMAGE or self._script.utilities.queryNonEmptyText(obj)): isHeading = lambda x: x and x.getRole() == pyatspi.ROLE_HEADING heading = pyatspi.findAncestor(obj, isHeading) if heading: result.extend(self._generateRoleName(heading)) return result
def _adjustObject(self, obj): """We want to treat text objects inside list items and table cells as list items and table cells. """ if obj.getState().contains(pyatspi.STATE_FOCUSED): return obj roles = [pyatspi.ROLE_TABLE_CELL, pyatspi.ROLE_LIST_ITEM] ancestor = pyatspi.findAncestor(obj, lambda x: x and x.getRole() in roles) if ancestor and not self._script.utilities.isLayoutOnly( ancestor.parent): obj = ancestor return obj
def locusOfFocusChanged(self, event, oldFocus, newFocus): """Handles changes of focus of interest to the script.""" if self.utilities.isToggleDescendantOfComboBox(newFocus): isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX newFocus = pyatspi.findAncestor(newFocus, isComboBox) or newFocus orca.setLocusOfFocus(event, newFocus, False) elif self.utilities.isInOpenMenuBarMenu(newFocus): window = self.utilities.topLevelObject(newFocus) windowChanged = window and orca_state.activeWindow != window if windowChanged: orca_state.activeWindow = window self.windowActivateTime = time.time() super().locusOfFocusChanged(event, oldFocus, newFocus)
def onCheckedChanged(self, event): """Callback for object:state-changed:checked accessibility events.""" obj = event.source if self.utilities.isSameObject(obj, orca_state.locusOfFocus): default.Script.onCheckedChanged(self, event) return # Present changes of child widgets of GtkListBox items isListBox = lambda x: x and x.getRole() == pyatspi.ROLE_LIST_BOX if not pyatspi.findAncestor(obj, isListBox): return self.updateBraille(obj) speech.speak(self.speechGenerator.generateSpeech(obj, alreadyFocused=True))
def isToggleDescendantOfComboBox(self, obj): if not (obj and obj.getRole() == pyatspi.ROLE_TOGGLE_BUTTON): return False rv = self._isToggleDescendantOfComboBox.get(hash(obj)) if rv is not None: return rv isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX comboBox = pyatspi.findAncestor(obj, isComboBox) if comboBox: self._isComboBoxWithToggleDescendant[hash(comboBox)] = True rv = comboBox is not None self._isToggleDescendantOfComboBox[hash(obj)] = rv return rv
def unrelatedLabels(self, root, onlyShowing=True, minimumWords=3): if not root: return [] roles = [ pyatspi.ROLE_DIALOG, pyatspi.ROLE_NOTIFICATION, pyatspi.ROLE_MENU_ITEM ] hasRole = lambda x: x and x.getRole() in roles if not hasRole(root) and pyatspi.findAncestor(root, hasRole) is None: msg = "GNOME SHELL: Not seeking unrelated labels for %s" % root debug.println(debug.LEVEL_INFO, msg, True) return [] return super().unrelatedLabels(root, onlyShowing, minimumWords)
def locateInputLine(self, obj): """Return the spread sheet input line. This only needs to be found the very first time a spread sheet table cell gets focus. We use the table cell to work back up the component hierarchy until we have found the common panel that both it and the input line reside in. We then use that as the base component to search for a component which has a paragraph role. This will be the input line. Arguments: - obj: the spread sheet table cell that has just got focus. Returns the spread sheet input line component. """ if self._script.inputLineForCell: try: topLevel = self.topLevelObject(self._script.inputLineForCell) except: msg = "ERROR: Exception getting topLevelObject for inputline" debug.println(debug.LEVEL_INFO, msg, True) self._script.inputLineForCell = None else: if self.isSameObject(orca_state.activeWindow, topLevel): return self._script.inputLineForCell isScrollPane = lambda x: x and x.getRole() == pyatspi.ROLE_SCROLL_PANE scrollPane = pyatspi.findAncestor(obj, isScrollPane) if not scrollPane: return None toolbar = None for child in scrollPane.parent: if child and child.getRole() == pyatspi.ROLE_TOOL_BAR: toolbar = child break if not toolbar: msg = "ERROR: Calc inputline toolbar not found." debug.println(debug.LEVEL_INFO, msg, True) return None isParagraph = lambda x: x and x.getRole() == pyatspi.ROLE_PARAGRAPH allParagraphs = pyatspi.findAllDescendants(toolbar, isParagraph) if len(allParagraphs) == 1: self._script.inputLineForCell = allParagraphs[0] return self._script.inputLineForCell
def inFindContainer(self, obj=None): if not obj: obj = orca_state.locusOfFocus if not obj or self.inDocumentContent(obj): return False if obj.getRole() not in [pyatspi.ROLE_ENTRY, pyatspi.ROLE_PUSH_BUTTON]: return False isDialog = lambda x: x and x.getRole() == pyatspi.ROLE_DIALOG result = self.isFindContainer(pyatspi.findAncestor(obj, isDialog)) if result: msg = "CHROMIUM: %s believed to be find-in-page widget" % obj debug.println(debug.LEVEL_INFO, msg, True) return result
def containingComboBox(self, obj): isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX if isComboBox(obj): comboBox = obj else: comboBox = pyatspi.findAncestor(obj, isComboBox) if not comboBox: return None if not self.isZombie(comboBox): return comboBox try: parent = comboBox.parent except: pass else: replicant = self.findReplicant(parent, comboBox) if replicant and not self.isZombie(replicant): comboBox = replicant return comboBox
def _generateOldAncestors(self, obj, **args): """Returns an array of strings (and possibly voice and audio specifications) that represent the text of the ancestors for the object being left.""" priorObj = args.get('priorObj', None) if not priorObj: return [] if self._script.utilities.isSpreadSheetCell(priorObj): return [] isTable = lambda x: x and x.getRole() == pyatspi.ROLE_TABLE oldTable = pyatspi.findAncestor(priorObj, isTable) if oldTable: ancestor = self._script.utilities.commonAncestor(oldTable, obj) if ancestor and ancestor.getRole() == pyatspi.ROLE_DOCUMENT_FRAME: result = [messages.TABLE_LEAVING] result.extend(self.voice(speech_generator.SYSTEM)) result.extend(self._generatePause(obj, **args)) return result return speech_generator.SpeechGenerator._generateOldAncestors( self, obj, **args)
def inFindContainer(self, obj=None): if not obj: obj = orca_state.locusOfFocus if not obj or self.inDocumentContent(obj): return False if obj.getRole() not in [pyatspi.ROLE_ENTRY, pyatspi.ROLE_PUSH_BUTTON]: return False isToolbar = lambda x: x and x.getRole() == pyatspi.ROLE_TOOL_BAR toolbar = pyatspi.findAncestor(obj, isToolbar) result = self.isFindContainer(toolbar) if result: msg = "GECKO: %s believed to be find-in-page widget (toolbar)" % obj debug.println(debug.LEVEL_INFO, msg, True) return True if self._isQuickFind(toolbar): msg = "GECKO: %s believed to be find-in-page widget (quick find)" % obj debug.println(debug.LEVEL_INFO, msg, True) return True return False
def inferFromTable(self, obj, proximityForRight=50): """Attempt to infer the functional/displayed label of obj by looking at the contents of the surrounding table cells. Note that this approach assumes a simple table in which the widget is the sole occupant of its cell. Arguments - obj: the unlabeled widget Returns the text which we think is the label, or None. """ cell = pyatspi.findAncestor(obj, self._isCell) if not self._isSimpleObject(cell): return None, [] if not cell in [obj.parent, obj.parent.parent]: return None, [] grid = pyatspi.findAncestor(cell, self._isTable) if not grid: return None, [] cellLeft = cellRight = cellAbove = cellBelow = None gridrow = pyatspi.findAncestor(cell, self._isRow) rowindex, colindex = self._script.utilities.coordinatesForCell(cell) if colindex > -1: cellLeft = self._getCellFromTable(grid, rowindex, colindex - 1) cellRight = self._getCellFromTable(grid, rowindex, colindex + 1) cellAbove = self._getCellFromTable(grid, rowindex - 1, colindex) cellBelow = self._getCellFromTable(grid, rowindex + 1, colindex) elif gridrow and cell.parent == gridrow: cellindex = cell.getIndexInParent() cellLeft = self._getCellFromRow(gridrow, cellindex - 1) cellRight = self._getCellFromRow(gridrow, cellindex + 1) rowindex = gridrow.getIndexInParent() if rowindex > 0: cellAbove = self._getCellFromRow(gridrow.parent[rowindex - 1], cellindex) if rowindex + 1 < grid.childCount: cellBelow = self._getCellFromRow(gridrow.parent[rowindex + 1], cellindex) if cellLeft and not self._preferRight(obj): label, sources = self._createLabelFromContents(cellLeft) if label: return label.strip(), sources objX, objY, objWidth, objHeight = self._getExtents(obj) if cellRight and not self._preventRight(obj): x, y, width, height = self._getExtents(cellRight) distance = x - (objX + objWidth) if distance <= proximityForRight or self._preferRight(obj): label, sources = self._createLabelFromContents(cellRight) if label: return label.strip(), sources labelAbove = labelBelow = None if cellAbove: labelAbove, sourcesAbove = self._createLabelFromContents(cellAbove) if labelAbove and self._preferTop(obj): return labelAbove.strip(), sourcesAbove if cellBelow and not self._preventBelow(obj): labelBelow, sourcesBelow = self._createLabelFromContents(cellBelow) if labelAbove and labelBelow: aboveX, aboveY, aboveWidth, aboveHeight = self._getExtents( cellAbove) belowX, belowY, belowWidth, belowHeight = self._getExtents( cellBelow) dAbove = objY - (aboveY + aboveHeight) dBelow = belowY - (objY + objHeight) if dAbove <= dBelow: return labelAbove.strip(), sourcesAbove return labelBelow.strip(), sourcesBelow if labelAbove: return labelAbove.strip(), sourcesAbove if labelBelow: return labelBelow.strip(), sourcesBelow # None of the cells immediately surrounding this cell seem to be serving # as a functional label. Therefore, see if this table looks like a grid # of widgets with the functional labels in the first row. try: table = grid.queryTable() except NotImplementedError: return None, [] firstRow = [table.getAccessibleAt(0, i) for i in range(table.nColumns)] if not firstRow or list(filter(self._isWidget, firstRow)): return None, [] if colindex < 0: return None, [] cells = [ table.getAccessibleAt(i, colindex) for i in range(1, table.nRows) ] cells = [x for x in cells if x is not None] if [ x for x in cells if x.childCount and x[0].getRole() != obj.getRole() ]: return None, [] label, sources = self._createLabelFromContents(firstRow[colindex]) if label: return label.strip(), sources return None, []
def _generateRoleName(self, obj, **args): if not self._script.utilities.inDocumentContent(obj): return super()._generateRoleName(obj, **args) result = [] acss = self.voice(speech_generator.SYSTEM) roledescription = self._script.utilities.getRoleDescription(obj) if roledescription: result = [roledescription] result.extend(acss) return result role = args.get("role", obj.getRole()) force = args.get("force", False) start = args.get("startOffset") end = args.get("endOffset") if not force: doNotSpeak = [ pyatspi.ROLE_FOOTER, pyatspi.ROLE_FORM, pyatspi.ROLE_LABEL, pyatspi.ROLE_MENU_ITEM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_SECTION, pyatspi.ROLE_UNKNOWN, ] else: doNotSpeak = [pyatspi.ROLE_UNKNOWN] if not force: doNotSpeak.append(pyatspi.ROLE_TABLE_CELL) doNotSpeak.append(pyatspi.ROLE_TEXT) doNotSpeak.append("ROLE_STATIC") if args.get("formatType", "unfocused") != "basicWhereAmI": doNotSpeak.append(pyatspi.ROLE_LIST_ITEM) doNotSpeak.append(pyatspi.ROLE_LIST) if start or end: doNotSpeak.append(pyatspi.ROLE_DOCUMENT_FRAME) doNotSpeak.append(pyatspi.ROLE_ALERT) if self._script.utilities.isAnchor(obj): doNotSpeak.append(obj.getRole()) if obj.getState().contains(pyatspi.STATE_EDITABLE): lastKey, mods = self._script.utilities.lastKeyAndModifiers() if ((lastKey in ["Down", "Right"] and not mods) or self._script.inSayAll()) and start: return [] if lastKey in ["Up", "Left"] and not mods: text = self._script.utilities.queryNonEmptyText(obj) if text and end not in [None, text.characterCount]: return [] if role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role == pyatspi.ROLE_HEADING: level = self._script.utilities.headingLevel(obj) if level: result.append( object_properties.ROLE_HEADING_LEVEL_SPEECH % {"role": self.getLocalizedRoleName(obj, **args), "level": level} ) result.extend(acss) else: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif self._script.utilities.isLink(obj): if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) result.extend(acss) else: if self._script.utilities.hasUselessCanvasDescendant(obj): result.append(self.getLocalizedRoleName(obj, role=pyatspi.ROLE_IMAGE)) result.extend(acss) result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) index = args.get("index", 0) total = args.get("total", 1) ancestorRoles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK] if index == total - 1 and (role == pyatspi.ROLE_IMAGE or self._script.utilities.queryNonEmptyText(obj)): speakRoles = lambda x: x and x.getRole() in ancestorRoles ancestor = pyatspi.findAncestor(obj, speakRoles) if ancestor and ancestor.getRole() != role: result.extend(self._generateRoleName(ancestor)) return result
def _generateRoleName(self, obj, **args): if not self._script.utilities.inDocumentContent(obj): return super()._generateRoleName(obj, **args) result = [] acss = self.voice(speech_generator.SYSTEM) roledescription = self._script.utilities.getRoleDescription(obj) if roledescription: result = [roledescription] result.extend(acss) return result role = args.get('role', obj.getRole()) enabled, disabled = self._getEnabledAndDisabledContextRoles() if role in disabled: return [] force = args.get('force', False) start = args.get('startOffset') end = args.get('endOffset') index = args.get('index', 0) total = args.get('total', 1) if not force: doNotSpeak = [ pyatspi.ROLE_FOOTER, pyatspi.ROLE_FORM, pyatspi.ROLE_LABEL, pyatspi.ROLE_MENU_ITEM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_SECTION, pyatspi.ROLE_REDUNDANT_OBJECT, pyatspi.ROLE_UNKNOWN ] else: doNotSpeak = [pyatspi.ROLE_UNKNOWN] if not force: doNotSpeak.append(pyatspi.ROLE_TABLE_CELL) doNotSpeak.append(pyatspi.ROLE_TEXT) doNotSpeak.append(pyatspi.ROLE_STATIC) if args.get('formatType', 'unfocused') != 'basicWhereAmI': doNotSpeak.append(pyatspi.ROLE_LIST_ITEM) doNotSpeak.append(pyatspi.ROLE_LIST) if (start or end): doNotSpeak.append(pyatspi.ROLE_DOCUMENT_FRAME) doNotSpeak.append(pyatspi.ROLE_DOCUMENT_WEB) doNotSpeak.append(pyatspi.ROLE_ALERT) if self._script.utilities.isAnchor(obj): doNotSpeak.append(obj.getRole()) if total > 1: doNotSpeak.append(pyatspi.ROLE_ROW_HEADER) if self._script.utilities.isMenuInCollapsedSelectElement(obj): doNotSpeak.append(pyatspi.ROLE_MENU) if obj.getState().contains(pyatspi.STATE_EDITABLE): lastKey, mods = self._script.utilities.lastKeyAndModifiers() if ((lastKey in ["Down", "Right"] and not mods) or self._script.inSayAll()) and start: return [] if lastKey in ["Up", "Left"] and not mods: text = self._script.utilities.queryNonEmptyText(obj) if text and end not in [None, text.characterCount]: return [] if role in [ pyatspi.ROLE_ENTRY, pyatspi.ROLE_PASSWORD_TEXT, pyatspi.ROLE_SPIN_BUTTON ]: result.append(self.getLocalizedRoleName(obj, **args)) elif obj.parent and not obj.parent.getState().contains( pyatspi.STATE_EDITABLE): if lastKey not in [ "Home", "End", "Up", "Down", "Left", "Right", "Page_Up", "Page_Down" ]: result.append(object_properties.ROLE_EDITABLE_CONTENT) elif role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, **args)) if result: result.extend(acss) elif role == pyatspi.ROLE_HEADING: if index == total - 1 or not self._script.utilities.isFocusableWithMathChild( obj): level = self._script.utilities.headingLevel(obj) if level: result.append( object_properties.ROLE_HEADING_LEVEL_SPEECH % { 'role': self.getLocalizedRoleName(obj, **args), 'level': level }) result.extend(acss) else: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif self._script.utilities.isLink(obj): if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) result.extend(acss) else: if self._script.utilities.hasUselessCanvasDescendant(obj): result.append( self.getLocalizedRoleName(obj, role=pyatspi.ROLE_IMAGE)) result.extend(acss) if index == total - 1 or not self._script.utilities.isFocusableWithMathChild( obj): result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role == pyatspi.ROLE_COMMENT: if index == 0: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role not in doNotSpeak and args.get('priorObj') != obj: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) if self._script.utilities.isMath( obj) and not self._script.utilities.isMathTopLevel(obj): return result ancestorRoles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK] speakRoles = lambda x: x and x.getRole() in ancestorRoles ancestor = pyatspi.findAncestor(obj, speakRoles) if ancestor and ancestor.getRole() != role and ( index == total - 1 or obj.name == ancestor.name): result.extend(self._generateRoleName(ancestor)) return result
def _generateRoleName(self, obj, **args): if not self._script.utilities.inDocumentContent(obj): return super()._generateRoleName(obj, **args) result = [] acss = self.voice(speech_generator.SYSTEM) roledescription = self._script.utilities.getRoleDescription(obj) if roledescription: result = [roledescription] result.extend(acss) return result role = args.get('role', obj.getRole()) enabled, disabled = self._getEnabledAndDisabledContextRoles() if role in disabled: return [] force = args.get('force', False) start = args.get('startOffset') end = args.get('endOffset') index = args.get('index', 0) total = args.get('total', 1) if not force: doNotSpeak = [pyatspi.ROLE_FOOTER, pyatspi.ROLE_FORM, pyatspi.ROLE_LABEL, pyatspi.ROLE_MENU_ITEM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_SECTION, pyatspi.ROLE_REDUNDANT_OBJECT, pyatspi.ROLE_UNKNOWN] else: doNotSpeak = [pyatspi.ROLE_UNKNOWN] if not force: doNotSpeak.append(pyatspi.ROLE_TABLE_CELL) doNotSpeak.append(pyatspi.ROLE_TEXT) doNotSpeak.append(pyatspi.ROLE_STATIC) if args.get('formatType', 'unfocused') != 'basicWhereAmI': doNotSpeak.append(pyatspi.ROLE_LIST_ITEM) doNotSpeak.append(pyatspi.ROLE_LIST) if (start or end): doNotSpeak.append(pyatspi.ROLE_DOCUMENT_FRAME) doNotSpeak.append(pyatspi.ROLE_DOCUMENT_WEB) doNotSpeak.append(pyatspi.ROLE_ALERT) if self._script.utilities.isAnchor(obj): doNotSpeak.append(obj.getRole()) if total > 1: doNotSpeak.append(pyatspi.ROLE_ROW_HEADER) if obj.getState().contains(pyatspi.STATE_EDITABLE): lastKey, mods = self._script.utilities.lastKeyAndModifiers() if ((lastKey in ["Down", "Right"] and not mods) or self._script.inSayAll()) and start: return [] if lastKey in ["Up", "Left"] and not mods: text = self._script.utilities.queryNonEmptyText(obj) if text and end not in [None, text.characterCount]: return [] if role in [pyatspi.ROLE_ENTRY, pyatspi.ROLE_PASSWORD_TEXT, pyatspi.ROLE_SPIN_BUTTON]: result.append(self.getLocalizedRoleName(obj, **args)) elif obj.parent and not obj.parent.getState().contains(pyatspi.STATE_EDITABLE): if lastKey not in ["Home", "End", "Up", "Down", "Left", "Right", "Page_Up", "Page_Down"]: result.append(object_properties.ROLE_EDITABLE_CONTENT) elif role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, **args)) if result: result.extend(acss) elif role == pyatspi.ROLE_HEADING: if index == total - 1 or not self._script.utilities.isFocusableWithMathChild(obj): level = self._script.utilities.headingLevel(obj) if level: result.append(object_properties.ROLE_HEADING_LEVEL_SPEECH % { 'role': self.getLocalizedRoleName(obj, **args), 'level': level}) result.extend(acss) else: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif self._script.utilities.isLink(obj): if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) result.extend(acss) else: if self._script.utilities.hasUselessCanvasDescendant(obj): result.append(self.getLocalizedRoleName(obj, role=pyatspi.ROLE_IMAGE)) result.extend(acss) if index == total - 1 or not self._script.utilities.isFocusableWithMathChild(obj): result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role == pyatspi.ROLE_COMMENT: if index == 0: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) elif role not in doNotSpeak and args.get('priorObj') != obj: result.append(self.getLocalizedRoleName(obj, **args)) result.extend(acss) if self._script.utilities.isMath(obj) and not self._script.utilities.isMathTopLevel(obj): return result ancestorRoles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK] if index == total - 1 \ and (role == pyatspi.ROLE_IMAGE or self._script.utilities.queryNonEmptyText(obj)): speakRoles = lambda x: x and x.getRole() in ancestorRoles ancestor = pyatspi.findAncestor(obj, speakRoles) if ancestor and ancestor.getRole() != role: result.extend(self._generateRoleName(ancestor)) return result
def _on_mouse_moved(self, event): """Callback for mouse:abs events.""" screen, pX, pY = self._pointer.get_position() window = self._accessible_window_at_point(pX, pY) msg = "MOUSE REVIEW: Window at (%i, %i) is %s" % (pX, pY, window) debug.println(debug.LEVEL_INFO, msg, True) if not window: return script = orca_state.activeScript if not script: return isMenu = lambda x: x and x.getRole() == pyatspi.ROLE_MENU if script.utilities.isDead(orca_state.locusOfFocus): menu = None elif isMenu(orca_state.locusOfFocus): menu = orca_state.locusOfFocus else: try: menu = pyatspi.findAncestor(orca_state.locusOfFocus, isMenu) except: msg = "ERROR: Exception getting ancestor of %s" % orca_state.locusOfFocus debug.println(debug.LEVEL_INFO, msg, True) menu = None document = None if script.utilities.inDocumentContent(): document = script.utilities.activeDocument() obj = script.utilities.descendantAtPoint(menu, pX, pY) \ or script.utilities.descendantAtPoint(document, pX, pY) \ or script.utilities.descendantAtPoint(window, pX, pY) msg = "MOUSE REVIEW: Object at (%i, %i) is %s" % (pX, pY, obj) debug.println(debug.LEVEL_INFO, msg, True) script = _scriptManager.getScript(window.getApplication(), obj) if menu and obj and not pyatspi.findAncestor(obj, isMenu): if script.utilities.intersectingRegion(obj, menu) != (0, 0, 0, 0): msg = "MOUSE REVIEW: %s believed to be under %s" % (obj, menu) debug.println(debug.LEVEL_INFO, msg, True) return if document and obj and document != script.utilities.getContainingDocument( obj): msg = "MOUSE REVIEW: %s is not in active document %s" % (obj, document) debug.println(debug.LEVEL_INFO, msg, True) return if obj and obj.getRole() in script.utilities.getCellRoles() \ and script.utilities.shouldReadFullRow(obj): isRow = lambda x: x and x.getRole() == pyatspi.ROLE_TABLE_ROW obj = pyatspi.findAncestor(obj, isRow) or obj screen, nowX, nowY = self._pointer.get_position() if (pX, pY) != (nowX, nowY): msg = "MOUSE REVIEW: Pointer moved again: (%i, %i)" % (nowX, nowY) debug.println(debug.LEVEL_INFO, msg, True) return boundary = None x, y, width, height = self._currentMouseOver.getBoundingBox() if y <= pY <= y + height and self._currentMouseOver.getString(): boundary = pyatspi.TEXT_BOUNDARY_WORD_START elif obj == self._currentMouseOver.getObject(): boundary = pyatspi.TEXT_BOUNDARY_LINE_START elif obj and obj.getState().contains(pyatspi.STATE_SELECTABLE): boundary = pyatspi.TEXT_BOUNDARY_LINE_START new = _ItemContext(pX, pY, obj, boundary, window, script) if new.present(self._currentMouseOver): self._currentMouseOver = new
def _is_in_frame(self, event): try: return pyatspi.findAncestor( event.source, lambda x: x == self._top_frame) except: return None
def _generateRoleName(self, obj, **args): if not self._script.utilities.inDocumentContent(obj): return super()._generateRoleName(obj, **args) result = [] acss = self.voice(speech_generator.SYSTEM) roledescription = self._script.utilities.getRoleDescription(obj) if roledescription: result = [roledescription] result.extend(acss) return result role = args.get('role', obj.getRole()) force = args.get('force', False) start = args.get('startOffset') end = args.get('endOffset') if not force: doNotSpeak = [pyatspi.ROLE_FOOTER, pyatspi.ROLE_FORM, pyatspi.ROLE_LABEL, pyatspi.ROLE_MENU_ITEM, pyatspi.ROLE_PARAGRAPH, pyatspi.ROLE_SECTION, pyatspi.ROLE_UNKNOWN] else: doNotSpeak = [pyatspi.ROLE_UNKNOWN] if not force: doNotSpeak.append(pyatspi.ROLE_TABLE_CELL) doNotSpeak.append(pyatspi.ROLE_TEXT) doNotSpeak.append('ROLE_STATIC') if args.get('formatType', 'unfocused') != 'basicWhereAmI': doNotSpeak.append(pyatspi.ROLE_LIST_ITEM) doNotSpeak.append(pyatspi.ROLE_LIST) if (start or end): doNotSpeak.append(pyatspi.ROLE_DOCUMENT_FRAME) doNotSpeak.append(pyatspi.ROLE_ALERT) if obj.getState().contains(pyatspi.STATE_EDITABLE): lastKey, mods = self._script.utilities.lastKeyAndModifiers() if ((lastKey in ["Down", "Right"] and not mods) or self._script.inSayAll()) and start: return [] if lastKey in ["Up", "Left"] and not mods: text = self._script.utilities.queryNonEmptyText(obj) if text and end not in [None, text.characterCount]: return [] if role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, role)) result.extend(acss) elif role == pyatspi.ROLE_HEADING: level = self._script.utilities.headingLevel(obj) if level: result.append(object_properties.ROLE_HEADING_LEVEL_SPEECH % { 'role': self.getLocalizedRoleName(obj, role), 'level': level}) result.extend(acss) else: result.append(self.getLocalizedRoleName(obj, role)) result.extend(acss) elif role == pyatspi.ROLE_LINK: if obj.parent.getRole() == pyatspi.ROLE_IMAGE: result.append(messages.IMAGE_MAP_LINK) result.extend(acss) else: if self._script.utilities.hasUselessCanvasDescendant(obj): result.append(self.getLocalizedRoleName(obj, pyatspi.ROLE_IMAGE)) result.extend(acss) result.append(self.getLocalizedRoleName(obj, role)) result.extend(acss) elif role not in doNotSpeak: result.append(self.getLocalizedRoleName(obj, role)) result.extend(acss) index = args.get('index', 0) total = args.get('total', 1) ancestorRoles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK] if index == total - 1 \ and (role == pyatspi.ROLE_IMAGE or self._script.utilities.queryNonEmptyText(obj)): speakRoles = lambda x: x and x.getRole() in ancestorRoles ancestor = pyatspi.findAncestor(obj, speakRoles) if ancestor and ancestor.getRole() != role: result.extend(self._generateRoleName(ancestor)) return result
def isSeekSlider(self, obj): return bool(pyatspi.findAncestor( obj, lambda x: x.getRole() == pyatspi.ROLE_TOOL_BAR))