stick/
ctlr.rs

1// Stick
2// Copyright © 2017-2021 Jeron Aldaron Lau.
3//
4// Licensed under any of:
5// - Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
6// - MIT License (https://mit-license.org/)
7// - Boost Software License, Version 1.0 (https://www.boost.org/LICENSE_1_0.txt)
8// At your option (See accompanying files LICENSE_APACHE_2_0.txt,
9// LICENSE_MIT.txt and LICENSE_BOOST_1_0.txt).  This file may not be copied,
10// modified, or distributed except according to those terms.
11
12use std::collections::HashMap;
13use std::fmt::Debug;
14use std::future::Future;
15use std::pin::Pin;
16use std::sync::Arc;
17use std::task::{Context, Poll};
18
19use crate::Event;
20
21#[repr(i8)]
22enum Btn {
23    Exit = 0,
24    MenuL = 1,
25    MenuR = 2,
26    ActionA = 3,
27    ActionB = 4,
28    ActionC = 5,
29    ActionH = 6,
30    ActionV = 7,
31    ActionD = 8,
32    Up = 9,
33    Down = 10,
34    Right = 11,
35    Left = 12,
36    BumperL = 13,
37    BumperR = 14,
38    Joy = 15,
39    Cam = 16,
40    PaddleLeft = 17,
41    PaddleRight = 18,
42    PinkyLeft = 19,
43    PinkyRight = 20,
44    Trigger = 21,
45    HatUp = 22,
46    HatDown = 23,
47    HatRight = 24,
48    HatLeft = 25,
49    MicUp = 26,
50    MicDown = 27,
51    MicRight = 28,
52    MicLeft = 29,
53    PovUp = 30,
54    PovDown = 31,
55    PovRight = 32,
56    PovLeft = 33,
57    MicPush = 34,
58    ActionL = 35,
59    ActionR = 36,
60    Bumper = 37,
61    ActionM = 38,
62    Pinky = 39,
63    PinkyForward = 40,
64    PinkyBackward = 41,
65    FlapsUp = 42,
66    FlapsDown = 43,
67    BoatForward = 44,
68    BoatBackward = 45,
69    AutopilotPath = 46,
70    AutopilotAlt = 47,
71    EngineMotorL = 48,
72    EngineMotorR = 49,
73    EngineFuelFlowL = 50,
74    EngineFuelFlowR = 51,
75    EngineIgnitionL = 52,
76    EngineIgnitionR = 53,
77    SpeedbrakeBackward = 54,
78    SpeedbrakeForward = 55,
79    ChinaBackward = 56,
80    ChinaForward = 57,
81    Apu = 58,
82    RadarAltimeter = 59,
83    LandingGearSilence = 60,
84    Eac = 61,
85    AutopilotToggle = 62,
86    ThrottleButton = 63,
87    Mouse = 64,
88    Scroll = 65,
89    Context = 66,
90    Dpi = 67,
91    TrimUp = 68,
92    TrimDown = 69,
93    TrimRight = 70,
94    TrimLeft = 71,
95}
96
97#[repr(i8)]
98enum Axs {
99    TriggerL = 0,
100    TriggerR = 1,
101    JoyX = 2,
102    JoyY = 3,
103    JoyZ = 4,
104    CamX = 5,
105    CamY = 6,
106    CamZ = 7,
107    Wheel = 8,
108    Brake = 9,
109    Gas = 10,
110    Rudder = 11,
111    Slew = 12,
112    Throttle = 13,
113    ThrottleL = 14,
114    ThrottleR = 15,
115    Volume = 16,
116    MouseX = 17,
117    MouseY = 18,
118    ScrollX = 19,
119    ScrollY = 20,
120    ActionWheelX = 21,
121    ActionWheelY = 22,
122    Count, // Inferred correctly as long as it's last
123}
124
125#[derive(Debug)]
126struct Map {
127    deadzone: f64,
128    scale: f64,
129    max: i32,
130    min: i32,
131    out: u8,
132}
133
134#[derive(Debug)]
135struct Info {
136    name: String,
137    maps: HashMap<u8, Map>,
138    type_: char,
139}
140
141impl Default for Info {
142    fn default() -> Self {
143        Self {
144            name: "Unknown".to_string(),
145            maps: HashMap::new(),
146            type_: 'w',
147        }
148    }
149}
150
151/// Controller remapping information
152#[derive(Debug)]
153pub struct Remap(HashMap<u64, Arc<Info>>);
154
155impl Default for Remap {
156    fn default() -> Self {
157        Self::new()
158    }
159}
160
161impl Remap {
162    /// Create new remapper.
163    #[allow(unused_mut, clippy::let_and_return)]
164    pub fn new() -> Self {
165        let mut remapper = Remap(HashMap::new());
166        #[cfg(all(feature = "gcdb", target_os = "linux"))]
167        {
168            let data = include_str!("../sdlgc_linux.sdb");
169            remapper = remapper.load(data).unwrap();
170        }
171        #[cfg(all(feature = "sdb", target_os = "linux"))]
172        {
173            let data = include_str!("../remap_linux.sdb");
174            remapper = remapper.load(data).unwrap();
175        }
176        remapper
177    }
178
179    /// Load a custom re-mapping.
180    pub fn load(mut self, data: &str) -> Option<Remap> {
181        // Controllers
182        for line in data.lines() {
183            let id = u64::from_str_radix(&line[..16], 16).ok()?;
184            let tab = line.find('\t')?;
185            let name = line[16..tab].to_string();
186            let type_ = line.get(tab + 1..tab + 2)?.chars().next()?;
187            let mut maps = HashMap::new();
188
189            // Events
190            for event in line.get(tab + 2..)?.split(';') {
191                let in_ = u8::from_str_radix(event.get(0..2)?, 16).ok()?;
192                let out = u8::from_str_radix(event.get(2..4)?, 16).ok()?;
193
194                // Tweaks
195                let mut cursor = 4;
196                let mut deadzone = f64::NAN;
197                let mut scale = f64::NAN;
198                let mut max: i32 = 0;
199                let mut min: i32 = 0;
200                while let Some(tweak) = event.get(cursor..)?.chars().next() {
201                    match tweak {
202                        'd' => {
203                            let end = event
204                                .get(cursor + 1..)?
205                                .find(char::is_lowercase)
206                                .unwrap_or(event.get(cursor + 1..)?.len());
207                            deadzone = event
208                                .get(cursor + 1..cursor + 1 + end)?
209                                .parse::<f64>()
210                                .ok()?;
211                            cursor += end + 1;
212                        }
213                        's' => {
214                            let end = event
215                                .get(cursor + 1..)?
216                                .find(char::is_lowercase)
217                                .unwrap_or(event.get(cursor + 1..)?.len());
218                            scale = event
219                                .get(cursor + 1..cursor + 1 + end)?
220                                .parse::<f64>()
221                                .ok()?
222                                .recip();
223                            cursor += end + 1;
224                        }
225                        'a' => {
226                            let end = event
227                                .get(cursor + 1..)?
228                                .find(char::is_lowercase)
229                                .unwrap_or(event.get(cursor + 1..)?.len());
230                            max = event
231                                .get(cursor + 1..cursor + 1 + end)?
232                                .parse::<i32>()
233                                .ok()?;
234                            cursor += end + 1;
235                        }
236                        'i' => {
237                            let end = event
238                                .get(cursor + 1..)?
239                                .find(char::is_lowercase)
240                                .unwrap_or(event.get(cursor + 1..)?.len());
241                            min = event
242                                .get(cursor + 1..cursor + 1 + end)?
243                                .parse::<i32>()
244                                .ok()?;
245                            cursor += end + 1;
246                        }
247                        _ => return None,
248                    }
249                }
250
251                maps.insert(
252                    in_,
253                    Map {
254                        deadzone,
255                        scale,
256                        max,
257                        min,
258                        out,
259                    },
260                );
261            }
262
263            self.0.insert(id, Arc::new(Info { name, maps, type_ }));
264        }
265
266        Some(self)
267    }
268}
269
270/// A gamepad, flightstick, or other controller.
271pub struct Controller {
272    // Shared remapping.
273    remap: Arc<Info>,
274    //
275    raw: Box<dyn crate::raw::Controller>,
276    // Button states
277    btns: u128,
278    // Number button states
279    nums: u128,
280    // Axis states:
281    axis: [f64; Axs::Count as usize],
282}
283
284impl Debug for Controller {
285    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
286        write!(f, "Controller(\"{}\")", self.name())
287    }
288}
289
290impl Controller {
291    #[allow(unused)]
292    pub(crate) fn new(
293        raw: Box<dyn crate::raw::Controller>,
294        remap: &Remap,
295    ) -> Self {
296        let btns = 0;
297        let nums = 0;
298        let axis = [0.0; Axs::Count as usize];
299        let remap = remap.0.get(&raw.id()).cloned().unwrap_or_default();
300        Self {
301            remap,
302            raw,
303            btns,
304            nums,
305            axis,
306        }
307    }
308
309    /// Get a unique identifier for the specific model of gamepad.
310    pub fn id(&self) -> u64 {
311        self.raw.id()
312    }
313
314    /// Get the name of this Pad.
315    pub fn name(&self) -> &str {
316        self.raw.name()
317    }
318
319    /// Turn on/off haptic force feedback.
320    ///
321    /// Takes either an `f32` for mono power or `(f32, f32)` for directional
322    /// power.  Power will be clamped between 0.0 (off) and 1.0 (maximum power).
323    ///
324    /// The first `f32` in directional power is typically low frequency and is
325    /// located on the left, and the second is typically high frequency and is
326    /// located on the right (controllers may vary).
327    pub fn rumble<R: Rumble>(&mut self, power: R) {
328        self.raw.rumble(power.left(), power.right());
329    }
330
331    fn button(&mut self, b: Btn, f: fn(bool) -> Event, p: bool) -> Poll<Event> {
332        let b = 1u128 << b as i8;
333        if (self.btns & b != 0) == p {
334            Poll::Pending
335        } else {
336            self.btns ^= b;
337            Poll::Ready(f(p))
338        }
339    }
340
341    fn number(
342        &mut self,
343        n: i8,
344        f: fn(i8, bool) -> Event,
345        p: bool,
346    ) -> Poll<Event> {
347        let b = 1u128 << n;
348        if (self.nums & b != 0) == p {
349            Poll::Pending
350        } else {
351            self.nums ^= b;
352            Poll::Ready(f(n, p))
353        }
354    }
355
356    #[allow(clippy::float_cmp)] // imprecision should be consistent
357    fn axis(
358        &mut self,
359        ev: u8,
360        a: Axs,
361        f: fn(f64) -> Event,
362        v: f64,
363    ) -> Poll<Event> {
364        let map = self.remap.maps.get(&ev);
365        let v = if let Some(map) = map {
366            let v = if map.min != 0 || map.max != 0 {
367                (((v - f64::from(map.min)) / f64::from(map.max - map.min))
368                    * 2.0
369                    - 1.0)
370                    .clamp(-1.0, 1.0)
371            } else {
372                self.raw.axis(v).clamp(-1.0, 1.0)
373            };
374            if !map.deadzone.is_nan() && v.abs() <= map.deadzone {
375                0.0
376            } else {
377                v
378            }
379        } else {
380            self.raw.axis(v).clamp(-1.0, 1.0)
381        };
382        let axis = a as usize;
383        if self.axis[axis] == v {
384            Poll::Pending
385        } else {
386            self.axis[axis] = v;
387            Poll::Ready(f(v))
388        }
389    }
390
391    #[allow(clippy::float_cmp)] // imprecision should be consistent
392    fn pressure(
393        &mut self,
394        ev: u8,
395        a: Axs,
396        f: fn(f64) -> Event,
397        v: f64,
398    ) -> Poll<Event> {
399        let map = self.remap.maps.get(&ev);
400        let v = if let Some(map) = map {
401            let v = if map.min != 0 || map.max != 0 {
402                ((v - f64::from(map.min)) / f64::from(map.max - map.min))
403                    .clamp(0.0, 1.0)
404            } else {
405                self.raw.pressure(v).clamp(0.0, 1.0)
406            };
407            if !map.deadzone.is_nan() && v <= map.deadzone {
408                0.0
409            } else {
410                v
411            }
412        } else {
413            self.raw.pressure(v).clamp(0.0, 1.0)
414        };
415        let axis = a as usize;
416        if self.axis[axis] == v {
417            Poll::Pending
418        } else {
419            self.axis[axis] = v;
420            Poll::Ready(f(v))
421        }
422    }
423
424    fn process(&mut self, event: Event) -> Poll<Event> {
425        // Do remapping step first.
426        let ev = event.to_id().0;
427        let event = if let Some(new_id) = self.remap.maps.get(&ev) {
428            let event = event.remap(new_id.out);
429            if matches!(event, Disconnect) {
430                return Poll::Pending;
431            }
432            event
433        } else {
434            event
435        };
436        //
437        use Event::*;
438        match event {
439            Disconnect => Poll::Ready(Disconnect),
440            Exit(p) => self.button(Btn::Exit, Exit, p),
441            MenuL(p) => self.button(Btn::MenuL, MenuL, p),
442            MenuR(p) => self.button(Btn::MenuR, MenuR, p),
443            ActionA(p) => self.button(Btn::ActionA, ActionA, p),
444            ActionB(p) => self.button(Btn::ActionB, ActionB, p),
445            ActionC(p) => self.button(Btn::ActionC, ActionC, p),
446            ActionH(p) => self.button(Btn::ActionH, ActionH, p),
447            ActionV(p) => self.button(Btn::ActionV, ActionV, p),
448            ActionD(p) => self.button(Btn::ActionD, ActionD, p),
449            Up(p) => self.button(Btn::Up, Up, p),
450            Down(p) => self.button(Btn::Down, Down, p),
451            Right(p) => self.button(Btn::Right, Right, p),
452            Left(p) => self.button(Btn::Left, Left, p),
453            BumperL(p) => self.button(Btn::BumperL, BumperL, p),
454            BumperR(p) => self.button(Btn::BumperR, BumperR, p),
455            TriggerL(v) => self.pressure(ev, Axs::TriggerL, TriggerL, v),
456            TriggerR(v) => self.pressure(ev, Axs::TriggerR, TriggerR, v),
457            Joy(p) => self.button(Btn::Joy, Joy, p),
458            Cam(p) => self.button(Btn::Cam, Cam, p),
459            JoyX(v) => self.axis(ev, Axs::JoyX, JoyX, v),
460            JoyY(v) => self.axis(ev, Axs::JoyY, JoyY, v),
461            JoyZ(v) => self.axis(ev, Axs::JoyZ, JoyZ, v),
462            CamX(v) => self.axis(ev, Axs::CamX, CamX, v),
463            CamY(v) => self.axis(ev, Axs::CamY, CamY, v),
464            CamZ(v) => self.axis(ev, Axs::CamZ, CamZ, v),
465            PaddleLeft(p) => self.button(Btn::PaddleLeft, PaddleLeft, p),
466            PaddleRight(p) => self.button(Btn::PaddleRight, PaddleRight, p),
467            PinkyLeft(p) => self.button(Btn::PinkyLeft, PinkyLeft, p),
468            PinkyRight(p) => self.button(Btn::PinkyRight, PinkyRight, p),
469            Number(n, p) => self.number(n, Number, p),
470            HatUp(p) => self.button(Btn::HatUp, HatUp, p),
471            HatDown(p) => self.button(Btn::HatDown, HatDown, p),
472            HatRight(p) => self.button(Btn::HatRight, HatRight, p),
473            HatLeft(p) => self.button(Btn::HatLeft, HatLeft, p),
474            Trigger(p) => self.button(Btn::Trigger, Trigger, p),
475            MicUp(p) => self.button(Btn::MicUp, MicUp, p),
476            MicDown(p) => self.button(Btn::MicDown, MicDown, p),
477            MicRight(p) => self.button(Btn::MicRight, MicRight, p),
478            MicLeft(p) => self.button(Btn::MicLeft, MicLeft, p),
479            PovUp(p) => self.button(Btn::PovUp, PovUp, p),
480            PovDown(p) => self.button(Btn::PovDown, PovDown, p),
481            PovRight(p) => self.button(Btn::PovRight, PovRight, p),
482            PovLeft(p) => self.button(Btn::PovLeft, PovLeft, p),
483            Slew(v) => self.pressure(ev, Axs::Slew, Slew, v),
484            Throttle(v) => self.pressure(ev, Axs::Throttle, Throttle, v),
485            ThrottleL(v) => self.pressure(ev, Axs::ThrottleL, ThrottleL, v),
486            ThrottleR(v) => self.pressure(ev, Axs::ThrottleR, ThrottleR, v),
487            Volume(v) => self.pressure(ev, Axs::Volume, Volume, v),
488            Wheel(v) => self.pressure(ev, Axs::Wheel, Wheel, v),
489            Rudder(v) => self.pressure(ev, Axs::Rudder, Rudder, v),
490            Gas(v) => self.pressure(ev, Axs::Gas, Gas, v),
491            Brake(v) => self.pressure(ev, Axs::Brake, Brake, v),
492            MicPush(p) => self.button(Btn::MicPush, MicPush, p),
493            ActionL(p) => self.button(Btn::ActionL, ActionL, p),
494            ActionM(p) => self.button(Btn::ActionM, ActionM, p),
495            ActionR(p) => self.button(Btn::ActionR, ActionR, p),
496            Bumper(p) => self.button(Btn::Bumper, Bumper, p),
497            Pinky(p) => self.button(Btn::Pinky, Pinky, p),
498            PinkyForward(p) => self.button(Btn::PinkyForward, PinkyForward, p),
499            PinkyBackward(p) => {
500                self.button(Btn::PinkyBackward, PinkyBackward, p)
501            }
502            FlapsUp(p) => self.button(Btn::FlapsUp, FlapsUp, p),
503            FlapsDown(p) => self.button(Btn::FlapsDown, FlapsDown, p),
504            BoatForward(p) => self.button(Btn::BoatForward, BoatForward, p),
505            BoatBackward(p) => self.button(Btn::BoatBackward, BoatBackward, p),
506            AutopilotPath(p) => {
507                self.button(Btn::AutopilotPath, AutopilotPath, p)
508            }
509            AutopilotAlt(p) => self.button(Btn::AutopilotAlt, AutopilotAlt, p),
510            EngineMotorL(p) => self.button(Btn::EngineMotorL, EngineMotorL, p),
511            EngineMotorR(p) => self.button(Btn::EngineMotorR, EngineMotorR, p),
512            EngineFuelFlowL(p) => {
513                self.button(Btn::EngineFuelFlowL, EngineFuelFlowL, p)
514            }
515            EngineFuelFlowR(p) => {
516                self.button(Btn::EngineFuelFlowR, EngineFuelFlowR, p)
517            }
518            EngineIgnitionL(p) => {
519                self.button(Btn::EngineIgnitionL, EngineIgnitionL, p)
520            }
521            EngineIgnitionR(p) => {
522                self.button(Btn::EngineIgnitionR, EngineIgnitionR, p)
523            }
524            SpeedbrakeBackward(p) => {
525                self.button(Btn::SpeedbrakeBackward, SpeedbrakeBackward, p)
526            }
527            SpeedbrakeForward(p) => {
528                self.button(Btn::SpeedbrakeForward, SpeedbrakeForward, p)
529            }
530            ChinaBackward(p) => {
531                self.button(Btn::ChinaBackward, ChinaBackward, p)
532            }
533            ChinaForward(p) => self.button(Btn::ChinaForward, ChinaForward, p),
534            Apu(p) => self.button(Btn::Apu, Apu, p),
535            RadarAltimeter(p) => {
536                self.button(Btn::RadarAltimeter, RadarAltimeter, p)
537            }
538            LandingGearSilence(p) => {
539                self.button(Btn::LandingGearSilence, LandingGearSilence, p)
540            }
541            Eac(p) => self.button(Btn::Eac, Eac, p),
542            AutopilotToggle(p) => {
543                self.button(Btn::AutopilotToggle, AutopilotToggle, p)
544            }
545            ThrottleButton(p) => {
546                self.button(Btn::ThrottleButton, ThrottleButton, p)
547            }
548            MouseX(v) => self.axis(ev, Axs::MouseX, MouseX, v),
549            MouseY(v) => self.axis(ev, Axs::MouseY, MouseY, v),
550            ScrollX(v) => self.axis(ev, Axs::ScrollX, ScrollX, v),
551            ScrollY(v) => self.axis(ev, Axs::ScrollY, ScrollY, v),
552            Mouse(p) => self.button(Btn::Mouse, Mouse, p),
553            Scroll(p) => self.button(Btn::Scroll, Scroll, p),
554            Context(p) => self.button(Btn::Context, Context, p),
555            Dpi(p) => self.button(Btn::Dpi, Dpi, p),
556            TrimUp(p) => self.button(Btn::TrimUp, TrimUp, p),
557            TrimDown(p) => self.button(Btn::TrimDown, TrimDown, p),
558            TrimLeft(p) => self.button(Btn::TrimLeft, TrimLeft, p),
559            TrimRight(p) => self.button(Btn::TrimRight, TrimRight, p),
560            ActionWheelX(v) => {
561                self.axis(ev, Axs::ActionWheelX, ActionWheelX, v)
562            }
563            ActionWheelY(v) => {
564                self.axis(ev, Axs::ActionWheelY, ActionWheelY, v)
565            }
566        }
567    }
568}
569
570impl Future for Controller {
571    type Output = Event;
572
573    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Event> {
574        let mut this = self.as_mut();
575
576        if let Poll::Ready(event) = this.raw.poll(cx) {
577            let out = Self::process(&mut *this, event);
578            if out.is_pending() {
579                Self::poll(self, cx)
580            } else {
581                out
582            }
583        } else {
584            Poll::Pending
585        }
586    }
587}
588
589pub trait Rumble {
590    fn left(&self) -> f32;
591    fn right(&self) -> f32;
592}
593
594impl Rumble for f32 {
595    #[inline(always)]
596    fn left(&self) -> f32 {
597        self.clamp(0.0, 1.0)
598    }
599
600    #[inline(always)]
601    fn right(&self) -> f32 {
602        self.clamp(0.0, 1.0)
603    }
604}
605
606impl Rumble for (f32, f32) {
607    #[inline(always)]
608    fn left(&self) -> f32 {
609        self.0.clamp(0.0, 1.0)
610    }
611
612    #[inline(always)]
613    fn right(&self) -> f32 {
614        self.1.clamp(0.0, 1.0)
615    }
616}