1#[macro_use]
2extern crate log;
3
4use std::fmt;
5use std::fmt::Display;
6use std::fmt::Formatter;
7
8use std::error;
9use std::time::Duration;
10use std::time::SystemTime;
11
12mod platform;
13pub mod utils;
14
15pub const IS_Y_AXIS_REVERSED: bool = platform::IS_Y_AXIS_REVERSED;
17
18#[derive(Debug)]
20pub struct FfDevice {
21 inner: platform::FfDevice,
22}
23
24impl FfDevice {
25 pub fn set_ff_state(&mut self, strong: u16, weak: u16, min_duration: Duration) {
27 self.inner.set_ff_state(strong, weak, min_duration)
28 }
29}
30
31#[derive(Copy, Clone, PartialEq, Eq, Debug)]
33#[non_exhaustive]
34pub struct Event {
35 pub id: usize,
37 pub event: EventType,
39 pub time: SystemTime,
41}
42
43impl Event {
44 pub fn new(id: usize, event: EventType) -> Self {
46 let time = utils::time_now();
47 Event { id, event, time }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[non_exhaustive]
54pub enum EventType {
55 ButtonPressed(EvCode),
56 ButtonReleased(EvCode),
57 AxisValueChanged(i32, EvCode),
58 Connected,
59 Disconnected,
60}
61
62#[derive(Copy, Clone, Debug)]
64pub struct AxisInfo {
65 pub min: i32,
66 pub max: i32,
67 pub deadzone: Option<u32>,
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq)]
87pub enum PowerInfo {
88 Unknown,
90 Wired,
92 Discharging(u8),
94 Charging(u8),
96 Charged,
98}
99
100#[derive(Debug)]
102pub struct Gilrs {
103 inner: platform::Gilrs,
104}
105
106impl Gilrs {
107 pub fn new() -> Result<Self, Error> {
108 let inner = platform::Gilrs::new().map_err(|e| match e {
109 PlatformError::NotImplemented(inner) => Error::NotImplemented(Gilrs { inner }),
110 PlatformError::Other(e) => Error::Other(e),
111 })?;
112
113 Ok(Gilrs { inner })
114 }
115
116 pub fn next_event(&mut self) -> Option<Event> {
118 self.inner.next_event()
119 }
120
121 pub fn next_event_blocking(&mut self, timeout: Option<Duration>) -> Option<Event> {
123 self.inner.next_event_blocking(timeout)
124 }
125
126 pub fn gamepad(&self, id: usize) -> Option<&Gamepad> {
128 unsafe {
129 let gp: Option<&platform::Gamepad> = self.inner.gamepad(id);
130
131 gp.map(|gp| &*(gp as *const _ as *const Gamepad))
132 }
133 }
134
135 pub fn last_gamepad_hint(&self) -> usize {
142 self.inner.last_gamepad_hint()
143 }
144}
145
146#[derive(Debug)]
148#[repr(transparent)]
149pub struct Gamepad {
150 inner: platform::Gamepad,
151}
152
153impl Gamepad {
154 pub fn name(&self) -> &str {
156 self.inner.name()
157 }
158
159 pub fn is_connected(&self) -> bool {
161 self.inner.is_connected()
162 }
163
164 pub fn uuid(&self) -> [u8; 16] {
172 *self.inner.uuid().as_bytes()
173 }
174
175 pub fn vendor_id(&self) -> Option<u16> {
177 self.inner.vendor_id()
178 }
179
180 pub fn product_id(&self) -> Option<u16> {
182 self.inner.product_id()
183 }
184
185 pub fn power_info(&self) -> PowerInfo {
187 self.inner.power_info()
188 }
189
190 pub fn is_ff_supported(&self) -> bool {
192 self.inner.is_ff_supported()
193 }
194
195 pub fn ff_device(&self) -> Option<FfDevice> {
197 self.inner.ff_device().map(|inner| FfDevice { inner })
198 }
199
200 pub fn buttons(&self) -> &[EvCode] {
202 unsafe {
203 let bt: &[platform::EvCode] = self.inner.buttons();
204
205 &*(bt as *const _ as *const [EvCode])
206 }
207 }
208
209 pub fn axes(&self) -> &[EvCode] {
211 unsafe {
212 let ax: &[platform::EvCode] = self.inner.axes();
213
214 &*(ax as *const _ as *const [EvCode])
215 }
216 }
217
218 pub fn axis_info(&self, nec: EvCode) -> Option<&AxisInfo> {
221 self.inner.axis_info(nec.0)
222 }
223}
224
225#[cfg(target_os = "linux")]
226use std::path::Path;
227
228#[cfg(target_os = "linux")]
230pub trait LinuxGamepadExt {
231 fn devpath(&self) -> &Path;
233}
234
235#[cfg(target_os = "linux")]
236impl LinuxGamepadExt for Gamepad {
237 fn devpath(&self) -> &Path {
239 Path::new(self.inner.devpath())
240 }
241}
242
243#[cfg(feature = "serde-serialize")]
244use serde::{Deserialize, Serialize};
245
246#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
248#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
249#[repr(transparent)]
250pub struct EvCode(platform::EvCode);
251
252impl EvCode {
253 pub fn into_u32(self) -> u32 {
255 self.0.into_u32()
256 }
257}
258
259impl Display for EvCode {
260 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
261 self.0.fmt(f)
262 }
263}
264
265#[derive(Debug)]
269enum PlatformError {
270 #[allow(dead_code)]
273 NotImplemented(platform::Gilrs),
274 #[allow(dead_code)]
276 Other(Box<dyn error::Error + Send + Sync>),
277}
278
279impl Display for PlatformError {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 match *self {
282 PlatformError::NotImplemented(_) => {
283 f.write_str("Gilrs does not support current platform.")
284 }
285 PlatformError::Other(ref e) => e.fmt(f),
286 }
287 }
288}
289
290impl error::Error for PlatformError {
291 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
292 match self {
293 PlatformError::Other(e) => Some(e.as_ref()),
294 _ => None,
295 }
296 }
297}
298
299#[non_exhaustive]
301#[derive(Debug)]
302pub enum Error {
303 NotImplemented(Gilrs),
306 Other(Box<dyn error::Error + Send + Sync + 'static>),
308}
309
310impl Display for Error {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 match *self {
313 Error::NotImplemented(_) => f.write_str("Gilrs does not support current platform."),
314 Error::Other(ref e) => e.fmt(f),
315 }
316 }
317}
318
319impl error::Error for Error {
320 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
321 match self {
322 Error::Other(e) => Some(e.as_ref()),
323 _ => None,
324 }
325 }
326}
327
328pub mod native_ev_codes {
331 use super::EvCode;
332 use crate::platform::native_ev_codes as nec;
333
334 pub const AXIS_LSTICKX: EvCode = EvCode(nec::AXIS_LSTICKX);
335 pub const AXIS_LSTICKY: EvCode = EvCode(nec::AXIS_LSTICKY);
336 pub const AXIS_LEFTZ: EvCode = EvCode(nec::AXIS_LEFTZ);
337 pub const AXIS_RSTICKX: EvCode = EvCode(nec::AXIS_RSTICKX);
338 pub const AXIS_RSTICKY: EvCode = EvCode(nec::AXIS_RSTICKY);
339 pub const AXIS_RIGHTZ: EvCode = EvCode(nec::AXIS_RIGHTZ);
340 pub const AXIS_DPADX: EvCode = EvCode(nec::AXIS_DPADX);
341 pub const AXIS_DPADY: EvCode = EvCode(nec::AXIS_DPADY);
342 pub const AXIS_RT: EvCode = EvCode(nec::AXIS_RT);
343 pub const AXIS_LT: EvCode = EvCode(nec::AXIS_LT);
344 pub const AXIS_RT2: EvCode = EvCode(nec::AXIS_RT2);
345 pub const AXIS_LT2: EvCode = EvCode(nec::AXIS_LT2);
346
347 pub const BTN_SOUTH: EvCode = EvCode(nec::BTN_SOUTH);
348 pub const BTN_EAST: EvCode = EvCode(nec::BTN_EAST);
349 pub const BTN_C: EvCode = EvCode(nec::BTN_C);
350 pub const BTN_NORTH: EvCode = EvCode(nec::BTN_NORTH);
351 pub const BTN_WEST: EvCode = EvCode(nec::BTN_WEST);
352 pub const BTN_Z: EvCode = EvCode(nec::BTN_Z);
353 pub const BTN_LT: EvCode = EvCode(nec::BTN_LT);
354 pub const BTN_RT: EvCode = EvCode(nec::BTN_RT);
355 pub const BTN_LT2: EvCode = EvCode(nec::BTN_LT2);
356 pub const BTN_RT2: EvCode = EvCode(nec::BTN_RT2);
357 pub const BTN_SELECT: EvCode = EvCode(nec::BTN_SELECT);
358 pub const BTN_START: EvCode = EvCode(nec::BTN_START);
359 pub const BTN_MODE: EvCode = EvCode(nec::BTN_MODE);
360 pub const BTN_LTHUMB: EvCode = EvCode(nec::BTN_LTHUMB);
361 pub const BTN_RTHUMB: EvCode = EvCode(nec::BTN_RTHUMB);
362
363 pub const BTN_DPAD_UP: EvCode = EvCode(nec::BTN_DPAD_UP);
364 pub const BTN_DPAD_DOWN: EvCode = EvCode(nec::BTN_DPAD_DOWN);
365 pub const BTN_DPAD_LEFT: EvCode = EvCode(nec::BTN_DPAD_LEFT);
366 pub const BTN_DPAD_RIGHT: EvCode = EvCode(nec::BTN_DPAD_RIGHT);
367}