diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 8ac42fc925..1e22da3fc8 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -334,12 +334,9 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. // Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold) - // Get all the legally pressed buttons and use the one with highest value (prioritize first) - struct - { - u16 value = 0; - std::string name; - } pressed_button{}; + // Get all the legally pressed buttons. We only accept one value per stick though, otherwise it will get messy. + std::map pressed_buttons; + std::array, 2> pressed_sticks{}; for (const auto& [keycode, name] : button_list) { @@ -356,7 +353,9 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri } const bool is_trigger = get_is_left_trigger(device, keycode) || get_is_right_trigger(device, keycode); - const bool is_stick = !is_trigger && (get_is_left_stick(device, keycode) || get_is_right_stick(device, keycode)); + const bool is_left_stick = !is_trigger && get_is_left_stick(device, keycode); + const bool is_right_stick = !is_trigger && !is_left_stick && get_is_right_stick(device, keycode); + const bool is_stick = is_left_stick || is_right_stick; const bool is_touch_motion = !is_trigger && !is_stick && get_is_touch_pad_motion(device, keycode); const bool is_button = !is_trigger && !is_stick && !is_touch_motion; @@ -374,9 +373,27 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri const u16 diff = value > min_value ? value - min_value : 0; - if (diff > button_press_threshold && value > pressed_button.value) + if (diff > button_press_threshold) { - pressed_button = { .value = value, .name = name }; + if (is_left_stick) + { + if (pressed_sticks[0].second < value) + { + pressed_sticks[0] = { name, value }; + } + } + else if (is_right_stick) + { + if (pressed_sticks[1].second < value) + { + pressed_sticks[1] = { name, value }; + } + } + else + { + u16& pressed_value = pressed_buttons[name]; + pressed_value = std::max(pressed_value, value); + } } } } @@ -399,10 +416,7 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri pad_capabilities capabilities = get_capabilities(pad_id); const u32 battery_level = get_battery_level(pad_id); - if (pressed_button.value > 0) - callback(pressed_button.value, std::move(pressed_button.name), pad_id, battery_level, std::move(preview_values), std::move(capabilities)); - else - callback(0, "", pad_id, battery_level, std::move(preview_values), std::move(capabilities)); + callback(std::move(pressed_buttons), std::move(pressed_sticks), pad_id, battery_level, std::move(preview_values), std::move(capabilities)); } return status; diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index e7b5791f43..14970a4268 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -90,12 +90,12 @@ struct pad_capabilities }; using pad_preview_values = std::array; -using pad_callback = std::function; +using pad_callback = std::function&& /*pressed_buttons*/, std::array, 2>&& /*pressed_sticks*/, std::string /*pad_name*/, u32 /*battery_level*/, pad_preview_values&&, pad_capabilities&&)>; using pad_fail_callback = std::function; using motion_preview_values = std::array; -using motion_callback = std::function; -using motion_fail_callback = std::function; +using motion_callback = std::function; +using motion_fail_callback = std::function; class PadHandlerBase { diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index e920a61d14..5b5e2731ae 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -422,15 +422,15 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s if (call_type != gui_call_type::blacklist && call_type != gui_call_type::reset_input && !has_new_event) { if (callback) - callback(0, "", padId, 0, preview_values, get_capabilities(padId)); + callback({}, {}, padId, 0, std::move(preview_values), get_capabilities(padId)); return connection::no_data; } - struct - { - u16 value = 0; - std::string name; - } pressed_button{}; + // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. + // Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold) + // Get all the legally pressed buttons. We only accept one value for axis though, otherwise it will get messy. + std::map pressed_buttons; + std::array, 2> pressed_sticks{}; const auto set_button_press = [&](const u32 code, const std::string& name, std::string_view type, u16 threshold, int ev_type, bool is_rev_axis) { @@ -497,9 +497,20 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s const u16 diff = value > min_value ? value - min_value : 0; - if (diff > button_press_threshold && value > pressed_button.value) + if (diff > button_press_threshold) { - pressed_button = { .value = value, .name = name }; + if (ev_type == EV_ABS) + { + if (pressed_sticks[0].second < value) + { + pressed_sticks[0] = {name, value}; + } + } + else + { + u16& pressed_value = pressed_buttons[name]; + pressed_value = std::max(pressed_value, value); + } } }; @@ -546,10 +557,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s { pad_capabilities capabilities = get_capabilities(padId); - if (pressed_button.value > 0) - callback(pressed_button.value, pressed_button.name, padId, 0, std::move(preview_values), std::move(capabilities)); - else - callback(0, "", padId, 0, std::move(preview_values), std::move(capabilities)); + callback(std::move(pressed_buttons), std::move(pressed_sticks), padId, 0, std::move(preview_values), std::move(capabilities)); } return connection::connected; diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 84afc37a67..5305b8606a 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -17,6 +17,7 @@ #include "Emu/System.h" #include "Emu/system_utils.hpp" #include "Utilities/File.h" +#include "Utilities/Timer.h" #include "Input/pad_thread.h" #include "Input/gui_pad_thread.h" @@ -551,16 +552,95 @@ void pad_settings_dialog::InitButtons() // Enable Button Remapping update_preview(data.pad_name, true, data.battery_level, data.preview_values[0], data.preview_values[1], data.preview_values[2], data.preview_values[3], data.preview_values[4], data.preview_values[5], data.capabilities); + static Timer s_first_input_timer = {}; + static std::map s_pressed_buttons; + static std::array, 2> s_pressed_sticks = {}; + static u32 s_button_id = button_ids::id_pad_begin; + + const u32 button_id = m_button_id; + + if (s_button_id != button_id) + { + s_button_id = button_id; + s_pressed_buttons.clear(); + s_pressed_sticks = {}; + s_first_input_timer.Stop(); + } + // Handle Button Presses for (const input_callback_data::input_values& values : data.values) { - if (values.val <= 0) continue; - - cfg_log.notice("get_next_button_press: %s device %s button %s pressed with value %d", m_handler->m_type, data.pad_name, values.button_name, values.val); - - if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end && m_button_id == values.button_id) + for (const auto& [key, value] : values.buttons) { - m_cfg_entries[m_button_id].insert_key(values.button_name, m_binding_mode); + if (value == 0) continue; + + cfg_log.notice("get_next_button_press: %s device %s button %s pressed with value %d", m_handler->m_type, data.pad_name, key, value); + + if (button_id > button_ids::id_pad_begin && button_id < button_ids::id_pad_end && button_id == values.button_id) + { + if (s_pressed_buttons.empty()) + { + s_first_input_timer.Start(); + } + + u16& val = s_pressed_buttons[key]; + val = std::max(val, value); + } + } + + for (usz i = 0; i < values.sticks.size(); i++) + { + const auto& [key, value] = values.sticks[i]; + + if (value == 0) continue; + + cfg_log.notice("get_next_button_press: %s device %s button %s pressed with value %d", m_handler->m_type, data.pad_name, key, value); + + if (button_id > button_ids::id_pad_begin && button_id < button_ids::id_pad_end && button_id == values.button_id) + { + if (s_pressed_sticks[i].second == 0) + { + s_first_input_timer.Start(); + } + + if (value > s_pressed_sticks[i].second) + { + s_pressed_sticks[i] = {key, value}; + } + } + } + } + + if (button_id > button_ids::id_pad_begin && button_id < button_ids::id_pad_end && (!s_pressed_buttons.empty() || s_pressed_sticks[0].second || s_pressed_sticks[1].second)) + { + const double elapsed_ms = s_first_input_timer.GetElapsedTimeInMilliSec(); + if (elapsed_ms > 100.0) + { + binding_mode mode = m_binding_mode; + + for (const auto& [key, value] : s_pressed_buttons) + { + if (value == 0) continue; + + m_cfg_entries[m_button_id].insert_key(key, mode); + + // Switch to combo mode for all further keys + mode = binding_mode::combo; + } + + for (const auto& [key, value] : s_pressed_sticks) + { + if (value == 0) continue; + + m_cfg_entries[m_button_id].insert_key(key, mode); + + // Switch to combo mode for all further keys + mode = binding_mode::combo; + } + + s_pressed_buttons.clear(); + s_pressed_sticks = {}; + s_first_input_timer.Stop(); ReactivateButtons(); } } @@ -613,7 +693,7 @@ void pad_settings_dialog::InitButtons() const PadHandlerBase::gui_call_type call_type = first_call ? PadHandlerBase::gui_call_type::reset_input : PadHandlerBase::gui_call_type::normal; const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name, - [this, button_id](u16 val, std::string button_name, std::string pad_name, u32 battery_level, pad_preview_values preview_values, pad_capabilities capabilities) + [this, button_id](std::map&& pressed_buttons, std::array, 2>&& pressed_sticks, std::string pad_name, u32 battery_level, pad_preview_values&& preview_values, pad_capabilities&& capabilities) { std::lock_guard lock(m_input_mutex); if (m_input_callback_data.pad_name != pad_name) @@ -626,13 +706,13 @@ void pad_settings_dialog::InitButtons() m_input_callback_data.capabilities = std::move(capabilities); m_input_callback_data.has_new_data = true; m_input_callback_data.status = PadHandlerBase::connection::connected; - if (val > 0) + if (!pressed_buttons.empty() || !pressed_sticks.empty()) { m_input_callback_data.values.push_back(input_callback_data::input_values { - .button_name = std::move(button_name), .button_id = button_id, - .val = val, + .buttons = std::move(pressed_buttons), + .sticks = std::move(pressed_sticks) }); } }, @@ -917,7 +997,7 @@ void pad_settings_dialog::RepaintPreviewLabel(QLabel* label, int deadzone, int a label->setPixmap(pixmap); } -void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) +void pad_settings_dialog::keyPressEvent(QKeyEvent* keyEvent) { if (m_button_id == button_ids::id_pad_begin) { @@ -976,7 +1056,7 @@ void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event) ReactivateButtons(); } -void pad_settings_dialog::wheelEvent(QWheelEvent *event) +void pad_settings_dialog::wheelEvent(QWheelEvent* event) { if (m_button_id == button_ids::id_pad_begin) { diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 02b4cd6e79..5fded0edcd 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -199,9 +199,9 @@ private: struct input_values { - std::string button_name; u32 button_id = button_ids::id_pad_begin; - u16 val = 0; + std::map buttons; + std::array, 2> sticks{}; }; std::vector values; } m_input_callback_data; @@ -273,10 +273,10 @@ protected: void showEvent(QShowEvent* event) override; /** Handle keyboard handler input */ - void keyPressEvent(QKeyEvent *keyEvent) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void wheelEvent(QWheelEvent *event) override; + void keyPressEvent(QKeyEvent* keyEvent) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; bool eventFilter(QObject* object, QEvent* event) override; void closeEvent(QCloseEvent* event) override; };