diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 51a371f2cf..8a6dc2d033 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp @@ -295,11 +295,12 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { // Or ulaunch initialization where we push parameters willingly! if (params.launch_type == LaunchType::ApplicationInitiated) { applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); - } else if (params.launch_type == LaunchType::FrontendUlaunchInitiated) { + } else if (params.launch_type == LaunchType::FrontendUlaunchInitiated + || params.launch_type == LaunchType::FrontendUmenuInitiated) { constexpr size_t NroPathSize = 512; constexpr size_t NroArgvSize = 2048; constexpr size_t MenuCaptionSize = 1024; - struct UlauncherTargetInput { + struct UloaderTargetInput { u32 magic; bool target_once; bool is_auto_game_recording; @@ -307,17 +308,42 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) { std::array nro_path; std::array nro_argv; std::array menu_caption; - } target_ipt = {}; - static_assert(sizeof(target_ipt) == 3592); + }; + static_assert(sizeof(UloaderTargetInput) == 3592); - target_ipt.magic = 0x49444C55; // "ULDI" - target_ipt.nro_path = {"sdmc:/hbmenu.nro"}; - target_ipt.menu_caption = {"Loaded by uLoader v1.2.4 - uLaunch's custom hbloader replacement ;)"}; + if (params.launch_type == LaunchType::FrontendUlaunchInitiated) { + UloaderTargetInput target_ipt = {}; + target_ipt.magic = 0x49444C55; // "ULDI" + target_ipt.nro_path = {"sdmc:/hbmenu.nro"}; + target_ipt.menu_caption = {"Loaded by uLoader v1.2.4 - uLaunch's custom hbloader replacement ;)"}; - std::vector v(sizeof(target_ipt)); - std::memcpy(v.data(), &target_ipt, sizeof(target_ipt)); - applet->user_channel_launch_parameter.clear(); - applet->user_channel_launch_parameter.push_back(std::move(v)); + std::vector v(sizeof(target_ipt)); + std::memcpy(v.data(), std::addressof(target_ipt), sizeof(target_ipt)); + applet->user_channel_launch_parameter.clear(); + applet->user_channel_launch_parameter.push_back(std::move(v)); + } else { + typedef u64 AccountUid; + struct UmenuInput { + AccountUid selected_user; + UloaderTargetInput suspended_hb_target_ipt; // Set if homebrew (launched as an application) is currently suspended + u64 suspended_app_id; // Set if any normal application is suspended + std::array last_menu_fs_path; //FS_MAX_PATH + std::array last_menu_path; + u32 last_menu_index; + bool reload_theme_cache; + bool warned_about_outdated_theme; + u32 last_added_app_count; + u32 last_deleted_app_count; + u32 in_verify_app_count; + }; + + UmenuInput target_umenu_ipt = {}; + + std::vector v(sizeof(target_umenu_ipt)); + std::memcpy(v.data(), std::addressof(target_umenu_ipt), sizeof(target_umenu_ipt)); + applet->user_channel_launch_parameter.clear(); + applet->user_channel_launch_parameter.push_back(std::move(v)); + } } // TODO: Read whether we need a preselected user from NACP? diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h index cd97a6e157..8c2378aca3 100644 --- a/src/core/hle/service/am/applet_manager.h +++ b/src/core/hle/service/am/applet_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project @@ -28,6 +28,7 @@ enum class LaunchType { ApplicationInitiated, // Special masquerade for AMS + uLaunch CFW FrontendUlaunchInitiated = 0x800, + FrontendUmenuInitiated, }; struct FrontendAppletParameters { diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 714555a633..f3ff0eadda 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -515,6 +515,7 @@ MainWindow::MainWindow(bool has_broken_vulkan) QString game_path; bool should_launch_qlaunch = false; bool should_launch_hlaunch = false; + bool should_launch_hlaunch_uloader = false; bool should_launch_ulaunch = false; bool should_launch_setup = false; bool has_gamepath = false; @@ -559,6 +560,8 @@ MainWindow::MainWindow(bool has_broken_vulkan) should_launch_qlaunch = true; } else if (args[i] == QStringLiteral("-hlaunch")) { should_launch_hlaunch = true; + } else if (args[i] == QStringLiteral("-hlaunch-uloader")) { + should_launch_hlaunch_uloader = true; } else if (args[i] == QStringLiteral("-ulaunch")) { should_launch_ulaunch = true; } else if (args[i] == QStringLiteral("-setup")) { @@ -585,12 +588,19 @@ MainWindow::MainWindow(bool has_broken_vulkan) std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); auto const path = (sd_dir / "atmosphere" / "hbl.nsp").string(); BootGame(QString::fromStdString(path), ApplicationAppletParameters()); - } else if (should_launch_ulaunch) { + } else if (should_launch_hlaunch_uloader) { std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); auto const path = (sd_dir / "ulaunch" / "bin" / "uLoader" / "application" / "main").string(); auto params = ApplicationAppletParameters(); params.launch_type = Service::AM::LaunchType::FrontendUlaunchInitiated; BootGame(QString::fromStdString(path), params); + } else if (should_launch_ulaunch) { + std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir); + auto const path = (sd_dir / "ulaunch" / "bin" / "uMenu" / "main").string(); + auto const program_id = 0x0100000000010000; + auto params = LibraryAppletParameters(u64(program_id), Service::AM::AppletId::Cabinet); + params.launch_type = Service::AM::LaunchType::FrontendUmenuInitiated; + BootGame(QString::fromStdString(path), params); } } }