1use repose_core::input::{GamepadAxis, GamepadButton, PointerButton};
4use repose_core::shortcuts::KeyChord;
5
6#[derive(Clone, Debug)]
9pub enum Binding {
10 Key(KeyChord),
12 Mouse(PointerButton),
14 Pad(GamepadButton),
16 Axis { axis: GamepadAxis, threshold: f32 },
20}
21
22impl PartialEq for Binding {
25 fn eq(&self, other: &Self) -> bool {
26 match (self, other) {
27 (Binding::Key(a), Binding::Key(b)) => a == b,
28 (Binding::Mouse(a), Binding::Mouse(b)) => {
29 std::mem::discriminant(a) == std::mem::discriminant(b)
30 }
31 (Binding::Pad(a), Binding::Pad(b)) => a == b,
32 (
33 Binding::Axis {
34 axis: a,
35 threshold: t,
36 },
37 Binding::Axis {
38 axis: b,
39 threshold: u,
40 },
41 ) => a == b && t == u,
42 _ => false,
43 }
44 }
45}
46
47impl Eq for Binding {}
48
49impl std::hash::Hash for Binding {
50 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
51 std::mem::discriminant(self).hash(state);
52 match self {
53 Binding::Key(chord) => chord.hash(state),
54 Binding::Mouse(b) => std::mem::discriminant(b).hash(state),
55 Binding::Pad(b) => b.hash(state),
56 Binding::Axis { axis, threshold } => {
57 axis.hash(state);
58 let t = if *threshold == 0.0 { 0.0 } else { *threshold };
59 t.to_bits().hash(state);
60 }
61 }
62 }
63}
64
65impl Binding {
66 pub fn axis_active(threshold: f32, value: f32) -> bool {
71 if !value.is_finite() {
72 return false;
73 }
74 if threshold == 0.0 {
75 value != 0.0
76 } else if threshold > 0.0 {
77 value >= threshold
78 } else {
79 value <= threshold
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn axis_threshold_sign_selects_side() {
90 assert!(Binding::axis_active(0.5, 0.7));
91 assert!(!Binding::axis_active(0.5, 0.3));
92 assert!(Binding::axis_active(-0.5, -0.7));
93 assert!(!Binding::axis_active(-0.5, -0.3));
94 assert!(!Binding::axis_active(0.0, 0.0));
95 assert!(Binding::axis_active(0.0, 0.1));
96 assert!(Binding::axis_active(0.0, -0.1));
97 assert!(!Binding::axis_active(0.0, f32::NAN));
98 assert!(!Binding::axis_active(0.5, f32::NAN));
99 assert!(!Binding::axis_active(-0.5, f32::NAN));
100 }
101
102 #[test]
103 fn bindings_hash_for_sets() {
104 use repose_core::input::{GamepadAxis, GamepadButton, Key, Modifiers, PointerButton};
105 use repose_core::shortcuts::KeyChord;
106 use std::collections::HashSet;
107 let mut set = HashSet::new();
108 set.insert(Binding::Pad(GamepadButton::South));
109 assert!(set.contains(&Binding::Pad(GamepadButton::South)));
110 set.insert(Binding::Mouse(PointerButton::Primary));
111 assert!(set.contains(&Binding::Mouse(PointerButton::Primary)));
112 assert!(!set.contains(&Binding::Mouse(PointerButton::Secondary)));
113 set.insert(Binding::Axis {
114 axis: GamepadAxis::LeftStickX,
115 threshold: 0.5,
116 });
117 assert!(set.contains(&Binding::Axis {
118 axis: GamepadAxis::LeftStickX,
119 threshold: 0.5,
120 }));
121 assert!(!set.contains(&Binding::Axis {
122 axis: GamepadAxis::LeftStickX,
123 threshold: 0.6,
124 }));
125 let _ = KeyChord::new(Key::Space, Modifiers::default());
126 }
127}