From 704d8764afa0074a4ee996850858e482afbefbeb Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 17 Mar 2026 21:30:18 +0100 Subject: [PATCH] input: refactor combos into a struct for future use Also update some terminology in the code --- rpcs3/Emu/Io/PadHandler.cpp | 61 +++++-------------------- rpcs3/Emu/Io/PadHandler.h | 11 ++--- rpcs3/Emu/Io/pad_config.cpp | 47 +++++++++---------- rpcs3/Emu/Io/pad_config.h | 36 ++++++++++++++- rpcs3/Input/evdev_joystick_handler.cpp | 26 +++++------ rpcs3/Input/keyboard_pad_handler.cpp | 8 ++-- rpcs3/Input/mm_joystick_handler.cpp | 2 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 62 +++++++++++++------------- rpcs3/rpcs3qt/pad_settings_dialog.h | 8 ++-- 9 files changed, 121 insertions(+), 140 deletions(-) diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 1e22da3fc8..ccd81d2805 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -11,30 +11,15 @@ PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type) { } -std::vector> PadHandlerBase::find_key_combos(const std::unordered_map& map, const std::string& cfg_string, const std::string& fallback) +std::vector> PadHandlerBase::find_key_combos(const std::unordered_map& map, const std::string& cfg_string) { std::vector> key_codes; - const std::vector> combos = cfg_pad::get_buttons(cfg_string); - u32 def_code = umax; + const std::vector combos = cfg_pad::get_combos(cfg_string); - for (const std::vector& names : combos) + for (const pad::combo& combo : combos) { - std::set keys; - - for (const std::string& nam : names) - { - for (const auto& [code, name] : map) - { - if (name == nam) - { - keys.insert(code); - } - - if (!fallback.empty() && name == fallback) - def_code = code; - } - } + std::set keys = find_key_codes(map, combo); if (!keys.empty()) { @@ -42,39 +27,18 @@ std::vector> PadHandlerBase::find_key_combos(const std::unordered_ } } - if (!key_codes.empty()) - { - return key_codes; - } - - if (!fallback.empty()) - { - if (!combos.empty()) - input_log.error("FindKeyCode for [name = %s] returned with [def_code = %d] for [fallback = %s]", cfg_string, def_code, fallback); - - if (def_code != umax) - { - return {{ def_code }}; - } - } - - return {}; + return key_codes; } -std::vector> PadHandlerBase::find_key_combos(const std::unordered_map& map, const cfg::string& cfg_string, bool fallback) -{ - return find_key_combos(map, cfg_string.to_string(), fallback ? cfg_string.def : ""); -} - -std::set PadHandlerBase::find_key_codes(const std::unordered_map& map, const std::vector& names) +std::set PadHandlerBase::find_key_codes(const std::unordered_map& map, const pad::combo& combo) { std::set key_codes; - for (const std::string& name : names) + for (const std::string& button_name : combo.buttons()) { - for (const auto& [code, nam] : map) + for (const auto& [code, name] : map) { - if (nam == name) + if (button_name == name) { key_codes.insert(code); break; @@ -82,12 +46,7 @@ std::set PadHandlerBase::find_key_codes(const std::unordered_map m_pad_for_pad_settings; - // Search an unordered map for a string value and return the found combo - static std::vector> find_key_combos(const std::unordered_map& map, const std::string& cfg_string, const std::string& fallback); + // Search an unordered map for a string value and return the found combos + static std::vector> find_key_combos(const std::unordered_map& map, const std::string& cfg_string); - // Search an unordered map for a string value and return the found combo - static std::vector> find_key_combos(const std::unordered_map& map, const cfg::string& cfg_string, bool fallback = true); - - // Search an unordered map for string values and return the found key codes - static std::set find_key_codes(const std::unordered_map& map, const std::vector& names); + // Search an unordered map for a combo and return the found key codes + static std::set find_key_codes(const std::unordered_map& map, const pad::combo& combo); // Get normalized trigger value based on the range defined by a threshold u16 NormalizeTriggerInput(u16 value, u32 threshold) const; diff --git a/rpcs3/Emu/Io/pad_config.cpp b/rpcs3/Emu/Io/pad_config.cpp index ce64513659..5b89ca709d 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -5,15 +5,15 @@ extern std::string g_input_config_override; -std::vector> cfg_pad::get_buttons(std::string_view str) +std::vector cfg_pad::get_combos(std::string_view button_string) { - if (str.empty()) + if (button_string.empty()) return {}; // Handle special case: string contains separator itself as configured value (it's why I don't use fmt::split here) const auto split = [](std::string_view str, char sep) { - std::vector vec; + std::set buttons; bool was_sep = true; usz btn_start = 0ULL; usz i = 0ULL; @@ -27,7 +27,7 @@ std::vector> cfg_pad::get_buttons(std::string_view str) if (!was_sep) { was_sep = true; - vec.push_back(std::string(str.substr(btn_start, i - btn_start))); + buttons.insert(std::string(str.substr(btn_start, i - btn_start))); continue; } } @@ -40,54 +40,47 @@ std::vector> cfg_pad::get_buttons(std::string_view str) if (i == (str.size() - 1)) { - vec.push_back(std::string(str.substr(btn_start, i - btn_start + 1))); + buttons.insert(std::string(str.substr(btn_start, i - btn_start + 1))); } } - // Remove duplicates - std::sort(vec.begin(), vec.end()); - vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); - - return vec; + return buttons; }; - std::vector> res; + std::vector combos; // Get all combos (seperated by ',') - const std::vector vec = split(str, ','); + const std::set combo_strings = split(button_string, ','); - for (const std::string& combo : vec) + for (const std::string& combo_string : combo_strings) { // Get all keys for this combo (seperated by '&') - std::vector keys = split(combo, '&'); - if (!keys.empty()) + std::set combo = split(combo_string, '&'); + if (!combo.empty()) { - res.push_back(std::move(keys)); + combos.push_back(pad::combo{std::move(combo)}); } } - return res; + return combos; } -std::string cfg_pad::get_buttons(std::vector> vec) +std::string cfg_pad::get_button_string(std::vector& combos) { - std::vector combos; + std::vector combo_strings; // Remove duplicates - std::sort(vec.begin(), vec.end()); - vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); + std::sort(combos.begin(), combos.end()); + combos.erase(std::unique(combos.begin(), combos.end()), combos.end()); - for (std::vector& combo : vec) + for (const pad::combo& combo : combos) { - std::sort(combo.begin(), combo.end()); - combo.erase(std::unique(combo.begin(), combo.end()), combo.end()); - // Merge all keys for this combo (seperated by '&') - combos.push_back(fmt::merge(combo, "&")); + combo_strings.push_back(fmt::merge(combo.buttons(), "&")); } // Merge combos (seperated by ',') - return fmt::merge(combos, ","); + return fmt::merge(combo_strings, ","); } u8 cfg_pad::get_motor_speed(VibrateMotor& motor, f32 multiplier) const diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 07de4a7299..24fe3e50b4 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -5,10 +5,42 @@ #include "Utilities/Config.h" #include +#include namespace pad { constexpr static std::string_view keyboard_device_name = "Keyboard"; + + struct combo + { + public: + combo() = default; + combo(std::set buttons) : m_buttons(std::move(buttons)) {} + + const std::set& buttons() const + { + return m_buttons; + } + + void add_button(const std::string& button) + { + if (button.empty()) return; + m_buttons.insert(button); + } + + bool operator==(const combo& other) const + { + return m_buttons == other.m_buttons; + } + + bool operator<(const combo& other) const + { + return m_buttons < other.m_buttons; + } + + private: + std::set m_buttons; + }; } struct cfg_sensor final : cfg::node @@ -25,8 +57,8 @@ struct cfg_pad final : cfg::node cfg_pad() {}; cfg_pad(node* owner, const std::string& name) : cfg::node(owner, name) {} - static std::vector> get_buttons(std::string_view str); - static std::string get_buttons(std::vector> vec); + static std::vector get_combos(std::string_view button_string); + static std::string get_button_string(std::vector& combos); u8 get_motor_speed(VibrateMotor& motor, f32 multiplier) const; u8 get_large_motor_speed(std::array& motors) const; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 5b5e2731ae..104d8d8c41 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -373,7 +373,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s const auto find_value = [&, this](const std::string& str) { - const std::vector> combos = cfg_pad::get_buttons(str); + const std::vector combos = cfg_pad::get_combos(str); u16 value{}; @@ -385,19 +385,19 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s } }; - for (const std::vector& names : combos) + for (const pad::combo& combo : combos) { - for (const u32 code : find_key_codes(rev_axis_list, names)) + for (const u32 code : find_key_codes(rev_axis_list, combo)) { set_value(code, true); } - for (const u32 code : find_key_codes(axis_list, names)) + for (const u32 code : find_key_codes(axis_list, combo)) { set_value(code, false); } - for (const u32 code : find_key_codes(button_list, names)) + for (const u32 code : find_key_codes(button_list, combo)) { set_value(code, false); } @@ -1379,37 +1379,37 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad) const auto find_buttons = [&](const cfg::string& name) -> std::vector> { - const std::vector> str_combos = cfg_pad::get_buttons(name.to_string()); + const std::vector combos = cfg_pad::get_combos(name.to_string()); // In evdev we store indices to an EvdevButton vector in our pad objects instead of the usual key codes. - std::vector> combos; + std::vector> index_combos; - for (const std::vector& names : str_combos) + for (const pad::combo& combo : combos) { std::set indices; - for (const u32 code : find_key_codes(axis_list, names)) + for (const u32 code : find_key_codes(axis_list, combo)) { indices.insert(register_evdevbutton(code, true, false)); } - for (const u32 code : find_key_codes(rev_axis_list, names)) + for (const u32 code : find_key_codes(rev_axis_list, combo)) { indices.insert(register_evdevbutton(code, true, true)); } - for (const u32 code : find_key_codes(button_list, names)) + for (const u32 code : find_key_codes(button_list, combo)) { indices.insert(register_evdevbutton(code, false, false)); } if (!indices.empty()) { - combos.push_back(std::move(indices)); + index_combos.push_back(std::move(indices)); } } - return combos; + return index_combos; }; const auto find_motion_button = [&](const cfg_sensor& sensor) -> evdev_sensor diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index e7435b09ba..662b03c0a3 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -895,13 +895,13 @@ std::vector> keyboard_pad_handler::GetKeyCombos(const cfg::string& { std::vector> res; - for (const std::vector& combo : cfg_pad::get_buttons(cfg_string.to_string())) + for (const pad::combo& combo : cfg_pad::get_combos(cfg_string.to_string())) { std::set key_codes; - for (const std::string& key_name : combo) + for (const std::string& button : combo.buttons()) { - if (u32 code = GetKeyCode(QString::fromStdString(key_name)); code != Qt::NoButton) + if (u32 code = GetKeyCode(QString::fromStdString(button)); code != Qt::NoButton) { key_codes.insert(code); } @@ -1051,7 +1051,7 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad) const auto find_combos = [this](const cfg::string& name) { - std::vector> combos = find_key_combos(mouse_list, name, false); + std::vector> combos = find_key_combos(mouse_list, name); for (const std::set& combo : GetKeyCombos(name)) combos.push_back(combo); if (!combos.empty()) diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index 12ca000d1d..0769d9db4d 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -232,7 +232,7 @@ pad_preview_values mm_joystick_handler::get_preview_values(const std::unordered_ u16 value{}; // The DS3 Button is considered pressed if any configured button combination is pressed - for (const std::set& codes : find_key_combos(button_list, str, std::string())) + for (const std::set& codes : find_key_combos(button_list, str)) { bool combo_pressed = !codes.empty(); u16 combo_val = 0; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 5305b8606a..049579a351 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -51,30 +51,30 @@ inline bool CreateConfigFile(const QString& dir, const QString& name) return true; } -void pad_settings_dialog::pad_button::insert_key(const std::string& key, binding_mode mode) +void pad_settings_dialog::pad_button::insert_button(const std::string& button, binding_mode mode) { - std::vector> combos; + std::vector combos; if (mode != binding_mode::single) { - combos = cfg_pad::get_buttons(m_keys); + combos = cfg_pad::get_combos(m_button_string); } if (combos.empty() || mode != binding_mode::combo) { - combos.push_back({key}); + combos.push_back(pad::combo({button})); } else if (mode == binding_mode::combo) { - combos.back().push_back(key); + combos.back().add_button(button); } - update(cfg_pad::get_buttons(combos)); + update(cfg_pad::get_button_string(combos)); } -void pad_settings_dialog::pad_button::update(const std::string& keys) +void pad_settings_dialog::pad_button::update(const std::string& button_string) { - m_keys = keys; - QString new_text = QString::fromStdString(keys); + m_button_string = button_string; + QString new_text = QString::fromStdString(button_string); m_text = new_text.replace(",", ", ").replace("&", " + "); } @@ -622,7 +622,7 @@ void pad_settings_dialog::InitButtons() { if (value == 0) continue; - m_cfg_entries[m_button_id].insert_key(key, mode); + m_cfg_entries[m_button_id].insert_button(key, mode); // Switch to combo mode for all further keys mode = binding_mode::combo; @@ -632,7 +632,7 @@ void pad_settings_dialog::InitButtons() { if (value == 0) continue; - m_cfg_entries[m_button_id].insert_key(key, mode); + m_cfg_entries[m_button_id].insert_button(key, mode); // Switch to combo mode for all further keys mode = binding_mode::combo; @@ -674,16 +674,16 @@ void pad_settings_dialog::InitButtons() const std::vector buttons = { - m_cfg_entries[button_ids::id_pad_l2].keys(), - m_cfg_entries[button_ids::id_pad_r2].keys(), - m_cfg_entries[button_ids::id_pad_lstick_left].keys(), - m_cfg_entries[button_ids::id_pad_lstick_right].keys(), - m_cfg_entries[button_ids::id_pad_lstick_down].keys(), - m_cfg_entries[button_ids::id_pad_lstick_up].keys(), - m_cfg_entries[button_ids::id_pad_rstick_left].keys(), - m_cfg_entries[button_ids::id_pad_rstick_right].keys(), - m_cfg_entries[button_ids::id_pad_rstick_down].keys(), - m_cfg_entries[button_ids::id_pad_rstick_up].keys() + m_cfg_entries[button_ids::id_pad_l2].button_string(), + m_cfg_entries[button_ids::id_pad_r2].button_string(), + m_cfg_entries[button_ids::id_pad_lstick_left].button_string(), + m_cfg_entries[button_ids::id_pad_lstick_right].button_string(), + m_cfg_entries[button_ids::id_pad_lstick_down].button_string(), + m_cfg_entries[button_ids::id_pad_lstick_up].button_string(), + m_cfg_entries[button_ids::id_pad_rstick_left].button_string(), + m_cfg_entries[button_ids::id_pad_rstick_right].button_string(), + m_cfg_entries[button_ids::id_pad_rstick_down].button_string(), + m_cfg_entries[button_ids::id_pad_rstick_up].button_string() }; // Check if this is the first call during a remap @@ -1023,7 +1023,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent* keyEvent) } else { - m_cfg_entries[m_button_id].insert_key(keyboard_pad_handler::GetKeyName(keyEvent, false), m_binding_mode); + m_cfg_entries[m_button_id].insert_button(keyboard_pad_handler::GetKeyName(keyEvent, false), m_binding_mode); } ReactivateButtons(); @@ -1050,7 +1050,7 @@ void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event) } else { - m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(event), m_binding_mode); + m_cfg_entries[m_button_id].insert_button((static_cast(m_handler.get()))->GetMouseName(event), m_binding_mode); } ReactivateButtons(); @@ -1112,7 +1112,7 @@ void pad_settings_dialog::wheelEvent(QWheelEvent* event) } } - m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(key), m_binding_mode); + m_cfg_entries[m_button_id].insert_button((static_cast(m_handler.get()))->GetMouseName(key), m_binding_mode); ReactivateButtons(); } @@ -1163,7 +1163,7 @@ void pad_settings_dialog::mouseMoveEvent(QMouseEvent* event) if (key != 0) { - m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(key), m_binding_mode); + m_cfg_entries[m_button_id].insert_button((static_cast(m_handler.get()))->GetMouseName(key), m_binding_mode); ReactivateButtons(); } } @@ -2110,7 +2110,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) // Check for duplicate button choices if (m_handler->m_type != pad_handler::null) { - std::set unique_keys; + std::set unique_button_strings; for (const auto& [id, button] : m_cfg_entries) { // Let's ignore special keys, unless we're using a keyboard @@ -2120,13 +2120,13 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) continue; } - for (const std::vector& combo : cfg_pad::get_buttons(button.keys())) + for (const pad::combo& combo : cfg_pad::get_combos(button.button_string())) { - for (const std::string& key : combo) + for (const std::string& button_string : combo.buttons()) { - if (const auto& [it, ok] = unique_keys.insert(key); !ok) + if (const auto& [it, ok] = unique_button_strings.insert(button_string); !ok) { - m_duplicate_buttons[m_last_player_id] = key; + m_duplicate_buttons[m_last_player_id] = button_string; break; } } @@ -2137,7 +2137,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) // Apply buttons for (const auto& entry : m_cfg_entries) { - entry.second.cfg_text()->from_string(entry.second.keys()); + entry.second.cfg_text()->from_string(entry.second.button_string()); } // Apply rest of config diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 5fded0edcd..4a6c253689 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -93,16 +93,16 @@ class pad_settings_dialog : public QDialog update(*cfg_text); } - void insert_key(const std::string& key, binding_mode mode); - void update(const std::string& keys); + void insert_button(const std::string& button, binding_mode mode); + void update(const std::string& button_string); cfg::string* cfg_text() const { return m_cfg_text; } - const std::string& keys() const { return m_keys; } + const std::string& button_string() const { return m_button_string; } const QString& text() const { return m_text; } private: cfg::string* m_cfg_text = nullptr; - std::string m_keys; + std::string m_button_string; QString m_text; };