# Orca # # Copyright 2005-2009 Sun Microsystems Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. # pylint: disable=too-many-lines # pylint: disable=too-many-branches # pylint: disable=too-many-statements # pylint: disable=wrong-import-position # pylint: disable=too-many-return-statements # pylint: disable=too-few-public-methods # pylint: disable=too-many-locals # pylint: disable=too-many-boolean-expressions # pylint: disable=unused-argument """Produces speech presentation for accessible objects.""" # This has to be the first non-docstring line in the module to make linters happy. from __future__ import annotations __id__ = "$Id:$" __version__ = "$Revision:$" __date__ = "$Date:$" __copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc." __license__ = "LGPL" import urllib.error import urllib.parse import urllib.request from typing import Any, TYPE_CHECKING import gi gi.require_version("Atspi", "2.0") from gi.repository import Atspi from . import acss from . import debug from . import focus_manager from . import generator from . import input_event_manager from . import mathsymbols from . import messages from . import object_properties from . import settings from . import settings_manager from . import speech from . import speech_and_verbosity_manager from .ax_document import AXDocument from .ax_hypertext import AXHypertext from .ax_object import AXObject from .ax_table import AXTable from .ax_text import AXText from .ax_utilities import AXUtilities from .ax_value import AXValue if TYPE_CHECKING: from . import script class Pause: """A dummy class to indicate we want to insert a pause into an utterance.""" def __init__(self) -> None: pass def __str__(self) -> str: return "PAUSE" PAUSE = [Pause()] DEFAULT = "default" UPPERCASE = "uppercase" HYPERLINK = "hyperlink" SYSTEM = "system" STATE = "state" # Candidate for sound VALUE = "value" # Candidate for sound voiceType = { DEFAULT: settings.DEFAULT_VOICE, UPPERCASE: settings.UPPERCASE_VOICE, HYPERLINK: settings.HYPERLINK_VOICE, SYSTEM: settings.SYSTEM_VOICE, STATE: settings.SYSTEM_VOICE, # Users may prefer DEFAULT_VOICE here VALUE: settings.SYSTEM_VOICE, # Users may prefer DEFAULT_VOICE here } class SpeechGenerator(generator.Generator): """Produces speech presentation for accessible objects.""" def __init__(self, script: script.Script) -> None: super().__init__(script, "speech") @staticmethod def log_generator_output(func): """Decorator for logging.""" def wrapper(*args, **kwargs): result = func(*args, **kwargs) tokens = [f"SPEECH GENERATOR: {func.__name__}:", result] debug.print_tokens(debug.LEVEL_INFO, tokens, True) return result return wrapper def generate_speech(self, obj: Atspi.Accessible, **args) -> list[Any]: """Generates speech presentation for obj.""" rv = self.generate(obj, **args) if rv and not list(filter(lambda x: not isinstance(x, Pause), rv)): tokens = ["SPEECH GENERATOR: Results for", obj, "are pauses only"] debug.print_tokens(debug.LEVEL_INFO, tokens, True) rv = [] return rv def get_name(self, obj: Atspi.Accessible, **args) -> str: """Returns the generated name of obj as a string.""" generated = self._generate_accessible_name(obj, **args) if generated: return generated[0] return "" def get_error_message(self, obj: Atspi.Accessible, **args) -> str: """Returns the generated error message for obj as a string.""" generated = self._generate_state_invalid(obj, **args) if generated: return generated[0] return "" def get_localized_role_name(self, obj: Atspi.Accessible, **args) -> str: if AXObject.find_ancestor_inclusive(obj, AXUtilities.is_editable_combo_box): return object_properties.ROLE_EDITABLE_COMBO_BOX if AXUtilities.is_link(obj, args.get("role")) and AXUtilities.is_visited(obj): return object_properties.ROLE_VISITED_LINK return super().get_localized_role_name(obj, **args) def get_role_name(self, obj, **args): """Returns the generated rolename of obj as a string.""" generated = self._generate_accessible_role(obj, **args) if generated: return generated[0] return "" def generate_window_title(self, obj: Atspi.Accessible, **args) -> list[Any]: """Returns an array of strings the represents details about the window title for obj.""" result = [] frame, dialog = self._script.utilities.frame_and_dialog(obj) if frame: frame_result = self._generate_accessible_label_and_name(frame) if not frame_result: frame_result = self._generate_accessible_role(frame) if frame_result: result.append(frame_result) if dialog: if dialog_result := self._generate_accessible_label_and_name(dialog): result.append(dialog_result) elif spreadsheet := AXObject.find_ancestor( obj, self._script.utilities.is_spreadsheet_table): if spreadsheet_result := self._generate_accessible_label_and_name(spreadsheet): result.append(spreadsheet_result) alert_and_dialog_count = len(AXUtilities.get_unfocused_alerts_and_dialogs(obj)) if alert_and_dialog_count > 0: dialogs = [messages.dialog_count_speech(alert_and_dialog_count)] dialogs.extend(self.voice(DEFAULT, obj=obj, **args)) result.append(dialogs) return result def _generate_result_separator( self, obj: Atspi.Accessible, **args ) -> list[Any]: return PAUSE def _generate_pause( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not settings_manager.get_manager().get_setting("enablePauseBreaks") \ or args.get("eliminatePauses", False): return [] if settings_manager.get_manager().get_setting("verbalizePunctuationStyle") == \ settings.PUNCTUATION_STYLE_ALL: return [] return PAUSE def voice(self, key: str | None = None, **args) -> list[acss.ACSS]: """Returns an array containing a voice.""" voicename = voiceType.get(key or DEFAULT, voiceType.get(DEFAULT)) voices = settings_manager.get_manager().get_setting("voices") voice = acss.ACSS(voices.get(voiceType.get(DEFAULT), acss.ACSS())) language = args.get("language") dialect = args.get("dialect", "") msg = ( f"SPEECH GENERATOR: {key} voice requested with " f"language='{language}', dialect='{dialect}'" ) debug.print_message(debug.LEVEL_INFO, msg, True) # This is purely for debugging. The code needed to actually switch voices # does not yet exist due to some problems which need to be debugged and # fixed. check_voices_for_language = False if language and check_voices_for_language: server = speech.get_speech_server() assert server, "No speech server available" server.should_change_voice_for_language(language, dialect) if key in [None, DEFAULT]: string = args.get("string", "") obj = args.get("obj") if AXUtilities.is_link(obj): voice.update(voices.get(voiceType.get(HYPERLINK), acss.ACSS())) elif isinstance(string, str) and string.isupper() and string.strip().isalpha(): voice.update(voices.get(voiceType.get(UPPERCASE), acss.ACSS())) else: override = voices.get(voicename) if override and override.get("established", True): voice.update(override) return [voice] def utterances_to_string(self, utterances: list[Any]) -> str: """Converts utterances to a string.""" string = "" for u in utterances: if isinstance(u, str): string += f" {u}" elif isinstance(u, Pause) and string and string[-1].isalnum(): string += "." return string.strip() ################################# BASIC DETAILS ################################# @log_generator_output def _generate_accessible_description( self, obj: Atspi.Accessible, **args ) -> list[Any]: mgr = settings_manager.get_manager() if not mgr.get_setting("speakDescription") or mgr.get_setting("onlySpeakDisplayedText"): return [] if args.get("inMouseReview") and not mgr.get_setting("presentToolTips"): return [] prior_obj = args.get("priorObj") if prior_obj == obj: return [] if AXUtilities.is_tool_tip(prior_obj): return [] result = super()._generate_accessible_description(obj, **args) if result: manager = speech_and_verbosity_manager.get_manager() result[0] = manager.adjust_for_presentation(obj, result[0]) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_accessible_image_description( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_accessible_image_description(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_accessible_label( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_accessible_label(obj, **args) if result: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_accessible_name( self, obj: Atspi.Accessible, **args ) -> list[Any]: is_layered_pane = AXUtilities.is_layered_pane(obj, args.get("role")) if is_layered_pane and settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_accessible_name(obj, **args) if result: if is_layered_pane: result.extend(self.voice(SYSTEM, obj=obj, **args)) else: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_accessible_label_and_name( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_accessible_label_and_name(obj, **args) if result: manager = speech_and_verbosity_manager.get_manager() result[0] = manager.adjust_for_presentation(obj, result[0]) if len(result) == 1: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_accessible_placeholder_text( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_accessible_placeholder_text(obj, **args) if result: manager = speech_and_verbosity_manager.get_manager() result[0] = manager.adjust_for_presentation(obj, result[0]) result.extend(self.voice(DEFAULT, obj=obj, **args)) return result def _get_ancestor_with_usable_role(self, obj, **args): role = args.get("role", AXObject.get_role(obj)) index = args.get("index", 0) total = args.get("total", 1) def use_ancestor_role(x): if not (AXUtilities.is_heading(x) or AXUtilities.is_link(x)): return False if AXObject.get_role(x) == role: return False return index == total - 1 or AXObject.get_name(x) == AXObject.get_name(obj) return AXObject.find_ancestor(obj, use_ancestor_role) def _should_speak_role(self, obj, **args): settings_mgr = settings_manager.get_manager() if settings_mgr.get_setting("onlySpeakDisplayedText"): return False mode, _acc = focus_manager.get_manager().get_active_mode_and_object_of_interest() if mode == focus_manager.OBJECT_NAVIGATOR: return True role = args.get("role", AXObject.get_role(obj)) _enabled, disabled = self._get_enabled_and_disabled_context_roles() if role in disabled: return False do_not_speak = [Atspi.Role.ARTICLE, Atspi.Role.EXTENDED, Atspi.Role.FILLER, Atspi.Role.FOOTER, Atspi.Role.FORM, Atspi.Role.LABEL, Atspi.Role.MENU_ITEM, Atspi.Role.PARAGRAPH, Atspi.Role.REDUNDANT_OBJECT, Atspi.Role.SECTION, Atspi.Role.STATIC, Atspi.Role.TABLE_CELL, Atspi.Role.UNKNOWN] if settings_mgr.get_setting("speechVerbosityLevel") == settings.VERBOSITY_LEVEL_BRIEF: do_not_speak.extend([ Atspi.Role.CANVAS, Atspi.Role.ICON, ]) if args.get("string"): do_not_speak.extend([ "ROLE_CONTENT_SUGGESTION", ]) if args.get("formatType") != "basicWhereAmI": do_not_speak.extend([ Atspi.Role.LIST, Atspi.Role.LIST_ITEM, ]) if args.get("startOffset") is not None or args.get("endOffset") is not None: do_not_speak.extend([ Atspi.Role.ALERT, Atspi.Role.DOCUMENT_FRAME, Atspi.Role.DOCUMENT_PRESENTATION, Atspi.Role.DOCUMENT_SPREADSHEET, Atspi.Role.DOCUMENT_TEXT, Atspi.Role.DOCUMENT_WEB, ]) if args.get("total", 1) > 1: do_not_speak.extend([ Atspi.Role.ROW_HEADER, ]) if role in do_not_speak: return False if AXUtilities.is_combo_box(AXObject.get_parent(obj)): return False if self._script.utilities.is_anchor(obj): return False if AXUtilities.is_desktop_frame(obj): return False if AXUtilities.is_docked_frame(obj): return False if AXUtilities.is_panel(obj, role): if AXUtilities.is_selected(obj): return False child = args.get("ancestorOf") if not (child and AXUtilities.is_widget(child)): return False if obj == args.get("priorObj"): return False return True @log_generator_output def _generate_accessible_role( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not self._should_speak_role(obj, **args): return [] parent = AXObject.get_parent(obj) if AXUtilities.is_menu(obj, args.get("role")) and AXUtilities.is_combo_box(parent): return self._generate_accessible_role(parent) if AXUtilities.is_single_line_autocomplete_entry(obj): result: list[Any] = [self.get_localized_role_name(obj, role=Atspi.Role.AUTOCOMPLETE)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result level = AXUtilities.get_heading_level(obj) if level: result = [object_properties.ROLE_HEADING_LEVEL_SPEECH % { "role": self.get_localized_role_name(obj, **args), "level": level}] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result result = [self.get_localized_role_name(obj, **args)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_tutorial( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Provides the tutorial message for obj.""" if not settings_manager.get_manager().get_setting("enableTutorialMessages") \ and not args.get("formatType", "").endswith("WhereAmI"): return [] text = AXObject.get_help_text(obj) if not text: return [] return [text, self.voice(SYSTEM, obj=obj, **args)] @log_generator_output def _generate_has_click_action( self, obj: Atspi.Accessible, **args ) -> list[Any]: return [] @log_generator_output def _generate_has_long_description( self, obj: Atspi.Accessible, **args ) -> list[Any]: return [] @log_generator_output def _generate_has_details( self, obj: Atspi.Accessible, **args ) -> list[Any]: return [] @log_generator_output def _generate_details_for( self, obj: Atspi.Accessible, **args ) -> list[Any]: return [] @log_generator_output def _generate_all_details( self, obj: Atspi.Accessible, **args ) -> list[Any]: return [] @log_generator_output def _generate_new_radio_button_group( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not AXUtilities.is_radio_button(obj): return [] result = super()._generate_radio_button_group(obj, **args) if not result: return [] result.extend(self.voice(DEFAULT, obj=obj, **args)) prior_obj = args.get("priorObj", None) if not AXUtilities.is_radio_button(prior_obj): return result # TODO - JD: We need other ways to determine group membership. Not all # implementations expose the member-of relation. Gtk3 does. Others are TBD. members = AXUtilities.get_is_member_of(obj) if prior_obj not in members: return result return [] @log_generator_output def _generate_term_value_count( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_term_value_count(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_number_of_children( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText") \ or settings_manager.get_manager().get_setting("speechVerbosityLevel") \ == settings.VERBOSITY_LEVEL_BRIEF: return [] if AXObject.find_ancestor(obj, AXUtilities.is_tree_or_tree_table): child_nodes = self._script.utilities.child_nodes(obj) if child_nodes: result = [messages.item_count(len(child_nodes))] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result return [] role = args.get("role") if AXUtilities.is_list(obj, role) or AXUtilities.is_list_box(obj, role): set_size = AXUtilities.get_set_size(obj) if set_size: result = [messages.list_item_count(set_size)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result return [] # TODO - JD: Only presenting the lack of children is what we were doing before the # generator cleanup. This is potentially because we would (optionally) present the # number of children as part of the selected child's presentation. Figure out what # we should really be doing, e.g in the case where no item is selected. if AXUtilities.is_layered_pane(obj, role): children = list(AXObject.iter_children(obj, AXUtilities.is_icon_or_canvas)) if not children: result = [messages.ZERO_ITEMS] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result return [] @log_generator_output def _generate_selected_item_count( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] container = obj if not AXObject.supports_selection(container): container = AXObject.get_parent(obj) if not AXObject.supports_selection(container): return [] result = [] child_count = AXObject.get_child_count(container) selected_count = len(self._script.utilities.selected_children(container)) result.append(messages.selected_items_count(selected_count, child_count)) result.extend(self.voice(SYSTEM, obj=obj, **args)) result.append(object_properties.ICON_INDEX_SPEECH \ % {"index" : AXObject.get_index_in_parent(obj) + 1, "total" : child_count}) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_selected_items( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] container = obj if not AXObject.supports_selection(container): container = AXObject.get_parent(obj) if not AXObject.supports_selection(container): return [] selected_items = self._script.utilities.selected_children(container) return list(map(self._generate_accessible_label_and_name, selected_items)) @log_generator_output def _generate_unfocused_dialog_count( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = [] alert_and_dialog_count = len(AXUtilities.get_unfocused_alerts_and_dialogs(obj)) if alert_and_dialog_count > 0: result.append(messages.dialog_count_speech(alert_and_dialog_count)) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result def _get_enabled_and_disabled_context_roles(self): # TODO - JD: Move to the speech and verbosity manager. all_roles = [Atspi.Role.BLOCK_QUOTE, Atspi.Role.CONTENT_DELETION, Atspi.Role.CONTENT_INSERTION, Atspi.Role.MARK, Atspi.Role.SUGGESTION, "ROLE_DPUB_LANDMARK", "ROLE_DPUB_SECTION", Atspi.Role.DESCRIPTION_LIST, "ROLE_FEED", Atspi.Role.FORM, Atspi.Role.GROUPING, Atspi.Role.LANDMARK, Atspi.Role.LIST, Atspi.Role.PANEL, "ROLE_REGION", Atspi.Role.TABLE, Atspi.Role.TOOL_TIP] enabled, disabled = [], [] if focus_manager.get_manager().in_say_all(): if settings_manager.get_manager().get_setting("sayAllContextBlockquote"): enabled.append(Atspi.Role.BLOCK_QUOTE) if settings_manager.get_manager().get_setting("sayAllContextLandmark"): enabled.extend([Atspi.Role.LANDMARK, "ROLE_DPUB_LANDMARK"]) if settings_manager.get_manager().get_setting("sayAllContextList"): enabled.append(Atspi.Role.LIST) enabled.append(Atspi.Role.DESCRIPTION_LIST) enabled.append("ROLE_FEED") if settings_manager.get_manager().get_setting("sayAllContextPanel"): enabled.extend([Atspi.Role.PANEL, Atspi.Role.TOOL_TIP, Atspi.Role.CONTENT_DELETION, Atspi.Role.CONTENT_INSERTION, Atspi.Role.GROUPING, Atspi.Role.MARK, Atspi.Role.SUGGESTION, "ROLE_DPUB_SECTION"]) if settings_manager.get_manager().get_setting("sayAllContextNonLandmarkForm"): enabled.append(Atspi.Role.FORM) if settings_manager.get_manager().get_setting("sayAllContextTable"): enabled.append(Atspi.Role.TABLE) else: if settings_manager.get_manager().get_setting("speakContextBlockquote"): enabled.append(Atspi.Role.BLOCK_QUOTE) if settings_manager.get_manager().get_setting("speakContextLandmark"): enabled.extend([Atspi.Role.LANDMARK, "ROLE_DPUB_LANDMARK", "ROLE_REGION"]) if settings_manager.get_manager().get_setting("speakContextList"): enabled.append(Atspi.Role.LIST) enabled.append(Atspi.Role.DESCRIPTION_LIST) enabled.append("ROLE_FEED") if settings_manager.get_manager().get_setting("speakContextPanel"): enabled.extend([Atspi.Role.PANEL, Atspi.Role.TOOL_TIP, Atspi.Role.CONTENT_DELETION, Atspi.Role.CONTENT_INSERTION, Atspi.Role.GROUPING, Atspi.Role.MARK, Atspi.Role.SUGGESTION, "ROLE_DPUB_SECTION"]) if settings_manager.get_manager().get_setting("speakContextNonLandmarkForm"): enabled.append(Atspi.Role.FORM) if settings_manager.get_manager().get_setting("speakContextTable"): enabled.append(Atspi.Role.TABLE) disabled = list(set(all_roles).symmetric_difference(enabled)) return enabled, disabled @log_generator_output def _generate_leaving( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not args.get("leaving"): return [] role = args.get("role", AXObject.get_role(obj)) enabled, _disabled = self._get_enabled_and_disabled_context_roles() is_details = bool(AXUtilities.get_is_details_for(obj)) if not (role in enabled or is_details): return [] count = args.get("count", 1) result = [] if is_details: result.append(messages.LEAVING_DETAILS) elif role == Atspi.Role.BLOCK_QUOTE: if count > 1: result.append(messages.leaving_n_blockquotes(count)) else: result.append(messages.LEAVING_BLOCKQUOTE) elif self._script.utilities.is_document_list(obj): if count > 1: result.append(messages.leaving_n_lists(count)) else: result.append(messages.LEAVING_LIST) elif role == "ROLE_FEED": result.append(messages.LEAVING_FEED) elif role == Atspi.Role.PANEL: if AXUtilities.is_figure(obj): result.append(messages.LEAVING_FIGURE) elif self._script.utilities.is_document_panel(obj): result.append(messages.LEAVING_PANEL) else: result = [""] elif role == Atspi.Role.GROUPING: result.append(messages.LEAVING_GROUPING) elif role == Atspi.Role.TABLE and self._script.utilities.is_text_document_table(obj): result.append(messages.LEAVING_TABLE) elif role == "ROLE_DPUB_LANDMARK": if AXUtilities.is_dpub_acknowledgments(obj): result.append(messages.LEAVING_ACKNOWLEDGMENTS) elif AXUtilities.is_dpub_afterword(obj): result.append(messages.LEAVING_AFTERWORD) elif AXUtilities.is_dpub_appendix(obj): result.append(messages.LEAVING_APPENDIX) elif AXUtilities.is_dpub_bibliography(obj): result.append(messages.LEAVING_BIBLIOGRAPHY) elif AXUtilities.is_dpub_chapter(obj): result.append(messages.LEAVING_CHAPTER) elif AXUtilities.is_dpub_conclusion(obj): result.append(messages.LEAVING_CONCLUSION) elif AXUtilities.is_dpub_credits(obj): result.append(messages.LEAVING_CREDITS) elif AXUtilities.is_dpub_endnotes(obj): result.append(messages.LEAVING_ENDNOTES) elif AXUtilities.is_dpub_epilogue(obj): result.append(messages.LEAVING_EPILOGUE) elif AXUtilities.is_dpub_errata(obj): result.append(messages.LEAVING_ERRATA) elif AXUtilities.is_dpub_foreword(obj): result.append(messages.LEAVING_FOREWORD) elif AXUtilities.is_dpub_glossary(obj): result.append(messages.LEAVING_GLOSSARY) elif AXUtilities.is_dpub_index(obj): result.append(messages.LEAVING_INDEX) elif AXUtilities.is_dpub_introduction(obj): result.append(messages.LEAVING_INTRODUCTION) elif AXUtilities.is_dpub_pagelist(obj): result.append(messages.LEAVING_PAGELIST) elif AXUtilities.is_dpub_part(obj): result.append(messages.LEAVING_PART) elif AXUtilities.is_dpub_preface(obj): result.append(messages.LEAVING_PREFACE) elif AXUtilities.is_dpub_prologue(obj): result.append(messages.LEAVING_PROLOGUE) elif AXUtilities.is_dpub_toc(obj): result.append(messages.LEAVING_TOC) elif role == "ROLE_DPUB_SECTION": if AXUtilities.is_dpub_abstract(obj): result.append(messages.LEAVING_ABSTRACT) elif AXUtilities.is_dpub_colophon(obj): result.append(messages.LEAVING_COLOPHON) elif AXUtilities.is_dpub_credit(obj): result.append(messages.LEAVING_CREDIT) elif AXUtilities.is_dpub_dedication(obj): result.append(messages.LEAVING_DEDICATION) elif AXUtilities.is_dpub_epigraph(obj): result.append(messages.LEAVING_EPIGRAPH) elif AXUtilities.is_dpub_example(obj): result.append(messages.LEAVING_EXAMPLE) elif AXUtilities.is_dpub_pullquote(obj): result.append(messages.LEAVING_PULLQUOTE) elif AXUtilities.is_dpub_qna(obj): result.append(messages.LEAVING_QNA) elif AXUtilities.is_landmark(obj): if AXUtilities.is_landmark_banner(obj): result.append(messages.LEAVING_LANDMARK_BANNER) elif AXUtilities.is_landmark_complementary(obj): result.append(messages.LEAVING_LANDMARK_COMPLEMENTARY) elif AXUtilities.is_landmark_contentinfo(obj): result.append(messages.LEAVING_LANDMARK_CONTENTINFO) elif AXUtilities.is_landmark_main(obj): result.append(messages.LEAVING_LANDMARK_MAIN) elif AXUtilities.is_landmark_navigation(obj): result.append(messages.LEAVING_LANDMARK_NAVIGATION) elif AXUtilities.is_landmark_region(obj): result.append(messages.LEAVING_LANDMARK_REGION) elif AXUtilities.is_landmark_search(obj): result.append(messages.LEAVING_LANDMARK_SEARCH) elif AXUtilities.is_landmark_form(obj): result.append(messages.LEAVING_FORM) else: result = [""] elif role == Atspi.Role.FORM: result.append(messages.LEAVING_FORM) elif role == Atspi.Role.TOOL_TIP: result.append(messages.LEAVING_TOOL_TIP) elif role == Atspi.Role.CONTENT_DELETION: result.append(messages.CONTENT_DELETION_END) elif role == Atspi.Role.CONTENT_INSERTION: result.append(messages.CONTENT_INSERTION_END) elif role == Atspi.Role.MARK: result.append(messages.CONTENT_MARK_END) elif role == Atspi.Role.SUGGESTION and not AXUtilities.is_inline_suggestion(obj, role): result.append(messages.LEAVING_SUGGESTION) else: result = [""] if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result def _generate_ancestors( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [] leaving = args.get("leaving") if leaving and args.get("priorObj"): prior_obj = obj obj = args.get("priorObj") else: prior_obj = args.get("priorObj") if prior_obj and AXObject.is_dead(prior_obj): return [] if AXUtilities.is_tool_tip(prior_obj): return [] if prior_obj and AXObject.get_parent(prior_obj) == AXObject.get_parent(obj): return [] if AXUtilities.is_page_tab(obj): return [] if AXUtilities.is_tool_tip(obj): return [] common_ancestor = AXObject.get_common_ancestor(prior_obj, obj) if obj == common_ancestor: return [] include_only = args.get("includeOnly", []) skip_roles = args.get("skipRoles", []) skip_roles.append(Atspi.Role.TREE_ITEM) _enabled, disabled = self._get_enabled_and_disabled_context_roles() skip_roles.extend(disabled) stop_at_roles = args.get("stop_at_roles", []) stop_at_roles.extend([Atspi.Role.APPLICATION, Atspi.Role.MENU_BAR]) stop_after_roles = args.get("stop_after_roles", []) stop_after_roles.extend([Atspi.Role.TOOL_TIP]) present_once = [Atspi.Role.BLOCK_QUOTE, Atspi.Role.LIST] present_common_ancestor = False if common_ancestor and not leaving: common_role = self._get_functional_role(common_ancestor) if common_role in present_once: def pred(x): return self._get_functional_role(x) == common_role obj_ancestor = AXObject.find_ancestor(obj, pred) prior_ancestor = AXObject.find_ancestor(prior_obj, pred) obj_level = self._get_nesting_level(obj_ancestor) prior_level = self._get_nesting_level(prior_ancestor) present_common_ancestor = obj_level != prior_level ancestors: list[Atspi.Accessible] = [] ancestor_roles: list[Atspi.Role] = [] parent = AXObject.get_parent_checked(obj) while parent: parent_role = self._get_functional_role(parent) if parent_role in stop_at_roles: break # TODO - JD: Create an alternative role for this. if parent_role in skip_roles \ and not self._script.utilities.is_spreadsheet_table(parent): pass elif include_only and parent_role not in include_only: pass elif AXUtilities.is_layout_only(parent): pass elif AXUtilities.is_button_with_popup(parent): pass elif parent != common_ancestor or present_common_ancestor: is_redundant = False for ancestor in ancestors: if AXUtilities.is_redundant_object(ancestor, parent): is_redundant = True break if not is_redundant: ancestors.append(parent) ancestor_roles.append(parent_role) if parent == common_ancestor or parent_role in stop_after_roles: break parent = AXObject.get_parent_checked(parent) presented_roles = [] for i, x in enumerate(ancestors): alt_role = ancestor_roles[i] if alt_role in present_once and alt_role in presented_roles: continue presented_roles.append(alt_role) count = ancestor_roles.count(alt_role) result.append( self.generate(x, formatType="ancestor", role=alt_role, leaving=leaving, count=count, ancestorOf=obj, priorObj=prior_obj)) if not leaving: result.reverse() return result @log_generator_output def _generate_old_ancestors( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if self._script.utilities.in_find_container(): return [] prior_obj = args.get("priorObj") if not prior_obj or obj == prior_obj or not AXObject.is_valid(prior_obj): return [] if AXUtilities.is_page_tab(obj): return [] if AXUtilities.get_application(obj) != AXUtilities.get_application(prior_obj) \ or AXObject.find_ancestor(obj, lambda x: x == prior_obj): return [] _frame, dialog = self._script.utilities.frame_and_dialog(obj) if dialog: return [] args["leaving"] = True args["includeOnly"] = [Atspi.Role.BLOCK_QUOTE, Atspi.Role.DESCRIPTION_LIST, Atspi.Role.FORM, Atspi.Role.LANDMARK, Atspi.Role.CONTENT_DELETION, Atspi.Role.CONTENT_INSERTION, Atspi.Role.MARK, Atspi.Role.SUGGESTION, "ROLE_DPUB_LANDMARK", "ROLE_DPUB_SECTION", "ROLE_FEED", Atspi.Role.LIST, Atspi.Role.PANEL, "ROLE_REGION", Atspi.Role.TABLE, Atspi.Role.TOOL_TIP] result = [] if AXUtilities.is_block_quote(prior_obj): result.extend(self.generate(prior_obj, role=self._get_functional_role(prior_obj), formatType="focused", leaving=True)) result.extend(self._generate_ancestors(obj, **args)) args.pop("leaving") args.pop("includeOnly") return result @log_generator_output def _generate_new_ancestors( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if self._script.utilities.in_find_container(): return [] prior_obj = args.get("priorObj") if prior_obj == obj: return [] role = args.get("role", AXObject.get_role(obj)) if AXUtilities.is_frame(obj, role) or AXUtilities.is_window(obj, role): return [] if AXUtilities.is_menu_item_of_any_kind(obj, role) \ and (not prior_obj or AXUtilities.is_window(prior_obj)): return [] if prior_obj is not None: return self._generate_ancestors(obj, **args) frame, dialog = self._script.utilities.frame_and_dialog(obj) top_level = dialog or frame if AXUtilities.is_dialog_or_alert(top_level): return self._generate_ancestors(obj, **args) return [] def generate_context(self, obj, **args): if args.get("priorObj") == obj: return [] result = self._generate_old_ancestors(obj, **args) result.append(self._generate_new_ancestors(obj, **args)) return result def _generate_parent_role_name( self, obj: Atspi.Accessible, **args ) -> list[Any]: if args.get("role", AXObject.get_role(obj)) == Atspi.Role.ICON \ and args.get("formatType", None) \ in ["basicWhereAmI", "detailedWhereAmI"]: return [object_properties.ROLE_ICON_PANEL] parent = AXObject.get_parent(obj) if AXUtilities.is_table_cell(parent) or AXUtilities.is_menu(parent): obj = parent return self._generate_accessible_role(AXObject.get_parent(obj)) @log_generator_output def _generate_position_in_list( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText") \ or not (settings_manager.get_manager().get_setting("enablePositionSpeaking") \ or args.get("forceList", False)) \ or args.get("formatType") == "ancestor": return [] if args.get("index", 0) + 1 < args.get("total", 1): return [] result = [] position = AXUtilities.get_position_in_set(obj) total = AXUtilities.get_set_size(obj) if position < 0: return [] string = object_properties.GROUP_INDEX_SPEECH if total < 0: if not AXUtilities.get_set_size_is_unknown(obj): return [] string = object_properties.GROUP_INDEX_TOTAL_UNKNOWN_SPEECH if total == 1 and AXUtilities.is_menu(obj): return [] position += 1 result.append(string % {"index": position, "total": total}) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ################################### KEYBOARD ################################### @log_generator_output def _generate_keyboard_accelerator( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result: list[Any] = [] accelerator = AXObject.get_accelerator(obj) if accelerator: result.append(accelerator) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_keyboard_mnemonic( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result: list[Any] = [] if settings_manager.get_manager().get_setting("enableMnemonicSpeaking") \ or args.get("forceMnemonic", False): mnemonic = AXObject.get_mnemonic(obj) if mnemonic: result = [mnemonic[-1]] # we just want a single character result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ##################################### LINK ##################################### @log_generator_output def _generate_link_info( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [] link_uri = AXHypertext.get_link_uri(obj) if not link_uri: result.extend(self._generate_accessible_label(obj)) result.extend(self._generate_accessible_role(obj)) result.append(AXText.get_all_text(obj)) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result link_uri_info = urllib.parse.urlparse(link_uri) if link_uri_info[0] in ["ftp", "ftps", "file"]: file_name = link_uri_info[2].split("/") result.append( messages.LINK_TO_FILE % {"uri" : link_uri_info[0], "file" : file_name[-1]}) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result link_output = messages.LINK_WITH_PROTOCOL % link_uri_info[0] text = AXText.get_all_text(obj) if not AXUtilities.is_visited(obj): link_output = messages.LINK_WITH_PROTOCOL % link_uri_info[0] else: link_output = messages.LINK_WITH_PROTOCOL_VISITED % link_uri_info[0] if not text: text = AXHypertext.get_link_basename(obj) if text: link_output += " " + text result.append(link_output) child = AXObject.get_child(obj, 0) if AXUtilities.is_image(child): result.extend(self._generate_accessible_role(child)) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_link_site_description( self, obj: Atspi.Accessible, **args ) -> list[Any]: link_uri = AXHypertext.get_link_uri(obj) if not link_uri: return [] link_uri_info = urllib.parse.urlparse(link_uri) doc_uri = AXDocument.get_uri(self._script.utilities.active_document()) if not doc_uri: return [] result = [] doc_uri_info = urllib.parse.urlparse(doc_uri) if link_uri_info[1] == doc_uri_info[1]: if link_uri_info[2] == doc_uri_info[2]: result.append(messages.LINK_SAME_PAGE) else: result.append(messages.LINK_SAME_SITE) else: link_domain = link_uri_info[1].split(".") doc_domain = doc_uri_info[1].split(".") if len(link_domain) > 1 and len(doc_domain) > 1 \ and link_domain[-1] == doc_domain[-1] \ and link_domain[-2] == doc_domain[-2]: result.append(messages.LINK_SAME_SITE) else: result.append(messages.LINK_DIFFERENT_SITE) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_link_file_size( self, obj: Atspi.Accessible, **args ) -> list[Any]: result: list[Any] = [] size_string = "" uri = AXHypertext.get_link_uri(obj) if not uri: return result try: with urllib.request.urlopen(uri) as x: try: size_string = x.info()["Content-length"] except KeyError: pass except (ValueError, urllib.error.URLError, OSError): pass if size_string: size = int(size_string) if size < 10000: result.append(messages.file_size_bytes(size)) elif size < 1000000: result.append(messages.FILE_SIZE_KB % (float(size) * .001)) elif size >= 1000000: result.append(messages.FILE_SIZE_MB % (float(size) * .000001)) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ##################################### MATH ##################################### @log_generator_output def _generate_math_contents( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [] children = list(AXObject.iter_children(obj)) if not children and not AXUtilities.is_math(obj): children = [obj] for child in children: if AXUtilities.is_math_layout_only(child) and AXObject.get_child_count(child): result.extend(self._generate_math_contents(child)) continue result.extend(self.generate(child, role=self._get_functional_role(child))) return result @log_generator_output def _generate_math_enclosed_enclosures( self, obj: Atspi.Accessible, **args ) -> list[Any]: strings = [] attrs = AXObject.get_attributes_dict(obj) enclosures = attrs.get("notation", "longdiv").split() if "actuarial" in enclosures: strings.append(messages.MATH_ENCLOSURE_ACTUARIAL) if "box" in enclosures: strings.append(messages.MATH_ENCLOSURE_BOX) if "circle" in enclosures: strings.append(messages.MATH_ENCLOSURE_CIRCLE) if "longdiv" in enclosures: strings.append(messages.MATH_ENCLOSURE_LONGDIV) if "radical" in enclosures: strings.append(messages.MATH_ENCLOSURE_RADICAL) if "roundedbox" in enclosures: strings.append(messages.MATH_ENCLOSURE_ROUNDEDBOX) if "horizontalstrike" in enclosures: strings.append(messages.MATH_ENCLOSURE_HORIZONTALSTRIKE) if "verticalstrike" in enclosures: strings.append(messages.MATH_ENCLOSURE_VERTICALSTRIKE) if "downdiagonalstrike" in enclosures: strings.append(messages.MATH_ENCLOSURE_DOWNDIAGONALSTRIKE) if "updiagonalstrike" in enclosures: strings.append(messages.MATH_ENCLOSURE_UPDIAGONALSTRIKE) if "northeastarrow" in enclosures: strings.append(messages.MATH_ENCLOSURE_NORTHEASTARROW) if "bottom" in enclosures: strings.append(messages.MATH_ENCLOSURE_BOTTOM) if "left" in enclosures: strings.append(messages.MATH_ENCLOSURE_LEFT) if "right" in enclosures: strings.append(messages.MATH_ENCLOSURE_RIGHT) if "top" in enclosures: strings.append(messages.MATH_ENCLOSURE_TOP) if "phasorangle" in enclosures: strings.append(messages.MATH_ENCLOSURE_PHASOR_ANGLE) if "madruwb" in enclosures: strings.append(messages.MATH_ENCLOSURE_MADRUWB) if not strings: tokens = ["SPEECH GENERATOR: Could not get enclosure message for", enclosures] debug.print_tokens(debug.LEVEL_INFO, tokens, True) return [] if len(strings) == 1: result = [messages.MATH_ENCLOSURE_ENCLOSED_BY % strings[0]] else: strings.insert(-1, messages.MATH_ENCLOSURE_AND) if len(strings) == 3: result = [messages.MATH_ENCLOSURE_ENCLOSED_BY % " ".join(strings)] else: result = [messages.MATH_ENCLOSURE_ENCLOSED_BY % ", ".join(strings)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_math_fenced_contents( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [] attrs = AXObject.get_attributes_dict(obj) separators = list(attrs.get("separators", ",")) child_count = AXObject.get_child_count(obj) separators.extend(separators[-1] for _ in range(len(separators), child_count - 1)) separators.append("") for i, child in enumerate(AXObject.iter_children(obj)): result.extend(self._generate_math_contents(child, **args)) separator_name = mathsymbols.get_character_name(separators[i]) result.append(separator_name) result.extend(self.voice(DEFAULT, obj=obj, **args)) if separator_name: result.extend(self._generate_pause(obj, **args)) return result @log_generator_output def _generate_math_fraction_numerator( self, obj: Atspi.Accessible, **args ) -> list[Any]: numerator = AXObject.get_child(obj, 0) if AXUtilities.is_math_layout_only(numerator): return self._generate_math_contents(numerator) result = self.generate(numerator, role=self._get_functional_role(numerator)) return result @log_generator_output def _generate_math_fraction_denominator( self, obj: Atspi.Accessible, **args ) -> list[Any]: denominator = AXObject.get_child(obj, 1) if AXUtilities.is_math_layout_only(denominator): return self._generate_math_contents(denominator) result = self.generate(denominator, role=self._get_functional_role(denominator)) return result @log_generator_output def _generate_math_fraction_line( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [messages.MATH_FRACTION_LINE] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_math_root_base( self, obj: Atspi.Accessible, **args ) -> list[Any]: is_square_root = AXUtilities.is_math_square_root(obj) if is_square_root: base = obj else: base = AXObject.get_child(obj, 0) if not base: return [] if is_square_root or AXUtilities.is_math_token(base) \ or AXUtilities.is_math_layout_only(base): return self._generate_math_contents(base) result = [self._generate_pause(obj, **args)] result.extend(self.generate(base, role=self._get_functional_role(base))) return result @log_generator_output def _generate_math_script_base( self, obj: Atspi.Accessible, **args ) -> list[Any]: base = AXObject.get_child(obj, 0) if not base: return [] return self._generate_math_contents(base) @log_generator_output def _generate_math_script_script( self, obj: Atspi.Accessible, **args ) -> list[Any]: if AXUtilities.is_math_layout_only(obj): return self._generate_math_contents(obj) result = self.generate(obj, role=self._get_functional_role(obj)) return result @log_generator_output def _generate_math_script_subscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: if AXObject.get_attribute(obj, "tag") == "msup": return [] subscript = AXObject.get_child(obj, 1) if not subscript: return [] result = [messages.MATH_SUBSCRIPT] result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_math_script_script(subscript)) return result @log_generator_output def _generate_math_script_superscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: tag = AXObject.get_attribute(obj, "tag") if tag == "msup": superscript = AXObject.get_child(obj, 1) elif tag == "msubsup": superscript = AXObject.get_child(obj, 2) else: return [] result = [messages.MATH_SUPERSCRIPT] result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_math_script_script(superscript)) return result @log_generator_output def _generate_math_script_underscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: if AXObject.get_attribute(obj, "tag") == "mover": return [] underscript = AXObject.get_child(obj, 1) if not underscript: return [] result = [messages.MATH_UNDERSCRIPT] result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_math_script_script(underscript)) return result @log_generator_output def _generate_math_script_overscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: tag = AXObject.get_attribute(obj, "tag") if tag == "mover": overscript = AXObject.get_child(obj, 1) elif tag == "munderover": overscript = AXObject.get_child(obj, 2) else: return [] result = [messages.MATH_OVERSCRIPT] result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_math_script_script(overscript)) return result @log_generator_output def _generate_math_script_prescripts( self, obj: Atspi.Accessible, **args ) -> list[Any]: prescripts = [] found_separator = False for child in AXObject.iter_children(obj): if AXObject.get_attribute(child, "tag") == "mprescripts": found_separator = True continue if found_separator: prescripts.append(child) result = [] for i, script in enumerate(prescripts): if AXUtilities.is_math_layout_only(script): continue if i % 2: rv = [messages.MATH_PRE_SUPERSCRIPT] else: rv = [messages.MATH_PRE_SUBSCRIPT] rv.extend(self.voice(SYSTEM, obj=obj, **args)) rv.extend(self._generate_math_script_script(script)) result.append(rv) return result @log_generator_output def _generate_math_script_postscripts( self, obj: Atspi.Accessible, **args ) -> list[Any]: postscripts = [] child = AXObject.get_child(obj, 1) while child and AXObject.get_attribute(child, "tag") != "mprescripts": postscripts.append(child) child = AXObject.get_next_sibling(child) result = [] for i, script in enumerate(postscripts): if AXUtilities.is_math_layout_only(script): continue if i % 2: rv = [messages.MATH_SUPERSCRIPT] else: rv = [messages.MATH_SUBSCRIPT] rv.extend(self.voice(SYSTEM, obj=obj, **args)) rv.extend(self._generate_math_script_script(script)) result.append(rv) return result @log_generator_output def _generate_math_table_rows( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = [] for row in AXObject.iter_children(obj): result.extend(self.generate(row, role=self._get_functional_role(row))) return result ############################### START-OF/END-OF ################################ @log_generator_output def _generate_start_of_deletion( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] start_offset = args.get("startOffset", 0) if start_offset != 0: return [] result = [] suggestion = AXObject.find_ancestor(obj, AXUtilities.is_inline_suggestion) if suggestion and obj == AXObject.get_child(suggestion, 0): result.extend([object_properties.ROLE_CONTENT_SUGGESTION]) result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_pause(obj, **args)) result.extend([messages.CONTENT_DELETION_START]) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_deletion( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] end_offset = args.get("endOffset") if end_offset is not None: length = AXText.get_character_count(obj) if length and length != end_offset: return [] result = [messages.CONTENT_DELETION_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) suggestion = AXObject.find_ancestor(obj, AXUtilities.is_inline_suggestion) if suggestion and obj == AXObject.get_child( suggestion, AXObject.get_child_count(suggestion) - 1): result.extend(self._generate_pause(obj, **args)) result.extend([messages.CONTENT_SUGGESTION_END]) result.extend(self.voice(SYSTEM, obj=obj, **args)) container = AXObject.find_ancestor(obj, lambda x: bool(AXUtilities.get_details(x))) if AXUtilities.is_suggestion(container): result.extend(self._generate_pause(obj, **args)) result.extend(self._generate_has_details(container)) return result @log_generator_output def _generate_start_of_insertion( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] start_offset = args.get("startOffset", 0) if start_offset != 0: return [] result = [] suggestion = AXObject.find_ancestor(obj, AXUtilities.is_inline_suggestion) if suggestion and obj == AXObject.get_child(suggestion, 0): result.extend([object_properties.ROLE_CONTENT_SUGGESTION]) result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_pause(obj, **args)) result.extend([messages.CONTENT_INSERTION_START]) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_insertion( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] end_offset = args.get("endOffset") if end_offset is not None: length = AXText.get_character_count(obj) if length and length != end_offset: return [] result = [messages.CONTENT_INSERTION_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) suggestion = AXObject.find_ancestor(obj, AXUtilities.is_inline_suggestion) if suggestion and obj == AXObject.get_child( suggestion, AXObject.get_child_count(suggestion) - 1): result.extend(self._generate_pause(obj, **args)) result.extend([messages.CONTENT_SUGGESTION_END]) result.extend(self.voice(SYSTEM, obj=obj, **args)) container = AXObject.find_ancestor(obj, lambda x: bool(AXUtilities.get_details(x))) if AXUtilities.is_suggestion(container): result.extend(self._generate_pause(obj, **args)) result.extend(self._generate_has_details(container)) return result @log_generator_output def _generate_start_of_mark( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] start_offset = args.get("startOffset", 0) if start_offset != 0: return [] result: list[Any] = [] role_description = AXObject.get_role_description(obj) if role_description: result.append(role_description) result.extend(self.voice(SYSTEM, obj=obj, **args)) result.extend(self._generate_pause(obj, **args)) result.append(messages.CONTENT_MARK_START) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_mark( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] end_offset = args.get("endOffset") if end_offset is not None: length = AXText.get_character_count(obj) if length and length != end_offset: return [] result = [messages.CONTENT_MARK_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_start_of_math_fenced( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] attrs = AXObject.get_attributes_dict(obj) fence_start = attrs.get("open", "(") result = [mathsymbols.get_character_name(fence_start)] result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_end_of_math_fenced( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] attrs = AXObject.get_attributes_dict(obj) fence_end = attrs.get("close", ")") result = [mathsymbols.get_character_name(fence_end)] result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_start_of_math_fraction( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if AXUtilities.is_math_fraction_without_bar(obj): result = [messages.MATH_FRACTION_WITHOUT_BAR_START] else: result = [messages.MATH_FRACTION_START] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_math_fraction( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = [messages.MATH_FRACTION_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_start_of_math_root( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = [] if AXUtilities.is_math_square_root(obj): result = [messages.MATH_SQUARE_ROOT_OF] else: index = AXObject.get_child(obj, 1) string = AXText.get_all_text(index) if string == "2": result = [messages.MATH_SQUARE_ROOT_OF] elif string == "3": result = [messages.MATH_CUBE_ROOT_OF] elif string: result = [string] result.extend([messages.MATH_ROOT_OF]) elif AXUtilities.is_math_layout_only(index): result = self._generate_math_contents(index) result.extend([messages.MATH_ROOT_OF]) else: result.extend(self.generate(index, role=self._get_functional_role(index))) result.extend([messages.MATH_ROOT_OF]) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_math_root( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = [messages.MATH_ROOT_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_start_of_math_table( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if not AXObject.supports_table(obj): return [] rows = AXTable.get_row_count(obj) columns = AXTable.get_column_count(obj) nesting_level = self._get_nesting_level(obj) if nesting_level > 0: result = [messages.math_nested_table_size(rows, columns)] else: result = [messages.math_table_size(rows, columns)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_end_of_math_table( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] nesting_level = self._get_nesting_level(obj) if nesting_level > 0: result = [messages.MATH_NESTED_TABLE_END] else: result = [messages.MATH_TABLE_END] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ##################################### STATE ##################################### @log_generator_output def _generate_state_current( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_current(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_checked( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_checked(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_checked_for_switch( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_checked_for_switch(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_checked_if_checkable( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_checked_if_checkable(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_expanded( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_expanded(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_has_popup( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText") \ or settings_manager.get_manager().get_setting("speechVerbosityLevel") \ == settings.VERBOSITY_LEVEL_BRIEF: return [] if AXUtilities.is_menu(obj) or not AXUtilities.has_popup(obj): return [] return [messages.HAS_POPUP, self.voice(SYSTEM, obj=obj, **args)] @log_generator_output def _generate_state_invalid( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_invalid(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_state_multiselectable( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_multiselectable(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_pressed( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_pressed(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_read_only( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_state_read_only(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_state_required( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if args.get("alreadyFocused"): return [] result = super()._generate_state_required(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_state_selected_for_radio_button( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_selected_for_radio_button(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_sensitive( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] result = super()._generate_state_sensitive(obj, **args) if result: result.extend(self.voice(STATE, obj=obj, **args)) return result @log_generator_output def _generate_state_unselected( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if args.get("inMouseReview"): return [] if not obj: return [] if not AXUtilities.is_selectable(obj): return [] if AXUtilities.is_selected(obj): return [] if AXUtilities.is_text(obj, args.get("role")): return [] if AXUtilities.is_list_item(obj, args.get("role")): result = [object_properties.STATE_UNSELECTED_LIST_ITEM] result.extend(self.voice(STATE, obj=obj, **args)) return result parent = AXObject.get_parent(obj) table = AXTable.get_table(obj) if table: if input_event_manager.get_manager().last_event_was_left_or_right(): return [] if AXTable.is_layout_table(table): return [] if not self._script.utilities.is_gui_cell(obj): return [] elif AXUtilities.is_layered_pane(parent): if obj in self._script.utilities.selected_children(parent): return [] else: return [] result = [object_properties.STATE_UNSELECTED_TABLE_CELL] result.extend(self.voice(STATE, obj=obj, **args)) return result ################################## POSITION ##################################### @log_generator_output def _generate_nesting_level( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_nesting_level(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_tree_item_level( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] args["newOnly"] = True result = super()._generate_tree_item_level(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ################################ PROGRESS BARS ################################## @log_generator_output def _generate_progress_bar_index( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not args.get("isProgressBarUpdate") \ or not self._should_present_progress_bar_update(obj, **args): return [] result = [] acc = self._get_most_recent_progress_bar_update()[0] if acc != obj: number = self._get_progress_bar_number_and_count(obj)[0] result = [messages.PROGRESS_BAR_NUMBER % (number)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_progress_bar_value( self, obj: Atspi.Accessible, **args ) -> list[Any]: if args.get("isProgressBarUpdate") \ and not self._should_present_progress_bar_update(obj, **args): return [""] result = [] percent = AXValue.get_value_as_percent(obj) if percent is not None: result.append(messages.percentage(percent)) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result def _get_progress_bar_update_interval(self): interval = settings_manager.get_manager().get_setting("progressBarSpeechInterval") if interval is None: interval = super()._get_progress_bar_update_interval() return int(interval) def _should_present_progress_bar_update(self, obj, **args): if not settings_manager.get_manager().get_setting("speakProgressBarUpdates"): return False return super()._should_present_progress_bar_update(obj, **args) ##################################### TABLE ##################################### # TODO - JD: This function and fake role really need to die.... @log_generator_output def _generate_real_table_cell( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_real_table_cell(obj, **args) if not (result and result[0]) \ and settings_manager.get_manager().get_setting("speakBlankLines") \ and not args.get("readingRow", False) \ and args.get("formatType") != "ancestor": result.append(messages.BLANK) if result: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_table_cell_column_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not settings_manager.get_manager().get_setting("speakCellHeaders"): return [] if focus_manager.get_manager().in_say_all(): return [] if not self._script.utilities.cell_column_changed(obj, args.get("priorObj")) \ and not args.get("formatType", "").endswith("WhereAmI"): return [] args["newOnly"] = not self._get_is_nameless_toggle(obj) result = super()._generate_table_cell_column_header(obj, **args) if result: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_table_cell_row_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: if args.get("readingRow"): return [] if not settings_manager.get_manager().get_setting("speakCellHeaders"): return [] if focus_manager.get_manager().in_say_all(): return [] if not self._script.utilities.cell_row_changed(obj, args.get("priorObj")) \ and not args.get("formatType", "").endswith("WhereAmI"): return [] args["newOnly"] = True result = super()._generate_table_cell_row_header(obj, **args) if result: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_table_size( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if args.get("leaving"): return [] if AXTable.is_layout_table(obj): return [] if self._script.utilities.is_spreadsheet_table(obj): return [] if settings_manager.get_manager().get_setting("speechVerbosityLevel") \ == settings.VERBOSITY_LEVEL_BRIEF: return self._generate_accessible_role(obj, **args) if self._script.utilities.is_text_document_table(obj): role = args.get("role", AXObject.get_role(obj)) _enabled, disabled = self._get_enabled_and_disabled_context_roles() if role in disabled: return [] rows = AXTable.get_row_count(obj) cols = AXTable.get_column_count(obj) if (rows < 0 or cols < 0) and not AXUtilities.get_set_size_is_unknown(obj): return [] result = [messages.table_size(rows, cols)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_table_sort_order( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_table_sort_order(obj, **args) if result: result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_table_cell_column_index( self, obj: Atspi.Accessible, **args ) -> list[Any]: if args.get("readingRow"): return [] if not settings_manager.get_manager().get_setting("speakCellCoordinates"): return [] if not self._script.utilities.cell_column_changed(obj): return [] col = AXTable.get_cell_coordinates(obj, find_cell=True)[1] if col == -1: return [] result = [messages.TABLE_COLUMN % (col + 1)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_table_cell_row_index( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not self._script.utilities.cell_row_changed(obj): return [] if args.get("readingRow"): return [] if not settings_manager.get_manager().get_setting("speakCellCoordinates"): return [] row = AXTable.get_cell_coordinates(obj, find_cell=True)[0] if row == -1: return [] result = [messages.TABLE_ROW % (row + 1)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_table_cell_position( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] row, col = AXTable.get_cell_coordinates(obj, find_cell=True) if row == -1 or col == -1: return [] table = AXTable.get_table(obj) if table is None: return [] result = [] rows = AXTable.get_row_count(table) columns = AXTable.get_column_count(table) result.append(messages.TABLE_COLUMN_DETAILED % {"index" : (col + 1), "total" : columns}) result.append(messages.TABLE_ROW_DETAILED % {"index" : (row + 1), "total" : rows}) result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ##################################### TEXT ###################################### @log_generator_output def _generate_text_substring( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_text_substring(obj, **args) if not result: return [] result.extend(self.voice(DEFAULT, obj=obj, **args)) if result[0] in ["\n", ""]: if args.get("total", 1) > 1: return [""] if settings_manager.get_manager().get_setting("speakBlankLines") \ and not focus_manager.get_manager().in_say_all() \ and not AXUtilities.is_table_cell_or_header(obj) \ and args.get("formatType") != "ancestor": result[0] = messages.BLANK manager = speech_and_verbosity_manager.get_manager() result[0] = manager.adjust_for_presentation(obj, result[0]) return result @log_generator_output def _generate_text_line( self, obj: Atspi.Accessible, **args ) -> list[Any]: if args.get("inMouseReview") and AXUtilities.is_editable(obj): return [] result = self._generate_text_substring(obj, **args) if result: return result text, start_offset = AXText.get_line_at_offset(obj)[0:2] if text == "\n": if args.get("total", 1) > 1: return [""] if settings_manager.get_manager().get_setting("speakBlankLines") \ and not focus_manager.get_manager().in_say_all() \ and not AXUtilities.is_table_cell_or_header(obj) \ and args.get("formatType") != "ancestor": result = [messages.BLANK] result.extend(self.voice(string=text, obj=obj, **args)) return result end_offset = start_offset + len(text) for start, _end, string, language, dialect in \ self._script.utilities.split_substring_by_language(obj, start_offset, end_offset): string = string.replace("\ufffc", "") if not string: continue args["language"], args["dialect"] = language, dialect if "string" in args: msg = f"INFO: Found existing string '{args.get('string')}'; using '{string}'" debug.print_message(debug.LEVEL_INFO, msg, True) args.pop("string") voice = self.voice(string=string, obj=obj, **args) manager = speech_and_verbosity_manager.get_manager() rv: list[Any] = [manager.adjust_for_presentation(obj, string, start)] rv.extend(voice) # TODO - JD: speech.speak() has a bug which causes a list of utterances to # be presented before a string+voice pair that comes first. Until we can # fix speak() properly, we'll avoid triggering it here. # result.append(rv) result.extend(rv) return result @log_generator_output def _generate_text_content( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = self._generate_text_substring(obj, **args) if result and result[0]: return result result = super()._generate_text_content(obj, **args) if not (result and result[0]): return [] string = result[0].strip() if len(string) == 1 and AXUtilities.is_math_related(obj): charname = mathsymbols.get_character_name(string) if charname and charname != string: result[0] = charname manager = speech_and_verbosity_manager.get_manager() result[0] = manager.adjust_for_presentation(obj, result[0]) result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_text_selection( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] if not AXText.is_all_text_selected(obj): return [] result = [messages.TEXT_SELECTED] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result @log_generator_output def _generate_text_indentation( self, obj: Atspi.Accessible, **args ) -> list[Any]: if not settings_manager.get_manager().get_setting("enableSpeechIndentation"): return [] if input_event_manager.get_manager().last_event_was_word_navigation(): return [] format_type = args.get("formatType", "unfocused") only_if_changed = None if format_type.endswith("WhereAmI"): only_if_changed = False line = AXText.get_line_at_offset(obj, args.get("startOffset"))[0] description = speech_and_verbosity_manager.get_manager().get_indentation_description( line, only_if_changed) if not description: return [] result: list[Any] = [description] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result ##################################### VALUE ##################################### @log_generator_output def _generate_value( self, obj: Atspi.Accessible, **args ) -> list[Any]: result = super()._generate_value(obj, **args) if result: result.extend(self.voice(DEFAULT, obj=obj, **args)) return result @log_generator_output def _generate_value_as_percentage( self, obj: Atspi.Accessible, **args ) -> list[Any]: if settings_manager.get_manager().get_setting("onlySpeakDisplayedText"): return [] percent_value = AXValue.get_value_as_percent(obj) if percent_value is not None: result = [messages.percentage(percent_value)] result.extend(self.voice(SYSTEM, obj=obj, **args)) return result return [] ################################### PER-ROLE ################################### def _generate_default_prefix( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Provides the default/role-agnostic information to present before obj.""" if args.get("includeContext") is False: return [] format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_details_for(obj, **args) if format_type == "unfocused": return self._generate_old_ancestors(obj, **args) + \ self._generate_new_ancestors(obj, **args) if format_type == "detailedWhereAmI": return self._generate_ancestors(obj, **args) return [] def _generate_default_presentation( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Provides a default/role-agnostic presentation of obj.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return result result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_default_suffix( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Provides the default/role-agnostic information to present after obj.""" if args.get("includeContext") is False: return [] if obj == args.get("priorObj"): return [] # Do not call _generate_accessible_static_text here for ancestors. # The roles of objects which typically have static text we want to # present (panels, groupings, dialogs) already generate it. If we # include it here, it will be double-presented. format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return [] result = [] if format_type.endswith("WhereAmI"): result += self._generate_tutorial(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_state_current(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_has_click_action(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_has_details(obj, **args) result += self._generate_details_for(obj, **args) result += self._generate_accessible_description(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_state_has_popup(obj, **args) if format_type == "unfocused": result += self._generate_tutorial(obj, **args) return result def _generate_accelerator_label( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the accelerator-label role.""" return self._generate_default_presentation(obj, **args) def _generate_alert( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the alert role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_static_text(obj, **args) return result def _generate_animation( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the animation role.""" return self._generate_default_presentation(obj, **args) def _generate_application( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the application role.""" return self._generate_default_presentation(obj, **args) def _generate_arrow( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the arrow role.""" return self._generate_default_presentation(obj, **args) def _generate_article( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the article role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return result result += self._generate_pause(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_article_in_feed( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the article role when the article is in a feed.""" result = [] result += self._generate_accessible_label_and_name(obj, **args) if not result: result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_role(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return self._generate_default_prefix(obj, **args) + result def _generate_audio( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the audio role.""" return self._generate_default_presentation(obj, **args) def _generate_autocomplete( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the autocomplete role.""" return self._generate_default_presentation(obj, **args) def _generate_block_quote( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the block-quote role.""" result = [] if args.get("priorObj") != obj: result += self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_nesting_level(obj, **args) result += self._generate_text_line(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) or result result += self._generate_default_suffix(obj, **args) return result def _generate_calendar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the calendar role.""" return self._generate_default_presentation(obj, **args) def _generate_canvas( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the canvas role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type.endswith("WhereAmI"): result += self._generate_parent_role_name(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_accessible_image_description(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_pause(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_selected_item_count(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_selected_items(obj, **args) else: result += self._generate_position_in_list(obj, **args) result += self._generate_state_unselected(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_caption( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the caption role.""" result = [] if self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return self._generate_default_prefix(obj, **args) + result def _generate_chart( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the chart role.""" return self._generate_default_presentation(obj, **args) def _generate_check_box( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the check-box role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_checked(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_checked(obj, **args) result += self._generate_state_required(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_check_menu_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the check-menu-item role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_checked(obj, **args) result = self._generate_default_prefix(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_ancestors(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_checked(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_color_chooser( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the color-chooser role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_value(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_value_as_percentage(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_column_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the column-header role.""" result = [] format_type = args.get("formatType", "unfocused") if format_type != "focused" and self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_table_sort_order(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_table_cell_row_index(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_table_cell_column_index(obj, **args) result += self._generate_default_suffix(obj, **args) return self._generate_default_prefix(obj, **args) + result def _generate_combo_box( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the combo-box role.""" result = [] result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_state_expanded(obj, **args) return result result += self._generate_value(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_required(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return self._generate_default_prefix(obj, **args) + result def _generate_comment( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the comment role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return result result += self._generate_pause(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_content_deletion( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the content-deletion role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) \ or self._generate_start_of_deletion(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_start_of_deletion(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_deletion(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_content_insertion( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the content-insertion role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) \ or self._generate_start_of_insertion(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_start_of_insertion(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_insertion(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_date_editor( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the date-editor role.""" return self._generate_default_presentation(obj, **args) def _generate_definition( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the definition role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_description_list( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the description-list role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result = self._generate_leaving(obj, **args) if result: return result result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_number_of_children(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_nesting_level(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_description_term( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the description-term role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return [] result = self._generate_default_prefix(obj, **args) if self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) else: result += (self._generate_accessible_label_and_name(obj, **args) or \ self._generate_text_line(obj, **args)) if settings_manager.get_manager().get_setting("speakContextList"): if args.get("index", 0) + 1 < args.get("total", 1): return result result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_term_value_count(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_description_value( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the description-value role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return [] result = self._generate_default_prefix(obj, **args) result += (self._generate_accessible_label_and_name(obj, **args) or \ self._generate_text_line(obj, **args)) if settings_manager.get_manager().get_setting("speakContextList"): if args.get("index", 0) + 1 < args.get("total", 1): return result result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_desktop_frame( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the desktop-frame role.""" return self._generate_default_presentation(obj, **args) def _generate_desktop_icon( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the desktop-icon role.""" return self._generate_icon(obj, **args) def _generate_dial( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the dial role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_value(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) result += self._generate_state_required(obj, **args) result += self._generate_value_as_percentage(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_dialog( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the dialog role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused": result = self._generate_text_expanding_embedded_objects(obj, **args) if result: return result result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_static_text(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_directory_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the directory_pane role.""" return self._generate_default_presentation(obj, **args) def _generate_document( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for document-related roles.""" result = [] prior_doc = None if prior_obj := args.get("priorObj"): prior_doc = AXObject.find_ancestor_inclusive(prior_obj, AXUtilities.is_document) if prior_doc != obj: result += self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) if prior_doc != obj: result += self._generate_default_suffix(obj, **args) return result def _generate_document_email( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-email role.""" return self._generate_document(obj, **args) def _generate_document_frame( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-frame role.""" return self._generate_document(obj, **args) def _generate_document_presentation( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-presentation role.""" return self._generate_document(obj, **args) def _generate_document_spreadsheet( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-spreadsheet role.""" return self._generate_document(obj, **args) def _generate_document_text( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-text role.""" return self._generate_document(obj, **args) def _generate_document_web( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the document-web role.""" return self._generate_document(obj, **args) def _generate_dpub_landmark( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the dpub section role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) or result result += self._generate_pause(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_dpub_section( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the dpub section role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) or result result += self._generate_pause(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_drawing_area( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the drawing-area role.""" return self._generate_default_presentation(obj, **args) def _generate_editbar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the editbar role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_text_indentation(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_text_selection(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_embedded( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the embedded role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused": result += (self._generate_text_expanding_embedded_objects(obj, **args) \ or self._generate_accessible_static_text(obj, **args)) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_entry( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the entry role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_indentation(obj, **args) result += (self._generate_text_line(obj, **args) \ or self._generate_accessible_placeholder_text(obj, **args)) result += self._generate_text_selection(obj, **args) result += self._generate_state_required(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_feed( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the feed role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_leaving(obj, **args) if result: return result result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_number_of_children(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_default_suffix(obj, **args) return result def _generate_file_chooser( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the file-chooser role.""" return self._generate_dialog(obj, **args) def _generate_filler( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the filler role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_font_chooser( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the font-chooser role.""" return self._generate_dialog(obj, **args) def _generate_footer( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the footer role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_footnote( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the footnote role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_form( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the form role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) \ or (self._generate_accessible_label_and_name(obj, **args) + \ self._generate_accessible_role(obj, **args)) result = self._generate_default_prefix(obj, **args) if self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) else: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_frame( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the frame role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_accessible_label_and_name(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_unfocused_dialog_count(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_glass_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the glass-pane role.""" return self._generate_default_presentation(obj, **args) def _generate_grouping( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the grouping role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_leaving(obj, **args) if result: return result if self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_static_text(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the header role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_heading( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the heading role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_html_container( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the html-container role.""" return self._generate_default_presentation(obj, **args) def _generate_icon( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the icon role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type.endswith("WhereAmI"): result += self._generate_parent_role_name(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_accessible_image_description(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_pause(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_selected_item_count(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_selected_items(obj, **args) else: result += self._generate_position_in_list(obj, **args) result += self._generate_state_unselected(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_image( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the image role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_has_long_description(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_image_map( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the image-map role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_info_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the info-bar role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_static_text(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_input_method_window( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the input-method-window role.""" return self._generate_default_presentation(obj, **args) def _generate_internal_frame( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the internal-frame role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_label( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the label role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label(obj, **args) result += (self._generate_text_content(obj) or self._generate_accessible_name(obj)) result += self._generate_text_selection(obj) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_landmark( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the landmark role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result = self._generate_leaving(obj, **args) if not result: result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) return result result = self._generate_default_prefix(obj, **args) prior_obj = args.get("priorObj") if prior_obj and obj != prior_obj and not AXObject.is_ancestor(prior_obj, obj): result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_layered_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the layered-pane role.""" result = self._generate_default_prefix(obj, **args) result += (self._generate_accessible_label_and_name(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_state_sensitive(obj, **args) result += self._generate_number_of_children(obj, **args) format_type = args.get("formatType", "unfocused") if not format_type.endswith("WhereAmI"): return result result += self._generate_selected_item_count(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_selected_items(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_level_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the level-bar role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_value(obj, **args) result = [] result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_link( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the link role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type.endswith("WhereAmI"): result += self._generate_link_info(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_link_site_description(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_link_file_size(obj, **args) return result result += (self._generate_accessible_label_and_name(obj, **args) \ or self._generate_text_content(obj, **args)) result += self._generate_accessible_role(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_list( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the list role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_leaving(obj, **args) if result: return result result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_number_of_children(obj, **args) \ or self._generate_accessible_role(obj, **args)) if AXUtilities.is_gui_list(obj): result += self._generate_accessible_static_text(obj, **args) else: result += self._generate_nesting_level(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_list_box( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the list-box role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") result += self._generate_accessible_label_and_name(obj, **args) if format_type not in ["focused", "ancestor"]: result += self._generate_focused_item(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_multiselectable(obj, **args) result += (self._generate_number_of_children(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_default_suffix(obj, **args) return result def _generate_list_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the list-item role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_state_checked_if_checkable(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_expanded(obj, **args) return result result += (self._generate_text_line(obj, **args) or \ self._generate_accessible_label_and_name(obj, **args)) result += self._generate_accessible_role(obj, **args) result += self._generate_state_checked_if_checkable(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_unselected(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_expanded(obj, **args) if AXUtilities.is_focusable(obj): result += self._generate_descendants(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_log( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the log role.""" return self._generate_default_presentation(obj, **args) def _generate_mark( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the mark role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) or self._generate_start_of_mark(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_start_of_mark(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_mark(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_marquee( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the marquee role.""" return self._generate_default_presentation(obj, **args) def _generate_math( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math role.""" # TODO - JD: Move this logic here. return self._generate_math_contents(obj, **args) def _generate_math_enclosed( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-enclosed role.""" result = [] result += self._generate_math_contents(obj, **args) # TODO - JD: Move this logic here. result += self._generate_math_enclosed_enclosures(obj, **args) return result def _generate_math_fenced( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-fenced role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_start_of_math_fenced(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_fenced_contents(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_math_fenced(obj, **args) return result def _generate_math_fraction( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-fraction role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_start_of_math_fraction(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_fraction_numerator(obj, **args) result += self._generate_math_fraction_line(obj, **args) result += self._generate_math_fraction_denominator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_math_fraction(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_math_multiscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-multiscript role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_math_script_base(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_prescripts(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_postscripts(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_math_root( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-root role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_start_of_math_root(obj, **args) result += self._generate_math_root_base(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_end_of_math_root(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_math_row( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-row role.""" result = [messages.TABLE_ROW % (AXObject.get_index_in_parent(obj) + 1)] result += (self.voice(SYSTEM, obj=obj, **args)) result += self._generate_pause(obj, **args) for child in AXObject.iter_children(obj): result += self._generate_math_contents(child) result += self._generate_pause(child, **args) return result def _generate_math_script_subsuper( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math script subsuper role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_math_script_base(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_subscript(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_superscript(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_math_script_underover( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math script underover role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_math_script_base(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_underscript(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_script_overscript(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_math_table( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the math-table role.""" # TODO - JD: Move the logic from these functions here. result = [] result += self._generate_start_of_math_table(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_math_table_rows(obj, **args) result += self._generate_end_of_math_table(obj, **args) result += self._generate_pause(obj, **args) return result def _generate_menu( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the menu role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) return result if format_type.endswith("WhereAmI"): result += (self._generate_ancestors(obj, **args) \ or self._generate_parent_role_name(obj, **args)) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_menu_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the menu-bar role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_menu_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the menu-item role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_expanded(obj, **args) result = self._generate_default_prefix(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_ancestors(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_checked_if_checkable(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_notification( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the notification role.""" # TODO - JD: Should this instead or also be using the logic in get_notification_content()? result = [] result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_pause(obj, **args) result += (self._generate_text_expanding_embedded_objects(obj, **args) \ or self._generate_accessible_static_text(obj, **args)) result += self._generate_default_suffix(obj, **args) return result def _generate_option_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the option-pane role.""" return self._generate_default_presentation(obj, **args) def _generate_page( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the page role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_page_tab( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the page-tab role.""" format_type = args.get("formatType", "unfocused") if format_type == "ancestor": result = self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) return result result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_page_tab_list( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the page-tab-list role.""" return self._generate_default_presentation(obj, **args) def _generate_panel( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the panel role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result += self._generate_leaving(obj, **args) if result: return result if self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_static_text(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_paragraph( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the paragraph role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_indentation(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_password_text( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the password-text role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_text_selection(obj, **args) result += self._generate_state_required(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_popup_menu( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the popup-menu role.""" return self._generate_menu(obj, **args) def _generate_progress_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the progress-bar role.""" result = [] result += self._generate_progress_bar_index(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused": result += self._generate_accessible_label_and_name(obj, **args) result += (self._generate_progress_bar_value(obj, **args) \ or self._generate_accessible_role(obj, **args)) result += self._generate_default_suffix(obj, **args) return result def _generate_push_button( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the push-button role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_expanded(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_push_button_menu( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the push-button-menu role.""" return self._generate_push_button(obj, **args) def _generate_radio_button( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the radio-button role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_selected_for_radio_button(obj, **args) result = self._generate_default_prefix(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_radio_button_group(obj, **args) else: result += self._generate_new_radio_button_group(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_selected_for_radio_button(obj, **args) result += self._generate_accessible_role(obj, **args) if not AXUtilities.is_focused(obj): return result result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_radio_menu_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the radio-menu-item role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_selected_for_radio_button(obj, **args) result = self._generate_default_prefix(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_ancestors(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_selected_for_radio_button(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_rating( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the rating role.""" return self._generate_default_presentation(obj, **args) def _generate_region( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the region landmark role.""" result = self._generate_default_prefix(obj, **args) prior_obj = args.get("priorObj") if prior_obj and obj != prior_obj and not AXObject.is_ancestor(prior_obj, obj): result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) or result result += self._generate_pause(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_root_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the root-pane role.""" return self._generate_default_presentation(obj, **args) def _generate_row_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the row-header role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused" and self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_table_sort_order(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_table_cell_row_index(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_table_cell_column_index(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_ruler( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the ruler role.""" return self._generate_default_presentation(obj, **args) def _generate_scroll_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the scroll-bar role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_value(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) result += self._generate_value_as_percentage(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_scroll_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the scroll-pane role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_section( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the section role.""" format_type = args.get("formatType", "unfocused") result = self._generate_default_prefix(obj, **args) if AXUtilities.is_focusable(obj) \ and (AXUtilities.has_explicit_name(obj) \ or focus_manager.get_manager().get_in_focus_mode()): result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_pause(obj, **args) if format_type == "ancestor": return result result += self._generate_text_indentation(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_separator( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the separator role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return result result += (self._generate_accessible_label_and_name(obj, **args) \ or self._generate_text_content(obj, **args) \ or self._generate_value(obj, **args)) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_slider( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the slider role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_value(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) result += self._generate_value_as_percentage(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_spin_button( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the spin-button role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_text_content(obj, **args) or self._generate_value(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) + result result += self._generate_accessible_role(obj, **args) result += (self._generate_text_content(obj, **args) or self._generate_value(obj, **args)) result += self._generate_state_required(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_split_pane( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the split-pane role.""" format_type = args.get("formatType", "unfocused") if format_type == "focused": return self._generate_value(obj, **args) if format_type == "ancestor": return [] result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_value(obj, **args) result += self._generate_value_as_percentage(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_static( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the static role.""" result = self._generate_default_prefix(obj, **args) if AXUtilities.is_code(obj): result += self._generate_text_indentation(obj, **args) result += self._generate_text_line(obj, **args) else: result += (self._generate_text_content(obj, **args) \ or self._generate_accessible_name(obj, **args)) result += self._generate_accessible_role(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_status_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the status-bar role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return result content = self._generate_descendants(obj, **args) \ or self._generate_text_content(obj, **args) if not content and AXObject.get_child_count(obj) == 1: content = self._generate_text_content(AXObject.get_child(obj, 0), **args) if content: result += self._generate_pause(obj, **args) + content result += self._generate_default_suffix(obj, **args) return result def _generate_subscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the subscript role.""" result = [] result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_suggestion( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the suggestion role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) \ or self._generate_accessible_role(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_text_content(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_superscript( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the superscript role.""" result = [] result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_switch( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the switch role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_checked_for_switch(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_checked_for_switch(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_table( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: result = self._generate_leaving(obj, **args) if result: return result result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_table_size(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_table_cell( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table-cell role.""" # TODO - JD: There should be separate generators for each type of cell. result = self._generate_default_prefix(obj, **args) result = self._generate_table_cell_row_header(obj, **args) result += self._generate_table_cell_column_header(obj, **args) result += self._generate_state_checked_for_cell(obj, **args) result += (self._generate_real_active_descendant_displayed_text(obj, **args) \ or self._generate_accessible_label_and_name(obj, **args) \ or self._generate_accessible_image_description(obj, **args)) result += self._generate_state_expanded(obj, **args) result += self._generate_number_of_children(obj, **args) result += self._generate_state_required(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_state_invalid(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_state_sensitive(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_tree_item_level(obj, **args) result += self._generate_state_unselected(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_table_cell_in_row( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table-cell role in the context of its row.""" format_type = args.get("formatType", "unfocused") if format_type == "focused": result = self._generate_state_checked_for_cell(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_state_expanded(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_number_of_children(obj, **args) return result if format_type == "ancestor": result = self._generate_table_cell_row_header(obj, **args) result += self._generate_table_cell_column_header(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_row_index(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_column_index(obj, **args) return result if format_type.endswith("WhereAmI"): result = self._generate_row_header(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result = self._generate_column_header(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_table_cell_row(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_position(obj, **args) return result result = self._generate_table_cell_row(obj, **args) return result def _generate_table_column_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table-column-header role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused" and self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_table_sort_order(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_row_index(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_column_index(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_table_row( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table-row role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_expanded(obj, **args) result = self._generate_default_prefix(obj, **args) result += (self._generate_accessible_label_and_name(obj, **args) \ or self._generate_text_content(obj, **args)) result += self._generate_pause(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_table_row_header( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the table-row-header role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if format_type != "focused" and self._generate_text_substring(obj, **args): result += self._generate_text_line(obj, **args) if not result: result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_table_sort_order(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_row_index(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_table_cell_column_index(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_tearoff_menu_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tearoff-menu-item role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_state_expanded(obj, **args) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_accelerator(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_terminal( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the terminal role.""" result = self._generate_default_prefix(obj, **args) format_type = args.get("formatType", "unfocused") if not format_type.endswith("WhereAmI"): return result + self._generate_text_line(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_text_line(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_text( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the text role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_state_read_only(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_text_indentation(obj, **args) result += (self._generate_text_line(obj, **args) \ or self._generate_accessible_placeholder_text(obj, **args)) result += self._generate_text_selection(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_timer( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the timer role.""" return self._generate_default_presentation(obj, **args) def _generate_title_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the title-bar role.""" return self._generate_default_presentation(obj, **args) def _generate_toggle_button( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the toggle-button role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_expanded(obj, **args) \ or self._generate_state_pressed(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_accessible_role(obj, **args) result += (self._generate_state_expanded(obj, **args) \ or self._generate_state_pressed(obj, **args)) result += self._generate_state_sensitive(obj, **args) result += self._generate_pause(obj, **args) result += self._generate_keyboard_mnemonic(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_tool_bar( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tool-bar role.""" return self._generate_default_presentation(obj, **args) def _generate_tool_tip( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tool-tip role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_leaving(obj, **args) \ or self._generate_accessible_role(obj, **args) result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_role(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_tree( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tree role.""" return self._generate_default_presentation(obj, **args) def _generate_tree_item( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tree-item role.""" format_type = args.get("formatType", "unfocused") if format_type in ["focused", "ancestor"]: return self._generate_state_expanded(obj, **args) result = self._generate_default_prefix(obj, **args) if format_type.endswith("WhereAmI"): result += self._generate_ancestors(obj, **args) result += self._generate_pause(obj, **args) result += (self._generate_accessible_label_and_name(obj, **args) \ or self._generate_text_content(obj, **args)) result += self._generate_pause(obj, **args) result += self._generate_state_expanded(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_position_in_list(obj, **args) if result and not isinstance(result[-1], Pause): result += self._generate_pause(obj, **args) result += self._generate_tree_item_level(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_tree_table( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the tree-table role.""" return self._generate_default_presentation(obj, **args) def _generate_unknown( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the unknown role.""" result = self._generate_default_prefix(obj, **args) result += self._generate_accessible_label_and_name(obj, **args) result += self._generate_default_suffix(obj, **args) return result def _generate_video( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the video role.""" return self._generate_default_presentation(obj, **args) def _generate_viewport( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the viewport role.""" return self._generate_default_presentation(obj, **args) def _generate_window( self, obj: Atspi.Accessible, **args ) -> list[Any]: """Generates speech for the window role.""" return self._generate_default_presentation(obj, **args) def generate_contents( self, contents: list[tuple[Atspi.Accessible, int, int, str]], **args ) -> list[Any]: """Generates speech for a list of [obj, start, end, string] contents.""" result = [] for content in contents: obj, _start, _end, text = content if not text: continue voices = self.voice(obj=obj, string=text) voice = voices[0] if voices and isinstance(voices, list) else voices result.append([text, voice]) if not result or (len(result) == 1 and result[0][0] == "\n"): if focus_manager.get_manager().in_say_all() \ or not settings_manager.get_manager().get_setting("speakBlankLines") \ or args.get("formatType") == "ancestor": string = "" else: string = messages.BLANK result = [[string, self.voice(DEFAULT, **args)]] return result