diff --git a/Utilities/Timer.h b/Utilities/Timer.h index 7d084b2f91..50f6ab7462 100644 --- a/Utilities/Timer.h +++ b/Utilities/Timer.h @@ -12,7 +12,7 @@ private: steady_clock::time_point m_end; public: - Timer() : m_stopped(false) + Timer() : m_stopped(false), m_start(steady_clock::now()) { } diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index d417aeec19..d129ee1800 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -3,6 +3,9 @@ #include "ds4_pad_handler.h" #include "dualsense_pad_handler.h" #include "util/logs.hpp" +#include "Utilities/Timer.h" +#include "Emu/System.h" +#include "pad_thread.h" #include #include @@ -23,6 +26,13 @@ hid_pad_handler::hid_pad_handler(pad_handler type, std::vector template hid_pad_handler::~hid_pad_handler() { + if (m_enumeration_thread) + { + auto& enumeration_thread = *m_enumeration_thread; + enumeration_thread = thread_state::aborting; + enumeration_thread(); + } + for (auto& controller : m_controllers) { if (controller.second && controller.second->hidDevice) @@ -59,21 +69,30 @@ bool hid_pad_handler::Init() } enumerate_devices(); + update_devices(); m_is_init = true; + + m_enumeration_thread = std::make_unique>>(fmt::format("%s Enumerator", m_type), [this]() + { + while (thread_ctrl::state() != thread_state::aborting) + { + if (pad::g_enabled && Emu.IsRunning()) + { + enumerate_devices(); + } + + thread_ctrl::wait_for(2'000'000); + } + }); + return true; } template void hid_pad_handler::ThreadProc() { - const auto now = std::chrono::system_clock::now(); - const auto elapsed = std::chrono::duration_cast(now - m_last_enumeration).count(); - if (elapsed > 2000) - { - m_last_enumeration = now; - enumerate_devices(); - } + update_devices(); PadHandlerBase::ThreadProc(); } @@ -97,6 +116,7 @@ std::vector hid_pad_handler::ListDevices() template void hid_pad_handler::enumerate_devices() { + Timer timer; std::set device_paths; std::map serials; @@ -113,18 +133,29 @@ void hid_pad_handler::enumerate_devices() } hid_free_enumeration(head); } + hid_log.notice("%s enumeration found %d devices (%f ms)", m_type, device_paths.size(), timer.GetElapsedTimeInMilliSec()); - if (m_last_enumerated_devices == device_paths) + std::lock_guard lock(m_enumeration_mutex); + m_new_enumerated_devices = device_paths; + m_enumerated_serials = serials; +} + +template +void hid_pad_handler::update_devices() +{ + std::lock_guard lock(m_enumeration_mutex); + + if (m_last_enumerated_devices == m_new_enumerated_devices) { return; } - m_last_enumerated_devices = device_paths; + m_last_enumerated_devices = m_new_enumerated_devices; // Scrap devices that are not in the new list for (auto& controller : m_controllers) { - if (controller.second && !controller.second->path.empty() && !device_paths.contains(controller.second->path)) + if (controller.second && !controller.second->path.empty() && !m_new_enumerated_devices.contains(controller.second->path)) { hid_close(controller.second->hidDevice); cfg_pad* config = controller.second->config; @@ -136,7 +167,7 @@ void hid_pad_handler::enumerate_devices() bool warn_about_drivers = false; // Find and add new devices - for (const auto& path : device_paths) + for (const auto& path : m_new_enumerated_devices) { // Check if we have at least one virtual controller left if (std::none_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return !c.second || !c.second->hidDevice; })) @@ -149,7 +180,7 @@ void hid_pad_handler::enumerate_devices() hid_device* dev = hid_open_path(path.c_str()); if (dev) { - check_add_device(dev, path, serials[path]); + check_add_device(dev, path, m_enumerated_serials[path]); } else { diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index 2ef0f9613e..9c8b13d1e6 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -2,6 +2,7 @@ #include "Emu/Io/PadHandler.h" #include "Utilities/CRC.h" +#include "Utilities/Thread.h" #include "hidapi.h" @@ -77,10 +78,14 @@ protected: std::map> m_controllers; bool m_is_init = false; - std::chrono::system_clock::time_point m_last_enumeration; std::set m_last_enumerated_devices; + std::set m_new_enumerated_devices; + std::map m_enumerated_serials; + std::mutex m_enumeration_mutex; + std::unique_ptr>> m_enumeration_thread; void enumerate_devices(); + void update_devices(); std::shared_ptr get_hid_device(const std::string& padId); virtual void check_add_device(hid_device* hidDevice, std::string_view path, std::wstring_view serial) = 0;