mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-12 06:39:26 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8797def7cf | |||
| d84bb61d86 | |||
| 2a432c0306 | |||
| c4ac07c392 | |||
| 65cd822bed | |||
| 18726a4518 | |||
| ec111683cd |
@@ -73,16 +73,20 @@ Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) {
|
||||
R_TRY(m_manager_display_service->CreateManagedLayer(
|
||||
out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()}));
|
||||
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id);
|
||||
(void)m_display_service->GetContainer()->SetLayerStackMask(*out_layer_id,
|
||||
this->GetLayerStackMask());
|
||||
|
||||
if (m_applet_id != AppletId::Application) {
|
||||
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, *out_layer_id);
|
||||
if (m_applet_id == AppletId::OverlayDisplay) {
|
||||
(void)m_manager_display_service->SetLayerZIndex(-1, *out_layer_id);
|
||||
(void)m_display_service->GetContainer()->SetLayerIsOverlay(*out_layer_id, true);
|
||||
(void)m_manager_display_service->SetLayerZIndex(Overlay, *out_layer_id);
|
||||
} else {
|
||||
(void)m_manager_display_service->SetLayerZIndex(1, *out_layer_id);
|
||||
(void)m_manager_display_service->SetLayerZIndex(Foreground, *out_layer_id);
|
||||
}
|
||||
}
|
||||
(void)m_display_service->GetContainer()->SetLayerZIndex(*out_layer_id, true);
|
||||
|
||||
m_display_service->GetContainer()->SetLayerZIndex(*out_layer_id, true);
|
||||
m_managed_display_layers.emplace(*out_layer_id);
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -122,14 +126,16 @@ Result DisplayLayerManager::IsSystemBufferSharingEnabled() {
|
||||
|
||||
// Ensure the overlay layer is visible
|
||||
m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id);
|
||||
m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
|
||||
s32 initial_z = 1;
|
||||
(void)m_display_service->GetContainer()->SetLayerZIndex(m_system_shared_layer_id, true);
|
||||
(void)m_manager_display_service->SetLayerBlending(m_blending_enabled, m_system_shared_layer_id);
|
||||
s32 initial_z = Foreground;
|
||||
if (m_applet_id == AppletId::OverlayDisplay) {
|
||||
initial_z = -1;
|
||||
initial_z = Overlay;
|
||||
(void)m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
|
||||
(void)m_display_service->GetContainer()->SetLayerIsOverlay(m_system_shared_layer_id, true);
|
||||
}
|
||||
m_manager_display_service->SetLayerZIndex(initial_z, m_system_shared_layer_id);
|
||||
m_display_service->GetContainer()->SetLayerZIndex(m_system_shared_layer_id, true);
|
||||
m_managed_display_layers.emplace(m_system_shared_layer_id);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,8 @@ JoyconDriver::~JoyconDriver() {
|
||||
}
|
||||
|
||||
void JoyconDriver::Stop() {
|
||||
if (input_thread.joinable()) {
|
||||
input_thread.request_stop();
|
||||
input_thread.join();
|
||||
}
|
||||
is_connected = false;
|
||||
input_thread = {};
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
|
||||
@@ -60,6 +58,7 @@ Common::Input::DriverResult JoyconDriver::InitializeDevice() {
|
||||
return Common::Input::DriverResult::InvalidHandle;
|
||||
}
|
||||
std::scoped_lock lock{mutex};
|
||||
disable_input_thread = true;
|
||||
|
||||
// Reset Counters
|
||||
error_counter = 0;
|
||||
@@ -127,44 +126,62 @@ Common::Input::DriverResult JoyconDriver::InitializeDevice() {
|
||||
right_stick_calibration, motion_calibration);
|
||||
|
||||
// Start polling for data
|
||||
if (!input_thread.joinable()) {
|
||||
input_thread = std::jthread([this](std::stop_token stop_token) {
|
||||
InputThread(stop_token);
|
||||
});
|
||||
is_connected = true;
|
||||
if (!input_thread_running) {
|
||||
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<u8> buffer(MaxBufferSize);
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
// Max update rate is 5ms, so just (timeout) at 300ms
|
||||
constexpr int READ_TIMEOUT_MS = 300;
|
||||
constexpr size_t MAX_VIBRATIONS = 4;
|
||||
std::array<u8, MaxBufferSize> buffer; // Filled by SDL, don't zero-init
|
||||
int status = 0;
|
||||
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(), READ_TIMEOUT_MS);
|
||||
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 {
|
||||
|
||||
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);
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay));
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -254,6 +271,11 @@ void JoyconDriver::OnNewData(std::span<u8> 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) {
|
||||
@@ -360,12 +382,17 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
|
||||
}
|
||||
|
||||
bool JoyconDriver::IsInputThreadValid() const {
|
||||
if (hidapi_handle == nullptr || hidapi_handle->handle == nullptr)
|
||||
if (!is_connected.load()) {
|
||||
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 input_thread.joinable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
|
||||
@@ -388,18 +415,30 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> 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};
|
||||
return irs_protocol->SetIrsConfig(mode_, format_);
|
||||
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;
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
|
||||
@@ -493,7 +532,12 @@ Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
|
||||
if (!nfc_protocol->IsEnabled()) {
|
||||
return Common::Input::DriverResult::Disabled;
|
||||
}
|
||||
return nfc_protocol->StartNFCPollingMode();
|
||||
|
||||
disable_input_thread = true;
|
||||
const auto result = nfc_protocol->StartNFCPollingMode();
|
||||
disable_input_thread = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
|
||||
@@ -506,7 +550,10 @@ 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({});
|
||||
@@ -529,7 +576,11 @@ Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_da
|
||||
}
|
||||
|
||||
out_data.resize(0x21C);
|
||||
return nfc_protocol->ReadAmiibo(out_data);
|
||||
disable_input_thread = true;
|
||||
const auto result = nfc_protocol->ReadAmiibo(out_data);
|
||||
disable_input_thread = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
|
||||
@@ -544,7 +595,12 @@ Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data)
|
||||
if (!amiibo_detected) {
|
||||
return Common::Input::DriverResult::ErrorWritingData;
|
||||
}
|
||||
return nfc_protocol->WriteAmiibo(data);
|
||||
|
||||
disable_input_thread = true;
|
||||
const auto result = nfc_protocol->WriteAmiibo(data);
|
||||
disable_input_thread = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
|
||||
@@ -560,7 +616,12 @@ Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareR
|
||||
if (!amiibo_detected) {
|
||||
return Common::Input::DriverResult::ErrorWritingData;
|
||||
}
|
||||
return nfc_protocol->ReadMifare(data, out_data);
|
||||
|
||||
disable_input_thread = true;
|
||||
const auto result = nfc_protocol->ReadMifare(data, out_data);
|
||||
disable_input_thread = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
|
||||
@@ -575,11 +636,17 @@ Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const Mifare
|
||||
if (!amiibo_detected) {
|
||||
return Common::Input::DriverResult::ErrorWritingData;
|
||||
}
|
||||
return nfc_protocol->WriteMifare(data);
|
||||
|
||||
disable_input_thread = true;
|
||||
const auto result = nfc_protocol->WriteMifare(data);
|
||||
disable_input_thread = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool JoyconDriver::IsConnected() const {
|
||||
return input_thread.joinable();
|
||||
std::scoped_lock lock{mutex};
|
||||
return is_connected.load();
|
||||
}
|
||||
|
||||
bool JoyconDriver::IsVibrationEnabled() const {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// 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
|
||||
|
||||
@@ -163,6 +160,8 @@ private:
|
||||
// Thread related
|
||||
mutable std::mutex mutex;
|
||||
std::jthread input_thread;
|
||||
bool input_thread_running{};
|
||||
bool disable_input_thread{};
|
||||
};
|
||||
|
||||
} // namespace InputCommon::Joycon
|
||||
|
||||
@@ -22,7 +22,7 @@ void JoyconPoller::SetCallbacks(const JoyconCallbacks& callbacks_) {
|
||||
void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& motion_status,
|
||||
const RingStatus& ring_status) {
|
||||
InputReportActive data{};
|
||||
std::memcpy(&data, buffer.data(), sizeof(InputReportActive));
|
||||
memcpy(&data, buffer.data(), sizeof(InputReportActive));
|
||||
|
||||
switch (device_type) {
|
||||
case ControllerType::Left:
|
||||
@@ -47,7 +47,7 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti
|
||||
|
||||
void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) {
|
||||
InputReportPassive data{};
|
||||
std::memcpy(&data, buffer.data(), sizeof(InputReportPassive));
|
||||
memcpy(&data, buffer.data(), sizeof(InputReportPassive));
|
||||
|
||||
switch (device_type) {
|
||||
case ControllerType::Left:
|
||||
|
||||
Reference in New Issue
Block a user