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