Skip to main content

Module accesskit_bridge

Module accesskit_bridge 

Expand description

AccessKit bridge: turns the toolkit’s per-widget semantic model (crate::a11y::AccessNode, from Widget::accessibility) into an accesskit::TreeUpdate, published over AT-SPI2.

build_tree_update_with_resources is a pure function of (root_widget, node_map, focused, resources): a depth-first walk that emits one node per widget returning Some(AccessNode), and collapses presentational widgets (None) by reparenting their accessible children onto the nearest ancestor — mirroring ARIA role="presentation". Being pure and keyed off the same node_map the App maintains makes it unit-testable without a live AT-SPI bus.

§Id spaces

Five disjoint ranges share the u64, so an id says what it addresses without a lookup and resolve_node_id can invert it:

spacederivationrange
rootROOT_ID (0)zero
widgettaffy::NodeId + 1 (0 reserved for the root)below 1 << 48
widget, never laid out(1 << 48) + walk_indexbit 48
text run(1 << 62) | owner idbit 62
syntheticthe owner’s id chained with each AccessNode::keybit 63

A taffy::NodeId indexes a live arena, so it is bounded by the number of nodes in memory and cannot reach 1 << 48, let alone the two marker bits; that is what keeps the widget range clear of the other three.

§Canvas widgets: focus and actions on synthetic nodes

A widget that paints its own contents — a timeline of clips, a table of rows — has no child widgets to expose, so it synthesises its accessible structure through AccessNode::children. Two things make those nodes first-class rather than merely readable:

  • Focus. The widget marks one descendant focused; while that widget holds the keyboard, build_tree_update aims the tree’s focus at that node instead of the widget. This is ARIA’s aria-activedescendant: the widget owns the keyboard, the marked node is where the user is. Keying it off the App’s real focus is deliberate — an unfocused widget cannot steal the reader’s cursor by setting a flag. active_descendant_path names the same node for the keyboard path, so Enter activates what the reader just announced.
  • Actions. resolve_node_id inverts a synthetic id back to (owning widget, key path) so an incoming ActionRequest reaches the clip the user was on, via Widget::perform_action. Inversion re-walks the live tree rather than caching an index, so a stale id from a previous frame resolves to None instead of to the wrong clip.

Enums§

A11yTarget
Where an accesskit::NodeId points in the live widget tree. Produced by resolve_node_id, which is how an incoming ActionRequest is turned back into something the app can act on.

Constants§

RESOURCE_ID_BASE
Resource and action nodes occupy reserved ranges above synthetic widget nodes and below text-run nodes. The ids are stable hashes of their public addresses, so assistive technology can retain identity across frames.
ROOT_ID
Reserved so no widget can collide with it: widget ids are offset by +1 from their taffy node id, and structural fallback ids are large offsets — see widget_node_id.
SYNTHETIC_ID_BIT
Bit that marks an accesskit::NodeId as belonging to a synthetic node — one with no backing Widget. Widget ids are taffy_id + 1 or (1 << 48) + index and text-run ids sit at bit 62, so nothing else in the tree can reach bit 63 and the space cannot collide.

Functions§

accesskit_action_to_ours
Inverse of map_action. None for actions we don’t model (scroll-by-direction, custom actions, …).
active_descendant_path
The key path to the active descendant a widget nominates — the first node in its synthetic subtree marked focused — or None when it nominates none.
build_tree_update
build_tree_update_with_resources
Build the widget accessibility tree and append the exact same live resource/action surface used by the palette, shell and collaboration API. Immediate operations expose Click; prompted operations expose SetValue with the supplied value becoming their argument.
is_synthetic_id
Whether id addresses a synthetic node rather than a widget, a text run or the root.
map_action
ToggleCheck has no dedicated verb — toggling is a Click at the platform level. SetValue/SetSelection payloads travel in ActionData on the round trip (accesskit_action_to_ours).
map_role
E.g. Role::Spinner becomes a busy AkRole::ProgressIndicator and Role::ToggleButton becomes AkRole::Button carrying toggled state.
resolve_node_id
Invert an accesskit::NodeId back to the thing it addresses, by re-deriving ids over the current widget tree.
resource_action_node_id
resource_node_id
widget_ak_id
The AccessKit id of the widget laid out at taffy_id, or None when that taffy node holds no live widget.