aboutsummaryrefslogtreecommitdiff
path: root/src/input/binding.rs
blob: 386fb667c94b2f36477deefd5d12d1c55be345c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Bindings module, which is a key combination that does something when pressed.

use super::Button;
use raylib::RaylibHandle;
use serde::{Deserialize, Serialize};

/// Binding struct, which holds any number of buttons (keyboard and mouse may be mixed, if desired)
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Binding {
    buttons: Vec<Button>,
}

impl Binding {
    /// Create a new binding from a range of buttons. The button order does not matter, but at least
    /// one button must be supplied.
    pub fn new(buttons: Vec<Button>) -> Self {
        if buttons.is_empty() {
            panic!("Tried to create a binding without any keys.");
        }

        Self { buttons }
    }

    /// Returns `true` if only mouse buttons are present in this binding, otherwise false.
    pub fn mouse_only(&self) -> bool {
        for button in &self.buttons {
            match button {
                Button::Mouse(_) => continue,
                _ => return false,
            }
        }

        true
    }

    /// Returns `true` if only keyboard buttons are present in this binding, otherwise false.
    pub fn keyboard_only(&self) -> bool {
        for button in &self.buttons {
            match button {
                Button::Scancode(_) | Button::Text(_) => continue,
                _ => return false,
            }
        }

        true
    }

    /// Returns `true` if at least one mouse button is required for this binding to work.
    pub fn has_mouse_component(&self) -> bool {
        self.buttons.iter().any(|b| {
            if let Button::Mouse(_) = b {
                true
            } else {
                false
            }
        })
    }

    /// Returns `true` if at least one keyboard button is required for this binding to work.
    pub fn has_keyboard_component(&self) -> bool {
        self.buttons.iter().any(|b| match b {
            Button::Scancode(_) | Button::Text(_) => true,
            _ => false,
        })
    }

    /// Checks if this binding was pressed this frame. Heavily dependent on input struct working
    /// correctly.
    pub(super) fn is_pressed(
        &self,
        allow_mouse: bool,
        allow_keyboard: bool,
        text: &str,
        rl: &RaylibHandle,
    ) -> bool {
        let mut distinct_press = false;
        for button in &self.buttons {
            match *button {
                Button::Mouse(mouse_button) => {
                    if !allow_mouse || !rl.is_mouse_button_down(mouse_button.into()) {
                        return false;
                    }

                    /* Check if the button has been pressed in this frame exactly.
                     * This prevents activating the same keybinding every frame
                     * while the buttons are being held down.
                     */
                    if rl.is_mouse_button_pressed(mouse_button.into()) {
                        distinct_press = true;
                    }
                }
                Button::Scancode(code) => {
                    if !allow_keyboard || !rl.is_key_down(code.into()) {
                        return false;
                    }

                    // Check the same as with the mouse button.
                    if rl.is_key_pressed(code.into()) {
                        distinct_press = true;
                    }
                }
                Button::Text(c) => {
                    if !allow_keyboard || !text.contains(c) {
                        return false;
                    }

                    // Always distinct, since on triggering, the text is cleared.
                    distinct_press = true;
                }
            }
        }

        distinct_press
    }
}

impl From<Button> for Binding {
    fn from(button: Button) -> Self {
        Self {
            buttons: vec![button],
        }
    }
}