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

[Merged by Bors] - feat: add GamepadInfo, expose gamepad names #6342

Closed
wants to merge 2 commits into from
Closed
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
12 changes: 9 additions & 3 deletions crates/bevy_gilrs/src/gilrs_system.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
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<Gilrs>, mut events: EventWriter<GamepadEventRaw>) {
for (id, _) in gilrs.gamepads() {
for (id, gamepad) in gilrs.gamepads() {
let info = GamepadInfo::new(gamepad.name());

events.send(GamepadEventRaw::new(
convert_gamepad_id(id),
GamepadEventType::Connected,
GamepadEventType::Connected(info),
));
}
}
Expand All @@ -22,9 +25,12 @@ pub fn gilrs_event_system(mut gilrs: NonSendMut<Gilrs>, mut events: EventWriter<

match gilrs_event.event {
EventType::Connected => {
let pad = gilrs.gamepad(gilrs_event.id);
let info = GamepadInfo::new(pad.name());

events.send(GamepadEventRaw::new(
convert_gamepad_id(gilrs_event.id),
GamepadEventType::Connected,
GamepadEventType::Connected(info),
));
}
EventType::Disconnected => {
Expand Down
79 changes: 52 additions & 27 deletions crates/bevy_input/src/gamepad.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -78,6 +78,25 @@ impl Gamepad {
}
}

/// Metadata associated with a `Gamepad`.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct GamepadInfo {
name: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this isn't high risk; we can just make the field pub and simplify the API dramatically.

}

impl GamepadInfo {
/// Creates a new `GamepadInfo` with the specified name.
pub fn new(name: impl Into<String>) -> GamepadInfo {
GamepadInfo { name: name.into() }
}

/// Returns the name of the gamepad.
pub fn name(&self) -> &str {
&self.name
}
}

/// A collection of connected [`Gamepad`]s.
///
/// ## Usage
Expand All @@ -92,23 +111,27 @@ impl Gamepad {
#[derive(Resource, Default, Debug)]
pub struct Gamepads {
/// The collection of the connected [`Gamepad`]s.
gamepads: HashSet<Gamepad>,
gamepads: HashMap<Gamepad, GamepadInfo>,
}

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<Item = Gamepad> + '_ {
self.gamepads.iter().copied()
self.gamepads.keys().copied()
}

pub fn name(&self, gamepad: Gamepad) -> Option<&str> {
self.gamepads.get(&gamepad).map(|g| g.name())
}

/// 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.
Expand All @@ -118,11 +141,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,

Expand Down Expand Up @@ -151,7 +174,7 @@ pub enum GamepadEventType {
/// [`Axis<GamepadAxis>`], and [`Axis<GamepadButton>`] 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.
Expand Down Expand Up @@ -191,7 +214,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)]
Expand Down Expand Up @@ -223,7 +246,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::new("Mock Gamepad");
/// 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<GamepadButton>` resource accordingly.
Expand Down Expand Up @@ -254,7 +278,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.
Expand Down Expand Up @@ -1062,11 +1086,12 @@ pub fn gamepad_connection_system(
mut gamepad_event: EventReader<GamepadEvent>,
) {
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);
Expand Down Expand Up @@ -1096,9 +1121,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);
Expand All @@ -1109,7 +1134,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);
Expand All @@ -1120,37 +1145,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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/input/gamepad_input_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() {
fn gamepad_events(mut gamepad_event: EventReader<GamepadEvent>) {
for event in gamepad_event.iter() {
match event.event_type {
GamepadEventType::Connected => {
GamepadEventType::Connected(_) => {
info!("{:?} Connected", event.gamepad);
}
GamepadEventType::Disconnected => {
Expand Down
4 changes: 2 additions & 2 deletions examples/tools/gamepad_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ fn setup_connected(mut commands: Commands, font: Res<FontHandle>) {
commands.spawn((
TextBundle::from_sections([
TextSection {
value: "Connected Gamepads\n".to_string(),
value: "Connected Gamepads:\n".to_string(),
style: style.clone(),
},
TextSection {
Expand Down Expand Up @@ -521,7 +521,7 @@ fn update_connected(

let formatted = gamepads
.iter()
.map(|g| format!("{:?}", g))
.map(|g| format!("- {}", gamepads.name(g).unwrap()))
.collect::<Vec<_>>()
.join("\n");

Expand Down