#![forbid(unsafe_code)]1#![cfg_attr(docsrs, feature(doc_auto_cfg))]2#![doc(3html_logo_url = "https://bevy.org/assets/icon.png",4html_favicon_url = "https://bevy.org/assets/icon.png"5)]6#![no_std]78//! Reusable accessibility primitives9//!10//! This crate provides accessibility integration for the engine. It exposes the11//! [`AccessibilityPlugin`]. This plugin integrates `AccessKit`, a Rust crate12//! providing OS-agnostic accessibility primitives, with Bevy's ECS.13//!14//! ## Some notes on utility15//!16//! While this crate defines useful types for accessibility, it does not17//! actually power accessibility features in Bevy.18//!19//! Instead, it helps other interfaces coordinate their approach to20//! accessibility. Binary authors should add the [`AccessibilityPlugin`], while21//! library maintainers may use the [`AccessibilityRequested`] and22//! [`ManageAccessibilityUpdates`] resources.23//!24//! The [`AccessibilityNode`] component is useful in both cases. It helps25//! describe an entity in terms of its accessibility factors through an26//! `AccessKit` "node".27//!28//! Typical UI concepts, like buttons, checkboxes, and textboxes, are easily29//! described by this component, though, technically, it can represent any kind30//! of Bevy [`Entity`].31//!32//! ## This crate no longer re-exports `AccessKit`33//!34//! As of Bevy version 0.15, [the `accesskit` crate][accesskit_crate] is no35//! longer re-exported from this crate.[^accesskit_node_confusion] If you need36//! to use `AccessKit` yourself, you'll have to add it as a separate dependency37//! in your project's `Cargo.toml`.38//!39//! Make sure to use the same version of the `accesskit` crate as Bevy.40//! Otherwise, you may experience errors similar to: "Perhaps two different41//! versions of crate `accesskit` are being used?"42//!43//! [accesskit_crate]: https://crates.io/crates/accesskit44//! [`Entity`]: bevy_ecs::entity::Entity45//!46//! <!--47//! note: multi-line footnotes need to be indented like this!48//!49//! please do not remove the indentation, or the second paragraph will display50//! at the end of the module docs, **before** the footnotes...51//! -->52//!53//! [^accesskit_node_confusion]: Some users were confused about `AccessKit`'s54//! `Node` type, sometimes thinking it was Bevy UI's primary way to define55//! nodes!56//!57//! For this reason, its re-export was removed by default. Users who need58//! its types can instead manually depend on the `accesskit` crate.5960#[cfg(feature = "std")]61extern crate std;6263extern crate alloc;6465use alloc::sync::Arc;66use core::sync::atomic::{AtomicBool, Ordering};6768use accesskit::Node;69use bevy_app::Plugin;70use bevy_derive::{Deref, DerefMut};71use bevy_ecs::{72component::Component, event::BufferedEvent, resource::Resource, schedule::SystemSet,73};7475#[cfg(feature = "bevy_reflect")]76use {77bevy_ecs::reflect::ReflectResource, bevy_reflect::std_traits::ReflectDefault,78bevy_reflect::Reflect,79};8081#[cfg(feature = "serialize")]82use serde::{Deserialize, Serialize};8384#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]85use bevy_reflect::{ReflectDeserialize, ReflectSerialize};8687/// Wrapper struct for [`accesskit::ActionRequest`].88///89/// This newtype is required to use `ActionRequest` as a Bevy `Event`.90#[derive(BufferedEvent, Deref, DerefMut)]91#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]92pub struct ActionRequest(pub accesskit::ActionRequest);9394/// Tracks whether an assistive technology has requested accessibility95/// information.96///97/// This type is a [`Resource`] initialized by the98/// [`AccessibilityPlugin`]. It may be useful if a third-party plugin needs to99/// conditionally integrate with `AccessKit`.100///101/// In other words, this resource represents whether accessibility providers102/// are "turned on" or "turned off" across an entire Bevy `App`.103///104/// By default, it is set to `false`, indicating that nothing has requested105/// accessibility information yet.106///107/// [`Resource`]: bevy_ecs::resource::Resource108#[derive(Resource, Default, Clone, Debug, Deref, DerefMut)]109#[cfg_attr(110feature = "bevy_reflect",111derive(Reflect),112reflect(Default, Clone, Resource)113)]114pub struct AccessibilityRequested(Arc<AtomicBool>);115116impl AccessibilityRequested {117/// Checks if any assistive technology has requested accessibility118/// information.119///120/// If so, this method returns `true`, indicating that accessibility tree121/// updates should be sent.122pub fn get(&self) -> bool {123self.load(Ordering::SeqCst)124}125126/// Sets the app's preference for sending accessibility updates.127///128/// If the `value` argument is `true`, this method requests that the app,129/// including both Bevy and third-party interfaces, provides updates to130/// accessibility information.131///132/// Setting with `false` requests that the entire app stops providing these133/// updates.134pub fn set(&self, value: bool) {135self.store(value, Ordering::SeqCst);136}137}138139/// Determines whether Bevy's ECS updates the accessibility tree.140///141/// This [`Resource`] tells Bevy internals whether it should be handling142/// `AccessKit` updates (`true`), or if something else is doing that (`false`).143///144/// It defaults to `true`. So, by default, Bevy is configured to maintain the145/// `AccessKit` tree.146///147/// Set to `false` in cases where an external GUI library is sending148/// accessibility updates instead. When this option is set inconsistently with149/// that requirement, the external library and ECS will generate conflicting150/// updates.151///152/// [`Resource`]: bevy_ecs::resource::Resource153#[derive(Resource, Clone, Debug, Deref, DerefMut)]154#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]155#[cfg_attr(156feature = "bevy_reflect",157derive(Reflect),158reflect(Resource, Clone, Default)159)]160#[cfg_attr(161all(feature = "bevy_reflect", feature = "serialize"),162reflect(Serialize, Deserialize)163)]164pub struct ManageAccessibilityUpdates(bool);165166impl Default for ManageAccessibilityUpdates {167fn default() -> Self {168Self(true)169}170}171172impl ManageAccessibilityUpdates {173/// Returns `true` if Bevy's ECS should update the accessibility tree.174pub fn get(&self) -> bool {175self.0176}177178/// Sets whether Bevy's ECS should update the accessibility tree.179pub fn set(&mut self, value: bool) {180self.0 = value;181}182}183184/// Represents an entity to `AccessKit` through an [`accesskit::Node`].185///186/// Platform-specific accessibility APIs utilize `AccessKit` nodes in their187/// accessibility frameworks. So, this component acts as a translation between188/// "Bevy entity" and "platform-agnostic accessibility element".189///190/// ## Organization in the `AccessKit` Accessibility Tree191///192/// `AccessKit` allows users to form a "tree of nodes" providing accessibility193/// information. That tree is **not** Bevy's ECS!194///195/// To explain, let's say this component is added to an entity, `E`.196///197/// ### Parent and Child198///199/// If `E` has a parent, `P`, and `P` also has this `AccessibilityNode`200/// component, then `E`'s `AccessKit` node will be a child of `P`'s `AccessKit`201/// node.202///203/// Resulting `AccessKit` tree:204/// - P205/// - E206///207/// In other words, parent-child relationships are maintained, but only if both208/// have this component.209///210/// ### On the Window211///212/// If `E` doesn't have a parent, or if the immediate parent doesn't have an213/// `AccessibilityNode`, its `AccessKit` node will be an immediate child of the214/// primary window.215///216/// Resulting `AccessKit` tree:217/// - Primary window218/// - E219///220/// When there's no `AccessKit`-compatible parent, the child lacks hierarchical221/// information in `AccessKit`. As such, it is placed directly under the222/// primary window on the `AccessKit` tree.223///224/// This behavior may or may not be intended, so please utilize225/// `AccessibilityNode`s with care.226#[derive(Component, Clone, Deref, DerefMut)]227#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]228pub struct AccessibilityNode(229/// A representation of this component's entity to `AccessKit`.230///231/// Note that, with its parent struct acting as just a newtype, users are232/// intended to directly update this field.233pub Node,234);235236impl From<Node> for AccessibilityNode {237/// Converts an [`accesskit::Node`] into the Bevy Engine238/// [`AccessibilityNode`] newtype.239///240/// Doing so allows it to be inserted onto Bevy entities, representing Bevy241/// entities in the `AccessKit` tree.242fn from(node: Node) -> Self {243Self(node)244}245}246247/// A system set relating to accessibility.248///249/// Helps run accessibility updates all at once.250#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]251#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]252#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]253#[cfg_attr(254all(feature = "bevy_reflect", feature = "serialize"),255reflect(Serialize, Deserialize, Clone)256)]257pub enum AccessibilitySystems {258/// Update the accessibility tree.259Update,260}261262/// Deprecated alias for [`AccessibilitySystems`].263#[deprecated(since = "0.17.0", note = "Renamed to `AccessibilitySystems`.")]264pub type AccessibilitySystem = AccessibilitySystems;265266/// Plugin managing integration with accessibility APIs.267///268/// Note that it doesn't handle GUI aspects of this integration, instead269/// providing helpful resources for other interfaces to utilize.270///271/// ## Behavior272///273/// This plugin's main role is to initialize the [`AccessibilityRequested`] and274/// [`ManageAccessibilityUpdates`] resources to their default values, meaning:275///276/// - no assistive technologies have requested accessibility information yet,277/// and278/// - Bevy's ECS will manage updates to the accessibility tree.279#[derive(Default)]280pub struct AccessibilityPlugin;281282impl Plugin for AccessibilityPlugin {283fn build(&self, app: &mut bevy_app::App) {284app.init_resource::<AccessibilityRequested>()285.init_resource::<ManageAccessibilityUpdates>()286.allow_ambiguous_component::<AccessibilityNode>();287}288}289290291