gfx/accessibility.h
Walking the tree a screen reader would want to see.
#include <sonore/gfx/accessibility.h>- 2types
- 4other declarations
- Guides: The native editor
On this page
Design notes
The vocabulary -- roles, names, values, ranges -- is in accessible_info.h, which Component includes so it can declare accessibleInfo(). This is the traversal, which needs Components and so cannot live there.
Everything here is testable against a component tree with no window at all. That is the reason for the split: the platform bridges are the part that cannot be tested on this machine, and they should be a mechanical mapping from this rather than a second source of truth about what a knob is called.
One table, every platform
What each role is called on each platform lives in ONE table below, read by both bridges: uia_win32.h for UI Automation's control type, and accessibility_mac.h for NSAccessibility's role, subrole and how the value is read. Two switch statements in two files are two answers to "what is a combo box", and the second platform would drift from the first without anything noticing; one row per role is a thing a test can walk.
The rest of what the macOS bridge decides -- which change to announce, which element survives a rebuild, where a rectangle is on a y-up screen -- is here too, in detail, because it is arithmetic and bookkeeping that runs on any machine. The bridge that cannot be run here is left holding only the calls into AppKit.
Types 2
One role, on every platform.
The UIA numbers are UIA_*ControlTypeId from UIAutomationClient.h -- stable ABI, written out so this header needs no Windows header, and checked against the real constants by static_assert in uia_win32.h. The AX strings are the values of Apple's kAX*Role / kAX*Subrole constants (AXRoleConstants.h), which is what NSAccessibilityButtonRole and the rest ARE: NSStrings that compare by value.
One entry in the flattened tree a bridge walks.
Flattened rather than nested, because every bridge needs both -- a linear order for "next element" and a parent link for hierarchy -- and computing one from the other twice is how the two end up disagreeing.
Functions 3
- fn
inline const AccessibleRoleMapping& accessibleRoleMapping(AccessibleRole role)The row forgfx::accessibleRoleMapping · accessibility.h:81role. Every role has one; Unknown's is the fallback. - fn
inline void collectAccessible(Component* c, std::vector<AccessibleNode>& out, int parent = -1, int depth = 0, Point offset = {0.0f, 0.0f})The accessible tree, in reading order.gfx::collectAccessible · accessibility.h:176 - fn
inline std::string describeAccessibleTree(Component* root)The whole tree as one string, one line per element, indented by depth.gfx::describeAccessibleTree · accessibility.h:202
Enums 1
- enum
enum class AccessibleValueKindHow a platform that types its values (NSAccessibility: a number for a slider, a string for a field) should read this role's.gfx::AccessibleValueKind · accessibility.h:42