veloren_voxygen/
controller.rs

1//! Module containing controller-specific abstractions allowing complex
2//! keybindings
3
4use crate::{
5    game_input::GameInput, settings::gamepad::con_settings::LayerEntry, window::MenuInput,
6};
7use gilrs::{Axis as GilAxis, Button as GilButton, ev::Code as GilCode};
8use hashbrown::{HashMap, HashSet};
9use i18n::Localization;
10use serde::{Deserialize, Serialize};
11
12/// Contains all controller related settings and keymaps
13#[derive(Clone, Debug, Default)]
14pub struct ControllerSettings {
15    pub game_button_map: HashMap<GameInput, Button>,
16    pub inverse_game_button_map: HashMap<Button, HashSet<GameInput>>,
17    pub menu_button_map: HashMap<MenuInput, Button>,
18    pub inverse_menu_button_map: HashMap<Button, HashSet<MenuInput>>,
19    pub game_analog_button_map: HashMap<AnalogButtonGameAction, AnalogButton>,
20    pub inverse_game_analog_button_map: HashMap<AnalogButton, HashSet<AnalogButtonGameAction>>,
21    pub menu_analog_button_map: HashMap<AnalogButtonMenuAction, AnalogButton>,
22    pub inverse_menu_analog_button_map: HashMap<AnalogButton, HashSet<AnalogButtonMenuAction>>,
23    pub game_axis_map: HashMap<AxisGameAction, Axis>,
24    pub inverse_game_axis_map: HashMap<Axis, HashSet<AxisGameAction>>,
25    pub menu_axis_map: HashMap<AxisMenuAction, Axis>,
26    pub inverse_menu_axis_map: HashMap<Axis, HashSet<AxisMenuAction>>,
27    pub layer_button_map: HashMap<GameInput, LayerEntry>,
28    pub inverse_layer_button_map: HashMap<LayerEntry, HashSet<GameInput>>,
29    pub modifier_buttons: Vec<Button>,
30    pub pan_sensitivity: u32,
31    pub pan_invert_y: bool,
32    pub axis_deadzones: HashMap<Axis, f32>,
33    pub button_deadzones: HashMap<AnalogButton, f32>,
34    pub mouse_emulation_sensitivity: u32,
35    pub inverted_axes: Vec<Axis>,
36}
37
38impl ControllerSettings {
39    pub fn apply_axis_deadzone(&self, k: &Axis, input: f32) -> f32 {
40        let threshold = *self.axis_deadzones.get(k).unwrap_or(&0.2);
41
42        // This could be one comparison per handled event faster if threshold was
43        // guaranteed to fall into <0, 1) range
44        let input_abs = input.abs();
45        if input_abs <= threshold || threshold >= 1.0 {
46            0.0
47        } else if threshold <= 0.0 {
48            input
49        } else {
50            (input_abs - threshold) / (1.0 - threshold) * input.signum()
51        }
52    }
53
54    pub fn apply_button_deadzone(&self, k: &AnalogButton, input: f32) -> f32 {
55        let threshold = *self.button_deadzones.get(k).unwrap_or(&0.2);
56
57        // This could be one comparison per handled event faster if threshold was
58        // guaranteed to fall into <0, 1) range
59        if input <= threshold || threshold >= 1.0 {
60            0.0
61        } else if threshold <= 0.0 {
62            input
63        } else {
64            (input - threshold) / (1.0 - threshold)
65        }
66    }
67
68    pub fn get_game_button_binding(&self, input: GameInput) -> Option<Button> {
69        self.game_button_map.get(&input).copied()
70    }
71
72    pub fn get_menu_button_binding(&self, input: MenuInput) -> Option<Button> {
73        self.menu_button_map.get(&input).copied()
74    }
75
76    pub fn get_layer_button_binding(&self, input: GameInput) -> Option<LayerEntry> {
77        self.layer_button_map.get(&input).copied()
78    }
79
80    pub fn insert_game_button_binding(&mut self, game_input: GameInput, game_button: Button) {
81        if game_button != Button::default() {
82            self.game_button_map.insert(game_input, game_button);
83            self.inverse_game_button_map
84                .entry(game_button)
85                .or_default()
86                .insert(game_input);
87        }
88    }
89
90    pub fn insert_menu_button_binding(&mut self, menu_input: MenuInput, button: Button) {
91        if button != Button::default() {
92            self.menu_button_map.insert(menu_input, button);
93            self.inverse_menu_button_map
94                .entry(button)
95                .or_default()
96                .insert(menu_input);
97        }
98    }
99
100    pub fn insert_game_axis_binding(&mut self, input: AxisGameAction, axis: Axis) {
101        if axis != Axis::default() {
102            self.game_axis_map.insert(input, axis);
103            self.inverse_game_axis_map
104                .entry(axis)
105                .or_default()
106                .insert(input);
107        }
108    }
109
110    pub fn insert_menu_axis_binding(&mut self, input: AxisMenuAction, axis: Axis) {
111        if axis != Axis::default() {
112            self.menu_axis_map.insert(input, axis);
113            self.inverse_menu_axis_map
114                .entry(axis)
115                .or_default()
116                .insert(input);
117        }
118    }
119
120    pub fn insert_layer_button_binding(&mut self, input: GameInput, layer_entry: LayerEntry) {
121        if layer_entry != LayerEntry::default() {
122            self.layer_button_map.insert(input, layer_entry);
123            self.inverse_layer_button_map
124                .entry(layer_entry)
125                .or_default()
126                .insert(input);
127        }
128    }
129
130    /// Return true if this button is used for multiple GameInputs that aren't
131    /// expected to be safe to have bound to the same button at the same time
132    pub fn game_button_has_conflicting_bindings(&self, game_button: Button) -> bool {
133        if let Some(game_inputs) = self.inverse_game_button_map.get(&game_button) {
134            for a in game_inputs.iter() {
135                for b in game_inputs.iter() {
136                    if !GameInput::can_share_bindings(*a, *b) {
137                        return true;
138                    }
139                }
140            }
141
142            let layer_entry = LayerEntry {
143                button: game_button,
144                mod1: Button::Simple(GilButton::Unknown),
145                mod2: Button::Simple(GilButton::Unknown),
146            };
147            if let Some(layer_inputs) = self.inverse_layer_button_map.get(&layer_entry) {
148                for a in game_inputs.iter() {
149                    for b in layer_inputs.iter() {
150                        if !GameInput::can_share_bindings(*a, *b) {
151                            return true;
152                        }
153                    }
154                }
155            }
156        }
157        false
158    }
159
160    pub fn menu_button_has_conflicting_bindings(&self, menu_button: Button) -> bool {
161        self.inverse_menu_button_map
162            .get(&menu_button)
163            .is_some_and(|menu_inputs| menu_inputs.len() > 1)
164    }
165
166    /// Return true if this key is used for multiple GameInputs that aren't
167    /// expected to be safe to have bound to the same key at the same time
168    pub fn layer_entry_has_conflicting_bindings(&self, layer_entry: LayerEntry) -> bool {
169        if let Some(layer_inputs) = self.inverse_layer_button_map.get(&layer_entry) {
170            for a in layer_inputs.iter() {
171                for b in layer_inputs.iter() {
172                    if !GameInput::can_share_bindings(*a, *b) {
173                        return true;
174                    }
175                }
176            }
177
178            if layer_entry.mod1 == Button::Simple(GilButton::Unknown)
179                && layer_entry.mod2 == Button::Simple(GilButton::Unknown)
180            {
181                if let Some(game_inputs) = self.inverse_game_button_map.get(&layer_entry.button) {
182                    for a in layer_inputs.iter() {
183                        for b in game_inputs.iter() {
184                            if !GameInput::can_share_bindings(*a, *b) {
185                                return true;
186                            }
187                        }
188                    }
189                }
190            }
191        }
192        false
193    }
194}
195
196impl From<&crate::settings::GamepadSettings> for ControllerSettings {
197    fn from(settings: &crate::settings::GamepadSettings) -> Self {
198        let mut controller_settings: ControllerSettings = ControllerSettings::default();
199
200        controller_settings
201            .insert_game_button_binding(GameInput::Primary, settings.game_buttons.primary);
202        controller_settings
203            .insert_game_button_binding(GameInput::Secondary, settings.game_buttons.secondary);
204        controller_settings
205            .insert_game_button_binding(GameInput::Block, settings.game_buttons.block);
206        controller_settings
207            .insert_game_button_binding(GameInput::Slot1, settings.game_buttons.slot1);
208        controller_settings
209            .insert_game_button_binding(GameInput::Slot2, settings.game_buttons.slot2);
210        controller_settings
211            .insert_game_button_binding(GameInput::Slot3, settings.game_buttons.slot3);
212        controller_settings
213            .insert_game_button_binding(GameInput::Slot4, settings.game_buttons.slot4);
214        controller_settings
215            .insert_game_button_binding(GameInput::Slot5, settings.game_buttons.slot5);
216        controller_settings
217            .insert_game_button_binding(GameInput::Slot6, settings.game_buttons.slot6);
218        controller_settings
219            .insert_game_button_binding(GameInput::Slot7, settings.game_buttons.slot7);
220        controller_settings
221            .insert_game_button_binding(GameInput::Slot8, settings.game_buttons.slot8);
222        controller_settings
223            .insert_game_button_binding(GameInput::Slot9, settings.game_buttons.slot9);
224        controller_settings
225            .insert_game_button_binding(GameInput::Slot10, settings.game_buttons.slot10);
226        controller_settings.insert_game_button_binding(
227            GameInput::ToggleCursor,
228            settings.game_buttons.toggle_cursor,
229        );
230        controller_settings
231            .insert_game_button_binding(GameInput::Escape, settings.game_buttons.escape);
232        controller_settings
233            .insert_game_button_binding(GameInput::Chat, settings.game_buttons.enter);
234        controller_settings
235            .insert_game_button_binding(GameInput::Command, settings.game_buttons.command);
236        controller_settings
237            .insert_game_button_binding(GameInput::MoveForward, settings.game_buttons.move_forward);
238        controller_settings
239            .insert_game_button_binding(GameInput::MoveLeft, settings.game_buttons.move_left);
240        controller_settings
241            .insert_game_button_binding(GameInput::MoveBack, settings.game_buttons.move_back);
242        controller_settings
243            .insert_game_button_binding(GameInput::MoveRight, settings.game_buttons.move_right);
244        controller_settings.insert_game_button_binding(GameInput::Jump, settings.game_buttons.jump);
245        controller_settings.insert_game_button_binding(GameInput::Sit, settings.game_buttons.sit);
246        controller_settings
247            .insert_game_button_binding(GameInput::Dance, settings.game_buttons.dance);
248        controller_settings
249            .insert_game_button_binding(GameInput::Glide, settings.game_buttons.glide);
250        controller_settings
251            .insert_game_button_binding(GameInput::SwimUp, settings.game_buttons.swimup);
252        controller_settings
253            .insert_game_button_binding(GameInput::SwimDown, settings.game_buttons.swimdown);
254        controller_settings
255            .insert_game_button_binding(GameInput::Sneak, settings.game_buttons.sneak);
256        controller_settings.insert_game_button_binding(
257            GameInput::ToggleLantern,
258            settings.game_buttons.toggle_lantern,
259        );
260        controller_settings
261            .insert_game_button_binding(GameInput::Mount, settings.game_buttons.mount);
262        controller_settings.insert_game_button_binding(GameInput::Map, settings.game_buttons.map);
263        controller_settings
264            .insert_game_button_binding(GameInput::Inventory, settings.game_buttons.bag);
265        controller_settings
266            .insert_game_button_binding(GameInput::Social, settings.game_buttons.social);
267        controller_settings
268            .insert_game_button_binding(GameInput::Crafting, settings.game_buttons.crafting);
269        controller_settings
270            .insert_game_button_binding(GameInput::Diary, settings.game_buttons.diary);
271        controller_settings
272            .insert_game_button_binding(GameInput::Settings, settings.game_buttons.settings);
273        controller_settings
274            .insert_game_button_binding(GameInput::Controls, settings.game_buttons.controls);
275        controller_settings.insert_game_button_binding(
276            GameInput::ToggleInterface,
277            settings.game_buttons.toggle_interface,
278        );
279        controller_settings
280            .insert_game_button_binding(GameInput::ToggleDebug, settings.game_buttons.toggle_debug);
281        #[cfg(feature = "egui-ui")]
282        controller_settings.insert_game_button_binding(
283            GameInput::ToggleEguiDebug,
284            settings.game_buttons.toggle_debug,
285        );
286        controller_settings
287            .insert_game_button_binding(GameInput::ToggleChat, settings.game_buttons.toggle_chat);
288        controller_settings
289            .insert_game_button_binding(GameInput::Fullscreen, settings.game_buttons.fullscreen);
290        controller_settings
291            .insert_game_button_binding(GameInput::Screenshot, settings.game_buttons.screenshot);
292        controller_settings.insert_game_button_binding(
293            GameInput::ToggleIngameUi,
294            settings.game_buttons.toggle_ingame_ui,
295        );
296        controller_settings.insert_game_button_binding(GameInput::Roll, settings.game_buttons.roll);
297        controller_settings
298            .insert_game_button_binding(GameInput::Respawn, settings.game_buttons.respawn);
299        controller_settings
300            .insert_game_button_binding(GameInput::Interact, settings.game_buttons.interact);
301        controller_settings
302            .insert_game_button_binding(GameInput::ToggleWield, settings.game_buttons.toggle_wield);
303        controller_settings
304            .insert_game_button_binding(GameInput::SwapLoadout, settings.game_buttons.swap_loadout);
305
306        controller_settings.insert_menu_button_binding(MenuInput::Up, settings.menu_buttons.up);
307        controller_settings.insert_menu_button_binding(MenuInput::Down, settings.menu_buttons.down);
308        controller_settings.insert_menu_button_binding(MenuInput::Left, settings.menu_buttons.left);
309        controller_settings
310            .insert_menu_button_binding(MenuInput::Right, settings.menu_buttons.right);
311        controller_settings
312            .insert_menu_button_binding(MenuInput::ScrollUp, settings.menu_buttons.scroll_up);
313        controller_settings
314            .insert_menu_button_binding(MenuInput::ScrollDown, settings.menu_buttons.scroll_down);
315        controller_settings
316            .insert_menu_button_binding(MenuInput::ScrollLeft, settings.menu_buttons.scroll_left);
317        controller_settings
318            .insert_menu_button_binding(MenuInput::ScrollRight, settings.menu_buttons.scroll_right);
319        controller_settings.insert_menu_button_binding(MenuInput::Home, settings.menu_buttons.home);
320        controller_settings.insert_menu_button_binding(MenuInput::End, settings.menu_buttons.end);
321        controller_settings
322            .insert_menu_button_binding(MenuInput::Apply, settings.menu_buttons.apply);
323        controller_settings.insert_menu_button_binding(MenuInput::Back, settings.menu_buttons.back);
324        controller_settings.insert_menu_button_binding(MenuInput::Exit, settings.menu_buttons.exit);
325
326        controller_settings
327            .insert_game_axis_binding(AxisGameAction::MovementX, settings.game_axis.movement_x);
328        controller_settings
329            .insert_game_axis_binding(AxisGameAction::MovementY, settings.game_axis.movement_y);
330        controller_settings
331            .insert_game_axis_binding(AxisGameAction::CameraX, settings.game_axis.camera_x);
332        controller_settings
333            .insert_game_axis_binding(AxisGameAction::CameraY, settings.game_axis.camera_y);
334
335        controller_settings
336            .insert_menu_axis_binding(AxisMenuAction::MoveX, settings.menu_axis.move_x);
337        controller_settings
338            .insert_menu_axis_binding(AxisMenuAction::MoveY, settings.menu_axis.move_y);
339        controller_settings
340            .insert_menu_axis_binding(AxisMenuAction::ScrollX, settings.menu_axis.scroll_x);
341        controller_settings
342            .insert_menu_axis_binding(AxisMenuAction::ScrollY, settings.menu_axis.scroll_y);
343
344        controller_settings.insert_layer_button_binding(
345            GameInput::Secondary,
346            settings.game_layer_buttons.secondary,
347        );
348        controller_settings
349            .insert_layer_button_binding(GameInput::Primary, settings.game_layer_buttons.primary);
350        controller_settings
351            .insert_layer_button_binding(GameInput::Block, settings.game_layer_buttons.block);
352        controller_settings
353            .insert_layer_button_binding(GameInput::Slot1, settings.game_layer_buttons.slot1);
354        controller_settings
355            .insert_layer_button_binding(GameInput::Slot2, settings.game_layer_buttons.slot2);
356        controller_settings
357            .insert_layer_button_binding(GameInput::Slot3, settings.game_layer_buttons.slot3);
358        controller_settings
359            .insert_layer_button_binding(GameInput::Slot4, settings.game_layer_buttons.slot4);
360        controller_settings
361            .insert_layer_button_binding(GameInput::Slot5, settings.game_layer_buttons.slot5);
362        controller_settings
363            .insert_layer_button_binding(GameInput::Slot6, settings.game_layer_buttons.slot6);
364        controller_settings
365            .insert_layer_button_binding(GameInput::Slot7, settings.game_layer_buttons.slot7);
366        controller_settings
367            .insert_layer_button_binding(GameInput::Slot8, settings.game_layer_buttons.slot8);
368        controller_settings
369            .insert_layer_button_binding(GameInput::Slot9, settings.game_layer_buttons.slot9);
370        controller_settings
371            .insert_layer_button_binding(GameInput::Slot10, settings.game_layer_buttons.slot10);
372        controller_settings.insert_layer_button_binding(
373            GameInput::ToggleCursor,
374            settings.game_layer_buttons.toggle_cursor,
375        );
376        controller_settings
377            .insert_layer_button_binding(GameInput::Escape, settings.game_layer_buttons.escape);
378        controller_settings
379            .insert_layer_button_binding(GameInput::Chat, settings.game_layer_buttons.enter);
380        controller_settings
381            .insert_layer_button_binding(GameInput::Command, settings.game_layer_buttons.command);
382        controller_settings.insert_layer_button_binding(
383            GameInput::MoveForward,
384            settings.game_layer_buttons.move_forward,
385        );
386        controller_settings.insert_layer_button_binding(
387            GameInput::MoveLeft,
388            settings.game_layer_buttons.move_left,
389        );
390        controller_settings.insert_layer_button_binding(
391            GameInput::MoveBack,
392            settings.game_layer_buttons.move_back,
393        );
394        controller_settings.insert_layer_button_binding(
395            GameInput::MoveRight,
396            settings.game_layer_buttons.move_right,
397        );
398        controller_settings
399            .insert_layer_button_binding(GameInput::Jump, settings.game_layer_buttons.jump);
400        controller_settings
401            .insert_layer_button_binding(GameInput::Sit, settings.game_layer_buttons.sit);
402        controller_settings
403            .insert_layer_button_binding(GameInput::Dance, settings.game_layer_buttons.dance);
404        controller_settings
405            .insert_layer_button_binding(GameInput::Glide, settings.game_layer_buttons.glide);
406        controller_settings
407            .insert_layer_button_binding(GameInput::SwimUp, settings.game_layer_buttons.swimup);
408        controller_settings
409            .insert_layer_button_binding(GameInput::SwimDown, settings.game_layer_buttons.swimdown);
410        controller_settings
411            .insert_layer_button_binding(GameInput::Sneak, settings.game_layer_buttons.sneak);
412        controller_settings.insert_layer_button_binding(
413            GameInput::ToggleLantern,
414            settings.game_layer_buttons.toggle_lantern,
415        );
416        controller_settings
417            .insert_layer_button_binding(GameInput::Mount, settings.game_layer_buttons.mount);
418        controller_settings
419            .insert_layer_button_binding(GameInput::Map, settings.game_layer_buttons.map);
420        controller_settings
421            .insert_layer_button_binding(GameInput::Inventory, settings.game_layer_buttons.bag);
422        controller_settings
423            .insert_layer_button_binding(GameInput::Social, settings.game_layer_buttons.social);
424        controller_settings
425            .insert_layer_button_binding(GameInput::Crafting, settings.game_layer_buttons.crafting);
426        controller_settings
427            .insert_layer_button_binding(GameInput::Diary, settings.game_layer_buttons.diary);
428        controller_settings
429            .insert_layer_button_binding(GameInput::Settings, settings.game_layer_buttons.settings);
430        controller_settings
431            .insert_layer_button_binding(GameInput::Controls, settings.game_layer_buttons.controls);
432        controller_settings.insert_layer_button_binding(
433            GameInput::ToggleInterface,
434            settings.game_layer_buttons.toggle_interface,
435        );
436        controller_settings.insert_layer_button_binding(
437            GameInput::ToggleDebug,
438            settings.game_layer_buttons.toggle_debug,
439        );
440        #[cfg(feature = "egui-ui")]
441        controller_settings.insert_layer_button_binding(
442            GameInput::ToggleEguiDebug,
443            settings.game_layer_buttons.toggle_debug,
444        );
445        controller_settings.insert_layer_button_binding(
446            GameInput::ToggleChat,
447            settings.game_layer_buttons.toggle_chat,
448        );
449        controller_settings.insert_layer_button_binding(
450            GameInput::Fullscreen,
451            settings.game_layer_buttons.fullscreen,
452        );
453        controller_settings.insert_layer_button_binding(
454            GameInput::Screenshot,
455            settings.game_layer_buttons.screenshot,
456        );
457        controller_settings.insert_layer_button_binding(
458            GameInput::ToggleIngameUi,
459            settings.game_layer_buttons.toggle_ingame_ui,
460        );
461        controller_settings
462            .insert_layer_button_binding(GameInput::Roll, settings.game_layer_buttons.roll);
463        controller_settings
464            .insert_layer_button_binding(GameInput::Respawn, settings.game_layer_buttons.respawn);
465        controller_settings
466            .insert_layer_button_binding(GameInput::Interact, settings.game_layer_buttons.interact);
467        controller_settings.insert_layer_button_binding(
468            GameInput::ToggleWield,
469            settings.game_layer_buttons.toggle_wield,
470        );
471        controller_settings.insert_layer_button_binding(
472            GameInput::SwapLoadout,
473            settings.game_layer_buttons.swap_loadout,
474        );
475
476        controller_settings.modifier_buttons = vec![
477            Button::Simple(GilButton::RightTrigger),
478            Button::Simple(GilButton::LeftTrigger),
479        ];
480        controller_settings.pan_sensitivity = settings.pan_sensitivity;
481        controller_settings.pan_invert_y = settings.pan_invert_y;
482        controller_settings
483            .axis_deadzones
484            .clone_from(&settings.axis_deadzones);
485        controller_settings
486            .button_deadzones
487            .clone_from(&settings.button_deadzones);
488        controller_settings.mouse_emulation_sensitivity = settings.mouse_emulation_sensitivity;
489        controller_settings
490            .inverted_axes
491            .clone_from(&settings.inverted_axes);
492
493        controller_settings
494    }
495}
496
497/// All the menu actions you can bind to an Axis
498#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
499pub enum AxisMenuAction {
500    MoveX,
501    MoveY,
502    ScrollX,
503    ScrollY,
504}
505
506/// All the game actions you can bind to an Axis
507#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
508pub enum AxisGameAction {
509    MovementX,
510    MovementY,
511    CameraX,
512    CameraY,
513}
514
515/// All the menu actions you can bind to an analog button
516#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
517pub enum AnalogButtonMenuAction {}
518
519/// All the game actions you can bind to an analog button
520#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
521pub enum AnalogButtonGameAction {}
522
523/// Button::Simple(GilButton::Unknown) is invalid and equal to mapping an action
524/// to nothing
525#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
526pub enum Button {
527    Simple(GilButton),
528    EventCode(u32),
529}
530
531impl Default for Button {
532    fn default() -> Self { Button::Simple(GilButton::Unknown) }
533}
534
535impl Button {
536    // Returns button description (e.g Left Trigger)
537    pub fn display_string(&self, localized_strings: &Localization) -> String {
538        use self::Button::*;
539        // This exists here to keep the string in scope after the match
540        let button_string = match self {
541            Simple(GilButton::South) => localized_strings.get_msg("gamepad-south").to_string(),
542            Simple(GilButton::East) => localized_strings.get_msg("gamepad-east").to_string(),
543            Simple(GilButton::North) => localized_strings.get_msg("gamepad-north").to_string(),
544            Simple(GilButton::West) => localized_strings.get_msg("gamepad-west").to_string(),
545            Simple(GilButton::C) => localized_strings.get_msg("gamepad-c").to_string(),
546            Simple(GilButton::Z) => localized_strings.get_msg("gamepad-z").to_string(),
547            Simple(GilButton::LeftTrigger) => localized_strings
548                .get_msg("gamepad-left_trigger")
549                .to_string(),
550            Simple(GilButton::LeftTrigger2) => localized_strings
551                .get_msg("gamepad-left_trigger_2")
552                .to_string(),
553            Simple(GilButton::RightTrigger) => localized_strings
554                .get_msg("gamepad-right_trigger")
555                .to_string(),
556            Simple(GilButton::RightTrigger2) => localized_strings
557                .get_msg("gamepad-right_trigger_2")
558                .to_string(),
559            Simple(GilButton::Select) => localized_strings.get_msg("gamepad-select").to_string(),
560            Simple(GilButton::Start) => localized_strings.get_msg("gamepad-start").to_string(),
561            Simple(GilButton::Mode) => localized_strings.get_msg("gamepad-mode").to_string(),
562            Simple(GilButton::LeftThumb) => {
563                localized_strings.get_msg("gamepad-left_thumb").to_string()
564            },
565            Simple(GilButton::RightThumb) => {
566                localized_strings.get_msg("gamepad-right_thumb").to_string()
567            },
568            Simple(GilButton::DPadUp) => localized_strings.get_msg("gamepad-dpad_up").to_string(),
569            Simple(GilButton::DPadDown) => {
570                localized_strings.get_msg("gamepad-dpad_down").to_string()
571            },
572            Simple(GilButton::DPadLeft) => {
573                localized_strings.get_msg("gamepad-dpad_left").to_string()
574            },
575            Simple(GilButton::DPadRight) => {
576                localized_strings.get_msg("gamepad-dpad_right").to_string()
577            },
578            Simple(GilButton::Unknown) => localized_strings.get_msg("gamepad-unknown").to_string(),
579            EventCode(code) => code.to_string(),
580        };
581
582        button_string.to_owned()
583    }
584
585    // If it exists, returns the shortened version of a button name
586    // (e.g. Left Trigger -> LT)
587    pub fn try_shortened(&self) -> Option<String> {
588        use self::Button::*;
589        let button_string = match self {
590            Simple(GilButton::South) => "A",
591            Simple(GilButton::East) => "B",
592            Simple(GilButton::North) => "Y",
593            Simple(GilButton::West) => "X",
594            Simple(GilButton::LeftTrigger) => "LB",
595            Simple(GilButton::LeftTrigger2) => "LT",
596            Simple(GilButton::RightTrigger) => "RB",
597            Simple(GilButton::RightTrigger2) => "RT",
598            Simple(GilButton::LeftThumb) => "L3",
599            Simple(GilButton::RightThumb) => "R3",
600            _ => return None,
601        };
602
603        Some(button_string.to_owned())
604    }
605}
606
607/// AnalogButton::Simple(GilButton::Unknown) is invalid and equal to mapping an
608/// action to nothing
609#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
610pub enum AnalogButton {
611    Simple(GilButton),
612    EventCode(u32),
613}
614
615impl Default for AnalogButton {
616    fn default() -> Self { AnalogButton::Simple(GilButton::Unknown) }
617}
618
619/// Axis::Simple(GilAxis::Unknown) is invalid and equal to mapping an action to
620/// nothing
621#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
622pub enum Axis {
623    Simple(GilAxis),
624    EventCode(u32),
625}
626
627impl Default for Axis {
628    fn default() -> Self { Axis::Simple(GilAxis::Unknown) }
629}
630
631impl From<(GilAxis, GilCode)> for Axis {
632    fn from((axis, code): (GilAxis, GilCode)) -> Self {
633        match axis {
634            GilAxis::Unknown => Self::EventCode(code.into_u32()),
635            _ => Self::Simple(axis),
636        }
637    }
638}
639
640impl From<(GilButton, GilCode)> for Button {
641    fn from((button, code): (GilButton, GilCode)) -> Self {
642        match button {
643            GilButton::Unknown => Self::EventCode(code.into_u32()),
644            _ => Self::Simple(button),
645        }
646    }
647}
648
649impl From<(GilButton, GilCode)> for AnalogButton {
650    fn from((button, code): (GilButton, GilCode)) -> Self {
651        match button {
652            GilButton::Unknown => Self::EventCode(code.into_u32()),
653            _ => Self::Simple(button),
654        }
655    }
656}