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::ToggleCursor => Some(Button::Simple(GilButton::Unknown)),
426            GameInput::MoveForward => Some(Button::Simple(GilButton::Unknown)),
427            GameInput::MoveBack => Some(Button::Simple(GilButton::Unknown)),
428            GameInput::MoveLeft => Some(Button::Simple(GilButton::Unknown)),
429            GameInput::MoveRight => Some(Button::Simple(GilButton::Unknown)),
430            GameInput::Jump => Some(Button::Simple(GilButton::South)),
431            GameInput::WallJump => Some(Button::Simple(GilButton::South)),
432            GameInput::Sit => Some(Button::Simple(GilButton::Unknown)),
433            GameInput::Crawl => Some(Button::Simple(GilButton::Unknown)),
434            GameInput::Dance => Some(Button::Simple(GilButton::Unknown)),
435            GameInput::Greet => Some(Button::Simple(GilButton::Unknown)),
436            GameInput::Glide => Some(Button::Simple(GilButton::DPadUp)),
437            GameInput::SwimUp => Some(Button::Simple(GilButton::South)),
438            GameInput::SwimDown => Some(Button::Simple(GilButton::West)),
439            GameInput::Fly => Some(Button::Simple(GilButton::Unknown)),
440            GameInput::Sneak => Some(Button::Simple(GilButton::LeftThumb)),
441            GameInput::CancelClimb => Some(Button::Simple(GilButton::East)),
442            GameInput::ToggleLantern => Some(Button::Simple(GilButton::Unknown)),
443            GameInput::Mount => Some(Button::Simple(GilButton::South)),
444            GameInput::StayFollow => Some(Button::Simple(GilButton::Unknown)),
445            GameInput::Chat => Some(Button::Simple(GilButton::Unknown)),
446            GameInput::Command => Some(Button::Simple(GilButton::Unknown)),
447            GameInput::Escape => Some(Button::Simple(GilButton::Start)),
448            GameInput::Map => Some(Button::Simple(GilButton::Select)),
449            GameInput::Inventory => Some(Button::Simple(GilButton::DPadRight)),
450            GameInput::Trade => Some(Button::Simple(GilButton::Unknown)),
451            GameInput::Social => Some(Button::Simple(GilButton::DPadLeft)),
452            GameInput::Crafting => Some(Button::Simple(GilButton::Unknown)),
453            GameInput::Diary => Some(Button::Simple(GilButton::Unknown)),
454            GameInput::Settings => Some(Button::Simple(GilButton::Unknown)),
455            GameInput::Controls => Some(Button::Simple(GilButton::Unknown)),
456            GameInput::ToggleInterface => Some(Button::Simple(GilButton::Unknown)),
457            GameInput::ToggleDebug => Some(Button::Simple(GilButton::Unknown)),
458            #[cfg(feature = "egui-ui")]
459            GameInput::ToggleEguiDebug => Some(Button::Simple(GilButton::Unknown)),
460            GameInput::ToggleChat => Some(Button::Simple(GilButton::Unknown)),
461            GameInput::Fullscreen => Some(Button::Simple(GilButton::Unknown)),
462            GameInput::Screenshot => Some(Button::Simple(GilButton::Unknown)),
463            GameInput::ToggleIngameUi => Some(Button::Simple(GilButton::Unknown)),
464            GameInput::Roll => Some(Button::Simple(GilButton::RightThumb)),
465            GameInput::GiveUp => Some(Button::Simple(GilButton::South)),
466            GameInput::Respawn => Some(Button::Simple(GilButton::South)),
467            GameInput::Interact => Some(Button::Simple(GilButton::West)),
468            GameInput::ToggleWield => Some(Button::Simple(GilButton::East)),
469            GameInput::SwapLoadout => Some(Button::Simple(GilButton::DPadDown)),
470            GameInput::FreeLook => Some(Button::Simple(GilButton::Unknown)),
471            GameInput::AutoWalk => Some(Button::Simple(GilButton::Unknown)),
472            GameInput::ZoomIn => Some(Button::Simple(GilButton::Unknown)),
473            GameInput::ZoomOut => Some(Button::Simple(GilButton::Unknown)),
474            GameInput::ZoomLock => Some(Button::Simple(GilButton::Unknown)),
475            GameInput::CameraClamp => Some(Button::Simple(GilButton::Unknown)),
476            GameInput::CycleCamera => Some(Button::Simple(GilButton::Unknown)),
477            GameInput::Select => Some(Button::Simple(GilButton::Unknown)),
478            GameInput::AcceptGroupInvite => Some(Button::Simple(GilButton::Unknown)),
479            GameInput::DeclineGroupInvite => Some(Button::Simple(GilButton::Unknown)),
480            GameInput::MapZoomIn => Some(Button::Simple(GilButton::Unknown)),
481            GameInput::MapZoomOut => Some(Button::Simple(GilButton::Unknown)),
482            GameInput::MapSetMarker => Some(Button::Simple(GilButton::Unknown)),
483            GameInput::SpectateSpeedBoost => Some(Button::Simple(GilButton::Unknown)),
484            GameInput::SpectateViewpoint => Some(Button::Simple(GilButton::Unknown)),
485            GameInput::MuteMaster => Some(Button::Simple(GilButton::Unknown)),
486            GameInput::MuteInactiveMaster => Some(Button::Simple(GilButton::Unknown)),
487            GameInput::MuteMusic => Some(Button::Simple(GilButton::Unknown)),
488            GameInput::MuteSfx => Some(Button::Simple(GilButton::Unknown)),
489            GameInput::MuteAmbience => Some(Button::Simple(GilButton::Unknown)),
490            GameInput::ToggleWalk => Some(Button::Simple(GilButton::Unknown)),
491        }
492    }
493
494    pub fn default_layer_binding(layer_input: GameInput) -> Option<LayerEntry> {
495        match layer_input {
496            GameInput::Primary => Some(LayerEntry {
497                button: Button::Simple(GilButton::Unknown),
498                mod1: Button::Simple(GilButton::Unknown),
499                mod2: Button::Simple(GilButton::Unknown),
500            }),
501            GameInput::Secondary => Some(LayerEntry {
502                button: Button::Simple(GilButton::Unknown),
503                mod1: Button::Simple(GilButton::Unknown),
504                mod2: Button::Simple(GilButton::Unknown),
505            }),
506            GameInput::Block => Some(LayerEntry {
507                button: Button::Simple(GilButton::Unknown),
508                mod1: Button::Simple(GilButton::Unknown),
509                mod2: Button::Simple(GilButton::Unknown),
510            }),
511            GameInput::Slot1 => Some(LayerEntry {
512                button: Button::Simple(GilButton::Unknown),
513                mod1: Button::Simple(GilButton::Unknown),
514                mod2: Button::Simple(GilButton::Unknown),
515            }),
516            GameInput::Slot2 => Some(LayerEntry {
517                button: Button::Simple(GilButton::Unknown),
518                mod1: Button::Simple(GilButton::Unknown),
519                mod2: Button::Simple(GilButton::Unknown),
520            }),
521            GameInput::Slot3 => Some(LayerEntry {
522                button: Button::Simple(GilButton::Unknown),
523                mod1: Button::Simple(GilButton::Unknown),
524                mod2: Button::Simple(GilButton::Unknown),
525            }),
526            GameInput::Slot4 => Some(LayerEntry {
527                button: Button::Simple(GilButton::Unknown),
528                mod1: Button::Simple(GilButton::Unknown),
529                mod2: Button::Simple(GilButton::Unknown),
530            }),
531            GameInput::Slot5 => Some(LayerEntry {
532                button: Button::Simple(GilButton::Unknown),
533                mod1: Button::Simple(GilButton::Unknown),
534                mod2: Button::Simple(GilButton::Unknown),
535            }),
536            GameInput::Slot6 => Some(LayerEntry {
537                button: Button::Simple(GilButton::Unknown),
538                mod1: Button::Simple(GilButton::Unknown),
539                mod2: Button::Simple(GilButton::Unknown),
540            }),
541            GameInput::Slot7 => Some(LayerEntry {
542                button: Button::Simple(GilButton::Unknown),
543                mod1: Button::Simple(GilButton::Unknown),
544                mod2: Button::Simple(GilButton::Unknown),
545            }),
546            GameInput::Slot8 => Some(LayerEntry {
547                button: Button::Simple(GilButton::Unknown),
548                mod1: Button::Simple(GilButton::Unknown),
549                mod2: Button::Simple(GilButton::Unknown),
550            }),
551            GameInput::Slot9 => Some(LayerEntry {
552                button: Button::Simple(GilButton::Unknown),
553                mod1: Button::Simple(GilButton::Unknown),
554                mod2: Button::Simple(GilButton::Unknown),
555            }),
556            GameInput::Slot10 => Some(LayerEntry {
557                button: Button::Simple(GilButton::Unknown),
558                mod1: Button::Simple(GilButton::Unknown),
559                mod2: Button::Simple(GilButton::Unknown),
560            }),
561            GameInput::ToggleCursor => Some(LayerEntry {
562                button: Button::Simple(GilButton::Unknown),
563                mod1: Button::Simple(GilButton::Unknown),
564                mod2: Button::Simple(GilButton::Unknown),
565            }),
566            GameInput::MoveForward => Some(LayerEntry {
567                button: Button::Simple(GilButton::Unknown),
568                mod1: Button::Simple(GilButton::Unknown),
569                mod2: Button::Simple(GilButton::Unknown),
570            }),
571            GameInput::MoveBack => Some(LayerEntry {
572                button: Button::Simple(GilButton::Unknown),
573                mod1: Button::Simple(GilButton::Unknown),
574                mod2: Button::Simple(GilButton::Unknown),
575            }),
576            GameInput::MoveLeft => Some(LayerEntry {
577                button: Button::Simple(GilButton::Unknown),
578                mod1: Button::Simple(GilButton::Unknown),
579                mod2: Button::Simple(GilButton::Unknown),
580            }),
581            GameInput::MoveRight => Some(LayerEntry {
582                button: Button::Simple(GilButton::Unknown),
583                mod1: Button::Simple(GilButton::Unknown),
584                mod2: Button::Simple(GilButton::Unknown),
585            }),
586            GameInput::Jump => Some(LayerEntry {
587                button: Button::Simple(GilButton::Unknown),
588                mod1: Button::Simple(GilButton::Unknown),
589                mod2: Button::Simple(GilButton::Unknown),
590            }),
591            GameInput::WallJump => Some(LayerEntry {
592                button: Button::Simple(GilButton::Unknown),
593                mod1: Button::Simple(GilButton::Unknown),
594                mod2: Button::Simple(GilButton::Unknown),
595            }),
596            GameInput::Sit => Some(LayerEntry {
597                button: Button::Simple(GilButton::DPadDown),
598                mod1: Button::Simple(GilButton::RightTrigger),
599                mod2: Button::Simple(GilButton::Unknown),
600            }),
601            GameInput::Crawl => Some(LayerEntry {
602                button: Button::Simple(GilButton::Unknown),
603                mod1: Button::Simple(GilButton::Unknown),
604                mod2: Button::Simple(GilButton::Unknown),
605            }),
606            GameInput::Dance => Some(LayerEntry {
607                button: Button::Simple(GilButton::Unknown),
608                mod1: Button::Simple(GilButton::Unknown),
609                mod2: Button::Simple(GilButton::Unknown),
610            }),
611            GameInput::Greet => Some(LayerEntry {
612                button: Button::Simple(GilButton::Unknown),
613                mod1: Button::Simple(GilButton::Unknown),
614                mod2: Button::Simple(GilButton::Unknown),
615            }),
616            GameInput::Glide => Some(LayerEntry {
617                button: Button::Simple(GilButton::Unknown),
618                mod1: Button::Simple(GilButton::Unknown),
619                mod2: Button::Simple(GilButton::Unknown),
620            }),
621            GameInput::SwimUp => Some(LayerEntry {
622                button: Button::Simple(GilButton::Unknown),
623                mod1: Button::Simple(GilButton::Unknown),
624                mod2: Button::Simple(GilButton::Unknown),
625            }),
626            GameInput::SwimDown => Some(LayerEntry {
627                button: Button::Simple(GilButton::Unknown),
628                mod1: Button::Simple(GilButton::Unknown),
629                mod2: Button::Simple(GilButton::Unknown),
630            }),
631            GameInput::Fly => Some(LayerEntry {
632                button: Button::Simple(GilButton::Unknown),
633                mod1: Button::Simple(GilButton::Unknown),
634                mod2: Button::Simple(GilButton::Unknown),
635            }),
636            GameInput::Sneak => Some(LayerEntry {
637                button: Button::Simple(GilButton::Unknown),
638                mod1: Button::Simple(GilButton::Unknown),
639                mod2: Button::Simple(GilButton::Unknown),
640            }),
641            GameInput::CancelClimb => Some(LayerEntry {
642                button: Button::Simple(GilButton::Unknown),
643                mod1: Button::Simple(GilButton::Unknown),
644                mod2: Button::Simple(GilButton::Unknown),
645            }),
646            GameInput::ToggleLantern => Some(LayerEntry {
647                button: Button::Simple(GilButton::DPadUp),
648                mod1: Button::Simple(GilButton::RightTrigger),
649                mod2: Button::Simple(GilButton::Unknown),
650            }),
651            GameInput::Mount => Some(LayerEntry {
652                button: Button::Simple(GilButton::Unknown),
653                mod1: Button::Simple(GilButton::Unknown),
654                mod2: Button::Simple(GilButton::Unknown),
655            }),
656            GameInput::StayFollow => Some(LayerEntry {
657                button: Button::Simple(GilButton::Unknown),
658                mod1: Button::Simple(GilButton::Unknown),
659                mod2: Button::Simple(GilButton::Unknown),
660            }),
661            GameInput::Chat => Some(LayerEntry {
662                button: Button::Simple(GilButton::Unknown),
663                mod1: Button::Simple(GilButton::Unknown),
664                mod2: Button::Simple(GilButton::Unknown),
665            }),
666            GameInput::Command => Some(LayerEntry {
667                button: Button::Simple(GilButton::Unknown),
668                mod1: Button::Simple(GilButton::Unknown),
669                mod2: Button::Simple(GilButton::Unknown),
670            }),
671            GameInput::Escape => Some(LayerEntry {
672                button: Button::Simple(GilButton::Unknown),
673                mod1: Button::Simple(GilButton::Unknown),
674                mod2: Button::Simple(GilButton::Unknown),
675            }),
676            GameInput::Map => Some(LayerEntry {
677                button: Button::Simple(GilButton::Unknown),
678                mod1: Button::Simple(GilButton::Unknown),
679                mod2: Button::Simple(GilButton::Unknown),
680            }),
681            GameInput::Inventory => Some(LayerEntry {
682                button: Button::Simple(GilButton::Unknown),
683                mod1: Button::Simple(GilButton::Unknown),
684                mod2: Button::Simple(GilButton::Unknown),
685            }),
686            GameInput::Trade => Some(LayerEntry {
687                button: Button::Simple(GilButton::North),
688                mod1: Button::Simple(GilButton::RightTrigger),
689                mod2: Button::Simple(GilButton::Unknown),
690            }),
691            GameInput::Social => Some(LayerEntry {
692                button: Button::Simple(GilButton::Unknown),
693                mod1: Button::Simple(GilButton::Unknown),
694                mod2: Button::Simple(GilButton::Unknown),
695            }),
696            GameInput::Crafting => Some(LayerEntry {
697                button: Button::Simple(GilButton::Unknown),
698                mod1: Button::Simple(GilButton::Unknown),
699                mod2: Button::Simple(GilButton::Unknown),
700            }),
701            GameInput::Diary => Some(LayerEntry {
702                button: Button::Simple(GilButton::Unknown),
703                mod1: Button::Simple(GilButton::Unknown),
704                mod2: Button::Simple(GilButton::Unknown),
705            }),
706            GameInput::Settings => Some(LayerEntry {
707                button: Button::Simple(GilButton::Unknown),
708                mod1: Button::Simple(GilButton::Unknown),
709                mod2: Button::Simple(GilButton::Unknown),
710            }),
711            GameInput::Controls => Some(LayerEntry {
712                button: Button::Simple(GilButton::Unknown),
713                mod1: Button::Simple(GilButton::Unknown),
714                mod2: Button::Simple(GilButton::Unknown),
715            }),
716            GameInput::ToggleInterface => Some(LayerEntry {
717                button: Button::Simple(GilButton::Unknown),
718                mod1: Button::Simple(GilButton::Unknown),
719                mod2: Button::Simple(GilButton::Unknown),
720            }),
721            GameInput::ToggleDebug => Some(LayerEntry {
722                button: Button::Simple(GilButton::Unknown),
723                mod1: Button::Simple(GilButton::Unknown),
724                mod2: Button::Simple(GilButton::Unknown),
725            }),
726            #[cfg(feature = "egui-ui")]
727            GameInput::ToggleEguiDebug => Some(LayerEntry {
728                button: Button::Simple(GilButton::Unknown),
729                mod1: Button::Simple(GilButton::Unknown),
730                mod2: Button::Simple(GilButton::Unknown),
731            }),
732            GameInput::ToggleChat => Some(LayerEntry {
733                button: Button::Simple(GilButton::Unknown),
734                mod1: Button::Simple(GilButton::Unknown),
735                mod2: Button::Simple(GilButton::Unknown),
736            }),
737            GameInput::Fullscreen => Some(LayerEntry {
738                button: Button::Simple(GilButton::Unknown),
739                mod1: Button::Simple(GilButton::Unknown),
740                mod2: Button::Simple(GilButton::Unknown),
741            }),
742            GameInput::Screenshot => Some(LayerEntry {
743                button: Button::Simple(GilButton::Unknown),
744                mod1: Button::Simple(GilButton::Unknown),
745                mod2: Button::Simple(GilButton::Unknown),
746            }),
747            GameInput::ToggleIngameUi => Some(LayerEntry {
748                button: Button::Simple(GilButton::Unknown),
749                mod1: Button::Simple(GilButton::Unknown),
750                mod2: Button::Simple(GilButton::Unknown),
751            }),
752            GameInput::Roll => Some(LayerEntry {
753                button: Button::Simple(GilButton::Unknown),
754                mod1: Button::Simple(GilButton::Unknown),
755                mod2: Button::Simple(GilButton::Unknown),
756            }),
757            GameInput::GiveUp => Some(LayerEntry {
758                button: Button::Simple(GilButton::Unknown),
759                mod1: Button::Simple(GilButton::Unknown),
760                mod2: Button::Simple(GilButton::Unknown),
761            }),
762            GameInput::Respawn => Some(LayerEntry {
763                button: Button::Simple(GilButton::Unknown),
764                mod1: Button::Simple(GilButton::Unknown),
765                mod2: Button::Simple(GilButton::Unknown),
766            }),
767            GameInput::Interact => Some(LayerEntry {
768                button: Button::Simple(GilButton::Unknown),
769                mod1: Button::Simple(GilButton::Unknown),
770                mod2: Button::Simple(GilButton::Unknown),
771            }),
772            GameInput::ToggleWield => Some(LayerEntry {
773                button: Button::Simple(GilButton::Unknown),
774                mod1: Button::Simple(GilButton::Unknown),
775                mod2: Button::Simple(GilButton::Unknown),
776            }),
777            GameInput::SwapLoadout => Some(LayerEntry {
778                button: Button::Simple(GilButton::Unknown),
779                mod1: Button::Simple(GilButton::Unknown),
780                mod2: Button::Simple(GilButton::Unknown),
781            }),
782            GameInput::FreeLook => Some(LayerEntry {
783                button: Button::Simple(GilButton::South),
784                mod1: Button::Simple(GilButton::RightTrigger),
785                mod2: Button::Simple(GilButton::Unknown),
786            }),
787            GameInput::AutoWalk => Some(LayerEntry {
788                button: Button::Simple(GilButton::Unknown),
789                mod1: Button::Simple(GilButton::Unknown),
790                mod2: Button::Simple(GilButton::Unknown),
791            }),
792            GameInput::ZoomIn => Some(LayerEntry {
793                button: Button::Simple(GilButton::Unknown),
794                mod1: Button::Simple(GilButton::Unknown),
795                mod2: Button::Simple(GilButton::Unknown),
796            }),
797            GameInput::ZoomOut => Some(LayerEntry {
798                button: Button::Simple(GilButton::Unknown),
799                mod1: Button::Simple(GilButton::Unknown),
800                mod2: Button::Simple(GilButton::Unknown),
801            }),
802            GameInput::ZoomLock => Some(LayerEntry {
803                button: Button::Simple(GilButton::Unknown),
804                mod1: Button::Simple(GilButton::Unknown),
805                mod2: Button::Simple(GilButton::Unknown),
806            }),
807            GameInput::CameraClamp => Some(LayerEntry {
808                button: Button::Simple(GilButton::Unknown),
809                mod1: Button::Simple(GilButton::Unknown),
810                mod2: Button::Simple(GilButton::Unknown),
811            }),
812            GameInput::CycleCamera => Some(LayerEntry {
813                button: Button::Simple(GilButton::Unknown),
814                mod1: Button::Simple(GilButton::Unknown),
815                mod2: Button::Simple(GilButton::Unknown),
816            }),
817            GameInput::Select => Some(LayerEntry {
818                button: Button::Simple(GilButton::Unknown),
819                mod1: Button::Simple(GilButton::Unknown),
820                mod2: Button::Simple(GilButton::Unknown),
821            }),
822            GameInput::AcceptGroupInvite => Some(LayerEntry {
823                button: Button::Simple(GilButton::DPadLeft),
824                mod1: Button::Simple(GilButton::RightTrigger),
825                mod2: Button::Simple(GilButton::Unknown),
826            }),
827            GameInput::DeclineGroupInvite => Some(LayerEntry {
828                button: Button::Simple(GilButton::DPadRight),
829                mod1: Button::Simple(GilButton::RightTrigger),
830                mod2: Button::Simple(GilButton::Unknown),
831            }),
832            GameInput::MapZoomIn => Some(LayerEntry {
833                button: Button::Simple(GilButton::Unknown),
834                mod1: Button::Simple(GilButton::Unknown),
835                mod2: Button::Simple(GilButton::Unknown),
836            }),
837            GameInput::MapZoomOut => Some(LayerEntry {
838                button: Button::Simple(GilButton::Unknown),
839                mod1: Button::Simple(GilButton::Unknown),
840                mod2: Button::Simple(GilButton::Unknown),
841            }),
842            GameInput::MapSetMarker => Some(LayerEntry {
843                button: Button::Simple(GilButton::Unknown),
844                mod1: Button::Simple(GilButton::Unknown),
845                mod2: Button::Simple(GilButton::Unknown),
846            }),
847            GameInput::SpectateSpeedBoost => Some(LayerEntry {
848                button: Button::Simple(GilButton::Unknown),
849                mod1: Button::Simple(GilButton::Unknown),
850                mod2: Button::Simple(GilButton::Unknown),
851            }),
852            GameInput::SpectateViewpoint => Some(LayerEntry {
853                button: Button::Simple(GilButton::Unknown),
854                mod1: Button::Simple(GilButton::Unknown),
855                mod2: Button::Simple(GilButton::Unknown),
856            }),
857            GameInput::MuteMaster => Some(LayerEntry {
858                button: Button::Simple(GilButton::Unknown),
859                mod1: Button::Simple(GilButton::Unknown),
860                mod2: Button::Simple(GilButton::Unknown),
861            }),
862            GameInput::MuteInactiveMaster => Some(LayerEntry {
863                button: Button::Simple(GilButton::Unknown),
864                mod1: Button::Simple(GilButton::Unknown),
865                mod2: Button::Simple(GilButton::Unknown),
866            }),
867            GameInput::MuteMusic => Some(LayerEntry {
868                button: Button::Simple(GilButton::Unknown),
869                mod1: Button::Simple(GilButton::Unknown),
870                mod2: Button::Simple(GilButton::Unknown),
871            }),
872            GameInput::MuteSfx => Some(LayerEntry {
873                button: Button::Simple(GilButton::Unknown),
874                mod1: Button::Simple(GilButton::Unknown),
875                mod2: Button::Simple(GilButton::Unknown),
876            }),
877            GameInput::MuteAmbience => Some(LayerEntry {
878                button: Button::Simple(GilButton::Unknown),
879                mod1: Button::Simple(GilButton::Unknown),
880                mod2: Button::Simple(GilButton::Unknown),
881            }),
882            GameInput::ToggleWalk => Some(LayerEntry {
883                button: Button::Simple(GilButton::Unknown),
884                mod1: Button::Simple(GilButton::Unknown),
885                mod2: Button::Simple(GilButton::Unknown),
886            }),
887        }
888    }
889
890    pub fn default_menu_button_binding(menu_input: MenuInput) -> Option<Button> {
891        match menu_input {
892            MenuInput::Up => Some(Button::Simple(GilButton::DPadUp)),
893            MenuInput::Down => Some(Button::Simple(GilButton::DPadDown)),
894            MenuInput::Left => Some(Button::Simple(GilButton::DPadLeft)),
895            MenuInput::Right => Some(Button::Simple(GilButton::DPadRight)),
896            MenuInput::ScrollUp => Some(Button::Simple(GilButton::Unknown)),
897            MenuInput::ScrollDown => Some(Button::Simple(GilButton::Unknown)),
898            MenuInput::ScrollLeft => Some(Button::Simple(GilButton::Unknown)),
899            MenuInput::ScrollRight => Some(Button::Simple(GilButton::Unknown)),
900            MenuInput::Home => Some(Button::Simple(GilButton::Unknown)),
901            MenuInput::End => Some(Button::Simple(GilButton::Unknown)),
902            MenuInput::Apply => Some(Button::Simple(GilButton::South)),
903            MenuInput::Back => Some(Button::Simple(GilButton::East)),
904            MenuInput::Exit => Some(Button::Simple(GilButton::Mode)),
905        }
906    }
907}
908
909impl Default for ControllerSettings {
910    fn default() -> Self {
911        let mut controller_settings = Self {
912            game_button_map: HashMap::new(),
913            inverse_game_button_map: HashMap::new(),
914            menu_button_map: HashMap::new(),
915            inverse_menu_button_map: HashMap::new(),
916            game_analog_button_map: HashMap::new(),
917            inverse_game_analog_button_map: HashMap::new(),
918            menu_analog_button_map: HashMap::new(),
919            inverse_menu_analog_button_map: HashMap::new(),
920            game_axis_map: HashMap::new(),
921            inverse_game_axis_map: HashMap::new(),
922            menu_axis_map: HashMap::new(),
923            inverse_menu_axis_map: HashMap::new(),
924            layer_button_map: HashMap::new(),
925            inverse_layer_button_map: HashMap::new(),
926
927            modifier_buttons: vec![
928                Button::Simple(GilButton::RightTrigger),
929                Button::Simple(GilButton::LeftTrigger),
930            ],
931            pan_sensitivity: 10,
932            pan_invert_y: false,
933            axis_deadzones: HashMap::new(),
934            button_deadzones: HashMap::new(),
935            mouse_emulation_sensitivity: 12,
936            inverted_axes: Vec::new(),
937        };
938        // sets the button bindings for game button inputs
939        for button_input in GameInput::iter() {
940            if let Some(default) = ControllerSettings::default_button_binding(button_input) {
941                controller_settings.insert_game_button_binding(button_input, default)
942            };
943        }
944        // sets the layer bindings for game layer inputs
945        for layer_input in GameInput::iter() {
946            if let Some(default) = ControllerSettings::default_layer_binding(layer_input) {
947                controller_settings.insert_layer_button_binding(layer_input, default);
948            };
949        }
950        // sets the menu button bindings for game menu button inputs
951        for button_input in MenuInput::iter() {
952            if let Some(default) = ControllerSettings::default_menu_button_binding(button_input) {
953                controller_settings.insert_menu_button_binding(button_input, default)
954            };
955        }
956        // sets the axis bindings for game axis inputs
957        for axis_input in AxisGameAction::iter() {
958            if let Some(default) = ControllerSettings::default_game_axis(axis_input) {
959                controller_settings.insert_game_axis_binding(axis_input, default)
960            };
961        }
962        // sets the axis bindings for menu axis inputs
963        for axis_input in AxisMenuAction::iter() {
964            if let Some(default) = ControllerSettings::default_menu_axis(axis_input) {
965                controller_settings.insert_menu_axis_binding(axis_input, default)
966            };
967        }
968        controller_settings
969    }
970}
971
972/// All the menu actions you can bind to an Axis
973#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, EnumIter)]
974pub enum AxisMenuAction {
975    MoveX,
976    MoveY,
977    ScrollX,
978    ScrollY,
979}
980
981/// All the game actions you can bind to an Axis
982#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, EnumIter)]
983pub enum AxisGameAction {
984    MovementX,
985    MovementY,
986    CameraX,
987    CameraY,
988}
989
990/// All the menu actions you can bind to an analog button
991#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
992pub enum AnalogButtonMenuAction {}
993
994/// All the game actions you can bind to an analog button
995#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
996pub enum AnalogButtonGameAction {}
997
998/// Button::Simple(GilButton::Unknown) is invalid and equal to mapping an action
999/// to nothing
1000#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1001pub enum Button {
1002    Simple(GilButton),
1003    EventCode(u32),
1004}
1005
1006impl Default for Button {
1007    fn default() -> Self { Button::Simple(GilButton::Unknown) }
1008}
1009
1010impl Button {
1011    // Returns button description (e.g Left Trigger)
1012    pub fn display_string(&self, localized_strings: &Localization) -> String {
1013        use self::Button::*;
1014        // This exists here to keep the string in scope after the match
1015        let button_string = match self {
1016            Simple(GilButton::South) => localized_strings.get_msg("gamepad-south").to_string(),
1017            Simple(GilButton::East) => localized_strings.get_msg("gamepad-east").to_string(),
1018            Simple(GilButton::North) => localized_strings.get_msg("gamepad-north").to_string(),
1019            Simple(GilButton::West) => localized_strings.get_msg("gamepad-west").to_string(),
1020            Simple(GilButton::C) => localized_strings.get_msg("gamepad-c").to_string(),
1021            Simple(GilButton::Z) => localized_strings.get_msg("gamepad-z").to_string(),
1022            Simple(GilButton::LeftTrigger) => localized_strings
1023                .get_msg("gamepad-left_trigger")
1024                .to_string(),
1025            Simple(GilButton::LeftTrigger2) => localized_strings
1026                .get_msg("gamepad-left_trigger_2")
1027                .to_string(),
1028            Simple(GilButton::RightTrigger) => localized_strings
1029                .get_msg("gamepad-right_trigger")
1030                .to_string(),
1031            Simple(GilButton::RightTrigger2) => localized_strings
1032                .get_msg("gamepad-right_trigger_2")
1033                .to_string(),
1034            Simple(GilButton::Select) => localized_strings.get_msg("gamepad-select").to_string(),
1035            Simple(GilButton::Start) => localized_strings.get_msg("gamepad-start").to_string(),
1036            Simple(GilButton::Mode) => localized_strings.get_msg("gamepad-mode").to_string(),
1037            Simple(GilButton::LeftThumb) => {
1038                localized_strings.get_msg("gamepad-left_thumb").to_string()
1039            },
1040            Simple(GilButton::RightThumb) => {
1041                localized_strings.get_msg("gamepad-right_thumb").to_string()
1042            },
1043            Simple(GilButton::DPadUp) => localized_strings.get_msg("gamepad-dpad_up").to_string(),
1044            Simple(GilButton::DPadDown) => {
1045                localized_strings.get_msg("gamepad-dpad_down").to_string()
1046            },
1047            Simple(GilButton::DPadLeft) => {
1048                localized_strings.get_msg("gamepad-dpad_left").to_string()
1049            },
1050            Simple(GilButton::DPadRight) => {
1051                localized_strings.get_msg("gamepad-dpad_right").to_string()
1052            },
1053            Simple(GilButton::Unknown) => localized_strings.get_msg("gamepad-unknown").to_string(),
1054            EventCode(code) => code.to_string(),
1055        };
1056
1057        button_string.to_owned()
1058    }
1059
1060    // If it exists, returns the shortened version of a button name
1061    // (e.g. Left Trigger -> LT)
1062    pub fn try_shortened(&self) -> Option<String> {
1063        use self::Button::*;
1064        let button_string = match self {
1065            Simple(GilButton::South) => "A",
1066            Simple(GilButton::East) => "B",
1067            Simple(GilButton::North) => "Y",
1068            Simple(GilButton::West) => "X",
1069            Simple(GilButton::LeftTrigger) => "LB",
1070            Simple(GilButton::LeftTrigger2) => "LT",
1071            Simple(GilButton::RightTrigger) => "RB",
1072            Simple(GilButton::RightTrigger2) => "RT",
1073            Simple(GilButton::LeftThumb) => "L3",
1074            Simple(GilButton::RightThumb) => "R3",
1075            _ => return None,
1076        };
1077
1078        Some(button_string.to_owned())
1079    }
1080}
1081
1082// represents a controller button to fire a GameInput on
1083// includes two modifier buttons to determine what layer is active
1084#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
1085#[serde(default)]
1086pub struct LayerEntry {
1087    pub button: Button,
1088    pub mod1: Button,
1089    pub mod2: Button,
1090}
1091
1092impl Default for LayerEntry {
1093    fn default() -> Self {
1094        // binding to unknown = getting skipped from processing
1095        Self {
1096            button: Button::Simple(GilButton::Unknown),
1097            mod1: Button::Simple(GilButton::Unknown),
1098            mod2: Button::Simple(GilButton::Unknown),
1099        }
1100    }
1101}
1102
1103impl LayerEntry {
1104    pub fn display_string(&self, localized_strings: &Localization) -> String {
1105        use self::Button::*;
1106
1107        let mod1: Option<String> = match self.mod1 {
1108            Simple(GilButton::Unknown) => None,
1109            _ => self
1110                .mod1
1111                .try_shortened()
1112                .map_or(Some(self.mod1.display_string(localized_strings)), Some),
1113        };
1114        let mod2: Option<String> = match self.mod2 {
1115            Simple(GilButton::Unknown) => None,
1116            _ => self
1117                .mod2
1118                .try_shortened()
1119                .map_or(Some(self.mod2.display_string(localized_strings)), Some),
1120        };
1121
1122        format!(
1123            "{}{}{} {}",
1124            mod1.map_or("".to_owned(), |m1| format!("{} + ", m1)),
1125            mod2.map_or("".to_owned(), |m2| format!("{} + ", m2)),
1126            self.button.display_string(localized_strings),
1127            self.button
1128                .try_shortened()
1129                .map_or("".to_owned(), |short| format!("({})", short))
1130        )
1131    }
1132}
1133
1134/// AnalogButton::Simple(GilButton::Unknown) is invalid and equal to mapping an
1135/// action to nothing
1136#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1137pub enum AnalogButton {
1138    Simple(GilButton),
1139    EventCode(u32),
1140}
1141
1142impl Default for AnalogButton {
1143    fn default() -> Self { AnalogButton::Simple(GilButton::Unknown) }
1144}
1145
1146/// Axis::Simple(GilAxis::Unknown) is invalid and equal to mapping an action to
1147/// nothing
1148#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
1149pub enum Axis {
1150    Simple(GilAxis),
1151    EventCode(u32),
1152}
1153
1154impl Default for Axis {
1155    fn default() -> Self { Axis::Simple(GilAxis::Unknown) }
1156}
1157
1158impl From<(GilAxis, GilCode)> for Axis {
1159    fn from((axis, code): (GilAxis, GilCode)) -> Self {
1160        match axis {
1161            GilAxis::Unknown => Self::EventCode(code.into_u32()),
1162            _ => Self::Simple(axis),
1163        }
1164    }
1165}
1166
1167impl From<(GilButton, GilCode)> for Button {
1168    fn from((button, code): (GilButton, GilCode)) -> Self {
1169        match button {
1170            GilButton::Unknown => Self::EventCode(code.into_u32()),
1171            _ => Self::Simple(button),
1172        }
1173    }
1174}
1175
1176impl From<(GilButton, GilCode)> for AnalogButton {
1177    fn from((button, code): (GilButton, GilCode)) -> Self {
1178        match button {
1179            GilButton::Unknown => Self::EventCode(code.into_u32()),
1180            _ => Self::Simple(button),
1181        }
1182    }
1183}