From b2328abe939831f457acbb4984fdc939757172a6 Mon Sep 17 00:00:00 2001 From: Maufeat Date: Mon, 10 Nov 2025 13:52:39 +0100 Subject: [PATCH] some improvements :) --- src/core/file_sys/control_metadata.h | 1 + src/core/file_sys/savedata_factory.cpp | 2 + src/core/hle/service/am/am.cpp | 2 +- src/core/hle/service/am/button_poller.cpp | 63 ++++++++++-- src/core/hle/service/am/button_poller.h | 14 +++ .../ns/application_manager_interface.cpp | 16 +++- .../ns/application_manager_interface.h | 3 +- ...nly_application_control_data_interface.cpp | 95 +++++++------------ ..._only_application_control_data_interface.h | 8 +- src/qt_common/config/shared_translation.cpp | 1 + 10 files changed, 121 insertions(+), 84 deletions(-) diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index ccb37bc85b..d4ef346b20 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -5,6 +5,7 @@ #include #include +#include #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index dda8d526d3..6e4fcf1c26 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -98,6 +98,8 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { return "/user/"; case SaveDataSpaceId::Temporary: return "/temp/"; + case SaveDataSpaceId::SdUser: + return "/user/"; default: ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast(space)); return "/unrecognized/"; ///< To prevent corruption when ignoring asserts. diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 2ef393439b..45b97ad83f 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -13,8 +13,8 @@ namespace Service::AM { void LoopProcess(Core::System& system) { WindowSystem window_system(system); - ButtonPoller button_poller(system, window_system); EventObserver event_observer(system, window_system); + ButtonPoller button_poller(system, window_system); auto server_manager = std::make_unique(system); diff --git a/src/core/hle/service/am/button_poller.cpp b/src/core/hle/service/am/button_poller.cpp index bb915f9ea4..75b1f2ca0e 100644 --- a/src/core/hle/service/am/button_poller.cpp +++ b/src/core/hle/service/am/button_poller.cpp @@ -48,14 +48,22 @@ ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system) m_handheld_key = m_handheld->SetCallback(engine_callback); m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); m_player1_key = m_player1->SetCallback(engine_callback); + + m_thread = std::thread([this] { this->ThreadLoop(); }); } ButtonPoller::~ButtonPoller() { m_handheld->DeleteCallback(m_handheld_key); m_player1->DeleteCallback(m_player1_key); + m_stop = true; + m_cv.notify_all(); + if (m_thread.joinable()) { + m_thread.join(); + } } void ButtonPoller::OnButtonStateChanged() { + std::lock_guard lk{m_mutex}; const bool home_button = m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value(); const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() || @@ -64,28 +72,53 @@ void ButtonPoller::OnButtonStateChanged() { // Buttons pressed which were not previously pressed if (home_button && !m_home_button_press_start) { m_home_button_press_start = std::chrono::steady_clock::now(); + m_home_button_long_sent = false; } if (capture_button && !m_capture_button_press_start) { m_capture_button_press_start = std::chrono::steady_clock::now(); + m_capture_button_long_sent = false; } // if (power_button && !m_power_button_press_start) { // m_power_button_press_start = std::chrono::steady_clock::now(); // } - // Buttons released which were previously held - if (!home_button && m_home_button_press_start) { + // While buttons are held, check whether they have crossed the long-press + // threshold and, if so, send the long-press action immediately (only once). + if (home_button && m_home_button_press_start && !m_home_button_long_sent) { const auto duration = ClassifyPressDuration(*m_home_button_press_start); - m_window_system.OnSystemButtonPress( - duration == ButtonPressDuration::ShortPressing ? SystemButtonType::HomeButtonShortPressing - : SystemButtonType::HomeButtonLongPressing); + if (duration != ButtonPressDuration::ShortPressing) { + m_window_system.OnSystemButtonPress(SystemButtonType::HomeButtonLongPressing); + m_home_button_long_sent = true; + } + } + + if (capture_button && m_capture_button_press_start && !m_capture_button_long_sent) { + const auto duration = ClassifyPressDuration(*m_capture_button_press_start); + if (duration != ButtonPressDuration::ShortPressing) { + m_window_system.OnSystemButtonPress(SystemButtonType::CaptureButtonLongPressing); + m_capture_button_long_sent = true; + } + } + + // Buttons released which were previously held + if (!home_button && m_home_button_press_start) { (!m_home_button_long_sent) { + const auto duration = ClassifyPressDuration(*m_home_button_press_start); + m_window_system.OnSystemButtonPress( + duration == ButtonPressDuration::ShortPressing ? SystemButtonType::HomeButtonShortPressing + : SystemButtonType::HomeButtonLongPressing); + } m_home_button_press_start = std::nullopt; + m_home_button_long_sent = false; } if (!capture_button && m_capture_button_press_start) { - const auto duration = ClassifyPressDuration(*m_capture_button_press_start); - m_window_system.OnSystemButtonPress( - duration == ButtonPressDuration::ShortPressing ? SystemButtonType::CaptureButtonShortPressing - : SystemButtonType::CaptureButtonLongPressing); + if (!m_capture_button_long_sent) { + const auto duration = ClassifyPressDuration(*m_capture_button_press_start); + m_window_system.OnSystemButtonPress( + duration == ButtonPressDuration::ShortPressing ? SystemButtonType::CaptureButtonShortPressing + : SystemButtonType::CaptureButtonLongPressing); + } m_capture_button_press_start = std::nullopt; + m_capture_button_long_sent = false; } // if (!power_button && m_power_button_press_start) { // // TODO @@ -93,4 +126,16 @@ void ButtonPoller::OnButtonStateChanged() { // } } +void ButtonPoller::ThreadLoop() { + using namespace std::chrono_literals; + std::unique_lock lk{m_mutex}; + while (!m_stop) { + m_cv.wait_for(lk, 50ms); + if (m_stop) break; + lk.unlock(); + OnButtonStateChanged(); + lk.lock(); + } +} + } // namespace Service::AM diff --git a/src/core/hle/service/am/button_poller.h b/src/core/hle/service/am/button_poller.h index b1c39aad30..21d61bb0c1 100644 --- a/src/core/hle/service/am/button_poller.h +++ b/src/core/hle/service/am/button_poller.h @@ -3,8 +3,12 @@ #pragma once +#include #include +#include +#include #include +#include #include "hid_core/frontend/emulated_controller.h" namespace Core { @@ -26,6 +30,7 @@ public: private: void OnButtonStateChanged(); + void ThreadLoop(); private: WindowSystem& m_window_system; @@ -38,6 +43,15 @@ private: std::optional m_home_button_press_start{}; std::optional m_capture_button_press_start{}; std::optional m_power_button_press_start{}; + + bool m_home_button_long_sent{}; + bool m_capture_button_long_sent{}; + bool m_power_button_long_sent{}; + + std::thread m_thread; + std::atomic m_stop{false}; + std::condition_variable m_cv; + std::mutex m_mutex; }; } // namespace Service::AM diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp index 98d56667c0..c072b7e75d 100644 --- a/src/core/hle/service/ns/application_manager_interface.cpp +++ b/src/core/hle/service/ns/application_manager_interface.cpp @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/file_sys/control_metadata.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/cmif_serialization.h" @@ -11,6 +12,7 @@ #include "core/hle/service/ns/application_manager_interface.h" #include "core/hle/service/ns/content_management_interface.h" #include "core/hle/service/ns/read_only_application_control_data_interface.h" +#include "core/file_sys/patch_manager.h" namespace Service::NS { @@ -19,7 +21,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_ service_context{system, "IApplicationManagerInterface"}, record_update_system_event{service_context}, sd_card_mount_status_event{service_context}, gamecard_update_detection_event{service_context}, - gamecard_mount_status_event{service_context}, gamecard_mount_failure_event{service_context}, gamecard_waken_ready_event{service_context} { + gamecard_mount_status_event{service_context}, gamecard_mount_failure_event{service_context}, gamecard_waken_ready_event{service_context}, unknown_event{service_context} { // clang-format off static const FunctionInfo functions[] = { {0, D<&IApplicationManagerInterface::ListApplicationRecord>, "ListApplicationRecord"}, @@ -331,7 +333,7 @@ Result IApplicationManagerInterface::GetApplicationControlData( OutBuffer out_buffer, Out out_actual_size, ApplicationControlSource application_control_source, u64 application_id) { LOG_DEBUG(Service_NS, "called"); - R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlDataOld( + R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlData( out_buffer, out_actual_size, application_control_source, application_id)); } @@ -563,15 +565,19 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out o } Result IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground( - u64 unk, u64 application_id) { - LOG_WARNING(Service_NS, "(STUBBED), app={:016X} unk={}", application_id, unk); + u64 control_source, u64 application_id) { + LOG_INFO(Service_NS, "called, control_source={} app={:016X}", + control_source, application_id); + + unknown_event.Signal(); R_SUCCEED(); } Result IApplicationManagerInterface::Unknown4022( OutCopyHandle out_event) { LOG_WARNING(Service_NS, "(STUBBED) called"); - *out_event = gamecard_update_detection_event.GetHandle(); + unknown_event.Signal(); + *out_event = unknown_event.GetHandle(); R_SUCCEED(); } diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h index 205a9ec7a7..befdf2eac5 100644 --- a/src/core/hle/service/ns/application_manager_interface.h +++ b/src/core/hle/service/ns/application_manager_interface.h @@ -62,7 +62,7 @@ public: Result Unknown4023(Out out_result); Result Unknown4053(); - Result RequestDownloadApplicationControlDataInBackground(u64 unk, + Result RequestDownloadApplicationControlDataInBackground(u64 control_source, u64 application_id); private: @@ -73,6 +73,7 @@ private: Event gamecard_mount_status_event; Event gamecard_mount_failure_event; Event gamecard_waken_ready_event; + Event unknown_event; }; } // namespace Service::NS diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.cpp b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp index 42d8fc3338..93531e76c8 100644 --- a/src/core/hle/service/ns/read_only_application_control_data_interface.cpp +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp @@ -22,12 +22,12 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { // clang-format off static const FunctionInfo functions[] = { - {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataOld>, "GetApplicationControlDataOld"}, + {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"}, {1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"}, {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"}, {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, {4, nullptr, "SelectApplicationDesiredLanguage"}, - {5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize>, "GetApplicationControlDataWithIconSize"}, + {5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithoutIcon>, "GetApplicationControlDataWithoutIcon"}, }; // clang-format on @@ -36,7 +36,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; -Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataOld( +Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( OutBuffer out_buffer, Out out_actual_size, ApplicationControlSource application_control_source, u64 application_id) { LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}", @@ -124,8 +124,8 @@ Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLan R_SUCCEED(); } -Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( - OutBuffer out_buffer, Out out_actual_size, +Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithoutIcon( + OutBuffer out_buffer, Out out_total_size, ApplicationControlSource application_control_source, u64 application_id) { LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}", application_control_source, application_id); @@ -135,76 +135,47 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( const auto control = pm.GetControlMetadata(); const auto size = out_buffer.size(); - const auto icon_size = control.second ? control.second->GetSize() : 0; - const auto total_size = sizeof(FileSys::RawNACP) + icon_size; + // Use the caller-provided buffer capacity as the total size to return. This + // matches behavior where the caller expects a fixed-size package (NACP + icon + // area) and the icon area may be zero-padded up to the buffer size. + const auto nacp_size = sizeof(FileSys::RawNACP); - if (size < total_size) { - LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", - size); + if (size < nacp_size) { + LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min={:08X})", + size, nacp_size); R_THROW(ResultUnknown); } if (control.first != nullptr) { const auto bytes = control.first->GetRawBytes(); - std::memcpy(out_buffer.data(), bytes.data(), bytes.size()); + const auto copy_len = (std::min)(static_cast(bytes.size()), static_cast(nacp_size)); + std::memcpy(out_buffer.data(), bytes.data(), copy_len); + if (copy_len < nacp_size) { + std::memset(out_buffer.data() + copy_len, 0, nacp_size - copy_len); + } } else { LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero", application_id); - std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP)); - } - - if (control.second != nullptr) { - control.second->Read(out_buffer.data() + sizeof(FileSys::RawNACP), icon_size); - } else { - LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id); - } - - *out_actual_size = static_cast(total_size); - R_SUCCEED(); -} - -Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize( - OutBuffer out_buffer, - Out out_total_size, - ApplicationControlSource application_control_source, - u64 application_id) { - LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}", - application_control_source, application_id); - - constexpr size_t kExpectedBufferSize = 0x14000; - constexpr size_t kNACPSize = sizeof(FileSys::RawNACP); - constexpr size_t kMaxIconSize = kExpectedBufferSize - kNACPSize; - - const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), - system.GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto size = out_buffer.size(); - - if (size < kExpectedBufferSize) { - LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, required={:016X})", size, kExpectedBufferSize); - R_THROW(ResultUnknown); - } - - // Copy NACP - if (control.first != nullptr) { - const auto bytes = control.first->GetRawBytes(); - std::memcpy(out_buffer.data(), bytes.data(), bytes.size()); - } else { - std::memset(out_buffer.data(), 0, kNACPSize); + std::memset(out_buffer.data(), 0, nacp_size); } - // Copy icon, pad with zeros if needed - size_t icon_size = control.second ? control.second->GetSize() : 0; - if (icon_size > kMaxIconSize) { - icon_size = kMaxIconSize; // Truncate if too large - } - if (control.second != nullptr && icon_size > 0) { - control.second->Read(out_buffer.data() + kNACPSize, icon_size); - } else { - std::memset(out_buffer.data() + kNACPSize, 0, kMaxIconSize); + const auto icon_area_size = size - nacp_size; + if (icon_area_size > 0) { + if (control.second != nullptr) { + const auto icon_size = control.second->GetSize(); + const auto to_copy = static_cast((std::min)(icon_size, icon_area_size)); + control.second->Read(out_buffer.data() + nacp_size, to_copy); + if (to_copy < icon_area_size) { + std::memset(out_buffer.data() + nacp_size + to_copy, 0, icon_area_size - to_copy); + } + } else { + std::memset(out_buffer.data() + nacp_size, 0, icon_area_size); + LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}, zero-filling icon area", + application_id); + } } - *out_total_size = kExpectedBufferSize; + *out_total_size = static_cast(size); R_SUCCEED(); } diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.h b/src/core/hle/service/ns/read_only_application_control_data_interface.h index 365e1f7ee3..99366c5792 100644 --- a/src/core/hle/service/ns/read_only_application_control_data_interface.h +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.h @@ -19,7 +19,7 @@ public: explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); ~IReadOnlyApplicationControlDataInterface() override; - Result GetApplicationControlDataOld(OutBuffer out_buffer, + Result GetApplicationControlData(OutBuffer out_buffer, Out out_actual_size, ApplicationControlSource application_control_source, u64 application_id); @@ -27,11 +27,7 @@ public: u32 supported_languages); Result ConvertApplicationLanguageToLanguageCode(Out out_language_code, ApplicationLanguage application_language); - Result GetApplicationControlData(OutBuffer out_buffer, - Out out_actual_size, - ApplicationControlSource application_control_source, - u64 application_id); - Result GetApplicationControlDataWithIconSize( + Result GetApplicationControlDataWithoutIcon( OutBuffer out_buffer, Out out_total_size, ApplicationControlSource application_control_source, diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index b54211142c..e2a85a74f9 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -47,6 +47,7 @@ std::unique_ptr InitializeTranslations(QObject* parent) INSERT(Settings, login_share_applet_mode, tr("Login share"), QString()); INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QString()); INSERT(Settings, my_page_applet_mode, tr("My page"), QString()); + INSERT(Settings, enable_overlay, tr("Enable Overlay Applet"), QString()); // Audio INSERT(Settings, sink_id, tr("Output Engine:"), QString());