from typing import TypeVar, Any from typing import Dict, List import platform import subprocess import ctypes import os import pyatspi from pyatspi import Accessible, StateType from pyatspi import Component, Document from pyatspi import Text as ATText from pyatspi import Value as ATValue from pyatspi import Action as ATAction import lxml.etree from lxml.etree import _Element import logging logger = logging.getLogger("desktopenv.getters.misc") R = TypeVar("Rule") def get_rule(env, config: R) -> R: """ Returns the rule as-is. """ return config["rules"] def get_desktop_path(*args): username = os.getlogin() # Get the current username if platform.system() == "Windows": return os.path.join("C:", "Users", username, "Desktop") elif platform.system() == "Darwin": # macOS is identified as 'Darwin' return os.path.join("/Users", username, "Desktop") elif platform.system() == "Linux": return os.path.join("/home", username, "Desktop") else: raise Exception("Unsupported operating system") def get_wallpaper(*args): def get_wallpaper_windows(): SPI_GETDESKWALLPAPER = 0x73 MAX_PATH = 260 buffer = ctypes.create_unicode_buffer(MAX_PATH) ctypes.windll.user32.SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, buffer, 0) return buffer.value def get_wallpaper_macos(): script = """ tell application "System Events" to tell every desktop to get picture """ process = subprocess.Popen(['osascript', '-e', script], stdout=subprocess.PIPE) output, error = process.communicate() if error: logger.error("Error: %s", error) else: return output.strip().decode('utf-8') def get_wallpaper_linux(): try: output = subprocess.check_output(["gsettings", "get", "org.gnome.desktop.background", "picture-uri"]) return output.decode('utf-8').strip().replace('file://', '').replace("'", "") except Exception as e: logger.error("Error: %s", e) return None os_name = platform.system() if os_name == 'Windows': return get_wallpaper_windows() elif os_name == 'Darwin': return get_wallpaper_macos() elif os_name == 'Linux': return get_wallpaper_linux() else: return "Unsupported OS" _accessibility_ns_map = { "st": "uri:deskat:state.at-spi.gnome.org" , "attr": "uri:deskat:attributes.at-spi.gnome.org" , "cp": "uri:deskat:component.at-spi.gnome.org" , "doc": "uri:deskat:document.at-spi.gnome.org" , "docattr": "uri:deskat:attributes.document.at-spi.gnome.org" , "txt": "uri:deskat:text.at-spi.gnome.org" , "val": "uri:deskat:value.at-spi.gnome.org" , "act": "uri:deskat:action.at-spi.gnome.org" } def _create_node(node: Accessible) -> _Element: attribute_dict: Dict[str, Any] = {"name": node.name} # States {{{ # states: List[StateType] = node.getState().get_states() for st in states: state_name: str = StateType._enum_lookup[st] attribute_dict[ "{{{:}}}{:}"\ .format( _accessibility_ns_map["st"] , state_name.split("_", maxsplit=1)[1].lower() ) ] = "true" # }}} States # # Attributes {{{ # attributes: List[str] = node.getAttributes() for attrbt in attributes: attribute_name: str attribute_value: str attribute_name, attribute_value = attrbt.split(":", maxsplit=1) attribute_dict[ "{{{:}}}{:}"\ .format( _accessibility_ns_map["attr"] , attribute_name ) ] = attribute_value # }}} Attributes # # Component {{{ # try: component: Component = node.queryComponent() except NotImplementedError: pass else: attribute_dict["{{{:}}}screencoord".format(_accessibility_ns_map["cp"])] = str(component.getPosition(pyatspi.XY_SCREEN)) attribute_dict["{{{:}}}windowcoord".format(_accessibility_ns_map["cp"])] = str(component.getPosition(pyatspi.XY_WINDOW)) attribute_dict["{{{:}}}parentcoord".format(_accessibility_ns_map["cp"])] = str(component.getPosition(pyatspi.XY_PARENT)) attribute_dict["{{{:}}}size".format(_accessibility_ns_map["cp"])] = str(component.getSize()) # }}} Component # # Document {{{ # try: document: Document = node.queryDocument() except NotImplementedError: pass else: attribute_dict["{{{:}}}locale".format(_accessibility_ns_map["doc"])] = document.getLocale() attribute_dict["{{{:}}}pagecount".format(_accessibility_ns_map["doc"])] = str(document.getPageCount()) attribute_dict["{{{:}}}currentpage".format(_accessibility_ns_map["doc"])] = str(document.getCurrentPageNumber()) for attrbt in document.getAttributes(): attribute_name: str attribute_value: str attribute_name, attribute_value = attrbt.split(":", maxsplit=1) attribute_dict[ "{{{:}}}{:}"\ .format( _accessibility_ns_map["docattr"] , attribute_name ) ] = attribute_value # }}} Document # # Text {{{ # try: text_obj: ATText = node.queryText() except NotImplementedError: pass else: # only text shown on current screen is available #attribute_dict["txt:text"] = text_obj.getText(0, text_obj.characterCount) text: str = text_obj.getText(0, text_obj.characterCount) # }}} Text # # Selection {{{ # try: node.querySelection() except NotImplementedError: pass else: attribute_dict["selection"] = "true" # }}} Selection # # Value {{{ # try: value: ATValue = node.queryValue() except NotImplementedError: pass else: attribute_dict["{{{:}}}value".format(_accessibility_ns_map["val"])] = str(value.currentValue) attribute_dict["{{{:}}}min".format(_accessibility_ns_map["val"])] = str(value.minimumValue) attribute_dict["{{{:}}}max".format(_accessibility_ns_map["val"])] = str(value.maximumValue) attribute_dict["{{{:}}}step".format(_accessibility_ns_map["val"])] = str(value.minimumIncrement) # }}} Value # # Action {{{ # try: action: ATAction = node.queryAction() except NotImplementedError: pass else: for i in range(action.nActions): action_name: str = action.getName(i).replace(" ", "-") attribute_dict[ "{{{:}}}{:}_desc"\ .format( _accessibility_ns_map["act"] , action_name ) ] = action.getDescription(i) attribute_dict[ "{{{:}}}{:}_kb"\ .format( _accessibility_ns_map["act"] , action_name ) ] = action.getKeyBinding(i) # }}} Action # xml_node = lxml.etree.Element( node.getRoleName().replace(" ", "-") , attrib=attribute_dict , nsmap=_accessibility_ns_map ) if "text" in locals() and len(text)>0: xml_node.text = text for ch in node: xml_node.append(_create_node(ch)) return xml_node def get_accessibility_tree(*args) -> _Element: desktop: Accessible = pyatspi.Registry.getDesktop(0) desktop_xml: _Element = _create_node(desktop) return desktop_xml if __name__ == "__main__": import sys with open(sys.argv[1], "w") as f: f.write( lxml.etree.tostring( get_accessibility_tree() , encoding="unicode" , pretty_print=True ) )