From cb122819ae683db0c523d0e646c55914eaf26f78 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Fri, 9 Aug 2024 20:39:56 +0200 Subject: [PATCH] evdev: try to fix first call behaviour We don't have all the events in the first call to get_next_button_press. So we have to set all the buttons to max on the first call. We also have to make sure that we don't manipulate the values if we just want to know the connection status. --- rpcs3/Emu/Io/PadHandler.cpp | 20 +++---- rpcs3/Emu/Io/PadHandler.h | 10 +++- rpcs3/Input/evdev_joystick_handler.cpp | 80 +++++++++++++++++--------- rpcs3/Input/evdev_joystick_handler.h | 2 +- rpcs3/Input/keyboard_pad_handler.h | 2 +- rpcs3/Input/mm_joystick_handler.cpp | 23 +++++--- rpcs3/Input/mm_joystick_handler.h | 2 +- rpcs3/Input/sdl_pad_handler.cpp | 4 +- rpcs3/Input/sdl_pad_handler.h | 2 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 7 ++- 10 files changed, 95 insertions(+), 57 deletions(-) diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 6739bac2b6..ce1bf81abe 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -220,12 +220,12 @@ cfg_pad* PadHandlerBase::get_config(const std::string& pad_id) return nullptr; } -PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::string& pad_id, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& /*buttons*/) +PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::string& pad_id, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& /*buttons*/) { - if (get_blacklist) + if (call_type == gui_call_type::blacklist) blacklist.clear(); - if (first_call || get_blacklist) + if (call_type == gui_call_type::reset_input || call_type == gui_call_type::blacklist) min_button_values.clear(); auto device = get_device(pad_id); @@ -238,7 +238,7 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri return status; } - if (status == connection::no_data) + if (status == connection::no_data || call_type == gui_call_type::get_connection) { return status; } @@ -257,13 +257,13 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri for (const auto& [keycode, name] : button_list) { - if (!get_blacklist && blacklist.contains(keycode)) + if (call_type != gui_call_type::blacklist && blacklist.contains(keycode)) continue; const u16 value = data[keycode]; u16& min_value = min_button_values[keycode]; - if (first_call || value < min_value) + if (call_type == gui_call_type::reset_input || value < min_value) { min_value = value; continue; @@ -279,14 +279,14 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri (is_button && (value > button_press_threshold)) || (is_touch_motion && (value > touch_threshold))) { - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { blacklist.insert(keycode); input_log.error("%s Calibration: Added key [ %d = %s ] to blacklist. Value = %d", m_type, keycode, name, value); continue; } - const u16 diff = std::abs(min_value - value); + const u16 diff = value > min_value ? value - min_value : 0; if (diff > button_press_threshold && value > pressed_button.value) { @@ -295,12 +295,12 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri } } - if (first_call) + if (call_type == gui_call_type::reset_input) { return connection::no_data; } - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { if (blacklist.empty()) input_log.success("%s Calibration: Blacklist is clear. No input spam detected", m_type); diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 44089d601c..b5ac7c6186 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -256,6 +256,14 @@ public: pad_handler m_type; bool m_is_init = false; + enum class gui_call_type + { + normal, + get_connection, + reset_input, + blacklist + }; + std::vector& bindings() { return m_bindings; } std::string name_string() const { return m_name_string; } usz max_devices() const { return m_max_devices; } @@ -287,7 +295,7 @@ public: // Binds a Pad to a device virtual bool bindPadToDevice(std::shared_ptr pad); virtual void init_config(cfg_pad* cfg) = 0; - virtual connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons); + virtual connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons); virtual void get_motion_sensors(const std::string& pad_id, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array& sensors); virtual std::unordered_map get_motion_axis_list() const { return {}; } diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index a1c651da70..89cf32517b 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -239,10 +239,8 @@ std::unordered_map> evdev_joystick_handler::GetButtonV if (!Init()) return button_values; - for (const auto& entry : button_list) + for (const auto& [code, name] : button_list) { - const u32 code = entry.first; - if (code == NO_BUTTON) continue; @@ -254,9 +252,8 @@ std::unordered_map> evdev_joystick_handler::GetButtonV button_values.emplace(code, std::make_pair(static_cast(val > 0 ? 255 : 0), false)); } - for (const auto& entry : axis_list) + for (const auto& [code, name] : axis_list) { - const u32 code = entry.first; int val = 0; if (libevdev_fetch_event_value(dev, EV_ABS, code, &val) == 0) @@ -298,12 +295,12 @@ std::shared_ptr evdev_joystick_handler::get return evdev_device; } -PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) +PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) { - if (get_blacklist) + if (call_type == gui_call_type::blacklist) m_blacklist.clear(); - if (first_call || get_blacklist) + if (call_type == gui_call_type::reset_input || call_type == gui_call_type::blacklist) m_min_button_values.clear(); // Get our evdev device @@ -336,7 +333,12 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s has_new_event |= ret == LIBEVDEV_READ_STATUS_SUCCESS; } - auto data = GetButtonValues(device); + if (call_type == gui_call_type::get_connection) + { + return has_new_event ? connection::connected : connection::no_data; + } + + const auto data = GetButtonValues(device); const auto find_value = [&, this](const std::string& str) { @@ -382,8 +384,8 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s preview_values[5] = find_value(buttons[9]) - find_value(buttons[8]); // Right Stick Y } - // return if nothing new has happened. ignore this to get the current state for blacklist or first_call - if (!get_blacklist && !first_call && !has_new_event) + // return if nothing new has happened. ignore this to get the current state for blacklist or reset_input + 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); @@ -396,15 +398,43 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s std::string name; } pressed_button{}; - const auto set_button_press = [&](const u32 code, const std::string& name, std::string_view type, u16 threshold, int ev_type) + 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) { - if (!get_blacklist && m_blacklist.contains(name)) + if (call_type != gui_call_type::blacklist && m_blacklist.contains(name)) + return; + + // Ignore codes that aren't part of the latest events. Otherwise we will get value 0 which will reset our min_value. + const auto it = data.find(static_cast(code)); + if (it == data.cend()) + { + if (call_type == gui_call_type::reset_input) + { + // Set to max. We won't have all the events for all the buttons or axis at this point. + m_min_button_values[name] = 65535; + + if (ev_type == EV_ABS) + { + // Also set the other direction to max if it wasn't already found. + const auto it_other_axis = is_rev_axis ? axis_list.find(code) : rev_axis_list.find(code); + ensure(it_other_axis != (is_rev_axis ? axis_list.cend() : rev_axis_list.cend())); + if (const std::string& other_name = it_other_axis->second; !m_min_button_values.contains(other_name)) + { + m_min_button_values[other_name] = 65535; + } + } + } + return; + } + + const auto& [value, is_rev_ax] = it->second; + + // If we want the value for an axis, its direction has to match the direction of the data. + if (ev_type == EV_ABS && is_rev_axis != is_rev_ax) return; - const u16 value = data[code].first; u16& min_value = m_min_button_values[name]; - if (first_call || value < min_value) + if (call_type == gui_call_type::reset_input || value < min_value) { min_value = value; return; @@ -413,7 +443,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s if (value <= threshold) return; - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { m_blacklist.insert(name); @@ -431,7 +461,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s return; } - const u16 diff = std::abs(min_value - value); + const u16 diff = value > min_value ? value - min_value : 0; if (diff > button_press_threshold && value > pressed_button.value) { @@ -453,31 +483,25 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s if (is_sony_controller && !is_sony_guitar && (code == BTN_TL2 || code == BTN_TR2)) continue; - set_button_press(code, name, "button"sv, 0, EV_KEY); + set_button_press(code, name, "button"sv, 0, EV_KEY, false); } for (const auto& [code, name] : axis_list) { - if (data[code].second) - continue; - - set_button_press(code, name, "axis"sv, m_thumb_threshold, EV_ABS); + set_button_press(code, name, "axis"sv, m_thumb_threshold, EV_ABS, false); } for (const auto& [code, name] : rev_axis_list) { - if (!data[code].second) - continue; - - set_button_press(code, name, "rev axis"sv, m_thumb_threshold, EV_ABS); + set_button_press(code, name, "rev axis"sv, m_thumb_threshold, EV_ABS, true); } - if (first_call) + if (call_type == gui_call_type::reset_input) { return connection::no_data; } - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { if (m_blacklist.empty()) evdev_log.success("Evdev Calibration: Blacklist is clear. No input spam detected"); diff --git a/rpcs3/Input/evdev_joystick_handler.h b/rpcs3/Input/evdev_joystick_handler.h index 5dd0609360..3ac4fd1df0 100644 --- a/rpcs3/Input/evdev_joystick_handler.h +++ b/rpcs3/Input/evdev_joystick_handler.h @@ -407,7 +407,7 @@ public: bool Init() override; std::vector list_devices() override; bool bindPadToDevice(std::shared_ptr pad) override; - connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) override; + connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) override; void 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) override; std::unordered_map get_motion_axis_list() const override; void 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) override; diff --git a/rpcs3/Input/keyboard_pad_handler.h b/rpcs3/Input/keyboard_pad_handler.h index 98578d6d34..9185c299bb 100644 --- a/rpcs3/Input/keyboard_pad_handler.h +++ b/rpcs3/Input/keyboard_pad_handler.h @@ -84,7 +84,7 @@ public: void init_config(cfg_pad* cfg) override; std::vector list_devices() override; - connection get_next_button_press(const std::string& /*padId*/, const pad_callback& /*callback*/, const pad_fail_callback& /*fail_callback*/, bool /*first_call*/, bool /*get_blacklist*/, const std::vector& /*buttons*/) override { return connection::connected; } + connection get_next_button_press(const std::string& /*padId*/, const pad_callback& /*callback*/, const pad_fail_callback& /*fail_callback*/, gui_call_type /*call_type*/, const std::vector& /*buttons*/) override { return connection::connected; } bool bindPadToDevice(std::shared_ptr pad) override; void process() override; diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index 6f03c8a0f8..1ea805a022 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -230,12 +230,12 @@ std::array, PadHandlerBase::button::button_count> mm_joystick_hand return mapping; } -PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) +PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) { - if (get_blacklist) + if (call_type == gui_call_type::blacklist) m_blacklist.clear(); - if (first_call || get_blacklist) + if (call_type == gui_call_type::reset_input || call_type == gui_call_type::blacklist) m_min_button_values.clear(); if (!Init()) @@ -281,6 +281,11 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: } case JOYERR_NOERROR: { + if (call_type == gui_call_type::get_connection) + { + return connection::connected; + } + auto data = GetButtonValues(js_info, js_caps); // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. @@ -294,13 +299,13 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: const auto set_button_press = [&](const u64& keycode, const std::string& name, std::string_view type, u16 threshold) { - if (!get_blacklist && m_blacklist.contains(keycode)) + if (call_type != gui_call_type::blacklist && m_blacklist.contains(keycode)) return; const u16 value = data[keycode]; u16& min_value = m_min_button_values[keycode]; - if (first_call || value < min_value) + if (call_type == gui_call_type::reset_input || value < min_value) { min_value = value; return; @@ -309,14 +314,14 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: if (value <= threshold) return; - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { m_blacklist.insert(keycode); input_log.error("MMJOY Calibration: Added %s [ %d = %s ] to blacklist. Value = %d", type, keycode, name, value); return; } - const u16 diff = std::abs(min_value - value); + const u16 diff = value > min_value ? value - min_value : 0; if (diff > button_press_threshold && value > pressed_button.value) { @@ -342,12 +347,12 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std: set_button_press(keycode, name, "button"sv, 0); } - if (first_call) + if (call_type == gui_call_type::reset_input) { return connection::no_data; } - if (get_blacklist) + if (call_type == gui_call_type::blacklist) { if (m_blacklist.empty()) input_log.success("MMJOY Calibration: Blacklist is clear. No input spam detected"); diff --git a/rpcs3/Input/mm_joystick_handler.h b/rpcs3/Input/mm_joystick_handler.h index 02cb705d0f..1459e9be82 100644 --- a/rpcs3/Input/mm_joystick_handler.h +++ b/rpcs3/Input/mm_joystick_handler.h @@ -114,7 +114,7 @@ public: bool Init() override; std::vector list_devices() override; - connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) override; + connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) override; void init_config(cfg_pad* cfg) override; private: diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 7c8d5deb81..65d5628c13 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -763,14 +763,14 @@ void sdl_pad_handler::get_motion_sensors(const std::string& pad_id, const motion PadHandlerBase::get_motion_sensors(pad_id, callback, fail_callback, preview_values, sensors); } -PadHandlerBase::connection sdl_pad_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) +PadHandlerBase::connection sdl_pad_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) { if (!m_is_init) return connection::disconnected; SDL_PumpEvents(); - return PadHandlerBase::get_next_button_press(padId, callback, fail_callback, first_call, get_blacklist, buttons); + return PadHandlerBase::get_next_button_press(padId, callback, fail_callback, call_type, buttons); } void sdl_pad_handler::apply_pad_data(const pad_ensemble& binding) diff --git a/rpcs3/Input/sdl_pad_handler.h b/rpcs3/Input/sdl_pad_handler.h index 39a37a1678..1ac8398474 100644 --- a/rpcs3/Input/sdl_pad_handler.h +++ b/rpcs3/Input/sdl_pad_handler.h @@ -128,7 +128,7 @@ public: void 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) override; u32 get_battery_level(const std::string& padId) override; void get_motion_sensors(const std::string& pad_id, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array& sensors) override; - connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool first_call, bool get_blacklist, const std::vector& buttons) override; + connection get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, gui_call_type call_type, const std::vector& buttons) override; private: // pseudo 'controller id' to keep track of unique controllers diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index f4967e7973..3cf67dbbba 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -594,6 +594,7 @@ void pad_settings_dialog::InitButtons() const u32 new_button_id = m_button_id; const bool is_mapping = new_button_id > button_ids::id_pad_begin && new_button_id < button_ids::id_pad_end; const bool first_call = std::exchange(button_id, new_button_id) != button_id && is_mapping; + 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 name, std::string pad_name, u32 battery_level, pad_preview_values preview_values) @@ -616,7 +617,7 @@ void pad_settings_dialog::InitButtons() m_input_callback_data.status = PadHandlerBase::connection::disconnected; m_input_callback_data.button_id = button_id; }, - first_call, false, buttons); + call_type, buttons); if (status == PadHandlerBase::connection::no_data) { @@ -642,7 +643,7 @@ void pad_settings_dialog::RefreshPads() } std::lock_guard lock(m_handler_mutex); - const PadHandlerBase::connection status = m_handler->get_next_button_press(info.name, nullptr, nullptr, false, false, {}); + const PadHandlerBase::connection status = m_handler->get_next_button_press(info.name, nullptr, nullptr, PadHandlerBase::gui_call_type::get_connection, {}); switch_pad_info(i, info, status != PadHandlerBase::connection::disconnected); } } @@ -1327,7 +1328,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) case button_ids::id_blacklist: { std::lock_guard lock(m_handler_mutex); - [[maybe_unused]] const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name, nullptr, nullptr, false, true, {}); + [[maybe_unused]] const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name, nullptr, nullptr, PadHandlerBase::gui_call_type::blacklist, {}); return; } default: