diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 81d30c1a2f..49abbef55e 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -7,103 +7,21 @@ cfg_input g_cfg_input; -LOG_CHANNEL(input_log, "Input"); - PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type) { } -// Search an unordered map for a string value and return found keycode -int PadHandlerBase::FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback) +std::set PadHandlerBase::narrow_set(const std::set& src) { - const std::string def = name.def; - const std::string nam = name.to_string(); - int def_code = -1; + if (src.empty()) + return {}; - for (auto it = map.begin(); it != map.end(); ++it) + std::set dst; + for (const u64& s : src) { - if (it->second == nam) - return it->first; - - if (fallback && it->second == def) - def_code = it->first; + dst.insert(::narrow(s)); } - - if (fallback) - { - if (!nam.empty()) - input_log.error("int FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def); - - if (def_code < 0) - def_code = 0; - } - - return def_code; -} - -long PadHandlerBase::FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback) -{ - const std::string def = name.def; - const std::string nam = name.to_string(); - long def_code = -1; - - for (auto it = map.begin(); it != map.end(); ++it) - { - if (it->second == nam) - return static_cast(it->first); - - if (fallback && it->second == def) - def_code = static_cast(it->first); - } - - if (fallback) - { - if (!nam.empty()) - input_log.error("long FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def); - - if (def_code < 0) - def_code = 0; - } - - return def_code; -} - -// Search an unordered map for a string value and return found keycode -int PadHandlerBase::FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback) -{ - for (auto it = map.begin(); it != map.end(); ++it) - { - if (it->second == name) - return it->first; - } - - if (fallback) - { - if (!name.empty()) - input_log.error("long FindKeyCodeByString for [name = %s] returned with 0", name); - return 0; - } - - return -1; -} - -// Search an unordered map for a string value and return found keycode -long PadHandlerBase::FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback) -{ - for (auto it = map.begin(); it != map.end(); ++it) - { - if (it->second == name) - return static_cast(it->first); - } - - if (fallback) - { - if (!name.empty()) - input_log.error("long FindKeyCodeByString for [name = %s] returned with 0", name); - return 0; - } - - return -1; + return dst; } // Get new multiplied value based on the multiplier @@ -351,7 +269,7 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri auto device = get_device(pad_id); - const auto status = update_connection(device); + const connection status = update_connection(device); if (status == connection::disconnected) { if (fail_callback) @@ -432,7 +350,7 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_ // Reset sensors auto device = get_device(pad_id); - const auto status = update_connection(device); + const connection status = update_connection(device); if (status == connection::disconnected) { if (fail_callback) @@ -536,11 +454,11 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, u8 player_id) return false; } - std::array mapping = get_mapped_key_codes(pad_device, config); + std::array, button::button_count> mapping = get_mapped_key_codes(pad_device, config); u32 pclass_profile = 0x0; - for (const auto& product : input::get_products_by_class(config->device_class_type)) + for (const input::product_info& product : input::get_products_by_class(config->device_class_type)) { if (product.vendor_id == config->vendor_id && product.product_id == config->product_id) { @@ -599,50 +517,50 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad, u8 player_id) return true; } -std::array PadHandlerBase::get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) +std::array, PadHandlerBase::button::button_count> PadHandlerBase::get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) { - std::array mapping{}; + std::array, button::button_count> mapping{}; if (!device || !cfg) return mapping; - device->trigger_code_left = FindKeyCode(button_list, cfg->l2); - device->trigger_code_right = FindKeyCode(button_list, cfg->r2); - device->axis_code_left[0] = FindKeyCode(button_list, cfg->ls_left); - device->axis_code_left[1] = FindKeyCode(button_list, cfg->ls_right); - device->axis_code_left[2] = FindKeyCode(button_list, cfg->ls_down); - device->axis_code_left[3] = FindKeyCode(button_list, cfg->ls_up); - device->axis_code_right[0] = FindKeyCode(button_list, cfg->rs_left); - device->axis_code_right[1] = FindKeyCode(button_list, cfg->rs_right); - device->axis_code_right[2] = FindKeyCode(button_list, cfg->rs_down); - device->axis_code_right[3] = FindKeyCode(button_list, cfg->rs_up); + device->trigger_code_left = FindKeyCodes(button_list, cfg->l2); + device->trigger_code_right = FindKeyCodes(button_list, cfg->r2); + device->axis_code_left[0] = FindKeyCodes(button_list, cfg->ls_left); + device->axis_code_left[1] = FindKeyCodes(button_list, cfg->ls_right); + device->axis_code_left[2] = FindKeyCodes(button_list, cfg->ls_down); + device->axis_code_left[3] = FindKeyCodes(button_list, cfg->ls_up); + device->axis_code_right[0] = FindKeyCodes(button_list, cfg->rs_left); + device->axis_code_right[1] = FindKeyCodes(button_list, cfg->rs_right); + device->axis_code_right[2] = FindKeyCodes(button_list, cfg->rs_down); + device->axis_code_right[3] = FindKeyCodes(button_list, cfg->rs_up); - 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] = ::narrow(device->trigger_code_left); - mapping[button::l3] = FindKeyCode(button_list, cfg->l3); - mapping[button::r1] = FindKeyCode(button_list, cfg->r1); - mapping[button::r2] = ::narrow(device->trigger_code_right); - mapping[button::r3] = FindKeyCode(button_list, cfg->r3); - mapping[button::ls_left] = ::narrow(device->axis_code_left[0]); - mapping[button::ls_right] = ::narrow(device->axis_code_left[1]); - mapping[button::ls_down] = ::narrow(device->axis_code_left[2]); - mapping[button::ls_up] = ::narrow(device->axis_code_left[3]); - mapping[button::rs_left] = ::narrow(device->axis_code_right[0]); - mapping[button::rs_right] = ::narrow(device->axis_code_right[1]); - mapping[button::rs_down] = ::narrow(device->axis_code_right[2]); - mapping[button::rs_up] = ::narrow(device->axis_code_right[3]); - mapping[button::ps] = FindKeyCode(button_list, cfg->ps); + mapping[button::up] = FindKeyCodes(button_list, cfg->up); + mapping[button::down] = FindKeyCodes(button_list, cfg->down); + mapping[button::left] = FindKeyCodes(button_list, cfg->left); + mapping[button::right] = FindKeyCodes(button_list, cfg->right); + mapping[button::cross] = FindKeyCodes(button_list, cfg->cross); + mapping[button::square] = FindKeyCodes(button_list, cfg->square); + mapping[button::circle] = FindKeyCodes(button_list, cfg->circle); + mapping[button::triangle] = FindKeyCodes(button_list, cfg->triangle); + mapping[button::start] = FindKeyCodes(button_list, cfg->start); + mapping[button::select] = FindKeyCodes(button_list, cfg->select); + mapping[button::l1] = FindKeyCodes(button_list, cfg->l1); + mapping[button::l2] = narrow_set(device->trigger_code_left); + mapping[button::l3] = FindKeyCodes(button_list, cfg->l3); + mapping[button::r1] = FindKeyCodes(button_list, cfg->r1); + mapping[button::r2] = narrow_set(device->trigger_code_right); + mapping[button::r3] = FindKeyCodes(button_list, cfg->r3); + mapping[button::ls_left] = narrow_set(device->axis_code_left[0]); + mapping[button::ls_right] = narrow_set(device->axis_code_left[1]); + mapping[button::ls_down] = narrow_set(device->axis_code_left[2]); + mapping[button::ls_up] = narrow_set(device->axis_code_left[3]); + mapping[button::rs_left] = narrow_set(device->axis_code_right[0]); + mapping[button::rs_right] = narrow_set(device->axis_code_right[1]); + mapping[button::rs_down] = narrow_set(device->axis_code_right[2]); + mapping[button::rs_up] = narrow_set(device->axis_code_right[3]); + mapping[button::ps] = FindKeyCodes(button_list, cfg->ps); - mapping[button::pressure_intensity_button] = FindKeyCode(button_list, cfg->pressure_intensity_button); + mapping[button::pressure_intensity_button] = FindKeyCodes(button_list, cfg->pressure_intensity_button); return mapping; } @@ -655,7 +573,7 @@ void PadHandlerBase::get_mapping(const pad_ensemble& binding) if (!device || !pad) return; - const auto cfg = device->config; + const cfg_pad* cfg = device->config; auto button_values = get_button_values(device); @@ -664,40 +582,70 @@ void PadHandlerBase::get_mapping(const pad_ensemble& binding) const bool adjust_pressure = pad->get_pressure_intensity_enabled(cfg->pressure_intensity_toggle_mode.get()); // Translate any corresponding keycodes to our normal DS3 buttons and triggers - for (auto& btn : pad->m_buttons) + for (Button& btn : pad->m_buttons) { - // Using a temporary buffer because the values can change during translation - Button tmp = btn; - tmp.m_value = button_values[btn.m_keyCode]; + bool pressed{}; + u16 value{}; - TranslateButtonPress(device, tmp.m_keyCode, tmp.m_pressed, tmp.m_value); - - // Modify pressure if necessary if the button was pressed - if (adjust_pressure && tmp.m_pressed) + for (u32 code : btn.m_key_codes) { - tmp.m_value = pad->m_pressure_intensity; + bool press{}; + u16 val = button_values[code]; + + TranslateButtonPress(device, code, press, val); + + if (press) + { + // Modify pressure if necessary if the button was pressed + if (adjust_pressure) + { + val = pad->m_pressure_intensity; + } + + value = std::max(value, val); + pressed = true; + } } - btn = tmp; + btn.m_value = value; + btn.m_pressed = pressed; } // used to get the absolute value of an axis - s32 stick_val[4]{ 0 }; + s32 stick_val[4]{}; // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) for (int i = 0; i < static_cast(pad->m_sticks.size()); i++) { - bool pressed; + bool pressed{}; + u16 val_min{}; + u16 val_max{}; - // m_keyCodeMin is the mapped key for left or down - const u32 key_min = pad->m_sticks[i].m_keyCodeMin; - u16 val_min = button_values[key_min]; - TranslateButtonPress(device, key_min, pressed, val_min, true); + // m_key_codes_min are the mapped keys for left or down + for (u32 key_min : pad->m_sticks[i].m_key_codes_min) + { + u16 val = button_values[key_min]; - // m_keyCodeMax is the mapped key for right or up - const u32 key_max = pad->m_sticks[i].m_keyCodeMax; - u16 val_max = button_values[key_max]; - TranslateButtonPress(device, key_max, pressed, val_max, true); + TranslateButtonPress(device, key_min, pressed, val, true); + + if (pressed) + { + val_min = std::max(val_min, val); + } + } + + // m_key_codes_max are the mapped keys for right or up + for (u32 key_max : pad->m_sticks[i].m_key_codes_max) + { + u16 val = button_values[key_max]; + + TranslateButtonPress(device, key_max, pressed, val, true); + + if (pressed) + { + val_max = std::max(val_max, val); + } + } // cancel out opposing values and get the resulting difference stick_val[i] = val_max - val_min; @@ -741,7 +689,7 @@ void PadHandlerBase::process() if (!device || !pad) continue; - const auto status = update_connection(device); + const connection status = update_connection(device); switch (status) { diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 4bc7caf2e0..2cf9271d35 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -8,10 +8,13 @@ #include #include #include +#include #include #include #include +LOG_CHANNEL(input_log, "Input"); + class PadDevice { public: @@ -20,10 +23,10 @@ public: u8 player_id{0}; u8 large_motor{0}; u8 small_motor{0}; - u64 trigger_code_left = 0; - u64 trigger_code_right = 0; - std::array axis_code_left{}; - std::array axis_code_right{}; + std::set trigger_code_left{}; + std::set trigger_code_right{}; + std::array, 4> axis_code_left{}; + std::array, 4> axis_code_right{}; }; struct pad_ensemble @@ -123,17 +126,76 @@ protected: std::unordered_map button_list; std::vector blacklist; - // Search an unordered map for a string value and return found keycode - static int FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback = true); + static std::set narrow_set(const std::set& src); // Search an unordered map for a string value and return found keycode - static long FindKeyCode(const std::unordered_map& map, const cfg::string& name, bool fallback = true); + template + static std::set FindKeyCodes(const std::unordered_map& map, const cfg::string& cfg_string, bool fallback = true) + { + std::set key_codes; + + const std::string& def = cfg_string.def; + const std::vector names = cfg_pad::get_buttons(cfg_string); + T def_code = umax; + + for (const std::string& nam : names) + { + for (const auto& [code, name] : map) + { + if (name == nam) + { + key_codes.insert(static_cast(code)); + } + + if (fallback && name == def) + def_code = static_cast(code); + } + } + + if (!key_codes.empty()) + { + return key_codes; + } + + if (fallback) + { + if (!names.empty()) + input_log.error("FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", cfg_string.to_string(), def_code, def); + + if (def_code != umax) + { + return { def_code }; + } + } + + return {}; + } // Search an unordered map for a string value and return found keycode - static int FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback = true); + template + static std::set FindKeyCodes(const std::unordered_map& map, const std::vector& names) + { + std::set key_codes; - // Search an unordered map for a string value and return found keycode - static long FindKeyCodeByString(const std::unordered_map& map, const std::string& name, bool fallback = true); + for (const std::string& name : names) + { + for (const auto& [code, nam] : map) + { + if (nam == name) + { + key_codes.insert(static_cast(code)); + break; + } + } + } + + if (!key_codes.empty()) + { + return key_codes; + } + + return {}; + } // Get new multiplied value based on the multiplier static s32 MultipliedInput(s32 raw_value, s32 multiplier); @@ -225,7 +287,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 cfg_pad* cfg); + virtual std::array, PadHandlerBase::button::button_count> get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg); virtual void get_mapping(const pad_ensemble& binding); 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 db78ef2287..3e42ed684b 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -6,6 +6,26 @@ LOG_CHANNEL(input_log, "Input"); extern std::string g_pad_profile_override; +std::vector cfg_pad::get_buttons(const std::string& str) +{ + std::vector vec = fmt::split(str, {","});; + + // Remove duplicates + std::sort(vec.begin(), vec.end()); + vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); + + return vec; +} + +std::string cfg_pad::get_buttons(std::vector vec) +{ + // Remove duplicates + std::sort(vec.begin(), vec.end()); + vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); + + return fmt::merge(vec, ","); +} + bool cfg_input::load(const std::string& title_id, const std::string& profile, bool strict) { input_log.notice("Loading pad config (title_id='%s', profile='%s', strict=%d)", title_id, profile, strict); diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 7e4f4baaaa..bf9bcf7e91 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -25,6 +25,9 @@ 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(const std::string& str); + static std::string get_buttons(std::vector vec); + cfg::string ls_left{ this, "Left Stick Left", "" }; cfg::string ls_down{ this, "Left Stick Down", "" }; cfg::string ls_right{ this, "Left Stick Right", "" }; diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 7c59caf531..59230b1787 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -4,6 +4,7 @@ #include "util/endian.hpp" #include "Emu/Io/pad_config_types.h" +#include #include enum class pad_button : u8 @@ -240,18 +241,19 @@ enum special_button_value struct Button { u32 m_offset = 0; - u32 m_keyCode = 0; + std::set m_key_codes{}; u32 m_outKeyCode = 0; u16 m_value = 0; bool m_pressed = false; - u16 m_actual_value = 0; // only used in keyboard_pad_handler - bool m_analog = false; // only used in keyboard_pad_handler - bool m_trigger = false; // only used in keyboard_pad_handler + u16 m_actual_value = 0; // only used in keyboard_pad_handler + bool m_analog = false; // only used in keyboard_pad_handler + bool m_trigger = false; // only used in keyboard_pad_handler + std::set m_pressed_keys{}; // only used in keyboard_pad_handler - Button(u32 offset, u32 keyCode, u32 outKeyCode) + Button(u32 offset, std::set key_codes, u32 outKeyCode) : m_offset(offset) - , m_keyCode(keyCode) + , m_key_codes(std::move(key_codes)) , m_outKeyCode(outKeyCode) { if (offset == CELL_PAD_BTN_OFFSET_DIGITAL1) @@ -279,14 +281,14 @@ struct Button struct AnalogStick { u32 m_offset = 0; - u32 m_keyCodeMin = 0; - u32 m_keyCodeMax = 0; + std::set m_key_codes_min{}; + std::set m_key_codes_max{}; u16 m_value = 128; - AnalogStick(u32 offset, u32 keyCodeMin, u32 keyCodeMax) + AnalogStick(u32 offset, std::set key_codes_min, std::set key_codes_max) : m_offset(offset) - , m_keyCodeMin(keyCodeMin) - , m_keyCodeMax(keyCodeMax) + , m_key_codes_min(std::move(key_codes_min)) + , m_key_codes_max(std::move(key_codes_max)) {} }; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index c872167be1..e3f3c84c77 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -113,10 +113,10 @@ bool evdev_joystick_handler::Init() for (const auto& node : m_pos_axis_config.get_nodes()) { - if (*static_cast(node)) + if (node && *static_cast(node)) { - const auto name = node->get_name(); - const int code = libevdev_event_code_from_name(EV_ABS, name.c_str()); + const std::string& name = node->get_name(); + const int code = libevdev_event_code_from_name(EV_ABS, name.c_str()); if (code < 0) evdev_log.error("Failed to read axis name from %s. [code = %d] [name = %s]", m_pos_axis_config.cfg_name, code, name); else @@ -130,12 +130,14 @@ bool evdev_joystick_handler::Init() std::string evdev_joystick_handler::get_device_name(const libevdev* dev) { - std::string name = libevdev_get_name(dev); - const auto unique = libevdev_get_uniq(dev); + std::string name; + + if (const char* raw_name = libevdev_get_name(dev)) + name = raw_name; if (name.empty()) { - if (unique) + if (const char* unique = libevdev_get_uniq(dev)) name = unique; if (name.empty()) @@ -151,8 +153,8 @@ bool evdev_joystick_handler::update_device(const std::shared_ptr& dev if (!evdev_device) return false; - const auto& path = evdev_device->path; - libevdev*& dev = evdev_device->device; + const std::string& path = evdev_device->path; + libevdev*& dev = evdev_device->device; const bool was_connected = dev != nullptr; @@ -206,18 +208,18 @@ void evdev_joystick_handler::close_devices() } }; - for (auto& binding : m_bindings) + for (pad_ensemble& binding : m_bindings) { free_device(static_cast(binding.device.get())); free_device(static_cast(binding.buddy_device.get())); } - for (auto [name, device] : m_settings_added) + for (auto& [name, device] : m_settings_added) { free_device(static_cast(device.get())); } - for (auto [name, device] : m_motion_settings_added) + for (auto& [name, device] : m_motion_settings_added) { free_device(static_cast(device.get())); } @@ -229,14 +231,14 @@ std::unordered_map> evdev_joystick_handler::GetButtonV if (!device) return button_values; - auto& dev = device->device; + libevdev* dev = device->device; if (!Init()) return button_values; for (const auto& entry : button_list) { - const auto code = entry.first; + const u32 code = entry.first; if (code == NO_BUTTON) continue; @@ -251,8 +253,8 @@ std::unordered_map> evdev_joystick_handler::GetButtonV for (const auto& entry : axis_list) { - const auto code = entry.first; - int val = 0; + const u32 code = entry.first; + int val = 0; if (libevdev_fetch_event_value(dev, EV_ABS, code, &val) == 0) continue; @@ -298,7 +300,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s m_blacklist.clear(); // Get our evdev device - auto device = get_evdev_device(padId); + std::shared_ptr device = get_evdev_device(padId); if (!device || !device->device) { if (fail_callback) @@ -328,16 +330,36 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s auto data = GetButtonValues(device); - auto find_value = [=, this](const std::string& name) + const auto find_value = [&, this](const std::string& str) { - int key = FindKeyCodeByString(rev_axis_list, name, false); - const bool dir = key >= 0; - if (key < 0) - key = FindKeyCodeByString(axis_list, name, false); - if (key < 0) - key = FindKeyCodeByString(button_list, name); - auto it = data.find(static_cast(key)); - return it != data.end() && dir == it->second.second ? it->second.first : 0; + const std::vector names = cfg_pad::get_buttons(str); + + u16 value{}; + + const auto set_value = [&value, &data](u32 code, bool dir) + { + if (const auto it = data.find(static_cast(code)); it != data.cend() && dir == it->second.second) + { + value = std::max(value, it->second.first); + } + }; + + for (const u32 code : FindKeyCodes(rev_axis_list, names)) + { + set_value(code, true); + } + + for (const u32 code : FindKeyCodes(axis_list, names)) + { + set_value(code, false); + } + + for (const u32 code : FindKeyCodes(button_list, names)) + { + set_value(code, false); + } + + return value; }; pad_preview_values preview_values{}; @@ -469,7 +491,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s void evdev_joystick_handler::get_motion_sensors(const std::string& padId, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array& sensors) { // Add device if not yet present - auto device = add_motion_device(padId, true); + std::shared_ptr device = add_motion_device(padId, true); if (!device || !update_device(device) || !device->device) { if (fail_callback) @@ -477,7 +499,7 @@ void evdev_joystick_handler::get_motion_sensors(const std::string& padId, const return; } - auto& dev = device->device; + libevdev* dev = device->device; // Try to fetch all new events from the joystick. bool is_dirty = false; @@ -605,7 +627,7 @@ void evdev_joystick_handler::SetRumble(EvdevDevice* device, u8 large, u8 small) void evdev_joystick_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u8 large_motor, u8 small_motor, s32 /* r*/, s32 /* g*/, s32 /* b*/, bool /*player_led*/, bool /*battery_led*/, u32 /*battery_led_brightness*/) { // Get our evdev device - auto dev = get_evdev_device(padId); + std::shared_ptr dev = get_evdev_device(padId); if (!dev) { evdev_log.error("evdev TestVibration: Device [%s] not found! [large_motor = %d] [small_motor = %d]", padId, large_motor, small_motor); @@ -637,7 +659,7 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha if (button_list.find(code) == button_list.end()) { evdev_log.error("Evdev button %s (%d) is unknown. Please add it to the button list.", libevdev_event_code_get_name(EV_KEY, code), code); - return -1; + return umax; } value = val > 0 ? 255 : 0; @@ -647,9 +669,10 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha { if (!device || !device->device) { - return -1; + return umax; } - auto& dev = device->device; + + libevdev* dev = device->device; const int min = libevdev_get_abs_minimum(dev, code); const int max = libevdev_get_abs_maximum(dev, code); @@ -667,7 +690,8 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha value = static_cast(std::abs(fvalue)); return code; } - default: return -1; + default: + return umax; } } @@ -778,7 +802,7 @@ std::shared_ptr evdev_joystick_handler::add { if (const input_absinfo *info = libevdev_get_abs_info(dev, code)) { - const auto code_name = libevdev_event_code_get_name(EV_ABS, code); + const char* code_name = libevdev_event_code_get_name(EV_ABS, code); evdev_log.notice("Axis info for %s: %s (%s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d", name, code_name, axis_name, info->minimum, info->maximum, info->fuzz, info->flat, info->resolution); } @@ -853,7 +877,7 @@ std::shared_ptr evdev_joystick_handler::add if (const input_absinfo *info = libevdev_get_abs_info(dev, code)) { const bool is_accel = code == ABS_X || code == ABS_Y || code == ABS_Z; - const auto code_name = libevdev_event_code_get_name(EV_ABS, code); + const char* code_name = libevdev_event_code_get_name(EV_ABS, code); evdev_log.notice("Axis info for %s: %s (%s, %s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d", name, code_name, axis_name, is_accel ? "accelerometer" : "gyro", info->minimum, info->maximum, info->fuzz, info->flat, info->resolution); } @@ -898,7 +922,7 @@ void evdev_joystick_handler::get_mapping(const pad_ensemble& binding) if (!m_dev || !pad) return; - auto& dev = m_dev->device; + libevdev* dev = m_dev->device; if (!dev) return; @@ -940,7 +964,7 @@ void evdev_joystick_handler::get_extended_info(const pad_ensemble& binding) if (!pad || !device || !update_device(device)) return; - auto& dev = device->device; + libevdev* dev = device->device; if (!dev) return; @@ -1011,39 +1035,51 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st if (button_code == NO_BUTTON || value < 0) return; - const auto cfg = m_dev->config; + const cfg_pad* cfg = m_dev->config; if (!cfg) return; - auto axis_orientations = m_dev->axis_orientations; - // Find out if special buttons are pressed (introduced by RPCS3). // These buttons will have a delay of one cycle, but whatever. const bool adjust_pressure = pad->get_pressure_intensity_enabled(cfg->pressure_intensity_toggle_mode.get()); + // We can only have one match for this physical event in our button sets. + const auto find_evdev_button = [this, &button_code, &evt](const std::set& indices) -> const EvdevButton* + { + for (u32 index : indices) + { + const EvdevButton& evdev_button = ::at32(m_dev->all_buttons, index); + if (evdev_button.code == button_code && evdev_button.type == evt.type) + { + return &evdev_button; + } + } + return nullptr; + }; + // Translate any corresponding keycodes to our normal DS3 buttons and triggers for (int i = 0; i < static_cast(pad->m_buttons.size()); i++) { - auto& button = pad->m_buttons[i]; + Button& button = pad->m_buttons[i]; - if (button.m_keyCode != button_code) + const EvdevButton* evdev_button = find_evdev_button(button.m_key_codes); + if (!evdev_button) continue; // Be careful to handle mapped axis specially if (evt.type == EV_ABS) { - // get axis direction and skip on error or set to 0 if the stick/hat is actually pointing to the other direction. - // maybe mimic on error, needs investigation. FindAxisDirection should ideally never return -1 anyway - const int direction = FindAxisDirection(axis_orientations, i); - m_dev->cur_dir = direction; + // get axis direction for TranslateButtonPress and skip on error. + m_dev->cur_dir = evdev_button->dir; - if (direction < 0) + if (evdev_button->dir < 0) { - evdev_log.error("FindAxisDirection = %d, Button Nr.%d, value = %d", direction, i, value); + evdev_log.error("Invalid axis direction = %d, Button Nr.%d, value = %d", evdev_button->dir, i, value); continue; } - if (direction != (m_is_negative ? 1 : 0)) + // Set to 0 if the stick / hat is actually pointing to the other direction. + if (evdev_button->dir != (m_is_negative ? 1 : 0)) { button.m_value = 0; button.m_pressed = 0; @@ -1051,19 +1087,19 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st } } - // Using a temporary buffer because the values can change during translation - Button tmp = button; - tmp.m_value = static_cast(value); + bool pressed{}; + u16 val = static_cast(value); - TranslateButtonPress(m_dev, button_code, tmp.m_pressed, tmp.m_value); + TranslateButtonPress(m_dev, button_code, pressed, val); // Modify pressure if necessary if the button was pressed - if (adjust_pressure && tmp.m_pressed) + if (adjust_pressure && pressed) { - tmp.m_value = pad->m_pressure_intensity; + val = pad->m_pressure_intensity; } - button = tmp; + button.m_value = val; + button.m_pressed = pressed; } // Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now) @@ -1072,19 +1108,20 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st bool pressed_min = false; bool pressed_max = false; - // m_keyCodeMin is the mapped key for left or down - if (pad->m_sticks[idx].m_keyCodeMin == button_code) + // m_key_codes_min are the mapped keys for left or down + if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_min)) { bool is_direction_min = false; if (!m_is_button_or_trigger && evt.type == EV_ABS) { - const int index = pad->m_buttons.size() + (idx * 2) + 1; - const int min_direction = FindAxisDirection(axis_orientations, index); - m_dev->cur_dir = min_direction; + const int min_direction = evdev_button->dir; + + // We need to set the current direction for TranslateButtonPress + m_dev->cur_dir = min_direction; if (min_direction < 0) - evdev_log.error("keyCodeMin FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", min_direction, idx, index, value); + evdev_log.error("min_direction = %d, Axis Nr.%d, value = %d", min_direction, idx, value); else is_direction_min = m_is_negative == (min_direction == 1); } @@ -1100,19 +1137,20 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st } } - // m_keyCodeMax is the mapped key for right or up - if (pad->m_sticks[idx].m_keyCodeMax == button_code) + // m_key_codes_max are the mapped keys for right or up + if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_max)) { bool is_direction_max = false; if (!m_is_button_or_trigger && evt.type == EV_ABS) { - const int index = pad->m_buttons.size() + (idx * 2); - const int max_direction = FindAxisDirection(axis_orientations, index); - m_dev->cur_dir = max_direction; + const int max_direction = evdev_button->dir; + + // We need to set the current direction for TranslateButtonPress + m_dev->cur_dir = max_direction; if (max_direction < 0) - evdev_log.error("keyCodeMax FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", max_direction, idx, index, value); + evdev_log.error("max_direction = %d, Axis Nr.%d, value = %d", max_direction, idx, value); else is_direction_max = m_is_negative == (max_direction == 1); } @@ -1153,7 +1191,7 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding) if (!evdev_device) return; - auto cfg = device->config; + cfg_pad* cfg = device->config; if (!cfg) return; @@ -1165,16 +1203,6 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding) SetRumble(evdev_device, force_large, force_small); } -// Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative -int evdev_joystick_handler::FindAxisDirection(const std::unordered_map& map, int index) -{ - if (const auto it = map.find(index); it != map.end()) - { - return it->second; - } - return -1; -} - bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player_id) { if (!pad || player_id >= g_cfg_input.player.size()) @@ -1195,38 +1223,46 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player if (!cfg) return false; - std::unordered_map axis_orientations; - int i = 0; // increment to know the axis location - - auto evdevbutton = [&](const cfg::string& name) + // We need to register EvdevButtons due to their axis directions. + const auto register_evdevbutton = [this](u32 code, bool is_axis, bool is_reverse) -> u32 { - EvdevButton button{ 0, -1, EV_ABS }; + const u32 index = ::narrow(m_dev->all_buttons.size()); - int key = FindKeyCode(axis_list, name, false); - if (key >= 0) - axis_orientations.emplace(i, false); - - if (key < 0) + if (is_axis) { - key = FindKeyCode(rev_axis_list, name, false); - if (key >= 0) - axis_orientations.emplace(i, true); - } - - if (key < 0) - { - key = FindKeyCode(button_list, name); - button.type = EV_KEY; + m_dev->all_buttons.push_back(EvdevButton{ code, is_reverse ? 1 : 0, EV_ABS }); } else { - button.dir = axis_orientations[i]; + m_dev->all_buttons.push_back(EvdevButton{ code, -1, EV_KEY }); } - button.code = static_cast(key); + return index; + }; - i++; - return button; + const auto find_buttons = [&](const cfg::string& name) -> std::set + { + const std::vector names = cfg_pad::get_buttons(name); + + // In evdev we store indices to an EvdevButton vector in our pad objects instead of the usual key codes. + std::set indices; + + for (const u32 code : FindKeyCodes(axis_list, names)) + { + indices.insert(register_evdevbutton(code, true, false)); + } + + for (const u32 code : FindKeyCodes(rev_axis_list, names)) + { + indices.insert(register_evdevbutton(code, true, true)); + } + + for (const u32 code : FindKeyCodes(button_list, names)) + { + indices.insert(register_evdevbutton(code, false, false)); + } + + return indices; }; const auto find_motion_button = [&](const cfg_sensor& sensor) -> evdev_sensor @@ -1235,14 +1271,15 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player e_sensor.type = EV_ABS; e_sensor.mirrored = sensor.mirrored.get(); e_sensor.shift = sensor.shift.get(); - const int key = FindKeyCode(motion_axis_list, sensor.axis, false); - if (key >= 0) e_sensor.code = static_cast(key); + + const std::set keys = FindKeyCodes(motion_axis_list, sensor.axis); + if (!keys.empty()) e_sensor.code = *keys.begin(); // We should only have one key for each of our sensors return e_sensor; }; u32 pclass_profile = 0x0; - for (const auto product : input::get_products_by_class(cfg->device_class_type)) + for (const input::product_info& product : input::get_products_by_class(cfg->device_class_type)) { if (product.vendor_id == cfg->vendor_id && product.product_id == cfg->product_id) { @@ -1262,45 +1299,45 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player cfg->pressure_intensity ); - pad->m_buttons.emplace_back(special_button_offset, evdevbutton(cfg->pressure_intensity_button).code, special_button_value::pressure_intensity); + pad->m_buttons.emplace_back(special_button_offset, find_buttons(cfg->pressure_intensity_button), special_button_value::pressure_intensity); pad->m_pressure_intensity_button_index = static_cast(pad->m_buttons.size()) - 1; - 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); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->square), CELL_PAD_CTRL_SQUARE); - 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_left = find_buttons(cfg->l2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left, CELL_PAD_CTRL_L2); - 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); + m_dev->trigger_right = find_buttons(cfg->r2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right, CELL_PAD_CTRL_R2); - 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_DIGITAL1, evdevbutton(cfg->ps).code, CELL_PAD_CTRL_PS); - 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, find_buttons(cfg->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_buttons(cfg->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->ps), CELL_PAD_CTRL_PS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->right), CELL_PAD_CTRL_RIGHT); - 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); + m_dev->axis_left[0] = find_buttons(cfg->ls_right); + m_dev->axis_left[1] = find_buttons(cfg->ls_left); + m_dev->axis_left[2] = find_buttons(cfg->ls_up); + m_dev->axis_left[3] = find_buttons(cfg->ls_down); + m_dev->axis_right[0] = find_buttons(cfg->rs_right); + m_dev->axis_right[1] = find_buttons(cfg->rs_left); + m_dev->axis_right[2] = find_buttons(cfg->rs_up); + m_dev->axis_right[3] = find_buttons(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); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev->axis_right[1].code, m_dev->axis_right[0].code); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev->axis_right[3].code, m_dev->axis_right[2].code); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev->axis_left[1], m_dev->axis_left[0]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev->axis_left[3], m_dev->axis_left[2]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev->axis_right[1], m_dev->axis_right[0]); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev->axis_right[3], m_dev->axis_right[2]); m_dev->axis_motion[0] = find_motion_button(cfg->motion_sensor_x); m_dev->axis_motion[1] = find_motion_button(cfg->motion_sensor_y); @@ -1315,11 +1352,9 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(false, 0); - m_dev->axis_orientations = axis_orientations; - - if (auto evdev_device = add_device(player_config->device, false)) + if (std::shared_ptr evdev_device = add_device(player_config->device, false)) { - if (auto motion_device = add_motion_device(player_config->buddy_device, false)) + if (std::shared_ptr motion_device = add_motion_device(player_config->buddy_device, false)) { m_bindings.emplace_back(pad, evdev_device, motion_device); } @@ -1334,7 +1369,7 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player evdev_log.warning("evdev add_device in bindPadToDevice failed for device %s", player_config->device.to_string()); } - for (auto& binding : m_bindings) + for (pad_ensemble& binding : m_bindings) { update_device(binding.device); update_device(binding.buddy_device); @@ -1343,34 +1378,46 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, u8 player return true; } -bool evdev_joystick_handler::check_button(const EvdevButton& b, const u32 code) +bool evdev_joystick_handler::check_button_set(const std::set& indices, const u32 code) { - return m_dev && b.code == code && b.type == m_dev->cur_type && b.dir == m_dev->cur_dir; + if (!m_dev) + return false; + + for (u32 index : indices) + { + const EvdevButton& button = ::at32(m_dev->all_buttons, index); + if (button.code == code && button.type == m_dev->cur_type && button.dir == m_dev->cur_dir) + { + return true; + } + } + + return false; } -bool evdev_joystick_handler::check_buttons(const std::array& b, const u32 code) +bool evdev_joystick_handler::check_button_sets(const std::array, 4>& sets, const u32 code) { - return std::any_of(b.begin(), b.end(), [this, code](const EvdevButton& b) { return check_button(b, code); }); + return std::any_of(sets.begin(), sets.end(), [this, code](const std::set& indices) { return check_button_set(indices, code); }); }; bool evdev_joystick_handler::get_is_left_trigger(const std::shared_ptr& /*device*/, u64 keyCode) { - return check_button(m_dev->trigger_left, static_cast(keyCode)); + return check_button_set(m_dev->trigger_left, static_cast(keyCode)); } bool evdev_joystick_handler::get_is_right_trigger(const std::shared_ptr& /*device*/, u64 keyCode) { - return check_button(m_dev->trigger_right, static_cast(keyCode)); + return check_button_set(m_dev->trigger_right, static_cast(keyCode)); } bool evdev_joystick_handler::get_is_left_stick(const std::shared_ptr& /*device*/, u64 keyCode) { - return check_buttons(m_dev->axis_left, static_cast(keyCode)); + return check_button_sets(m_dev->axis_left, static_cast(keyCode)); } bool evdev_joystick_handler::get_is_right_stick(const std::shared_ptr& /*device*/, u64 keyCode) { - return check_buttons(m_dev->axis_right, static_cast(keyCode)); + return check_button_sets(m_dev->axis_right, static_cast(keyCode)); } #endif diff --git a/rpcs3/Input/evdev_joystick_handler.h b/rpcs3/Input/evdev_joystick_handler.h index a8f41cb2ed..0f2d917bf6 100644 --- a/rpcs3/Input/evdev_joystick_handler.h +++ b/rpcs3/Input/evdev_joystick_handler.h @@ -341,9 +341,9 @@ class evdev_joystick_handler final : public PadHandlerBase struct EvdevButton { - u32 code = 0; - int dir = 0; - int type = 0; + u32 code = 0; // key code of our button or axis + int dir = 0; // dir is -1 in case of a button, 0 in case of a regular axis and 1 in case of a reverse axis + int type = 0; // EV_KEY or EV_ABS }; struct evdev_sensor : public EvdevButton @@ -356,14 +356,14 @@ class evdev_joystick_handler final : public PadHandlerBase { libevdev* device{ nullptr }; std::string path; - std::unordered_map axis_orientations; // value is true if key was found in rev_axis_list std::array stick_val{}; std::array val_min{}; std::array val_max{}; - EvdevButton trigger_left{}; - EvdevButton trigger_right{}; - std::array axis_left{}; - std::array axis_right{}; + std::vector all_buttons; + std::set trigger_left{}; + std::set trigger_right{}; + std::array, 4> axis_left{}; + std::array, 4> axis_right{}; std::array axis_motion{}; int cur_dir = 0; int cur_type = 0; @@ -397,20 +397,17 @@ private: std::unordered_map> GetButtonValues(const std::shared_ptr& device); void SetRumble(EvdevDevice* device, u8 large, u8 small); - // Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative - int FindAxisDirection(const std::unordered_map& map, int index); - positive_axis m_pos_axis_config; std::vector m_positive_axis; std::vector m_blacklist; std::unordered_map> m_settings_added; std::unordered_map> m_motion_settings_added; std::shared_ptr m_dev; - bool m_is_button_or_trigger; - bool m_is_negative; + bool m_is_button_or_trigger{}; + bool m_is_negative{}; - bool check_button(const EvdevButton& b, const u32 code); - bool check_buttons(const std::array& b, const u32 code); + bool check_button_set(const std::set& indices, const u32 code); + bool check_button_sets(const std::array, 4>& sets, const u32 code); void handle_input_event(const input_event& evt, const std::shared_ptr& pad); diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index b97479ce51..817608bfdf 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -6,8 +6,6 @@ #include -LOG_CHANNEL(input_log, "Input"); - inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; @@ -85,7 +83,7 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) { Button& pressure_intensity_button = pad.m_buttons[pad.m_pressure_intensity_button_index]; - if (pressure_intensity_button.m_keyCode == code) + if (pressure_intensity_button.m_key_codes.contains(code)) { pressure_intensity_button.m_pressed = pressed; pressure_intensity_button.m_value = value; @@ -97,9 +95,31 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) // Handle buttons for (Button& button : pad.m_buttons) { - if (button.m_keyCode != code) + if (!button.m_key_codes.contains(code)) continue; + // Make sure we keep this button pressed until all related keys are released. + if (pressed) + { + button.m_pressed_keys.insert(code); + + if (button.m_pressed_keys.size() > 1) + { + // This button was already pressed by another key. Ignore this key press. + continue; + } + } + else + { + button.m_pressed_keys.erase(code); + + if (!button.m_pressed_keys.empty()) + { + // This button is still pressed by another key. Ignore this key release. + continue; + } + } + button.m_actual_value = pressed ? value : 0; bool update_button = true; @@ -133,8 +153,8 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) // Handle sticks for (usz i = 0; i < pad.m_sticks.size(); i++) { - const bool is_max = pad.m_sticks[i].m_keyCodeMax == code; - const bool is_min = pad.m_sticks[i].m_keyCodeMin == code; + const bool is_max = pad.m_sticks[i].m_key_codes_max.contains(code); + const bool is_min = pad.m_sticks[i].m_key_codes_min.contains(code); if (!is_max && !is_min) { @@ -697,9 +717,17 @@ std::string keyboard_pad_handler::GetKeyName(const u32& keyCode) return sstr(QKeySequence(keyCode).toString(QKeySequence::NativeText)); } -u32 keyboard_pad_handler::GetKeyCode(const std::string& keyName) +std::set keyboard_pad_handler::GetKeyCodes(const cfg::string& cfg_string) { - return GetKeyCode(qstr(keyName)); + std::set key_codes; + for (const std::string& key_name : cfg_pad::get_buttons(cfg_string)) + { + if (u32 code = GetKeyCode(QString::fromStdString(key_name)); code != Qt::NoButton) + { + key_codes.insert(code); + } + } + return key_codes; } u32 keyboard_pad_handler::GetKeyCode(const QString& keyName) @@ -731,7 +759,7 @@ u32 keyboard_pad_handler::GetKeyCode(const QString& keyName) #endif const QKeySequence seq(keyName); - u32 key_code = 0; + u32 key_code = Qt::NoButton; if (seq.count() == 1) key_code = seq[0]; @@ -812,18 +840,25 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, u8 player_i m_r_stick_multiplier = cfg->rstickmultiplier; m_pressure_intensity_toggle_mode = cfg->pressure_intensity_toggle_mode.get(); - const auto find_key = [this](const cfg::string& name) + const auto find_keys = [this](const cfg::string& name) { - int key = FindKeyCode(mouse_list, name, false); - if (key < 0) - key = GetKeyCode(name); - if (key < 0) - key = 0; - else if (!m_mouse_move_used && (key == mouse::move_left || key == mouse::move_right || key == mouse::move_up || key == mouse::move_down)) - m_mouse_move_used = true; - else if (!m_mouse_wheel_used && (key == mouse::wheel_left || key == mouse::wheel_right || key == mouse::wheel_up || key == mouse::wheel_down)) - m_mouse_wheel_used = true; - return key; + std::set keys = FindKeyCodes(mouse_list, name, false); + if (keys.empty()) + { + keys = GetKeyCodes(name); + } + if (!keys.empty()) + { + if (!m_mouse_move_used && (keys.contains(mouse::move_left) || keys.contains(mouse::move_right) || keys.contains(mouse::move_up) || keys.contains(mouse::move_down))) + { + m_mouse_move_used = true; + } + else if (!m_mouse_wheel_used && (keys.contains(mouse::wheel_left) || keys.contains(mouse::wheel_right) || keys.contains(mouse::wheel_up) || keys.contains(mouse::wheel_down))) + { + m_mouse_wheel_used = true; + } + } + return keys; }; u32 pclass_profile = 0x0; @@ -849,31 +884,31 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, u8 player_i cfg->pressure_intensity ); - pad->m_buttons.emplace_back(special_button_offset, find_key(cfg->pressure_intensity_button), special_button_value::pressure_intensity); + pad->m_buttons.emplace_back(special_button_offset, find_keys(cfg->pressure_intensity_button), special_button_value::pressure_intensity); pad->m_pressure_intensity_button_index = static_cast(pad->m_buttons.size()) - 1; - 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_DIGITAL1, find_key(cfg->ps), CELL_PAD_CTRL_PS); - 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_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->ps), CELL_PAD_CTRL_PS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->r2), CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->l2), CELL_PAD_CTRL_L2); - 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_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_keys(cfg->ls_left), find_keys(cfg->ls_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_keys(cfg->ls_up), find_keys(cfg->ls_down)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_keys(cfg->rs_left), find_keys(cfg->rs_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_keys(cfg->rs_up), find_keys(cfg->rs_down)); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y); @@ -891,8 +926,8 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, u8 player_i void keyboard_pad_handler::process() { - static const double stick_interval = 10.0; - static const double button_interval = 10.0; + constexpr double stick_interval = 10.0; + constexpr double button_interval = 10.0; const auto now = steady_clock::now(); @@ -914,7 +949,7 @@ void keyboard_pad_handler::process() if (m_mouse_move_used && m_mouse_movement_mode == mouse_movement_mode::relative) { - static const double mouse_interval = 30.0; + constexpr double mouse_interval = 30.0; const double elapsed_left = std::chrono::duration_cast(now - m_last_mouse_move_left).count() / 1000.0; const double elapsed_right = std::chrono::duration_cast(now - m_last_mouse_move_right).count() / 1000.0; @@ -987,7 +1022,7 @@ void keyboard_pad_handler::process() if (update_buttons) { - for (auto& button : pad.m_buttons) + for (Button& button : pad.m_buttons) { if (button.m_analog) { diff --git a/rpcs3/Input/keyboard_pad_handler.h b/rpcs3/Input/keyboard_pad_handler.h index 98926d150d..444b772bd4 100644 --- a/rpcs3/Input/keyboard_pad_handler.h +++ b/rpcs3/Input/keyboard_pad_handler.h @@ -93,7 +93,7 @@ public: static QStringList GetKeyNames(const QKeyEvent* keyEvent); static std::string GetKeyName(const QKeyEvent* keyEvent); static std::string GetKeyName(const u32& keyCode); - static u32 GetKeyCode(const std::string& keyName); + static std::set GetKeyCodes(const cfg::string& cfg_string); static u32 GetKeyCode(const QString& keyName); static int native_scan_code_from_string(const std::string& key); diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index 924eb1b21c..a89de5253c 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -2,8 +2,6 @@ #include "mm_joystick_handler.h" #include "Emu/Io/pad_config.h" -LOG_CHANNEL(input_log, "Input"); - mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm) { init_configs(); @@ -113,62 +111,70 @@ std::vector mm_joystick_handler::list_devices() return devices; } -u64 mm_joystick_handler::find_key(const std::string& name) const +template +std::set mm_joystick_handler::find_keys(const cfg::string& cfg_string) const { - long key = FindKeyCodeByString(axis_list, name, false); - if (key < 0) - key = FindKeyCodeByString(pov_list, name, false); - if (key < 0) - key = FindKeyCodeByString(button_list, name); - return static_cast(key); + return find_keys(cfg_pad::get_buttons(cfg_string)); } -std::array mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) +template +std::set mm_joystick_handler::find_keys(const std::vector& names) const { - std::array mapping{}; + std::set keys; + + for (const T& k : FindKeyCodes(axis_list, names)) keys.insert(k); + for (const T& k : FindKeyCodes(pov_list, names)) keys.insert(k); + for (const T& k : FindKeyCodes(button_list, names)) keys.insert(k); + + return keys; +} + +std::array, PadHandlerBase::button::button_count> mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) +{ + std::array, button::button_count> mapping{}; MMJOYDevice* joy_device = static_cast(device.get()); if (!joy_device || !cfg) return mapping; - joy_device->trigger_code_left = find_key(cfg->l2); - joy_device->trigger_code_right = find_key(cfg->r2); - joy_device->axis_code_left[0] = find_key(cfg->ls_left); - joy_device->axis_code_left[1] = find_key(cfg->ls_right); - joy_device->axis_code_left[2] = find_key(cfg->ls_down); - joy_device->axis_code_left[3] = find_key(cfg->ls_up); - joy_device->axis_code_right[0] = find_key(cfg->rs_left); - joy_device->axis_code_right[1] = find_key(cfg->rs_right); - joy_device->axis_code_right[2] = find_key(cfg->rs_down); - joy_device->axis_code_right[3] = find_key(cfg->rs_up); + joy_device->trigger_code_left = find_keys(cfg->l2); + joy_device->trigger_code_right = find_keys(cfg->r2); + joy_device->axis_code_left[0] = find_keys(cfg->ls_left); + joy_device->axis_code_left[1] = find_keys(cfg->ls_right); + joy_device->axis_code_left[2] = find_keys(cfg->ls_down); + joy_device->axis_code_left[3] = find_keys(cfg->ls_up); + joy_device->axis_code_right[0] = find_keys(cfg->rs_left); + joy_device->axis_code_right[1] = find_keys(cfg->rs_right); + joy_device->axis_code_right[2] = find_keys(cfg->rs_down); + joy_device->axis_code_right[3] = find_keys(cfg->rs_up); - 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_code_left); - 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_code_right); - 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_code_left[0]); - mapping[button::ls_right] = static_cast(joy_device->axis_code_left[1]); - mapping[button::ls_down] = static_cast(joy_device->axis_code_left[2]); - mapping[button::ls_up] = static_cast(joy_device->axis_code_left[3]); - mapping[button::rs_left] = static_cast(joy_device->axis_code_right[0]); - mapping[button::rs_right] = static_cast(joy_device->axis_code_right[1]); - mapping[button::rs_down] = static_cast(joy_device->axis_code_right[2]); - mapping[button::rs_up] = static_cast(joy_device->axis_code_right[3]); + mapping[button::up] = find_keys(cfg->up); + mapping[button::down] = find_keys(cfg->down); + mapping[button::left] = find_keys(cfg->left); + mapping[button::right] = find_keys(cfg->right); + mapping[button::cross] = find_keys(cfg->cross); + mapping[button::square] = find_keys(cfg->square); + mapping[button::circle] = find_keys(cfg->circle); + mapping[button::triangle] = find_keys(cfg->triangle); + mapping[button::l1] = find_keys(cfg->l1); + mapping[button::l2] = narrow_set(joy_device->trigger_code_left); + mapping[button::l3] = find_keys(cfg->l3); + mapping[button::r1] = find_keys(cfg->r1); + mapping[button::r2] = narrow_set(joy_device->trigger_code_right); + mapping[button::r3] = find_keys(cfg->r3); + mapping[button::start] = find_keys(cfg->start); + mapping[button::select] = find_keys(cfg->select); + mapping[button::ps] = find_keys(cfg->ps); + mapping[button::ls_left] = narrow_set(joy_device->axis_code_left[0]); + mapping[button::ls_right] = narrow_set(joy_device->axis_code_left[1]); + mapping[button::ls_down] = narrow_set(joy_device->axis_code_left[2]); + mapping[button::ls_up] = narrow_set(joy_device->axis_code_left[3]); + mapping[button::rs_left] = narrow_set(joy_device->axis_code_right[0]); + mapping[button::rs_right] = narrow_set(joy_device->axis_code_right[1]); + mapping[button::rs_down] = narrow_set(joy_device->axis_code_right[2]); + mapping[button::rs_up] = narrow_set(joy_device->axis_code_right[3]); - mapping[button::pressure_intensity_button] = static_cast(find_key(cfg->pressure_intensity_button)); + mapping[button::pressure_intensity_button] = find_keys(cfg->pressure_intensity_button); return mapping; } @@ -230,9 +236,8 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: std::string name; } pressed_button{}; - for (const auto& button : axis_list) + for (const auto& [keycode, name] : axis_list) { - u64 keycode = button.first; u16 value = data[keycode]; if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend()) @@ -242,20 +247,19 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: { if (get_blacklist) { - m_blacklist.emplace_back(keycode); - input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); + m_blacklist.push_back(keycode); + input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, name, value); } else if (value > pressed_button.value) { - pressed_button = { .value = value, .name = button.second }; + pressed_button = { .value = value, .name = name }; } } } - for (const auto& button : pov_list) + for (const auto& [keycode, name] : pov_list) { - u64 keycode = button.first; - u16 value = data[keycode]; + const u16 value = data[keycode]; if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend()) continue; @@ -264,20 +268,18 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: { if (get_blacklist) { - m_blacklist.emplace_back(keycode); - input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); + m_blacklist.push_back(keycode); + input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, name, value); } else if (value > pressed_button.value) { - pressed_button = { .value = value, .name = button.second }; + pressed_button = { .value = value, .name = name }; } } } - for (const auto& button : button_list) + for (const auto& [keycode, name] : button_list) { - const u64 keycode = button.first; - if (keycode == NO_BUTTON) continue; @@ -290,12 +292,12 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: { if (get_blacklist) { - m_blacklist.emplace_back(keycode); - input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); + m_blacklist.push_back(keycode); + input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, name, value); } else if (value > pressed_button.value) { - pressed_button = { .value = value, .name = button.second }; + pressed_button = { .value = value, .name = name }; } } } @@ -312,12 +314,24 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: pad_preview_values preview_values{}; if (buttons.size() == 10) { - preview_values[0] = data[find_key(buttons[0])]; - preview_values[1] = data[find_key(buttons[1])]; - preview_values[2] = data[find_key(buttons[3])] - data[find_key(buttons[2])]; - preview_values[3] = data[find_key(buttons[5])] - data[find_key(buttons[4])]; - preview_values[4] = data[find_key(buttons[7])] - data[find_key(buttons[6])]; - preview_values[5] = data[find_key(buttons[9])] - data[find_key(buttons[8])]; + const auto get_key_value = [this, &data](const std::string& str) -> u16 + { + u16 value{}; + for (u32 key_code : find_keys(cfg_pad::get_buttons(str))) + { + if (const auto it = data.find(key_code); it != data.cend()) + { + value = std::max(value, it->second); + } + } + return value; + }; + preview_values[0] = get_key_value(buttons[0]); + preview_values[1] = get_key_value(buttons[1]); + preview_values[2] = get_key_value(buttons[3]) - get_key_value(buttons[2]); + preview_values[3] = get_key_value(buttons[5]) - get_key_value(buttons[4]); + preview_values[4] = get_key_value(buttons[7]) - get_key_value(buttons[6]); + preview_values[5] = get_key_value(buttons[9]) - get_key_value(buttons[8]); } if (pressed_button.value > 0) @@ -492,25 +506,25 @@ std::shared_ptr mm_joystick_handler::get_device(const std::string& de bool mm_joystick_handler::get_is_left_trigger(const std::shared_ptr& device, u64 keyCode) { const MMJOYDevice* dev = static_cast(device.get()); - return dev && dev->trigger_code_left == keyCode; + return dev && dev->trigger_code_left.contains(keyCode); } bool mm_joystick_handler::get_is_right_trigger(const std::shared_ptr& device, u64 keyCode) { const MMJOYDevice* dev = static_cast(device.get()); - return dev && dev->trigger_code_right == keyCode; + return dev && dev->trigger_code_right.contains(keyCode); } bool mm_joystick_handler::get_is_left_stick(const std::shared_ptr& device, u64 keyCode) { const MMJOYDevice* dev = static_cast(device.get()); - return dev && std::find(dev->axis_code_left.cbegin(), dev->axis_code_left.cend(), keyCode) != dev->axis_code_left.cend(); + return dev && std::any_of(dev->axis_code_left.cbegin(), dev->axis_code_left.cend(), [&keyCode](const std::set& s){ return s.contains(keyCode); }); } bool mm_joystick_handler::get_is_right_stick(const std::shared_ptr& device, u64 keyCode) { const MMJOYDevice* dev = static_cast(device.get()); - return dev && std::find(dev->axis_code_right.cbegin(), dev->axis_code_right.cend(), keyCode) != dev->axis_code_right.cend(); + return dev && std::any_of(dev->axis_code_right.cbegin(), dev->axis_code_right.cend(), [&keyCode](const std::set& s){ return s.contains(keyCode); }); } PadHandlerBase::connection mm_joystick_handler::update_connection(const std::shared_ptr& device) diff --git a/rpcs3/Input/mm_joystick_handler.h b/rpcs3/Input/mm_joystick_handler.h index 3b597da223..d2752fa344 100644 --- a/rpcs3/Input/mm_joystick_handler.h +++ b/rpcs3/Input/mm_joystick_handler.h @@ -126,9 +126,13 @@ private: std::vector m_blacklist; std::unordered_map m_devices; - u64 find_key(const std::string& name) const; + template + std::set find_keys(const std::vector& names) const; - std::array get_mapped_key_codes(const std::shared_ptr& device, const cfg_pad* cfg) override; + template + std::set find_keys(const cfg::string& cfg_string) const; + + std::array, PadHandlerBase::button::button_count> 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(const std::shared_ptr& device, u64 keyCode) override; bool get_is_right_trigger(const std::shared_ptr& device, u64 keyCode) override; diff --git a/rpcs3/Input/pad_thread.cpp b/rpcs3/Input/pad_thread.cpp index ba750e73a7..72b49f41c9 100644 --- a/rpcs3/Input/pad_thread.cpp +++ b/rpcs3/Input/pad_thread.cpp @@ -24,7 +24,6 @@ #include "Utilities/Thread.h" #include "util/atomic.hpp" -LOG_CHANNEL(input_log, "Input"); LOG_CHANNEL(sys_log, "SYS"); extern bool is_input_allowed(); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index fc9a6136ac..6777ae2aaf 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -53,6 +53,15 @@ inline bool CreateConfigFile(const QString& dir, const QString& name) return true; } +void pad_settings_dialog::pad_button::insert_key(const std::string& key) +{ + std::vector buttons = cfg_pad::get_buttons(keys); + buttons.push_back(key); + + keys = cfg_pad::get_buttons(std::move(buttons)); + text = QString::fromStdString(keys).replace(",", ", "); +} + pad_settings_dialog::pad_settings_dialog(std::shared_ptr gui_settings, QWidget *parent, const GameInfo *game) : QDialog(parent) , ui(new Ui::pad_settings_dialog) @@ -291,7 +300,7 @@ void pad_settings_dialog::InitButtons() connect(m_pad_buttons, &QButtonGroup::idClicked, this, &pad_settings_dialog::OnPadButtonClicked); - connect(&m_timer, &QTimer::timeout, this, [this]() + connect(&m_remap_timer, &QTimer::timeout, this, [this]() { if (--m_seconds <= 0) { @@ -414,7 +423,7 @@ void pad_settings_dialog::InitButtons() { SwitchPadInfo(pad_name, true); - if (!m_enable_buttons && !m_timer.isActive()) + if (!m_enable_buttons && !m_remap_timer.isActive()) { SwitchButtons(true); } @@ -449,8 +458,7 @@ void pad_settings_dialog::InitButtons() if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) { - m_cfg_entries[m_button_id].key = name; - m_cfg_entries[m_button_id].text = qstr(name); + m_cfg_entries[m_button_id].insert_key(name); ReactivateButtons(); } }; @@ -536,10 +544,10 @@ void pad_settings_dialog::InitButtons() const std::vector buttons = { - m_cfg_entries[button_ids::id_pad_l2].key, m_cfg_entries[button_ids::id_pad_r2].key, m_cfg_entries[button_ids::id_pad_lstick_left].key, - m_cfg_entries[button_ids::id_pad_lstick_right].key, m_cfg_entries[button_ids::id_pad_lstick_down].key, m_cfg_entries[button_ids::id_pad_lstick_up].key, - m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key, - m_cfg_entries[button_ids::id_pad_rstick_up].key + 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 }; const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name, @@ -629,7 +637,7 @@ void pad_settings_dialog::switch_pad_info(int index, pad_device_info info, bool ui->chooseDevice->setItemText(index, is_connected ? qstr(info.name) : (qstr(info.name) + Disconnected_suffix)); } - if (!is_connected && m_timer.isActive() && ui->chooseDevice->currentIndex() == index) + if (!is_connected && m_remap_timer.isActive() && ui->chooseDevice->currentIndex() == index) { ReactivateButtons(); } @@ -699,7 +707,7 @@ void pad_settings_dialog::ReloadButtons() void pad_settings_dialog::ReactivateButtons() { - m_timer.stop(); + m_remap_timer.stop(); m_seconds = MAX_SECONDS; if (m_button_id == button_ids::id_pad_begin) @@ -844,8 +852,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) } else { - m_cfg_entries[m_button_id].key = keyboard_pad_handler::GetKeyName(keyEvent); - m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); + m_cfg_entries[m_button_id].insert_key(keyboard_pad_handler::GetKeyName(keyEvent)); } ReactivateButtons(); @@ -872,8 +879,7 @@ void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event) } else { - m_cfg_entries[m_button_id].key = (static_cast(m_handler.get()))->GetMouseName(event); - m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); + m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(event)); } ReactivateButtons(); @@ -934,8 +940,8 @@ void pad_settings_dialog::wheelEvent(QWheelEvent *event) key = mouse::wheel_down; } } - m_cfg_entries[m_button_id].key = (static_cast(m_handler.get()))->GetMouseName(key); - m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); + + m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(key)); ReactivateButtons(); } @@ -985,8 +991,7 @@ void pad_settings_dialog::mouseMoveEvent(QMouseEvent* event) if (key != 0) { - m_cfg_entries[m_button_id].key = (static_cast(m_handler.get()))->GetMouseName(key); - m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key); + m_cfg_entries[m_button_id].insert_key((static_cast(m_handler.get()))->GetMouseName(key)); ReactivateButtons(); } } @@ -1006,8 +1011,9 @@ bool pad_settings_dialog::eventFilter(QObject* object, QEvent* event) { if (const int button_id = m_pad_buttons->id(button); m_cfg_entries.contains(button_id)) { - m_cfg_entries[button_id].key.clear(); - m_cfg_entries[button_id].text.clear(); + pad_button& button = m_cfg_entries[button_id]; + button.keys.clear(); + button.text.clear(); UpdateLabels(); return true; @@ -1172,16 +1178,16 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) ui->gb_battery->setVisible(m_enable_battery || m_enable_led); } - for (auto& entry : m_cfg_entries) + for (auto& [id, button] : m_cfg_entries) { if (is_reset) { - entry.second.key = *entry.second.cfg_text; - entry.second.text = qstr(entry.second.key); + button.keys = *button.cfg_text; + button.text = qstr(button.keys); } // The button has to contain at least one character, because it would be square'ish otherwise - m_pad_buttons->button(entry.first)->setText(entry.second.text.isEmpty() ? QStringLiteral("-") : entry.second.text); + m_pad_buttons->button(id)->setText(button.text.isEmpty() ? QStringLiteral("-") : button.text); } } @@ -1271,7 +1277,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) m_pad_buttons->button(m_button_id)->setPalette(QPalette(Qt::blue)); m_pad_buttons->button(m_button_id)->grabMouse(); SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons - m_timer.start(1000); + m_remap_timer.start(1000); } void pad_settings_dialog::OnTabChanged(int index) @@ -1487,7 +1493,7 @@ void pad_settings_dialog::ChangeHandler() } // Handle running timers - if (m_timer.isActive()) + if (m_remap_timer.isActive()) { ReactivateButtons(); } @@ -1717,7 +1723,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) return; } - m_duplicate_buttons[m_last_player_id] = ""; + m_duplicate_buttons[m_last_player_id].clear(); auto& player = g_cfg_input.player[m_last_player_id]; m_last_player_id = new_player_id; @@ -1726,16 +1732,19 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id) if (m_handler->m_type != pad_handler::null) { std::set unique_keys; - for (const auto& entry : m_cfg_entries) + for (const auto& [id, button] : m_cfg_entries) { // Let's ignore special keys, unless we're using a keyboard - if (entry.first == button_ids::id_pressure_intensity && m_handler->m_type != pad_handler::keyboard) + if (id == button_ids::id_pressure_intensity && m_handler->m_type != pad_handler::keyboard) continue; - if (const auto& [it, ok] = unique_keys.insert(entry.second.key); !ok) + for (const std::string& key : cfg_pad::get_buttons(button.keys)) { - m_duplicate_buttons[m_last_player_id] = entry.second.key; - break; + if (const auto& [it, ok] = unique_keys.insert(key); !ok) + { + m_duplicate_buttons[m_last_player_id] = key; + break; + } } } } @@ -1743,7 +1752,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.key); + entry.second.cfg_text->from_string(entry.second.keys); } // Apply rest of config diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index e6cea62a94..e4bd7e5841 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -80,8 +80,10 @@ class pad_settings_dialog : public QDialog struct pad_button { cfg::string* cfg_text = nullptr; - std::string key; + std::string keys; QString text; + + void insert_key(const std::string& key); }; const QString Disconnected_suffix = tr(" (disconnected)"); @@ -152,7 +154,7 @@ private: // Remap Timer const int MAX_SECONDS = 5; int m_seconds = MAX_SECONDS; - QTimer m_timer; + QTimer m_remap_timer; // Mouse Move QPoint m_last_pos;