gilrs/gamepad.rs
1// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use crate::{
9 ev::{
10 state::{AxisData, ButtonData, GamepadState},
11 Axis, AxisOrBtn, Button, Code, Event, EventType,
12 },
13 ff::{
14 server::{self, FfMessage, Message},
15 Error as FfError,
16 },
17 mapping::{Mapping, MappingData, MappingDb},
18 utils, MappingError,
19};
20
21use gilrs_core::{
22 self, AxisInfo, Error as PlatformError, Event as RawEvent, EventType as RawEventType,
23};
24
25use uuid::Uuid;
26
27use std::cmp::Ordering;
28use std::{
29 collections::VecDeque,
30 error,
31 fmt::{self, Display},
32 sync::mpsc::{Receiver, Sender},
33 time::Duration,
34};
35
36pub use gilrs_core::PowerInfo;
37
38#[cfg(feature = "serde-serialize")]
39use serde::{Deserialize, Serialize};
40
41const DEFAULT_DEADZONE: f32 = 0.1;
42
43/// Main object responsible of managing gamepads.
44///
45/// In order to get gamepad handle, use `gamepad()`, or `connected_gamepad()`. The main difference
46/// between these two is that `gamepad()` will also return handle to gamepad that is currently
47/// disconnected. However, both functions will return `None` if gamepad with given id has never
48/// existed.
49///
50/// # Event loop
51///
52/// All interesting actions like button was pressed or new controller was connected are represented
53/// by struct [`Event`](struct.Event.html). Use `next_event()` function to retrieve event from
54/// queue.
55///
56/// ```
57/// use gilrs::{Gilrs, Event, EventType, Button};
58///
59/// let mut gilrs = Gilrs::new().unwrap();
60///
61/// // Event loop
62/// loop {
63/// while let Some(event) = gilrs.next_event() {
64/// match event {
65/// Event { id, event: EventType::ButtonPressed(Button::South, _), .. } => {
66/// println!("Player {}: jump!", id)
67/// }
68/// Event { id, event: EventType::Disconnected, .. } => {
69/// println!("We lost player {}", id)
70/// }
71/// _ => (),
72/// };
73/// }
74/// # break;
75/// }
76/// ```
77///
78/// # Cached gamepad state
79///
80/// `Gilrs` also menage cached gamepad state. Updating state is done automatically, unless it's
81/// disabled by `GilrsBuilder::set_update_state(false)`. However, if you are using custom filters,
82/// you still have to update state manually – to do this call `update()` method.
83///
84/// To access state you can use `Gamepad::state()` function. Gamepad also implement some state
85/// related functions directly, see [`Gamepad`](struct.Gamepad.html) for more.
86///
87/// ## Counter
88///
89/// `Gilrs` has additional functionality, referred here as *counter*. The idea behind it is simple,
90/// each time you end iteration of update loop, you call `Gilrs::inc()` which will increase
91/// internal counter by one. When state of one if elements changes, value of counter is saved. When
92/// checking state of one of elements you can tell exactly when this event happened. Timestamps are
93/// not good solution here because they can tell you when *system* observed event, not when you
94/// processed it. On the other hand, they are good when you want to implement key repeat or software
95/// debouncing.
96///
97/// ```
98/// use gilrs::{Gilrs, Button};
99///
100/// let mut gilrs = Gilrs::new().unwrap();
101/// let mut player_one = None;
102///
103/// loop {
104/// while let Some(ev) = gilrs.next_event() {
105/// if player_one.is_none() {
106/// player_one = Some(ev.id);
107/// }
108///
109/// // Do other things with event
110/// }
111///
112/// if let Some(id) = player_one {
113/// let gamepad = gilrs.gamepad(id);
114///
115/// if gamepad.is_pressed(Button::DPadLeft) {
116/// // go left
117/// }
118///
119/// match gamepad.button_data(Button::South) {
120/// Some(d) if d.is_pressed() && d.counter() == gilrs.counter() => {
121/// // jump only if button was observed to be pressed in this iteration
122/// }
123/// _ => ()
124/// }
125/// }
126///
127/// // Increase counter
128/// gilrs.inc();
129/// # break;
130/// }
131///
132#[derive(Debug)]
133pub struct Gilrs {
134 inner: gilrs_core::Gilrs,
135 next_id: usize,
136 tx: Sender<Message>,
137 rx: Receiver<FfMessage>,
138 counter: u64,
139 mappings: MappingDb,
140 default_filters: bool,
141 events: VecDeque<Event>,
142 axis_to_btn_pressed: f32,
143 axis_to_btn_released: f32,
144 pub(crate) update_state: bool,
145 pub(crate) gamepads_data: Vec<GamepadData>,
146}
147
148impl Gilrs {
149 /// Creates new `Gilrs` with default settings. See [`GilrsBuilder`](struct.GilrsBuilder.html)
150 /// for more details.
151 #[allow(clippy::result_large_err)]
152 pub fn new() -> Result<Self, Error> {
153 GilrsBuilder::new().build()
154 }
155
156 /// Returns next pending event. If there is no pending event, `None` is
157 /// returned. This function will not block current thread and should be safe
158 /// to call in async context. Doesn't block the thread it is run in
159 pub fn next_event(&mut self) -> Option<Event> {
160 self.next_event_inner(false, None)
161 }
162
163 /// Same as [Gilrs::next_event], but blocks the thread it is run in. Useful
164 /// for apps that aren't run inside a loop and just react to the user's input,
165 /// like GUI apps.
166 ///
167 /// ## Platform support
168 ///
169 /// This function is not supported on web and will always panic.
170 pub fn next_event_blocking(&mut self, timeout: Option<Duration>) -> Option<Event> {
171 self.next_event_inner(true, timeout)
172 }
173
174 fn next_event_inner(
175 &mut self,
176 is_blocking: bool,
177 blocking_timeout: Option<Duration>,
178 ) -> Option<Event> {
179 use crate::ev::filter::{axis_dpad_to_button, deadzone, Filter, Jitter};
180
181 let ev = if self.default_filters {
182 let jitter_filter = Jitter::new();
183 loop {
184 let ev = self
185 .next_event_priv(is_blocking, blocking_timeout)
186 .filter_ev(&axis_dpad_to_button, self)
187 .filter_ev(&jitter_filter, self)
188 .filter_ev(&deadzone, self);
189
190 // Skip all dropped events, there is no reason to return them
191 match ev {
192 Some(ev) if ev.is_dropped() => (),
193 _ => break ev,
194 }
195 }
196 } else {
197 self.next_event_priv(is_blocking, blocking_timeout)
198 };
199
200 if self.update_state {
201 if let Some(ref ev) = ev {
202 self.update(ev);
203 }
204 }
205
206 ev
207 }
208
209 /// Returns next pending event.
210 fn next_event_priv(
211 &mut self,
212 is_blocking: bool,
213 blocking_timeout: Option<Duration>,
214 ) -> Option<Event> {
215 if let Ok(msg) = self.rx.try_recv() {
216 return match msg {
217 FfMessage::EffectCompleted { event } => Some(event),
218 };
219 }
220 if let Some(ev) = self.events.pop_front() {
221 Some(ev)
222 } else {
223 let event = if is_blocking {
224 self.inner.next_event_blocking(blocking_timeout)
225 } else {
226 self.inner.next_event()
227 };
228
229 match event {
230 Some(RawEvent {
231 id,
232 event: event_type,
233 time,
234 ..
235 }) => {
236 trace!("Original event: {:?}", event);
237 let id = GamepadId(id);
238
239 let event = match event_type {
240 RawEventType::ButtonPressed(nec) => {
241 let nec = Code(nec);
242 match self.gamepad(id).axis_or_btn_name(nec) {
243 Some(AxisOrBtn::Btn(b)) => {
244 self.events.push_back(Event {
245 id,
246 time,
247 event: EventType::ButtonChanged(b, 1.0, nec),
248 });
249
250 EventType::ButtonPressed(b, nec)
251 }
252 Some(AxisOrBtn::Axis(a)) => EventType::AxisChanged(a, 1.0, nec),
253 None => {
254 self.events.push_back(Event {
255 id,
256 time,
257 event: EventType::ButtonChanged(Button::Unknown, 1.0, nec),
258 });
259
260 EventType::ButtonPressed(Button::Unknown, nec)
261 }
262 }
263 }
264 RawEventType::ButtonReleased(nec) => {
265 let nec = Code(nec);
266 match self.gamepad(id).axis_or_btn_name(nec) {
267 Some(AxisOrBtn::Btn(b)) => {
268 self.events.push_back(Event {
269 id,
270 time,
271 event: EventType::ButtonChanged(b, 0.0, nec),
272 });
273
274 EventType::ButtonReleased(b, nec)
275 }
276 Some(AxisOrBtn::Axis(a)) => EventType::AxisChanged(a, 0.0, nec),
277 None => {
278 self.events.push_back(Event {
279 id,
280 time,
281 event: EventType::ButtonChanged(Button::Unknown, 0.0, nec),
282 });
283
284 EventType::ButtonReleased(Button::Unknown, nec)
285 }
286 }
287 }
288 RawEventType::AxisValueChanged(val, nec) => {
289 // Let's trust at least our backend code
290 let axis_info = *self.gamepad(id).inner.axis_info(nec).unwrap();
291 let nec = Code(nec);
292
293 match self.gamepad(id).axis_or_btn_name(nec) {
294 Some(AxisOrBtn::Btn(b)) => {
295 let val = btn_value(&axis_info, val);
296
297 if val >= self.axis_to_btn_pressed
298 && !self.gamepad(id).state().is_pressed(nec)
299 {
300 self.events.push_back(Event {
301 id,
302 time,
303 event: EventType::ButtonChanged(b, val, nec),
304 });
305
306 EventType::ButtonPressed(b, nec)
307 } else if val <= self.axis_to_btn_released
308 && self.gamepad(id).state().is_pressed(nec)
309 {
310 self.events.push_back(Event {
311 id,
312 time,
313 event: EventType::ButtonChanged(b, val, nec),
314 });
315
316 EventType::ButtonReleased(b, nec)
317 } else {
318 EventType::ButtonChanged(b, val, nec)
319 }
320 }
321 Some(AxisOrBtn::Axis(a)) => {
322 EventType::AxisChanged(a, axis_value(&axis_info, val, a), nec)
323 }
324 None => EventType::AxisChanged(
325 Axis::Unknown,
326 axis_value(&axis_info, val, Axis::Unknown),
327 nec,
328 ),
329 }
330 }
331 RawEventType::Connected => {
332 match id.0.cmp(&self.gamepads_data.len()) {
333 Ordering::Equal => {
334 self.gamepads_data.push(GamepadData::new(
335 id,
336 self.tx.clone(),
337 self.inner.gamepad(id.0).unwrap(),
338 &self.mappings,
339 ));
340 }
341 Ordering::Less => {
342 self.gamepads_data[id.0] = GamepadData::new(
343 id,
344 self.tx.clone(),
345 self.inner.gamepad(id.0).unwrap(),
346 &self.mappings,
347 );
348 }
349 Ordering::Greater => {
350 error!(
351 "Platform implementation error: got Connected event with \
352 id {}, when expected id {}",
353 id.0,
354 self.gamepads_data.len()
355 );
356 }
357 }
358
359 EventType::Connected
360 }
361 RawEventType::Disconnected => {
362 let _ = self.tx.send(Message::Close { id: id.0 });
363
364 EventType::Disconnected
365 }
366 _ => {
367 unimplemented!()
368 }
369 };
370
371 Some(Event { id, event, time })
372 }
373 None => None,
374 }
375 }
376 }
377
378 /// Updates internal state according to `event`.
379 ///
380 /// Please note, that it's not necessary to call this function unless you modify events by using
381 /// additional filters and disabled automatic updates when creating `Gilrs`.
382 pub fn update(&mut self, event: &Event) {
383 use crate::EventType::*;
384
385 let counter = self.counter;
386
387 let data = match self.gamepads_data.get_mut(event.id.0) {
388 Some(d) => d,
389 None => return,
390 };
391
392 match event.event {
393 ButtonPressed(_, nec) => {
394 data.state.set_btn_pressed(nec, true, counter, event.time);
395 }
396 ButtonReleased(_, nec) => {
397 data.state.set_btn_pressed(nec, false, counter, event.time);
398 }
399 ButtonRepeated(_, nec) => {
400 data.state.set_btn_repeating(nec, counter, event.time);
401 }
402 ButtonChanged(_, value, nec) => {
403 data.state.set_btn_value(nec, value, counter, event.time);
404 }
405 AxisChanged(_, value, nec) => {
406 data.state
407 .update_axis(nec, AxisData::new(value, counter, event.time));
408 }
409 Disconnected | Connected | Dropped | ForceFeedbackEffectCompleted => (),
410 }
411 }
412
413 /// Increases internal counter by one. Counter data is stored with state and can be used to
414 /// determine when last event happened. You probably want to use this function in your update
415 /// loop after processing events.
416 pub fn inc(&mut self) {
417 // Counter is 62bit. See `ButtonData`.
418 if self.counter == 0x3FFF_FFFF_FFFF_FFFF {
419 self.counter = 0;
420 } else {
421 self.counter += 1;
422 }
423 }
424
425 /// Returns counter. Counter data is stored with state and can be used to determine when last
426 /// event happened.
427 pub fn counter(&self) -> u64 {
428 self.counter
429 }
430
431 /// Sets counter to 0.
432 pub fn reset_counter(&mut self) {
433 self.counter = 0;
434 }
435
436 fn finish_gamepads_creation(&mut self) {
437 let tx = self.tx.clone();
438 for id in 0..self.inner.last_gamepad_hint() {
439 let gamepad = self.inner.gamepad(id).unwrap();
440 self.gamepads_data.push(GamepadData::new(
441 GamepadId(id),
442 tx.clone(),
443 gamepad,
444 &self.mappings,
445 ))
446 }
447 }
448
449 /// Returns handle to gamepad with given ID. Unlike `connected_gamepad()`, this function will
450 /// also return handle to gamepad that is currently disconnected.
451 ///
452 /// ```
453 /// # let mut gilrs = gilrs::Gilrs::new().unwrap();
454 /// use gilrs::{Button, EventType};
455 ///
456 /// loop {
457 /// while let Some(ev) = gilrs.next_event() {
458 /// // unwrap() should never panic because we use id from event
459 /// let is_up_pressed = gilrs.gamepad(ev.id).is_pressed(Button::DPadUp);
460 ///
461 /// match ev.event {
462 /// EventType::ButtonPressed(Button::South, _) if is_up_pressed => {
463 /// // do something…
464 /// }
465 /// _ => (),
466 /// }
467 /// }
468 /// # break;
469 /// }
470 /// ```
471 pub fn gamepad(&self, id: GamepadId) -> Gamepad<'_> {
472 Gamepad {
473 inner: self.inner.gamepad(id.0).unwrap(),
474 data: &self.gamepads_data[id.0],
475 }
476 }
477
478 /// Returns a reference to connected gamepad or `None`.
479 pub fn connected_gamepad(&self, id: GamepadId) -> Option<Gamepad<'_>> {
480 // Make sure that it will not panic even with invalid GamepadId, so ConnectedGamepadIterator
481 // will always work.
482 if let Some(data) = self.gamepads_data.get(id.0) {
483 let inner = self.inner.gamepad(id.0)?;
484
485 if inner.is_connected() {
486 Some(Gamepad { inner, data })
487 } else {
488 None
489 }
490 } else {
491 None
492 }
493 }
494
495 /// Returns iterator over all connected gamepads and their ids.
496 ///
497 /// ```
498 /// # let gilrs = gilrs::Gilrs::new().unwrap();
499 /// for (id, gamepad) in gilrs.gamepads() {
500 /// assert!(gamepad.is_connected());
501 /// println!("Gamepad with id {} and name {} is connected",
502 /// id, gamepad.name());
503 /// }
504 /// ```
505 pub fn gamepads(&self) -> ConnectedGamepadsIterator<'_> {
506 ConnectedGamepadsIterator(self, 0)
507 }
508
509 /// Adds `ev` at the end of internal event queue. It can later be retrieved with `next_event()`.
510 pub fn insert_event(&mut self, ev: Event) {
511 self.events.push_back(ev);
512 }
513
514 pub(crate) fn ff_sender(&self) -> &Sender<Message> {
515 &self.tx
516 }
517
518 /// Sets gamepad's mapping and returns SDL2 representation of them. Returned mappings may not be
519 /// compatible with SDL2 - if it is important, use
520 /// [`set_mapping_strict()`](#method.set_mapping_strict).
521 ///
522 /// The `name` argument can be a string slice with custom gamepad name or `None`. If `None`,
523 /// gamepad name reported by driver will be used.
524 ///
525 /// # Errors
526 ///
527 /// This function return error if `name` contains comma, `mapping` have axis and button entry
528 /// for same element (for example `Axis::LetfTrigger` and `Button::LeftTrigger`) or gamepad does
529 /// not have any element with `EvCode` used in mapping. `Button::Unknown` and
530 /// `Axis::Unknown` are not allowd as keys to `mapping` – in this case,
531 /// `MappingError::UnknownElement` is returned.
532 ///
533 /// Error is also returned if this function is not implemented or gamepad is not connected.
534 ///
535 /// # Example
536 ///
537 /// ```
538 /// use gilrs::{Mapping, Button};
539 ///
540 /// # let mut gilrs = gilrs::Gilrs::new().unwrap();
541 /// let mut data = Mapping::new();
542 /// // …
543 ///
544 /// // or `match gilrs.set_mapping(0, &data, None) {`
545 /// match gilrs.set_mapping(0, &data, "Custom name") {
546 /// Ok(sdl) => println!("SDL2 mapping: {}", sdl),
547 /// Err(e) => println!("Failed to set mapping: {}", e),
548 /// };
549 /// ```
550 ///
551 /// See also `examples/mapping.rs`.
552 pub fn set_mapping<'b, O: Into<Option<&'b str>>>(
553 &mut self,
554 gamepad_id: usize,
555 mapping: &MappingData,
556 name: O,
557 ) -> Result<String, MappingError> {
558 if let Some(gamepad) = self.inner.gamepad(gamepad_id) {
559 if !gamepad.is_connected() {
560 return Err(MappingError::NotConnected);
561 }
562
563 let name = match name.into() {
564 Some(s) => s,
565 None => gamepad.name(),
566 };
567
568 let (mapping, s) = Mapping::from_data(
569 mapping,
570 gamepad.buttons(),
571 gamepad.axes(),
572 name,
573 Uuid::from_bytes(gamepad.uuid()),
574 )?;
575
576 // We checked if gamepad is connected, so it should never panic
577 let data = &mut self.gamepads_data[gamepad_id];
578 data.mapping = mapping;
579
580 Ok(s)
581 } else {
582 Err(MappingError::NotConnected)
583 }
584 }
585
586 /// Similar to [`set_mapping()`](#method.set_mapping) but returned string should be compatible
587 /// with SDL2.
588 ///
589 /// # Errors
590 ///
591 /// Returns `MappingError::NotSdl2Compatible` if `mapping` have an entry for `Button::{C, Z}`
592 /// or `Axis::{LeftZ, RightZ}`.
593 pub fn set_mapping_strict<'b, O: Into<Option<&'b str>>>(
594 &mut self,
595 gamepad_id: usize,
596 mapping: &MappingData,
597 name: O,
598 ) -> Result<String, MappingError> {
599 if mapping.button(Button::C).is_some()
600 || mapping.button(Button::Z).is_some()
601 || mapping.axis(Axis::LeftZ).is_some()
602 || mapping.axis(Axis::RightZ).is_some()
603 {
604 Err(MappingError::NotSdl2Compatible)
605 } else {
606 self.set_mapping(gamepad_id, mapping, name)
607 }
608 }
609
610 pub(crate) fn next_ff_id(&mut self) -> usize {
611 // TODO: reuse free ids
612 let id = self.next_id;
613 self.next_id = match self.next_id.checked_add(1) {
614 Some(x) => x,
615 None => panic!("Failed to assign ID to new effect"),
616 };
617 id
618 }
619}
620
621/// Allow to create `Gilrs ` with customized behaviour.
622pub struct GilrsBuilder {
623 mappings: MappingDb,
624 default_filters: bool,
625 axis_to_btn_pressed: f32,
626 axis_to_btn_released: f32,
627 update_state: bool,
628 env_mappings: bool,
629 included_mappings: bool,
630 force_feedback: bool,
631}
632
633impl GilrsBuilder {
634 /// Create builder with default settings. Use `build()` to create `Gilrs`.
635 pub fn new() -> Self {
636 GilrsBuilder {
637 mappings: MappingDb::new(),
638 default_filters: true,
639 axis_to_btn_pressed: 0.75,
640 axis_to_btn_released: 0.65,
641 update_state: true,
642 env_mappings: true,
643 included_mappings: true,
644 force_feedback: true,
645 }
646 }
647
648 /// If `true`, use [`axis_dpad_to_button`](ev/filter/fn.axis_dpad_to_button.html),
649 /// [`Jitter`](ev/filter/struct.Jitter.html) and [`deadzone`](ev/filter/fn.deadzone.html)
650 /// filters with default parameters. Defaults to `true`.
651 pub fn with_default_filters(mut self, default_filters: bool) -> Self {
652 self.default_filters = default_filters;
653
654 self
655 }
656
657 /// If `true`, enables force feedback support. Defaults to `true`.
658 pub fn with_force_feedback(mut self, enable_ff: bool) -> Self {
659 self.force_feedback = enable_ff;
660
661 self
662 }
663
664 /// Adds SDL mappings.
665 pub fn add_mappings(mut self, mappings: &str) -> Self {
666 self.mappings.insert(mappings);
667
668 self
669 }
670
671 /// If true, will add SDL mappings from `SDL_GAMECONTROLLERCONFIG` environment variable.
672 /// Defaults to true.
673 pub fn add_env_mappings(mut self, env_mappings: bool) -> Self {
674 self.env_mappings = env_mappings;
675
676 self
677 }
678
679 /// If true, will add SDL mappings included from
680 /// https://github.com/gabomdq/SDL_GameControllerDB. Defaults to true.
681 pub fn add_included_mappings(mut self, included_mappings: bool) -> Self {
682 self.included_mappings = included_mappings;
683
684 self
685 }
686
687 /// Sets values on which `ButtonPressed` and `ButtonReleased` events will be emitted. `build()`
688 /// will return error if `pressed ≤ released` or if one of values is outside [0.0, 1.0].
689 ///
690 /// Defaults to 0.75 for `pressed` and 0.65 for `released`.
691 pub fn set_axis_to_btn(mut self, pressed: f32, released: f32) -> Self {
692 self.axis_to_btn_pressed = pressed;
693 self.axis_to_btn_released = released;
694
695 self
696 }
697
698 /// Disable or enable automatic state updates. You should use this if you use custom filters;
699 /// in this case you have to update state manually anyway.
700 pub fn set_update_state(mut self, enabled: bool) -> Self {
701 self.update_state = enabled;
702
703 self
704 }
705
706 /// Creates `Gilrs`.
707 #[allow(clippy::result_large_err)]
708 pub fn build(mut self) -> Result<Gilrs, Error> {
709 if self.included_mappings {
710 self.mappings.add_included_mappings();
711 }
712
713 if self.env_mappings {
714 self.mappings.add_env_mappings();
715 }
716
717 debug!("Loaded {} mappings.", self.mappings.len());
718
719 if self.axis_to_btn_pressed <= self.axis_to_btn_released
720 || self.axis_to_btn_pressed < 0.0
721 || self.axis_to_btn_pressed > 1.0
722 || self.axis_to_btn_released < 0.0
723 || self.axis_to_btn_released > 1.0
724 {
725 return Err(Error::InvalidAxisToBtn);
726 }
727
728 let mut is_dummy = false;
729 let inner = match gilrs_core::Gilrs::new() {
730 Ok(g) => g,
731 Err(PlatformError::NotImplemented(g)) => {
732 is_dummy = true;
733
734 g
735 }
736 Err(PlatformError::Other(e)) => return Err(Error::Other(e)),
737 Err(_) => unimplemented!(),
738 };
739
740 let (tx, rx) = server::init(self.force_feedback);
741
742 let mut gilrs = Gilrs {
743 inner,
744 next_id: 0,
745 tx,
746 rx,
747 counter: 0,
748 mappings: self.mappings,
749 default_filters: self.default_filters,
750 events: VecDeque::new(),
751 axis_to_btn_pressed: self.axis_to_btn_pressed,
752 axis_to_btn_released: self.axis_to_btn_released,
753 update_state: self.update_state,
754 gamepads_data: Vec::new(),
755 };
756 gilrs.finish_gamepads_creation();
757
758 if is_dummy {
759 Err(Error::NotImplemented(gilrs))
760 } else {
761 Ok(gilrs)
762 }
763 }
764}
765
766impl Default for GilrsBuilder {
767 fn default() -> Self {
768 Self::new()
769 }
770}
771
772/// Iterator over all connected gamepads.
773pub struct ConnectedGamepadsIterator<'a>(&'a Gilrs, usize);
774
775impl<'a> Iterator for ConnectedGamepadsIterator<'a> {
776 type Item = (GamepadId, Gamepad<'a>);
777
778 fn next(&mut self) -> Option<(GamepadId, Gamepad<'a>)> {
779 loop {
780 if self.1 == self.0.inner.last_gamepad_hint() {
781 return None;
782 }
783
784 if let Some(gp) = self.0.connected_gamepad(GamepadId(self.1)) {
785 let idx = self.1;
786 self.1 += 1;
787 return Some((GamepadId(idx), gp));
788 }
789
790 self.1 += 1;
791 }
792 }
793}
794
795/// Represents handle to game controller.
796///
797/// Using this struct you can access cached gamepad state, information about gamepad such as name
798/// or UUID and manage force feedback effects.
799#[derive(Debug, Copy, Clone)]
800pub struct Gamepad<'a> {
801 data: &'a GamepadData,
802 inner: &'a gilrs_core::Gamepad,
803}
804
805impl Gamepad<'_> {
806 /// Returns the mapping name if it exists otherwise returns the os provided name.
807 pub fn name(&self) -> &str {
808 if let Some(map_name) = self.map_name() {
809 map_name
810 } else {
811 self.os_name()
812 }
813 }
814
815 /// if `mapping_source()` is `SdlMappings` returns the name of the mapping used by the gamepad.
816 /// Otherwise returns `None`.
817 pub fn map_name(&self) -> Option<&str> {
818 self.data.map_name()
819 }
820
821 /// Returns the name of the gamepad supplied by the OS.
822 pub fn os_name(&self) -> &str {
823 self.inner.name()
824 }
825
826 /// Returns gamepad's UUID.
827 ///
828 /// It is recommended to process with the [UUID crate](https://crates.io/crates/uuid).
829 /// Use `Uuid::from_bytes` method to create a `Uuid` from the returned bytes.
830 pub fn uuid(&self) -> [u8; 16] {
831 self.inner.uuid()
832 }
833
834 /// Returns the vendor ID, as assigned by the USB-IF, when available.
835 pub fn vendor_id(&self) -> Option<u16> {
836 self.inner.vendor_id()
837 }
838
839 /// Returns the product ID, as assigned by the vendor, when available.
840 pub fn product_id(&self) -> Option<u16> {
841 self.inner.product_id()
842 }
843
844 /// Returns cached gamepad state.
845 pub fn state(&self) -> &GamepadState {
846 &self.data.state
847 }
848
849 /// Returns true if gamepad is connected.
850 pub fn is_connected(&self) -> bool {
851 self.inner.is_connected()
852 }
853
854 /// Examines cached gamepad state to check if given button is pressed. Panics if `btn` is
855 /// `Unknown`.
856 ///
857 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
858 /// directly on `State`, because this version have to check which `Code` is mapped to element of
859 /// gamepad.
860 pub fn is_pressed(&self, btn: Button) -> bool {
861 self.data.is_pressed(btn)
862 }
863
864 /// Examines cached gamepad state to check axis's value. Panics if `axis` is `Unknown`.
865 ///
866 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
867 /// directly on `State`, because this version have to check which `Code` is mapped to element of
868 /// gamepad.
869 pub fn value(&self, axis: Axis) -> f32 {
870 self.data.value(axis)
871 }
872
873 /// Returns button state and when it changed.
874 ///
875 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
876 /// directly on `State`, because this version have to check which `Code` is mapped to element of
877 /// gamepad.
878 pub fn button_data(&self, btn: Button) -> Option<&ButtonData> {
879 self.data.button_data(btn)
880 }
881
882 /// Returns axis state and when it changed.
883 ///
884 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
885 /// directly on `State`, because this version have to check which `Code` is mapped to element of
886 /// gamepad.
887 pub fn axis_data(&self, axis: Axis) -> Option<&AxisData> {
888 self.data.axis_data(axis)
889 }
890
891 /// Returns device's power supply state. See [`PowerInfo`](enum.PowerInfo.html) for details.
892 pub fn power_info(&self) -> PowerInfo {
893 self.inner.power_info()
894 }
895
896 /// Returns source of gamepad mapping. Can be used to filter gamepads which do not provide
897 /// unified controller layout.
898 ///
899 /// ```
900 /// use gilrs::MappingSource;
901 /// # let mut gilrs = gilrs::Gilrs::new().unwrap();
902 ///
903 /// for (_, gamepad) in gilrs.gamepads().filter(
904 /// |gp| gp.1.mapping_source() != MappingSource::None)
905 /// {
906 /// println!("{} is ready to use!", gamepad.name());
907 /// }
908 /// ```
909 pub fn mapping_source(&self) -> MappingSource {
910 if self.data.mapping.is_default() {
911 // TODO: check if it's Driver or None
912 MappingSource::Driver
913 } else {
914 MappingSource::SdlMappings
915 }
916 }
917
918 /// Returns true if force feedback is supported by device.
919 pub fn is_ff_supported(&self) -> bool {
920 self.inner.is_ff_supported()
921 }
922
923 /// Change gamepad position used by force feedback effects.
924 pub fn set_listener_position<Vec3: Into<[f32; 3]>>(
925 &self,
926 position: Vec3,
927 ) -> Result<(), FfError> {
928 if !self.is_connected() {
929 Err(FfError::Disconnected(self.id()))
930 } else if !self.is_ff_supported() {
931 Err(FfError::FfNotSupported(self.id()))
932 } else {
933 self.data.tx.send(Message::SetListenerPosition {
934 id: self.data.id.0,
935 position: position.into(),
936 })?;
937 Ok(())
938 }
939 }
940
941 /// Returns `AxisOrBtn` mapped to `Code`.
942 pub fn axis_or_btn_name(&self, ec: Code) -> Option<AxisOrBtn> {
943 self.data.axis_or_btn_name(ec)
944 }
945
946 /// Returns `Code` associated with `btn`.
947 pub fn button_code(&self, btn: Button) -> Option<Code> {
948 self.data.button_code(btn)
949 }
950
951 /// Returns `Code` associated with `axis`.
952 pub fn axis_code(&self, axis: Axis) -> Option<Code> {
953 self.data.axis_code(axis)
954 }
955
956 /// Returns area in which axis events should be ignored.
957 pub fn deadzone(&self, axis: Code) -> Option<f32> {
958 self.inner.axis_info(axis.0).map(|i| {
959 let range = i.max as f32 - i.min as f32;
960
961 if range == 0.0 {
962 0.0
963 } else {
964 i.deadzone
965 .map(|d| d as f32 / range * 2.0)
966 .unwrap_or(DEFAULT_DEADZONE)
967 }
968 })
969 }
970
971 /// Returns ID of gamepad.
972 pub fn id(&self) -> GamepadId {
973 self.data.id
974 }
975
976 pub(crate) fn mapping(&self) -> &Mapping {
977 &self.data.mapping
978 }
979}
980
981#[cfg(target_os = "linux")]
982pub use gilrs_core::LinuxGamepadExt;
983#[cfg(target_os = "linux")]
984use std::path::Path;
985
986#[cfg(target_os = "linux")]
987impl LinuxGamepadExt for Gamepad<'_> {
988 /// Returns the device node of gamepad.
989 fn devpath(&self) -> &Path {
990 self.inner.devpath()
991 }
992}
993
994#[derive(Debug)]
995pub(crate) struct GamepadData {
996 state: GamepadState,
997 mapping: Mapping,
998 tx: Sender<Message>,
999 id: GamepadId,
1000 // Flags used by the deadzone filter.
1001 pub(crate) have_sent_nonzero_for_axis: [bool; 6],
1002}
1003
1004impl GamepadData {
1005 fn new(
1006 id: GamepadId,
1007 tx: Sender<Message>,
1008 gamepad: &gilrs_core::Gamepad,
1009 db: &MappingDb,
1010 ) -> Self {
1011 let uuid = Uuid::from_bytes(gamepad.uuid());
1012 let mapping = db
1013 .get(uuid)
1014 .map(
1015 |s| match Mapping::parse_sdl_mapping(s, gamepad.buttons(), gamepad.axes()) {
1016 Ok(result) => result,
1017 Err(e) => {
1018 warn!(
1019 "Unable to parse SDL mapping for UUID {uuid}\n\t{e:?}\n\tDefault \
1020 mapping will be used.",
1021 );
1022 Mapping::default(gamepad)
1023 }
1024 },
1025 )
1026 .unwrap_or_else(|| {
1027 warn!("No mapping found for UUID {uuid}\n\tDefault mapping will be used.");
1028 Mapping::default(gamepad)
1029 });
1030
1031 if gamepad.is_ff_supported() && gamepad.is_connected() {
1032 if let Some(device) = gamepad.ff_device() {
1033 let _ = tx.send(Message::Open { id: id.0, device });
1034 }
1035 }
1036
1037 GamepadData {
1038 state: GamepadState::new(),
1039 mapping,
1040 tx,
1041 id,
1042 have_sent_nonzero_for_axis: Default::default(),
1043 }
1044 }
1045
1046 /// if `mapping_source()` is `SdlMappings` returns the name of the mapping used by the gamepad.
1047 /// Otherwise returns `None`.
1048 ///
1049 /// Warning: Mappings are set after event `Connected` is processed, therefore this function will
1050 /// always return `None` before first calls to `Gilrs::next_event()`.
1051 pub fn map_name(&self) -> Option<&str> {
1052 if self.mapping.is_default() {
1053 None
1054 } else {
1055 Some(self.mapping.name())
1056 }
1057 }
1058
1059 /// Examines cached gamepad state to check if the given button is pressed. Panics if `btn` is
1060 /// `Unknown`.
1061 ///
1062 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
1063 /// directly on `State`, because this version has to check which `Code` is mapped to element of
1064 /// gamepad.
1065 pub fn is_pressed(&self, btn: Button) -> bool {
1066 assert_ne!(btn, Button::Unknown);
1067
1068 self.button_code(btn)
1069 .or_else(|| btn.to_nec())
1070 .map(|nec| self.state.is_pressed(nec))
1071 .unwrap_or(false)
1072 }
1073
1074 /// Examines cached gamepad state to check axis's value. Panics if `axis` is `Unknown`.
1075 ///
1076 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
1077 /// directly on `State`, because this version has to check which `Code` is mapped to element of
1078 /// gamepad.
1079 pub fn value(&self, axis: Axis) -> f32 {
1080 assert_ne!(axis, Axis::Unknown);
1081
1082 self.axis_code(axis)
1083 .map(|nec| self.state.value(nec))
1084 .unwrap_or(0.0)
1085 }
1086
1087 /// Returns button state and when it changed.
1088 ///
1089 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
1090 /// directly on `State`, because this version has to check which `Code` is mapped to element of
1091 /// gamepad.
1092 pub fn button_data(&self, btn: Button) -> Option<&ButtonData> {
1093 self.button_code(btn)
1094 .and_then(|nec| self.state.button_data(nec))
1095 }
1096
1097 /// Returns axis state and when it changed.
1098 ///
1099 /// If you know `Code` of the element that you want to examine, it's recommended to use methods
1100 /// directly on `State`, because this version has to check which `Code` is mapped to element of
1101 /// gamepad.
1102 pub fn axis_data(&self, axis: Axis) -> Option<&AxisData> {
1103 self.axis_code(axis)
1104 .and_then(|nec| self.state.axis_data(nec))
1105 }
1106
1107 /// Returns `AxisOrBtn` mapped to `Code`.
1108 pub fn axis_or_btn_name(&self, ec: Code) -> Option<AxisOrBtn> {
1109 self.mapping.map(&ec.0)
1110 }
1111
1112 /// Returns `Code` associated with `btn`.
1113 pub fn button_code(&self, btn: Button) -> Option<Code> {
1114 self.mapping.map_rev(&AxisOrBtn::Btn(btn)).map(Code)
1115 }
1116
1117 /// Returns `Code` associated with `axis`.
1118 pub fn axis_code(&self, axis: Axis) -> Option<Code> {
1119 self.mapping.map_rev(&AxisOrBtn::Axis(axis)).map(Code)
1120 }
1121}
1122
1123/// Source of gamepad mappings.
1124#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1125pub enum MappingSource {
1126 /// Gamepad uses SDL mappings.
1127 SdlMappings,
1128 /// Gamepad does not use any mappings but driver should provide unified controller layout.
1129 Driver,
1130 /// Gamepad does not use any mappings and most gamepad events will probably be `Button::Unknown`
1131 /// or `Axis::Unknown`
1132 None,
1133}
1134
1135/// Gamepad ID.
1136///
1137/// It's not possible to create an instance of this type directly, but you can obtain one from a Gamepad
1138/// handle or any event. ID is valid for the entire lifetime of the `Gilrs` context.
1139#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
1140#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1141pub struct GamepadId(pub(crate) usize);
1142
1143impl From<GamepadId> for usize {
1144 fn from(x: GamepadId) -> usize {
1145 x.0
1146 }
1147}
1148
1149impl Display for GamepadId {
1150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1151 self.0.fmt(f)
1152 }
1153}
1154
1155fn axis_value(info: &AxisInfo, val: i32, axis: Axis) -> f32 {
1156 let mut range = info.max as f32 - info.min as f32;
1157 let mut val = val as f32 - info.min as f32;
1158
1159 if let Some(i_range) = info.max.checked_sub(info.min) {
1160 // Only consider adjusting range & val if calculating the range doesn't cause overflow. If
1161 // the range is so large overflow occurs, adjusting values by 1.0 would be insignificant.
1162 if i_range % 2 == 1 {
1163 // Add one to range and val, so the value is centered (like 127/255) will be mapped 0.0
1164 range += 1.0;
1165 val += 1.0;
1166 }
1167 }
1168
1169 val = val / range * 2.0 - 1.0;
1170
1171 if gilrs_core::IS_Y_AXIS_REVERSED
1172 && (axis == Axis::LeftStickY || axis == Axis::RightStickY || axis == Axis::DPadY)
1173 && val != 0.0
1174 {
1175 val = -val;
1176 }
1177
1178 utils::clamp(val, -1.0, 1.0)
1179}
1180
1181fn btn_value(info: &AxisInfo, val: i32) -> f32 {
1182 let range = info.max as f32 - info.min as f32;
1183 let mut val = val as f32 - info.min as f32;
1184 val /= range;
1185
1186 utils::clamp(val, 0.0, 1.0)
1187}
1188
1189/// Error type which can be returned when creating `Gilrs`.
1190#[non_exhaustive]
1191#[derive(Debug)]
1192#[allow(clippy::large_enum_variant)]
1193pub enum Error {
1194 /// Gilrs does not support the current platform, but you can use dummy context from this error if
1195 /// gamepad input is not essential.
1196 NotImplemented(Gilrs),
1197 /// Either `pressed ≤ released` or one of values is outside [0.0, 1.0] range.
1198 InvalidAxisToBtn,
1199 /// Platform specific error.
1200 Other(Box<dyn error::Error + Send + Sync + 'static>),
1201}
1202
1203impl Display for Error {
1204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205 match self {
1206 Error::NotImplemented(_) => f.write_str("Gilrs does not support current platform."),
1207 Error::InvalidAxisToBtn => f.write_str(
1208 "Either `pressed ≤ released` or one of values is outside [0.0, 1.0] range.",
1209 ),
1210 Error::Other(ref e) => e.fmt(f),
1211 }
1212 }
1213}
1214
1215impl error::Error for Error {
1216 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1217 match self {
1218 Error::Other(e) => Some(e.as_ref()),
1219 _ => None,
1220 }
1221 }
1222}
1223
1224const _: () = {
1225 const fn assert_send<T: Send>() {}
1226
1227 #[cfg(not(target_arch = "wasm32"))]
1228 assert_send::<Gilrs>();
1229};
1230
1231#[cfg(test)]
1232mod tests {
1233 use super::{axis_value, btn_value, Axis, AxisInfo};
1234
1235 #[test]
1236 fn axis_value_documented_case() {
1237 let info = AxisInfo {
1238 min: 0,
1239 max: 255,
1240 deadzone: None,
1241 };
1242 let axis = Axis::LeftStickY;
1243 assert_eq!(0., axis_value(&info, 127, axis));
1244 }
1245
1246 #[test]
1247 fn axis_value_overflow() {
1248 let info = AxisInfo {
1249 min: i32::MIN,
1250 max: i32::MAX,
1251 deadzone: None,
1252 };
1253 let axis = Axis::LeftStickY;
1254
1255 assert_eq!(0., axis_value(&info, -1, axis));
1256 assert_eq!(0., axis_value(&info, 0, axis));
1257 assert_eq!(0., axis_value(&info, 1, axis));
1258
1259 assert_eq!(1.0, axis_value(&info, i32::MIN, axis));
1260 assert_eq!(-1.0, axis_value(&info, i32::MAX, axis));
1261 }
1262
1263 #[test]
1264 fn btn_value_overflow() {
1265 let info = AxisInfo {
1266 min: i32::MIN,
1267 max: i32::MAX,
1268 deadzone: None,
1269 };
1270
1271 assert_eq!(0.5, btn_value(&info, -1));
1272 assert_eq!(0.5, btn_value(&info, 0));
1273 assert_eq!(0.5, btn_value(&info, 1));
1274
1275 assert_eq!(0.0, btn_value(&info, i32::MIN));
1276 assert_eq!(1.0, btn_value(&info, i32::MAX));
1277 }
1278}