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: