From b67698c62222a1a98eaab5fb16f026181c692bbe Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 12 Sep 2026 01:06:59 +0000 Subject: [PATCH] 2026-09-12 01:06:59 Signed-off-by: lizzie --- src/input_common/helpers/joycon_driver.cpp | 143 +++++------------- src/input_common/helpers/joycon_driver.h | 5 +- .../helpers/joycon_protocol/poller.cpp | 4 +- 3 files changed, 43 insertions(+), 109 deletions(-) diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 78df802b73..170b8901a0 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -28,8 +28,10 @@ JoyconDriver::~JoyconDriver() { } void JoyconDriver::Stop() { - is_connected = false; - input_thread = {}; + if (input_thread.joinable()) { + input_thread.request_stop(); + input_thread.join(); + } } Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { @@ -58,7 +60,6 @@ Common::Input::DriverResult JoyconDriver::InitializeDevice() { return Common::Input::DriverResult::InvalidHandle; } std::scoped_lock lock{mutex}; - disable_input_thread = true; // Reset Counters error_counter = 0; @@ -126,62 +127,44 @@ Common::Input::DriverResult JoyconDriver::InitializeDevice() { right_stick_calibration, motion_calibration); // Start polling for data - is_connected = true; - if (!input_thread_running) { - input_thread = - std::jthread([this](std::stop_token stop_token) { InputThread(stop_token); }); + if (!input_thread.joinable()) { + input_thread = std::jthread([this](std::stop_token stop_token) { + InputThread(stop_token); + }); } - - disable_input_thread = false; return Common::Input::DriverResult::Success; } void JoyconDriver::InputThread(std::stop_token stop_token) { LOG_INFO(Input, "Joycon Adapter input thread started"); Common::SetCurrentThreadName("JoyconInput"); - input_thread_running = true; // Max update rate is 5ms, ensure we are always able to read a bit faster - constexpr int ThreadDelay = 3; - std::vector buffer(MaxBufferSize); - while (!stop_token.stop_requested()) { + constexpr int THREAD_SLEEP_DELAY = 3; + constexpr size_t MAX_VIBRATIONS = 4; + std::array buffer; // Filled by SDL, don't zero-init int status = 0; - - if (!IsInputThreadValid()) { - input_thread.request_stop(); - continue; - } - - // By disabling the input thread we can ensure custom commands will succeed as no package is - // skipped - if (!disable_input_thread) { - status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), - ThreadDelay); + if (IsInputThreadValid()) { + // By disabling the input thread we can ensure custom commands will succeed as no package is + // skipped + status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), THREAD_SLEEP_DELAY); + if (IsPayloadCorrect(status, buffer)) { + OnNewData(buffer); + } + if (!vibration_queue.Empty()) { + VibrationValue vibration_value; + vibration_queue.Pop(vibration_value); + last_vibration_result = rumble_protocol->SendVibration(vibration_value); + } + // We can't keep up with vibrations. Start skipping. + while (vibration_queue.Size() >= MAX_VIBRATIONS) { + vibration_queue.Pop(); + } } else { - std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay)); + input_thread.request_stop(); } - - if (IsPayloadCorrect(status, buffer)) { - OnNewData(buffer); - } - - if (!vibration_queue.Empty()) { - VibrationValue vibration_value; - vibration_queue.Pop(vibration_value); - last_vibration_result = rumble_protocol->SendVibration(vibration_value); - } - - // We can't keep up with vibrations. Start skipping. - while (vibration_queue.Size() > 6) { - vibration_queue.Pop(); - } - - std::this_thread::yield(); } - - is_connected = false; - input_thread_running = false; LOG_INFO(Input, "Joycon Adapter input thread stopped"); } @@ -271,11 +254,6 @@ void JoyconDriver::OnNewData(std::span buffer) { } Common::Input::DriverResult JoyconDriver::SetPollingMode() { - SCOPE_EXIT { - disable_input_thread = false; - }; - disable_input_thread = true; - rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); if (motion_enabled && supported_features.motion) { @@ -382,17 +360,12 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { } bool JoyconDriver::IsInputThreadValid() const { - if (!is_connected.load()) { + if (hidapi_handle == nullptr || hidapi_handle->handle == nullptr) return false; - } - if (hidapi_handle->handle == nullptr) { - return false; - } // Controller is not responding. Terminate connection - if (error_counter > MaxErrorCount) { + if (error_counter > MaxErrorCount) return false; - } - return true; + return input_thread.joinable(); } bool JoyconDriver::IsPayloadCorrect(int status, std::span buffer) { @@ -415,30 +388,18 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span buffer) { Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { std::scoped_lock lock{mutex}; - if (disable_input_thread) { - return Common::Input::DriverResult::HandleInUse; - } vibration_queue.Push(vibration); return last_vibration_result; } Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { std::scoped_lock lock{mutex}; - if (disable_input_thread) { - return Common::Input::DriverResult::HandleInUse; - } return generic_protocol->SetLedPattern(led_pattern); } Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { std::scoped_lock lock{mutex}; - if (disable_input_thread) { - return Common::Input::DriverResult::HandleInUse; - } - disable_input_thread = true; - const auto result = irs_protocol->SetIrsConfig(mode_, format_); - disable_input_thread = false; - return result; + return irs_protocol->SetIrsConfig(mode_, format_); } Common::Input::DriverResult JoyconDriver::SetPassiveMode() { @@ -532,12 +493,7 @@ Common::Input::DriverResult JoyconDriver::StartNfcPolling() { if (!nfc_protocol->IsEnabled()) { return Common::Input::DriverResult::Disabled; } - - disable_input_thread = true; - const auto result = nfc_protocol->StartNFCPollingMode(); - disable_input_thread = false; - - return result; + return nfc_protocol->StartNFCPollingMode(); } Common::Input::DriverResult JoyconDriver::StopNfcPolling() { @@ -550,10 +506,7 @@ Common::Input::DriverResult JoyconDriver::StopNfcPolling() { return Common::Input::DriverResult::Disabled; } - disable_input_thread = true; const auto result = nfc_protocol->StopNFCPollingMode(); - disable_input_thread = false; - if (amiibo_detected) { amiibo_detected = false; joycon_poller->UpdateAmiibo({}); @@ -576,11 +529,7 @@ Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector& out_da } out_data.resize(0x21C); - disable_input_thread = true; - const auto result = nfc_protocol->ReadAmiibo(out_data); - disable_input_thread = false; - - return result; + return nfc_protocol->ReadAmiibo(out_data); } Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span data) { @@ -595,12 +544,7 @@ Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span data) if (!amiibo_detected) { return Common::Input::DriverResult::ErrorWritingData; } - - disable_input_thread = true; - const auto result = nfc_protocol->WriteAmiibo(data); - disable_input_thread = false; - - return result; + return nfc_protocol->WriteAmiibo(data); } Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span data, @@ -616,12 +560,7 @@ Common::Input::DriverResult JoyconDriver::ReadMifareData(std::spanReadMifare(data, out_data); - disable_input_thread = false; - - return result; + return nfc_protocol->ReadMifare(data, out_data); } Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span data) { @@ -636,17 +575,11 @@ Common::Input::DriverResult JoyconDriver::WriteMifareData(std::spanWriteMifare(data); - disable_input_thread = false; - - return result; + return nfc_protocol->WriteMifare(data); } bool JoyconDriver::IsConnected() const { - std::scoped_lock lock{mutex}; - return is_connected.load(); + return input_thread.joinable(); } bool JoyconDriver::IsVibrationEnabled() const { diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index 5355780fbb..90f99ed318 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -160,8 +163,6 @@ private: // Thread related mutable std::mutex mutex; std::jthread input_thread; - bool input_thread_running{}; - bool disable_input_thread{}; }; } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index 2384981f50..a2a031cafd 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp @@ -22,7 +22,7 @@ void JoyconPoller::SetCallbacks(const JoyconCallbacks& callbacks_) { void JoyconPoller::ReadActiveMode(std::span buffer, const MotionStatus& motion_status, const RingStatus& ring_status) { InputReportActive data{}; - memcpy(&data, buffer.data(), sizeof(InputReportActive)); + std::memcpy(&data, buffer.data(), sizeof(InputReportActive)); switch (device_type) { case ControllerType::Left: @@ -47,7 +47,7 @@ void JoyconPoller::ReadActiveMode(std::span buffer, const MotionStatus& moti void JoyconPoller::ReadPassiveMode(std::span buffer) { InputReportPassive data{}; - memcpy(&data, buffer.data(), sizeof(InputReportPassive)); + std::memcpy(&data, buffer.data(), sizeof(InputReportPassive)); switch (device_type) { case ControllerType::Left: