// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/core_timing.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am_results.h" #include "core/hle/service/am/frontend/applet_cabinet.h" #include "core/hle/service/am/frontend/applet_controller.h" #include "core/hle/service/am/frontend/applet_mii_edit_types.h" #include "core/hle/service/am/frontend/applet_software_keyboard_types.h" #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/am/library_applet_self_accessor.h" #include "core/hle/service/am/storage.h" #include "core/hle/service/ipc_helpers.h" #include "hid_core/hid_types.h" namespace Service::AM { ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, {2, nullptr, "PopInteractiveInData"}, {3, nullptr, "PushInteractiveOutData"}, {5, nullptr, "GetPopInDataEvent"}, {6, nullptr, "GetPopInteractiveInDataEvent"}, {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, {13, nullptr, "CanUseApplicationCore"}, {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, {15, nullptr, "GetMainAppletApplicationControlProperty"}, {16, nullptr, "GetMainAppletStorageId"}, {17, nullptr, "GetCallerAppletIdentityInfoStack"}, {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, {20, nullptr, "PopExtraStorage"}, {25, nullptr, "GetPopExtraStorageEvent"}, {30, nullptr, "UnpopInData"}, {31, nullptr, "UnpopExtraStorage"}, {40, nullptr, "GetIndirectLayerProducerHandle"}, {50, nullptr, "ReportVisibleError"}, {51, nullptr, "ReportVisibleErrorWithErrorContext"}, {60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, {70, nullptr, "GetCurrentApplicationId"}, {80, nullptr, "RequestExitToSelf"}, {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, {100, nullptr, "CreateGameMovieTrimmer"}, {101, nullptr, "ReserveResourceForMovieOperation"}, {102, nullptr, "UnreserveResourceForMovieOperation"}, {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, {120, nullptr, "GetLaunchStorageInfoForDebug"}, {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, {140, nullptr, "SetApplicationMemoryReservation"}, {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, }; // clang-format on RegisterHandlers(functions); switch (system.GetFrontendAppletHolder().GetCurrentAppletId()) { case AppletId::Cabinet: PushInShowCabinetData(); break; case AppletId::MiiEdit: PushInShowMiiEditData(); break; case AppletId::PhotoViewer: PushInShowAlbum(); break; case AppletId::SoftwareKeyboard: PushInShowSoftwareKeyboard(); break; case AppletId::Controller: PushInShowController(); break; default: break; } } ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { LOG_INFO(Service_AM, "called"); if (queue_data.empty()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(AM::ResultNoDataInChannel); return; } auto data = queue_data.front(); queue_data.pop_front(); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); rb.PushIpcInterface(system, std::move(data)); } void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); system.Exit(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { struct LibraryAppletInfo { AppletId applet_id; LibraryAppletMode library_applet_mode; }; LOG_WARNING(Service_AM, "(STUBBED) called"); const LibraryAppletInfo applet_info{ .applet_id = system.GetFrontendAppletHolder().GetCurrentAppletId(), .library_applet_mode = LibraryAppletMode::AllForeground, }; IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); rb.PushRaw(applet_info); } void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { struct AppletIdentityInfo { AppletId applet_id; INSERT_PADDING_BYTES(0x4); u64 application_id; }; static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); LOG_WARNING(Service_AM, "(STUBBED) called"); const AppletIdentityInfo applet_info{ .applet_id = AppletId::QLaunch, .application_id = 0x0100000000001000ull, }; IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); rb.PushRaw(applet_info); } void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { struct AppletIdentityInfo { AppletId applet_id; INSERT_PADDING_BYTES(0x4); u64 application_id; }; static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); LOG_WARNING(Service_AM, "(STUBBED) called"); const AppletIdentityInfo applet_info{ .applet_id = AppletId::QLaunch, .application_id = 0x0100000000001000ull, }; IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); rb.PushRaw(applet_info); } void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(0); } void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { const Service::Account::ProfileManager manager{}; bool is_empty{true}; s32 user_count{-1}; LOG_INFO(Service_AM, "called"); if (manager.GetUserCount() > 0) { is_empty = false; user_count = static_cast(manager.GetUserCount()); ctx.WriteBuffer(manager.GetAllUsers()); } IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); rb.Push(is_empty); rb.Push(user_count); } void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(0); } void ILibraryAppletSelfAccessor::PushInShowAlbum() { const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, .library_version = 1, .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; std::vector argument_data(sizeof(arguments)); std::vector settings_data{2}; std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); queue_data.emplace_back(std::move(argument_data)); queue_data.emplace_back(std::move(settings_data)); } void ILibraryAppletSelfAccessor::PushInShowController() { const CommonArguments common_args = { .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, .library_version = static_cast(Frontend::ControllerAppletVersion::Version8), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; Frontend::ControllerSupportArgNew user_args = { .header = {.player_count_min = 1, .player_count_max = 4, .enable_take_over_connection = true, .enable_left_justify = false, .enable_permit_joy_dual = true, .enable_single_mode = false, .enable_identification_color = false}, .identification_colors = {}, .enable_explain_text = false, .explain_text = {}, }; Frontend::ControllerSupportArgPrivate private_args = { .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate), .arg_size = sizeof(Frontend::ControllerSupportArgNew), .is_home_menu = true, .flag_1 = true, .mode = Frontend::ControllerSupportMode::ShowControllerSupport, .caller = Frontend::ControllerSupportCaller:: Application, // switchbrew: Always zero except with // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, // which sets this to the input param .style_set = Core::HID::NpadStyleSet::None, .joy_hold_type = 0, }; std::vector common_args_data(sizeof(common_args)); std::vector private_args_data(sizeof(private_args)); std::vector user_args_data(sizeof(user_args)); std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); queue_data.emplace_back(std::move(common_args_data)); queue_data.emplace_back(std::move(private_args_data)); queue_data.emplace_back(std::move(user_args_data)); } void ILibraryAppletSelfAccessor::PushInShowCabinetData() { const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, .library_version = static_cast(Frontend::CabinetAppletVersion::Version1), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; const Frontend::StartParamForAmiiboSettings amiibo_settings{ .param_1 = 0, .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(), .flags = Frontend::CabinetFlags::None, .amiibo_settings_1 = 0, .device_handle = 0, .tag_info{}, .register_info{}, .amiibo_settings_3{}, }; std::vector argument_data(sizeof(arguments)); std::vector settings_data(sizeof(amiibo_settings)); std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); queue_data.emplace_back(std::move(argument_data)); queue_data.emplace_back(std::move(settings_data)); } void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { struct MiiEditV3 { Frontend::MiiEditAppletInputCommon common; Frontend::MiiEditAppletInputV3 input; }; static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); MiiEditV3 mii_arguments{ .common = { .version = Frontend::MiiEditAppletVersion::Version3, .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit, }, .input{}, }; std::vector argument_data(sizeof(mii_arguments)); std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); queue_data.emplace_back(std::move(argument_data)); } void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { const CommonArguments arguments{ .arguments_version = CommonArgumentVersion::Version3, .size = CommonArgumentSize::Version3, .library_version = static_cast(Frontend::SwkbdAppletVersion::Version524301), .theme_color = ThemeColor::BasicBlack, .play_startup_sound = true, .system_tick = system.CoreTiming().GetClockTicks(), }; std::vector initial_string(0); const Frontend::SwkbdConfigCommon swkbd_config{ .type = Frontend::SwkbdType::Qwerty, .ok_text{}, .left_optional_symbol_key{}, .right_optional_symbol_key{}, .use_prediction = false, .key_disable_flags{}, .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start, .header_text{}, .sub_text{}, .guide_text{}, .max_text_length = 500, .min_text_length = 0, .password_mode = Frontend::SwkbdPasswordMode::Disabled, .text_draw_type = Frontend::SwkbdTextDrawType::Box, .enable_return_button = true, .use_utf8 = false, .use_blur_background = true, .initial_string_offset{}, .initial_string_length = static_cast(initial_string.size()), .user_dictionary_offset{}, .user_dictionary_entries{}, .use_text_check = false, }; Frontend::SwkbdConfigNew swkbd_config_new{}; std::vector argument_data(sizeof(arguments)); std::vector swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); std::vector work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, sizeof(Frontend::SwkbdConfigNew)); std::memcpy(work_buffer.data(), initial_string.data(), swkbd_config.initial_string_length * sizeof(char16_t)); queue_data.emplace_back(std::move(argument_data)); queue_data.emplace_back(std::move(swkbd_data)); queue_data.emplace_back(std::move(work_buffer)); } } // namespace Service::AM