veloren_voxygen/settings/
controller.rs

1use crate::{game_input::GameInput, window::MenuInput};
2use gilrs::{Axis as GilAxis, Button as GilButton, ev::Code as GilCode};
3use hashbrown::{HashMap, HashSet};
4use i18n::Localization;
5use serde::{Deserialize, Serialize};
6use strum::{EnumIter, IntoEnumIterator};
7
8#[derive(Serialize, Deserialize)]
9#[serde(default)]
10struct ControllerSettingsSerde {
11    // save as a delta against defaults for efficiency
12    game_button_map: HashMap<GameInput, Option<Button>>,
13    menu_button_map: HashMap<MenuInput, Option<Button>>,
14    game_analog_button_map: HashMap<AnalogButtonGameAction, AnalogButton>,
15    menu_analog_button_map: HashMap<AnalogButtonMenuAction, AnalogButton>,
16    game_axis_map: HashMap<AxisGameAction, Axis>,
17    menu_axis_map: HashMap<AxisMenuAction, Axis>,
18    layer_button_map: HashMap<GameInput, Option<LayerEntry>>,
19    modifier_buttons: Vec<Button>,
20
21    pan_sensitivity: u32,
22    pan_invert_y: bool,
23    axis_deadzones: HashMap<Axis, f32>,
24    button_deadzones: HashMap<AnalogButton, f32>,
25    mouse_emulation_sensitivity: u32,
26    inverted_axes: Vec<Axis>,
27}
28
29impl From<ControllerSettings> for ControllerSettingsSerde {
30    fn from(controller_settings: ControllerSettings) -> Self {
31        // Do a delta between default() ControllerSettings and the argument,
32        // let buttons be only the custom keybindings chosen by the user
33        //
34        // check game buttons
35        let mut button_bindings: HashMap<GameInput, Option<Button>> = HashMap::new();
36        for (k, v) in controller_settings.game_button_map {
37            if ControllerSettings::default_button_binding(k) != v {
38                button_bindings.insert(k, v);
39            }
40        }
41
42        // check game layers
43        let mut layer_bindings: HashMap<GameInput, Option<LayerEntry>> = HashMap::new();
44        for (k, v) in controller_settings.layer_button_map {
45            if ControllerSettings::default_layer_binding(k) != v {
46                layer_bindings.insert(k, v);
47            }
48        }
49
50        // none hashmap values
51        let modifier_buttons = controller_settings.modifier_buttons;
52        let pan_sensitivity = controller_settings.pan_sensitivity;
53        let pan_invert_y = controller_settings.pan_invert_y;
54        let axis_deadzones = controller_settings.axis_deadzones;
55
56        let mouse_emulation_sensitivity = controller_settings.mouse_emulation_sensitivity;
57        let inverted_axes = controller_settings.inverted_axes;
58
59        ControllerSettingsSerde {
60            game_button_map: button_bindings,
61            menu_button_map: HashMap::new(),
62            game_analog_button_map: HashMap::new(),
63            menu_analog_button_map: HashMap::new(),
64            game_axis_map: HashMap::new(),
65            menu_axis_map: HashMap::new(),
66            layer_button_map: layer_bindings,
67
68            modifier_buttons,
69            pan_sensitivity,
70            pan_invert_y,
71            axis_deadzones,
72
73            button_deadzones: HashMap::new(),
74            mouse_emulation_sensitivity,
75            inverted_axes,
76        }
77    }
78}
79
80impl Default for ControllerSettingsSerde {
81    fn default() -> Self { ControllerSettings::default().into() }
82}
83
84/// Contains all controller related settings and keymaps
85#[derive(Clone, Debug, Serialize, Deserialize)]
86#[serde(from = "ControllerSettingsSerde", into = "ControllerSettingsSerde")]
87pub struct ControllerSettings {
88    pub game_button_map: HashMap<GameInput, Option<Button>>,
89    pub inverse_game_button_map: HashMap<Button, HashSet<GameInput>>,
90    pub menu_button_map: HashMap<MenuInput, Option<Button>>,
91    pub inverse_menu_button_map: HashMap<Button, HashSet<MenuInput>>,
92    pub game_analog_button_map: HashMap<AnalogButtonGameAction, AnalogButton>,
93    pub inverse_game_analog_button_map: HashMap<AnalogButton, HashSet<AnalogButtonGameAction>>,
94    pub menu_analog_button_map: HashMap<AnalogButtonMenuAction, AnalogButton>,
95    pub inverse_menu_analog_button_map: HashMap<AnalogButton, HashSet<AnalogButtonMenuAction>>,
96    pub game_axis_map: HashMap<AxisGameAction, Axis>,
97    pub inverse_game_axis_map: HashMap<Axis, HashSet<AxisGameAction>>,
98    pub menu_axis_map: HashMap<AxisMenuAction, Axis>,
99    pub inverse_menu_axis_map: HashMap<Axis, HashSet<AxisMenuAction>>,
100    pub layer_button_map: HashMap<GameInput, Option<LayerEntry>>,
101    pub inverse_layer_button_map: HashMap<LayerEntry, HashSet<GameInput>>,
102
103    pub modifier_buttons: Vec<Button>,
104    pub pan_sensitivity: u32,
105    pub pan_invert_y: bool,
106    pub axis_deadzones: HashMap<Axis, f32>,
107    pub button_deadzones: HashMap<AnalogButton, f32>,
108    pub mouse_emulation_sensitivity: u32,
109    pub inverted_axes: Vec<Axis>,
110}
111
112impl From<ControllerSettingsSerde> for ControllerSettings {
113    fn from(controller_serde: ControllerSettingsSerde) -> Self {
114        let button_bindings = controller_serde.game_button_map;
115        let layer_bindings = controller_serde.layer_button_map;
116        let mut controller_settings = ControllerSettings::default();
117        // update button bindings
118        for (k, maybe_v) in button_bindings {
119            match maybe_v {
120                Some(v) => controller_settings.modify_button_binding(k, v),
121                None => controller_settings.remove_button_binding(k),
122            }
123        }
124        // update layer bindings
125        for (k, maybe_v) in layer_bindings {
126            match maybe_v {
127                Some(v) => controller_settings.modify_layer_binding(k, v),
128                None => controller_settings.remove_layer_binding(k),
129            }
130        }
131        controller_settings
132    }
133}
134
135impl ControllerSettings {
136    pub fn apply_axis_deadzone(&self, k: &Axis, input: f32) -> f32 {
137        let threshold = *self.axis_deadzones.get(k).unwrap_or(&0.2);
138
139        // This could be one comparison per handled event faster if threshold was
140        // guaranteed to fall into <0, 1) range
141        let input_abs = input.abs();
142        if input_abs <= threshold || threshold >= 1.0 {
143            0.0
144        } else if threshold <= 0.0 {
145            input
146        } else {
147            (input_abs - threshold) / (1.0 - threshold) * input.signum()
148        }
149    }
150
151    pub fn apply_button_deadzone(&self, k: &AnalogButton, input: f32) -> f32 {
152        let threshold = *self.button_deadzones.get(k).unwrap_or(&0.2);
153
154        // This could be one comparison per handled event faster if threshold was
155        // guaranteed to fall into <0, 1) range
156        if input <= threshold || threshold >= 1.0 {
157            0.0
158        } else if threshold <= 0.0 {
159            input
160        } else {
161            (input - threshold) / (1.0 - threshold)
162        }
163    }
164
165    pub fn remove_button_binding(&mut self, game_input: GameInput) {
166        if let Some(inverse) = self
167            .game_button_map
168            .insert(game_input, None)
169            .flatten()
170            .and_then(|button| self.inverse_game_button_map.get_mut(&button))
171        {
172            inverse.remove(&game_input);
173        }
174    }
175
176    pub fn remove_layer_binding(&mut self, layer_input: GameInput) {
177        if let Some(inverse) = self
178            .layer_button_map
179            .insert(layer_input, None)
180            .flatten()
181            .and_then(|button| self.inverse_layer_button_map.get_mut(&button))
182        {
183            inverse.remove(&layer_input);
184        }
185    }
186
187    pub fn remove_menu_binding(&mut self, menu_input: MenuInput) {
188        if let Some(inverse) = self
189            .menu_button_map
190            .insert(menu_input, None)
191            .flatten()
192            .and_then(|button| self.inverse_menu_button_map.get_mut(&button))
193        {
194            inverse.remove(&menu_input);
195        }
196    }
197
198    pub fn get_game_button_binding(&self, input: GameInput) -> Option<Button> {
199        self.game_button_map.get(&input).cloned().flatten()
200    }
201
202    pub fn get_associated_game_button_inputs(
203        &self,
204        button: &Button,
205    ) -> Option<&HashSet<GameInput>> {
206        self.inverse_game_button_map.get(button)
207    }
208
209    pub fn get_associated_game_layer_inputs(
210        &self,
211        layers: &LayerEntry,
212    ) -> Option<&HashSet<GameInput>> {
213        self.inverse_layer_button_map.get(layers)
214    }
215
216    pub fn get_menu_button_binding(&self, input: MenuInput) -> Option<Button> {
217        self.menu_button_map.get(&input).cloned().flatten()
218    }
219
220    pub fn get_layer_button_binding(&self, input: GameInput) -> Option<LayerEntry> {
221        self.layer_button_map.get(&input).cloned().flatten()
222    }
223
224    pub fn insert_game_button_binding(&mut self, game_input: GameInput, game_button: Button) {
225        if game_button != Button::default() {
226            self.game_button_map.insert(game_input, Some(game_button));
227            self.inverse_game_button_map
228                .entry(game_button)
229                .or_default()
230                .insert(game_input);
231        }
232    }
233
234    pub fn insert_menu_button_binding(&mut self, menu_input: MenuInput, button: Button) {
235        if button != Button::default() {
236            self.menu_button_map.insert(menu_input, Some(button));
237            self.inverse_menu_button_map
238                .entry(button)
239                .or_default()
240                .insert(menu_input);
241        }
242    }
243
244    pub fn insert_game_axis_binding(&mut self, input: AxisGameAction, axis: Axis) {
245        if axis != Axis::default() {
246            self.game_axis_map.insert(input, axis);
247            self.inverse_game_axis_map
248                .entry(axis)
249                .or_default()
250                .insert(input);
251        }
252    }
253
254    pub fn insert_menu_axis_binding(&mut self, input: AxisMenuAction, axis: Axis) {
255        if axis != Axis::default() {
256            self.menu_axis_map.insert(input, axis);
257            self.inverse_menu_axis_map
258                .entry(axis)
259                .or_default()
260                .insert(input);
261        }
262    }
263
264    pub fn insert_layer_button_binding(&mut self, input: GameInput, layer_entry: LayerEntry) {
265        if layer_entry != LayerEntry::default() {
266            self.layer_button_map.insert(input, Some(layer_entry));
267            self.inverse_layer_button_map
268                .entry(layer_entry)
269                .or_default()
270                .insert(input);
271        }
272    }
273
274    pub fn modify_button_binding(&mut self, game_input: GameInput, button: Button) {
275        // for the Button->GameInput hashmap, we first need to remove the GameInput from
276        // the old binding
277        if let Some(old_binding) = self.get_game_button_binding(game_input) {
278            self.inverse_game_button_map
279                .entry(old_binding)
280                .or_default()
281                .remove(&game_input);
282        }
283        // then we add the GameInput to the proper key
284        self.inverse_game_button_map
285            .entry(button)
286            .or_default()
287            .insert(game_input);
288        // for the GameInput->button hashmap, just overwrite the value
289        self.game_button_map.insert(game_input, Some(button));
290    }
291
292    pub fn modify_layer_binding(&mut self, game_input: GameInput, layers: LayerEntry) {
293        // for the LayerEntry->GameInput hashmap, we first need to remove the GameInput
294        // from the old binding
295        if let Some(old_binding) = self.get_layer_button_binding(game_input) {
296            self.inverse_layer_button_map
297                .entry(old_binding)
298                .or_default()
299                .remove(&game_input);
300        }
301        // then we add the GameInput to the proper key
302        self.inverse_layer_button_map
303            .entry(layers)
304            .or_default()
305            .insert(game_input);
306        // for the GameInput->layer hashmap, just overwrite the value
307        self.layer_button_map.insert(game_input, Some(layers));
308    }
309
310    pub fn modify_menu_binding(&mut self, menu_input: MenuInput, button: Button) {
311        // for the Button->GameInput hashmap, we first need to remove the GameInput from
312        // the old binding
313        if let Some(old_binding) = self.get_menu_button_binding(menu_input) {
314            self.inverse_menu_button_map
315                .entry(old_binding)
316                .or_default()
317                .remove(&menu_input);
318        }
319        // then we add the GameInput to the proper key
320        self.inverse_menu_button_map
321            .entry(button)
322            .or_default()
323            .insert(menu_input);
324        // for the MenuInput->button hashmap, just overwrite the value
325        self.menu_button_map.insert(menu_input, Some(button));
326    }
327
328    /// Return true if this button is used for multiple GameInputs that aren't
329    /// expected to be safe to have bound to the same button at the same time
330    pub fn game_button_has_conflicting_bindings(&self, game_button: Button) -> bool {
331        if let Some(game_inputs) = self.inverse_game_button_map.get(&game_button) {
332            for a in game_inputs.iter() {
333                for b in game_inputs.iter() {
334                    if !GameInput::can_share_bindings(*a, *b) {
335                        return true;
336                    }
337                }
338            }
339
340            let layer_entry = LayerEntry {
341                button: game_button,
342                mod1: Button::Simple(GilButton::Unknown),
343                mod2: Button::Simple(GilButton::Unknown),
344            };
345            if let Some(layer_inputs) = self.inverse_layer_button_map.get(&layer_entry) {
346                for a in game_inputs.iter() {
347                    for b in layer_inputs.iter() {
348                        if !GameInput::can_share_bindings(*a, *b) {
349                            return true;
350                        }
351                    }
352                }
353            }
354        }
355        false
356    }
357
358    pub fn menu_button_has_conflicting_bindings(&self, menu_button: Button) -> bool {
359        self.inverse_menu_button_map
360            .get(&menu_button)
361            .is_some_and(|menu_inputs| menu_inputs.len() > 1)
362    }
363
364    /// Return true if this key is used for multiple GameInputs that aren't
365    /// expected to be safe to have bound to the same key at the same time
366    pub fn layer_entry_has_conflicting_bindings(&self, layer_entry: LayerEntry) -> bool {
367        if let Some(layer_inputs) = self.inverse_layer_button_map.get(&layer_entry) {
368            for a in layer_inputs.iter() {
369                for b in layer_inputs.iter() {
370                    if !GameInput::can_share_bindings(*a, *b) {
371                        return true;
372                    }
373                }
374            }
375
376            if layer_entry.mod1 == Button::Simple(GilButton::Unknown)
377                && layer_entry.mod2 == Button::Simple(GilButton::Unknown)
378                && let Some(game_inputs) = self.inverse_game_button_map.get(&layer_entry.button)
379            {
380                for a in layer_inputs.iter() {
381                    for b in game_inputs.iter() {
382                        if !GameInput::can_share_bindings(*a, *b) {
383                            return true;
384                        }
385                    }
386                }
387            }
388        }
389        false
390    }
391
392    pub fn default_game_axis(game_axis: AxisGameAction) -> Option<Axis> {
393        match game_axis {
394            AxisGameAction::MovementX => Some(Axis::Simple(GilAxis::LeftStickX)),
395            AxisGameAction::MovementY => Some(Axis::Simple(GilAxis::LeftStickY)),
396            AxisGameAction::CameraX => Some(Axis::Simple(GilAxis::RightStickX)),
397            AxisGameAction::CameraY => Some(Axis::Simple(GilAxis::RightStickY)),
398        }
399    }
400
401    pub fn default_menu_axis(menu_axis: AxisMenuAction) -> Option<Axis> {
402        match menu_axis {
403            AxisMenuAction::MoveX => Some(Axis::Simple(GilAxis::LeftStickX)),
404            AxisMenuAction::MoveY => Some(Axis::Simple(GilAxis::LeftStickY)),
405            AxisMenuAction::ScrollX => Some(Axis::Simple(GilAxis::RightStickX)),
406            AxisMenuAction::ScrollY => Some(Axis::Simple(GilAxis::RightStickY)),
407        }
408    }
409
410    pub fn default_button_binding(game_input: GameInput) -> Option<Button> {
411        match game_input {
412            GameInput::Primary => Some(Button::Simple(GilButton::RightTrigger2)),
413            GameInput::Secondary => Some(Button::Simple(GilButton::LeftTrigger2)),
414            GameInput::Block => Some(Button::Simple(GilButton::LeftTrigger)),
415            GameInput::Slot1 => Some(Button::Simple(GilButton::Unknown)),
416            GameInput::Slot2 => Some(Button::Simple(GilButton::Unknown)),
417            GameInput::Slot3 => Some(Button::Simple(GilButton::Unknown)),
418            GameInput::Slot4 => Some(Button::Simple(GilButton::Unknown)),
419            GameInput::Slot5 => Some(Button::Simple(GilButton::Unknown)),
420            GameInput::Slot6 => Some(Button::Simple(GilButton::Unknown)),
421            GameInput::Slot7 => Some(Button::Simple(GilButton::Unknown)),
422            GameInput::Slot8 => Some(Button::Simple(GilButton::Unknown)),
423            GameInput::Slot9 => Some(Button::Simple(GilButton::Unknown)),
424            GameInput::Slot10 => Some(Button::Simple(GilButton::Unknown)),
425            GameInput::PreviousSlot => Some(Button::Simple(GilButton::Unknown)),
426            GameInput::NextSlot => Some(Button::Simple(GilButton::Unknown)),
427            GameInput::CurrentSlot => Some(Button::Simple(GilButton::North)),
428            GameInput::ToggleCursor => Some(Button::Simple(GilButton::Unknown)),
429            GameInput::MoveForward => Some(Button::Simple(GilButton::Unknown)),
430            GameInput::MoveBack => Some(Button::Simple(GilButton::Unknown)),
431            GameInput::MoveLeft => Some(Button::Simple(GilButton::Unknown)),
432            GameInput::MoveRight => Some(Button::Simple(GilButton::Unknown)),
433            GameInput::Jump => Some(Button::Simple(GilButton::South)),
434            GameInput::WallJump => Some(Button::Simple(GilButton::South)),
435            GameInput::Sit => Some(Button::Simple(GilButton::Unknown)),
436            GameInput::Crawl => Some(Button::Simple(GilButton::Unknown)),
437            GameInput::Dance => Some(Button::Simple(GilButton::Unknown)),
438            GameInput::Greet => Some(Button::Simple(GilButton::Unknown)),
439            GameInput::Glide => Some(Button::Simple(GilButton::DPadUp)),
440            GameInput::SwimUp => Some(Button::Simple(GilButton::South)),
441            GameInput::SwimDown => Some(Button::Simple(GilButton::West)),
442            GameInput::Fly => Some(Button::Simple(GilButton::Unknown)),
443            GameInput::Sneak => Some(Button::Simple(GilButton::LeftThumb)),
444            GameInput::CancelClimb => Some(Button::Simple(GilButton::East)),
445            GameInput::ToggleLantern => Some(Button::Simple(GilButton::Unknown)),
446            GameInput::Mount => Some(Button::Simple(GilButton::South)),
447            GameInput::StayFollow => Some(Button::Simple(GilButton::Unknown)),
448            GameInput::Chat => Some(Button::Simple(GilButton::Unknown)),
449            GameInput::Command => Some(Button::Simple(GilButton::Unknown)),
450            GameInput::Escape => Some(Button::Simple(GilButton::Start)),
451            GameInput::Map => Some(Button::Simple(GilButton::Select)),
452            GameInput::Inventory => Some(Button::Simple(GilButton::DPadRight)),
453            GameInput::Trade => Some(Button::Simple(GilButton::Unknown)),
454            GameInput::Social => Some(Button::Simple(GilButton::DPadLeft)),
455            GameInput::Crafting => Some(Button::Simple(GilButton::Unknown)),
456            GameInput::Diary => Some(Button::Simple(GilButton::Unknown)),
457            GameInput::Settings => Some(Button::Simple(GilButton::Unknown)),
458            GameInput::Controls => Some(Button::Simple(GilButton::Unknown)),
459            GameInput::ToggleInterface => Some(Button::Simple(GilButton::Unknown)),
460            GameInput::ToggleDebug => Some(Button::Simple(GilButton::Unknown)),
461            #[cfg(feature = "egui-ui")]
462            GameInput::ToggleEguiDebug => Some(Button::Simple(GilButton::Unknown)),
463            GameInput::ToggleChat => Some(Button::Simple(GilButton::Unknown)),
464            GameInput::Fullscreen => Some(Button::Simple(GilButton::Unknown)),
465            GameInput::Screenshot => Some(Button::Simple(GilButton::Unknown)),
466            GameInput::ToggleIngameUi => Some(Button::Simple(GilButton::Unknown)),
467            GameInput::Roll => Some(Button::Simple(GilButton::RightThumb)),
468            GameInput::GiveUp => Some(Button::Simple(GilButton::South)),
469            GameInput::Respawn => Some(Button::Simple(GilButton::South)),
470            GameInput::Interact => Some(Button::Simple(GilButton::West)),
471            GameInput::ToggleWield => Some(Button::Simple(GilButton::East)),
472            GameInput::SwapLoadout => Some(Button::Simple(GilButton::DPadDown)),
473            GameInput::FreeLook => Some(Button::Simple(GilButton::Unknown)),
474            GameInput::AutoWalk => Some(Button::Simple(GilButton::Unknown)),
475            GameInput::ZoomIn => Some(Button::Simple(GilButton::Unknown)),
476            GameInput::ZoomOut => Some(Button::Simple(GilButton::Unknown)),
477            GameInput::ZoomLock => Some(Button::Simple(GilButton::Unknown)),
478            GameInput::CameraClamp => Some(Button::Simple(GilButton::Unknown)),
479            GameInput::CycleCamera => Some(Button::Simple(GilButton::Unknown)),
480            GameInput::Select => Some(Button::Simple(GilButton::Unknown)),
481            GameInput::AcceptGroupInvite => Some(Button::Simple(GilButton::Unknown)),
482            GameInput::DeclineGroupInvite => Some(Button::Simple(GilButton::Unknown)),
483            GameInput::MapZoomIn => Some(Button::Simple(GilButton::Unknown)),
484            GameInput::MapZoomOut => Some(Button::Simple(GilButton::Unknown)),
485            GameInput::MapSetMarker => Some(Button::Simple(GilButton::Unknown)),
486            GameInput::SpectateSpeedBoost => Some(Button::Simple(GilButton::Unknown)),
487            GameInput::SpectateViewpoint => Some(Button::Simple(GilButton::Unknown)),
488            GameInput::MuteMaster => Some(Button::Simple(GilButton::Unknown)),
489            GameInput::MuteInactiveMaster => Some(Button::Simple(GilButton::Unknown)),
490            GameInput::MuteMusic => Some(Button::Simple(GilButton::Unknown)),
491            GameInput::MuteSfx => Some(Button::Simple(GilButton::Unknown)),
492            GameInput::MuteAmbience => Some(Button::Simple(GilButton::Unknown)),
493            GameInput::ToggleWalk => Some(Button::Simple(GilButton::Unknown)),
494        }
495    }
496
497    pub fn default_layer_binding(layer_input: GameInput) -> Option<LayerEntry> {
498        match layer_input {
499            GameInput::Primary => Some(LayerEntry {
500                button: Button::Simple(GilButton::Unknown),
501                mod1: Button::Simple(GilButton::Unknown),
502                mod2: Button::Simple(GilButton::Unknown),
503            }),
504            GameInput::Secondary => Some(LayerEntry {
505                button: Button::Simple(GilButton::Unknown),
506                mod1: Button::Simple(GilButton::Unknown),
507                mod2: Button::Simple(GilButton::Unknown),
508            }),
509            GameInput::Block => Some(LayerEntry {
510                button: Button::Simple(GilButton::Unknown),
511                mod1: Button::Simple(GilButton::Unknown),
512                mod2: Button::Simple(GilButton::Unknown),
513            }),
514            GameInput::Slot1 => Some(LayerEntry {
515                button: Button::Simple(GilButton::Unknown),
516                mod1: Button::Simple(GilButton::Unknown),
517                mod2: Button::Simple(GilButton::Unknown),
518            }),
519            GameInput::Slot2 => Some(LayerEntry {
520                button: Button::Simple(GilButton::Unknown),
521                mod1: Button::Simple(GilButton::Unknown),
522                mod2: Button::Simple(GilButton::Unknown),
523            }),
524            GameInput::Slot3 => Some(LayerEntry {
525                button: Button::Simple(GilButton::Unknown),
526                mod1: Button::Simple(GilButton::Unknown),
527                mod2: Button::Simple(GilButton::Unknown),
528            }),
529            GameInput::Slot4 => Some(LayerEntry {
530                button: Button::Simple(GilButton::Unknown),
531                mod1: Button::Simple(GilButton::Unknown),
532                mod2: Button::Simple(GilButton::Unknown),
533            }),
534            GameInput::Slot5 => Some(LayerEntry {
535                button: Button::Simple(GilButton::Unknown),
536                mod1: Button::Simple(GilButton::Unknown),
537                mod2: Button::Simple(GilButton::Unknown),
538            }),
539            GameInput::Slot6 => Some(LayerEntry {
540                button: Button::Simple(GilButton::Unknown),
541                mod1: Button::Simple(GilButton::Unknown),
542                mod2: Button::Simple(GilButton::Unknown),
543            }),
544            GameInput::Slot7 => Some(LayerEntry {
545                button: Button::Simple(GilButton::Unknown),
546                mod1: Button::Simple(GilButton::Unknown),
547                mod2: Button::Simple(GilButton::Unknown),
548            }),
549            GameInput::Slot8 => Some(LayerEntry {
550                button: Button::Simple(GilButton::Unknown),
551                mod1: Button::Simple(GilButton::Unknown),
552                mod2: Button::Simple(GilButton::Unknown),
553            }),
554            GameInput::Slot9 => Some(LayerEntry {
555                button: Button::Simple(GilButton::Unknown),
556                mod1: Button::Simple(GilButton::Unknown),
557                mod2: Button::Simple(GilButton::Unknown),
558            }),
559            GameInput::Slot10 => Some(LayerEntry {
560                button: Button::Simple(GilButton::Unknown),
561                mod1: Button::Simple(GilButton::Unknown),
562                mod2: Button::Simple(GilButton::Unknown),
563            }),
564            GameInput::PreviousSlot => Some(LayerEntry {
565                button: Button::Simple(GilButton::West),
566                mod1: Button::Simple(GilButton::RightTrigger),
567                mod2: Button::Simple(GilButton::Unknown),
568            }),
569            GameInput::NextSlot => Some(LayerEntry {
570                button: Button::Simple(GilButton::East),
571                mod1: Button::Simple(GilButton::RightTrigger),
572                mod2: Button::Simple(GilButton::Unknown),
573            }),
574            GameInput::CurrentSlot => Some(LayerEntry {
575                button: Button::Simple(GilButton::Unknown),
576                mod1: Button::Simple(GilButton::Unknown),
577                mod2: Button::Simple(GilButton::Unknown),
578            }),
579            GameInput::ToggleCursor => Some(LayerEntry {
580                button: Button::Simple(GilButton::Unknown),
581                mod1: Button::Simple(GilButton::Unknown),
582                mod2: Button::Simple(GilButton::Unknown),
583            }),
584            GameInput::MoveForward => Some(LayerEntry {
585                button: Button::Simple(GilButton::Unknown),
586                mod1: Button::Simple(GilButton::Unknown),
587                mod2: Button::Simple(GilButton::Unknown),
588            }),
589            GameInput::MoveBack => Some(LayerEntry {
590                button: Button::Simple(GilButton::Unknown),
591                mod1: Button::Simple(GilButton::Unknown),
592                mod2: Button::Simple(GilButton::Unknown),
593            }),
594            GameInput::MoveLeft => Some(LayerEntry {
595                button: Button::Simple(GilButton::Unknown),
596                mod1: Button::Simple(GilButton::Unknown),
597                mod2: Button::Simple(GilButton::Unknown),
598            }),
599            GameInput::MoveRight => Some(LayerEntry {
600                button: Button::Simple(GilButton::Unknown),
601                mod1: Button::Simple(GilButton::Unknown),
602                mod2: Button::Simple(GilButton::Unknown),
603            }),
604            GameInput::Jump => Some(LayerEntry {
605                button: Button::Simple(GilButton::Unknown),
606                mod1: Button::Simple(GilButton::Unknown),
607                mod2: Button::Simple(GilButton::Unknown),
608            }),
609            GameInput::WallJump => Some(LayerEntry {
610                button: Button::Simple(GilButton::Unknown),
611                mod1: Button::Simple(GilButton::Unknown),
612                mod2: Button::Simple(GilButton::Unknown),
613            }),
614            GameInput::Sit => Some(LayerEntry {
615                button: Button::Simple(GilButton::DPadDown),
616                mod1: Button::Simple(GilButton::RightTrigger),
617                mod2: Button::Simple(GilButton::Unknown),
618            }),
619            GameInput::Crawl => Some(LayerEntry {
620                button: Button::Simple(GilButton::Unknown),
621                mod1: Button::Simple(GilButton::Unknown),
622                mod2: Button::Simple(GilButton::Unknown),
623            }),
624            GameInput::Dance => Some(LayerEntry {
625                button: Button::Simple(GilButton::Unknown),
626                mod1: Button::Simple(GilButton::Unknown),
627                mod2: Button::Simple(GilButton::Unknown),
628            }),
629            GameInput::Greet => Some(LayerEntry {
630                button: Button::Simple(GilButton::Unknown),
631                mod1: Button::Simple(GilButton::Unknown),
632                mod2: Button::Simple(GilButton::Unknown),
633            }),
634            GameInput::Glide => Some(LayerEntry {
635                button: Button::Simple(GilButton::Unknown),
636                mod1: Button::Simple(GilButton::Unknown),
637                mod2: Button::Simple(GilButton::Unknown),
638            }),
639            GameInput::SwimUp => Some(LayerEntry {
640                button: Button::Simple(GilButton::Unknown),
641                mod1: Button::Simple(GilButton::Unknown),
642                mod2: Button::Simple(GilButton::Unknown),
643            }),
644            GameInput::SwimDown => Some(LayerEntry {
645                button: Button::Simple(GilButton::Unknown),
646                mod1: Button::Simple(GilButton::Unknown),
647                mod2: Button::Simple(GilButton::Unknown),
648            }),
649            GameInput::Fly => Some(LayerEntry {
650                button: Button::Simple(GilButton::Unknown),
651                mod1: Button::Simple(GilButton::Unknown),
652                mod2: Button::Simple(GilButton::Unknown),
653            }),
654            GameInput::Sneak => Some(LayerEntry {
655                button: Button::Simple(GilButton::Unknown),
656                mod1: Button::Simple(GilButton::Unknown),
657                mod2: Button::Simple(GilButton::Unknown),
658            }),
659            GameInput::CancelClimb => Some(LayerEntry {
660                button: Button::Simple(GilButton::Unknown),
661                mod1: Button::Simple(GilButton::Unknown),
662                mod2: Button::Simple(GilButton::Unknown),
663            }),
664            GameInput::ToggleLantern => Some(LayerEntry {
665                button: Button::Simple(GilButton::DPadUp),
666                mod1: Button::Simple(GilButton::RightTrigger),
667                mod2: Button::Simple(GilButton::Unknown),
668            }),
669            GameInput::Mount => Some(LayerEntry {
670                button: Button::Simple(GilButton::Unknown),
671                mod1: Button::Simple(GilButton::Unknown),
672                mod2: Button::Simple(GilButton::Unknown),
673            }),
674            GameInput::StayFollow => Some(LayerEntry {
675                button: Button::Simple(GilButton::Unknown),
676                mod1: Button::Simple(GilButton::Unknown),
677                mod2: Button::Simple(GilButton::Unknown),
678            }),
679            GameInput::Chat => Some(LayerEntry {
680                button: Button::Simple(GilButton::Unknown),
681                mod1: Button::Simple(GilButton::Unknown),
682                mod2: Button::Simple(GilButton::Unknown),
683            }),
684            GameInput::Command => Some(LayerEntry {
685                button: Button::Simple(GilButton::Unknown),
686                mod1: Button::Simple(GilButton::Unknown),
687                mod2: Button::Simple(GilButton::Unknown),
688            }),
689            GameInput::Escape => Some(LayerEntry {
690                button: Button::Simple(GilButton::Unknown),
691                mod1: Button::Simple(GilButton::Unknown),
692                mod2: Button::Simple(GilButton::Unknown),
693            }),
694            GameInput::Map => Some(LayerEntry {
695                button: Button::Simple(GilButton::Unknown),
696                mod1: Button::Simple(GilButton::Unknown),
697                mod2: Button::Simple(GilButton::Unknown),
698            }),
699            GameInput::Inventory => Some(LayerEntry {
700                button: Button::Simple(GilButton::Unknown),
701                mod1: Button::Simple(GilButton::Unknown),
702                mod2: Button::Simple(GilButton::Unknown),
703            }),
704            GameInput::Trade => Some(LayerEntry {
705                button: Button::Simple(GilButton::North),
706                mod1: Button::Simple(GilButton::RightTrigger),
707                mod2: Button::Simple(GilButton::Unknown),
708            }),
709            GameInput::Social => Some(LayerEntry {
710                button: Button::Simple(GilButton::Unknown),
711                mod1: Button::Simple(GilButton::Unknown),
712                mod2: Button::Simple(GilButton::Unknown),
713            }),
714            GameInput::Crafting => Some(LayerEntry {
715                button: Button::Simple(GilButton::Unknown),
716                mod1: Button::Simple(GilButton::Unknown),
717                mod2: Button::Simple(GilButton::Unknown),
718            }),
719            GameInput::Diary => Some(LayerEntry {
720                button: Button::Simple(GilButton::Unknown),
721                mod1: Button::Simple(GilButton::Unknown),
722                mod2: Button::Simple(GilButton::Unknown),
723            }),
724            GameInput::Settings => Some(LayerEntry {
725                button: Button::Simple(GilButton::Unknown),
726                mod1: Button::Simple(GilButton::Unknown),
727                mod2: Button::Simple(GilButton::Unknown),
728            }),
729            GameInput::Controls => Some(LayerEntry {
730                button: Button::Simple(GilButton::Unknown),
731                mod1: Button::Simple(GilButton::Unknown),
732                mod2: Button::Simple(GilButton::Unknown),
733            }),
734            GameInput::ToggleInterface => Some(LayerEntry {
735                button: Button::Simple(GilButton::Unknown),
736                mod1: Button::Simple(GilButton::Unknown),
737                mod2: Button::Simple(GilButton::Unknown),
738            }),
739            GameInput::ToggleDebug => Some(LayerEntry {
740                button: Button::Simple(GilButton::Unknown),
741                mod1: Button::Simple(GilButton::Unknown),
742                mod2: Button::Simple(GilButton::Unknown),
743            }),
744            #[cfg(feature = "egui-ui")]
745            GameInput::ToggleEguiDebug => Some(LayerEntry {
746                button: Button::Simple(GilButton::Unknown),
747                mod1: Button::Simple(GilButton::Unknown),
748                mod2: Button::Simple(GilButton::Unknown),
749            }),
750            GameInput::ToggleChat => Some(LayerEntry {
751                button: Button::Simple(GilButton::Unknown),
752                mod1: Button::Simple(GilButton::Unknown),
753                mod2: Button::Simple(GilButton::Unknown),
754            }),
755            GameInput::Fullscreen => Some(LayerEntry {
756                button: Button::Simple(GilButton::Unknown),
757                mod1: Button::Simple(GilButton::Unknown),
758                mod2: Button::Simple(GilButton::Unknown),
759            }),
760            GameInput::Screenshot => Some(LayerEntry {
761                button: Button::Simple(GilButton::Unknown),
762                mod1: Button::Simple(GilButton::Unknown),
763                mod2: Button::Simple(GilButton::Unknown),
764            }),
765            GameInput::ToggleIngameUi => Some(LayerEntry {
766                button: Button::Simple(GilButton::Unknown),
767                mod1: Button::Simple(GilButton::Unknown),
768                mod2: Button::Simple(GilButton::Unknown),
769            }),
770            GameInput::Roll => Some(LayerEntry {
771                button: Button::Simple(GilButton::Unknown),
772                mod1: Button::Simple(GilButton::Unknown),
773                mod2: Button::Simple(GilButton::Unknown),
774            }),
775            GameInput::GiveUp => Some(LayerEntry {
776                button: Button::Simple(GilButton::Unknown),
777                mod1: Button::Simple(GilButton::Unknown),
778                mod2: Button::Simple(GilButton::Unknown),
779            }),
780            GameInput::Respawn => Some(LayerEntry {
781                button: Button::Simple(GilButton::Unknown),
782                mod1: Button::Simple(GilButton::Unknown),
783                mod2: Button::Simple(GilButton::Unknown),
784            }),
785            GameInput::Interact => Some(LayerEntry {
786                button: Button::Simple(GilButton::Unknown),
787                mod1: Button::Simple(GilButton::Unknown),
788                mod2: Button::Simple(GilButton::Unknown),
789            }),
790            GameInput::ToggleWield => Some(LayerEntry {
791                button: Button::Simple(GilButton::Unknown),
792                mod1: Button::Simple(GilButton::Unknown),
793                mod2: Button::Simple(GilButton::Unknown),
794            }),
795            GameInput::SwapLoadout => Some(LayerEntry {
796                button: Button::Simple(GilButton::Unknown),
797                mod1: Button::Simple(GilButton::Unknown),
798                mod2: Button::Simple(GilButton::Unknown),
799            }),
800            GameInput::FreeLook => Some(LayerEntry {
801                button: Button::Simple(GilButton::South),
802                mod1: Button::Simple(GilButton::RightTrigger),
803                mod2: Button::Simple(GilButton::Unknown),
804            }),
805            GameInput::AutoWalk => Some(LayerEntry {
806                button: Button::Simple(GilButton::Unknown),
807                mod1: Button::Simple(GilButton::Unknown),
808                mod2: Button::Simple(GilButton::Unknown),
809            }),
810            GameInput::ZoomIn => Some(LayerEntry {
811                button: Button::Simple(GilButton::Unknown),
812                mod1: Button::Simple(GilButton::Unknown),
813                mod2: Button::Simple(GilButton::Unknown),
814            }),
815            GameInput::ZoomOut => Some(LayerEntry {
816                button: Button::Simple(GilButton::Unknown),
817                mod1: Button::Simple(GilButton::Unknown),
818                mod2: Button::Simple(GilButton::Unknown),
819            }),
820            GameInput::ZoomLock => Some(LayerEntry {
821                button: Button::Simple(GilButton::Unknown),
822                mod1: Button::Simple(GilButton::Unknown),
823                mod2: Button::Simple(GilButton::Unknown),
824            }),
825            GameInput::CameraClamp => Some(LayerEntry {
826                button: Button::Simple(GilButton::Unknown),
827                mod1: Button::Simple(GilButton::Unknown),
828                mod2: Button::Simple(GilButton::Unknown),
829            }),
830            GameInput::CycleCamera => Some(LayerEntry {
831                button: Button::Simple(GilButton::Unknown),
832                mod1: Button::Simple(GilButton::Unknown),
833                mod2: Button::Simple(GilButton::Unknown),
834            }),
835            GameInput::Select => Some(LayerEntry {
836                button: Button::Simple(GilButton::Unknown),
837                mod1: Button::Simple(GilButton::Unknown),
838                mod2: Button::Simple(GilButton::Unknown),
839            }),
840            GameInput::AcceptGroupInvite => Some(LayerEntry {
841                button: Button::Simple(GilButton::DPadLeft),
842                mod1: Button::Simple(GilButton::RightTrigger),
843                mod2: Button::Simple(GilButton::Unknown),
844            }),
845            GameInput::DeclineGroupInvite => Some(LayerEntry {
846                button: Button::Simple(GilButton::DPadRight),
847                mod1: Button::Simple(GilButton::RightTrigger),
848                mod2: Button::Simple(GilButton::Unknown),
849            }),
850            GameInput::MapZoomIn => Some(LayerEntry {
851                button: Button::Simple(GilButton::Unknown),
852                mod1: Button::Simple(GilButton::Unknown),
853                mod2: Button::Simple(GilButton::Unknown),
854            }),
855            GameInput::MapZoomOut => Some(LayerEntry {
856                button: Button::Simple(GilButton::Unknown),
857                mod1: Button::Simple(GilButton::Unknown),
858                mod2: Button::Simple(GilButton::Unknown),
859            }),
860            GameInput::MapSetMarker => Some(LayerEntry {
861                button: Button::Simple(GilButton::Unknown),
862                mod1: Button::Simple(GilButton::Unknown),
863                mod2: Button::Simple(GilButton::Unknown),
864            }),
865            GameInput::SpectateSpeedBoost => Some(LayerEntry {
866                button: Button::Simple(GilButton::Unknown),
867                mod1: Button::Simple(GilButton::Unknown),
868                mod2: Button::Simple(GilButton::Unknown),
869            }),
870            GameInput::SpectateViewpoint => Some(LayerEntry {
871                button: Button::Simple(GilButton::Unknown),
872                mod1: Button::Simple(GilButton::Unknown),
873                mod2: Button::Simple(GilButton::Unknown),
874            }),
875            GameInput::MuteMaster => Some(LayerEntry {
876                button: Button::Simple(GilButton::Unknown),
877                mod1: Button::Simple(GilButton::Unknown),
878                mod2: Button::Simple(GilButton::Unknown),
879            }),
880            GameInput::MuteInactiveMaster => Some(LayerEntry {
881                button: Button::Simple(GilButton::Unknown),
882                mod1: Button::Simple(GilButton::Unknown),
883                mod2: Button::Simple(GilButton::Unknown),
884            }),
885            GameInput::MuteMusic => Some(LayerEntry {
886                button: Button::Simple(GilButton::Unknown),
887                mod1: Button::Simple(GilButton::Unknown),
888                mod2: Button::Simple(GilButton::Unknown),
889            }),
890            GameInput::MuteSfx => Some(LayerEntry {
891                button: Button::Simple(GilButton::Unknown),
892                mod1: Button::Simple(GilButton::Unknown),
893                mod2: Button::Simple(GilButton::Unknown),
894            }),
895            GameInput::MuteAmbience => Some(LayerEntry {
896                button: Button::Simple(GilButton::Unknown),
897                mod1: Button::Simple(GilButton::Unknown),
898                mod2: Button::Simple(GilButton::Unknown),
899            }),
900            GameInput::ToggleWalk => Some(LayerEntry {
901                button: Button::Simple(GilButton::Unknown),
902                mod1: Button::Simple(GilButton::Unknown),
903                mod2: Button::Simple(GilButton::Unknown),
904            }),
905        }
906    }
907
908    pub fn default_menu_button_binding(menu_input: MenuInput) -> Option<Button> {
909        match menu_input {
910            MenuInput::Up => Some(Button::Simple(GilButton::DPadUp)),
911            MenuInput::Down => Some(Button::Simple(GilButton::DPadDown)),
912            MenuInput::Left => Some(Button::Simple(GilButton::DPadLeft)),
913            MenuInput::Right => Some(Button::Simple(GilButton::DPadRight)),
914            MenuInput::ScrollUp => Some(Button::Simple(GilButton::Unknown)),
915            MenuInput::ScrollDown => Some(Button::Simple(GilButton::Unknown)),
916            MenuInput::ScrollLeft => Some(Button::Simple(GilButton::Unknown)),
917            MenuInput::ScrollRight => Some(Button::Simple(GilButton::Unknown)),
918            MenuInput::Home => Some(Button::Simple(GilButton::Unknown)),
919            MenuInput::End => Some(Button::Simple(GilButton::Unknown)),
920            MenuInput::Apply => Some(Button::Simple(GilButton::South)),
921            MenuInput::Back => Some(Button::Simple(GilButton::East)),
922            MenuInput::Exit => Some(Button::Simple(GilButton::Mode)),
923        }
924    }
925}
926
927impl Default for ControllerSettings {
928    fn default() -> Self {
929        let mut controller_settings = Self {
930            game_button_map: HashMap::new(),
931            inverse_game_button_map: HashMap::new(),
932            menu_button_map: HashMap::new(),
933            inverse_menu_button_map: HashMap::new(),
934            game_analog_button_map: HashMap::new(),
935            inverse_game_analog_button_map: HashMap::new(),
936            menu_analog_button_map: HashMap::new(),
937            inverse_menu_analog_button_map: HashMap::new(),
938            game_axis_map: HashMap::new(),
939            inverse_game_axis_map: HashMap::new(),
940            menu_axis_map: HashMap::new(),
941            inverse_menu_axis_map: HashMap::new(),
942            layer_button_map: HashMap::new(),
943            inverse_layer_button_map: HashMap::new(),
944
945            modifier_buttons: vec![
946                Button::Simple(GilButton::RightTrigger),
947                Button::Simple(GilButton::LeftTrigger),
948            ],
949            pan_sensitivity: 10,
950            pan_invert_y: false,
951            axis_deadzones: HashMap::new(),
952            button_deadzones: HashMap::new(),
953            mouse_emulation_sensitivity: 12,
954            inverted_axes: Vec::new(),
955        };
956        // sets the button bindings for game button inputs
957        for button_input in GameInput::iter() {
958            if let Some(default) = ControllerSettings::default_button_binding(button_input) {
959                controller_settings.insert_game_button_binding(button_input, default)
960            };
961        }
962        // sets the layer bindings for game layer inputs
963        for layer_input in GameInput::iter() {
964            if let Some(default) = ControllerSettings::default_layer_binding(layer_input) {
965                controller_settings.insert_layer_button_binding(layer_input, default);
966            };
967        }
968        // sets the menu button bindings for game menu button inputs
969        for button_input in MenuInput::iter() {
970            if let Some(default) = ControllerSettings::default_menu_button_binding(button_input) {
971                controller_settings.insert_menu_button_binding(button_input, default)
972            };
973        }
974        // sets the axis bindings for game axis inputs
975        for axis_input in AxisGameAction::iter() {
976            if let Some(default) = ControllerSettings::default_game_axis(axis_input) {
977                controller_settings.insert_game_axis_binding(axis_input, default)
978            };
979        }
980        // sets the axis bindings for menu axis inputs
981        for axis_input in AxisMenuAction::iter() {
982            if let Some(default) = ControllerSettings::default_menu_axis(axis_input) {
983                controller_settings.insert_menu_axis_binding(axis_input, default)
984            };
985        }
986        controller_settings
987    }
988}
989
990/// All the menu actions you can bind to an Axis
991#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, EnumIter)]
992pub enum AxisMenuAction {
993    MoveX,
994    MoveY,
995    ScrollX,
996    ScrollY,
997}
998
999/// All the game actions you can bind to an Axis
1000#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, EnumIter)]
1001pub enum AxisGameAction {
1002    MovementX,
1003    MovementY,
1004    CameraX,
1005    CameraY,
1006}
1007
1008/// All the menu actions you can bind to an analog button
1009#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1010pub enum AnalogButtonMenuAction {}
1011
1012/// All the game actions you can bind to an analog button
1013#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1014pub enum AnalogButtonGameAction {}
1015
1016/// Button::Simple(GilButton::Unknown) is invalid and equal to mapping an action
1017/// to nothing
1018#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1019pub enum Button {
1020    Simple(GilButton),
1021    EventCode(u32),
1022}
1023
1024impl Default for Button {
1025    fn default() -> Self { Button::Simple(GilButton::Unknown) }
1026}
1027
1028impl Button {
1029    // Returns button description (e.g Left Trigger)
1030    pub fn display_string(&self, localized_strings: &Localization) -> String {
1031        use self::Button::*;
1032        // This exists here to keep the string in scope after the match
1033        let button_string = match self {
1034            Simple(GilButton::South) => localized_strings.get_msg("gamepad-south").to_string(),
1035            Simple(GilButton::East) => localized_strings.get_msg("gamepad-east").to_string(),
1036            Simple(GilButton::North) => localized_strings.get_msg("gamepad-north").to_string(),
1037            Simple(GilButton::West) => localized_strings.get_msg("gamepad-west").to_string(),
1038            Simple(GilButton::C) => localized_strings.get_msg("gamepad-c").to_string(),
1039            Simple(GilButton::Z) => localized_strings.get_msg("gamepad-z").to_string(),
1040            Simple(GilButton::LeftTrigger) => localized_strings
1041                .get_msg("gamepad-left_trigger")
1042                .to_string(),
1043            Simple(GilButton::LeftTrigger2) => localized_strings
1044                .get_msg("gamepad-left_trigger_2")
1045                .to_string(),
1046            Simple(GilButton::RightTrigger) => localized_strings
1047                .get_msg("gamepad-right_trigger")
1048                .to_string(),
1049            Simple(GilButton::RightTrigger2) => localized_strings
1050                .get_msg("gamepad-right_trigger_2")
1051                .to_string(),
1052            Simple(GilButton::Select) => localized_strings.get_msg("gamepad-select").to_string(),
1053            Simple(GilButton::Start) => localized_strings.get_msg("gamepad-start").to_string(),
1054            Simple(GilButton::Mode) => localized_strings.get_msg("gamepad-mode").to_string(),
1055            Simple(GilButton::LeftThumb) => {
1056                localized_strings.get_msg("gamepad-left_thumb").to_string()
1057            },
1058            Simple(GilButton::RightThumb) => {
1059                localized_strings.get_msg("gamepad-right_thumb").to_string()
1060            },
1061            Simple(GilButton::DPadUp) => localized_strings.get_msg("gamepad-dpad_up").to_string(),
1062            Simple(GilButton::DPadDown) => {
1063                localized_strings.get_msg("gamepad-dpad_down").to_string()
1064            },
1065            Simple(GilButton::DPadLeft) => {
1066                localized_strings.get_msg("gamepad-dpad_left").to_string()
1067            },
1068            Simple(GilButton::DPadRight) => {
1069                localized_strings.get_msg("gamepad-dpad_right").to_string()
1070            },
1071            Simple(GilButton::Unknown) => localized_strings.get_msg("gamepad-unknown").to_string(),
1072            EventCode(code) => code.to_string(),
1073        };
1074
1075        button_string.to_owned()
1076    }
1077
1078    // If it exists, returns the shortened version of a button name
1079    // (e.g. Left Trigger -> LT)
1080    pub fn try_shortened(&self) -> Option<String> {
1081        use self::Button::*;
1082        let button_string = match self {
1083            Simple(GilButton::South) => "A",
1084            Simple(GilButton::East) => "B",
1085            Simple(GilButton::North) => "Y",
1086            Simple(GilButton::West) => "X",
1087            Simple(GilButton::LeftTrigger) => "LB",
1088            Simple(GilButton::LeftTrigger2) => "LT",
1089            Simple(GilButton::RightTrigger) => "RB",
1090            Simple(GilButton::RightTrigger2) => "RT",
1091            Simple(GilButton::LeftThumb) => "L3",
1092            Simple(GilButton::RightThumb) => "R3",
1093            _ => return None,
1094        };
1095
1096        Some(button_string.to_owned())
1097    }
1098}
1099
1100// represents a controller button to fire a GameInput on
1101// includes two modifier buttons to determine what layer is active
1102#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
1103#[serde(default)]
1104pub struct LayerEntry {
1105    pub button: Button,
1106    pub mod1: Button,
1107    pub mod2: Button,
1108}
1109
1110impl Default for LayerEntry {
1111    fn default() -> Self {
1112        // binding to unknown = getting skipped from processing
1113        Self {
1114            button: Button::Simple(GilButton::Unknown),
1115            mod1: Button::Simple(GilButton::Unknown),
1116            mod2: Button::Simple(GilButton::Unknown),
1117        }
1118    }
1119}
1120
1121impl LayerEntry {
1122    pub fn display_string(&self, localized_strings: &Localization) -> String {
1123        use self::Button::*;
1124
1125        let mod1: Option<String> = match self.mod1 {
1126            Simple(GilButton::Unknown) => None,
1127            _ => self
1128                .mod1
1129                .try_shortened()
1130                .map_or(Some(self.mod1.display_string(localized_strings)), Some),
1131        };
1132        let mod2: Option<String> = match self.mod2 {
1133            Simple(GilButton::Unknown) => None,
1134            _ => self
1135                .mod2
1136                .try_shortened()
1137                .map_or(Some(self.mod2.display_string(localized_strings)), Some),
1138        };
1139
1140        format!(
1141            "{}{}{} {}",
1142            mod1.map_or("".to_owned(), |m1| format!("{} + ", m1)),
1143            mod2.map_or("".to_owned(), |m2| format!("{} + ", m2)),
1144            self.button.display_string(localized_strings),
1145            self.button
1146                .try_shortened()
1147                .map_or("".to_owned(), |short| format!("({})", short))
1148        )
1149    }
1150}
1151
1152/// AnalogButton::Simple(GilButton::Unknown) is invalid and equal to mapping an
1153/// action to nothing
1154#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1155pub enum AnalogButton {
1156    Simple(GilButton),
1157    EventCode(u32),
1158}
1159
1160impl Default for AnalogButton {
1161    fn default() -> Self { AnalogButton::Simple(GilButton::Unknown) }
1162}
1163
1164/// Axis::Simple(GilAxis::Unknown) is invalid and equal to mapping an action to
1165/// nothing
1166#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1167pub enum Axis {
1168    Simple(GilAxis),
1169    EventCode(u32),
1170}
1171
1172impl Default for Axis {
1173    fn default() -> Self { Axis::Simple(GilAxis::Unknown) }
1174}
1175
1176impl From<(GilAxis, GilCode)> for Axis {
1177    fn from((axis, code): (GilAxis, GilCode)) -> Self {
1178        match axis {
1179            GilAxis::Unknown => Self::EventCode(code.into_u32()),
1180            _ => Self::Simple(axis),
1181        }
1182    }
1183}
1184
1185impl From<(GilButton, GilCode)> for Button {
1186    fn from((button, code): (GilButton, GilCode)) -> Self {
1187        match button {
1188            GilButton::Unknown => Self::EventCode(code.into_u32()),
1189            _ => Self::Simple(button),
1190        }
1191    }
1192}
1193
1194impl From<(GilButton, GilCode)> for AnalogButton {
1195    fn from((button, code): (GilButton, GilCode)) -> Self {
1196        match button {
1197            GilButton::Unknown => Self::EventCode(code.into_u32()),
1198            _ => Self::Simple(button),
1199        }
1200    }
1201}