diff --git a/include/banjo_config.h b/include/banjo_config.h index e77e5dd..a8e089a 100644 --- a/include/banjo_config.h +++ b/include/banjo_config.h @@ -14,7 +14,6 @@ namespace banjo { void load_config(); void save_config(); - void initialize_input_bindings(); void reset_input_bindings(); void reset_cont_input_bindings(int profile_index); void reset_kb_input_bindings(int profile_index); diff --git a/include/recomp_input.h b/include/recomp_input.h index 9dd1bd9..12b1439 100644 --- a/include/recomp_input.h +++ b/include/recomp_input.h @@ -204,8 +204,14 @@ namespace recomp { int get_controller_by_guid(ControllerGUID guid); int get_controller_count(); ControllerGUID get_guid_from_sdl_controller(SDL_GameController* game_controller); + int get_controller_profile_index_from_sdl_controller(SDL_GameController* game_controller); std::string get_string_from_controller_guid(ControllerGUID guid); + void initialize_input_bindings(); + int get_sp_controller_profile_index(); + int get_sp_keyboard_profile_index(); + int get_mp_keyboard_profile_index(int player_index); + bool get_n64_input(int player_index, uint16_t* buttons_out, float* x_out, float* y_out); void set_rumble(int player_index, bool); void update_rumble(); @@ -288,6 +294,7 @@ namespace recompinput { AssignedPlayer& get_assigned_player(int player_index, bool temp_player = false); bool get_player_is_assigned(int player_index); + recomp::InputDevice get_assigned_player_input_device(int player_index); void start_player_assignment(void); void stop_player_assignment(void); void stop_player_assignment_and_close_modal(void); diff --git a/src/game/config.cpp b/src/game/config.cpp index fceafc5..3cedec3 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -34,13 +34,6 @@ constexpr int ds_default = 1; constexpr int rr_manual_default = 60; constexpr bool developer_mode_default = false; -static std::string keyboard_sp_profile_key = "keyboard_sp"; -static std::string controller_sp_profile_key = "controller_sp"; -static std::string keyboard_sp_profile_name = "Keyboard (SP)"; -static std::string controller_sp_profile_name = "Controller (SP)"; -static int keyboard_sp_profile_index = -1; -static int controller_sp_profile_index = -1; - static bool is_steam_deck = false; ultramodern::renderer::WindowMode wm_default() { @@ -328,18 +321,9 @@ void assign_all_mappings(int profile_index, const recomp::DefaultN64Mappings& va assign_mapping_complete(profile_index, recomp::GameInput::APPLY_MENU, values.apply_menu); }; -void banjo::initialize_input_bindings() { - keyboard_sp_profile_index = recomp::add_input_profile(keyboard_sp_profile_key, keyboard_sp_profile_name, recomp::InputDevice::Keyboard, false); - controller_sp_profile_index = recomp::add_input_profile(controller_sp_profile_key, controller_sp_profile_name, recomp::InputDevice::Controller, false); - - // Set Player 1 to the SP profiles by default. - recomp::set_input_profile_for_player(0, keyboard_sp_profile_index, recomp::InputDevice::Keyboard); - recomp::set_input_profile_for_player(0, controller_sp_profile_index, recomp::InputDevice::Controller); -} - void banjo::reset_input_bindings() { - assign_all_mappings(keyboard_sp_profile_index, recomp::default_n64_keyboard_mappings); - assign_all_mappings(controller_sp_profile_index, recomp::default_n64_controller_mappings); + assign_all_mappings(recomp::get_sp_keyboard_profile_index(), recomp::default_n64_keyboard_mappings); + assign_all_mappings(recomp::get_sp_controller_profile_index(), recomp::default_n64_controller_mappings); } void banjo::reset_cont_input_bindings(int profile_index) { @@ -524,12 +508,12 @@ bool load_controls_config(const std::filesystem::path& path) { } else { // Version 1 of the format only had bindings for Player 1 on the root element. - if (!load_input_device_from_json(config_json, keyboard_sp_profile_index, recomp::InputDevice::Keyboard, "keyboard")) { - assign_all_mappings(keyboard_sp_profile_index, recomp::default_n64_keyboard_mappings); + if (!load_input_device_from_json(config_json, recomp::get_sp_keyboard_profile_index(), recomp::InputDevice::Keyboard, "keyboard")) { + assign_all_mappings(recomp::get_sp_keyboard_profile_index(), recomp::default_n64_keyboard_mappings); } - if (!load_input_device_from_json(config_json, controller_sp_profile_index, recomp::InputDevice::Controller, "controller")) { - assign_all_mappings(controller_sp_profile_index, recomp::default_n64_controller_mappings); + if (!load_input_device_from_json(config_json, recomp::get_sp_controller_profile_index(), recomp::InputDevice::Controller, "controller")) { + assign_all_mappings(recomp::get_sp_controller_profile_index(), recomp::default_n64_controller_mappings); } } @@ -583,7 +567,7 @@ void banjo::load_config() { save_graphics_config(graphics_path); } - banjo::initialize_input_bindings(); + recomp::initialize_input_bindings(); if (!load_controls_config(controls_path)) { banjo::reset_input_bindings(); diff --git a/src/game/controls.cpp b/src/game/controls.cpp index 549f2f6..78515e8 100644 --- a/src/game/controls.cpp +++ b/src/game/controls.cpp @@ -31,6 +31,17 @@ struct Controller { static std::vector controllers; static std::unordered_map controller_hash_index_map{}; +static int keyboard_sp_profile_index = -1; +static int controller_sp_profile_index = -1; + +static const std::string keyboard_sp_profile_key = "keyboard_sp"; +static const std::string controller_sp_profile_key = "controller_sp"; +static const std::string keyboard_sp_profile_name = "Keyboard (SP)"; +static const std::string controller_sp_profile_name = "Controller (SP)"; + +static const std::string keyboard_mp_profile_key = "keyboard_mp_player_"; // + player index +static const std::string keyboard_mp_profile_name = "Keyboard "; // + "(player number)" + // Make the button value array, which maps a button index to its bit field. #define DEFINE_INPUT(name, value, readable) uint16_t(value##u), static const std::array n64_button_values = { @@ -266,6 +277,62 @@ recomp::ControllerGUID recomp::get_guid_from_sdl_controller(SDL_GameController * return guid; } +int recomp::get_controller_profile_index_from_sdl_controller(SDL_GameController *game_controller) { + if (game_controller == nullptr) { + return -1; + } + + ControllerGUID guid = recomp::get_guid_from_sdl_controller(game_controller); + if (guid.hash == 0) { + return -1; + } + + int controller_index = recomp::get_controller_by_guid(guid); + if (controller_index < 0) { + return -1; + } + + return recomp::get_controller_profile_index(controller_index); +} + +std::string get_mp_keyboard_profile_key(int player_index) { + return keyboard_mp_profile_key + std::to_string(player_index); +} + +std::string get_mp_keyboard_profile_name(int player_index) { + return keyboard_mp_profile_name + "(Player " + std::to_string(player_index + 1) + ")"; +} + +void recomp::initialize_input_bindings() { + keyboard_sp_profile_index = recomp::add_input_profile(keyboard_sp_profile_key, keyboard_sp_profile_name, recomp::InputDevice::Keyboard, false); + controller_sp_profile_index = recomp::add_input_profile(controller_sp_profile_key, controller_sp_profile_name, recomp::InputDevice::Controller, false); + + // Set Player 1 to the SP profiles by default. + recomp::set_input_profile_for_player(0, keyboard_sp_profile_index, recomp::InputDevice::Keyboard); + recomp::set_input_profile_for_player(0, controller_sp_profile_index, recomp::InputDevice::Controller); + + for (int i = 0; i < recompinput::get_num_players(); i++) { + recomp::add_input_profile( + get_mp_keyboard_profile_key(i), + get_mp_keyboard_profile_name(i), + recomp::InputDevice::Keyboard, + false + ); + } +} + +int recomp::get_sp_controller_profile_index() { + return controller_sp_profile_index; +} + +int recomp::get_sp_keyboard_profile_index() { + return keyboard_sp_profile_index; +} + +int recomp::get_mp_keyboard_profile_index(int player_index) { + return recomp::get_input_profile_by_key(get_mp_keyboard_profile_key(player_index)); +} + std::string recomp::get_string_from_controller_guid(ControllerGUID guid) { return "SERIAL_" + guid.serial + "_VID_" + std::to_string(guid.vendor) + "_PID_" + std::to_string(guid.product) +"_VERSION_" + std::to_string(guid.version) +"_CRC16_" + std::to_string(guid.crc16); } diff --git a/src/game/input.cpp b/src/game/input.cpp index a1ddacd..0d2b511 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -88,6 +88,21 @@ recompinput::AssignedPlayer& recompinput::get_assigned_player(int player_index, } } +recomp::InputDevice recompinput::get_assigned_player_input_device(int player_index) { + if (player_index < 0 || player_index >= recompinput::get_num_players()) { + return recomp::InputDevice::COUNT; + } + + const auto& assigned_player = InputState.assigned_controllers[player_index]; + if (assigned_player.controller != nullptr) { + return recomp::InputDevice::Controller; + } else if (assigned_player.keyboard_enabled) { + return recomp::InputDevice::Keyboard; + } else { + return recomp::InputDevice::COUNT; + } +} + bool recompinput::get_player_is_assigned(int player_index) { if (player_index < 0 || player_index >= recompinput::get_num_players()) { return false; @@ -122,6 +137,14 @@ void recompinput::commit_player_assignment() { for (int i = 0; i < recompinput::get_num_players(); i++) { InputState.assigned_controllers[i] = player_assignment_state.temp_assigned_players[i]; + if (InputState.assigned_controllers[i].controller != nullptr) { + int cont_profile_index = recomp::get_controller_profile_index_from_sdl_controller(InputState.assigned_controllers[i].controller); + if (cont_profile_index >= 0) { + recomp::set_input_profile_for_player(i, cont_profile_index, InputDevice::Controller); + } + } else { + recomp::set_input_profile_for_player(i, recomp::get_mp_keyboard_profile_index(i), InputDevice::Keyboard); + } } } diff --git a/src/ui/elements/ui_element.cpp b/src/ui/elements/ui_element.cpp index 43405e0..c02236e 100644 --- a/src/ui/elements/ui_element.cpp +++ b/src/ui/elements/ui_element.cpp @@ -547,6 +547,18 @@ Element *Element::select_add_option(std::string_view text, std::string_view valu return option_element; } +void Element::select_set_selection(std::string_view option_value) { + if (base->GetTagName() != "select") { + return; + } + + Rml::ElementFormControlSelect* select = (Rml::ElementFormControlSelect *)(base); + if (!select) { + return; + } + select->SetValue(std::string(option_value)); +} + Element Element::get_element_with_tag_name(std::string_view tag_name) { for (int i = 0; i < base->GetNumChildren(true); i++) { Rml::Element* child = base->GetChild(i); diff --git a/src/ui/elements/ui_element.h b/src/ui/elements/ui_element.h index 848a705..382c644 100644 --- a/src/ui/elements/ui_element.h +++ b/src/ui/elements/ui_element.h @@ -105,6 +105,7 @@ public: bool is_pseudo_class_set(Rml::String pseudo_class); Element *select_add_option(std::string_view text, std::string_view value); + void select_set_selection(std::string_view option_value); }; void queue_ui_callback(recompui::ResourceId resource, const Event& e, const UICallback& callback); diff --git a/src/ui/elements/ui_select.cpp b/src/ui/elements/ui_select.cpp index 2c89a12..d02a840 100644 --- a/src/ui/elements/ui_select.cpp +++ b/src/ui/elements/ui_select.cpp @@ -85,15 +85,14 @@ namespace recompui { constexpr float select_element_caret_size = 24.0f; Select::Select( - Element *parent, std::vector options, const std::string &label, const std::string &default_text + Element *parent, std::vector options, std::string selected_option_value ) : Element( parent, Events(EventType::Text, EventType::Click, EventType::Hover, EventType::Enable, EventType::Focus), "select", false), - label(label), - default_text(default_text) + selected_option_value(selected_option_value) { this->options = options; @@ -285,6 +284,11 @@ namespace recompui { auto &option = options[i]; Option *option_element = context.create_element