rich_sdl2_rust/event/game_controller/
button.rs

1//! Buttons for a game controller.
2
3use std::{
4    ffi::{CStr, CString},
5    str::FromStr,
6};
7
8use crate::{bind, SdlError};
9
10/// An one of four buttons which be placed like the diamond.
11#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash)]
12pub enum FourButton {
13    /// A button on the up.
14    Up,
15    /// A button on the right.
16    Right,
17    /// A button on the down.
18    Down,
19    /// A button on the left.
20    Left,
21}
22
23/// A button on a game controller except the trigger buttons.
24/// Trigger buttons are covered by [`super::axis::Axis`].
25#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash)]
26#[non_exhaustive]
27pub enum Button {
28    /// Four buttons on the left.
29    LeftFour(FourButton),
30    /// Four buttons on the right.
31    RightFour(FourButton),
32    /// A back button on the center.
33    Back,
34    /// A meta button on the center.
35    Guide,
36    /// A start button on the center.
37    Start,
38    /// A stick push button on the left.
39    LeftStick,
40    /// A stick push button on the right.
41    RightStick,
42    /// A sub trigger button on the left.
43    LeftShoulder,
44    /// A sub trigger button on the right.
45    RightShoulder,
46}
47
48impl Button {
49    pub(super) fn from_raw(raw: bind::SDL_GameControllerButton) -> Option<Self> {
50        let val = match raw {
51            bind::SDL_CONTROLLER_BUTTON_A => Button::RightFour(FourButton::Down),
52            bind::SDL_CONTROLLER_BUTTON_B => Button::RightFour(FourButton::Right),
53            bind::SDL_CONTROLLER_BUTTON_X => Button::RightFour(FourButton::Left),
54            bind::SDL_CONTROLLER_BUTTON_Y => Button::RightFour(FourButton::Up),
55            bind::SDL_CONTROLLER_BUTTON_BACK => Button::Back,
56            bind::SDL_CONTROLLER_BUTTON_GUIDE => Button::Guide,
57            bind::SDL_CONTROLLER_BUTTON_START => Button::Start,
58            bind::SDL_CONTROLLER_BUTTON_LEFTSTICK => Button::LeftStick,
59            bind::SDL_CONTROLLER_BUTTON_RIGHTSTICK => Button::RightStick,
60            bind::SDL_CONTROLLER_BUTTON_LEFTSHOULDER => Button::LeftShoulder,
61            bind::SDL_CONTROLLER_BUTTON_DPAD_DOWN => Button::LeftFour(FourButton::Down),
62            bind::SDL_CONTROLLER_BUTTON_DPAD_RIGHT => Button::LeftFour(FourButton::Right),
63            bind::SDL_CONTROLLER_BUTTON_DPAD_LEFT => Button::LeftFour(FourButton::Left),
64            bind::SDL_CONTROLLER_BUTTON_DPAD_UP => Button::LeftFour(FourButton::Up),
65            _ => return None,
66        };
67        Some(val)
68    }
69
70    pub(super) fn as_raw(self) -> bind::SDL_GameControllerButton {
71        match self {
72            Button::LeftFour(FourButton::Up) => bind::SDL_CONTROLLER_BUTTON_Y,
73            Button::LeftFour(FourButton::Right) => bind::SDL_CONTROLLER_BUTTON_B,
74            Button::LeftFour(FourButton::Down) => bind::SDL_CONTROLLER_BUTTON_A,
75            Button::LeftFour(FourButton::Left) => bind::SDL_CONTROLLER_BUTTON_X,
76            Button::RightFour(FourButton::Up) => bind::SDL_CONTROLLER_BUTTON_DPAD_UP,
77            Button::RightFour(FourButton::Right) => bind::SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
78            Button::RightFour(FourButton::Down) => bind::SDL_CONTROLLER_BUTTON_DPAD_DOWN,
79            Button::RightFour(FourButton::Left) => bind::SDL_CONTROLLER_BUTTON_DPAD_LEFT,
80            Button::Back => bind::SDL_CONTROLLER_BUTTON_BACK,
81            Button::Guide => bind::SDL_CONTROLLER_BUTTON_GUIDE,
82            Button::Start => bind::SDL_CONTROLLER_BUTTON_START,
83            Button::LeftStick => bind::SDL_CONTROLLER_BUTTON_LEFTSTICK,
84            Button::RightStick => bind::SDL_CONTROLLER_BUTTON_RIGHTSTICK,
85            Button::LeftShoulder => bind::SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
86            Button::RightShoulder => bind::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
87        }
88    }
89
90    /// Returns the mapping string if exists.
91    #[must_use]
92    pub fn to_mapping_string(self) -> Option<String> {
93        let ptr = unsafe { bind::SDL_GameControllerGetStringForButton(self.as_raw()) };
94        if ptr.is_null() {
95            return None;
96        }
97        let cstr = unsafe { CStr::from_ptr(ptr) };
98        Some(cstr.to_string_lossy().to_string())
99    }
100}
101
102impl std::fmt::Display for Button {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        let c_str =
105            unsafe { CStr::from_ptr(bind::SDL_GameControllerGetStringForButton(self.as_raw())) };
106        write!(f, "{}", c_str.to_str().unwrap())
107    }
108}
109
110impl FromStr for Button {
111    type Err = SdlError;
112
113    fn from_str(s: &str) -> Result<Self, Self::Err> {
114        let cstr = CString::new(s).map_err(|_| SdlError::Others {
115            msg: "string must not be empty".into(),
116        })?;
117        let axis = unsafe { bind::SDL_GameControllerGetButtonFromString(cstr.as_ptr()) };
118        Button::from_raw(axis).ok_or_else(|| SdlError::Others {
119            msg: "the axis was not found".into(),
120        })
121    }
122}