diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 6a058d05fd063..d0bb67c5c28c6 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -1,14 +1,19 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; use bevy_ecs::event::EventWriter; use bevy_ecs::system::{NonSend, NonSendMut}; +use bevy_input::gamepad::GamepadInfo; use bevy_input::{gamepad::GamepadEventRaw, prelude::*}; use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; pub fn gilrs_event_startup_system(gilrs: NonSend, mut events: EventWriter) { - for (id, _) in gilrs.gamepads() { + for (id, gamepad) in gilrs.gamepads() { + let info = GamepadInfo { + name: gamepad.name().into(), + }; + events.send(GamepadEventRaw::new( convert_gamepad_id(id), - GamepadEventType::Connected, + GamepadEventType::Connected(info), )); } } @@ -22,9 +27,14 @@ pub fn gilrs_event_system(mut gilrs: NonSendMut, mut events: EventWriter< match gilrs_event.event { EventType::Connected => { + let pad = gilrs.gamepad(gilrs_event.id); + let info = GamepadInfo { + name: pad.name().into(), + }; + events.send(GamepadEventRaw::new( convert_gamepad_id(gilrs_event.id), - GamepadEventType::Connected, + GamepadEventType::Connected(info), )); } EventType::Disconnected => { diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 3d96932af8c8c..d9d0a1d362a35 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,7 +1,7 @@ use crate::{Axis, Input}; use bevy_ecs::event::{EventReader, EventWriter}; use bevy_ecs::system::{Res, ResMut, Resource}; -use bevy_utils::{tracing::info, HashMap, HashSet}; +use bevy_utils::{tracing::info, HashMap}; use thiserror::Error; /// Errors that occur when setting axis settings for gamepad input. @@ -78,6 +78,13 @@ impl Gamepad { } } +/// Metadata associated with a `Gamepad`. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct GamepadInfo { + pub name: String, +} + /// A collection of connected [`Gamepad`]s. /// /// ## Usage @@ -92,23 +99,27 @@ impl Gamepad { #[derive(Resource, Default, Debug)] pub struct Gamepads { /// The collection of the connected [`Gamepad`]s. - gamepads: HashSet, + gamepads: HashMap, } impl Gamepads { /// Returns `true` if the `gamepad` is connected. pub fn contains(&self, gamepad: Gamepad) -> bool { - self.gamepads.contains(&gamepad) + self.gamepads.contains_key(&gamepad) } /// Returns an iterator over registered [`Gamepad`]s in an arbitrary order. pub fn iter(&self) -> impl Iterator + '_ { - self.gamepads.iter().copied() + self.gamepads.keys().copied() + } + + pub fn name(&self, gamepad: Gamepad) -> Option<&str> { + self.gamepads.get(&gamepad).map(|g| g.name.as_str()) } /// Registers the `gamepad`, marking it as connected. - fn register(&mut self, gamepad: Gamepad) { - self.gamepads.insert(gamepad); + fn register(&mut self, gamepad: Gamepad, info: GamepadInfo) { + self.gamepads.insert(gamepad, info); } /// Deregisters the `gamepad`, marking it as disconnected. @@ -118,11 +129,11 @@ impl Gamepads { } /// The data contained in a [`GamepadEvent`] or [`GamepadEventRaw`]. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub enum GamepadEventType { /// A [`Gamepad`] has been connected. - Connected, + Connected(GamepadInfo), /// A [`Gamepad`] has been disconnected. Disconnected, @@ -151,7 +162,7 @@ pub enum GamepadEventType { /// [`Axis`], and [`Axis`] resources won't be updated correctly. /// /// An example for gamepad input mocking can be seen in the documentation of the [`GamepadEventRaw`]. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadEvent { /// The gamepad this event corresponds to. @@ -191,7 +202,7 @@ impl GamepadEvent { /// ``` /// # use bevy_input::prelude::*; /// # use bevy_input::InputPlugin; -/// # use bevy_input::gamepad::GamepadEventRaw; +/// # use bevy_input::gamepad::{GamepadEventRaw, GamepadInfo}; /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] @@ -223,7 +234,8 @@ impl GamepadEvent { /// /// // Send the gamepad connected event to mark our gamepad as connected. /// // This updates the `Gamepads` resource accordingly. -/// app.world.send_event(GamepadEventRaw::new(gamepad, GamepadEventType::Connected)); +/// let info = GamepadInfo { name: "Mock Gamepad".into() }; +/// app.world.send_event(GamepadEventRaw::new(gamepad, GamepadEventType::Connected(info))); /// /// // Send the gamepad input event to mark the `South` gamepad button as pressed. /// // This updates the `Input` resource accordingly. @@ -254,7 +266,7 @@ impl GamepadEvent { /// # /// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press); /// ``` -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct GamepadEventRaw { /// The gamepad this event corresponds to. @@ -1062,11 +1074,12 @@ pub fn gamepad_connection_system( mut gamepad_event: EventReader, ) { for event in gamepad_event.iter() { - match event.event_type { - GamepadEventType::Connected => { - gamepads.register(event.gamepad); + match &event.event_type { + GamepadEventType::Connected(info) => { + gamepads.register(event.gamepad, info.clone()); info!("{:?} Connected", event.gamepad); } + GamepadEventType::Disconnected => { gamepads.deregister(event.gamepad); info!("{:?} Disconnected", event.gamepad); @@ -1096,9 +1109,9 @@ pub fn gamepad_event_system( ) { button_input.clear(); for event in raw_events.iter() { - match event.event_type { - GamepadEventType::Connected => { - events.send(GamepadEvent::new(event.gamepad, event.event_type)); + match &event.event_type { + GamepadEventType::Connected(_) => { + events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); for button_type in &ALL_BUTTON_TYPES { let gamepad_button = GamepadButton::new(event.gamepad, *button_type); button_input.reset(gamepad_button); @@ -1109,7 +1122,7 @@ pub fn gamepad_event_system( } } GamepadEventType::Disconnected => { - events.send(GamepadEvent::new(event.gamepad, event.event_type)); + events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); for button_type in &ALL_BUTTON_TYPES { let gamepad_button = GamepadButton::new(event.gamepad, *button_type); button_input.reset(gamepad_button); @@ -1120,37 +1133,37 @@ pub fn gamepad_event_system( } } GamepadEventType::AxisChanged(axis_type, value) => { - let gamepad_axis = GamepadAxis::new(event.gamepad, axis_type); + let gamepad_axis = GamepadAxis::new(event.gamepad, *axis_type); if let Some(filtered_value) = settings .get_axis_settings(gamepad_axis) - .filter(value, axis.get(gamepad_axis)) + .filter(*value, axis.get(gamepad_axis)) { axis.set(gamepad_axis, filtered_value); events.send(GamepadEvent::new( event.gamepad, - GamepadEventType::AxisChanged(axis_type, filtered_value), + GamepadEventType::AxisChanged(*axis_type, filtered_value), )); } } GamepadEventType::ButtonChanged(button_type, value) => { - let gamepad_button = GamepadButton::new(event.gamepad, button_type); + let gamepad_button = GamepadButton::new(event.gamepad, *button_type); if let Some(filtered_value) = settings .get_button_axis_settings(gamepad_button) - .filter(value, button_axis.get(gamepad_button)) + .filter(*value, button_axis.get(gamepad_button)) { button_axis.set(gamepad_button, filtered_value); events.send(GamepadEvent::new( event.gamepad, - GamepadEventType::ButtonChanged(button_type, filtered_value), + GamepadEventType::ButtonChanged(*button_type, filtered_value), )); } let button_property = settings.get_button_settings(gamepad_button); if button_input.pressed(gamepad_button) { - if button_property.is_released(value) { + if button_property.is_released(*value) { button_input.release(gamepad_button); } - } else if button_property.is_pressed(value) { + } else if button_property.is_pressed(*value) { button_input.press(gamepad_button); } } diff --git a/examples/input/gamepad_input_events.rs b/examples/input/gamepad_input_events.rs index 9bc020a22cde1..3d33a0e32b138 100644 --- a/examples/input/gamepad_input_events.rs +++ b/examples/input/gamepad_input_events.rs @@ -15,7 +15,7 @@ fn main() { fn gamepad_events(mut gamepad_event: EventReader) { for event in gamepad_event.iter() { match event.event_type { - GamepadEventType::Connected => { + GamepadEventType::Connected(_) => { info!("{:?} Connected", event.gamepad); } GamepadEventType::Disconnected => { diff --git a/examples/tools/gamepad_viewer.rs b/examples/tools/gamepad_viewer.rs index 671fb382229c2..dba082b8b5e9c 100644 --- a/examples/tools/gamepad_viewer.rs +++ b/examples/tools/gamepad_viewer.rs @@ -437,7 +437,7 @@ fn setup_connected(mut commands: Commands, font: Res) { commands.spawn(( TextBundle::from_sections([ TextSection { - value: "Connected Gamepads\n".to_string(), + value: "Connected Gamepads:\n".to_string(), style: style.clone(), }, TextSection { @@ -521,7 +521,7 @@ fn update_connected( let formatted = gamepads .iter() - .map(|g| format!("{:?}", g)) + .map(|g| format!("- {}", gamepads.name(g).unwrap())) .collect::>() .join("\n");