Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various accessibility API updates. #9989

Merged
merged 6 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Various accessibility API updates.
* Add `bevy_a11y::ManageAccessibilityUpdates` to indicate whether the ECS should manage tree updates.
* Add getter/setter to `bevy_a11y::AccessibilityRequested`.
* Add `bevy_a11y::AccessibilitySystem` `SystemSet` for ordering relative to accessibility tree updates.
* Correctly set initial focus to new windows on creation.
  • Loading branch information
ndarilek committed Oct 1, 2023
commit facf9c032815dd59b1c4df6546866397b719000b
54 changes: 53 additions & 1 deletion crates/bevy_a11y/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

use std::{
num::NonZeroU128,
sync::{atomic::AtomicBool, Arc},
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};

pub use accesskit;
Expand All @@ -15,6 +18,7 @@ use bevy_app::Plugin;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
prelude::{Component, Entity, Event},
schedule::SystemSet,
system::Resource,
};

Expand All @@ -30,6 +34,46 @@ pub struct ActionRequest(pub accesskit::ActionRequest);
#[derive(Resource, Default, Clone, Debug, Deref, DerefMut)]
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
/// accessibility API.
///
Expand Down Expand Up @@ -64,12 +108,20 @@ impl AccessKitEntityExt for Entity {
#[derive(Resource, Default, Deref, DerefMut)]
pub struct Focus(Option<Entity>);
ndarilek marked this conversation as resolved.
Show resolved Hide resolved

/// 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.
pub struct AccessibilityPlugin;

impl Plugin for AccessibilityPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.init_resource::<AccessibilityRequested>()
.init_resource::<ManageAccessibilityUpdates>()
.init_resource::<Focus>();
}
}
1 change: 1 addition & 0 deletions crates/bevy_window/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ serialize = ["serde"]

[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", 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_math = { path = "../bevy_math", version = "0.12.0-dev" }
Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_window/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//! The [`WindowPlugin`] sets up some global window-related parameters and
//! is part of the [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).

use bevy_a11y::Focus;

mod cursor;
mod event;
mod raw_handle;
Expand Down Expand Up @@ -99,9 +101,14 @@ impl Plugin for WindowPlugin {
.add_event::<WindowThemeChanged>();

if let Some(primary_window) = &self.primary_window {
app.world
let initial_focus = app
.world
.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 {
Expand Down
22 changes: 12 additions & 10 deletions crates/bevy_winit/src/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

use std::{
collections::VecDeque,
sync::{atomic::Ordering, Arc, Mutex},
sync::{Arc, Mutex},
};

use accesskit_winit::Adapter;
use bevy_a11y::ActionRequest as ActionRequestWrapper;
use bevy_a11y::{
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, AccessibilitySystem, Focus,
};
use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates};
use bevy_app::{App, Plugin, PostUpdate};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
prelude::{DetectChanges, Entity, EventReader, EventWriter},
query::With,
schedule::IntoSystemConfigs,
system::{NonSend, NonSendMut, Query, Res, ResMut, Resource},
};
use bevy_hierarchy::{Children, Parent};
Expand Down Expand Up @@ -48,17 +49,16 @@ fn handle_window_focus(
) {
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 {
if let Some(focus_id) = **focus {
adapter.update_if_active(|| TreeUpdate {
focus: if event.focused {
Some(focus_id.to_node_id())
} else {
None
},
..default()
}
});
});
}
}
}
}
Expand Down Expand Up @@ -91,6 +91,7 @@ fn update_accessibility_nodes(
focus: Res<Focus>,
accessibility_requested: Res<AccessibilityRequested>,
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
manage_accessibility_updates: Res<ManageAccessibilityUpdates>,
nodes: Query<(
Entity,
&AccessibilityNode,
Expand All @@ -99,7 +100,7 @@ fn update_accessibility_nodes(
)>,
node_entities: Query<Entity, With<AccessibilityNode>>,
) {
if !accessibility_requested.load(Ordering::SeqCst) {
if !accessibility_requested.get() || !manage_accessibility_updates.get() {
ndarilek marked this conversation as resolved.
Show resolved Hide resolved
return;
}
if let Ok((primary_window_id, primary_window)) = primary_window.get_single() {
Expand Down Expand Up @@ -176,7 +177,8 @@ impl Plugin for AccessibilityPlugin {
window_closed,
poll_receivers,
update_accessibility_nodes,
),
)
.in_set(AccessibilitySystem::Update),
);
}
}
3 changes: 1 addition & 2 deletions crates/bevy_winit/src/winit_windows.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![warn(missing_docs)]
use std::sync::atomic::Ordering;

use accesskit_winit::Adapter;
use bevy_a11y::{
Expand Down Expand Up @@ -157,7 +156,7 @@ impl WinitWindows {
let adapter = Adapter::with_action_handler(
&winit_window,
move || {
accessibility_requested.store(true, Ordering::SeqCst);
accessibility_requested.set(true);
TreeUpdate {
nodes: vec![(accesskit_window_id, root)],
tree: Some(Tree::new(accesskit_window_id)),
Expand Down