mirror of
https://github.com/bevyengine/bevy
synced 2024-11-28 15:40:21 +00:00
Various accessibility API updates. (#9989)
# Objective `bevy_a11y` was impossible to integrate into some third-party projects in part because it insisted on managing the accessibility tree on its own. ## Solution The changes in this PR were necessary to get `bevy_egui` working with Bevy's AccessKit integration. They were tested on a fork of 0.11, developed against `bevy_egui`, then ported to main and tested against the `ui` example. ## Changelog ### Changed * Add `bevy_a11y::ManageAccessibilityUpdates` to indicate whether the ECS should manage accessibility tree updates. * Add getter/setter to `bevy_a11y::AccessibilityRequested`. * Add `bevy_a11y::AccessibilitySystem` `SystemSet` for ordering relative to accessibility tree updates. * Upgrade `accesskit` to v0.12.0. ### Fixed * Correctly set initial accessibility focus to new windows on creation. ## Migration Guide ### Change direct accesses of `AccessibilityRequested` to use `AccessibilityRequested.::get()`/`AccessibilityRequested::set()` #### Before ``` use std::sync::atomic::Ordering; // To access accessibility_requested.load(Ordering::SeqCst) // To update accessibility_requested.store(true, Ordering::SeqCst); ``` #### After ``` // To access accessibility_requested.get() // To update accessibility_requested.set(true); ``` --------- Co-authored-by: StaffEngineer <111751109+StaffEngineer@users.noreply.github.com>
This commit is contained in:
parent
44a9a4cc86
commit
73e0ac26ca
8 changed files with 108 additions and 86 deletions
|
@ -14,4 +14,4 @@ bevy_app = { path = "../bevy_app", version = "0.12.0-dev" }
|
||||||
bevy_derive = { path = "../bevy_derive", version = "0.12.0-dev" }
|
bevy_derive = { path = "../bevy_derive", version = "0.12.0-dev" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0-dev" }
|
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0-dev" }
|
||||||
|
|
||||||
accesskit = "0.11"
|
accesskit = "0.12"
|
||||||
|
|
|
@ -4,17 +4,18 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
use std::{
|
use std::sync::{
|
||||||
num::NonZeroU128,
|
atomic::{AtomicBool, Ordering},
|
||||||
sync::{atomic::AtomicBool, Arc},
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use accesskit;
|
pub use accesskit;
|
||||||
use accesskit::{NodeBuilder, NodeId};
|
use accesskit::NodeBuilder;
|
||||||
use bevy_app::Plugin;
|
use bevy_app::Plugin;
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::{Component, Entity, Event},
|
prelude::{Component, Entity, Event},
|
||||||
|
schedule::SystemSet,
|
||||||
system::Resource,
|
system::Resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +31,46 @@ pub struct ActionRequest(pub accesskit::ActionRequest);
|
||||||
#[derive(Resource, Default, Clone, Debug, Deref, DerefMut)]
|
#[derive(Resource, Default, Clone, Debug, Deref, DerefMut)]
|
||||||
pub struct AccessibilityRequested(Arc<AtomicBool>);
|
pub struct AccessibilityRequested(Arc<AtomicBool>);
|
||||||
|
|
||||||
|
impl AccessibilityRequested {
|
||||||
|
/// Returns `true` if an access technology is active and accessibility tree
|
||||||
|
/// updates should be sent.
|
||||||
|
pub fn get(&self) -> bool {
|
||||||
|
self.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether accessibility updates were requested by an access technology.
|
||||||
|
pub fn set(&self, value: bool) {
|
||||||
|
self.store(value, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resource whose value determines whether the accessibility tree is updated
|
||||||
|
/// via the ECS.
|
||||||
|
///
|
||||||
|
/// Set to `false` in cases where an external GUI library is sending
|
||||||
|
/// accessibility updates instead. Without this, the external library and ECS
|
||||||
|
/// will generate conflicting updates.
|
||||||
|
#[derive(Resource, Clone, Debug, Deref, DerefMut)]
|
||||||
|
pub struct ManageAccessibilityUpdates(bool);
|
||||||
|
|
||||||
|
impl Default for ManageAccessibilityUpdates {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManageAccessibilityUpdates {
|
||||||
|
/// Returns `true` if the ECS should update the accessibility tree.
|
||||||
|
pub fn get(&self) -> bool {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether the ECS should update the accessibility tree.
|
||||||
|
pub fn set(&mut self, value: bool) {
|
||||||
|
self.0 = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Component to wrap a [`accesskit::Node`], representing this entity to the platform's
|
/// Component to wrap a [`accesskit::Node`], representing this entity to the platform's
|
||||||
/// accessibility API.
|
/// accessibility API.
|
||||||
///
|
///
|
||||||
|
@ -47,22 +88,16 @@ impl From<NodeBuilder> for AccessibilityNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extensions to ease integrating entities with [`AccessKit`](https://accesskit.dev).
|
|
||||||
pub trait AccessKitEntityExt {
|
|
||||||
/// Convert an entity to a stable [`NodeId`].
|
|
||||||
fn to_node_id(&self) -> NodeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AccessKitEntityExt for Entity {
|
|
||||||
fn to_node_id(&self) -> NodeId {
|
|
||||||
let id = NonZeroU128::new(self.to_bits() as u128 + 1);
|
|
||||||
NodeId(id.unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resource representing which entity has keyboard focus, if any.
|
/// Resource representing which entity has keyboard focus, if any.
|
||||||
#[derive(Resource, Default, Deref, DerefMut)]
|
#[derive(Resource, Default, Deref, DerefMut)]
|
||||||
pub struct Focus(Option<Entity>);
|
pub struct Focus(pub Option<Entity>);
|
||||||
|
|
||||||
|
/// Set enum for the systems relating to accessibility
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
|
||||||
|
pub enum AccessibilitySystem {
|
||||||
|
/// Update the accessibility tree
|
||||||
|
Update,
|
||||||
|
}
|
||||||
|
|
||||||
/// Plugin managing non-GUI aspects of integrating with accessibility APIs.
|
/// Plugin managing non-GUI aspects of integrating with accessibility APIs.
|
||||||
pub struct AccessibilityPlugin;
|
pub struct AccessibilityPlugin;
|
||||||
|
@ -70,6 +105,7 @@ pub struct AccessibilityPlugin;
|
||||||
impl Plugin for AccessibilityPlugin {
|
impl Plugin for AccessibilityPlugin {
|
||||||
fn build(&self, app: &mut bevy_app::App) {
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
app.init_resource::<AccessibilityRequested>()
|
app.init_resource::<AccessibilityRequested>()
|
||||||
|
.init_resource::<ManageAccessibilityUpdates>()
|
||||||
.init_resource::<Focus>();
|
.init_resource::<Focus>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,14 +124,14 @@ fn label_changed(
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
let name = Some(values.join(" ").into_boxed_str());
|
let name = Some(values.join(" ").into_boxed_str());
|
||||||
if let Some(mut accessible) = accessible {
|
if let Some(mut accessible) = accessible {
|
||||||
accessible.set_role(Role::LabelText);
|
accessible.set_role(Role::StaticText);
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
accessible.set_name(name);
|
accessible.set_name(name);
|
||||||
} else {
|
} else {
|
||||||
accessible.clear_name();
|
accessible.clear_name();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut node = NodeBuilder::new(Role::LabelText);
|
let mut node = NodeBuilder::new(Role::StaticText);
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
node.set_name(name);
|
node.set_name(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ serialize = ["serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# bevy
|
# bevy
|
||||||
|
bevy_a11y = { path = "../bevy_a11y", version = "0.12.0-dev" }
|
||||||
bevy_app = { path = "../bevy_app", version = "0.12.0-dev" }
|
bevy_app = { path = "../bevy_app", version = "0.12.0-dev" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0-dev" }
|
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0-dev" }
|
||||||
bevy_math = { path = "../bevy_math", version = "0.12.0-dev" }
|
bevy_math = { path = "../bevy_math", version = "0.12.0-dev" }
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
//! The [`WindowPlugin`] sets up some global window-related parameters and
|
//! The [`WindowPlugin`] sets up some global window-related parameters and
|
||||||
//! is part of the [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).
|
//! is part of the [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).
|
||||||
|
|
||||||
|
use bevy_a11y::Focus;
|
||||||
|
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod event;
|
mod event;
|
||||||
mod raw_handle;
|
mod raw_handle;
|
||||||
|
@ -99,9 +101,14 @@ impl Plugin for WindowPlugin {
|
||||||
.add_event::<WindowThemeChanged>();
|
.add_event::<WindowThemeChanged>();
|
||||||
|
|
||||||
if let Some(primary_window) = &self.primary_window {
|
if let Some(primary_window) = &self.primary_window {
|
||||||
app.world
|
let initial_focus = app
|
||||||
|
.world
|
||||||
.spawn(primary_window.clone())
|
.spawn(primary_window.clone())
|
||||||
.insert(PrimaryWindow);
|
.insert(PrimaryWindow)
|
||||||
|
.id();
|
||||||
|
if let Some(mut focus) = app.world.get_resource_mut::<Focus>() {
|
||||||
|
**focus = Some(initial_focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.exit_condition {
|
match self.exit_condition {
|
||||||
|
|
|
@ -29,7 +29,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.12.0-dev" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
winit = { version = "0.28.7", default-features = false }
|
winit = { version = "0.28.7", default-features = false }
|
||||||
accesskit_winit = { version = "0.14", default-features = false }
|
accesskit_winit = { version = "0.15", default-features = false }
|
||||||
approx = { version = "0.5", default-features = false }
|
approx = { version = "0.5", default-features = false }
|
||||||
raw-window-handle = "0.5"
|
raw-window-handle = "0.5"
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,28 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
sync::{atomic::Ordering, Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use accesskit_winit::Adapter;
|
use accesskit_winit::Adapter;
|
||||||
use bevy_a11y::ActionRequest as ActionRequestWrapper;
|
|
||||||
use bevy_a11y::{
|
use bevy_a11y::{
|
||||||
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
|
accesskit::{
|
||||||
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
|
ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, NodeId, Role, TreeUpdate,
|
||||||
|
},
|
||||||
|
AccessibilityNode, AccessibilityRequested, AccessibilitySystem, Focus,
|
||||||
};
|
};
|
||||||
|
use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates};
|
||||||
use bevy_app::{App, Plugin, PostUpdate};
|
use bevy_app::{App, Plugin, PostUpdate};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
||||||
query::With,
|
query::With,
|
||||||
|
schedule::IntoSystemConfigs,
|
||||||
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
|
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
|
||||||
};
|
};
|
||||||
use bevy_hierarchy::{Children, Parent};
|
use bevy_hierarchy::{Children, Parent};
|
||||||
use bevy_utils::{default, HashMap};
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::{PrimaryWindow, Window, WindowClosed, WindowFocused};
|
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
||||||
|
|
||||||
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
||||||
#[derive(Default, Deref, DerefMut)]
|
#[derive(Default, Deref, DerefMut)]
|
||||||
|
@ -35,34 +38,12 @@ pub struct WinitActionHandlers(pub HashMap<Entity, WinitActionHandler>);
|
||||||
pub struct WinitActionHandler(pub Arc<Mutex<VecDeque<ActionRequest>>>);
|
pub struct WinitActionHandler(pub Arc<Mutex<VecDeque<ActionRequest>>>);
|
||||||
|
|
||||||
impl ActionHandler for WinitActionHandler {
|
impl ActionHandler for WinitActionHandler {
|
||||||
fn do_action(&self, request: ActionRequest) {
|
fn do_action(&mut self, request: ActionRequest) {
|
||||||
let mut requests = self.0.lock().unwrap();
|
let mut requests = self.0.lock().unwrap();
|
||||||
requests.push_back(request);
|
requests.push_back(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_window_focus(
|
|
||||||
focus: Res<Focus>,
|
|
||||||
adapters: NonSend<AccessKitAdapters>,
|
|
||||||
mut focused: EventReader<WindowFocused>,
|
|
||||||
) {
|
|
||||||
for event in focused.read() {
|
|
||||||
if let Some(adapter) = adapters.get(&event.window) {
|
|
||||||
adapter.update_if_active(|| {
|
|
||||||
let focus_id = (*focus).unwrap_or_else(|| event.window);
|
|
||||||
TreeUpdate {
|
|
||||||
focus: if event.focused {
|
|
||||||
Some(focus_id.to_node_id())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_closed(
|
fn window_closed(
|
||||||
mut adapters: NonSendMut<AccessKitAdapters>,
|
mut adapters: NonSendMut<AccessKitAdapters>,
|
||||||
mut receivers: ResMut<WinitActionHandlers>,
|
mut receivers: ResMut<WinitActionHandlers>,
|
||||||
|
@ -86,10 +67,16 @@ fn poll_receivers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn should_update_accessibility_nodes(
|
||||||
|
accessibility_requested: Res<AccessibilityRequested>,
|
||||||
|
manage_accessibility_updates: Res<ManageAccessibilityUpdates>,
|
||||||
|
) -> bool {
|
||||||
|
accessibility_requested.get() && manage_accessibility_updates.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn update_accessibility_nodes(
|
fn update_accessibility_nodes(
|
||||||
adapters: NonSend<AccessKitAdapters>,
|
adapters: NonSend<AccessKitAdapters>,
|
||||||
focus: Res<Focus>,
|
focus: Res<Focus>,
|
||||||
accessibility_requested: Res<AccessibilityRequested>,
|
|
||||||
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
|
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
|
||||||
nodes: Query<(
|
nodes: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
|
@ -99,46 +86,37 @@ fn update_accessibility_nodes(
|
||||||
)>,
|
)>,
|
||||||
node_entities: Query<Entity, With<AccessibilityNode>>,
|
node_entities: Query<Entity, With<AccessibilityNode>>,
|
||||||
) {
|
) {
|
||||||
if !accessibility_requested.load(Ordering::SeqCst) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if let Ok((primary_window_id, primary_window)) = primary_window.get_single() {
|
if let Ok((primary_window_id, primary_window)) = primary_window.get_single() {
|
||||||
if let Some(adapter) = adapters.get(&primary_window_id) {
|
if let Some(adapter) = adapters.get(&primary_window_id) {
|
||||||
let should_run = focus.is_changed() || !nodes.is_empty();
|
let should_run = focus.is_changed() || !nodes.is_empty();
|
||||||
if should_run {
|
if should_run {
|
||||||
adapter.update_if_active(|| {
|
adapter.update_if_active(|| {
|
||||||
let mut to_update = vec![];
|
let mut to_update = vec![];
|
||||||
let mut has_focus = false;
|
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
if primary_window.focused {
|
if primary_window.focused {
|
||||||
has_focus = true;
|
|
||||||
let title = primary_window.title.clone();
|
let title = primary_window.title.clone();
|
||||||
name = Some(title.into_boxed_str());
|
name = Some(title.into_boxed_str());
|
||||||
}
|
}
|
||||||
let focus_id = if has_focus {
|
let focus_id = (*focus).unwrap_or_else(|| primary_window_id).to_bits();
|
||||||
(*focus).or_else(|| Some(primary_window_id))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let mut root_children = vec![];
|
let mut root_children = vec![];
|
||||||
for (entity, node, children, parent) in &nodes {
|
for (entity, node, children, parent) in &nodes {
|
||||||
let mut node = (**node).clone();
|
let mut node = (**node).clone();
|
||||||
if let Some(parent) = parent {
|
if let Some(parent) = parent {
|
||||||
if node_entities.get(**parent).is_err() {
|
if !node_entities.contains(**parent) {
|
||||||
root_children.push(entity.to_node_id());
|
root_children.push(NodeId(entity.to_bits()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
root_children.push(entity.to_node_id());
|
root_children.push(NodeId(entity.to_bits()));
|
||||||
}
|
}
|
||||||
if let Some(children) = children {
|
if let Some(children) = children {
|
||||||
for child in children {
|
for child in children {
|
||||||
if node_entities.get(*child).is_ok() {
|
if node_entities.contains(*child) {
|
||||||
node.push_child(child.to_node_id());
|
node.push_child(NodeId(child.to_bits()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
to_update.push((
|
to_update.push((
|
||||||
entity.to_node_id(),
|
NodeId(entity.to_bits()),
|
||||||
node.build(&mut NodeClassSet::lock_global()),
|
node.build(&mut NodeClassSet::lock_global()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -148,12 +126,12 @@ fn update_accessibility_nodes(
|
||||||
}
|
}
|
||||||
root.set_children(root_children);
|
root.set_children(root_children);
|
||||||
let root = root.build(&mut NodeClassSet::lock_global());
|
let root = root.build(&mut NodeClassSet::lock_global());
|
||||||
let window_update = (primary_window_id.to_node_id(), root);
|
let window_update = (NodeId(primary_window_id.to_bits()), root);
|
||||||
to_update.insert(0, window_update);
|
to_update.insert(0, window_update);
|
||||||
TreeUpdate {
|
TreeUpdate {
|
||||||
nodes: to_update,
|
nodes: to_update,
|
||||||
focus: focus_id.map(|v| v.to_node_id()),
|
tree: None,
|
||||||
..default()
|
focus: NodeId(focus_id),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -171,12 +149,13 @@ impl Plugin for AccessibilityPlugin {
|
||||||
.add_event::<ActionRequestWrapper>()
|
.add_event::<ActionRequestWrapper>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
(
|
(window_closed, poll_receivers).in_set(AccessibilitySystem::Update),
|
||||||
handle_window_focus,
|
)
|
||||||
window_closed,
|
.add_systems(
|
||||||
poll_receivers,
|
PostUpdate,
|
||||||
update_accessibility_nodes,
|
update_accessibility_nodes
|
||||||
),
|
.run_if(should_update_accessibility_nodes)
|
||||||
|
.in_set(AccessibilitySystem::Update),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use accesskit_winit::Adapter;
|
use accesskit_winit::Adapter;
|
||||||
use bevy_a11y::{
|
use bevy_a11y::{
|
||||||
accesskit::{NodeBuilder, NodeClassSet, Role, Tree, TreeUpdate},
|
accesskit::{NodeBuilder, NodeClassSet, NodeId, Role, Tree, TreeUpdate},
|
||||||
AccessKitEntityExt, AccessibilityRequested,
|
AccessibilityRequested,
|
||||||
};
|
};
|
||||||
use bevy_ecs::entity::Entity;
|
use bevy_ecs::entity::Entity;
|
||||||
|
|
||||||
|
@ -151,17 +150,17 @@ impl WinitWindows {
|
||||||
root_builder.set_name(name.into_boxed_str());
|
root_builder.set_name(name.into_boxed_str());
|
||||||
let root = root_builder.build(&mut NodeClassSet::lock_global());
|
let root = root_builder.build(&mut NodeClassSet::lock_global());
|
||||||
|
|
||||||
let accesskit_window_id = entity.to_node_id();
|
let accesskit_window_id = NodeId(entity.to_bits());
|
||||||
let handler = WinitActionHandler::default();
|
let handler = WinitActionHandler::default();
|
||||||
let accessibility_requested = (*accessibility_requested).clone();
|
let accessibility_requested = accessibility_requested.clone();
|
||||||
let adapter = Adapter::with_action_handler(
|
let adapter = Adapter::with_action_handler(
|
||||||
&winit_window,
|
&winit_window,
|
||||||
move || {
|
move || {
|
||||||
accessibility_requested.store(true, Ordering::SeqCst);
|
accessibility_requested.set(true);
|
||||||
TreeUpdate {
|
TreeUpdate {
|
||||||
nodes: vec![(accesskit_window_id, root)],
|
nodes: vec![(accesskit_window_id, root)],
|
||||||
tree: Some(Tree::new(accesskit_window_id)),
|
tree: Some(Tree::new(accesskit_window_id)),
|
||||||
focus: None,
|
focus: accesskit_window_id,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Box::new(handler.clone()),
|
Box::new(handler.clone()),
|
||||||
|
|
Loading…
Reference in a new issue