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}