diff --git a/core-aam/acacia/all_apis_example.html b/core-aam/acacia/all_apis_example.html index 38e2e3cca5b031..5dc231526f14c8 100644 --- a/core-aam/acacia/all_apis_example.html +++ b/core-aam/acacia/all_apis_example.html @@ -20,6 +20,9 @@ else if (node.API == 'axapi') { assert_equals(node.role, 'AXButton', 'AX API role'); } + else if (node.API == 'windows') { + assert_equals(node.msaa_role, 'ROLE_SYSTEM_PUSHBUTTON', 'MSAA Role'); + } else { assert_unreached(`Unknown API: ${node.API}`) } diff --git a/resources/testdriver.js b/resources/testdriver.js index ec892af499a9b5..ac3ed65bd039f3 100644 --- a/resources/testdriver.js +++ b/resources/testdriver.js @@ -1076,7 +1076,7 @@ * rejected in the cases of failures. */ get_accessibility_api_node: async function(dom_id) { - return window.test_driver_internal.get_accessibility_api_node(dom_id) + return window.test_driver_internal.get_accessibility_api_node(dom_id, location.href) .then((jsonresult) => { return JSON.parse(jsonresult); }); @@ -1270,7 +1270,7 @@ throw new Error("clear_device_posture() is not implemented by testdriver-vendor.js"); }, - async get_accessibility_api_node(dom_id) { + async get_accessibility_api_node(dom_id, url) { throw new Error("get_accessibility_api_node() is not available."); } }; diff --git a/tools/wptrunner/wptrunner/executors/actions.py b/tools/wptrunner/wptrunner/executors/actions.py index 90ae943ac25829..41c56585c70ce7 100644 --- a/tools/wptrunner/wptrunner/executors/actions.py +++ b/tools/wptrunner/wptrunner/executors/actions.py @@ -473,7 +473,8 @@ def __init__(self, logger, protocol): def __call__(self, payload): dom_id = payload["dom_id"] - return self.protocol.platform_accessibility.get_accessibility_api_node(dom_id) + url = payload["url"] + return self.protocol.platform_accessibility.get_accessibility_api_node(dom_id, url) actions = [ClickAction, diff --git a/tools/wptrunner/wptrunner/executors/executoratspi.py b/tools/wptrunner/wptrunner/executors/executoratspi.py index d92af192aedf58..feb2fb114fe951 100644 --- a/tools/wptrunner/wptrunner/executors/executoratspi.py +++ b/tools/wptrunner/wptrunner/executors/executoratspi.py @@ -109,7 +109,8 @@ def setup(self, product_name, logger): f"Couldn't find browser {self.product_name} in accessibility API ATSPI. Accessibility API queries will not succeeded." ) - def get_accessibility_api_node(self, dom_id): + + def get_accessibility_api_node(self, dom_id, url): if not self.root: raise Exception( f"Couldn't find browser {self.product_name} in accessibility API ATSPI. Did you turn on accessibility?" diff --git a/tools/wptrunner/wptrunner/executors/executoraxapi.py b/tools/wptrunner/wptrunner/executors/executoraxapi.py index f864cbfebb1754..54c4fea472b390 100644 --- a/tools/wptrunner/wptrunner/executors/executoraxapi.py +++ b/tools/wptrunner/wptrunner/executors/executoraxapi.py @@ -91,7 +91,7 @@ def setup(self, product_name): raise Exception(f"Couldn't find application: {product_name}") - def get_accessibility_api_node(self, dom_id): + def get_accessibility_api_node(self, dom_id, url): tab = find_active_tab(self.root) node = find_node(tab, "AXDOMIdentifier", dom_id) if not node: diff --git a/tools/wptrunner/wptrunner/executors/executorplatformaccessibility.py b/tools/wptrunner/wptrunner/executors/executorplatformaccessibility.py index b707352e7ab26d..f7868dc4c16a92 100644 --- a/tools/wptrunner/wptrunner/executors/executorplatformaccessibility.py +++ b/tools/wptrunner/wptrunner/executors/executorplatformaccessibility.py @@ -5,18 +5,19 @@ linux = False mac = False +windows = False if platform == "linux": linux = True from .executoratspi import * if platform == "darwin": mac = True from .executoraxapi import * - +if platform == "win32": + windows = True + from .executorwindowsaccessibility import WindowsAccessibilityExecutorImpl class PlatformAccessibilityProtocolPart(ProtocolPart): """Protocol part for platform accessibility introspection""" - __metaclass__ = ABCMeta - name = "platform_accessibility" def setup(self): @@ -28,6 +29,9 @@ def setup(self): if mac: self.impl = AXAPIExecutorImpl() self.impl.setup(self.product_name) + if windows: + self.impl = WindowsAccessibilityExecutorImpl() + self.impl.setup(self.product_name) - def get_accessibility_api_node(self, dom_id): - return self.impl.get_accessibility_api_node(dom_id) + def get_accessibility_api_node(self, dom_id, url): + return self.impl.get_accessibility_api_node(dom_id, url) diff --git a/tools/wptrunner/wptrunner/executors/executorwindowsaccessibility.py b/tools/wptrunner/wptrunner/executors/executorwindowsaccessibility.py new file mode 100644 index 00000000000000..bca19b40d82636 --- /dev/null +++ b/tools/wptrunner/wptrunner/executors/executorwindowsaccessibility.py @@ -0,0 +1,127 @@ +from ..executors.ia2.constants import * + +import json +import sys +import time + +import ctypes +from ctypes import POINTER, byref +from ctypes.wintypes import BOOL, HWND, LPARAM, POINT + +import comtypes.client +from comtypes import COMError, IServiceProvider + +CHILDID_SELF = 0 +OBJID_CLIENT = -4 + +user32 = ctypes.windll.user32 +oleacc = ctypes.oledll.oleacc +oleaccMod = comtypes.client.GetModule("oleacc.dll") +IAccessible = oleaccMod.IAccessible + +# CoCreateInstance of UIA also initializes IA2 +uiaMod = comtypes.client.GetModule("UIAutomationCore.dll") +uiaClient = comtypes.CoCreateInstance( + uiaMod.CUIAutomation._reg_clsid_, + interface=uiaMod.IUIAutomation, + clsctx=comtypes.CLSCTX_INPROC_SERVER, +) + +def accessible_object_from_window(hwnd): + p = POINTER(IAccessible)() + oleacc.AccessibleObjectFromWindow( + hwnd, OBJID_CLIENT, byref(IAccessible._iid_), byref(p) + ) + return p + +def name_from_hwnd(hwnd): + MAX_CHARS = 257 + buffer = ctypes.create_unicode_buffer(MAX_CHARS) + user32.GetWindowTextW(hwnd, buffer, MAX_CHARS) + return buffer.value + +def get_browser_hwnd(product_name): + found = [] + + @ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM) + def check_window_name(hwnd, lParam): + window_name = name_from_hwnd(hwnd) + if product_name not in window_name.lower(): + # EnumWindows should continue enumerating + return True + found.append(hwnd) + # EnumWindows should stop enumerating (since we found the right window) + return False + + user32.EnumWindows(check_window_name, LPARAM(0)) + if not found: + raise LookupError(f"Couldn't find {product_name} HWND") + return found[0] + +def to_ia2(node): + service = node.QueryInterface(IServiceProvider) + return service.QueryService(IAccessible2._iid_, IAccessible2) + +def find_browser(product_name): + hwnd = get_browser_hwnd(product_name) + root = accessible_object_from_window(hwnd) + return to_ia2(root) + +def poll_for_tab(url, root): + tab = find_tab(url, root) + while not tab: + time.sleep(0.01) + tab = find_tab(url, root) + return tab + +def find_tab(url, root): + for i in range(1, root.accChildCount + 1): + child = to_ia2(root.accChild(i)) + if child.accRole(CHILDID_SELF) == ROLE_SYSTEM_DOCUMENT: + if child.accValue(CHILDID_SELF) == url: + return child + # No need to search within documents. + return + descendant = find_tab(url, child) + if descendant: + return descendant + +def find_ia2_node(root, id): + id_attribute = f"id:{id};" + for i in range(1, root.accChildCount + 1): + child = to_ia2(root.accChild(i)) + if child.attributes and id_attribute in child.attributes: + return child + descendant = find_ia2_node(child, id) + if descendant: + return descendant + +def serialize_node(node): + node_dictionary = {} + node_dictionary["API"] = "windows" + + # MSAA properties + node_dictionary["name"] = node.accName(CHILDID_SELF) + node_dictionary["msaa_role"] = role_to_string[node.accRole(CHILDID_SELF)] + node_dictionary["msaa_states"] = get_msaa_state_list(node.accState(CHILDID_SELF)) + + # IAccessible2 properties + node_dictionary["ia2_role"] = role_to_string[node.role()] + node_dictionary["ia2_states"] = get_state_list(node.states) + + return node_dictionary + +class WindowsAccessibilityExecutorImpl: + def setup(self, product_name): + self.product_name = product_name + + def get_accessibility_api_node(self, dom_id, url): + self.root = find_browser(self.product_name) + if not self.root: + raise Exception(f"Couldn't find browser {self.product_name}.") + + tab = poll_for_tab(url, self.root) + node = find_ia2_node(tab, dom_id) + if not node: + raise Exception(f"Couldn't find node with ID {dom_id}.") + return json.dumps(serialize_node(node)) diff --git a/tools/wptrunner/wptrunner/executors/ia2/constants.py b/tools/wptrunner/wptrunner/executors/ia2/constants.py new file mode 100644 index 00000000000000..73b7ff2d3a7642 --- /dev/null +++ b/tools/wptrunner/wptrunner/executors/ia2/constants.py @@ -0,0 +1,344 @@ +import os +import comtypes.client + +# Get IAccessible2 constants for helper functions below +ia2Tlb = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "ia2_api_all.tlb", +) +ia2Mod = comtypes.client.GetModule(ia2Tlb) +# Add to globals the many IAccessible2 constants. These will also be imported +# when this file is imported. +globals().update((k, getattr(ia2Mod, k)) for k in ia2Mod.__all__) + +# Some constants are not provided via oleacc, specifically those for MSAA +ROLE_SYSTEM_TITLEBAR=1 +ROLE_SYSTEM_MENUBAR=2 +ROLE_SYSTEM_SCROLLBAR=3 +ROLE_SYSTEM_GRIP=4 +ROLE_SYSTEM_SOUND=5 +ROLE_SYSTEM_CURSOR=6 +ROLE_SYSTEM_CARET=7 +ROLE_SYSTEM_ALERT=8 +ROLE_SYSTEM_WINDOW=9 +ROLE_SYSTEM_CLIENT=10 +ROLE_SYSTEM_MENUPOPUP=11 +ROLE_SYSTEM_MENUITEM=12 +ROLE_SYSTEM_TOOLTIP=13 +ROLE_SYSTEM_APPLICATION=14 +ROLE_SYSTEM_DOCUMENT=15 +ROLE_SYSTEM_PANE=16 +ROLE_SYSTEM_CHART=17 +ROLE_SYSTEM_DIALOG=18 +ROLE_SYSTEM_BORDER=19 +ROLE_SYSTEM_GROUPING=20 +ROLE_SYSTEM_SEPARATOR=21 +ROLE_SYSTEM_TOOLBAR=22 +ROLE_SYSTEM_STATUSBAR=23 +ROLE_SYSTEM_TABLE=24 +ROLE_SYSTEM_COLUMNHEADER=25 +ROLE_SYSTEM_ROWHEADER=26 +ROLE_SYSTEM_COLUMN=27 +ROLE_SYSTEM_ROW=28 +ROLE_SYSTEM_CELL=29 +ROLE_SYSTEM_LINK=30 +ROLE_SYSTEM_HELPBALLOON=31 +ROLE_SYSTEM_CHARACTER=32 +ROLE_SYSTEM_LIST=33 +ROLE_SYSTEM_LISTITEM=34 +ROLE_SYSTEM_OUTLINE=35 +ROLE_SYSTEM_OUTLINEITEM=36 +ROLE_SYSTEM_PAGETAB=37 +ROLE_SYSTEM_PROPERTYPAGE=38 +ROLE_SYSTEM_INDICATOR=39 +ROLE_SYSTEM_GRAPHIC=40 +ROLE_SYSTEM_STATICTEXT=41 +ROLE_SYSTEM_TEXT=42 +ROLE_SYSTEM_PUSHBUTTON=43 +ROLE_SYSTEM_CHECKBUTTON=44 +ROLE_SYSTEM_RADIOBUTTON=45 +ROLE_SYSTEM_COMBOBOX=46 +ROLE_SYSTEM_DROPLIST=47 +ROLE_SYSTEM_PROGRESSBAR=48 +ROLE_SYSTEM_DIAL=49 +ROLE_SYSTEM_HOTKEYFIELD=50 +ROLE_SYSTEM_SLIDER=51 +ROLE_SYSTEM_SPINBUTTON=52 +ROLE_SYSTEM_DIAGRAM=53 +ROLE_SYSTEM_ANIMATION=54 +ROLE_SYSTEM_EQUATION=55 +ROLE_SYSTEM_BUTTONDROPDOWN=56 +ROLE_SYSTEM_BUTTONMENU=57 +ROLE_SYSTEM_BUTTONDROPDOWNGRID=58 +ROLE_SYSTEM_WHITESPACE=59 +ROLE_SYSTEM_PAGETABLIST=60 +ROLE_SYSTEM_CLOCK=61 +ROLE_SYSTEM_SPLITBUTTON=62 +ROLE_SYSTEM_IPADDRESS=63 +ROLE_SYSTEM_OUTLINEBUTTON=64 + +role_to_string = { + ROLE_SYSTEM_TITLEBAR: "ROLE_SYSTEM_TITLEBAR", + ROLE_SYSTEM_MENUBAR: "ROLE_SYSTEM_MENUBAR", + ROLE_SYSTEM_SCROLLBAR: "ROLE_SYSTEM_SCROLLBAR", + ROLE_SYSTEM_GRIP: "ROLE_SYSTEM_GRIP", + ROLE_SYSTEM_SOUND: "ROLE_SYSTEM_SOUND", + ROLE_SYSTEM_CURSOR: "ROLE_SYSTEM_CURSOR", + ROLE_SYSTEM_CARET: "ROLE_SYSTEM_CARET", + ROLE_SYSTEM_ALERT: "ROLE_SYSTEM_ALERT", + ROLE_SYSTEM_WINDOW: "ROLE_SYSTEM_WINDOW", + ROLE_SYSTEM_CLIENT: "ROLE_SYSTEM_CLIENT", + ROLE_SYSTEM_MENUPOPUP: "ROLE_SYSTEM_MENUPOPUP", + ROLE_SYSTEM_MENUITEM: "ROLE_SYSTEM_MENUITEM", + ROLE_SYSTEM_TOOLTIP: "ROLE_SYSTEM_TOOLTIP", + ROLE_SYSTEM_APPLICATION: "ROLE_SYSTEM_APPLICATION", + ROLE_SYSTEM_DOCUMENT: "ROLE_SYSTEM_DOCUMENT", + ROLE_SYSTEM_PANE: "ROLE_SYSTEM_PANE", + ROLE_SYSTEM_CHART: "ROLE_SYSTEM_CHART", + ROLE_SYSTEM_DIALOG: "ROLE_SYSTEM_DIALOG", + ROLE_SYSTEM_BORDER: "ROLE_SYSTEM_BORDER", + ROLE_SYSTEM_GROUPING: "ROLE_SYSTEM_GROUPING", + ROLE_SYSTEM_SEPARATOR: "ROLE_SYSTEM_SEPARATOR", + ROLE_SYSTEM_TOOLBAR: "ROLE_SYSTEM_TOOLBAR", + ROLE_SYSTEM_STATUSBAR: "ROLE_SYSTEM_STATUSBAR", + ROLE_SYSTEM_TABLE: "ROLE_SYSTEM_TABLE", + ROLE_SYSTEM_COLUMNHEADER: "ROLE_SYSTEM_COLUMNHEADER", + ROLE_SYSTEM_ROWHEADER: "ROLE_SYSTEM_ROWHEADER", + ROLE_SYSTEM_COLUMN: "ROLE_SYSTEM_COLUMN", + ROLE_SYSTEM_ROW: "ROLE_SYSTEM_ROW", + ROLE_SYSTEM_CELL: "ROLE_SYSTEM_CEL", + ROLE_SYSTEM_LINK: "ROLE_SYSTEM_LINK", + ROLE_SYSTEM_HELPBALLOON: "ROLE_SYSTEM_HELPBALLOON", + ROLE_SYSTEM_CHARACTER: "ROLE_SYSTEM_CHARACTER", + ROLE_SYSTEM_LIST: "ROLE_SYSTEM_LIST", + ROLE_SYSTEM_LISTITEM: "ROLE_SYSTEM_LISTITEM", + ROLE_SYSTEM_OUTLINE: "ROLE_SYSTEM_OUTLINE", + ROLE_SYSTEM_OUTLINEITEM: "ROLE_SYSTEM_OUTLINEITEM", + ROLE_SYSTEM_PAGETAB: "ROLE_SYSTEM_PAGETAB", + ROLE_SYSTEM_PROPERTYPAGE: "ROLE_SYSTEM_PROPERTYPAGE", + ROLE_SYSTEM_INDICATOR: "ROLE_SYSTEM_INDICATOR", + ROLE_SYSTEM_GRAPHIC: "ROLE_SYSTEM_GRAPHIC", + ROLE_SYSTEM_STATICTEXT: "ROLE_SYSTEM_STATICTEXT", + ROLE_SYSTEM_TEXT: "ROLE_SYSTEM_TEXT", + ROLE_SYSTEM_PUSHBUTTON: "ROLE_SYSTEM_PUSHBUTTON", + ROLE_SYSTEM_CHECKBUTTON: "ROLE_SYSTEM_CHECKBUTTON", + ROLE_SYSTEM_RADIOBUTTON: "ROLE_SYSTEM_RADIOBUTTON", + ROLE_SYSTEM_COMBOBOX: "ROLE_SYSTEM_COMBOBOX", + ROLE_SYSTEM_DROPLIST: "ROLE_SYSTEM_DROPLIST", + ROLE_SYSTEM_PROGRESSBAR: "ROLE_SYSTEM_PROGRESSBAR", + ROLE_SYSTEM_DIAL: "ROLE_SYSTEM_DIAL", + ROLE_SYSTEM_HOTKEYFIELD: "ROLE_SYSTEM_HOTKEYFIELD", + ROLE_SYSTEM_SLIDER: "ROLE_SYSTEM_SLIDER", + ROLE_SYSTEM_SPINBUTTON: "ROLE_SYSTEM_SPINBUTTON", + ROLE_SYSTEM_DIAGRAM: "ROLE_SYSTEM_DIAGRAM", + ROLE_SYSTEM_ANIMATION: "ROLE_SYSTEM_ANIMATION", + ROLE_SYSTEM_EQUATION: "ROLE_SYSTEM_EQUATION", + ROLE_SYSTEM_BUTTONDROPDOWN: "ROLE_SYSTEM_BUTTONDROPDOWN", + ROLE_SYSTEM_BUTTONMENU: "ROLE_SYSTEM_BUTTONMENU", + ROLE_SYSTEM_BUTTONDROPDOWNGRID: "ROLE_SYSTEM_BUTTONDROPDOWNGRID", + ROLE_SYSTEM_WHITESPACE: "ROLE_SYSTEM_WHITESPACE", + ROLE_SYSTEM_PAGETABLIST: "ROLE_SYSTEM_PAGETABLIST", + ROLE_SYSTEM_CLOCK: "ROLE_SYSTEM_CLOCK", + ROLE_SYSTEM_SPLITBUTTON: "ROLE_SYSTEM_SPLITBUTTON", + ROLE_SYSTEM_IPADDRESS: "ROLE_SYSTEM_IPADDRESS", + ROLE_SYSTEM_OUTLINEBUTTON: "ROLE_SYSTEM_OUTLINEBUTTON", + IA2_ROLE_CANVAS: "IA2_ROLE_CANVAS", + IA2_ROLE_CAPTION: "IA2_ROLE_CAPTION", + IA2_ROLE_CHECK_MENU_ITEM: "IA2_ROLE_CHECK_MENU_ITEM", + IA2_ROLE_COLOR_CHOOSER: "IA2_ROLE_COLOR_CHOOSER", + IA2_ROLE_DATE_EDITOR: "IA2_ROLE_DATE_EDITOR", + IA2_ROLE_DESKTOP_ICON: "IA2_ROLE_DESKTOP_ICON", + IA2_ROLE_DESKTOP_PANE: "IA2_ROLE_DESKTOP_PANE", + IA2_ROLE_DIRECTORY_PANE: "IA2_ROLE_DIRECTORY_PANE", + IA2_ROLE_EDITBAR: "IA2_ROLE_EDITBAR", + IA2_ROLE_EMBEDDED_OBJECT: "IA2_ROLE_EMBEDDED_OBJECT", + IA2_ROLE_ENDNOTE: "IA2_ROLE_ENDNOTE", + IA2_ROLE_FILE_CHOOSER: "IA2_ROLE_FILE_CHOOSER", + IA2_ROLE_FONT_CHOOSER: "IA2_ROLE_FONT_CHOOSER", + IA2_ROLE_FOOTER: "IA2_ROLE_FOOTER", + IA2_ROLE_FOOTNOTE: "IA2_ROLE_FOOTNOTE", + IA2_ROLE_FORM: "IA2_ROLE_FORM", + IA2_ROLE_FRAME: "IA2_ROLE_FRAME", + IA2_ROLE_GLASS_PANE: "IA2_ROLE_GLASS_PANE", + IA2_ROLE_HEADER: "IA2_ROLE_HEADER", + IA2_ROLE_HEADING: "IA2_ROLE_HEADING", + IA2_ROLE_ICON: "IA2_ROLE_ICON", + IA2_ROLE_IMAGE_MAP: "IA2_ROLE_IMAGE_MAP", + IA2_ROLE_INPUT_METHOD_WINDOW: "IA2_ROLE_INPUT_METHOD_WINDOW", + IA2_ROLE_INTERNAL_FRAME: "IA2_ROLE_INTERNAL_FRAME", + IA2_ROLE_LABEL: "IA2_ROLE_LABEL", + IA2_ROLE_LAYERED_PANE: "IA2_ROLE_LAYERED_PANE", + IA2_ROLE_NOTE: "IA2_ROLE_NOTE", + IA2_ROLE_OPTION_PANE: "IA2_ROLE_OPTION_PANE", + IA2_ROLE_PAGE: "IA2_ROLE_PAGE", + IA2_ROLE_PARAGRAPH: "IA2_ROLE_PARAGRAPH", + IA2_ROLE_RADIO_MENU_ITEM: "IA2_ROLE_RADIO_MENU_ITEM", + IA2_ROLE_REDUNDANT_OBJECT: "IA2_ROLE_REDUNDANT_OBJECT", + IA2_ROLE_ROOT_PANE: "IA2_ROLE_ROOT_PANE", + IA2_ROLE_RULER: "IA2_ROLE_RULER", + IA2_ROLE_SCROLL_PANE: "IA2_ROLE_SCROLL_PANE", + IA2_ROLE_SECTION: "IA2_ROLE_SECTION", + IA2_ROLE_SHAPE: "IA2_ROLE_SHAPE", + IA2_ROLE_SPLIT_PANE: "IA2_ROLE_SPLIT_PANE", + IA2_ROLE_TEAR_OFF_MENU: "IA2_ROLE_TEAR_OFF_MENU", + IA2_ROLE_TERMINAL: "IA2_ROLE_TERMINAL", + IA2_ROLE_TEXT_FRAME: "IA2_ROLE_TEXT_FRAME", + IA2_ROLE_TOGGLE_BUTTON: "IA2_ROLE_TOGGLE_BUTTON", + IA2_ROLE_UNKNOWN: "IA2_ROLE_UNKNOWN", + IA2_ROLE_VIEW_PORT: "IA2_ROLE_VIEW_PORT", + IA2_ROLE_COMPLEMENTARY_CONTENT: "IA2_ROLE_COMPLEMENTARY_CONTENT", + IA2_ROLE_LANDMARK: "IA2_ROLE_LANDMARK", + IA2_ROLE_LEVEL_BAR: "IA2_ROLE_LEVEL_BAR", + IA2_ROLE_CONTENT_DELETION: "IA2_ROLE_CONTENT_DELETION", + IA2_ROLE_CONTENT_INSERTION: "IA2_ROLE_CONTENT_INSERTION", + IA2_ROLE_BLOCK_QUOTE: "IA2_ROLE_BLOCK_QUOTE", + IA2_ROLE_MARK: "IA2_ROLE_MARK", + IA2_ROLE_SUGGESTION: "IA2_ROLE_SUGGESTION", + IA2_ROLE_COMMENT: "IA2_ROLE_COMMENT" +} + +STATE_SYSTEM_UNAVAILABLE = 0x00000001 +STATE_SYSTEM_SELECTED = 0x00000002 +STATE_SYSTEM_FOCUSED = 0x00000004 +STATE_SYSTEM_PRESSED = 0x00000008 +STATE_SYSTEM_CHECKED = 0x00000010 +STATE_SYSTEM_MIXED = 0x00000020 +STATE_SYSTEM_INDETERMINATE = STATE_SYSTEM_MIXED +STATE_SYSTEM_READONLY = 0x00000040 +STATE_SYSTEM_HOTTRACKED = 0x00000080 +STATE_SYSTEM_DEFAULT = 0x00000100 +STATE_SYSTEM_EXPANDED = 0x00000200 +STATE_SYSTEM_COLLAPSED = 0x00000400 +STATE_SYSTEM_BUSY = 0x00000800 +STATE_SYSTEM_FLOATING = 0x00001000 +STATE_SYSTEM_MARQUEED = 0x00002000 +STATE_SYSTEM_ANIMATED = 0x00004000 +STATE_SYSTEM_INVISIBLE = 0x00008000 +STATE_SYSTEM_OFFSCREEN = 0x00010000 +STATE_SYSTEM_SIZEABLE = 0x00020000 +STATE_SYSTEM_MOVEABLE = 0x00040000 +STATE_SYSTEM_SELFVOICING = 0x00080000 +STATE_SYSTEM_FOCUSABLE = 0x00100000 +STATE_SYSTEM_SELECTABLE = 0x00200000 +STATE_SYSTEM_LINKED = 0x00400000 +STATE_SYSTEM_TRAVERSED = 0x00800000 +STATE_SYSTEM_MULTISELECTABLE = 0x01000000 +STATE_SYSTEM_EXTSELECTABLE = 0x02000000 +STATE_SYSTEM_ALERT_LOW = 0x04000000 +STATE_SYSTEM_ALERT_MEDIUM = 0x08000000 +STATE_SYSTEM_ALERT_HIGH = 0x10000000 +STATE_SYSTEM_PROTECTED = 0x20000000 +STATE_SYSTEM_HASPOPUP = 0x40000000 +STATE_SYSTEM_VALID = 0x3FFFFFFF + +def get_msaa_state_list(states): + state_strings = [] + if states & STATE_SYSTEM_ALERT_HIGH: + state_strings.append("ALERT_HIGH") + if states & STATE_SYSTEM_ALERT_MEDIUM: + state_strings.append("ALERT_MEDIUM") + if states & STATE_SYSTEM_ALERT_LOW: + state_strings.append("ALERT_LOW") + if states & STATE_SYSTEM_ANIMATED: + state_strings.append("ANIMATED") + if states & STATE_SYSTEM_BUSY: + state_strings.append("BUSY") + if states & STATE_SYSTEM_CHECKED: + state_strings.append("CHECKED") + if states & STATE_SYSTEM_COLLAPSED: + state_strings.append("COLLAPSED") + if states & STATE_SYSTEM_DEFAULT: + state_strings.append("DEFAULT") + if states & STATE_SYSTEM_EXPANDED: + state_strings.append("EXPANDED") + if states & STATE_SYSTEM_EXTSELECTABLE: + state_strings.append("EXTSELECTABLE") + if states & STATE_SYSTEM_FLOATING: + state_strings.append("FLOATING") + if states & STATE_SYSTEM_FOCUSABLE: + state_strings.append("FOCUSABLE") + if states & STATE_SYSTEM_FOCUSED: + state_strings.append("FOCUSED") + if states & STATE_SYSTEM_HASPOPUP: + state_strings.append("HASPOPUP") + if states & STATE_SYSTEM_HOTTRACKED: + state_strings.append("HOTTRACKED") + if states & STATE_SYSTEM_INVISIBLE: + state_strings.append("INVISIBLE") + if states & STATE_SYSTEM_LINKED: + state_strings.append("LINKED") + if states & STATE_SYSTEM_MARQUEED: + state_strings.append("MARQUEED") + if states & STATE_SYSTEM_MIXED: + state_strings.append("MIXED") + if states & STATE_SYSTEM_MOVEABLE: + state_strings.append("MOVEABLE") + if states & STATE_SYSTEM_MULTISELECTABLE: + state_strings.append("MULTISELECTABLE") + if states & STATE_SYSTEM_OFFSCREEN: + state_strings.append("OFFSCREEN") + if states & STATE_SYSTEM_PRESSED: + state_strings.append("PRESSED") + if states & STATE_SYSTEM_PROTECTED: + state_strings.append("PROTECTED") + if states & STATE_SYSTEM_READONLY: + state_strings.append("READONLY") + if states & STATE_SYSTEM_SELECTABLE: + state_strings.append("SELECTABLE") + if states & STATE_SYSTEM_SELECTED: + state_strings.append("SELECTED") + if states & STATE_SYSTEM_SELFVOICING: + state_strings.append("SELFVOICING") + if states & STATE_SYSTEM_SIZEABLE: + state_strings.append("SIZEABLE") + if states & STATE_SYSTEM_TRAVERSED: + state_strings.append("TRAVERSED") + if states & STATE_SYSTEM_UNAVAILABLE: + state_strings.append("UNAVAILABLE") + + return state_strings + +def get_state_list(states): + state_strings = [] + if states & IA2_STATE_ACTIVE: + state_strings.append("ACTIVE") + if states & IA2_STATE_ARMED: + state_strings.append("ARMED") + if states & IA2_STATE_CHECKABLE: + state_strings.append("CHECKABLE") + if states & IA2_STATE_DEFUNCT: + state_strings.append("DEFUNCT") + if states & IA2_STATE_EDITABLE: + state_strings.append("EDITABLE") + if states & IA2_STATE_HORIZONTAL: + state_strings.append("HORIZONTAL") + if states & IA2_STATE_ICONIFIED: + state_strings.append("ICONIFIED") + if states & IA2_STATE_INVALID_ENTRY: + state_strings.append("INVALID_ENTRY") + if states & IA2_STATE_MANAGES_DESCENDANTS: + state_strings.append("MANAGES_DESCENDANTS") + if states & IA2_STATE_MODAL: + state_strings.append("MODAL") + if states & IA2_STATE_MULTI_LINE: + state_strings.append("MULTI_LINE") + if states & IA2_STATE_OPAQUE: + state_strings.append("OPAQUE") + if states & IA2_STATE_PINNED: + state_strings.append("PINNED") + if states & IA2_STATE_REQUIRED: + state_strings.append("REQUIRED") + if states & IA2_STATE_SELECTABLE_TEXT: + state_strings.append("SELECTABLE_TEXT") + if states & IA2_STATE_SINGLE_LINE: + state_strings.append("SINGLE_LINE") + if states & IA2_STATE_STALE: + state_strings.append("STALE") + if states & IA2_STATE_SUPPORTS_AUTOCOMPLETION: + state_strings.append("SUPPORTS_AUTOCOMPLETION") + if states & IA2_STATE_TRANSIENT: + state_strings.append("TRANSIENT") + if states & IA2_STATE_VERTICAL: + state_strings.append("VERTICAL") + + return state_strings diff --git a/tools/wptrunner/wptrunner/executors/ia2/ia2_api_all.tlb b/tools/wptrunner/wptrunner/executors/ia2/ia2_api_all.tlb new file mode 100644 index 00000000000000..449c10b258dd7b Binary files /dev/null and b/tools/wptrunner/wptrunner/executors/ia2/ia2_api_all.tlb differ diff --git a/tools/wptrunner/wptrunner/testdriver-extra.js b/tools/wptrunner/wptrunner/testdriver-extra.js index e80c3ecb3e31e8..9a5880b17a4713 100644 --- a/tools/wptrunner/wptrunner/testdriver-extra.js +++ b/tools/wptrunner/wptrunner/testdriver-extra.js @@ -336,7 +336,7 @@ return create_action("clear_device_posture", {context}); }; - window.test_driver_internal.get_accessibility_api_node = function(dom_id) { - return create_action("get_accessibility_api_node", {dom_id}); + window.test_driver_internal.get_accessibility_api_node = function(dom_id, url) { + return create_action("get_accessibility_api_node", {dom_id, url}); }; })();