mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
Add some missing features from the gamepads-as-entities change that were needed to update leafwing-input-manager
. (#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`.
This commit is contained in:
parent
4bf647ff3b
commit
48e2027827
4 changed files with 85 additions and 5 deletions
|
@ -28,6 +28,8 @@ pub fn gilrs_event_startup_system(
|
||||||
|
|
||||||
let info = GamepadInfo {
|
let info = GamepadInfo {
|
||||||
name: gamepad.name().into(),
|
name: gamepad.name().into(),
|
||||||
|
vendor_id: gamepad.vendor_id(),
|
||||||
|
product_id: gamepad.product_id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
events.send(GamepadConnectionEvent {
|
events.send(GamepadConnectionEvent {
|
||||||
|
@ -62,6 +64,8 @@ pub fn gilrs_event_system(
|
||||||
|
|
||||||
let info = GamepadInfo {
|
let info = GamepadInfo {
|
||||||
name: pad.name().into(),
|
name: pad.name().into(),
|
||||||
|
vendor_id: pad.vendor_id(),
|
||||||
|
product_id: pad.product_id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
events.send(
|
events.send(
|
||||||
|
|
|
@ -4,12 +4,16 @@ use bevy_ecs::system::Resource;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
|
|
||||||
|
#[cfg(feature = "bevy_reflect")]
|
||||||
|
use bevy_reflect::Reflect;
|
||||||
|
|
||||||
/// Stores the position data of the input devices of type `T`.
|
/// Stores the position data of the input devices of type `T`.
|
||||||
///
|
///
|
||||||
/// The values are stored as `f32`s, using [`Axis::set`].
|
/// The values are stored as `f32`s, using [`Axis::set`].
|
||||||
/// Use [`Axis::get`] to retrieve the value clamped between [`Axis::MIN`] and [`Axis::MAX`]
|
/// Use [`Axis::get`] to retrieve the value clamped between [`Axis::MIN`] and [`Axis::MAX`]
|
||||||
/// inclusive, or unclamped using [`Axis::get_unclamped`].
|
/// inclusive, or unclamped using [`Axis::get_unclamped`].
|
||||||
#[derive(Debug, Resource)]
|
#[derive(Debug, Resource)]
|
||||||
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||||
pub struct Axis<T> {
|
pub struct Axis<T> {
|
||||||
/// The position data of the input devices.
|
/// The position data of the input devices.
|
||||||
axis_data: HashMap<T, f32>,
|
axis_data: HashMap<T, f32>,
|
||||||
|
@ -70,6 +74,16 @@ where
|
||||||
pub fn remove(&mut self, input_device: T) -> Option<f32> {
|
pub fn remove(&mut self, input_device: T) -> Option<f32> {
|
||||||
self.axis_data.remove(&input_device)
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -364,6 +364,7 @@ pub enum ButtonSettingsError {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))]
|
||||||
#[require(GamepadSettings)]
|
#[require(GamepadSettings)]
|
||||||
pub struct Gamepad {
|
pub struct Gamepad {
|
||||||
info: GamepadInfo,
|
info: GamepadInfo,
|
||||||
|
@ -374,7 +375,7 @@ pub struct Gamepad {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gamepad {
|
impl Gamepad {
|
||||||
/// Creates a gamepad with the given metadata
|
/// Creates a gamepad with the given metadata.
|
||||||
fn new(info: GamepadInfo) -> Self {
|
fn new(info: GamepadInfo) -> Self {
|
||||||
let mut analog = Axis::default();
|
let mut analog = Axis::default();
|
||||||
for button in GamepadButton::all().iter().copied() {
|
for button in GamepadButton::all().iter().copied() {
|
||||||
|
@ -399,6 +400,18 @@ impl Gamepad {
|
||||||
self.info.name.as_str()
|
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`].
|
/// Returns the analog data of the provided [`GamepadAxis`] or [`GamepadButton`].
|
||||||
///
|
///
|
||||||
/// This will be clamped between [[`Axis::MIN`],[`Axis::MAX`]].
|
/// This will be clamped between [[`Axis::MIN`],[`Axis::MAX`]].
|
||||||
|
@ -505,8 +518,39 @@ impl Gamepad {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.all(|button_type| self.just_released(button_type))
|
.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`].
|
/// Metadata associated with a [`Gamepad`].
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
#[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".
|
/// For example on Windows the name may be "HID-compliant game controller".
|
||||||
pub name: String,
|
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].
|
/// 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`]
|
/// 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
|
// 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)]
|
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
||||||
pub enum GamepadInput {
|
pub enum GamepadInput {
|
||||||
/// A [`GamepadAxis`]
|
/// A [`GamepadAxis`]
|
||||||
Axis(GamepadAxis),
|
Axis(GamepadAxis),
|
||||||
|
@ -1988,6 +2041,8 @@ mod tests {
|
||||||
gamepad,
|
gamepad,
|
||||||
Connected(GamepadInfo {
|
Connected(GamepadInfo {
|
||||||
name: String::from("Gamepad test"),
|
name: String::from("Gamepad test"),
|
||||||
|
vendor_id: None,
|
||||||
|
product_id: None,
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
gamepad
|
gamepad
|
||||||
|
|
|
@ -51,11 +51,14 @@ use mouse::{
|
||||||
};
|
};
|
||||||
use touch::{touch_screen_input_system, TouchInput, Touches};
|
use touch::{touch_screen_input_system, TouchInput, Touches};
|
||||||
|
|
||||||
|
#[cfg(feature = "bevy_reflect")]
|
||||||
|
use gamepad::Gamepad;
|
||||||
use gamepad::{
|
use gamepad::{
|
||||||
gamepad_connection_system, gamepad_event_processing_system, GamepadAxisChangedEvent,
|
gamepad_connection_system, gamepad_event_processing_system, GamepadAxis,
|
||||||
GamepadButtonChangedEvent, GamepadButtonStateChangedEvent, GamepadConnection,
|
GamepadAxisChangedEvent, GamepadButton, GamepadButtonChangedEvent,
|
||||||
GamepadConnectionEvent, GamepadEvent, GamepadInfo, GamepadRumbleRequest, GamepadSettings,
|
GamepadButtonStateChangedEvent, GamepadConnection, GamepadConnectionEvent, GamepadEvent,
|
||||||
RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, RawGamepadEvent,
|
GamepadInfo, GamepadInput, GamepadRumbleRequest, GamepadSettings, RawGamepadAxisChangedEvent,
|
||||||
|
RawGamepadButtonChangedEvent, RawGamepadEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
||||||
|
@ -134,6 +137,7 @@ impl Plugin for InputPlugin {
|
||||||
.register_type::<RawGamepadEvent>()
|
.register_type::<RawGamepadEvent>()
|
||||||
.register_type::<RawGamepadAxisChangedEvent>()
|
.register_type::<RawGamepadAxisChangedEvent>()
|
||||||
.register_type::<RawGamepadButtonChangedEvent>()
|
.register_type::<RawGamepadButtonChangedEvent>()
|
||||||
|
.register_type::<Gamepad>()
|
||||||
.register_type::<GamepadConnectionEvent>()
|
.register_type::<GamepadConnectionEvent>()
|
||||||
.register_type::<GamepadButtonChangedEvent>()
|
.register_type::<GamepadButtonChangedEvent>()
|
||||||
.register_type::<GamepadAxisChangedEvent>()
|
.register_type::<GamepadAxisChangedEvent>()
|
||||||
|
@ -141,6 +145,9 @@ impl Plugin for InputPlugin {
|
||||||
.register_type::<GamepadInfo>()
|
.register_type::<GamepadInfo>()
|
||||||
.register_type::<GamepadConnection>()
|
.register_type::<GamepadConnection>()
|
||||||
.register_type::<GamepadSettings>()
|
.register_type::<GamepadSettings>()
|
||||||
|
.register_type::<GamepadAxis>()
|
||||||
|
.register_type::<GamepadButton>()
|
||||||
|
.register_type::<GamepadInput>()
|
||||||
.register_type::<AccumulatedMouseMotion>()
|
.register_type::<AccumulatedMouseMotion>()
|
||||||
.register_type::<AccumulatedMouseScroll>();
|
.register_type::<AccumulatedMouseScroll>();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue