Skip to content

Commit

Permalink
Gamepad events refactor (bevyengine#6965)
Browse files Browse the repository at this point in the history
# Objective 

- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.

## Solution

- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`. 
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.

Gamepad events are now handled in their own systems and have their own types. 

This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.

We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters. 

We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.

## Migration Guide

- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
  • Loading branch information
DevinLeamy authored and james7132 committed Jan 21, 2023
1 parent 49e76e6 commit 32dac8a
Show file tree
Hide file tree
Showing 5 changed files with 414 additions and 395 deletions.
81 changes: 52 additions & 29 deletions crates/bevy_gilrs/src/gilrs_system.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,85 @@
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 bevy_ecs::system::{NonSend, NonSendMut, Res};
use bevy_input::gamepad::{
GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent,
GamepadSettings,
};
use bevy_input::gamepad::{GamepadEvent, GamepadInfo};
use bevy_input::prelude::{GamepadAxis, GamepadButton};
use bevy_input::Axis;
use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs};

pub fn gilrs_event_startup_system(gilrs: NonSend<Gilrs>, mut events: EventWriter<GamepadEventRaw>) {
pub fn gilrs_event_startup_system(
gilrs: NonSend<Gilrs>,
mut connection_events: EventWriter<GamepadConnectionEvent>,
) {
for (id, gamepad) in gilrs.gamepads() {
let info = GamepadInfo {
name: gamepad.name().into(),
};

events.send(GamepadEventRaw::new(
convert_gamepad_id(id),
GamepadEventType::Connected(info),
));
connection_events.send(GamepadConnectionEvent {
gamepad: convert_gamepad_id(id),
connection: GamepadConnection::Connected(info),
});
}
}

pub fn gilrs_event_system(mut gilrs: NonSendMut<Gilrs>, mut events: EventWriter<GamepadEventRaw>) {
pub fn gilrs_event_system(
mut gilrs: NonSendMut<Gilrs>,
mut events: EventWriter<GamepadEvent>,
gamepad_axis: Res<Axis<GamepadAxis>>,
gamepad_buttons: Res<Axis<GamepadButton>>,
gamepad_settings: Res<GamepadSettings>,
) {
while let Some(gilrs_event) = gilrs
.next_event()
.filter_ev(&axis_dpad_to_button, &mut gilrs)
{
gilrs.update(&gilrs_event);

let gamepad = convert_gamepad_id(gilrs_event.id);
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(info),
));
events.send(
GamepadConnectionEvent::new(gamepad, GamepadConnection::Connected(info)).into(),
);
}
EventType::Disconnected => {
events.send(GamepadEventRaw::new(
convert_gamepad_id(gilrs_event.id),
GamepadEventType::Disconnected,
));
}
EventType::ButtonChanged(gilrs_button, value, _) => {
EventType::Disconnected => events
.send(GamepadConnectionEvent::new(gamepad, GamepadConnection::Disconnected).into()),
EventType::ButtonChanged(gilrs_button, raw_value, _) => {
if let Some(button_type) = convert_button(gilrs_button) {
events.send(GamepadEventRaw::new(
convert_gamepad_id(gilrs_event.id),
GamepadEventType::ButtonChanged(button_type, value),
));
let button = GamepadButton::new(gamepad, button_type);
let old_value = gamepad_buttons.get(button);
let button_settings = gamepad_settings.get_button_axis_settings(button);

// Only send events that pass the user-defined change threshold
if let Some(filtered_value) = button_settings.filter(raw_value, old_value) {
events.send(
GamepadButtonChangedEvent::new(gamepad, button_type, filtered_value)
.into(),
);
}
}
}
EventType::AxisChanged(gilrs_axis, value, _) => {
EventType::AxisChanged(gilrs_axis, raw_value, _) => {
if let Some(axis_type) = convert_axis(gilrs_axis) {
events.send(GamepadEventRaw::new(
convert_gamepad_id(gilrs_event.id),
GamepadEventType::AxisChanged(axis_type, value),
));
let axis = GamepadAxis::new(gamepad, axis_type);
let old_value = gamepad_axis.get(axis);
let axis_settings = gamepad_settings.get_axis_settings(axis);

// Only send events that pass the user-defined change threshold
if let Some(filtered_value) = axis_settings.filter(raw_value, old_value) {
events.send(
GamepadAxisChangedEvent::new(gamepad, axis_type, filtered_value).into(),
);
}
}
}
_ => (),
Expand Down
Loading

0 comments on commit 32dac8a

Please sign in to comment.