diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 4ea9d2bf78790..a0ed0e4e7659e 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -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 { @@ -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( diff --git a/crates/bevy_input/src/axis.rs b/crates/bevy_input/src/axis.rs index df16c0babf76c..f2e97777cb45e 100644 --- a/crates/bevy_input/src/axis.rs +++ b/crates/bevy_input/src/axis.rs @@ -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 { /// The position data of the input devices. axis_data: HashMap, @@ -70,6 +74,16 @@ where pub fn remove(&mut self, input_device: T) -> Option { self.axis_data.remove(&input_device) } + + /// Returns an iterator over all axes. + pub fn all_axes(&self) -> impl Iterator { + self.axis_data.keys() + } + + /// Returns an iterator over all axes and their values. + pub fn all_axes_and_values(&self) -> impl Iterator { + self.axis_data.iter().map(|(axis, value)| (axis, *value)) + } } #[cfg(test)] diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 152efe74c0ea7..1e508a1e8f67d 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -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, @@ -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() { @@ -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 { + 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 { + self.info.product_id + } + /// Returns the analog data of the provided [`GamepadAxis`] or [`GamepadButton`]. /// /// This will be clamped between [[`Axis::MIN`],[`Axis::MAX`]]. @@ -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 { + 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 { + 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 { + self.digital.get_just_released() + } + + /// Returns an iterator over all analog [axes]. + /// + /// [axes]: GamepadInput + pub fn get_analog_axes(&self) -> impl Iterator { + 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))] @@ -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, + + /// The USB product ID as assigned by the [vendor], if available. + /// + /// [vendor]: Self::vendor_id + pub product_id: Option, } /// Represents gamepad input types that are mapped in the range [0.0, 1.0]. @@ -665,6 +717,7 @@ impl GamepadAxis { /// Encapsulation over [`GamepadAxis`] and [`GamepadButton`] // This is done so Gamepad can share a single Axis 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), @@ -1988,6 +2041,8 @@ mod tests { gamepad, Connected(GamepadInfo { name: String::from("Gamepad test"), + vendor_id: None, + product_id: None, }), )); gamepad diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index ddcfa5bf17e89..f78b264977f5c 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -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"))] @@ -134,6 +137,7 @@ impl Plugin for InputPlugin { .register_type::() .register_type::() .register_type::() + .register_type::() .register_type::() .register_type::() .register_type::() @@ -141,6 +145,9 @@ impl Plugin for InputPlugin { .register_type::() .register_type::() .register_type::() + .register_type::() + .register_type::() + .register_type::() .register_type::() .register_type::(); }