diff --git a/crates/bevy_a11y/Cargo.toml b/crates/bevy_a11y/Cargo.toml index 82a3da1f297e5..73464d568ed4b 100644 --- a/crates/bevy_a11y/Cargo.toml +++ b/crates/bevy_a11y/Cargo.toml @@ -14,6 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.15.0-dev" } bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" } +bevy_input_focus = { path = "../bevy_input_focus", version = "0.15.0-dev" } accesskit = "0.17" diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs index 77ddf2073d9fa..453ac7b7f88cd 100644 --- a/crates/bevy_a11y/src/lib.rs +++ b/crates/bevy_a11y/src/lib.rs @@ -22,11 +22,10 @@ use accesskit::Node; use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - prelude::{Component, Entity, Event, ReflectResource}, + prelude::{Component, Event}, schedule::SystemSet, system::Resource, }; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; /// Wrapper struct for [`accesskit::ActionRequest`]. Required to allow it to be used as an `Event`. #[derive(Event, Deref, DerefMut)] @@ -97,11 +96,6 @@ impl From for AccessibilityNode { } } -/// Resource representing which entity has keyboard focus, if any. -#[derive(Resource, Default, Deref, DerefMut, Reflect)] -#[reflect(Resource, Default)] -pub struct Focus(pub Option); - /// Set enum for the systems relating to accessibility #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] pub enum AccessibilitySystem { @@ -115,11 +109,8 @@ pub struct AccessibilityPlugin; impl Plugin for AccessibilityPlugin { fn build(&self, app: &mut bevy_app::App) { - app.register_type::(); - app.init_resource::() .init_resource::() - .init_resource::() .allow_ambiguous_component::(); } } diff --git a/crates/bevy_input_focus/src/lib.rs b/crates/bevy_input_focus/src/lib.rs index e7b7dc0c017b1..cb2e24bfa8d79 100644 --- a/crates/bevy_input_focus/src/lib.rs +++ b/crates/bevy_input_focus/src/lib.rs @@ -18,13 +18,13 @@ pub mod tab_navigation; -use bevy_app::{App, Plugin, PreUpdate}; +use bevy_app::{App, Plugin, PreUpdate, Startup}; use bevy_ecs::{ component::Component, entity::Entity, event::{Event, EventReader}, query::{QueryData, With}, - system::{Commands, Query, Res, Resource, SystemParam}, + system::{Commands, Query, Res, ResMut, Resource, Single, SystemParam}, traversal::Traversal, world::{Command, DeferredWorld, World}, }; @@ -149,12 +149,21 @@ pub struct InputDispatchPlugin; impl Plugin for InputDispatchPlugin { fn build(&self, app: &mut App) { - app.insert_resource(InputFocus(None)) + app.add_systems(Startup, set_initial_focus) + .insert_resource(InputFocus(None)) .insert_resource(InputFocusVisible(false)) .add_systems(PreUpdate, dispatch_keyboard_input); } } +/// Sets the initial focus to the primary window, if any. +pub fn set_initial_focus( + mut input_focus: ResMut, + window: Single>, +) { + input_focus.0 = Some(*window); +} + /// System which dispatches keyboard input events to the focused entity, or to the primary window /// if no entity has focus. fn dispatch_keyboard_input( @@ -377,6 +386,9 @@ mod tests { }; app.world_mut().spawn((window, PrimaryWindow)); + // Run the world for a single frame to set up the initial focus + app.update(); + let entity_a = app .world_mut() .spawn((GatherKeyboardEvents::default(), SetFocusOnAdd)) diff --git a/crates/bevy_window/Cargo.toml b/crates/bevy_window/Cargo.toml index 2a8828cdef009..0399f9e782f06 100644 --- a/crates/bevy_window/Cargo.toml +++ b/crates/bevy_window/Cargo.toml @@ -13,7 +13,6 @@ serialize = ["serde", "smol_str/serde", "bevy_ecs/serialize"] [dependencies] # bevy -bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev" } bevy_app = { path = "../bevy_app", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } bevy_input = { path = "../bevy_input", version = "0.15.0-dev" } diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index e347dfadd69b7..5ec7e07a3edef 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -16,8 +16,6 @@ extern crate alloc; use alloc::sync::Arc; use std::sync::Mutex; -use bevy_a11y::Focus; - mod event; mod monitor; mod raw_handle; @@ -118,17 +116,10 @@ impl Plugin for WindowPlugin { .add_event::(); if let Some(primary_window) = &self.primary_window { - let initial_focus = app - .world_mut() - .spawn(primary_window.clone()) - .insert(( - PrimaryWindow, - RawHandleWrapperHolder(Arc::new(Mutex::new(None))), - )) - .id(); - if let Some(mut focus) = app.world_mut().get_resource_mut::() { - **focus = Some(initial_focus); - } + app.world_mut().spawn(primary_window.clone()).insert(( + PrimaryWindow, + RawHandleWrapperHolder(Arc::new(Mutex::new(None))), + )); } match self.exit_condition { diff --git a/crates/bevy_winit/Cargo.toml b/crates/bevy_winit/Cargo.toml index 2d9dfa7c1e537..02ff9f56a79b1 100644 --- a/crates/bevy_winit/Cargo.toml +++ b/crates/bevy_winit/Cargo.toml @@ -29,6 +29,7 @@ bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" } bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" } bevy_input = { path = "../bevy_input", version = "0.15.0-dev" } +bevy_input_focus = { path = "../bevy_input_focus", version = "0.15.0-dev" } bevy_log = { path = "../bevy_log", version = "0.15.0-dev" } bevy_math = { path = "../bevy_math", version = "0.15.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" } diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index 9b99d2eeca7dd..078f47ae4377a 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -1,6 +1,7 @@ //! Helpers for mapping window entities to accessibility types use alloc::{collections::VecDeque, sync::Arc}; +use bevy_input_focus::InputFocus; use std::sync::Mutex; use accesskit::{ @@ -10,13 +11,14 @@ use accesskit::{ use accesskit_winit::Adapter; use bevy_a11y::{ AccessibilityNode, AccessibilityRequested, AccessibilitySystem, - ActionRequest as ActionRequestWrapper, Focus, ManageAccessibilityUpdates, + ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates, }; use bevy_app::{App, Plugin, PostUpdate}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ + change_detection::DetectChanges, entity::EntityHashMap, - prelude::{DetectChanges, Entity, EventReader, EventWriter}, + prelude::{Entity, EventReader, EventWriter}, query::With, schedule::IntoSystemConfigs, system::{NonSendMut, Query, Res, ResMut, Resource}, @@ -179,7 +181,7 @@ fn should_update_accessibility_nodes( fn update_accessibility_nodes( mut adapters: NonSendMut, - focus: Res, + focus: Res, primary_window: Query<(Entity, &Window), With>, nodes: Query<( Entity, @@ -218,7 +220,7 @@ fn update_adapter( node_entities: Query>, primary_window: &Window, primary_window_id: Entity, - focus: Res, + focus: Res, ) -> TreeUpdate { let mut to_update = vec![]; let mut window_children = vec![]; @@ -241,7 +243,7 @@ fn update_adapter( TreeUpdate { nodes: to_update, tree: None, - focus: NodeId(focus.unwrap_or(primary_window_id).to_bits()), + focus: NodeId(focus.0.unwrap_or(primary_window_id).to_bits()), } }