limnus_gamepad_gilrs/
lib.rs1use gilrs::{Error, EventType, Gilrs};
6use limnus_app::prelude::{App, Plugin};
7use limnus_default_stages::First;
8use limnus_gamepad::{Axis, Button, GamepadMessage, Gamepads};
9use limnus_local_resource::prelude::LocalResource;
10use limnus_message::Messages;
11use limnus_system_params::prelude::*;
12use tracing::trace;
13
14#[derive(Debug)]
15pub enum GamepadError {
16 Error(Error),
17}
18
19impl From<Error> for GamepadError {
20 fn from(error: Error) -> Self {
21 Self::Error(error)
22 }
23}
24
25#[inline]
26const fn convert_axis(axis: &gilrs::Axis) -> Option<Axis> {
27 let converted = match axis {
28 gilrs::Axis::LeftStickX => Axis::LeftStickX,
29 gilrs::Axis::LeftStickY => Axis::LeftStickY,
30 gilrs::Axis::RightStickX => Axis::RightStickX,
31 gilrs::Axis::RightStickY => Axis::RightStickY,
32 _ => return None,
33 };
34 Some(converted)
35}
36
37#[inline]
38const fn convert_button(axis: &gilrs::Button) -> Option<Button> {
39 let converted = match axis {
40 gilrs::Button::South => Button::South,
42 gilrs::Button::East => Button::East,
43 gilrs::Button::North => Button::North,
44 gilrs::Button::West => Button::West,
45
46 gilrs::Button::LeftTrigger => Button::LeftTrigger,
48 gilrs::Button::LeftTrigger2 => Button::LeftTrigger2,
49 gilrs::Button::RightTrigger => Button::RightTrigger,
50 gilrs::Button::RightTrigger2 => Button::RightTrigger2,
51
52 gilrs::Button::Select => Button::Select,
54 gilrs::Button::Start => Button::Start,
55 gilrs::Button::Mode => Button::Mode,
56
57 gilrs::Button::LeftThumb => Button::LeftThumb,
59 gilrs::Button::RightThumb => Button::RightThumb,
60
61 gilrs::Button::DPadUp => Button::DPadUp,
63 gilrs::Button::DPadDown => Button::DPadDown,
64 gilrs::Button::DPadLeft => Button::DPadLeft,
65 gilrs::Button::DPadRight => Button::DPadRight,
66
67 _ => return None,
68 };
69 Some(converted)
70}
71
72#[derive(Debug, LocalResource)]
73pub struct GamepadGilrs {
74 #[allow(dead_code)]
75 gilrs: Gilrs,
76}
77
78impl GamepadGilrs {
79 pub fn new() -> Result<Self, GamepadError> {
80 let gilrs = Gilrs::new()?;
81
82 Ok(Self { gilrs })
83 }
84
85 pub fn debug_output(&self) {
86 for (id, gamepad) in self.gilrs.gamepads() {
87 trace!("{id}:{} is {:?}", gamepad.name(), gamepad.power_info());
88 }
89 }
90
91 pub fn tick(&mut self, gamepads: &mut Gamepads, queue: &mut Messages<GamepadMessage>) {
92 while let Some(event) = self.gilrs.next_event() {
93 trace!(event=?event, "gilrs gamepad event");
94 match event.event {
95 EventType::ButtonPressed(_, _) => {}
96 EventType::ButtonRepeated(_, _) => {}
97 EventType::ButtonReleased(_, _) => {}
98 EventType::ButtonChanged(gilrs_button, button_value, _) => {
99 if let Some(real_button) = convert_button(&gilrs_button) {
100 gamepads.set_button(event.id.into(), real_button, button_value, queue);
101 }
102 }
103 EventType::AxisChanged(gilrs_axis, axis_value, _) => {
104 if let Some(real_axis) = convert_axis(&gilrs_axis) {
105 gamepads.set_axis(event.id.into(), real_axis, axis_value, queue);
106 }
107 }
108 EventType::Connected => {
109 let gamepad = self.gilrs.gamepad(event.id);
110 gamepads.connected(event.id.into(), gamepad.name(), queue);
111 }
112 EventType::Disconnected => {
113 gamepads.disconnected(event.id.into(), queue);
114 }
115 EventType::Dropped => {}
116 EventType::ForceFeedbackEffectCompleted => {}
117 _ => {}
118 }
119 }
120 }
121}
122
123fn check_gamepads(
124 mut gilrs: LoReM<GamepadGilrs>,
125 mut gamepads: ReM<Gamepads>,
126 mut queue: MsgM<GamepadMessage>,
127) {
128 gilrs.tick(&mut gamepads, &mut queue);
129}
130
131pub struct GamepadGilrsPlugin;
132
133impl Plugin for GamepadGilrsPlugin {
134 fn build(&self, app: &mut App) {
135 app.insert_local_resource(GamepadGilrs::new().expect("Failed to initialize GamepadGilrs"));
136
137 app.add_system(First, check_gamepads);
138 }
139}