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                && let Some(game_inputs) = self.inverse_game_button_map.get(&layer_entry.button)
181            {
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        false
192    }
193}
194
195impl From<&crate::settings::GamepadSettings> for ControllerSettings {
196    fn from(settings: &crate::settings::GamepadSettings) -> Self {
197        let mut controller_settings: ControllerSettings = ControllerSettings::default();
198
199        controller_settings
200            .insert_game_button_binding(GameInput::Primary, settings.game_buttons.primary);
201        controller_settings
202            .insert_game_button_binding(GameInput::Secondary, settings.game_buttons.secondary);
203        controller_settings
204            .insert_game_button_binding(GameInput::Block, settings.game_buttons.block);
205        controller_settings
206            .insert_game_button_binding(GameInput::Slot1, settings.game_buttons.slot1);
207        controller_settings
208            .insert_game_button_binding(GameInput::Slot2, settings.game_buttons.slot2);
209        controller_settings
210            .insert_game_button_binding(GameInput::Slot3, settings.game_buttons.slot3);
211        controller_settings
212            .insert_game_button_binding(GameInput::Slot4, settings.game_buttons.slot4);
213        controller_settings
214            .insert_game_button_binding(GameInput::Slot5, settings.game_buttons.slot5);
215        controller_settings
216            .insert_game_button_binding(GameInput::Slot6, settings.game_buttons.slot6);
217        controller_settings
218            .insert_game_button_binding(GameInput::Slot7, settings.game_buttons.slot7);
219        controller_settings
220            .insert_game_button_binding(GameInput::Slot8, settings.game_buttons.slot8);
221        controller_settings
222            .insert_game_button_binding(GameInput::Slot9, settings.game_buttons.slot9);
223        controller_settings
224            .insert_game_button_binding(GameInput::Slot10, settings.game_buttons.slot10);
225        controller_settings.insert_game_button_binding(
226            GameInput::ToggleCursor,
227            settings.game_buttons.toggle_cursor,
228        );
229        controller_settings
230            .insert_game_button_binding(GameInput::Escape, settings.game_buttons.escape);
231        controller_settings
232            .insert_game_button_binding(GameInput::Chat, settings.game_buttons.enter);
233        controller_settings
234            .insert_game_button_binding(GameInput::Command, settings.game_buttons.command);
235        controller_settings
236            .insert_game_button_binding(GameInput::MoveForward, settings.game_buttons.move_forward);
237        controller_settings
238            .insert_game_button_binding(GameInput::MoveLeft, settings.game_buttons.move_left);
239        controller_settings
240            .insert_game_button_binding(GameInput::MoveBack, settings.game_buttons.move_back);
241        controller_settings
242            .insert_game_button_binding(GameInput::MoveRight, settings.game_buttons.move_right);
243        controller_settings.insert_game_button_binding(GameInput::Jump, settings.game_buttons.jump);
244        controller_settings.insert_game_button_binding(GameInput::Sit, settings.game_buttons.sit);
245        controller_settings
246            .insert_game_button_binding(GameInput::Dance, settings.game_buttons.dance);
247        controller_settings
248            .insert_game_button_binding(GameInput::Glide, settings.game_buttons.glide);
249        controller_settings
250            .insert_game_button_binding(GameInput::SwimUp, settings.game_buttons.swimup);
251        controller_settings
252            .insert_game_button_binding(GameInput::SwimDown, settings.game_buttons.swimdown);
253        controller_settings
254            .insert_game_button_binding(GameInput::Sneak, settings.game_buttons.sneak);
255        controller_settings.insert_game_button_binding(
256            GameInput::ToggleLantern,
257            settings.game_buttons.toggle_lantern,
258        );
259        controller_settings
260            .insert_game_button_binding(GameInput::Mount, settings.game_buttons.mount);
261        controller_settings.insert_game_button_binding(GameInput::Map, settings.game_buttons.map);
262        controller_settings
263            .insert_game_button_binding(GameInput::Inventory, settings.game_buttons.bag);
264        controller_settings
265            .insert_game_button_binding(GameInput::Social, settings.game_buttons.social);
266        controller_settings
267            .insert_game_button_binding(GameInput::Crafting, settings.game_buttons.crafting);
268        controller_settings
269            .insert_game_button_binding(GameInput::Diary, settings.game_buttons.diary);
270        controller_settings
271            .insert_game_button_binding(GameInput::Settings, settings.game_buttons.settings);
272        controller_settings
273            .insert_game_button_binding(GameInput::Controls, settings.game_buttons.controls);
274        controller_settings.insert_game_button_binding(
275            GameInput::ToggleInterface,
276            settings.game_buttons.toggle_interface,
277        );
278        controller_settings
279            .insert_game_button_binding(GameInput::ToggleDebug, settings.game_buttons.toggle_debug);
280        #[cfg(feature = "egui-ui")]
281        controller_settings.insert_game_button_binding(
282            GameInput::ToggleEguiDebug,
283            settings.game_buttons.toggle_debug,
284        );
285        controller_settings
286            .insert_game_button_binding(GameInput::ToggleChat, settings.game_buttons.toggle_chat);
287        controller_settings
288            .insert_game_button_binding(GameInput::Fullscreen, settings.game_buttons.fullscreen);
289        controller_settings
290            .insert_game_button_binding(GameInput::Screenshot, settings.game_buttons.screenshot);
291        controller_settings.insert_game_button_binding(
292            GameInput::ToggleIngameUi,
293            settings.game_buttons.toggle_ingame_ui,
294        );
295        controller_settings.insert_game_button_binding(GameInput::Roll, settings.game_buttons.roll);
296        controller_settings
297            .insert_game_button_binding(GameInput::Respawn, settings.game_buttons.respawn);
298        controller_settings
299            .insert_game_button_binding(GameInput::Interact, settings.game_buttons.interact);
300        controller_settings
301            .insert_game_button_binding(GameInput::ToggleWield, settings.game_buttons.toggle_wield);
302        controller_settings
303            .insert_game_button_binding(GameInput::SwapLoadout, settings.game_buttons.swap_loadout);
304
305        controller_settings.insert_menu_button_binding(MenuInput::Up, settings.menu_buttons.up);
306        controller_settings.insert_menu_button_binding(MenuInput::Down, settings.menu_buttons.down);
307        controller_settings.insert_menu_button_binding(MenuInput::Left, settings.menu_buttons.left);
308        controller_settings
309            .insert_menu_button_binding(MenuInput::Right, settings.menu_buttons.right);
310        controller_settings
311            .insert_menu_button_binding(MenuInput::ScrollUp, settings.menu_buttons.scroll_up);
312        controller_settings
313            .insert_menu_button_binding(MenuInput::ScrollDown, settings.menu_buttons.scroll_down);
314        controller_settings
315            .insert_menu_button_binding(MenuInput::ScrollLeft, settings.menu_buttons.scroll_left);
316        controller_settings
317            .insert_menu_button_binding(MenuInput::ScrollRight, settings.menu_buttons.scroll_right);
318        controller_settings.insert_menu_button_binding(MenuInput::Home, settings.menu_buttons.home);
319        controller_settings.insert_menu_button_binding(MenuInput::End, settings.menu_buttons.end);
320        controller_settings
321            .insert_menu_button_binding(MenuInput::Apply, settings.menu_buttons.apply);
322        controller_settings.insert_menu_button_binding(MenuInput::Back, settings.menu_buttons.back);
323        controller_settings.insert_menu_button_binding(MenuInput::Exit, settings.menu_buttons.exit);
324
325        controller_settings
326            .insert_game_axis_binding(AxisGameAction::MovementX, settings.game_axis.movement_x);
327        controller_settings
328            .insert_game_axis_binding(AxisGameAction::MovementY, settings.game_axis.movement_y);
329        controller_settings
330            .insert_game_axis_binding(AxisGameAction::CameraX, settings.game_axis.camera_x);
331        controller_settings
332            .insert_game_axis_binding(AxisGameAction::CameraY, settings.game_axis.camera_y);
333
334        controller_settings
335            .insert_menu_axis_binding(AxisMenuAction::MoveX, settings.menu_axis.move_x);
336        controller_settings
337            .insert_menu_axis_binding(AxisMenuAction::MoveY, settings.menu_axis.move_y);
338        controller_settings
339            .insert_menu_axis_binding(AxisMenuAction::ScrollX, settings.menu_axis.scroll_x);
340        controller_settings
341            .insert_menu_axis_binding(AxisMenuAction::ScrollY, settings.menu_axis.scroll_y);
342
343        controller_settings.insert_layer_button_binding(
344            GameInput::Secondary,
345            settings.game_layer_buttons.secondary,
346        );
347        controller_settings
348            .insert_layer_button_binding(GameInput::Primary, settings.game_layer_buttons.primary);
349        controller_settings
350            .insert_layer_button_binding(GameInput::Block, settings.game_layer_buttons.block);
351        controller_settings
352            .insert_layer_button_binding(GameInput::Slot1, settings.game_layer_buttons.slot1);
353        controller_settings
354            .insert_layer_button_binding(GameInput::Slot2, settings.game_layer_buttons.slot2);
355        controller_settings
356            .insert_layer_button_binding(GameInput::Slot3, settings.game_layer_buttons.slot3);
357        controller_settings
358            .insert_layer_button_binding(GameInput::Slot4, settings.game_layer_buttons.slot4);
359        controller_settings
360            .insert_layer_button_binding(GameInput::Slot5, settings.game_layer_buttons.slot5);
361        controller_settings
362            .insert_layer_button_binding(GameInput::Slot6, settings.game_layer_buttons.slot6);
363        controller_settings
364            .insert_layer_button_binding(GameInput::Slot7, settings.game_layer_buttons.slot7);
365        controller_settings
366            .insert_layer_button_binding(GameInput::Slot8, settings.game_layer_buttons.slot8);
367        controller_settings
368            .insert_layer_button_binding(GameInput::Slot9, settings.game_layer_buttons.slot9);
369        controller_settings
370            .insert_layer_button_binding(GameInput::Slot10, settings.game_layer_buttons.slot10);
371        controller_settings.insert_layer_button_binding(
372            GameInput::ToggleCursor,
373            settings.game_layer_buttons.toggle_cursor,
374        );
375        controller_settings
376            .insert_layer_button_binding(GameInput::Escape, settings.game_layer_buttons.escape);
377        controller_settings
378            .insert_layer_button_binding(GameInput::Chat, settings.game_layer_buttons.enter);
379        controller_settings
380            .insert_layer_button_binding(GameInput::Command, settings.game_layer_buttons.command);
381        controller_settings.insert_layer_button_binding(
382            GameInput::MoveForward,
383            settings.game_layer_buttons.move_forward,
384        );
385        controller_settings.insert_layer_button_binding(
386            GameInput::MoveLeft,
387            settings.game_layer_buttons.move_left,
388        );
389        controller_settings.insert_layer_button_binding(
390            GameInput::MoveBack,
391            settings.game_layer_buttons.move_back,
392        );
393        controller_settings.insert_layer_button_binding(
394            GameInput::MoveRight,
395            settings.game_layer_buttons.move_right,
396        );
397        controller_settings
398            .insert_layer_button_binding(GameInput::Jump, settings.game_layer_buttons.jump);
399        controller_settings
400            .insert_layer_button_binding(GameInput::Sit, settings.game_layer_buttons.sit);
401        controller_settings
402            .insert_layer_button_binding(GameInput::Dance, settings.game_layer_buttons.dance);
403        controller_settings
404            .insert_layer_button_binding(GameInput::Glide, settings.game_layer_buttons.glide);
405        controller_settings
406            .insert_layer_button_binding(GameInput::SwimUp, settings.game_layer_buttons.swimup);
407        controller_settings
408            .insert_layer_button_binding(GameInput::SwimDown, settings.game_layer_buttons.swimdown);
409        controller_settings
410            .insert_layer_button_binding(GameInput::Sneak, settings.game_layer_buttons.sneak);
411        controller_settings.insert_layer_button_binding(
412            GameInput::ToggleLantern,
413            settings.game_layer_buttons.toggle_lantern,
414        );
415        controller_settings
416            .insert_layer_button_binding(GameInput::Mount, settings.game_layer_buttons.mount);
417        controller_settings
418            .insert_layer_button_binding(GameInput::Map, settings.game_layer_buttons.map);
419        controller_settings
420            .insert_layer_button_binding(GameInput::Inventory, settings.game_layer_buttons.bag);
421        controller_settings
422            .insert_layer_button_binding(GameInput::Social, settings.game_layer_buttons.social);
423        controller_settings
424            .insert_layer_button_binding(GameInput::Crafting, settings.game_layer_buttons.crafting);
425        controller_settings
426            .insert_layer_button_binding(GameInput::Diary, settings.game_layer_buttons.diary);
427        controller_settings
428            .insert_layer_button_binding(GameInput::Settings, settings.game_layer_buttons.settings);
429        controller_settings
430            .insert_layer_button_binding(GameInput::Controls, settings.game_layer_buttons.controls);
431        controller_settings.insert_layer_button_binding(
432            GameInput::ToggleInterface,
433            settings.game_layer_buttons.toggle_interface,
434        );
435        controller_settings.insert_layer_button_binding(
436            GameInput::ToggleDebug,
437            settings.game_layer_buttons.toggle_debug,
438        );
439        #[cfg(feature = "egui-ui")]
440        controller_settings.insert_layer_button_binding(
441            GameInput::ToggleEguiDebug,
442            settings.game_layer_buttons.toggle_debug,
443        );
444        controller_settings.insert_layer_button_binding(
445            GameInput::ToggleChat,
446            settings.game_layer_buttons.toggle_chat,
447        );
448        controller_settings.insert_layer_button_binding(
449            GameInput::Fullscreen,
450            settings.game_layer_buttons.fullscreen,
451        );
452        controller_settings.insert_layer_button_binding(
453            GameInput::Screenshot,
454            settings.game_layer_buttons.screenshot,
455        );
456        controller_settings.insert_layer_button_binding(
457            GameInput::ToggleIngameUi,
458            settings.game_layer_buttons.toggle_ingame_ui,
459        );
460        controller_settings
461            .insert_layer_button_binding(GameInput::Roll, settings.game_layer_buttons.roll);
462        controller_settings
463            .insert_layer_button_binding(GameInput::Respawn, settings.game_layer_buttons.respawn);
464        controller_settings
465            .insert_layer_button_binding(GameInput::Interact, settings.game_layer_buttons.interact);
466        controller_settings.insert_layer_button_binding(
467            GameInput::ToggleWield,
468            settings.game_layer_buttons.toggle_wield,
469        );
470        controller_settings.insert_layer_button_binding(
471            GameInput::SwapLoadout,
472            settings.game_layer_buttons.swap_loadout,
473        );
474
475        controller_settings.modifier_buttons = vec![
476            Button::Simple(GilButton::RightTrigger),
477            Button::Simple(GilButton::LeftTrigger),
478        ];
479        controller_settings.pan_sensitivity = settings.pan_sensitivity;
480        controller_settings.pan_invert_y = settings.pan_invert_y;
481        controller_settings
482            .axis_deadzones
483            .clone_from(&settings.axis_deadzones);
484        controller_settings
485            .button_deadzones
486            .clone_from(&settings.button_deadzones);
487        controller_settings.mouse_emulation_sensitivity = settings.mouse_emulation_sensitivity;
488        controller_settings
489            .inverted_axes
490            .clone_from(&settings.inverted_axes);
491
492        controller_settings
493    }
494}
495
496/// All the menu actions you can bind to an Axis
497#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
498pub enum AxisMenuAction {
499    MoveX,
500    MoveY,
501    ScrollX,
502    ScrollY,
503}
504
505/// All the game actions you can bind to an Axis
506#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
507pub enum AxisGameAction {
508    MovementX,
509    MovementY,
510    CameraX,
511    CameraY,
512}
513
514/// All the menu actions you can bind to an analog button
515#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
516pub enum AnalogButtonMenuAction {}
517
518/// All the game actions you can bind to an analog button
519#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
520pub enum AnalogButtonGameAction {}
521
522/// Button::Simple(GilButton::Unknown) is invalid and equal to mapping an action
523/// to nothing
524#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
525pub enum Button {
526    Simple(GilButton),
527    EventCode(u32),
528}
529
530impl Default for Button {
531    fn default() -> Self { Button::Simple(GilButton::Unknown) }
532}
533
534impl Button {
535    // Returns button description (e.g Left Trigger)
536    pub fn display_string(&self, localized_strings: &Localization) -> String {
537        use self::Button::*;
538        // This exists here to keep the string in scope after the match
539        let button_string = match self {
540            Simple(GilButton::South) => localized_strings.get_msg("gamepad-south").to_string(),
541            Simple(GilButton::East) => localized_strings.get_msg("gamepad-east").to_string(),
542            Simple(GilButton::North) => localized_strings.get_msg("gamepad-north").to_string(),
543            Simple(GilButton::West) => localized_strings.get_msg("gamepad-west").to_string(),
544            Simple(GilButton::C) => localized_strings.get_msg("gamepad-c").to_string(),
545            Simple(GilButton::Z) => localized_strings.get_msg("gamepad-z").to_string(),
546            Simple(GilButton::LeftTrigger) => localized_strings
547                .get_msg("gamepad-left_trigger")
548                .to_string(),
549            Simple(GilButton::LeftTrigger2) => localized_strings
550                .get_msg("gamepad-left_trigger_2")
551                .to_string(),
552            Simple(GilButton::RightTrigger) => localized_strings
553                .get_msg("gamepad-right_trigger")
554                .to_string(),
555            Simple(GilButton::RightTrigger2) => localized_strings
556                .get_msg("gamepad-right_trigger_2")
557                .to_string(),
558            Simple(GilButton::Select) => localized_strings.get_msg("gamepad-select").to_string(),
559            Simple(GilButton::Start) => localized_strings.get_msg("gamepad-start").to_string(),
560            Simple(GilButton::Mode) => localized_strings.get_msg("gamepad-mode").to_string(),
561            Simple(GilButton::LeftThumb) => {
562                localized_strings.get_msg("gamepad-left_thumb").to_string()
563            },
564            Simple(GilButton::RightThumb) => {
565                localized_strings.get_msg("gamepad-right_thumb").to_string()
566            },
567            Simple(GilButton::DPadUp) => localized_strings.get_msg("gamepad-dpad_up").to_string(),
568            Simple(GilButton::DPadDown) => {
569                localized_strings.get_msg("gamepad-dpad_down").to_string()
570            },
571            Simple(GilButton::DPadLeft) => {
572                localized_strings.get_msg("gamepad-dpad_left").to_string()
573            },
574            Simple(GilButton::DPadRight) => {
575                localized_strings.get_msg("gamepad-dpad_right").to_string()
576            },
577            Simple(GilButton::Unknown) => localized_strings.get_msg("gamepad-unknown").to_string(),
578            EventCode(code) => code.to_string(),
579        };
580
581        button_string.to_owned()
582    }
583
584    // If it exists, returns the shortened version of a button name
585    // (e.g. Left Trigger -> LT)
586    pub fn try_shortened(&self) -> Option<String> {
587        use self::Button::*;
588        let button_string = match self {
589            Simple(GilButton::South) => "A",
590            Simple(GilButton::East) => "B",
591            Simple(GilButton::North) => "Y",
592            Simple(GilButton::West) => "X",
593            Simple(GilButton::LeftTrigger) => "LB",
594            Simple(GilButton::LeftTrigger2) => "LT",
595            Simple(GilButton::RightTrigger) => "RB",
596            Simple(GilButton::RightTrigger2) => "RT",
597            Simple(GilButton::LeftThumb) => "L3",
598            Simple(GilButton::RightThumb) => "R3",
599            _ => return None,
600        };
601
602        Some(button_string.to_owned())
603    }
604}
605
606/// AnalogButton::Simple(GilButton::Unknown) is invalid and equal to mapping an
607/// action to nothing
608#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
609pub enum AnalogButton {
610    Simple(GilButton),
611    EventCode(u32),
612}
613
614impl Default for AnalogButton {
615    fn default() -> Self { AnalogButton::Simple(GilButton::Unknown) }
616}
617
618/// Axis::Simple(GilAxis::Unknown) is invalid and equal to mapping an action to
619/// nothing
620#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
621pub enum Axis {
622    Simple(GilAxis),
623    EventCode(u32),
624}
625
626impl Default for Axis {
627    fn default() -> Self { Axis::Simple(GilAxis::Unknown) }
628}
629
630impl From<(GilAxis, GilCode)> for Axis {
631    fn from((axis, code): (GilAxis, GilCode)) -> Self {
632        match axis {
633            GilAxis::Unknown => Self::EventCode(code.into_u32()),
634            _ => Self::Simple(axis),
635        }
636    }
637}
638
639impl From<(GilButton, GilCode)> for Button {
640    fn from((button, code): (GilButton, GilCode)) -> Self {
641        match button {
642            GilButton::Unknown => Self::EventCode(code.into_u32()),
643            _ => Self::Simple(button),
644        }
645    }
646}
647
648impl From<(GilButton, GilCode)> for AnalogButton {
649    fn from((button, code): (GilButton, GilCode)) -> Self {
650        match button {
651            GilButton::Unknown => Self::EventCode(code.into_u32()),
652            _ => Self::Simple(button),
653        }
654    }
655}