diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 15197a0b71..b500a251f5 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -226,7 +226,6 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs) out << YAML::Value; encode(out, *node); } - out << YAML::EndMap; return; } @@ -237,10 +236,20 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs) { out << str; } - out << YAML::EndSeq; return; } + case type::map: + { + out << YAML::BeginMap; + for (const auto& np : static_cast(rhs).get_map()) + { + out << YAML::Key << np.first; + out << YAML::Value << fmt::format("%s", np.second); + } + out << YAML::EndMap; + return; + } case type::log: { out << YAML::BeginMap; @@ -250,7 +259,6 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs) out << YAML::Key << np.first; out << YAML::Value << fmt::format("%s", np.second); } - out << YAML::EndMap; return; } @@ -305,6 +313,25 @@ void cfg::decode(const YAML::Node& data, cfg::_base& rhs, bool dynamic) break; } + case type::map: + { + if (!data.IsMap()) + { + return; + } + + std::map values; + + for (const auto& pair : data) + { + if (!pair.first.IsScalar() || !pair.second.IsScalar()) continue; + + values.emplace(pair.first.Scalar(), pair.second.Scalar()); + } + + static_cast(rhs).set_map(std::move(values)); + break; + } case type::log: { if (data.IsScalar() || data.IsSequence()) @@ -387,6 +414,26 @@ void cfg::set_entry::from_default() m_set = {}; } +std::string cfg::map_entry::get_value(const std::string& key) +{ + return m_map.contains(key) ? m_map.at(key) : ""; +} + +void cfg::map_entry::set_value(const std::string& key, const std::string& value) +{ + m_map[key] = value; +} + +void cfg::map_entry::set_map(std::map&& map) +{ + m_map = std::move(map); +} + +void cfg::map_entry::from_default() +{ + set_map({}); +} + void cfg::log_entry::set_map(std::map&& map) { m_map = std::move(map); diff --git a/Utilities/Config.h b/Utilities/Config.h index d891b47c76..51fd0c2d43 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -36,6 +36,7 @@ namespace cfg uint, // cfg::uint type string, // cfg::string type set, // cfg::set_entry type + map, // cfg::map_entry type log, }; @@ -473,6 +474,29 @@ namespace cfg } }; + class map_entry final : public _base + { + std::map m_map{}; + + public: + map_entry(node* owner, const std::string& name) + : _base(type::map, owner, name, true) + { + } + + const std::map& get_map() const + { + return m_map; + } + + std::string get_value(const std::string& key); + + void set_value(const std::string& key, const std::string& value); + void set_map(std::map&& map); + + void from_default() override; + }; + class log_entry final : public _base { std::map m_map{}; diff --git a/rpcs3/Emu/Io/Null/NullPadHandler.h b/rpcs3/Emu/Io/Null/NullPadHandler.h index cd77966721..dcba405059 100644 --- a/rpcs3/Emu/Io/Null/NullPadHandler.h +++ b/rpcs3/Emu/Io/Null/NullPadHandler.h @@ -15,13 +15,10 @@ public: return true; } - void init_config(pad_config* cfg, const std::string& /*name*/) override + void init_config(cfg_pad* cfg) override { if (!cfg) return; - // This profile does not need a save location - cfg->cfg_name = ""; - // Reset default button mapping cfg->ls_left.def = ""; cfg->ls_down.def = ""; diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 287d4e6ce5..894cfdb2d5 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -299,39 +299,11 @@ bool PadHandlerBase::has_pressure_intensity_button() const return b_has_pressure_intensity_button; } -std::string PadHandlerBase::get_config_dir(pad_handler type, const std::string& title_id) -{ - if (!title_id.empty()) - { - return rpcs3::utils::get_custom_input_config_dir(title_id) + fmt::format("%s", type) + "/"; - } - return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/"; -} - -std::string PadHandlerBase::get_config_filename(int i, const std::string& title_id) -{ - if (!title_id.empty() && fs::is_file(rpcs3::utils::get_custom_input_config_path(title_id))) - { - const std::string path = rpcs3::utils::get_custom_input_config_dir(title_id) + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml"; - if (fs::is_file(path)) - { - return path; - } - } - return fs::get_config_dir() + "/InputConfigs/" + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml"; -} - void PadHandlerBase::init_configs() { - int index = 0; - for (u32 i = 0; i < MAX_GAMEPADS; i++) { - if (g_cfg_input.player[i]->handler == m_type) - { - init_config(&m_pad_configs[index], get_config_filename(i, pad::g_title_id)); - index++; - } + init_config(&m_pad_configs[i]); } } @@ -460,24 +432,23 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, const std::string return false; } - const int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - pad_device->config = &m_pad_configs[index]; + m_pad_configs[player_id].from_string(g_cfg_input.player[player_id]->config.to_string()); + pad_device->config = &m_pad_configs[player_id]; pad_device->player_id = player_id; - pad_config* profile = pad_device->config; - if (profile == nullptr) + cfg_pad* config = pad_device->config; + if (config == nullptr) { - input_log.error("PadHandlerBase::bindPadToDevice: no profile found for device %d '%s'", index, device); + input_log.error("PadHandlerBase::bindPadToDevice: no profile found for device %d '%s'", bindings.size(), device); return false; } - std::array mapping = get_mapped_key_codes(pad_device, profile); + std::array mapping = get_mapped_key_codes(pad_device, config); u32 pclass_profile = 0x0; - for (const auto& product : input::get_products_by_class(profile->device_class_type)) + for (const auto& product : input::get_products_by_class(config->device_class_type)) { - if (product.vendor_id == profile->vendor_id && product.product_id == profile->product_id) + if (product.vendor_id == config->vendor_id && product.product_id == config->product_id) { pclass_profile = product.pclass_profile; } @@ -488,11 +459,11 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, const std::string CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - profile->device_class_type, + config->device_class_type, pclass_profile, - profile->vendor_id, - profile->product_id, - profile->pressure_intensity + config->vendor_id, + config->product_id, + config->pressure_intensity ); pad->m_buttons.emplace_back(special_button_offset, mapping[button::pressure_intensity_button], special_button_value::pressure_intensity); @@ -535,37 +506,39 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, const std::string return true; } -std::array PadHandlerBase::get_mapped_key_codes(const std::shared_ptr& /*device*/, const pad_config* profile) +std::array PadHandlerBase::get_mapped_key_codes(const std::shared_ptr& /*device*/, const cfg_pad* cfg) { - std::array mapping; + std::array mapping{}; + if (!cfg) + return mapping; - mapping[button::up] = FindKeyCode(button_list, profile->up); - mapping[button::down] = FindKeyCode(button_list, profile->down); - mapping[button::left] = FindKeyCode(button_list, profile->left); - mapping[button::right] = FindKeyCode(button_list, profile->right); - mapping[button::cross] = FindKeyCode(button_list, profile->cross); - mapping[button::square] = FindKeyCode(button_list, profile->square); - mapping[button::circle] = FindKeyCode(button_list, profile->circle); - mapping[button::triangle] = FindKeyCode(button_list, profile->triangle); - mapping[button::start] = FindKeyCode(button_list, profile->start); - mapping[button::select] = FindKeyCode(button_list, profile->select); - mapping[button::l1] = FindKeyCode(button_list, profile->l1); - mapping[button::l2] = FindKeyCode(button_list, profile->l2); - mapping[button::l3] = FindKeyCode(button_list, profile->l3); - mapping[button::r1] = FindKeyCode(button_list, profile->r1); - mapping[button::r2] = FindKeyCode(button_list, profile->r2); - mapping[button::r3] = FindKeyCode(button_list, profile->r3); - mapping[button::ls_left] = FindKeyCode(button_list, profile->ls_left); - mapping[button::ls_right] = FindKeyCode(button_list, profile->ls_right); - mapping[button::ls_down] = FindKeyCode(button_list, profile->ls_down); - mapping[button::ls_up] = FindKeyCode(button_list, profile->ls_up); - mapping[button::rs_left] = FindKeyCode(button_list, profile->rs_left); - mapping[button::rs_right] = FindKeyCode(button_list, profile->rs_right); - mapping[button::rs_down] = FindKeyCode(button_list, profile->rs_down); - mapping[button::rs_up] = FindKeyCode(button_list, profile->rs_up); - mapping[button::ps] = FindKeyCode(button_list, profile->ps); + mapping[button::up] = FindKeyCode(button_list, cfg->up); + mapping[button::down] = FindKeyCode(button_list, cfg->down); + mapping[button::left] = FindKeyCode(button_list, cfg->left); + mapping[button::right] = FindKeyCode(button_list, cfg->right); + mapping[button::cross] = FindKeyCode(button_list, cfg->cross); + mapping[button::square] = FindKeyCode(button_list, cfg->square); + mapping[button::circle] = FindKeyCode(button_list, cfg->circle); + mapping[button::triangle] = FindKeyCode(button_list, cfg->triangle); + mapping[button::start] = FindKeyCode(button_list, cfg->start); + mapping[button::select] = FindKeyCode(button_list, cfg->select); + mapping[button::l1] = FindKeyCode(button_list, cfg->l1); + mapping[button::l2] = FindKeyCode(button_list, cfg->l2); + mapping[button::l3] = FindKeyCode(button_list, cfg->l3); + mapping[button::r1] = FindKeyCode(button_list, cfg->r1); + mapping[button::r2] = FindKeyCode(button_list, cfg->r2); + mapping[button::r3] = FindKeyCode(button_list, cfg->r3); + mapping[button::ls_left] = FindKeyCode(button_list, cfg->ls_left); + mapping[button::ls_right] = FindKeyCode(button_list, cfg->ls_right); + mapping[button::ls_down] = FindKeyCode(button_list, cfg->ls_down); + mapping[button::ls_up] = FindKeyCode(button_list, cfg->ls_up); + mapping[button::rs_left] = FindKeyCode(button_list, cfg->rs_left); + mapping[button::rs_right] = FindKeyCode(button_list, cfg->rs_right); + mapping[button::rs_down] = FindKeyCode(button_list, cfg->rs_down); + mapping[button::rs_up] = FindKeyCode(button_list, cfg->rs_up); + mapping[button::ps] = FindKeyCode(button_list, cfg->ps); - mapping[button::pressure_intensity_button] = FindKeyCode(button_list, profile->pressure_intensity_button); + mapping[button::pressure_intensity_button] = FindKeyCode(button_list, cfg->pressure_intensity_button); return mapping; } diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index ee68240c9e..27217b1068 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -15,7 +15,7 @@ class PadDevice { public: - pad_config* config{ nullptr }; + cfg_pad* config{ nullptr }; u8 player_id{0}; }; @@ -83,7 +83,7 @@ protected: bool b_has_rumble = false; bool b_has_config = false; bool b_has_pressure_intensity_button = true; - std::array m_pad_configs; + std::array m_pad_configs; std::vector, std::shared_ptr>> bindings; std::unordered_map button_list; std::vector blacklist; @@ -153,9 +153,6 @@ public: bool has_battery() const; bool has_pressure_intensity_button() const; - static std::string get_config_dir(pad_handler type, const std::string& title_id = ""); - static std::string get_config_filename(int i, const std::string& title_id = ""); - u16 NormalizeStickInput(u16 raw_value, int threshold, int multiplier, bool ignore_threshold = false) const; void convert_stick_values(u16& x_out, u16& y_out, const s32& x_in, const s32& y_in, const s32& deadzone, const s32& padsquircling) const; @@ -171,7 +168,7 @@ public: virtual void ThreadProc(); // Binds a Pad to a device virtual bool bindPadToDevice(std::shared_ptr pad, const std::string& device, u8 player_id); - virtual void init_config(pad_config* /*cfg*/, const std::string& /*name*/) = 0; + virtual void init_config(cfg_pad* /*cfg*/) = 0; virtual void get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool get_blacklist, const std::vector& buttons = {}); private: @@ -187,7 +184,7 @@ private: virtual pad_preview_values get_preview_values(const std::unordered_map& /*data*/) { return {}; } protected: - virtual std::array get_mapped_key_codes(const std::shared_ptr& /*device*/, const pad_config* profile); + virtual std::array get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg); virtual void get_mapping(const std::shared_ptr& device, const std::shared_ptr& pad); void TranslateButtonPress(const std::shared_ptr& device, u64 keyCode, bool& pressed, u16& val, bool ignore_stick_threshold = false, bool ignore_trigger_threshold = false); void init_configs(); diff --git a/rpcs3/Emu/Io/pad_config.cpp b/rpcs3/Emu/Io/pad_config.cpp index 2d96f509dc..d68e1c1e23 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -2,64 +2,103 @@ #include "pad_config.h" #include "Emu/system_utils.hpp" -cfg_input::cfg_input() - : cfg_name(fs::get_config_dir() + "/config_input.yml") +LOG_CHANNEL(input_log, "Input"); + +bool cfg_input::load(const std::string& title_id, const std::string& profile, bool strict) { -} + // Check custom config first + std::string cfg_name; -bool cfg_input::load(const std::string& title_id) -{ - cfg_name = rpcs3::utils::get_custom_input_config_path(title_id); - - if (!fs::is_file(cfg_name)) - { - cfg_name = fs::get_config_dir() + "/config_input.yml"; - } - - if (fs::file cfg_file{ cfg_name, fs::read }) - { - return from_string(cfg_file.to_string()); - } - else - { - // Add keyboard by default - player[0]->handler.from_string(fmt::format("%s", pad_handler::keyboard)); - player[0]->device.from_string(pad::keyboard_device_name.data()); - } - - return false; -} - -void cfg_input::save(const std::string& title_id) -{ if (title_id.empty()) { - cfg_name = fs::get_config_dir() + "/config_input.yml"; + cfg_name = rpcs3::utils::get_input_config_dir() + profile + ".yml"; } else { cfg_name = rpcs3::utils::get_custom_input_config_path(title_id); } - fs::file(cfg_name, fs::rewrite).write(to_string()); -} + if (!strict && !fs::is_file(cfg_name)) + { + cfg_name = rpcs3::utils::get_input_config_dir() + g_cfg_profile.default_profile + ".yml"; + } -bool pad_config::exist() const -{ - return fs::is_file(cfg_name); -} + from_default(); -bool pad_config::load() -{ if (fs::file cfg_file{ cfg_name, fs::read }) { - return from_string(cfg_file.to_string()); + input_log.notice("Loading pad profile: '%s'", cfg_name); + + if (std::string content = cfg_file.to_string(); !content.empty()) + { + return from_string(content); + } } + // Add keyboard by default + input_log.notice("Pad profile empty. Adding default keyboard pad handler"); + player[0]->handler.from_string(fmt::format("%s", pad_handler::keyboard)); + player[0]->device.from_string(pad::keyboard_device_name.data()); + return false; } -void pad_config::save() const +void cfg_input::save(const std::string& title_id, const std::string& profile) const { - fs::file(cfg_name, fs::rewrite).write(to_string()); + std::string cfg_name; + + if (title_id.empty()) + { + cfg_name = rpcs3::utils::get_input_config_dir() + profile + ".yml"; + input_log.notice("Saving pad config profile '%s' to '%s'", profile, cfg_name); + } + else + { + cfg_name = rpcs3::utils::get_custom_input_config_path(title_id); + input_log.notice("Saving custom pad config for '%s' to '%s'", title_id, cfg_name); + } + + if (!fs::create_path(fs::get_parent_dir(cfg_name))) + { + input_log.fatal("Failed to create path: %s (%s)", cfg_name, fs::g_tls_error); + } + + if (auto cfg_file = fs::file(cfg_name, fs::rewrite)) + { + cfg_file.write(to_string()); + } + else + { + input_log.error("Failed to save pad config to '%s'", cfg_name); + } +} + +cfg_profile::cfg_profile() + : path(rpcs3::utils::get_input_config_root() + "/active_profiles.yml") +{ +} + +bool cfg_profile::load() +{ + if (fs::file cfg_file{ path, fs::read }) + { + return from_string(cfg_file.to_string()); + } + + from_default(); + return false; +} + +void cfg_profile::save() const +{ + input_log.notice("Saving pad profile config to '%s'", path); + + if (auto cfg_file = fs::file(path, fs::rewrite)) + { + cfg_file.write(to_string()); + } + else + { + input_log.error("Failed to save pad profile config to '%s'", path); + } } diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 69963062b5..a9d5048d53 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -4,44 +4,17 @@ #include "Utilities/Config.h" +#include + namespace pad { constexpr static std::string_view keyboard_device_name = "Keyboard"; } -struct cfg_player final : cfg::node +struct cfg_pad final : cfg::node { - pad_handler def_handler = pad_handler::null; - cfg_player(node* owner, const std::string& name, pad_handler type) : cfg::node(owner, name), def_handler(type) {} - - cfg::_enum handler{ this, "Handler", def_handler }; - cfg::string device{ this, "Device", handler.to_string() }; - cfg::string profile{ this, "Profile", "Default Profile" }; -}; - -struct cfg_input final : cfg::node -{ - cfg_input(); - - std::string cfg_name; - - cfg_player player1{ this, "Player 1 Input", pad_handler::null }; - cfg_player player2{ this, "Player 2 Input", pad_handler::null }; - cfg_player player3{ this, "Player 3 Input", pad_handler::null }; - cfg_player player4{ this, "Player 4 Input", pad_handler::null }; - cfg_player player5{ this, "Player 5 Input", pad_handler::null }; - cfg_player player6{ this, "Player 6 Input", pad_handler::null }; - cfg_player player7{ this, "Player 7 Input", pad_handler::null }; - - cfg_player* player[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! - - bool load(const std::string& title_id = ""); - void save(const std::string& title_id = ""); -}; - -struct pad_config final : cfg::node -{ - std::string cfg_name{}; + cfg_pad() {}; + cfg_pad(node* owner, const std::string& name) : cfg::node(owner, name) {} cfg::string ls_left{ this, "Left Stick Left", "" }; cfg::string ls_down{ this, "Left Stick Down", "" }; @@ -106,10 +79,46 @@ struct pad_config final : cfg::node cfg::uint<0, 5> device_class_type{ this, "Device Class Type", 0 }; cfg::uint<0, 65535> vendor_id{ this, "Vendor ID", 0 }; cfg::uint<0, 65535> product_id{ this, "Product ID", 0 }; +}; - bool exist() const; +struct cfg_player final : cfg::node +{ + pad_handler def_handler = pad_handler::null; + cfg_player(node* owner, const std::string& name, pad_handler type) : cfg::node(owner, name), def_handler(type) {} + + cfg::_enum handler{ this, "Handler", def_handler }; + cfg::string device{ this, "Device", handler.to_string() }; + cfg_pad config{ this, "Config" }; +}; + +struct cfg_input final : cfg::node +{ + cfg_player player1{ this, "Player 1 Input", pad_handler::null }; + cfg_player player2{ this, "Player 2 Input", pad_handler::null }; + cfg_player player3{ this, "Player 3 Input", pad_handler::null }; + cfg_player player4{ this, "Player 4 Input", pad_handler::null }; + cfg_player player5{ this, "Player 5 Input", pad_handler::null }; + cfg_player player6{ this, "Player 6 Input", pad_handler::null }; + cfg_player player7{ this, "Player 7 Input", pad_handler::null }; + + std::array player{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! + + bool load(const std::string& title_id = "", const std::string& profile = "", bool strict = false); + void save(const std::string& title_id, const std::string& profile = "") const; +}; + +struct cfg_profile final : cfg::node +{ + cfg_profile(); bool load(); void save() const; + + const std::string path; + const std::string global_key = "global"; + const std::string default_profile = "Default"; + + cfg::map_entry active_profiles{ this, "Active Profiles" }; }; extern cfg_input g_cfg_input; +extern cfg_profile g_cfg_profile; diff --git a/rpcs3/Emu/system_utils.cpp b/rpcs3/Emu/system_utils.cpp index 398507e2d5..30a1ee8b1e 100644 --- a/rpcs3/Emu/system_utils.cpp +++ b/rpcs3/Emu/system_utils.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "system_utils.hpp" #include "system_config.h" +#include "Emu/Io/pad_config.h" #include "util/sysinfo.hpp" #include "Utilities/File.h" #include "Utilities/StrUtil.h" @@ -225,19 +226,23 @@ namespace rpcs3::utils return path; } - std::string get_custom_input_config_dir(const std::string& title_id) + std::string get_input_config_root() { - // Notice: the extra folder for each title id may be removed at a later stage - // Warning: make sure to change any function that removes this directory as well #ifdef _WIN32 - return fs::get_config_dir() + "config/custom_input_configs/" + title_id + "/"; + return fs::get_config_dir() + "config/input_configs/"; #else - return fs::get_config_dir() + "custom_input_configs/" + title_id + "/"; + return fs::get_config_dir() + "input_configs/"; #endif } + std::string get_input_config_dir(const std::string& title_id) + { + return get_input_config_root() + (title_id.empty() ? "global" : title_id) + "/"; + } + std::string get_custom_input_config_path(const std::string& title_id) { - return get_custom_input_config_dir(title_id) + "/config_input_" + title_id + ".yml"; + if (title_id.empty()) return ""; + return get_input_config_dir(title_id) + g_cfg_profile.default_profile + ".yml"; } } diff --git a/rpcs3/Emu/system_utils.hpp b/rpcs3/Emu/system_utils.hpp index 573b083fb9..2342cab946 100644 --- a/rpcs3/Emu/system_utils.hpp +++ b/rpcs3/Emu/system_utils.hpp @@ -27,6 +27,8 @@ namespace rpcs3::utils std::string get_custom_config_dir(); std::string get_custom_config_path(const std::string& title_id, bool get_deprecated_path = false); - std::string get_custom_input_config_dir(const std::string& title_id); + + std::string get_input_config_root(); + std::string get_input_config_dir(const std::string& title_id = ""); std::string get_custom_input_config_path(const std::string& title_id); } diff --git a/rpcs3/Input/ds3_pad_handler.cpp b/rpcs3/Input/ds3_pad_handler.cpp index 7342ef12ca..710ff45ff7 100644 --- a/rpcs3/Input/ds3_pad_handler.cpp +++ b/rpcs3/Input/ds3_pad_handler.cpp @@ -137,7 +137,7 @@ void ds3_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 lar { if (g_cfg_input.player[i]->device.to_string() == padId) { - m_pad_configs[index].load(); + m_pad_configs[index].from_string(g_cfg_input.player[i]->config.to_string()); device->config = &m_pad_configs[index]; break; } @@ -197,13 +197,10 @@ int ds3_pad_handler::send_output_report(ds3_device* ds3dev) return hid_write(ds3dev->hidDevice, &output_report.report_id, sizeof(output_report)); } -void ds3_pad_handler::init_config(pad_config* cfg, const std::string& name) +void ds3_pad_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = button_list.at(DS3KeyCodes::LSXNeg); cfg->ls_down.def = button_list.at(DS3KeyCodes::LSYNeg); @@ -560,7 +557,7 @@ void ds3_pad_handler::apply_pad_data(const std::shared_ptr& device, c if (!dev || !dev->hidDevice || !dev->config || !pad) return; - pad_config* config = dev->config; + cfg_pad* config = dev->config; const int idx_l = config->switch_vibration_motors ? 1 : 0; const int idx_s = config->switch_vibration_motors ? 0 : 1; diff --git a/rpcs3/Input/ds3_pad_handler.h b/rpcs3/Input/ds3_pad_handler.h index 390db7aa4e..2fc351db50 100644 --- a/rpcs3/Input/ds3_pad_handler.h +++ b/rpcs3/Input/ds3_pad_handler.h @@ -82,7 +82,7 @@ public: void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; u32 get_battery_level(const std::string& padId) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; private: ds3_pad_handler::DataStatus get_data(ds3_device* ds3dev) override; diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index 02899019e2..6098976e34 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -129,13 +129,10 @@ ds4_pad_handler::ds4_pad_handler() m_thumb_threshold = thumb_max / 2; } -void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name) +void ds4_pad_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = button_list.at(DS4KeyCodes::LSXNeg); cfg->ls_down.def = button_list.at(DS4KeyCodes::LSYNeg); @@ -215,7 +212,7 @@ void ds4_pad_handler::SetPadData(const std::string& padId, u8 player_id, u32 lar { if (g_cfg_input.player[i]->device.to_string() == padId) { - m_pad_configs[index].load(); + m_pad_configs[index].from_string(g_cfg_input.player[i]->config.to_string()); device->config = &m_pad_configs[index]; break; } @@ -855,7 +852,7 @@ void ds4_pad_handler::apply_pad_data(const std::shared_ptr& device, c if (!ds4_dev || !ds4_dev->hidDevice || !ds4_dev->config || !pad) return; - pad_config* config = ds4_dev->config; + cfg_pad* config = ds4_dev->config; // Attempt to send rumble no matter what const int idx_l = config->switch_vibration_motors ? 1 : 0; diff --git a/rpcs3/Input/ds4_pad_handler.h b/rpcs3/Input/ds4_pad_handler.h index b60e483f8a..816eda727a 100644 --- a/rpcs3/Input/ds4_pad_handler.h +++ b/rpcs3/Input/ds4_pad_handler.h @@ -58,7 +58,7 @@ public: void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; u32 get_battery_level(const std::string& padId) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; private: // This function gets us usuable buffer from the rawbuffer of padData diff --git a/rpcs3/Input/dualsense_pad_handler.cpp b/rpcs3/Input/dualsense_pad_handler.cpp index 006c4d7b37..c9383a363d 100644 --- a/rpcs3/Input/dualsense_pad_handler.cpp +++ b/rpcs3/Input/dualsense_pad_handler.cpp @@ -240,13 +240,10 @@ void dualsense_pad_handler::check_add_device(hid_device* hidDevice, std::string_ dualsense_log.notice("Added device: bluetooth=%d, data_mode=%s, serial='%s', hw_version: 0x%x, fw_version: 0x%x, path='%s'", device->bt_controller, device->data_mode, serial, hw_version, fw_version, device->path); } -void dualsense_pad_handler::init_config(pad_config* cfg, const std::string& name) +void dualsense_pad_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = button_list.at(DualSenseKeyCodes::LSXNeg); cfg->ls_down.def = button_list.at(DualSenseKeyCodes::LSYNeg); @@ -1008,7 +1005,7 @@ void dualsense_pad_handler::apply_pad_data(const std::shared_ptr& dev if (!dualsense_dev || !dualsense_dev->hidDevice || !dualsense_dev->config || !pad) return; - pad_config* config = dualsense_dev->config; + cfg_pad* config = dualsense_dev->config; // Attempt to send rumble no matter what const int idx_l = config->switch_vibration_motors ? 1 : 0; @@ -1104,7 +1101,7 @@ void dualsense_pad_handler::SetPadData(const std::string& padId, u8 player_id, u { if (g_cfg_input.player[i]->device.to_string() == padId) { - m_pad_configs[index].load(); + m_pad_configs[index].from_string(g_cfg_input.player[i]->config.to_string()); device->config = &m_pad_configs[index]; break; } diff --git a/rpcs3/Input/dualsense_pad_handler.h b/rpcs3/Input/dualsense_pad_handler.h index fea229f544..39f3c29519 100644 --- a/rpcs3/Input/dualsense_pad_handler.h +++ b/rpcs3/Input/dualsense_pad_handler.h @@ -71,7 +71,7 @@ public: void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; u32 get_battery_level(const std::string& padId) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; private: bool get_calibration_data(DualSenseDevice* dualsense_device) const; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 45a91487f1..f7d971efd9 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -47,13 +47,10 @@ evdev_joystick_handler::~evdev_joystick_handler() Close(); } -void evdev_joystick_handler::init_config(pad_config* cfg, const std::string& name) +void evdev_joystick_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = rev_axis_list.at(ABS_X); cfg->ls_down.def = axis_list.at(ABS_Y); @@ -902,12 +899,11 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std m_dev = std::make_shared(); - const int index = static_cast(bindings.size()); - m_pad_configs[index].load(); - m_dev->config = &m_pad_configs[index]; + m_pad_configs[player_id].from_string(g_cfg_input.player[player_id]->config.to_string()); + m_dev->config = &m_pad_configs[player_id]; m_dev->player_id = player_id; - pad_config* p_profile = m_dev->config; - if (p_profile == nullptr) + cfg_pad* cfg = m_dev->config; + if (cfg == nullptr) return false; std::unordered_map axis_orientations; @@ -946,9 +942,9 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std u32 pclass_profile = 0x0; - for (const auto product : input::get_products_by_class(p_profile->device_class_type)) + for (const auto product : input::get_products_by_class(cfg->device_class_type)) { - if (product.vendor_id == p_profile->vendor_id && product.product_id == p_profile->product_id) + if (product.vendor_id == cfg->vendor_id && product.product_id == cfg->product_id) { pclass_profile = product.pclass_profile; } @@ -959,48 +955,48 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type, + cfg->device_class_type, pclass_profile, - p_profile->vendor_id, - p_profile->product_id, - p_profile->pressure_intensity + cfg->vendor_id, + cfg->product_id, + cfg->pressure_intensity ); - pad->m_buttons.emplace_back(special_button_offset, evdevbutton(p_profile->pressure_intensity_button).code, special_button_value::pressure_intensity); + pad->m_buttons.emplace_back(special_button_offset, evdevbutton(cfg->pressure_intensity_button).code, special_button_value::pressure_intensity); pad->m_pressure_intensity_button_index = pad->m_buttons.size() - 1; - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->triangle).code, CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->circle).code, CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->cross).code, CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->square).code, CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->triangle).code, CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->circle).code, CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->cross).code, CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->square).code, CELL_PAD_CTRL_SQUARE); - m_dev->trigger_left = evdevbutton(p_profile->l2); + m_dev->trigger_left = evdevbutton(cfg->l2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left.code, CELL_PAD_CTRL_L2); - m_dev->trigger_right = evdevbutton(p_profile->r2); + m_dev->trigger_right = evdevbutton(cfg->r2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right.code, CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->l1).code, CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->r1).code, CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->start).code, CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->select).code, CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->l3).code, CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->r3).code, CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(p_profile->ps).code, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->up).code, CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->down).code, CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->left).code, CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(p_profile->right).code, CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->l1).code, CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->r1).code, CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->start).code, CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->select).code, CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->l3).code, CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->r3).code, CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->ps).code, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->up).code, CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->down).code, CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->left).code, CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->right).code, CELL_PAD_CTRL_RIGHT); //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - m_dev->axis_left[0] = evdevbutton(p_profile->ls_right); - m_dev->axis_left[1] = evdevbutton(p_profile->ls_left); - m_dev->axis_left[2] = evdevbutton(p_profile->ls_up); - m_dev->axis_left[3] = evdevbutton(p_profile->ls_down); - m_dev->axis_right[0] = evdevbutton(p_profile->rs_right); - m_dev->axis_right[1] = evdevbutton(p_profile->rs_left); - m_dev->axis_right[2] = evdevbutton(p_profile->rs_up); - m_dev->axis_right[3] = evdevbutton(p_profile->rs_down); + m_dev->axis_left[0] = evdevbutton(cfg->ls_right); + m_dev->axis_left[1] = evdevbutton(cfg->ls_left); + m_dev->axis_left[2] = evdevbutton(cfg->ls_up); + m_dev->axis_left[3] = evdevbutton(cfg->ls_down); + m_dev->axis_right[0] = evdevbutton(cfg->rs_right); + m_dev->axis_right[1] = evdevbutton(cfg->rs_left); + m_dev->axis_right[2] = evdevbutton(cfg->rs_up); + m_dev->axis_right[3] = evdevbutton(cfg->rs_down); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev->axis_left[1].code, m_dev->axis_left[0].code); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev->axis_left[3].code, m_dev->axis_left[2].code); diff --git a/rpcs3/Input/evdev_joystick_handler.h b/rpcs3/Input/evdev_joystick_handler.h index db167588c3..9312adc5e6 100644 --- a/rpcs3/Input/evdev_joystick_handler.h +++ b/rpcs3/Input/evdev_joystick_handler.h @@ -359,7 +359,7 @@ public: evdev_joystick_handler(); ~evdev_joystick_handler(); - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; bool Init() override; std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device, u8 player_id) override; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index b4fc221f1f..7b7c4aa911 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -127,7 +127,7 @@ void hid_pad_handler::enumerate_devices() if (controller.second && !controller.second->path.empty() && !device_paths.contains(controller.second->path)) { hid_close(controller.second->hidDevice); - pad_config* config = controller.second->config; + cfg_pad* config = controller.second->config; controller.second.reset(new Device()); controller.second->config = config; } diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index 2589c2aa11..0f358dbe40 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -31,13 +31,10 @@ keyboard_pad_handler::keyboard_pad_handler() b_has_config = true; } -void keyboard_pad_handler::init_config(pad_config* cfg, const std::string& name) +void keyboard_pad_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = GetKeyName(Qt::Key_A); cfg->ls_down.def = GetKeyName(Qt::Key_S); @@ -690,27 +687,26 @@ std::string keyboard_pad_handler::native_scan_code_to_string(int native_scan_cod } } -bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device, u8 /*player_id*/) +bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::string& device, u8 player_id) { if (device != pad::keyboard_device_name) return false; - const int index = static_cast(m_bindings.size()); - m_pad_configs[index].load(); - pad_config* p_profile = &m_pad_configs[index]; - if (p_profile == nullptr) + m_pad_configs[player_id].from_string(g_cfg_input.player[player_id]->config.to_string()); + cfg_pad* cfg = &m_pad_configs[player_id]; + if (cfg == nullptr) return false; m_mouse_move_used = false; m_mouse_wheel_used = false; - m_deadzone_x = p_profile->mouse_deadzone_x; - m_deadzone_y = p_profile->mouse_deadzone_y; - m_multi_x = p_profile->mouse_acceleration_x / 100.0; - m_multi_y = p_profile->mouse_acceleration_y / 100.0; - m_l_stick_lerp_factor = p_profile->l_stick_lerp_factor / 100.0f; - m_r_stick_lerp_factor = p_profile->r_stick_lerp_factor / 100.0f; - m_analog_lerp_factor = p_profile->analog_lerp_factor / 100.0f; - m_trigger_lerp_factor = p_profile->trigger_lerp_factor / 100.0f; + m_deadzone_x = cfg->mouse_deadzone_x; + m_deadzone_y = cfg->mouse_deadzone_y; + m_multi_x = cfg->mouse_acceleration_x / 100.0; + m_multi_y = cfg->mouse_acceleration_y / 100.0; + m_l_stick_lerp_factor = cfg->l_stick_lerp_factor / 100.0f; + m_r_stick_lerp_factor = cfg->r_stick_lerp_factor / 100.0f; + m_analog_lerp_factor = cfg->analog_lerp_factor / 100.0f; + m_trigger_lerp_factor = cfg->trigger_lerp_factor / 100.0f; const auto find_key = [this](const cfg::string& name) { @@ -728,9 +724,9 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: u32 pclass_profile = 0x0; - for (const auto product : input::get_products_by_class(p_profile->device_class_type)) + for (const auto& product : input::get_products_by_class(cfg->device_class_type)) { - if (product.vendor_id == p_profile->vendor_id && product.product_id == p_profile->product_id) + if (product.vendor_id == cfg->vendor_id && product.product_id == cfg->product_id) { pclass_profile = product.pclass_profile; } @@ -742,39 +738,39 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE, CELL_PAD_DEV_TYPE_STANDARD, - p_profile->device_class_type, + cfg->device_class_type, pclass_profile, - p_profile->vendor_id, - p_profile->product_id, - p_profile->pressure_intensity + cfg->vendor_id, + cfg->product_id, + cfg->pressure_intensity ); - pad->m_buttons.emplace_back(special_button_offset, find_key(p_profile->pressure_intensity_button), special_button_value::pressure_intensity); + pad->m_buttons.emplace_back(special_button_offset, find_key(cfg->pressure_intensity_button), special_button_value::pressure_intensity); pad->m_pressure_intensity_button_index = pad->m_buttons.size() - 1; - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support //pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved (and currently not in use by rpcs3 at all) - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r2), CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l2), CELL_PAD_CTRL_L2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->r2), CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->l2), CELL_PAD_CTRL_L2); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(p_profile->ls_left), find_key(p_profile->ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(p_profile->ls_up), find_key(p_profile->ls_down)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(p_profile->rs_left), find_key(p_profile->rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(p_profile->rs_up), find_key(p_profile->rs_down)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(cfg->ls_left), find_key(cfg->ls_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(cfg->ls_up), find_key(cfg->ls_down)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(cfg->rs_left), find_key(cfg->rs_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(cfg->rs_up), find_key(cfg->rs_down)); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); diff --git a/rpcs3/Input/keyboard_pad_handler.h b/rpcs3/Input/keyboard_pad_handler.h index 1d492d29df..a88fb50f14 100644 --- a/rpcs3/Input/keyboard_pad_handler.h +++ b/rpcs3/Input/keyboard_pad_handler.h @@ -82,7 +82,7 @@ public: bool eventFilter(QObject* target, QEvent* ev) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; std::vector ListDevices() override; void get_next_button_press(const std::string& /*padId*/, const pad_callback& /*callback*/, const pad_fail_callback& /*fail_callback*/, bool /*get_blacklist*/ = false, const std::vector& /*buttons*/ = {}) override {} bool bindPadToDevice(std::shared_ptr pad, const std::string& device, u8 player_id) override; diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index fa982dff91..8438aa9e4f 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -26,13 +26,10 @@ mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm) m_thumb_threshold = thumb_max / 2; } -void mm_joystick_handler::init_config(pad_config* cfg, const std::string& name) +void mm_joystick_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = axis_list.at(mmjoy_axis::joy_x_neg); cfg->ls_down.def = axis_list.at(mmjoy_axis::joy_y_neg); @@ -129,42 +126,42 @@ u64 mm_joystick_handler::find_key(const std::string& name) const return static_cast(key); } -std::array mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr& device, const pad_config* profile) +std::array mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) { - std::array mapping{ 0 }; + std::array mapping{}; MMJOYDevice* joy_device = static_cast(device.get()); - if (!joy_device) + if (!joy_device || !cfg) return mapping; - joy_device->trigger_left = find_key(profile->l2); - joy_device->trigger_right = find_key(profile->r2); - joy_device->axis_left[0] = find_key(profile->ls_left); - joy_device->axis_left[1] = find_key(profile->ls_right); - joy_device->axis_left[2] = find_key(profile->ls_down); - joy_device->axis_left[3] = find_key(profile->ls_up); - joy_device->axis_right[0] = find_key(profile->rs_left); - joy_device->axis_right[1] = find_key(profile->rs_right); - joy_device->axis_right[2] = find_key(profile->rs_down); - joy_device->axis_right[3] = find_key(profile->rs_up); + joy_device->trigger_left = find_key(cfg->l2); + joy_device->trigger_right = find_key(cfg->r2); + joy_device->axis_left[0] = find_key(cfg->ls_left); + joy_device->axis_left[1] = find_key(cfg->ls_right); + joy_device->axis_left[2] = find_key(cfg->ls_down); + joy_device->axis_left[3] = find_key(cfg->ls_up); + joy_device->axis_right[0] = find_key(cfg->rs_left); + joy_device->axis_right[1] = find_key(cfg->rs_right); + joy_device->axis_right[2] = find_key(cfg->rs_down); + joy_device->axis_right[3] = find_key(cfg->rs_up); - mapping[button::up] = static_cast(find_key(profile->up)); - mapping[button::down] = static_cast(find_key(profile->down)); - mapping[button::left] = static_cast(find_key(profile->left)); - mapping[button::right] = static_cast(find_key(profile->right)); - mapping[button::cross] = static_cast(find_key(profile->cross)); - mapping[button::square] = static_cast(find_key(profile->square)); - mapping[button::circle] = static_cast(find_key(profile->circle)); - mapping[button::triangle] = static_cast(find_key(profile->triangle)); - mapping[button::l1] = static_cast(find_key(profile->l1)); + mapping[button::up] = static_cast(find_key(cfg->up)); + mapping[button::down] = static_cast(find_key(cfg->down)); + mapping[button::left] = static_cast(find_key(cfg->left)); + mapping[button::right] = static_cast(find_key(cfg->right)); + mapping[button::cross] = static_cast(find_key(cfg->cross)); + mapping[button::square] = static_cast(find_key(cfg->square)); + mapping[button::circle] = static_cast(find_key(cfg->circle)); + mapping[button::triangle] = static_cast(find_key(cfg->triangle)); + mapping[button::l1] = static_cast(find_key(cfg->l1)); mapping[button::l2] = static_cast(joy_device->trigger_left); - mapping[button::l3] = static_cast(find_key(profile->l3)); - mapping[button::r1] = static_cast(find_key(profile->r1)); + mapping[button::l3] = static_cast(find_key(cfg->l3)); + mapping[button::r1] = static_cast(find_key(cfg->r1)); mapping[button::r2] = static_cast(joy_device->trigger_right); - mapping[button::r3] = static_cast(find_key(profile->r3)); - mapping[button::start] = static_cast(find_key(profile->start)); - mapping[button::select] = static_cast(find_key(profile->select)); - mapping[button::ps] = static_cast(find_key(profile->ps)); + mapping[button::r3] = static_cast(find_key(cfg->r3)); + mapping[button::start] = static_cast(find_key(cfg->start)); + mapping[button::select] = static_cast(find_key(cfg->select)); + mapping[button::ps] = static_cast(find_key(cfg->ps)); mapping[button::ls_left] = static_cast(joy_device->axis_left[0]); mapping[button::ls_right] = static_cast(joy_device->axis_left[1]); mapping[button::ls_down] = static_cast(joy_device->axis_left[2]); @@ -174,7 +171,7 @@ std::array mm_joystick_handler::get_m mapping[button::rs_down] = static_cast(joy_device->axis_right[2]); mapping[button::rs_up] = static_cast(joy_device->axis_right[3]); - mapping[button::pressure_intensity_button] = static_cast(find_key(profile->pressure_intensity_button)); + mapping[button::pressure_intensity_button] = static_cast(find_key(cfg->pressure_intensity_button)); return mapping; } diff --git a/rpcs3/Input/mm_joystick_handler.h b/rpcs3/Input/mm_joystick_handler.h index 36e8846f76..d56a8ce75f 100644 --- a/rpcs3/Input/mm_joystick_handler.h +++ b/rpcs3/Input/mm_joystick_handler.h @@ -118,7 +118,7 @@ public: std::vector ListDevices() override; void get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool get_blacklist = false, const std::vector& buttons = {}) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; private: std::unordered_map GetButtonValues(const JOYINFOEX& js_info, const JOYCAPS& js_caps); @@ -133,7 +133,7 @@ private: u64 find_key(const std::string& name) const; - std::array get_mapped_key_codes(const std::shared_ptr& device, const pad_config* profile) override; + std::array get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) override; std::shared_ptr get_device(const std::string& device) override; bool get_is_left_trigger(u64 keyCode) override; bool get_is_right_trigger(u64 keyCode) override; diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index 185a0130fd..6a22185f92 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -89,7 +89,8 @@ void pad_thread::Init() handlers.clear(); - g_cfg_input.load(pad::g_title_id); + g_cfg_profile.load(); + g_cfg_input.load(pad::g_title_id, g_cfg_profile.active_profiles.get_value(pad::g_title_id)); std::shared_ptr keyptr; @@ -162,6 +163,8 @@ void pad_thread::Init() m_pads_interface[i] = std::make_shared(CELL_PAD_STATUS_DISCONNECTED, pad_settings[i].device_capability, pad_settings[i].device_type); *m_pads_interface[i] = *m_pads[i]; + + input_log.notice("Pad %d: %s", i, g_cfg_input.player[i]->device.to_string()); } } @@ -287,6 +290,8 @@ void pad_thread::InitLddPad(u32 handle) return; } + input_log.notice("Pad %d: LDD", handle); + static const auto product = input::get_product_info(input::product_type::playstation_3_controller); m_pads[handle]->ldd = true; diff --git a/rpcs3/Input/xinput_pad_handler.cpp b/rpcs3/Input/xinput_pad_handler.cpp index 8c0ae50bd8..74825b2478 100644 --- a/rpcs3/Input/xinput_pad_handler.cpp +++ b/rpcs3/Input/xinput_pad_handler.cpp @@ -83,13 +83,10 @@ xinput_pad_handler::~xinput_pad_handler() } } -void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name) +void xinput_pad_handler::init_config(cfg_pad* cfg) { if (!cfg) return; - // Set this profile's save location - cfg->cfg_name = name; - // Set default button mapping cfg->ls_left.def = button_list.at(XInputKeyCodes::LSXNeg); cfg->ls_down.def = button_list.at(XInputKeyCodes::LSYNeg); diff --git a/rpcs3/Input/xinput_pad_handler.h b/rpcs3/Input/xinput_pad_handler.h index 7f55690198..2ceddfdc35 100644 --- a/rpcs3/Input/xinput_pad_handler.h +++ b/rpcs3/Input/xinput_pad_handler.h @@ -112,7 +112,7 @@ public: std::vector ListDevices() override; void SetPadData(const std::string& padId, u8 player_id, u32 largeMotor, u32 smallMotor, s32 r, s32 g, s32 b, bool battery_led, u32 battery_led_brightness) override; u32 get_battery_level(const std::string& padId) override; - void init_config(pad_config* cfg, const std::string& name) override; + void init_config(cfg_pad* cfg) override; private: typedef DWORD (WINAPI * PFN_XINPUTGETEXTENDED)(DWORD, SCP_EXTN *); diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 937e3f4e8f..39a0bcab9e 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -1453,7 +1453,10 @@ bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, con bool game_list_frame::RemoveCustomPadConfiguration(const std::string& title_id, const game_info& game, bool is_interactive) { - const std::string config_dir = rpcs3::utils::get_custom_input_config_dir(title_id); + if (title_id.empty()) + return true; + + const std::string config_dir = rpcs3::utils::get_input_config_dir(title_id); if (!fs::is_dir(config_dir)) return true; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 12427b39c1..c3ef64bb45 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -13,7 +13,9 @@ #include "gui_settings.h" #include "Emu/System.h" +#include "Emu/system_utils.hpp" #include "Emu/Io/Null/NullPadHandler.h" +#include "Utilities/File.h" #include "Input/pad_thread.h" #include "Input/product_info.h" @@ -34,11 +36,13 @@ LOG_CHANNEL(cfg_log, "CFG"); inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; +cfg_profile g_cfg_profile; + inline bool CreateConfigFile(const QString& dir, const QString& name) { if (!QDir().mkpath(dir)) { - cfg_log.error("Failed to create dir %s", sstr(dir)); + cfg_log.fatal("Failed to create dir %s", sstr(dir)); return false; } @@ -47,7 +51,7 @@ inline bool CreateConfigFile(const QString& dir, const QString& name) if (!new_file.open(QIODevice::WriteOnly)) { - cfg_log.error("Failed to create file %s", sstr(filename)); + cfg_log.fatal("Failed to create file %s", sstr(filename)); return false; } @@ -64,21 +68,52 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti ui->setupUi(this); - // load input config - g_cfg_input.from_default(); - if (game) { m_title_id = game->serial; - g_cfg_input.load(game->serial); setWindowTitle(tr("Gamepad Settings: [%0] %1").arg(qstr(game->serial)).arg(qstr(game->name).simplified())); } else { - g_cfg_input.load(); setWindowTitle(tr("Gamepad Settings")); } + // Load profiles + if (m_title_id.empty()) + { + g_cfg_profile.load(); + + const QString profile_dir = qstr(rpcs3::utils::get_input_config_dir(m_title_id)); + QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml"); + QString active_profile = qstr(g_cfg_profile.active_profiles.get_value(g_cfg_profile.global_key)); + + if (!profiles.contains(active_profile)) + { + const QString default_profile = qstr(g_cfg_profile.default_profile); + + if (!profiles.contains(default_profile) && CreateConfigFile(profile_dir, default_profile)) + { + profiles.prepend(default_profile); + } + + active_profile = default_profile; + } + + for (const QString& profile : profiles) + { + ui->chooseProfile->addItem(profile); + } + + ui->chooseProfile->setCurrentText(active_profile); + } + else + { + g_cfg_profile.from_default(); + + ui->chooseProfile->addItem(qstr(m_title_id)); + ui->gb_profiles->setEnabled(false); + } + // Create tab widget for 7 players for (int i = 1; i < 8; i++) { @@ -98,78 +133,16 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti connect(ui->tabWidget, &QTabWidget::currentChanged, this, &pad_settings_dialog::OnTabChanged); // Combobox: Input type - connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType); + connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeHandler); // Combobox: Devices - connect(ui->chooseDevice, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) - { - if (index < 0) - return; - - const pad_device_info info = ui->chooseDevice->itemData(index).value(); - m_device_name = info.name; - if (!g_cfg_input.player[ui->tabWidget->currentIndex()]->device.from_string(m_device_name)) - { - // Something went wrong - cfg_log.error("Failed to convert device string: %s", m_device_name); - return; - } - }); + connect(ui->chooseDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &pad_settings_dialog::ChangeDevice); // Combobox: Profiles - connect(ui->chooseProfile, &QComboBox::currentTextChanged, this, [this](const QString& prof) - { - if (prof.isEmpty()) - { - return; - } - m_profile = sstr(prof); - if (!g_cfg_input.player[ui->tabWidget->currentIndex()]->profile.from_string(m_profile)) - { - // Something went wrong - cfg_log.error("Failed to convert profile string: %s", m_profile); - return; - } - ChangeProfile(); - }); + connect(ui->chooseProfile, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeProfile); // Pushbutton: Add Profile - connect(ui->b_addProfile, &QAbstractButton::clicked, this, [this]() - { - const int i = ui->tabWidget->currentIndex(); - - QInputDialog* dialog = new QInputDialog(this); - dialog->setWindowTitle(tr("Choose a unique name")); - dialog->setLabelText(tr("Profile Name: ")); - dialog->setFixedSize(500, 100); - - while (dialog->exec() != QDialog::Rejected) - { - const QString profile_name = dialog->textValue(); - - if (profile_name.isEmpty()) - { - QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty")); - continue; - } - if (profile_name.contains(".")) - { - QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'")); - continue; - } - if (ui->chooseProfile->findText(profile_name) != -1) - { - QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); - continue; - } - if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler, m_title_id)), profile_name)) - { - ui->chooseProfile->addItem(profile_name); - ui->chooseProfile->setCurrentText(profile_name); - } - break; - } - }); + connect(ui->b_addProfile, &QAbstractButton::clicked, this, &pad_settings_dialog::AddProfile); ui->buttonBox->button(QDialogButtonBox::Reset)->setText(tr("Filter Noise")); @@ -194,7 +167,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti }); // Refresh Button - connect(ui->b_refresh, &QPushButton::clicked, this, &pad_settings_dialog::RefreshInputTypes); + connect(ui->b_refresh, &QPushButton::clicked, this, &pad_settings_dialog::RefreshHandlers); ui->chooseClass->addItem(tr("Standard (Pad)")); // CELL_PAD_PCLASS_TYPE_STANDARD = 0x00, ui->chooseClass->addItem(tr("Guitar")); // CELL_PAD_PCLASS_TYPE_GUITAR = 0x01, @@ -210,8 +183,9 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti connect(ui->chb_show_emulated_values, &QCheckBox::clicked, [this](bool checked) { m_gui_settings->SetValue(gui::pads_show_emulated, checked); - RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), m_lx, m_ly, m_handler_cfg.lpadsquircling, m_handler_cfg.lstickmultiplier / 100.0); - RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), m_rx, m_ry, m_handler_cfg.rpadsquircling, m_handler_cfg.rstickmultiplier / 100.0); + const auto& cfg = GetPlayerConfig(); + RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), m_lx, m_ly, cfg.lpadsquircling, cfg.lstickmultiplier / 100.0); + RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), m_rx, m_ry, cfg.rpadsquircling, cfg.rstickmultiplier / 100.0); }); // Initialize configurable buttons @@ -234,6 +208,7 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_setti // Set up first tab OnTabChanged(0); + ChangeProfile(ui->chooseProfile->currentText()); // Resize in order to fit into our scroll area ResizeDialog(); @@ -378,8 +353,9 @@ void pad_settings_dialog::InitButtons() { // Allow LED battery indication while the dialog is open ensure(m_handler); - SetPadData(0, 0, m_handler_cfg.led_battery_indicator.get()); - pad_led_settings_dialog dialog(this, m_handler_cfg.colorR, m_handler_cfg.colorG, m_handler_cfg.colorB, m_handler->has_rgb(), m_handler->has_battery(), m_handler_cfg.led_low_battery_blink.get(), m_handler_cfg.led_battery_indicator.get(), m_handler_cfg.led_battery_indicator_brightness); + const auto& cfg = GetPlayerConfig(); + SetPadData(0, 0, cfg.led_battery_indicator.get()); + pad_led_settings_dialog dialog(this, cfg.colorR, cfg.colorG, cfg.colorB, m_handler->has_rgb(), m_handler->has_battery(), cfg.led_low_battery_blink.get(), cfg.led_battery_indicator.get(), cfg.led_battery_indicator_brightness); connect(&dialog, &pad_led_settings_dialog::pass_led_settings, this, &pad_settings_dialog::apply_led_settings); dialog.exec(); SetPadData(0, 0); @@ -497,21 +473,21 @@ void pad_settings_dialog::InitButtons() void pad_settings_dialog::SetPadData(u32 large_motor, u32 small_motor, bool led_battery_indicator) { ensure(m_handler); - const int player_id = ui->tabWidget->currentIndex(); - m_handler->SetPadData(m_device_name, player_id, large_motor, small_motor, m_handler_cfg.colorR, m_handler_cfg.colorG, m_handler_cfg.colorB, led_battery_indicator, m_handler_cfg.led_battery_indicator_brightness); + const auto& cfg = GetPlayerConfig(); + m_handler->SetPadData(m_device_name, GetPlayerIndex(), large_motor, small_motor, cfg.colorR, cfg.colorG, cfg.colorB, led_battery_indicator, cfg.led_battery_indicator_brightness); } // Slot to handle the data from a signal in the led settings dialog void pad_settings_dialog::apply_led_settings(int colorR, int colorG, int colorB, bool led_low_battery_blink, bool led_battery_indicator, int led_battery_indicator_brightness) { ensure(m_handler); - const int player_id = ui->tabWidget->currentIndex(); - m_handler_cfg.colorR.set(colorR); - m_handler_cfg.colorG.set(colorG); - m_handler_cfg.colorB.set(colorB); - m_handler_cfg.led_battery_indicator.set(led_battery_indicator); - m_handler_cfg.led_battery_indicator_brightness.set(led_battery_indicator_brightness); - m_handler_cfg.led_low_battery_blink.set(led_low_battery_blink); + auto& cfg = GetPlayerConfig(); + cfg.colorR.set(colorR); + cfg.colorG.set(colorG); + cfg.colorB.set(colorB); + cfg.led_battery_indicator.set(led_battery_indicator); + cfg.led_battery_indicator_brightness.set(led_battery_indicator_brightness); + cfg.led_low_battery_blink.set(led_low_battery_blink); SetPadData(0, 0, led_battery_indicator); } @@ -541,46 +517,48 @@ void pad_settings_dialog::ReloadButtons() { m_cfg_entries.clear(); - auto updateButton = [this](int id, QPushButton* button, cfg::string* cfg_name) + auto updateButton = [this](int id, QPushButton* button, cfg::string* cfg_text) { - const QString name = qstr(*cfg_name); - m_cfg_entries.insert(std::make_pair(id, pad_button{cfg_name, *cfg_name, name})); - button->setText(name); + const QString text = qstr(*cfg_text); + m_cfg_entries.insert(std::make_pair(id, pad_button{cfg_text, *cfg_text, text})); + button->setText(text); }; - updateButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg.ls_left); - updateButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg.ls_down); - updateButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg.ls_right); - updateButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg.ls_up); + auto& cfg = GetPlayerConfig(); - updateButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg.left); - updateButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg.down); - updateButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg.right); - updateButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg.up); + updateButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &cfg.ls_left); + updateButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &cfg.ls_down); + updateButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &cfg.ls_right); + updateButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &cfg.ls_up); - updateButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg.l1); - updateButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg.l2); - updateButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg.l3); + updateButton(button_ids::id_pad_left, ui->b_left, &cfg.left); + updateButton(button_ids::id_pad_down, ui->b_down, &cfg.down); + updateButton(button_ids::id_pad_right, ui->b_right, &cfg.right); + updateButton(button_ids::id_pad_up, ui->b_up, &cfg.up); - updateButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg.start); - updateButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg.select); - updateButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg.ps); + updateButton(button_ids::id_pad_l1, ui->b_shift_l1, &cfg.l1); + updateButton(button_ids::id_pad_l2, ui->b_shift_l2, &cfg.l2); + updateButton(button_ids::id_pad_l3, ui->b_shift_l3, &cfg.l3); - updateButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg.r1); - updateButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg.r2); - updateButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg.r3); + updateButton(button_ids::id_pad_start, ui->b_start, &cfg.start); + updateButton(button_ids::id_pad_select, ui->b_select, &cfg.select); + updateButton(button_ids::id_pad_ps, ui->b_ps, &cfg.ps); - updateButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg.square); - updateButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg.cross); - updateButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg.circle); - updateButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg.triangle); + updateButton(button_ids::id_pad_r1, ui->b_shift_r1, &cfg.r1); + updateButton(button_ids::id_pad_r2, ui->b_shift_r2, &cfg.r2); + updateButton(button_ids::id_pad_r3, ui->b_shift_r3, &cfg.r3); - updateButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg.rs_left); - updateButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg.rs_down); - updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right); - updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up); + updateButton(button_ids::id_pad_square, ui->b_square, &cfg.square); + updateButton(button_ids::id_pad_cross, ui->b_cross, &cfg.cross); + updateButton(button_ids::id_pad_circle, ui->b_circle, &cfg.circle); + updateButton(button_ids::id_pad_triangle, ui->b_triangle, &cfg.triangle); - updateButton(button_ids::id_pressure_intensity, ui->b_pressure_intensity, &m_handler_cfg.pressure_intensity_button); + updateButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &cfg.rs_left); + updateButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &cfg.rs_down); + updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &cfg.rs_right); + updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &cfg.rs_up); + + updateButton(button_ids::id_pressure_intensity, ui->b_pressure_intensity, &cfg.pressure_intensity_button); m_min_force = m_handler->vibration_min; m_max_force = m_handler->vibration_max; @@ -939,97 +917,99 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) { if (is_reset) { + const auto& cfg = GetPlayerConfig(); + // Update device class - ui->chooseClass->setCurrentIndex(m_handler_cfg.device_class_type); + ui->chooseClass->setCurrentIndex(cfg.device_class_type); // Trigger the change manually in case that the class dropdown didn't fire an event HandleDeviceClassChange(ui->chooseClass->currentIndex()); - const auto products = input::get_products_by_class(m_handler_cfg.device_class_type); + const auto products = input::get_products_by_class(cfg.device_class_type); for (usz i = 0; i < products.size(); i++) { - if (products[i].vendor_id == m_handler_cfg.vendor_id && products[i].product_id == m_handler_cfg.product_id) + if (products[i].vendor_id == cfg.vendor_id && products[i].product_id == cfg.product_id) { ui->chooseProduct->setCurrentIndex(static_cast(i)); break; } } - ui->chb_vibration_large->setChecked(static_cast(m_handler_cfg.enable_vibration_motor_large)); - ui->chb_vibration_small->setChecked(static_cast(m_handler_cfg.enable_vibration_motor_small)); - ui->chb_vibration_switch->setChecked(static_cast(m_handler_cfg.switch_vibration_motors)); + ui->chb_vibration_large->setChecked(static_cast(cfg.enable_vibration_motor_large)); + ui->chb_vibration_small->setChecked(static_cast(cfg.enable_vibration_motor_small)); + ui->chb_vibration_switch->setChecked(static_cast(cfg.switch_vibration_motors)); // Update Trigger Thresholds ui->preview_trigger_left->setRange(0, m_handler->trigger_max); ui->slider_trigger_left->setRange(0, m_handler->trigger_max); - ui->slider_trigger_left->setValue(m_handler_cfg.ltriggerthreshold); + ui->slider_trigger_left->setValue(cfg.ltriggerthreshold); ui->preview_trigger_right->setRange(0, m_handler->trigger_max); ui->slider_trigger_right->setRange(0, m_handler->trigger_max); - ui->slider_trigger_right->setValue(m_handler_cfg.rtriggerthreshold); + ui->slider_trigger_right->setValue(cfg.rtriggerthreshold); // Update Stick Deadzones ui->slider_stick_left->setRange(0, m_handler->thumb_max); - ui->slider_stick_left->setValue(m_handler_cfg.lstickdeadzone); + ui->slider_stick_left->setValue(cfg.lstickdeadzone); ui->slider_stick_right->setRange(0, m_handler->thumb_max); - ui->slider_stick_right->setValue(m_handler_cfg.rstickdeadzone); + ui->slider_stick_right->setValue(cfg.rstickdeadzone); std::vector range; // Update Mouse Deadzones - range = m_handler_cfg.mouse_deadzone_x.to_list(); + range = cfg.mouse_deadzone_x.to_list(); ui->mouse_dz_x->setRange(std::stoi(range.front()), std::stoi(range.back())); - ui->mouse_dz_x->setValue(m_handler_cfg.mouse_deadzone_x); + ui->mouse_dz_x->setValue(cfg.mouse_deadzone_x); - range = m_handler_cfg.mouse_deadzone_y.to_list(); + range = cfg.mouse_deadzone_y.to_list(); ui->mouse_dz_y->setRange(std::stoi(range.front()), std::stoi(range.back())); - ui->mouse_dz_y->setValue(m_handler_cfg.mouse_deadzone_y); + ui->mouse_dz_y->setValue(cfg.mouse_deadzone_y); // Update Mouse Acceleration - range = m_handler_cfg.mouse_acceleration_x.to_list(); + range = cfg.mouse_acceleration_x.to_list(); ui->mouse_accel_x->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->mouse_accel_x->setValue(m_handler_cfg.mouse_acceleration_x / 100.0); + ui->mouse_accel_x->setValue(cfg.mouse_acceleration_x / 100.0); - range = m_handler_cfg.mouse_acceleration_y.to_list(); + range = cfg.mouse_acceleration_y.to_list(); ui->mouse_accel_y->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->mouse_accel_y->setValue(m_handler_cfg.mouse_acceleration_y / 100.0); + ui->mouse_accel_y->setValue(cfg.mouse_acceleration_y / 100.0); // Update Stick Lerp Factors - range = m_handler_cfg.l_stick_lerp_factor.to_list(); + range = cfg.l_stick_lerp_factor.to_list(); ui->left_stick_lerp->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->left_stick_lerp->setValue(m_handler_cfg.l_stick_lerp_factor / 100.0); + ui->left_stick_lerp->setValue(cfg.l_stick_lerp_factor / 100.0); - range = m_handler_cfg.r_stick_lerp_factor.to_list(); + range = cfg.r_stick_lerp_factor.to_list(); ui->right_stick_lerp->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->right_stick_lerp->setValue(m_handler_cfg.r_stick_lerp_factor / 100.0); + ui->right_stick_lerp->setValue(cfg.r_stick_lerp_factor / 100.0); // Update Stick Multipliers - range = m_handler_cfg.lstickmultiplier.to_list(); + range = cfg.lstickmultiplier.to_list(); ui->stick_multi_left->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->stick_multi_left->setValue(m_handler_cfg.lstickmultiplier / 100.0); + ui->stick_multi_left->setValue(cfg.lstickmultiplier / 100.0); - range = m_handler_cfg.rstickmultiplier.to_list(); + range = cfg.rstickmultiplier.to_list(); ui->stick_multi_right->setRange(std::stod(range.front()) / 100.0, std::stod(range.back()) / 100.0); - ui->stick_multi_right->setValue(m_handler_cfg.rstickmultiplier / 100.0); + ui->stick_multi_right->setValue(cfg.rstickmultiplier / 100.0); // Update Squircle Factors - range = m_handler_cfg.lpadsquircling.to_list(); + range = cfg.lpadsquircling.to_list(); ui->squircle_left->setRange(std::stoi(range.front()), std::stoi(range.back())); - ui->squircle_left->setValue(m_handler_cfg.lpadsquircling); + ui->squircle_left->setValue(cfg.lpadsquircling); - range = m_handler_cfg.rpadsquircling.to_list(); + range = cfg.rpadsquircling.to_list(); ui->squircle_right->setRange(std::stoi(range.front()), std::stoi(range.back())); - ui->squircle_right->setValue(m_handler_cfg.rpadsquircling); + ui->squircle_right->setValue(cfg.rpadsquircling); - RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), m_lx, m_ly, m_handler_cfg.lpadsquircling, m_handler_cfg.lstickmultiplier / 100.0); - RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), m_rx, m_ry, m_handler_cfg.rpadsquircling, m_handler_cfg.rstickmultiplier / 100.0); + RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->size().width(), m_lx, m_ly, cfg.lpadsquircling, cfg.lstickmultiplier / 100.0); + RepaintPreviewLabel(ui->preview_stick_right, ui->slider_stick_right->value(), ui->slider_stick_right->size().width(), m_rx, m_ry, cfg.rpadsquircling, cfg.rstickmultiplier / 100.0); // Update pressure sensitivity factors - range = m_handler_cfg.pressure_intensity.to_list(); + range = cfg.pressure_intensity.to_list(); ui->sb_pressure_intensity->setRange(std::stoi(range.front()), std::stoi(range.back())); - ui->sb_pressure_intensity->setValue(m_handler_cfg.pressure_intensity); + ui->sb_pressure_intensity->setValue(cfg.pressure_intensity); // Apply stored/default LED settings to the device m_enable_led = m_handler->has_led(); @@ -1044,7 +1024,7 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) { if (is_reset) { - entry.second.key = *entry.second.cfg_name; + entry.second.key = *entry.second.cfg_text; entry.second.text = qstr(entry.second.key); } @@ -1089,7 +1069,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) return; case button_ids::id_reset_parameters: ReactivateButtons(); - m_handler_cfg.from_default(); + GetPlayerConfig().from_default(); UpdateLabels(true); return; case button_ids::id_blacklist: @@ -1130,15 +1110,14 @@ void pad_settings_dialog::OnPadButtonClicked(int id) void pad_settings_dialog::OnTabChanged(int index) { - // TODO: Do not save yet! But keep all profile changes until the dialog was saved. - // Save old profile - SaveProfile(); + // Apply current config + ApplyCurrentPlayerConfig(index); // Move layout to the new tab ui->tabWidget->widget(index)->setLayout(ui->mainLayout); // Refresh handlers - RefreshInputTypes(); + RefreshHandlers(); } std::shared_ptr pad_settings_dialog::GetHandler(pad_handler type) const @@ -1170,16 +1149,14 @@ std::shared_ptr pad_settings_dialog::GetHandler(pad_handler type return nullptr; } -void pad_settings_dialog::ChangeInputType() +void pad_settings_dialog::ChangeHandler() { bool force_enable = false; // enable configs even with disconnected devices - const int player = ui->tabWidget->currentIndex(); - ensure(player >= 0); + const u32 player = GetPlayerIndex(); const bool is_ldd_pad = GetIsLddPad(player); std::string handler; std::string device; - std::string profile; if (is_ldd_pad) { @@ -1189,23 +1166,30 @@ void pad_settings_dialog::ChangeInputType() { handler = sstr(ui->chooseHandler->currentData().toString()); device = g_cfg_input.player[player]->device.to_string(); - profile = g_cfg_input.player[player]->profile.to_string(); } + + auto& cfg = g_cfg_input.player[player]->config; - // Change this player's current handler - if (!g_cfg_input.player[player]->handler.from_string(handler)) + // Change and get this player's current handler. + if (auto& cfg_handler = g_cfg_input.player[player]->handler; handler != cfg_handler.to_string()) { - // Something went wrong - cfg_log.error("Failed to convert input string: %s", handler); - return; + if (!cfg_handler.from_string(handler)) + { + cfg_log.error("Failed to convert input string: %s", handler); + return; + } + + // Initialize the new pad config's defaults + InitPadConfig(cfg, cfg_handler); + } + else + { + m_handler = GetHandler(g_cfg_input.player[player]->handler); } - ui->chooseDevice->clear(); - ui->chooseProfile->clear(); - - // Get this player's current handler and it's currently available devices - m_handler = GetHandler(g_cfg_input.player[player]->handler); ensure(m_handler); + + // Get the handler's currently available devices. const auto device_list = m_handler->ListDevices(); // Localized tooltips @@ -1255,11 +1239,15 @@ void pad_settings_dialog::ChangeInputType() } ui->l_description->setText(m_description); - // change our contextual widgets + // Change our contextual widgets ui->left_stack->setCurrentIndex((m_handler->m_type == pad_handler::keyboard) ? 1 : 0); ui->right_stack->setCurrentIndex((m_handler->m_type == pad_handler::keyboard) ? 1 : 0); ui->gb_pressure_intensity->setVisible(m_handler->has_pressure_intensity_button()); + // Update device dropdown and block signals while doing so + ui->chooseDevice->blockSignals(true); + ui->chooseDevice->clear(); + // Refill the device combobox with currently available devices switch (m_handler->m_type) { @@ -1298,6 +1286,9 @@ void pad_settings_dialog::ChangeInputType() } } + // Re-enable signals for device dropdown + ui->chooseDevice->blockSignals(false); + // Handle empty device list bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && ui->chooseDevice->count() > 0); @@ -1321,59 +1312,17 @@ void pad_settings_dialog::ChangeInputType() } } - const QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type, m_title_id)); - const QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml"); - - if (profiles.isEmpty()) - { - const QString def_name = "Default Profile"; - if (CreateConfigFile(profile_dir, def_name)) - { - ui->chooseProfile->addItem(def_name); - } - else - { - config_enabled = false; - } - } - else - { - for (const auto& prof : profiles) - { - ui->chooseProfile->addItem(prof); - } - ui->chooseProfile->setCurrentText(qstr(profile)); - } + // Force Refresh + ChangeDevice(ui->chooseDevice->currentIndex()); } else { - ui->chooseProfile->setPlaceholderText(tr("No Profiles")); - if (ui->chooseDevice->count() == 0) { ui->chooseDevice->setPlaceholderText(tr("No Device Detected")); } } - // Enable configuration and profile list if possible - SwitchButtons(config_enabled && m_handler->m_type == pad_handler::keyboard); - - ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(!is_ldd_pad); - ui->b_addProfile->setEnabled(config_enabled); - ui->chooseProfile->setEnabled(config_enabled && ui->chooseProfile->count() > 0); - ui->chooseDevice->setEnabled(config_enabled && ui->chooseDevice->count() > 0); - ui->chooseClass->setEnabled(config_enabled && ui->chooseClass->count() > 0); - ui->chooseProduct->setEnabled(config_enabled && ui->chooseProduct->count() > 0); - ui->chooseHandler->setEnabled(!is_ldd_pad && ui->chooseHandler->count() > 0); -} - -void pad_settings_dialog::ChangeProfile() -{ - if (!m_handler) - { - return; - } - // Handle running timers if (m_timer.isActive()) { @@ -1388,53 +1337,19 @@ void pad_settings_dialog::ChangeProfile() m_timer_pad_refresh.stop(); } - // Change handler - const std::string cfg_name = PadHandlerBase::get_config_dir(m_handler->m_type, m_title_id) + m_profile + ".yml"; - - // Adjust to the different pad handlers - switch (m_handler->m_type) - { - case pad_handler::null: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; - case pad_handler::keyboard: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; - case pad_handler::ds3: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; - case pad_handler::ds4: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; - case pad_handler::dualsense: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; -#ifdef _WIN32 - case pad_handler::xinput: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; - case pad_handler::mm: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; -#endif -#ifdef HAVE_LIBEVDEV - case pad_handler::evdev: - static_cast(m_handler.get())->init_config(&m_handler_cfg, cfg_name); - break; -#endif - } - - // Load new config - if (m_handler->m_type != pad_handler::null && !m_handler_cfg.load()) - { - cfg_log.error("Could not load pad config file '%s'", m_handler_cfg.cfg_name); - m_handler_cfg.from_default(); - } - - // Reload the buttons with the new handler and profile + // Reload the buttons with the new handler ReloadButtons(); - // Reenable input timer + // Enable configuration if possible + SwitchButtons(config_enabled && m_handler->m_type == pad_handler::keyboard); + + ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(!is_ldd_pad); + ui->chooseDevice->setEnabled(config_enabled && ui->chooseDevice->count() > 0); + ui->chooseClass->setEnabled(config_enabled && ui->chooseClass->count() > 0); + ui->chooseProduct->setEnabled(config_enabled && ui->chooseProduct->count() > 0); + ui->chooseHandler->setEnabled(!is_ldd_pad && ui->chooseHandler->count() > 0); + + // Re-enable input timer if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0) { m_timer_input.start(1); @@ -1442,6 +1357,99 @@ void pad_settings_dialog::ChangeProfile() } } +void pad_settings_dialog::InitPadConfig(cfg_pad& cfg, pad_handler type) +{ + m_handler = GetHandler(type); + + switch (type) + { + case pad_handler::null: + static_cast(m_handler.get())->init_config(&cfg); + break; + case pad_handler::keyboard: + static_cast(m_handler.get())->init_config(&cfg); + break; + case pad_handler::ds3: + static_cast(m_handler.get())->init_config(&cfg); + break; + case pad_handler::ds4: + static_cast(m_handler.get())->init_config(&cfg); + break; + case pad_handler::dualsense: + static_cast(m_handler.get())->init_config(&cfg); + break; +#ifdef _WIN32 + case pad_handler::xinput: + static_cast(m_handler.get())->init_config(&cfg); + break; + case pad_handler::mm: + static_cast(m_handler.get())->init_config(&cfg); + break; +#endif +#ifdef HAVE_LIBEVDEV + case pad_handler::evdev: + static_cast(m_handler.get())->init_config(&cfg); + break; +#endif + } +} + +void pad_settings_dialog::ChangeProfile(const QString& profile) +{ + if (profile.isEmpty()) + return; + + m_profile = sstr(profile); + + std::unique_ptr tmp = std::make_unique(); + + if (!tmp->load(m_title_id, m_profile, true)) + { + cfg_log.notice("Loaded empty temporary pad config"); + } + + // Adjust to the different pad handlers + for (usz i = 0; i < tmp->player.size(); i++) + { + auto& cfg = g_cfg_input.player[i]->config; + InitPadConfig(cfg, tmp->player[i]->handler); + } + + if (!g_cfg_input.load(m_title_id, m_profile, true)) + { + cfg_log.notice("Loaded empty pad config"); + } + + const u32 player_id = GetPlayerIndex(); + const std::string handler = fmt::format("%s", g_cfg_input.player[player_id]->handler.get()); + + if (const QString q_handler = qstr(handler); ui->chooseHandler->findText(q_handler) >= 0) + { + ui->chooseHandler->setCurrentText(q_handler); + } + else + { + cfg_log.fatal("Handler '%s' not found in handler dropdown.", handler); + } + + // Force Refresh + ChangeHandler(); +} + +void pad_settings_dialog::ChangeDevice(int index) +{ + if (index < 0) + return; + + const pad_device_info info = ui->chooseDevice->itemData(index).value(); + m_device_name = info.name; + if (!g_cfg_input.player[GetPlayerIndex()]->device.from_string(m_device_name)) + { + // Something went wrong + cfg_log.error("Failed to convert device string: %s", m_device_name); + } +} + void pad_settings_dialog::HandleDeviceClassChange(int index) const { if (index < 0) @@ -1504,15 +1512,50 @@ void pad_settings_dialog::HandleDeviceClassChange(int index) const } } -void pad_settings_dialog::RefreshInputTypes() +void pad_settings_dialog::AddProfile() { - const int index = ui->tabWidget->currentIndex(); + QInputDialog* dialog = new QInputDialog(this); + dialog->setWindowTitle(tr("Choose a unique name")); + dialog->setLabelText(tr("Profile Name: ")); + dialog->setFixedSize(500, 100); - // Set the current input type from config. Disable signal to have ChangeInputType always executed exactly once + while (dialog->exec() != QDialog::Rejected) + { + const QString profile_name = dialog->textValue(); + + if (profile_name.isEmpty()) + { + QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty")); + continue; + } + if (profile_name.contains(".")) + { + QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'")); + continue; + } + if (ui->chooseProfile->findText(profile_name) != -1) + { + QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); + continue; + } + if (CreateConfigFile(qstr(rpcs3::utils::get_input_config_dir(m_title_id)), profile_name)) + { + ui->chooseProfile->addItem(profile_name); + ui->chooseProfile->setCurrentText(profile_name); + } + break; + } +} + +void pad_settings_dialog::RefreshHandlers() +{ + const u32 player_id = GetPlayerIndex(); + + // Set the current input type from config. Disable signal to have ChangeHandler always executed exactly once ui->chooseHandler->blockSignals(true); ui->chooseHandler->clear(); - if (GetIsLddPad(index)) + if (GetIsLddPad(player_id)) { ui->chooseHandler->addItem(tr("Reserved")); } @@ -1525,97 +1568,107 @@ void pad_settings_dialog::RefreshInputTypes() ui->chooseHandler->addItem(GetLocalizedPadHandler(item_data, static_cast(i)), QVariant(item_data)); } - const auto& handler = g_cfg_input.player[index]->handler; + const auto& handler = g_cfg_input.player[player_id]->handler; ui->chooseHandler->setCurrentText(GetLocalizedPadHandler(qstr(handler.to_string()), handler)); } ui->chooseHandler->blockSignals(false); // Force Change - ChangeInputType(); + ChangeHandler(); } -void pad_settings_dialog::SaveProfile() +void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) { - if (!m_handler || !ui->chooseProfile->isEnabled() || ui->chooseProfile->currentIndex() < 0) + if (!m_handler || new_player_id < 0) { return; } for (const auto& entry : m_cfg_entries) { - entry.second.cfg_name->from_string(entry.second.key); + entry.second.cfg_text->from_string(entry.second.key); } - m_handler_cfg.lstickmultiplier.set(ui->stick_multi_left->value() * 100); - m_handler_cfg.rstickmultiplier.set(ui->stick_multi_right->value() * 100); - m_handler_cfg.lpadsquircling.set(ui->squircle_left->value()); - m_handler_cfg.rpadsquircling.set(ui->squircle_right->value()); + auto& cfg = g_cfg_input.player[m_last_player_id]->config; + m_last_player_id = new_player_id; + + cfg.lstickmultiplier.set(ui->stick_multi_left->value() * 100); + cfg.rstickmultiplier.set(ui->stick_multi_right->value() * 100); + cfg.lpadsquircling.set(ui->squircle_left->value()); + cfg.rpadsquircling.set(ui->squircle_right->value()); if (m_handler->has_rumble()) { - m_handler_cfg.enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); - m_handler_cfg.enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); - m_handler_cfg.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); + cfg.enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); + cfg.enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); + cfg.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); } if (m_handler->has_deadzones()) { - m_handler_cfg.ltriggerthreshold.set(ui->slider_trigger_left->value()); - m_handler_cfg.rtriggerthreshold.set(ui->slider_trigger_right->value()); - m_handler_cfg.lstickdeadzone.set(ui->slider_stick_left->value()); - m_handler_cfg.rstickdeadzone.set(ui->slider_stick_right->value()); + cfg.ltriggerthreshold.set(ui->slider_trigger_left->value()); + cfg.rtriggerthreshold.set(ui->slider_trigger_right->value()); + cfg.lstickdeadzone.set(ui->slider_stick_left->value()); + cfg.rstickdeadzone.set(ui->slider_stick_right->value()); } if (m_handler->has_pressure_intensity_button()) { - m_handler_cfg.pressure_intensity.set(ui->sb_pressure_intensity->value()); + cfg.pressure_intensity.set(ui->sb_pressure_intensity->value()); } if (m_handler->m_type == pad_handler::keyboard) { - m_handler_cfg.mouse_acceleration_x.set(ui->mouse_accel_x->value() * 100); - m_handler_cfg.mouse_acceleration_y.set(ui->mouse_accel_y->value() * 100); - m_handler_cfg.mouse_deadzone_x.set(ui->mouse_dz_x->value()); - m_handler_cfg.mouse_deadzone_y.set(ui->mouse_dz_y->value()); - m_handler_cfg.l_stick_lerp_factor.set(ui->left_stick_lerp->value() * 100); - m_handler_cfg.r_stick_lerp_factor.set(ui->right_stick_lerp->value() * 100); + cfg.mouse_acceleration_x.set(ui->mouse_accel_x->value() * 100); + cfg.mouse_acceleration_y.set(ui->mouse_accel_y->value() * 100); + cfg.mouse_deadzone_x.set(ui->mouse_dz_x->value()); + cfg.mouse_deadzone_y.set(ui->mouse_dz_y->value()); + cfg.l_stick_lerp_factor.set(ui->left_stick_lerp->value() * 100); + cfg.r_stick_lerp_factor.set(ui->right_stick_lerp->value() * 100); } - m_handler_cfg.device_class_type.set(ui->chooseClass->currentIndex()); + cfg.device_class_type.set(ui->chooseClass->currentIndex()); const auto info = input::get_product_info(static_cast(ui->chooseProduct->currentData().toInt())); - m_handler_cfg.vendor_id.set(info.vendor_id); - m_handler_cfg.product_id.set(info.product_id); - - m_handler_cfg.save(); + cfg.vendor_id.set(info.vendor_id); + cfg.product_id.set(info.product_id); } void pad_settings_dialog::SaveExit() { - SaveProfile(); + ApplyCurrentPlayerConfig(m_last_player_id); // Check for invalid selection if (!ui->chooseDevice->isEnabled() || ui->chooseDevice->currentIndex() < 0) { - const int i = ui->tabWidget->currentIndex(); - - g_cfg_input.player[i]->handler.from_default(); - g_cfg_input.player[i]->device.from_default(); - g_cfg_input.player[i]->profile.from_default(); + const u32 played_id = GetPlayerIndex(); + g_cfg_input.player[played_id]->handler.from_default(); + g_cfg_input.player[played_id]->device.from_default(); + g_cfg_input.player[played_id]->config.from_default(); } - g_cfg_input.save(m_title_id); + if (m_title_id.empty()) + { + g_cfg_profile.active_profiles.set_value(g_cfg_profile.global_key, m_profile); + g_cfg_profile.save(); + + g_cfg_input.save(m_title_id, m_profile); + } + else + { + g_cfg_input.save(m_title_id); + } QDialog::accept(); } void pad_settings_dialog::CancelExit() { - // Reloads config from file or defaults + // Reloads configs from file or defaults + g_cfg_profile.load(); g_cfg_input.from_default(); - g_cfg_input.load(); QDialog::reject(); } @@ -1640,11 +1693,11 @@ QString pad_settings_dialog::GetLocalizedPadHandler(const QString& original, pad return original; } -bool pad_settings_dialog::GetIsLddPad(int index) const +bool pad_settings_dialog::GetIsLddPad(u32 index) const { // We only check for ldd pads if the current dialog may affect the running application. // To simplify this we include the global pad config indiscriminately as well as the relevant custom pad config. - if (index >= 0 && !Emu.IsStopped() && (m_title_id.empty() || m_title_id == Emu.GetTitleID())) + if (!Emu.IsStopped() && (m_title_id.empty() || m_title_id == Emu.GetTitleID())) { std::lock_guard lock(pad::g_pad_mutex); if (const auto handler = pad::get_current_handler(true)) @@ -1656,6 +1709,18 @@ bool pad_settings_dialog::GetIsLddPad(int index) const return false; } +u32 pad_settings_dialog::GetPlayerIndex() const +{ + const int player_id = ui->tabWidget->currentIndex(); + ensure(player_id >= 0 && static_cast(player_id) < g_cfg_input.player.size()); + return static_cast(player_id); +} + +cfg_pad& pad_settings_dialog::GetPlayerConfig() const +{ + return g_cfg_input.player[GetPlayerIndex()]->config; +} + void pad_settings_dialog::ResizeDialog() { // Widgets diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 4245bdc031..30264e25b4 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -81,7 +81,7 @@ class pad_settings_dialog : public QDialog struct pad_button { - cfg::string* cfg_name = nullptr; + cfg::string* cfg_text = nullptr; std::string key; QString text; }; @@ -98,11 +98,14 @@ public Q_SLOTS: private Q_SLOTS: void OnPadButtonClicked(int id); void OnTabChanged(int index); - void RefreshInputTypes(); - void ChangeInputType(); + void RefreshHandlers(); + void ChangeHandler(); + void ChangeProfile(const QString& profile); + void ChangeDevice(int index); void HandleDeviceClassChange(int index) const; - /** Save the Pad Configuration to the current Pad Handler Config File */ - void SaveProfile(); + void AddProfile(); + /** Update the current player config with the GUI values. */ + void ApplyCurrentPlayerConfig(int new_player_id); private: Ui::pad_settings_dialog *ui; @@ -141,10 +144,10 @@ private: // Pad Handlers std::shared_ptr m_handler; - pad_config m_handler_cfg; std::string m_device_name; std::string m_profile; QTimer m_timer_pad_refresh; + int m_last_player_id = 0; // Remap Timer const int MAX_SECONDS = 5; @@ -176,7 +179,7 @@ private: void InitButtons(); void ReloadButtons(); - void ChangeProfile(); + void InitPadConfig(cfg_pad& cfg, pad_handler type); /** Repaints a stick deadzone preview label */ void RepaintPreviewLabel(QLabel* l, int deadzone, int desired_width, int x, int y, int squircle, double multiplier) const; @@ -186,7 +189,13 @@ private: QString GetLocalizedPadHandler(const QString& original, pad_handler handler); /** Checks if the port at the given index is already reserved by the application as custom controller (ldd pad) */ - bool GetIsLddPad(int index) const; + bool GetIsLddPad(u32 index) const; + + /** Returns the current player index */ + u32 GetPlayerIndex() const; + + /** Returns the current player config */ + cfg_pad& GetPlayerConfig() const; /** Resizes the dialog. We need to do this because the main scroll area can't determine the size on its own. */ void ResizeDialog();