-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
475 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "bevy_gilrs" | ||
version = "0.1.0" | ||
edition = "2018" | ||
authors = ["Bevy Contributors <[email protected]>", "Carter Anderson <[email protected]>"] | ||
description = "Gamepad system made using Gilrs for Bevy Engine" | ||
homepage = "https://bevyengine.org" | ||
repository = "https://github.com/bevyengine/bevy" | ||
license = "MIT" | ||
keywords = ["bevy"] | ||
|
||
[dependencies] | ||
# bevy | ||
bevy_app = { path = "../bevy_app", version = "0.1" } | ||
bevy_ecs = { path = "../bevy_ecs", version = "0.1" } | ||
bevy_input = { path = "../bevy_input", version = "0.1" } | ||
|
||
# other | ||
gilrs = "0.7.4" | ||
log = { version = "0.4", features = ["release_max_level_info"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use bevy_input::gamepad::{Gamepad, GamepadAxisType, GamepadButtonType}; | ||
|
||
pub fn convert_gamepad_id(gamepad_id: gilrs::GamepadId) -> Gamepad { | ||
Gamepad(gamepad_id.into()) | ||
} | ||
|
||
pub fn convert_button(button: gilrs::Button) -> Option<GamepadButtonType> { | ||
match button { | ||
gilrs::Button::South => Some(GamepadButtonType::South), | ||
gilrs::Button::East => Some(GamepadButtonType::East), | ||
gilrs::Button::North => Some(GamepadButtonType::North), | ||
gilrs::Button::West => Some(GamepadButtonType::West), | ||
gilrs::Button::C => Some(GamepadButtonType::C), | ||
gilrs::Button::Z => Some(GamepadButtonType::Z), | ||
gilrs::Button::LeftTrigger => Some(GamepadButtonType::LeftTrigger), | ||
gilrs::Button::LeftTrigger2 => Some(GamepadButtonType::LeftTrigger2), | ||
gilrs::Button::RightTrigger => Some(GamepadButtonType::RightTrigger), | ||
gilrs::Button::RightTrigger2 => Some(GamepadButtonType::RightTrigger2), | ||
gilrs::Button::Select => Some(GamepadButtonType::Select), | ||
gilrs::Button::Start => Some(GamepadButtonType::Start), | ||
gilrs::Button::Mode => Some(GamepadButtonType::Mode), | ||
gilrs::Button::LeftThumb => Some(GamepadButtonType::LeftThumb), | ||
gilrs::Button::RightThumb => Some(GamepadButtonType::RightThumb), | ||
gilrs::Button::DPadUp => Some(GamepadButtonType::DPadUp), | ||
gilrs::Button::DPadDown => Some(GamepadButtonType::DPadDown), | ||
gilrs::Button::DPadLeft => Some(GamepadButtonType::DPadLeft), | ||
gilrs::Button::DPadRight => Some(GamepadButtonType::DPadRight), | ||
gilrs::Button::Unknown => None, | ||
} | ||
} | ||
|
||
pub fn convert_axis(axis: gilrs::Axis) -> Option<GamepadAxisType> { | ||
match axis { | ||
gilrs::Axis::LeftStickX => Some(GamepadAxisType::LeftStickX), | ||
gilrs::Axis::LeftStickY => Some(GamepadAxisType::LeftStickY), | ||
gilrs::Axis::LeftZ => Some(GamepadAxisType::LeftZ), | ||
gilrs::Axis::RightStickX => Some(GamepadAxisType::RightStickX), | ||
gilrs::Axis::RightStickY => Some(GamepadAxisType::RightStickY), | ||
gilrs::Axis::RightZ => Some(GamepadAxisType::RightZ), | ||
gilrs::Axis::DPadX => Some(GamepadAxisType::DPadX), | ||
gilrs::Axis::DPadY => Some(GamepadAxisType::DPadY), | ||
gilrs::Axis::Unknown => None, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; | ||
use bevy_app::Events; | ||
use bevy_ecs::{Res, ResMut}; | ||
use bevy_input::prelude::*; | ||
use gilrs::{Button, EventType, Gilrs}; | ||
use std::sync::{Arc, Mutex}; | ||
|
||
// TODO: remove this if/when bevy_ecs supports thread local resources | ||
struct GilrsSendWrapper(Gilrs); | ||
|
||
unsafe impl Send for GilrsSendWrapper {} | ||
|
||
pub struct GilrsArcMutexWrapper(Arc<Mutex<GilrsSendWrapper>>); | ||
|
||
impl GilrsArcMutexWrapper { | ||
pub fn new(gilrs: Gilrs) -> GilrsArcMutexWrapper { | ||
GilrsArcMutexWrapper(Arc::new(Mutex::new(GilrsSendWrapper(gilrs)))) | ||
} | ||
} | ||
|
||
pub fn gilrs_startup_system( | ||
gilrs: Res<GilrsArcMutexWrapper>, | ||
mut gamepad_event: ResMut<Events<GamepadEvent>>, | ||
mut inputs: ResMut<Input<GamepadButton>>, | ||
mut axes: ResMut<Axis<GamepadAxis>>, | ||
) { | ||
gamepad_event.update(); | ||
inputs.update(); | ||
let gilrs = &gilrs.0.lock().unwrap().0; | ||
for (gilrs_id, gilrs_gamepad) in gilrs.gamepads() { | ||
connect_gamepad( | ||
gilrs_gamepad, | ||
convert_gamepad_id(gilrs_id), | ||
&mut gamepad_event, | ||
&mut inputs, | ||
&mut axes, | ||
); | ||
} | ||
} | ||
|
||
pub fn gilrs_update_system( | ||
gilrs: Res<GilrsArcMutexWrapper>, | ||
mut gamepad_event: ResMut<Events<GamepadEvent>>, | ||
mut inputs: ResMut<Input<GamepadButton>>, | ||
mut axes: ResMut<Axis<GamepadAxis>>, | ||
) { | ||
gamepad_event.update(); | ||
inputs.update(); | ||
let gilrs = &mut gilrs.0.lock().unwrap().0; | ||
while let Some(gilrs_event) = gilrs.next_event() { | ||
match gilrs_event.event { | ||
EventType::Connected => { | ||
connect_gamepad( | ||
gilrs.gamepad(gilrs_event.id), | ||
convert_gamepad_id(gilrs_event.id), | ||
&mut gamepad_event, | ||
&mut inputs, | ||
&mut axes, | ||
); | ||
} | ||
EventType::Disconnected => { | ||
disconnect_gamepad( | ||
convert_gamepad_id(gilrs_event.id), | ||
&mut gamepad_event, | ||
&mut inputs, | ||
&mut axes, | ||
); | ||
} | ||
EventType::ButtonPressed(gilrs_button, _) => { | ||
if let Some(button_type) = convert_button(gilrs_button) { | ||
inputs.press(GamepadButton( | ||
convert_gamepad_id(gilrs_event.id), | ||
button_type, | ||
)); | ||
} | ||
} | ||
EventType::ButtonReleased(gilrs_button, _) => { | ||
if let Some(button_type) = convert_button(gilrs_button) { | ||
inputs.release(GamepadButton( | ||
convert_gamepad_id(gilrs_event.id), | ||
button_type, | ||
)); | ||
} | ||
} | ||
EventType::AxisChanged(gilrs_axis, value, _) => { | ||
if let Some(axis_type) = convert_axis(gilrs_axis) { | ||
axes.set( | ||
GamepadAxis(convert_gamepad_id(gilrs_event.id), axis_type), | ||
value, | ||
); | ||
} | ||
} | ||
_ => (), | ||
}; | ||
} | ||
gilrs.inc(); | ||
} | ||
|
||
const ALL_GILRS_BUTTONS: [Button; 19] = [ | ||
Button::South, | ||
Button::East, | ||
Button::North, | ||
Button::West, | ||
Button::C, | ||
Button::Z, | ||
Button::LeftTrigger, | ||
Button::LeftTrigger2, | ||
Button::RightTrigger, | ||
Button::RightTrigger2, | ||
Button::Select, | ||
Button::Start, | ||
Button::Mode, | ||
Button::LeftThumb, | ||
Button::RightThumb, | ||
Button::DPadUp, | ||
Button::DPadDown, | ||
Button::DPadLeft, | ||
Button::DPadRight, | ||
]; | ||
|
||
const ALL_GILRS_AXES: [gilrs::Axis; 8] = [ | ||
gilrs::Axis::LeftStickX, | ||
gilrs::Axis::LeftStickY, | ||
gilrs::Axis::LeftZ, | ||
gilrs::Axis::RightStickX, | ||
gilrs::Axis::RightStickY, | ||
gilrs::Axis::RightZ, | ||
gilrs::Axis::DPadX, | ||
gilrs::Axis::DPadY, | ||
]; | ||
|
||
fn connect_gamepad( | ||
gilrs_gamepad: gilrs::Gamepad, | ||
gamepad: Gamepad, | ||
events: &mut Events<GamepadEvent>, | ||
inputs: &mut Input<GamepadButton>, | ||
axes: &mut Axis<GamepadAxis>, | ||
) { | ||
for gilrs_button in ALL_GILRS_BUTTONS.iter() { | ||
if let Some(button_type) = convert_button(*gilrs_button) { | ||
let gamepad_button = GamepadButton(gamepad, button_type); | ||
inputs.reset(gamepad_button); | ||
if gilrs_gamepad.is_pressed(*gilrs_button) { | ||
inputs.press(gamepad_button); | ||
} | ||
} | ||
} | ||
for gilrs_axis in ALL_GILRS_AXES.iter() { | ||
if let Some(axis_type) = convert_axis(*gilrs_axis) { | ||
let gamepad_axis = GamepadAxis(gamepad, axis_type); | ||
axes.set(gamepad_axis, gilrs_gamepad.value(*gilrs_axis)); | ||
} | ||
} | ||
events.send(GamepadEvent(gamepad, GamepadEventType::Connected)); | ||
} | ||
|
||
fn disconnect_gamepad( | ||
gamepad: Gamepad, | ||
events: &mut Events<GamepadEvent>, | ||
inputs: &mut Input<GamepadButton>, | ||
axes: &mut Axis<GamepadAxis>, | ||
) { | ||
for gilrs_button in ALL_GILRS_BUTTONS.iter() { | ||
if let Some(button_type) = convert_button(*gilrs_button) { | ||
let gamepad_button = GamepadButton(gamepad, button_type); | ||
inputs.reset(gamepad_button); | ||
} | ||
} | ||
for gilrs_axis in ALL_GILRS_AXES.iter() { | ||
if let Some(axis_type) = convert_axis(*gilrs_axis) { | ||
let gamepad_axis = GamepadAxis(gamepad, axis_type); | ||
axes.remove(&gamepad_axis); | ||
} | ||
} | ||
events.send(GamepadEvent(gamepad, GamepadEventType::Disconnected)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
mod converter; | ||
mod gilrs_system; | ||
|
||
use bevy_app::prelude::*; | ||
use bevy_ecs::IntoQuerySystem; | ||
use gilrs_system::{gilrs_startup_system, gilrs_update_system, GilrsArcMutexWrapper}; | ||
|
||
#[derive(Default)] | ||
pub struct GilrsPlugin; | ||
|
||
impl Plugin for GilrsPlugin { | ||
fn build(&self, app: &mut AppBuilder) { | ||
match gilrs::Gilrs::new() { | ||
Ok(gilrs) => { | ||
app.add_resource(GilrsArcMutexWrapper::new(gilrs)) | ||
.add_startup_system(gilrs_startup_system.system()) | ||
.add_system_to_stage(stage::EVENT_UPDATE, gilrs_update_system.system()); | ||
} | ||
Err(err) => log::error!("Failed to start Gilrs. {}", err), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use std::{collections::HashMap, hash::Hash}; | ||
|
||
pub struct Axis<T> { | ||
axis_data: HashMap<T, f32>, | ||
} | ||
|
||
impl<T> Default for Axis<T> | ||
where | ||
T: Copy + Eq + Hash, | ||
{ | ||
fn default() -> Self { | ||
Axis { | ||
axis_data: HashMap::new(), | ||
} | ||
} | ||
} | ||
|
||
impl<T> Axis<T> | ||
where | ||
T: Copy + Eq + Hash, | ||
{ | ||
pub fn set(&mut self, axis: T, value: f32) -> Option<f32> { | ||
self.axis_data.insert(axis, value) | ||
} | ||
|
||
pub fn get(&self, axis: &T) -> Option<f32> { | ||
self.axis_data.get(axis).copied() | ||
} | ||
|
||
pub fn remove(&mut self, axis: &T) -> Option<f32> { | ||
self.axis_data.remove(axis) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub struct Gamepad(pub usize); | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq)] | ||
pub enum GamepadEventType { | ||
Connected, | ||
Disconnected, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq)] | ||
pub struct GamepadEvent(pub Gamepad, pub GamepadEventType); | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub enum GamepadButtonType { | ||
South, | ||
East, | ||
North, | ||
West, | ||
C, | ||
Z, | ||
LeftTrigger, | ||
LeftTrigger2, | ||
RightTrigger, | ||
RightTrigger2, | ||
Select, | ||
Start, | ||
Mode, | ||
LeftThumb, | ||
RightThumb, | ||
DPadUp, | ||
DPadDown, | ||
DPadLeft, | ||
DPadRight, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub struct GamepadButton(pub Gamepad, pub GamepadButtonType); | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub enum GamepadAxisType { | ||
LeftStickX, | ||
LeftStickY, | ||
LeftZ, | ||
RightStickX, | ||
RightStickY, | ||
RightZ, | ||
DPadX, | ||
DPadY, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
pub struct GamepadAxis(pub Gamepad, pub GamepadAxisType); |
Oops, something went wrong.