diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index c8985cd45d..dccebe2594 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -66,6 +66,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { LOGIN_SHARE_APPLET("login_share_applet_mode"), WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"), MY_PAGE_APPLET("my_page_applet_mode"), + SPLAY_APPLET("splay_applet_mode"), INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide"), OVERLAY_GRID_SIZE("overlay_grid_size"), DEBUG_KNOBS("debug_knobs"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Applet.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Applet.kt index 2845c71ec0..b021133002 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Applet.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Applet.kt @@ -38,7 +38,8 @@ enum class AppletInfo(val appletId: Int, val entryId: Long = 0) { OfflineWeb(0x17), LoginShare(0x18), WebAuth(0x19), - MyPage(0x1A) + MyPage(0x1A), + Splay(0x64) } // Matches enum in Service::NFP::CabinetMode with extra metadata diff --git a/src/common/settings.h b/src/common/settings.h index a03c6e1a2c..f17d0cd5bd 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -168,6 +168,7 @@ struct Values { linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet}; Setting my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode", Category::LibraryApplet}; + Setting splay_applet_mode{linkage, AppletMode::LLE, "splay_applet_mode", Category::LibraryApplet}; // Audio SwitchableSetting sink_id{linkage, AudioEngine::Auto, "output_engine", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8bcb66ac35..f7ec208c1c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -829,6 +829,8 @@ add_library(core STATIC hle/service/ns/ns_types.h hle/service/ns/platform_service_manager.cpp hle/service/ns/platform_service_manager.h + hle/service/ns/notify_service.cpp + hle/service/ns/notify_service.h hle/service/ns/query_service.cpp hle/service/ns/query_service.h hle/service/ns/read_only_application_control_data_interface.cpp diff --git a/src/core/hle/service/am/am_types.h b/src/core/hle/service/am/am_types.h index beb52b74dd..29e2f5b450 100644 --- a/src/core/hle/service/am/am_types.h +++ b/src/core/hle/service/am/am_types.h @@ -94,7 +94,8 @@ enum class AppletId : u32 { LoginShare = 0x18, WebAuth = 0x19, MyPage = 0x1A, - Lhub = 0x35 + Lhub = 0x35, + Splay = 0x64, }; enum class AppletProgramId : u64 { @@ -118,6 +119,8 @@ enum class AppletProgramId : u64 { WebAuth = 0x0100000000001011ull, Starter = 0x0100000000001012ull, MyPage = 0x0100000000001013ull, + Maintenance = 0x0100000000001015ull, + Splay = 0x0100000000001048ull, MaxProgramId = 0x0100000000001FFFull, }; diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index c2920f91ae..fcb9b23b72 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -172,6 +172,19 @@ void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) channel.Push(std::make_shared(system, std::move(argument_data))); } +void PushInShowSplay(Core::System& system, AppletStorageChannel& channel) { + struct SplayV1 { + std::array i_dont_know_what_this_is_used_for; + }; + static_assert(sizeof(SplayV1) == 0x100, "MiiEditV3 has incorrect size."); + + SplayV1 splay_arguments{}; + std::vector argument_data(sizeof(splay_arguments)); + std::memcpy(argument_data.data(), &splay_arguments, sizeof(splay_arguments)); + + channel.Push(std::make_shared(system, std::move(argument_data))); +} + void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, @@ -335,6 +348,9 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { case AppletId::Controller: PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); break; + case AppletId::Splay: + PushInShowSplay(m_system, InitializeFakeCallerApplet(m_system, applet)); + break; default: break; } diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp index e38729e70a..f0803bb350 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp @@ -44,6 +44,7 @@ bool ShouldCreateGuestApplet(AppletId applet_id) { X(LoginShare, login_share) X(WebAuth, wifi_web_auth) X(MyPage, my_page) + X(Splay, splay) #undef X @@ -52,48 +53,28 @@ bool ShouldCreateGuestApplet(AppletId applet_id) { AppletProgramId AppletIdToProgramId(AppletId applet_id) { switch (applet_id) { - case AppletId::OverlayDisplay: - return AppletProgramId::OverlayDisplay; - case AppletId::QLaunch: - return AppletProgramId::QLaunch; - case AppletId::Starter: - return AppletProgramId::Starter; - case AppletId::Auth: - return AppletProgramId::Auth; - case AppletId::Cabinet: - return AppletProgramId::Cabinet; - case AppletId::Controller: - return AppletProgramId::Controller; - case AppletId::DataErase: - return AppletProgramId::DataErase; - case AppletId::Error: - return AppletProgramId::Error; - case AppletId::NetConnect: - return AppletProgramId::NetConnect; - case AppletId::ProfileSelect: - return AppletProgramId::ProfileSelect; - case AppletId::SoftwareKeyboard: - return AppletProgramId::SoftwareKeyboard; - case AppletId::MiiEdit: - return AppletProgramId::MiiEdit; - case AppletId::Web: - return AppletProgramId::Web; - case AppletId::Shop: - return AppletProgramId::Shop; - case AppletId::PhotoViewer: - return AppletProgramId::PhotoViewer; - case AppletId::Settings: - return AppletProgramId::Settings; - case AppletId::OfflineWeb: - return AppletProgramId::OfflineWeb; - case AppletId::LoginShare: - return AppletProgramId::LoginShare; - case AppletId::WebAuth: - return AppletProgramId::WebAuth; - case AppletId::MyPage: - return AppletProgramId::MyPage; - default: - return static_cast(0); + case AppletId::OverlayDisplay: return AppletProgramId::OverlayDisplay; + case AppletId::QLaunch: return AppletProgramId::QLaunch; + case AppletId::Starter: return AppletProgramId::Starter; + case AppletId::Auth: return AppletProgramId::Auth; + case AppletId::Cabinet: return AppletProgramId::Cabinet; + case AppletId::Controller: return AppletProgramId::Controller; + case AppletId::DataErase: return AppletProgramId::DataErase; + case AppletId::Error: return AppletProgramId::Error; + case AppletId::NetConnect: return AppletProgramId::NetConnect; + case AppletId::ProfileSelect: return AppletProgramId::ProfileSelect; + case AppletId::SoftwareKeyboard: return AppletProgramId::SoftwareKeyboard; + case AppletId::MiiEdit: return AppletProgramId::MiiEdit; + case AppletId::Web: return AppletProgramId::Web; + case AppletId::Shop: return AppletProgramId::Shop; + case AppletId::PhotoViewer: return AppletProgramId::PhotoViewer; + case AppletId::Settings: return AppletProgramId::Settings; + case AppletId::OfflineWeb: return AppletProgramId::OfflineWeb; + case AppletId::LoginShare: return AppletProgramId::LoginShare; + case AppletId::WebAuth: return AppletProgramId::WebAuth; + case AppletId::MyPage: return AppletProgramId::MyPage; + case AppletId::Splay: return AppletProgramId::Splay; + default: return AppletProgramId(0); } } diff --git a/src/core/hle/service/ns/notify_service.cpp b/src/core/hle/service/ns/notify_service.cpp new file mode 100644 index 0000000000..4d3f1dd1e5 --- /dev/null +++ b/src/core/hle/service/ns/notify_service.cpp @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "common/uuid.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/service/ns/notify_service.h" +#include "core/hle/service/service.h" +#include "core/launch_timestamp_cache.h" +#include "frontend_common/play_time_manager.h" + +namespace Service::NS { + +INotifyService::INotifyService(Core::System& system_) + : ServiceFramework{system_, "pdm:ntfy"} +{ + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "NotifyAppletEvent"}, + {2, nullptr, "NotifyOperationModeChangeEvent"}, + {3, nullptr, "NotifyPowerStateChangeEvent"}, + {4, nullptr, "NotifyClearAllEvent"}, + {5, nullptr, "NotifyEventForDebug"}, + {6, nullptr, "SuspendUserAccountEventService"}, + {7, nullptr, "ResumeUserAccountEventService"}, + {8, nullptr, "Unknown8"}, + {9, nullptr, "Unknown9"}, + {20, nullptr, "Unknown20"}, + {100, nullptr, "Unknown100"}, + {101, nullptr, "Unknown101"}, + + }; + // clang-format on + RegisterHandlers(functions); +} + +INotifyService::~INotifyService() = default; + +} // namespace Service::NS diff --git a/src/core/hle/service/ns/notify_service.h b/src/core/hle/service/ns/notify_service.h new file mode 100644 index 0000000000..d20cff8409 --- /dev/null +++ b/src/core/hle/service/ns/notify_service.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/uuid.h" +#include "core/hle/service/am/am_types.h" +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/ns/ns_types.h" +#include "core/hle/service/service.h" + +#include + +namespace Service::NS { + +class INotifyService final : public ServiceFramework { +public: + explicit INotifyService(Core::System& system_); + ~INotifyService() override; +}; + +} // namespace Service::NS diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 8402e83cb1..01648b9be2 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -5,6 +5,7 @@ #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/platform_service_manager.h" #include "core/hle/service/ns/query_service.h" +#include "core/hle/service/ns/notify_service.h" #include "core/hle/service/ns/service_getter_interface.h" #include "core/hle/service/ns/system_update_interface.h" #include "core/hle/service/ns/vulnerability_manager_interface.h" @@ -33,6 +34,7 @@ void LoopProcess(Core::System& system) { server_manager->RegisterNamedService("ns:vm", std::make_shared(system)); server_manager->RegisterNamedService("pdm:qry", std::make_shared(system)); + server_manager->RegisterNamedService("pdm:ntfy", std::make_shared(system)); server_manager->RegisterNamedService("pl:s", std::make_shared(system, "pl:s")); diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index f4355197b0..64a9d83198 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, splay_applet_mode, tr("Splay"), QString()); INSERT(Settings, enable_overlay, tr("Enable Overlay Applet"), QString()); // Audio diff --git a/src/yuzu/configuration/configure_applets.cpp b/src/yuzu/configuration/configure_applets.cpp index 139bfa9da3..80d58c8b2e 100644 --- a/src/yuzu/configuration/configure_applets.cpp +++ b/src/yuzu/configuration/configure_applets.cpp @@ -63,7 +63,8 @@ void ConfigureApplets::Setup(const ConfigurationShared::Builder& builder) { setting->Id() == Settings::values.shop_applet_mode.Id() || setting->Id() == Settings::values.login_share_applet_mode.Id() || setting->Id() == Settings::values.wifi_web_auth_applet_mode.Id() || - setting->Id() == Settings::values.my_page_applet_mode.Id()) { + setting->Id() == Settings::values.my_page_applet_mode.Id() || + setting->Id() == Settings::values.splay_applet_mode.Id()) { widget->setHidden(true); } diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 59aab0ef93..2e10ccfb11 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -189,6 +189,7 @@ + @@ -465,6 +466,11 @@ &Mii Editor + + + &Splay + + &Configure TAS... diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 836aacb0fa..90bf6bdad8 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -1700,6 +1700,9 @@ void MainWindow::ConnectMenuEvents() { connect_menu(ui->action_Launch_QLaunch, [this]{ LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt); }); + connect_menu(ui->action_Launch_Splay, [this]{ + LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::Splay), std::nullopt); + }); // Tools (cabinet) connect_menu(ui->action_Launch_Cabinet_Nickname_Owner, [this]{ LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::Cabinet), {Service::NFP::CabinetMode::StartNicknameAndOwnerSettings}); @@ -1762,7 +1765,8 @@ void MainWindow::UpdateMenuState() { ui->action_Launch_Cabinet_Formatter, ui->action_Launch_MiiEdit, ui->action_Launch_QLaunch, - ui->action_Launch_Controller + ui->action_Launch_Controller, + ui->action_Launch_Splay }; for (QAction* action : running_actions) { @@ -4101,6 +4105,7 @@ void MainWindow::LaunchFirmwareApplet(u64 raw_program_id, std::optional