Skip to content

Commit

Permalink
Add some missing features from the gamepads-as-entities change that w…
Browse files Browse the repository at this point in the history
…ere needed to update `leafwing-input-manager`. (bevyengine#15685)

The gamepads-as-entities change caused several regressions. This patch
fixes each of them:

1. This PR introduces two new fields on `GamepadInfo`: `vendor_id`, and
`product_id`, as well as associated methods. These fields are simply
mirrored from the `gilrs` library.

2. That PR removed the methods that allowed iterating over all pressed
and released buttons, as well as the method that allowed iterating over
the axis values. (It was still technically possible to do so by using
reflection to access the private fields of `Gamepad`.)

3. The `Gamepad` component wasn't marked reflectable. This PR fixes that
problem.

These changes allowed me to forward port `leafwing-input-manager`.
  • Loading branch information
pcwalton authored Oct 8, 2024
1 parent 4bf647f commit 48e2027
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
4 changes: 4 additions & 0 deletions crates/bevy_gilrs/src/gilrs_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub fn gilrs_event_startup_system(

let info = GamepadInfo {
name: gamepad.name().into(),
vendor_id: gamepad.vendor_id(),
product_id: gamepad.product_id(),
};

events.send(GamepadConnectionEvent {
Expand Down Expand Up @@ -62,6 +64,8 @@ pub fn gilrs_event_system(

let info = GamepadInfo {
name: pad.name().into(),
vendor_id: pad.vendor_id(),
product_id: pad.product_id(),
};

events.send(
Expand Down
14 changes: 14 additions & 0 deletions crates/bevy_input/src/axis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ use bevy_ecs::system::Resource;
use bevy_utils::HashMap;
use core::hash::Hash;

#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;

/// Stores the position data of the input devices of type `T`.
///
/// The values are stored as `f32`s, using [`Axis::set`].
/// Use [`Axis::get`] to retrieve the value clamped between [`Axis::MIN`] and [`Axis::MAX`]
/// inclusive, or unclamped using [`Axis::get_unclamped`].
#[derive(Debug, Resource)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
pub struct Axis<T> {
/// The position data of the input devices.
axis_data: HashMap<T, f32>,
Expand Down Expand Up @@ -70,6 +74,16 @@ where
pub fn remove(&mut self, input_device: T) -> Option<f32> {
self.axis_data.remove(&input_device)
}

/// Returns an iterator over all axes.
pub fn all_axes(&self) -> impl Iterator<Item = &T> {
self.axis_data.keys()
}

/// Returns an iterator over all axes and their values.
pub fn all_axes_and_values(&self) -> impl Iterator<Item = (&T, f32)> {
self.axis_data.iter().map(|(axis, value)| (axis, *value))
}
}

#[cfg(test)]
Expand Down
57 changes: 56 additions & 1 deletion crates/bevy_input/src/gamepad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ pub enum ButtonSettingsError {
/// }
/// ```
#[derive(Component, Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))]
#[require(GamepadSettings)]
pub struct Gamepad {
info: GamepadInfo,
Expand All @@ -374,7 +375,7 @@ pub struct Gamepad {
}

impl Gamepad {
/// Creates a gamepad with the given metadata
/// Creates a gamepad with the given metadata.
fn new(info: GamepadInfo) -> Self {
let mut analog = Axis::default();
for button in GamepadButton::all().iter().copied() {
Expand All @@ -399,6 +400,18 @@ impl Gamepad {
self.info.name.as_str()
}

/// Returns the USB vendor ID as assigned by the USB-IF, if available.
pub fn vendor_id(&self) -> Option<u16> {
self.info.vendor_id
}

/// Returns the USB product ID as assigned by the [vendor], if available.
///
/// [vendor]: Self::vendor_id
pub fn product_id(&self) -> Option<u16> {
self.info.product_id
}

/// Returns the analog data of the provided [`GamepadAxis`] or [`GamepadButton`].
///
/// This will be clamped between [[`Axis::MIN`],[`Axis::MAX`]].
Expand Down Expand Up @@ -505,8 +518,39 @@ impl Gamepad {
.into_iter()
.all(|button_type| self.just_released(button_type))
}

/// Returns an iterator over all digital [button]s that are pressed.
///
/// [button]: GamepadButton
pub fn get_pressed(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_pressed()
}

/// Returns an iterator over all digital [button]s that were just pressed.
///
/// [button]: GamepadButton
pub fn get_just_pressed(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_just_pressed()
}

/// Returns an iterator over all digital [button]s that were just released.
///
/// [button]: GamepadButton
pub fn get_just_released(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_just_released()
}

/// Returns an iterator over all analog [axes].
///
/// [axes]: GamepadInput
pub fn get_analog_axes(&self) -> impl Iterator<Item = &GamepadInput> {
self.analog.all_axes()
}
}

// Note that we don't expose `gilrs::Gamepad::uuid` due to
// https://gitlab.com/gilrs-project/gilrs/-/issues/153.
//
/// Metadata associated with a [`Gamepad`].
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
Expand All @@ -522,6 +566,14 @@ pub struct GamepadInfo {
///
/// For example on Windows the name may be "HID-compliant game controller".
pub name: String,

/// The USB vendor ID as assigned by the USB-IF, if available.
pub vendor_id: Option<u16>,

/// The USB product ID as assigned by the [vendor], if available.
///
/// [vendor]: Self::vendor_id
pub product_id: Option<u16>,
}

/// Represents gamepad input types that are mapped in the range [0.0, 1.0].
Expand Down Expand Up @@ -665,6 +717,7 @@ impl GamepadAxis {
/// Encapsulation over [`GamepadAxis`] and [`GamepadButton`]
// This is done so Gamepad can share a single Axis<T> and simplifies the API by having only one get/get_unclamped method
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
pub enum GamepadInput {
/// A [`GamepadAxis`]
Axis(GamepadAxis),
Expand Down Expand Up @@ -1988,6 +2041,8 @@ mod tests {
gamepad,
Connected(GamepadInfo {
name: String::from("Gamepad test"),
vendor_id: None,
product_id: None,
}),
));
gamepad
Expand Down
15 changes: 11 additions & 4 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@ use mouse::{
};
use touch::{touch_screen_input_system, TouchInput, Touches};

#[cfg(feature = "bevy_reflect")]
use gamepad::Gamepad;
use gamepad::{
gamepad_connection_system, gamepad_event_processing_system, GamepadAxisChangedEvent,
GamepadButtonChangedEvent, GamepadButtonStateChangedEvent, GamepadConnection,
GamepadConnectionEvent, GamepadEvent, GamepadInfo, GamepadRumbleRequest, GamepadSettings,
RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, RawGamepadEvent,
gamepad_connection_system, gamepad_event_processing_system, GamepadAxis,
GamepadAxisChangedEvent, GamepadButton, GamepadButtonChangedEvent,
GamepadButtonStateChangedEvent, GamepadConnection, GamepadConnectionEvent, GamepadEvent,
GamepadInfo, GamepadInput, GamepadRumbleRequest, GamepadSettings, RawGamepadAxisChangedEvent,
RawGamepadButtonChangedEvent, RawGamepadEvent,
};

#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
Expand Down Expand Up @@ -134,13 +137,17 @@ impl Plugin for InputPlugin {
.register_type::<RawGamepadEvent>()
.register_type::<RawGamepadAxisChangedEvent>()
.register_type::<RawGamepadButtonChangedEvent>()
.register_type::<Gamepad>()
.register_type::<GamepadConnectionEvent>()
.register_type::<GamepadButtonChangedEvent>()
.register_type::<GamepadAxisChangedEvent>()
.register_type::<GamepadButtonStateChangedEvent>()
.register_type::<GamepadInfo>()
.register_type::<GamepadConnection>()
.register_type::<GamepadSettings>()
.register_type::<GamepadAxis>()
.register_type::<GamepadButton>()
.register_type::<GamepadInput>()
.register_type::<AccumulatedMouseMotion>()
.register_type::<AccumulatedMouseScroll>();
}
Expand Down

0 comments on commit 48e2027

Please sign in to comment.