use std::collections::HashMap; use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::framework::gamepad::{self, Axis, AxisDirection, Button, PlayerControllerInputType}; use crate::framework::keyboard::ScanCode; use crate::input::combined_menu_controller::CombinedMenuController; use crate::settings::{ControllerType, PlayerControllerButtonMap, PlayerKeyMap}; use crate::shared_game_state::SharedGameState; use super::{ControlMenuData, Menu, MenuEntry, MenuSelectionResult}; const FORBIDDEN_SCANCODES: [ScanCode; 12] = [ ScanCode::F1, ScanCode::F2, ScanCode::F3, ScanCode::F4, ScanCode::F5, ScanCode::F6, ScanCode::F7, ScanCode::F8, ScanCode::F9, ScanCode::F10, ScanCode::F11, ScanCode::F12, ]; #[derive(PartialEq, Eq, Clone, Debug)] #[repr(u8)] enum CurrentMenu { ControllerMenu, RebindMenu, ConfirmRebindMenu, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] enum ControllerMenuEntry { SelectedPlayer, Controller, Rebind, Back, } impl Default for ControllerMenuEntry { fn default() -> Self { ControllerMenuEntry::SelectedPlayer } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] enum RebindMenuEntry { Control(ControlEntry), Back, } impl Default for RebindMenuEntry { fn default() -> Self { RebindMenuEntry::Control(ControlEntry::Up) } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] enum Player { Player1, Player2, } impl Player { fn controller_type(self, state: &SharedGameState) -> ControllerType { match self { Player::Player1 => state.settings.player1_controller_type, Player::Player2 => state.settings.player2_controller_type, } } } #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] enum ControlEntry { Left, Up, Right, Down, PrevWeapon, NextWeapon, Jump, Shoot, Skip, Inventory, Map, Strafe, } impl ControlEntry { fn to_string(&self, state: &SharedGameState) -> String { match self { ControlEntry::Left => state.t("menus.controls_menu.rebind_menu.left"), ControlEntry::Up => state.t("menus.controls_menu.rebind_menu.up"), ControlEntry::Right => state.t("menus.controls_menu.rebind_menu.right"), ControlEntry::Down => state.t("menus.controls_menu.rebind_menu.down"), ControlEntry::PrevWeapon => state.t("menus.controls_menu.rebind_menu.prev_weapon"), ControlEntry::NextWeapon => state.t("menus.controls_menu.rebind_menu.next_weapon"), ControlEntry::Jump => state.t("menus.controls_menu.rebind_menu.jump"), ControlEntry::Shoot => state.t("menus.controls_menu.rebind_menu.shoot"), ControlEntry::Skip => state.t("menus.controls_menu.rebind_menu.skip"), ControlEntry::Inventory => state.t("menus.controls_menu.rebind_menu.inventory"), ControlEntry::Map => state.t("menus.controls_menu.rebind_menu.map"), ControlEntry::Strafe => state.t("menus.controls_menu.rebind_menu.strafe"), } } } pub struct ControlsMenu { current: CurrentMenu, controller: Menu, rebind: Menu, confirm_rebind: Menu, selected_player: Player, selected_controller: ControllerType, selected_control: Option, player1_key_map: Vec<(ControlEntry, ScanCode)>, player2_key_map: Vec<(ControlEntry, ScanCode)>, player1_controller_button_map: Vec<(ControlEntry, PlayerControllerInputType)>, player2_controller_button_map: Vec<(ControlEntry, PlayerControllerInputType)>, input_busy: bool, } impl ControlsMenu { pub fn new() -> ControlsMenu { let controller = Menu::new(0, 0, 220, 0); let rebind = Menu::new(0, 0, 220, 0); let confirm_rebind = Menu::new(0, 0, 220, 0); ControlsMenu { current: CurrentMenu::ControllerMenu, controller, rebind, confirm_rebind, selected_player: Player::Player1, selected_controller: ControllerType::Keyboard, selected_control: None, player1_key_map: Vec::new(), player2_key_map: Vec::new(), player1_controller_button_map: Vec::new(), player2_controller_button_map: Vec::new(), input_busy: false, } } pub fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { self.controller.push_entry( ControllerMenuEntry::SelectedPlayer, MenuEntry::Options( state.t("menus.controls_menu.select_player.entry"), self.selected_player as usize, vec![ state.t("menus.controls_menu.select_player.player_1"), state.t("menus.controls_menu.select_player.player_2"), ], ), ); self.controller.push_entry(ControllerMenuEntry::Controller, MenuEntry::Hidden); self.controller .push_entry(ControllerMenuEntry::Rebind, MenuEntry::Active(state.t("menus.controls_menu.rebind"))); self.controller.push_entry(ControllerMenuEntry::Back, MenuEntry::Active(state.t("common.back"))); self.player1_key_map = self.init_key_map(&state.settings.player1_key_map); self.player2_key_map = self.init_key_map(&state.settings.player2_key_map); self.player1_controller_button_map = self.init_controller_button_map(&state.settings.player1_controller_button_map); self.player2_controller_button_map = self.init_controller_button_map(&state.settings.player2_controller_button_map); self.confirm_rebind.draw_cursor = false; self.confirm_rebind.non_interactive = true; self.update_controller_options(state, ctx); self.update_rebind_menu(state, ctx); self.update_sizes(state); Ok(()) } fn update_sizes(&mut self, state: &SharedGameState) { self.controller.update_width(state); self.controller.update_height(); self.controller.x = ((state.canvas_size.0 - self.controller.width as f32) / 2.0).floor() as isize; self.controller.y = ((state.canvas_size.1 - self.controller.height as f32) / 2.0).floor() as isize; self.rebind.update_width(state); self.rebind.update_height(); self.rebind.x = ((state.canvas_size.0 - self.rebind.width as f32) / 2.0).floor() as isize; self.rebind.y = ((state.canvas_size.1 - self.rebind.height as f32) / 2.0).floor() as isize; self.confirm_rebind.update_width(state); self.confirm_rebind.update_height(); self.confirm_rebind.x = ((state.canvas_size.0 - self.confirm_rebind.width as f32) / 2.0).floor() as isize; self.confirm_rebind.y = ((state.canvas_size.1 - self.confirm_rebind.height as f32) / 2.0).floor() as isize; } fn init_key_map(&self, settings_key_map: &PlayerKeyMap) -> Vec<(ControlEntry, ScanCode)> { let mut map = Vec::new(); map.push((ControlEntry::Up, settings_key_map.up)); map.push((ControlEntry::Down, settings_key_map.down)); map.push((ControlEntry::Left, settings_key_map.left)); map.push((ControlEntry::Right, settings_key_map.right)); map.push((ControlEntry::Jump, settings_key_map.jump)); map.push((ControlEntry::Shoot, settings_key_map.shoot)); map.push((ControlEntry::PrevWeapon, settings_key_map.prev_weapon)); map.push((ControlEntry::NextWeapon, settings_key_map.next_weapon)); map.push((ControlEntry::Inventory, settings_key_map.inventory)); map.push((ControlEntry::Map, settings_key_map.map)); map.push((ControlEntry::Skip, settings_key_map.skip)); map.push((ControlEntry::Strafe, settings_key_map.strafe)); map } fn init_controller_button_map( &self, settings_controller_button_map: &PlayerControllerButtonMap, ) -> Vec<(ControlEntry, PlayerControllerInputType)> { let mut map = Vec::new(); map.push((ControlEntry::Up, settings_controller_button_map.up)); map.push((ControlEntry::Down, settings_controller_button_map.down)); map.push((ControlEntry::Left, settings_controller_button_map.left)); map.push((ControlEntry::Right, settings_controller_button_map.right)); map.push((ControlEntry::Jump, settings_controller_button_map.jump)); map.push((ControlEntry::Shoot, settings_controller_button_map.shoot)); map.push((ControlEntry::PrevWeapon, settings_controller_button_map.prev_weapon)); map.push((ControlEntry::NextWeapon, settings_controller_button_map.next_weapon)); map.push((ControlEntry::Inventory, settings_controller_button_map.inventory)); map.push((ControlEntry::Map, settings_controller_button_map.map)); map.push((ControlEntry::Skip, settings_controller_button_map.skip)); map.push((ControlEntry::Strafe, settings_controller_button_map.strafe)); map } fn update_rebind_menu(&mut self, state: &SharedGameState, ctx: &Context) { self.rebind.entries.clear(); match self.selected_player { Player::Player1 => { if self.selected_controller == ControllerType::Keyboard { for (k, v) in self.player1_key_map.iter() { self.rebind.push_entry( RebindMenuEntry::Control(*k), MenuEntry::Control( k.to_string(state).to_owned(), ControlMenuData::String(format!("{:?}", v)), ), ); } } else { for (k, v) in self.player1_controller_button_map.iter() { let gamepad_sprite_offset = match state.settings.player1_controller_type { ControllerType::Keyboard => 1, ControllerType::Gamepad(index) => { ctx.gamepad_context.get_gamepad_sprite_offset(index as usize) } }; self.rebind.push_entry( RebindMenuEntry::Control(*k), MenuEntry::Control( k.to_string(state).to_owned(), ControlMenuData::Rect(v.get_rect(gamepad_sprite_offset, &state.constants)), ), ); } } } Player::Player2 => { if self.selected_controller == ControllerType::Keyboard { for (k, v) in self.player2_key_map.iter() { self.rebind.push_entry( RebindMenuEntry::Control(*k), MenuEntry::Control( k.to_string(state).to_owned(), ControlMenuData::String(format!("{:?}", v)), ), ); } } else { for (k, v) in self.player2_controller_button_map.iter() { let gamepad_sprite_offset = match state.settings.player2_controller_type { ControllerType::Keyboard => 1, ControllerType::Gamepad(index) => { ctx.gamepad_context.get_gamepad_sprite_offset(index as usize) } }; self.rebind.push_entry( RebindMenuEntry::Control(*k), MenuEntry::Control( k.to_string(state).to_owned(), ControlMenuData::Rect(v.get_rect(gamepad_sprite_offset, &state.constants)), ), ); } } } } self.rebind.push_entry(RebindMenuEntry::Back, MenuEntry::Active(state.t("common.back"))); } fn update_controller_options(&mut self, state: &SharedGameState, ctx: &Context) { let mut controllers = Vec::new(); controllers.push(state.t("menus.controls_menu.controller.keyboard")); let gamepads = gamepad::get_gamepads(ctx); for i in 0..gamepads.len() { controllers.push(format!("{} {}", gamepads[i].get_gamepad_name(), i + 1)); } let controller_type = match self.selected_player { Player::Player1 => state.settings.player1_controller_type, Player::Player2 => state.settings.player2_controller_type, }; if let ControllerType::Gamepad(index) = controller_type { if index as usize >= gamepads.len() { self.selected_controller = ControllerType::Keyboard; } else { self.selected_controller = controller_type; } } else { self.selected_controller = controller_type; } let controller_idx = match self.selected_controller { ControllerType::Keyboard => 0, ControllerType::Gamepad(idx) => idx as usize + 1, }; self.controller.set_entry( ControllerMenuEntry::Controller, MenuEntry::Options( state.t("menus.controls_menu.controller.entry"), controller_idx as usize, controllers.clone(), ), ); } fn update_confirm_controls_menu(&mut self, state: &SharedGameState) { match self.selected_control { Some(control) => { self.confirm_rebind.entries.clear(); self.confirm_rebind.push_entry( 0, MenuEntry::DisabledWhite(state.tt( "menus.controls_menu.rebind_confirm_menu.title", HashMap::from([("control".to_string(), control.to_string(state))]), )), ); self.confirm_rebind .push_entry(1, MenuEntry::Disabled(state.t("menus.controls_menu.rebind_confirm_menu.cancel"))); } None => {} } } fn is_key_occupied(&self, scan_code: ScanCode) -> bool { let keymap = match self.selected_player { Player::Player1 => &self.player2_key_map, Player::Player2 => &self.player1_key_map, }; for (_, v) in keymap.iter() { if *v == scan_code { return true; } } false } fn set_key(&mut self, state: &mut SharedGameState, scan_code: ScanCode, ctx: &Context) -> GameResult { if self.selected_control.is_none() { return Ok(()); } match self.selected_control.unwrap() { ControlEntry::Left => match self.selected_player { Player::Player1 => state.settings.player1_key_map.left = scan_code, Player::Player2 => state.settings.player2_key_map.left = scan_code, }, ControlEntry::Up => match self.selected_player { Player::Player1 => state.settings.player1_key_map.up = scan_code, Player::Player2 => state.settings.player2_key_map.up = scan_code, }, ControlEntry::Right => match self.selected_player { Player::Player1 => state.settings.player1_key_map.right = scan_code, Player::Player2 => state.settings.player2_key_map.right = scan_code, }, ControlEntry::Down => match self.selected_player { Player::Player1 => state.settings.player1_key_map.down = scan_code, Player::Player2 => state.settings.player2_key_map.down = scan_code, }, ControlEntry::PrevWeapon => match self.selected_player { Player::Player1 => state.settings.player1_key_map.prev_weapon = scan_code, Player::Player2 => state.settings.player2_key_map.prev_weapon = scan_code, }, ControlEntry::NextWeapon => match self.selected_player { Player::Player1 => state.settings.player1_key_map.next_weapon = scan_code, Player::Player2 => state.settings.player2_key_map.next_weapon = scan_code, }, ControlEntry::Jump => match self.selected_player { Player::Player1 => state.settings.player1_key_map.jump = scan_code, Player::Player2 => state.settings.player2_key_map.jump = scan_code, }, ControlEntry::Shoot => match self.selected_player { Player::Player1 => state.settings.player1_key_map.shoot = scan_code, Player::Player2 => state.settings.player2_key_map.shoot = scan_code, }, ControlEntry::Skip => match self.selected_player { Player::Player1 => state.settings.player1_key_map.skip = scan_code, Player::Player2 => state.settings.player2_key_map.skip = scan_code, }, ControlEntry::Inventory => match self.selected_player { Player::Player1 => state.settings.player1_key_map.inventory = scan_code, Player::Player2 => state.settings.player2_key_map.inventory = scan_code, }, ControlEntry::Map => match self.selected_player { Player::Player1 => state.settings.player1_key_map.map = scan_code, Player::Player2 => state.settings.player2_key_map.map = scan_code, }, ControlEntry::Strafe => match self.selected_player { Player::Player1 => state.settings.player1_key_map.strafe = scan_code, Player::Player2 => state.settings.player2_key_map.strafe = scan_code, }, } state.settings.save(ctx)?; let keymap = match self.selected_player { Player::Player1 => &mut self.player1_key_map, Player::Player2 => &mut self.player2_key_map, }; for (entry, value) in keymap.iter_mut() { if *entry == self.selected_control.unwrap() { *value = scan_code; } } Ok(()) } fn set_controller_input( &mut self, state: &mut SharedGameState, input_type: PlayerControllerInputType, ctx: &Context, ) -> GameResult { if self.selected_control.is_none() { return Ok(()); } match self.selected_control.unwrap() { ControlEntry::Left => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.left = input_type, Player::Player2 => state.settings.player2_controller_button_map.left = input_type, }, ControlEntry::Up => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.up = input_type, Player::Player2 => state.settings.player2_controller_button_map.up = input_type, }, ControlEntry::Right => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.right = input_type, Player::Player2 => state.settings.player2_controller_button_map.right = input_type, }, ControlEntry::Down => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.down = input_type, Player::Player2 => state.settings.player2_controller_button_map.down = input_type, }, ControlEntry::PrevWeapon => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.prev_weapon = input_type, Player::Player2 => state.settings.player2_controller_button_map.prev_weapon = input_type, }, ControlEntry::NextWeapon => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.next_weapon = input_type, Player::Player2 => state.settings.player2_controller_button_map.next_weapon = input_type, }, ControlEntry::Jump => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.jump = input_type, Player::Player2 => state.settings.player2_controller_button_map.jump = input_type, }, ControlEntry::Shoot => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.shoot = input_type, Player::Player2 => state.settings.player2_controller_button_map.shoot = input_type, }, ControlEntry::Skip => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.skip = input_type, Player::Player2 => state.settings.player2_controller_button_map.skip = input_type, }, ControlEntry::Inventory => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.inventory = input_type, Player::Player2 => state.settings.player2_controller_button_map.inventory = input_type, }, ControlEntry::Map => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.map = input_type, Player::Player2 => state.settings.player2_controller_button_map.map = input_type, }, ControlEntry::Strafe => match self.selected_player { Player::Player1 => state.settings.player1_controller_button_map.strafe = input_type, Player::Player2 => state.settings.player2_controller_button_map.strafe = input_type, }, } state.settings.save(ctx)?; let button_map = match self.selected_player { Player::Player1 => &mut self.player1_controller_button_map, Player::Player2 => &mut self.player2_controller_button_map, }; for (entry, value) in button_map.iter_mut() { if *entry == self.selected_control.unwrap() { *value = input_type; } } Ok(()) } fn normalize_gamepad_input(&self, input: PlayerControllerInputType) -> PlayerControllerInputType { match input { PlayerControllerInputType::ButtonInput(Button::DPadUp) => { PlayerControllerInputType::Either(Button::DPadUp, Axis::LeftY, AxisDirection::Up) } PlayerControllerInputType::ButtonInput(Button::DPadDown) => { PlayerControllerInputType::Either(Button::DPadDown, Axis::LeftY, AxisDirection::Down) } PlayerControllerInputType::ButtonInput(Button::DPadLeft) => { PlayerControllerInputType::Either(Button::DPadLeft, Axis::LeftX, AxisDirection::Left) } PlayerControllerInputType::ButtonInput(Button::DPadRight) => { PlayerControllerInputType::Either(Button::DPadRight, Axis::LeftX, AxisDirection::Right) } PlayerControllerInputType::AxisInput(Axis::LeftY, AxisDirection::Up) => { PlayerControllerInputType::Either(Button::DPadUp, Axis::LeftY, AxisDirection::Up) } PlayerControllerInputType::AxisInput(Axis::LeftY, AxisDirection::Down) => { PlayerControllerInputType::Either(Button::DPadDown, Axis::LeftY, AxisDirection::Down) } PlayerControllerInputType::AxisInput(Axis::LeftX, AxisDirection::Left) => { PlayerControllerInputType::Either(Button::DPadLeft, Axis::LeftX, AxisDirection::Left) } PlayerControllerInputType::AxisInput(Axis::LeftX, AxisDirection::Right) => { PlayerControllerInputType::Either(Button::DPadRight, Axis::LeftX, AxisDirection::Right) } PlayerControllerInputType::AxisInput(Axis::RightY, AxisDirection::Up) => { PlayerControllerInputType::Either(Button::DPadUp, Axis::RightY, AxisDirection::Up) } PlayerControllerInputType::AxisInput(Axis::RightY, AxisDirection::Down) => { PlayerControllerInputType::Either(Button::DPadDown, Axis::RightY, AxisDirection::Down) } PlayerControllerInputType::AxisInput(Axis::RightX, AxisDirection::Left) => { PlayerControllerInputType::Either(Button::DPadLeft, Axis::RightX, AxisDirection::Left) } PlayerControllerInputType::AxisInput(Axis::RightX, AxisDirection::Right) => { PlayerControllerInputType::Either(Button::DPadRight, Axis::RightX, AxisDirection::Right) } _ => input, } } pub fn tick( &mut self, exit_action: &mut dyn FnMut(), controller: &mut CombinedMenuController, state: &mut SharedGameState, ctx: &mut Context, ) -> GameResult { self.update_sizes(state); match self.current { CurrentMenu::ControllerMenu => match self.controller.tick(controller, state) { MenuSelectionResult::Selected(ControllerMenuEntry::SelectedPlayer, toggle) | MenuSelectionResult::Left(ControllerMenuEntry::SelectedPlayer, toggle, _) | MenuSelectionResult::Right(ControllerMenuEntry::SelectedPlayer, toggle, _) => { if let MenuEntry::Options(_, value, _) = toggle { let (new_player, new_value) = match *value { 0 => (Player::Player2, 1), 1 => (Player::Player1, 0), _ => unreachable!(), }; *value = new_value; self.selected_player = new_player; self.selected_controller = new_player.controller_type(state); self.update_controller_options(state, ctx); self.update_rebind_menu(state, ctx); } } MenuSelectionResult::Selected(ControllerMenuEntry::Controller, toggle) | MenuSelectionResult::Right(ControllerMenuEntry::Controller, toggle, _) => { if self.input_busy { return Ok(()); } if let MenuEntry::Options(_, value, entries) = toggle { if *value == entries.len() - 1 { self.selected_controller = ControllerType::Keyboard; *value = 0; } else { self.selected_controller = ControllerType::Gamepad(*value as u32); *value = *value + 1; } } if self.selected_player == Player::Player1 { state.settings.player1_controller_type = self.selected_controller; } else { state.settings.player2_controller_type = self.selected_controller; } let _ = state.settings.save(ctx); let mut new_menu_controller = CombinedMenuController::new(); new_menu_controller.add(state.settings.create_player1_controller()); new_menu_controller.add(state.settings.create_player2_controller()); self.input_busy = true; *controller = new_menu_controller; self.update_rebind_menu(state, ctx); } MenuSelectionResult::Left(ControllerMenuEntry::Controller, toggle, _) => { if self.input_busy { return Ok(()); } if let MenuEntry::Options(_, value, entries) = toggle { if *value == 1 { self.selected_controller = ControllerType::Keyboard; *value = 0; } else { self.selected_controller = ControllerType::Gamepad(*value as u32); if *value == 0 { *value = entries.len() - 1; } else { *value = *value - 1; } } } if self.selected_player == Player::Player1 { state.settings.player1_controller_type = self.selected_controller; } else { state.settings.player2_controller_type = self.selected_controller; } let _ = state.settings.save(ctx); let mut new_menu_controller = CombinedMenuController::new(); new_menu_controller.add(state.settings.create_player1_controller()); new_menu_controller.add(state.settings.create_player2_controller()); self.input_busy = true; *controller = new_menu_controller; self.update_rebind_menu(state, ctx); } MenuSelectionResult::Selected(ControllerMenuEntry::Rebind, _) => { self.current = CurrentMenu::RebindMenu; } MenuSelectionResult::Selected(ControllerMenuEntry::Back, _) | MenuSelectionResult::Canceled => { exit_action() } _ => {} }, CurrentMenu::RebindMenu => match self.rebind.tick(controller, state) { MenuSelectionResult::Selected(RebindMenuEntry::Back, _) | MenuSelectionResult::Canceled => { self.current = CurrentMenu::ControllerMenu; } MenuSelectionResult::Selected(RebindMenuEntry::Control(control), _) => { if !self.input_busy { self.selected_control = Some(control); self.update_confirm_controls_menu(state); self.input_busy = true; self.current = CurrentMenu::ConfirmRebindMenu; } } _ => {} }, CurrentMenu::ConfirmRebindMenu => match self.confirm_rebind.tick(controller, state) { _ => { let pressed_keys: Vec<_> = ctx.keyboard_context.pressed_keys().into_iter().collect(); for key in pressed_keys.clone() { if *key == ScanCode::Escape { state.sound_manager.play_sfx(5); self.current = CurrentMenu::RebindMenu; return Ok(()); } } match self.selected_controller { ControllerType::Keyboard => { if pressed_keys.len() == 1 { if !self.input_busy { self.input_busy = true; let key = **pressed_keys.first().unwrap(); if self.is_key_occupied(key) || FORBIDDEN_SCANCODES.contains(&key) || self.selected_controller != ControllerType::Keyboard { state.sound_manager.play_sfx(12); } else { self.set_key(state, key, ctx)?; self.update_rebind_menu(state, ctx); self.selected_control = None; state.sound_manager.play_sfx(18); self.current = CurrentMenu::RebindMenu; } } } } ControllerType::Gamepad(idx) => { let pressed_gamepad_buttons: Vec<_> = ctx.gamepad_context.pressed_buttons(idx).into_iter().collect(); if pressed_gamepad_buttons.len() == 1 { if !self.input_busy { self.input_busy = true; if self.selected_player.controller_type(state) != self.selected_controller { state.sound_manager.play_sfx(12); } else { let button = *pressed_gamepad_buttons.first().unwrap(); let normalized_input = self .normalize_gamepad_input(PlayerControllerInputType::ButtonInput(button)); self.set_controller_input(state, normalized_input, ctx)?; self.update_rebind_menu(state, ctx); self.selected_control = None; state.sound_manager.play_sfx(18); self.current = CurrentMenu::RebindMenu; } } } let active_axes: Vec<_> = ctx.gamepad_context.active_axes(idx).into_iter().collect(); if active_axes.len() == 1 { if !self.input_busy { self.input_busy = true; if self.selected_player.controller_type(state) != self.selected_controller { state.sound_manager.play_sfx(12); } else { let (axis, value) = *active_axes.first().unwrap(); let direction = AxisDirection::from_axis_data(axis, value); let normalized_input = self.normalize_gamepad_input( PlayerControllerInputType::AxisInput(axis, direction), ); self.set_controller_input(state, normalized_input, ctx)?; self.update_rebind_menu(state, ctx); self.selected_control = None; state.sound_manager.play_sfx(18); self.current = CurrentMenu::RebindMenu; } } } if pressed_keys.is_empty() && pressed_gamepad_buttons.is_empty() && active_axes.is_empty() { self.input_busy = false; } } } } }, } if self.input_busy { let pressed_keys = ctx.keyboard_context.pressed_keys(); if let ControllerType::Gamepad(idx) = self.selected_controller { let pressed_buttons = ctx.gamepad_context.pressed_buttons(idx); let active_axes = ctx.gamepad_context.active_axes(idx); if pressed_keys.is_empty() && pressed_buttons.is_empty() && active_axes.is_empty() { self.input_busy = false; } } else { if pressed_keys.is_empty() { self.input_busy = false; } } } Ok(()) } pub fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { match self.current { CurrentMenu::ControllerMenu => self.controller.draw(state, ctx)?, CurrentMenu::RebindMenu => self.rebind.draw(state, ctx)?, CurrentMenu::ConfirmRebindMenu => self.confirm_rebind.draw(state, ctx)?, } Ok(()) } }