__ __ __ __ _____ _ _ _____ _ _ _ | \/ | \ \ / / | __ \ (_) | | / ____| | | | | | \ / |_ __\ V / | |__) | __ ___ ____ _| |_ ___ | (___ | |__ ___| | | | |\/| | '__|> < | ___/ '__| \ \ / / _` | __/ _ \ \___ \| '_ \ / _ \ | | | | | | |_ / . \ | | | | | |\ V / (_| | || __/ ____) | | | | __/ | | |_| |_|_(_)_/ \_\ |_| |_| |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1 if you need WebShell for Seo everyday contact me on Telegram Telegram Address : @jackleetFor_More_Tools:
# Orca # # Copyright 2023 The Orca Team # Author: Rynhardt Kruger <[email protected]> # # 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=wrong-import-position """Provides ability to navigate objects hierarchically.""" # 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) 2023 The Orca Team" __license__ = "LGPL" from typing import Optional, TYPE_CHECKING import gi gi.require_version("Atspi", "2.0") from gi.repository import Atspi from . import cmdnames from . import debug from . import focus_manager from . import input_event from . import keybindings from . import messages from .ax_event_synthesizer import AXEventSynthesizer from .ax_object import AXObject from .ax_utilities import AXUtilities if TYPE_CHECKING: from .scripts import default class ObjectNavigator: """Provides ability to navigate objects hierarchically.""" def __init__(self) -> None: self._navigator_focus: Optional[Atspi.Accessible] = None self._last_navigator_focus: Optional[Atspi.Accessible] = None self._last_locus_of_focus: Optional[Atspi.Accessible] = None self._simplify: bool = True self._handlers: dict = self.get_handlers(True) self._bindings: keybindings.KeyBindings = keybindings.KeyBindings() def get_bindings( self, refresh: bool = False, is_desktop: bool = True ) -> keybindings.KeyBindings: """Returns the object-navigator keybindings.""" if refresh: msg = f"OBJECT NAVIGATOR: Refreshing bindings. Is desktop: {is_desktop}" debug.print_message(debug.LEVEL_INFO, msg, True) self._setup_bindings() elif self._bindings.is_empty(): self._setup_bindings() return self._bindings def get_handlers(self, refresh: bool = False) -> dict[str, input_event.InputEventHandler]: """Returns the object-navigator handlers.""" if refresh: msg = "OBJECT NAVIGATOR: Refreshing handlers." debug.print_message(debug.LEVEL_INFO, msg, True) self._setup_handlers() return self._handlers def _setup_bindings(self) -> None: """Sets up the object-navigator key bindings.""" self._bindings = keybindings.KeyBindings() self._bindings.add( keybindings.KeyBinding( "Up", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_up"])) self._bindings.add( keybindings.KeyBinding( "Down", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_down"])) self._bindings.add( keybindings.KeyBinding( "Right", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_next"])) self._bindings.add( keybindings.KeyBinding( "Left", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_previous"])) self._bindings.add( keybindings.KeyBinding( "Return", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_perform_action"])) self._bindings.add( keybindings.KeyBinding( "s", keybindings.DEFAULT_MODIFIER_MASK, keybindings.ORCA_CTRL_MODIFIER_MASK, self._handlers["object_navigator_toggle_simplify"])) msg = "OBJECT NAVIGATOR: Bindings set up." debug.print_message(debug.LEVEL_INFO, msg, True) def _setup_handlers(self) -> None: """Sets up the object-navigator input event handlers.""" self._handlers = {} self._handlers["object_navigator_up"] = \ input_event.InputEventHandler( self.up, cmdnames.NAVIGATOR_UP) self._handlers["object_navigator_down"] = \ input_event.InputEventHandler( self.down, cmdnames.NAVIGATOR_DOWN) self._handlers["object_navigator_next"] = \ input_event.InputEventHandler( self.next, cmdnames.NAVIGATOR_NEXT) self._handlers["object_navigator_previous"] = \ input_event.InputEventHandler( self.previous, cmdnames.NAVIGATOR_PREVIOUS) self._handlers["object_navigator_perform_action"] = \ input_event.InputEventHandler( self.perform_action, cmdnames.NAVIGATOR_PERFORM_ACTION) self._handlers["object_navigator_toggle_simplify"] = \ input_event.InputEventHandler( self.toggle_simplify, cmdnames.NAVIGATOR_TOGGLE_SIMPLIFIED) msg = "OBJECT NAVIGATOR: Handlers set up." debug.print_message(debug.LEVEL_INFO, msg, True) def _include_in_simple_navigation(self, obj: Atspi.Accessible) -> bool: """Returns True if obj should be included in simple navigation.""" return AXUtilities.is_paragraph(obj) def _exclude_from_simple_navigation( self, _script: default.Script, obj: Atspi.Accessible ) -> bool: """Returns True if obj should be excluded from simple navigation.""" if self._include_in_simple_navigation(obj): tokens = ["OBJECT NAVIGATOR: Not excluding", obj, ": explicit inclusion"] debug.print_tokens(debug.LEVEL_INFO, tokens, True) return False # is_layout_only should catch things that really should be skipped. # # You do not want to exclude all sections because they may be focusable, e.g. # <div tabindex=0>foo</div> should not be excluded, despite the poor authoring. # # You do not want to exclude table cells and headers because it will make the # selectable items in tables non-navigable (e.g. the mail folders in Evolution) if AXUtilities.is_layout_only(obj): tokens = ["OBJECT NAVIGATOR: Excluding", obj, ": is layout only"] debug.print_tokens(debug.LEVEL_INFO, tokens, True) return True tokens = ["OBJECT NAVIGATOR: Not excluding", obj] debug.print_tokens(debug.LEVEL_INFO, tokens, True) return False def _children(self, script: default.Script, obj: Atspi.Accessible) -> list: """Returns a list of children for obj, taking simple navigation into account.""" if not AXObject.get_child_count(obj): return [] children = list(AXObject.iter_children(obj)) if not self._simplify: return children # Add the children of excluded objects to our list of children. functional_children = [] for child in children: if self._exclude_from_simple_navigation(script, child): functional_children.extend(self._children(script, child)) else: functional_children.append(child) return functional_children def _parent(self, script: default.Script, obj: Atspi.Accessible) -> Optional[Atspi.Accessible]: """Returns the parent for obj, taking simple navigation into account.""" parent = AXObject.get_parent(obj) if not self._simplify: return parent # The first non-excluded ancestor is the functional parent. while parent is not None and self._exclude_from_simple_navigation(script, parent): parent = AXObject.get_parent(parent) return parent def _set_navigator_focus(self, obj: Atspi.Accessible) -> None: """Changes the navigator focus, storing the previous focus.""" self._last_navigator_focus = self._navigator_focus self._navigator_focus = obj def update(self) -> None: """Updates the navigator focus to Orca's object of interest.""" mode, region = focus_manager.get_manager().get_active_mode_and_object_of_interest() obj = region or focus_manager.get_manager().get_locus_of_focus() if self._last_locus_of_focus == obj \ or (region is None and mode == focus_manager.FLAT_REVIEW): return self._navigator_focus = obj self._last_locus_of_focus = obj def present(self, script: default.Script) -> None: """Presents the current navigator focus to the user.""" tokens = ["OBJECT NAVIGATOR: Presenting", self._navigator_focus] debug.print_tokens(debug.LEVEL_INFO, tokens, True) focus_manager.get_manager().emit_region_changed( self._navigator_focus, mode=focus_manager.OBJECT_NAVIGATOR) script.presentObject(self._navigator_focus, priorObj=self._last_navigator_focus) def up(self, script: default.Script, _event: Optional[input_event.InputEvent] = None) -> bool: """Moves the navigator focus to the parent of the current focus.""" self.update() parent = self._parent(script, self._navigator_focus) if parent is not None: self._set_navigator_focus(parent) self.present(script) else: script.presentMessage(messages.NAVIGATOR_NO_PARENT) return True def down(self, script: default.Script, _event: Optional[input_event.InputEvent] = None) -> bool: """Moves the navigator focus to the first child of the current focus.""" self.update() children = self._children(script, self._navigator_focus) if not children: script.presentMessage(messages.NAVIGATOR_NO_CHILDREN) return True self._set_navigator_focus(children[0]) self.present(script) return True def next(self, script: default.Script, _event: Optional[input_event.InputEvent] = None) -> bool: """Moves the navigator focus to the next sibling of the current focus.""" self.update() parent = self._parent(script, self._navigator_focus) if parent is None: script.presentMessage(messages.NAVIGATOR_NO_NEXT) return True siblings = self._children(script, parent) if self._navigator_focus in siblings: index = siblings.index(self._navigator_focus) if index < len(siblings) - 1: self._set_navigator_focus(siblings[index+1]) self.present(script) else: script.presentMessage(messages.NAVIGATOR_NO_NEXT) else: self._set_navigator_focus(parent) self.present(script) return True def previous( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Moves the navigator focus to the previous sibling of the current focus.""" self.update() parent = self._parent(script, self._navigator_focus) if parent is None: script.presentMessage(messages.NAVIGATOR_NO_PREVIOUS) return True siblings = self._children(script, parent) if self._navigator_focus in siblings: index = siblings.index(self._navigator_focus) if index > 0: self._set_navigator_focus(siblings[index-1]) self.present(script) else: script.presentMessage(messages.NAVIGATOR_NO_PREVIOUS) else: self._set_navigator_focus(parent) self.present(script) return True def toggle_simplify( self, script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Toggles simplified navigation.""" self._simplify = not self._simplify if self._simplify: script.presentMessage(messages.NAVIGATOR_SIMPLIFIED_ENABLED) else: script.presentMessage(messages.NAVIGATOR_SIMPLIFIED_DISABLED) return True def perform_action( self, _script: default.Script, _event: Optional[input_event.InputEvent] = None ) -> bool: """Attempts to click on the current focus.""" if AXEventSynthesizer.try_all_clickable_actions(self._navigator_focus): return True AXEventSynthesizer.click_object(self._navigator_focus, 1) return True _navigator: ObjectNavigator = ObjectNavigator() def get_navigator() -> ObjectNavigator: """Returns the Object Navigator""" return _navigator
| Name | Type | Size | Permission | Actions |
|---|---|---|---|---|
| __pycache__ | Folder | 0755 |
|
|
| backends | Folder | 0755 |
|
|
| scripts | Folder | 0755 |
|
|
| __init__.py | File | 115 B | 0644 |
|
| acss.py | File | 3.85 KB | 0644 |
|
| action_presenter.py | File | 8.65 KB | 0644 |
|
| ax_collection.py | File | 6.16 KB | 0644 |
|
| ax_component.py | File | 14.93 KB | 0644 |
|
| ax_document.py | File | 9.36 KB | 0644 |
|
| ax_event_synthesizer.py | File | 17.39 KB | 0644 |
|
| ax_hypertext.py | File | 8.36 KB | 0644 |
|
| ax_object.py | File | 47.84 KB | 0644 |
|
| ax_selection.py | File | 4.54 KB | 0644 |
|
| ax_table.py | File | 47.98 KB | 0644 |
|
| ax_text.py | File | 45.13 KB | 0644 |
|
| ax_utilities.py | File | 28.24 KB | 0644 |
|
| ax_utilities_application.py | File | 7.17 KB | 0644 |
|
| ax_utilities_collection.py | File | 86.79 KB | 0644 |
|
| ax_utilities_debugging.py | File | 10.12 KB | 0644 |
|
| ax_utilities_event.py | File | 32.78 KB | 0644 |
|
| ax_utilities_relation.py | File | 15.2 KB | 0644 |
|
| ax_utilities_role.py | File | 91.79 KB | 0644 |
|
| ax_utilities_state.py | File | 11.63 KB | 0644 |
|
| ax_value.py | File | 6.83 KB | 0644 |
|
| bookmarks.py | File | 11.95 KB | 0644 |
|
| braille.py | File | 74.03 KB | 0644 |
|
| braille_generator.py | File | 55.79 KB | 0644 |
|
| braille_rolenames.py | File | 10.23 KB | 0644 |
|
| brlmon.py | File | 6.53 KB | 0644 |
|
| brltablenames.py | File | 7.3 KB | 0644 |
|
| bypass_mode_manager.py | File | 4.79 KB | 0644 |
|
| caret_navigation.py | File | 19.51 KB | 0644 |
|
| chat.py | File | 32.03 KB | 0644 |
|
| clipboard.py | File | 20.45 KB | 0644 |
|
| cmdnames.py | File | 61.77 KB | 0644 |
|
| colornames.py | File | 39.22 KB | 0644 |
|
| debug.py | File | 3.95 KB | 0644 |
|
| debugging_tools_manager.py | File | 10.69 KB | 0644 |
|
| event_manager.py | File | 36.07 KB | 0644 |
|
| flat_review.py | File | 48.89 KB | 0644 |
|
| flat_review_finder.py | File | 20.2 KB | 0644 |
|
| flat_review_presenter.py | File | 45.94 KB | 0644 |
|
| focus_manager.py | File | 11.52 KB | 0644 |
|
| generator.py | File | 67.07 KB | 0644 |
|
| guilabels.py | File | 56.38 KB | 0644 |
|
| highlighter.py | File | 6.95 KB | 0644 |
|
| input_event.py | File | 30.05 KB | 0644 |
|
| input_event_manager.py | File | 35.66 KB | 0644 |
|
| keybindings.py | File | 24.87 KB | 0644 |
|
| keynames.py | File | 9.55 KB | 0644 |
|
| label_inference.py | File | 19.77 KB | 0644 |
|
| learn_mode_presenter.py | File | 14.72 KB | 0644 |
|
| liveregions.py | File | 25.77 KB | 0644 |
|
| mathsymbols.py | File | 88.65 KB | 0644 |
|
| messages.py | File | 152.28 KB | 0644 |
|
| mouse_review.py | File | 23.34 KB | 0644 |
|
| notification_presenter.py | File | 14.17 KB | 0644 |
|
| object_navigator.py | File | 13.24 KB | 0644 |
|
| object_properties.py | File | 33.86 KB | 0644 |
|
| orca.py | File | 9.83 KB | 0644 |
|
| orca_gtkbuilder.py | File | 5.42 KB | 0644 |
|
| orca_gui_navlist.py | File | 6.51 KB | 0644 |
|
| orca_gui_prefs.py | File | 141.9 KB | 0644 |
|
| orca_gui_profile.py | File | 3.98 KB | 0644 |
|
| orca_i18n.py | File | 3.13 KB | 0644 |
|
| orca_modifier_manager.py | File | 13.76 KB | 0644 |
|
| orca_platform.py | File | 1.43 KB | 0644 |
|
| phonnames.py | File | 2.76 KB | 0644 |
|
| pronunciation_dict.py | File | 2.55 KB | 0644 |
|
| script.py | File | 11.11 KB | 0644 |
|
| script_manager.py | File | 14.68 KB | 0644 |
|
| script_utilities.py | File | 64.21 KB | 0644 |
|
| settings.py | File | 10.66 KB | 0644 |
|
| settings_manager.py | File | 27.13 KB | 0644 |
|
| sleep_mode_manager.py | File | 5.04 KB | 0644 |
|
| sound.py | File | 5.51 KB | 0644 |
|
| sound_generator.py | File | 48.88 KB | 0644 |
|
| speech.py | File | 8.87 KB | 0644 |
|
| speech_and_verbosity_manager.py | File | 27.71 KB | 0644 |
|
| speech_generator.py | File | 163.53 KB | 0644 |
|
| speechdispatcherfactory.py | File | 24.68 KB | 0644 |
|
| speechserver.py | File | 8 KB | 0644 |
|
| spellcheck.py | File | 18.11 KB | 0644 |
|
| spiel.py | File | 25.59 KB | 0644 |
|
| ssml.py | File | 6.71 KB | 0644 |
|
| structural_navigation.py | File | 77.63 KB | 0644 |
|
| system_information_presenter.py | File | 7.44 KB | 0644 |
|
| table_navigator.py | File | 29.78 KB | 0644 |
|
| text_attribute_names.py | File | 27.31 KB | 0644 |
|
| where_am_i_presenter.py | File | 21.59 KB | 0644 |
|