early-access version 1880

This commit is contained in:
pineappleEA
2021-07-15 05:24:54 +02:00
parent c230feea19
commit 47782d4a00
75 changed files with 16698 additions and 93 deletions

View File

@@ -24,16 +24,16 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/applets/applet_software_keyboard.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/applets/profile_select.h"
#include "core/hle/service/am/applets/software_keyboard.h"
#include "core/hle/service/am/applets/web_browser.h"
#include "core/hle/service/am/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/apm/interface.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/ns.h"

View File

@@ -0,0 +1,253 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/controller.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/hid/controllers/npad.h"
namespace Service::AM::Applets {
// This error code (0x183ACA) is thrown when the applet fails to initialize.
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
HID::Controller_NPad::NpadStyleSet npad_style_set;
npad_style_set.raw = private_arg.style_set;
return {
.min_players = std::max(s8{1}, header.player_count_min),
.max_players = header.player_count_max,
.keep_controllers_connected = header.enable_take_over_connection,
.enable_single_mode = header.enable_single_mode,
.enable_border_color = header.enable_identification_color,
.border_colors = std::move(identification_colors),
.enable_explain_text = enable_text,
.explain_text = std::move(text),
.allow_pro_controller = npad_style_set.fullkey == 1,
.allow_handheld = npad_style_set.handheld == 1,
.allow_dual_joycons = npad_style_set.joycon_dual == 1,
.allow_left_joycon = npad_style_set.joycon_left == 1,
.allow_right_joycon = npad_style_set.joycon_right == 1,
};
}
Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ControllerApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
Controller::~Controller() = default;
void Controller::Initialize() {
Applet::Initialize();
LOG_INFO(Service_HID, "Initializing Controller Applet.");
LOG_DEBUG(Service_HID,
"Initializing Applet with common_args: arg_version={}, lib_version={}, "
"play_startup_sound={}, size={}, system_tick={}, theme_color={}",
common_args.arguments_version, common_args.library_version,
common_args.play_startup_sound, common_args.size, common_args.system_tick,
common_args.theme_color);
controller_applet_version = ControllerAppletVersion{common_args.library_version};
const auto private_arg_storage = broker.PopNormalDataToApplet();
ASSERT(private_arg_storage != nullptr);
const auto& private_arg = private_arg_storage->GetData();
ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size());
ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
"Unknown ControllerSupportArgPrivate revision={} with size={}",
controller_applet_version, controller_private_arg.arg_private_size);
// Some games such as Cave Story+ set invalid values for the ControllerSupportMode.
// Defer to arg_size to set the ControllerSupportMode.
if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) {
switch (controller_private_arg.arg_size) {
case sizeof(ControllerSupportArgOld):
case sizeof(ControllerSupportArgNew):
controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
break;
case sizeof(ControllerUpdateFirmwareArg):
controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate;
break;
default:
UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}",
controller_private_arg.mode, controller_private_arg.arg_size);
controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
break;
}
}
// Some games such as Cave Story+ set invalid values for the ControllerSupportCaller.
// This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem.
if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) {
if (controller_private_arg.flag_1 &&
controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) {
controller_private_arg.caller = ControllerSupportCaller::System;
} else {
controller_private_arg.caller = ControllerSupportCaller::Application;
}
}
switch (controller_private_arg.mode) {
case ControllerSupportMode::ShowControllerSupport:
case ControllerSupportMode::ShowControllerStrapGuide: {
const auto user_arg_storage = broker.PopNormalDataToApplet();
ASSERT(user_arg_storage != nullptr);
const auto& user_arg = user_arg_storage->GetData();
switch (controller_applet_version) {
case ControllerAppletVersion::Version3:
case ControllerAppletVersion::Version4:
case ControllerAppletVersion::Version5:
ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size());
break;
case ControllerAppletVersion::Version7:
ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size());
break;
default:
UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
controller_applet_version, controller_private_arg.arg_size);
ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
break;
}
break;
}
case ControllerSupportMode::ShowControllerFirmwareUpdate: {
const auto update_arg_storage = broker.PopNormalDataToApplet();
ASSERT(update_arg_storage != nullptr);
const auto& update_arg = update_arg_storage->GetData();
ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg));
std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size());
break;
}
default: {
UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
break;
}
}
}
bool Controller::TransactionComplete() const {
return complete;
}
ResultCode Controller::GetStatus() const {
return status;
}
void Controller::ExecuteInteractive() {
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
}
void Controller::Execute() {
switch (controller_private_arg.mode) {
case ControllerSupportMode::ShowControllerSupport: {
const auto parameters = [this] {
switch (controller_applet_version) {
case ControllerAppletVersion::Version3:
case ControllerAppletVersion::Version4:
case ControllerAppletVersion::Version5:
return ConvertToFrontendParameters(
controller_private_arg, controller_user_arg_old.header,
controller_user_arg_old.enable_explain_text,
std::vector<IdentificationColor>(
controller_user_arg_old.identification_colors.begin(),
controller_user_arg_old.identification_colors.end()),
std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
controller_user_arg_old.explain_text.end()));
case ControllerAppletVersion::Version7:
default:
return ConvertToFrontendParameters(
controller_private_arg, controller_user_arg_new.header,
controller_user_arg_new.enable_explain_text,
std::vector<IdentificationColor>(
controller_user_arg_new.identification_colors.begin(),
controller_user_arg_new.identification_colors.end()),
std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(),
controller_user_arg_new.explain_text.end()));
}
}();
is_single_mode = parameters.enable_single_mode;
LOG_DEBUG(Service_HID,
"Controller Parameters: min_players={}, max_players={}, "
"keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, "
"enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, "
"allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
parameters.min_players, parameters.max_players,
parameters.keep_controllers_connected, parameters.enable_single_mode,
parameters.enable_border_color, parameters.enable_explain_text,
parameters.allow_pro_controller, parameters.allow_handheld,
parameters.allow_dual_joycons, parameters.allow_left_joycon,
parameters.allow_right_joycon);
frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
break;
}
case ControllerSupportMode::ShowControllerStrapGuide:
case ControllerSupportMode::ShowControllerFirmwareUpdate:
UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented",
controller_private_arg.mode);
ConfigurationComplete();
break;
default: {
ConfigurationComplete();
break;
}
}
}
void Controller::ConfigurationComplete() {
ControllerSupportResultInfo result_info{};
const auto& players = Settings::values.players.GetValue();
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
// Otherwise, only count connected players from P1-P8.
result_info.player_count =
is_single_mode
? 1
: static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
[](const auto& player) { return player.connected; }));
result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance(
players.begin(), std::find_if(players.begin(), players.end(),
[](const auto& player) { return player.connected; })));
result_info.result = 0;
LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
result_info.player_count, result_info.selected_id, result_info.result);
complete = true;
out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
std::memcpy(out_data.data(), &result_info, out_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,137 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
using IdentificationColor = std::array<u8, 4>;
using ExplainText = std::array<char, 0x81>;
enum class ControllerAppletVersion : u32_le {
Version3 = 0x3, // 1.0.0 - 2.3.0
Version4 = 0x4, // 3.0.0 - 5.1.0
Version5 = 0x5, // 6.0.0 - 7.0.1
Version7 = 0x7, // 8.0.0+
};
enum class ControllerSupportMode : u8 {
ShowControllerSupport,
ShowControllerStrapGuide,
ShowControllerFirmwareUpdate,
MaxControllerSupportMode,
};
enum class ControllerSupportCaller : u8 {
Application,
System,
MaxControllerSupportCaller,
};
struct ControllerSupportArgPrivate {
u32 arg_private_size{};
u32 arg_size{};
bool flag_0{};
bool flag_1{};
ControllerSupportMode mode{};
ControllerSupportCaller caller{};
u32 style_set{};
u32 joy_hold_type{};
};
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
"ControllerSupportArgPrivate has incorrect size.");
struct ControllerSupportArgHeader {
s8 player_count_min{};
s8 player_count_max{};
bool enable_take_over_connection{};
bool enable_left_justify{};
bool enable_permit_joy_dual{};
bool enable_single_mode{};
bool enable_identification_color{};
};
static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
"ControllerSupportArgHeader has incorrect size.");
// LibraryAppletVersion 0x3, 0x4, 0x5
struct ControllerSupportArgOld {
ControllerSupportArgHeader header{};
std::array<IdentificationColor, 4> identification_colors{};
bool enable_explain_text{};
std::array<ExplainText, 4> explain_text{};
};
static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
"ControllerSupportArgOld has incorrect size.");
// LibraryAppletVersion 0x7
struct ControllerSupportArgNew {
ControllerSupportArgHeader header{};
std::array<IdentificationColor, 8> identification_colors{};
bool enable_explain_text{};
std::array<ExplainText, 8> explain_text{};
};
static_assert(sizeof(ControllerSupportArgNew) == 0x430,
"ControllerSupportArgNew has incorrect size.");
struct ControllerUpdateFirmwareArg {
bool enable_force_update{};
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4,
"ControllerUpdateFirmwareArg has incorrect size.");
struct ControllerSupportResultInfo {
s8 player_count{};
INSERT_PADDING_BYTES(3);
u32 selected_id{};
u32 result{};
};
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
"ControllerSupportResultInfo has incorrect size.");
class Controller final : public Applet {
public:
explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ControllerApplet& frontend_);
~Controller() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void ConfigurationComplete();
private:
const Core::Frontend::ControllerApplet& frontend;
Core::System& system;
ControllerAppletVersion controller_applet_version;
ControllerSupportArgPrivate controller_private_arg;
ControllerSupportArgOld controller_user_arg_old;
ControllerSupportArgNew controller_user_arg_new;
ControllerUpdateFirmwareArg controller_update_arg;
bool complete{false};
ResultCode status{ResultSuccess};
bool is_single_mode{false};
std::vector<u8> out_data;
};
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,194 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/error.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/reporter.h"
namespace Service::AM::Applets {
#pragma pack(push, 4)
struct ShowError {
u8 mode;
bool jump;
INSERT_PADDING_BYTES_NOINIT(4);
bool use_64bit_error_code;
INSERT_PADDING_BYTES_NOINIT(1);
u64 error_code_64;
u32 error_code_32;
};
static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size.");
#pragma pack(pop)
struct ShowErrorRecord {
u8 mode;
bool jump;
INSERT_PADDING_BYTES_NOINIT(6);
u64 error_code_64;
u64 posix_time;
};
static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size.");
struct SystemErrorArg {
u8 mode;
bool jump;
INSERT_PADDING_BYTES_NOINIT(6);
u64 error_code_64;
std::array<char, 8> language_code;
std::array<char, 0x800> main_text;
std::array<char, 0x800> detail_text;
};
static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size.");
struct ApplicationErrorArg {
u8 mode;
bool jump;
INSERT_PADDING_BYTES_NOINIT(6);
u32 error_code;
std::array<char, 8> language_code;
std::array<char, 0x800> main_text;
std::array<char, 0x800> detail_text;
};
static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size.");
union Error::ErrorArguments {
ShowError error;
ShowErrorRecord error_record;
SystemErrorArg system_error;
ApplicationErrorArg application_error;
std::array<u8, 0x1018> raw{};
};
namespace {
template <typename T>
void CopyArgumentData(const std::vector<u8>& data, T& variable) {
ASSERT(data.size() >= sizeof(T));
std::memcpy(&variable, data.data(), sizeof(T));
}
ResultCode Decode64BitError(u64 error) {
const auto description = (error >> 32) & 0x1FFF;
auto module = error & 0x3FF;
if (module >= 2000)
module -= 2000;
module &= 0x1FF;
return {static_cast<ErrorModule>(module), static_cast<u32>(description)};
}
} // Anonymous namespace
Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ErrorApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
Error::~Error() = default;
void Error::Initialize() {
Applet::Initialize();
args = std::make_unique<ErrorArguments>();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
ASSERT(!data.empty());
std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode));
switch (mode) {
case ErrorAppletMode::ShowError:
CopyArgumentData(data, args->error);
if (args->error.use_64bit_error_code) {
error_code = Decode64BitError(args->error.error_code_64);
} else {
error_code = ResultCode(args->error.error_code_32);
}
break;
case ErrorAppletMode::ShowSystemError:
CopyArgumentData(data, args->system_error);
error_code = ResultCode(Decode64BitError(args->system_error.error_code_64));
break;
case ErrorAppletMode::ShowApplicationError:
CopyArgumentData(data, args->application_error);
error_code = ResultCode(args->application_error.error_code);
break;
case ErrorAppletMode::ShowErrorRecord:
CopyArgumentData(data, args->error_record);
error_code = Decode64BitError(args->error_record.error_code_64);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
}
}
bool Error::TransactionComplete() const {
return complete;
}
ResultCode Error::GetStatus() const {
return ResultSuccess;
}
void Error::ExecuteInteractive() {
UNREACHABLE_MSG("Unexpected interactive applet data!");
}
void Error::Execute() {
if (complete) {
return;
}
const auto callback = [this] { DisplayCompleted(); };
const auto title_id = system.CurrentProcess()->GetTitleID();
const auto& reporter{system.GetReporter()};
switch (mode) {
case ErrorAppletMode::ShowError:
reporter.SaveErrorReport(title_id, error_code);
frontend.ShowError(error_code, callback);
break;
case ErrorAppletMode::ShowSystemError:
case ErrorAppletMode::ShowApplicationError: {
const auto is_system = mode == ErrorAppletMode::ShowSystemError;
const auto& main_text =
is_system ? args->system_error.main_text : args->application_error.main_text;
const auto& detail_text =
is_system ? args->system_error.detail_text : args->application_error.detail_text;
const auto main_text_string =
Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size());
const auto detail_text_string =
Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size());
reporter.SaveErrorReport(title_id, error_code, main_text_string, detail_text_string);
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
break;
}
case ErrorAppletMode::ShowErrorRecord:
reporter.SaveErrorReport(title_id, error_code,
fmt::format("{:016X}", args->error_record.posix_time));
frontend.ShowErrorWithTimestamp(
error_code, std::chrono::seconds{args->error_record.posix_time}, callback);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
DisplayCompleted();
}
}
void Error::DisplayCompleted() {
complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,53 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class ErrorAppletMode : u8 {
ShowError = 0,
ShowSystemError = 1,
ShowApplicationError = 2,
ShowEula = 3,
ShowErrorPctl = 4,
ShowErrorRecord = 5,
ShowUpdateEula = 8,
};
class Error final : public Applet {
public:
explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ErrorApplet& frontend_);
~Error() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void DisplayCompleted();
private:
union ErrorArguments;
const Core::Frontend::ErrorApplet& frontend;
ResultCode error_code = ResultSuccess;
ErrorAppletMode mode = ErrorAppletMode::ShowError;
std::unique_ptr<ErrorArguments> args;
bool complete = false;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,255 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <string_view>
#include "common/assert.h"
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
#include "core/reporter.h"
namespace Service::AM::Applets {
constexpr ResultCode ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) {
std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet();
for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} received normal data with size={:08X}, data={}",
prefix, data.size(), Common::HexToString(data));
}
storage = broker.PopInteractiveDataToApplet();
for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
const auto data = storage->GetData();
LOG_INFO(Service_AM,
"called (STUBBED), during {} received interactive data with size={:08X}, data={}",
prefix, data.size(), Common::HexToString(data));
}
}
Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
Core::Frontend::ParentalControlsApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
Auth::~Auth() = default;
void Auth::Initialize() {
Applet::Initialize();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
ASSERT(data.size() >= 0xC);
struct Arg {
INSERT_PADDING_BYTES(4);
AuthAppletType type;
u8 arg0;
u8 arg1;
u8 arg2;
INSERT_PADDING_BYTES(1);
};
static_assert(sizeof(Arg) == 0xC, "Arg (AuthApplet) has incorrect size.");
Arg arg{};
std::memcpy(&arg, data.data(), sizeof(Arg));
type = arg.type;
arg0 = arg.arg0;
arg1 = arg.arg1;
arg2 = arg.arg2;
}
bool Auth::TransactionComplete() const {
return complete;
}
ResultCode Auth::GetStatus() const {
return successful ? ResultSuccess : ERROR_INVALID_PIN;
}
void Auth::ExecuteInteractive() {
UNREACHABLE_MSG("Unexpected interactive applet data.");
}
void Auth::Execute() {
if (complete) {
return;
}
const auto unimplemented_log = [this] {
UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, "
"arg1={:02X}, arg2={:02X}",
type, arg0, arg1, arg2);
};
switch (type) {
case AuthAppletType::ShowParentalAuthentication: {
const auto callback = [this](bool is_successful) { AuthFinished(is_successful); };
if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
// ShowAuthenticatorForConfiguration
frontend.VerifyPINForSettings(callback);
} else if (arg1 == 0 && arg2 == 0) {
// ShowParentalAuthentication(bool)
frontend.VerifyPIN(callback, static_cast<bool>(arg0));
} else {
unimplemented_log();
}
break;
}
case AuthAppletType::RegisterParentalPasscode: {
const auto callback = [this] { AuthFinished(true); };
if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
// RegisterParentalPasscode
frontend.RegisterPIN(callback);
} else {
unimplemented_log();
}
break;
}
case AuthAppletType::ChangeParentalPasscode: {
const auto callback = [this] { AuthFinished(true); };
if (arg0 == 0 && arg1 == 0 && arg2 == 0) {
// ChangeParentalPasscode
frontend.ChangePIN(callback);
} else {
unimplemented_log();
}
break;
}
default:
unimplemented_log();
}
}
void Auth::AuthFinished(bool is_successful) {
successful = is_successful;
struct Return {
ResultCode result_code;
};
static_assert(sizeof(Return) == 0x4, "Return (AuthApplet) has incorrect size.");
Return return_{GetStatus()};
std::vector<u8> out(sizeof(Return));
std::memcpy(out.data(), &return_, sizeof(Return));
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out)));
broker.SignalStateChanged();
}
PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
PhotoViewer::~PhotoViewer() = default;
void PhotoViewer::Initialize() {
Applet::Initialize();
complete = false;
const auto storage = broker.PopNormalDataToApplet();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
ASSERT(!data.empty());
mode = static_cast<PhotoViewerAppletMode>(data[0]);
}
bool PhotoViewer::TransactionComplete() const {
return complete;
}
ResultCode PhotoViewer::GetStatus() const {
return ResultSuccess;
}
void PhotoViewer::ExecuteInteractive() {
UNREACHABLE_MSG("Unexpected interactive applet data.");
}
void PhotoViewer::Execute() {
if (complete)
return;
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);
break;
default:
UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode);
}
}
void PhotoViewer::ViewFinished() {
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
broker.SignalStateChanged();
}
StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
: Applet{system_, applet_mode_}, id{id_}, system{system_} {}
StubApplet::~StubApplet() = default;
void StubApplet::Initialize() {
LOG_WARNING(Service_AM, "called (STUBBED)");
Applet::Initialize();
const auto data = broker.PeekDataToAppletForDebug();
system.GetReporter().SaveUnimplementedAppletReport(
static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
data.normal, data.interactive);
LogCurrentStorage(broker, "Initialize");
}
bool StubApplet::TransactionComplete() const {
LOG_WARNING(Service_AM, "called (STUBBED)");
return true;
}
ResultCode StubApplet::GetStatus() const {
LOG_WARNING(Service_AM, "called (STUBBED)");
return ResultSuccess;
}
void StubApplet::ExecuteInteractive() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "ExecuteInteractive");
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.PushInteractiveDataFromApplet(
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.SignalStateChanged();
}
void StubApplet::Execute() {
LOG_WARNING(Service_AM, "called (STUBBED)");
LogCurrentStorage(broker, "Execute");
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.PushInteractiveDataFromApplet(
std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,90 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
enum class AuthAppletType : u32 {
ShowParentalAuthentication,
RegisterParentalPasscode,
ChangeParentalPasscode,
};
class Auth final : public Applet {
public:
explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
Core::Frontend::ParentalControlsApplet& frontend_);
~Auth() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void AuthFinished(bool is_successful = true);
private:
Core::Frontend::ParentalControlsApplet& frontend;
Core::System& system;
bool complete = false;
bool successful = false;
AuthAppletType type = AuthAppletType::ShowParentalAuthentication;
u8 arg0 = 0;
u8 arg1 = 0;
u8 arg2 = 0;
};
enum class PhotoViewerAppletMode : u8 {
CurrentApp = 0,
AllApps = 1,
};
class PhotoViewer final : public Applet {
public:
explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void ViewFinished();
private:
const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
Core::System& system;
};
class StubApplet final : public Applet {
public:
explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
~StubApplet() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
private:
AppletId id;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,78 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/assert.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
namespace Service::AM::Applets {
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
ProfileSelect::~ProfileSelect() = default;
void ProfileSelect::Initialize() {
complete = false;
status = ResultSuccess;
final_data.clear();
Applet::Initialize();
const auto user_config_storage = broker.PopNormalDataToApplet();
ASSERT(user_config_storage != nullptr);
const auto& user_config = user_config_storage->GetData();
ASSERT(user_config.size() >= sizeof(UserSelectionConfig));
std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig));
}
bool ProfileSelect::TransactionComplete() const {
return complete;
}
ResultCode ProfileSelect::GetStatus() const {
return status;
}
void ProfileSelect::ExecuteInteractive() {
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
}
void ProfileSelect::Execute() {
if (complete) {
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
return;
}
frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); });
}
void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
UserSelectionOutput output{};
if (uuid.has_value() && uuid->uuid != Common::INVALID_UUID) {
output.result = 0;
output.uuid_selected = uuid->uuid;
} else {
status = ERR_USER_CANCELLED_SELECTION;
output.result = ERR_USER_CANCELLED_SELECTION.raw;
output.uuid_selected = Common::INVALID_UUID;
}
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
std::memcpy(final_data.data(), &output, final_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,59 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "common/common_funcs.h"
#include "common/uuid.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
struct UserSelectionConfig {
// TODO(DarkLordZach): RE this structure
// It seems to be flags and the like that determine the UI of the applet on the switch... from
// my research this is safe to ignore for now.
INSERT_PADDING_BYTES(0xA0);
};
static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size.");
struct UserSelectionOutput {
u64 result;
u128 uuid_selected;
};
static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size.");
class ProfileSelect final : public Applet {
public:
explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void SelectionComplete(std::optional<Common::UUID> uuid);
private:
const Core::Frontend::ProfileSelectApplet& frontend;
UserSelectionConfig config;
bool complete = false;
ResultCode status = ResultSuccess;
std::vector<u8> final_data;
Core::System& system;
};
} // namespace Service::AM::Applets

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace Service::AM::Applets {
class SoftwareKeyboard final : public Applet {
public:
explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
/**
* Submits the input text to the application.
* If text checking is enabled, the application will verify the input text.
* If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted.
* This should only be used by the normal software keyboard.
*
* @param result SwkbdResult enum
* @param submitted_text UTF-16 encoded string
*/
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
/**
* Submits the input text to the application.
* If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted.
* This should only be used by the inline software keyboard.
*
* @param reply_type SwkbdReplyType enum
* @param submitted_text UTF-16 encoded string
* @param cursor_position The current position of the text cursor
*/
void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
s32 cursor_position);
private:
/// Initializes the normal software keyboard.
void InitializeForeground();
/// Initializes the inline software keyboard.
void InitializeBackground(LibraryAppletMode library_applet_mode);
/// Processes the text check sent by the application.
void ProcessTextCheck();
/// Processes the inline software keyboard request command sent by the application.
void ProcessInlineKeyboardRequest();
/// Submits the input text and exits the applet.
void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text);
/// Submits the input text for text checking.
void SubmitForTextCheck(std::u16string submitted_text);
/// Sends a reply to the application after processing a request command.
void SendReply(SwkbdReplyType reply_type);
/// Changes the inline keyboard state.
void ChangeState(SwkbdState state);
/**
* Signals the frontend to initialize the software keyboard with common parameters.
* This initializes either the normal software keyboard or the inline software keyboard
* depending on the state of is_background.
* Note that this does not cause the keyboard to appear.
* Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
*/
void InitializeFrontendKeyboard();
/// Signals the frontend to show the normal software keyboard.
void ShowNormalKeyboard();
/// Signals the frontend to show the text check dialog.
void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
std::u16string text_check_message);
/// Signals the frontend to show the inline software keyboard.
void ShowInlineKeyboard();
/// Signals the frontend to hide the inline software keyboard.
void HideInlineKeyboard();
/// Signals the frontend that the current inline keyboard text has changed.
void InlineTextChanged();
/// Signals both the frontend and application that the software keyboard is exiting.
void ExitKeyboard();
// Inline Software Keyboard Requests
void RequestFinalize(const std::vector<u8>& request_data);
void RequestSetUserWordInfo(const std::vector<u8>& request_data);
void RequestSetCustomizeDic(const std::vector<u8>& request_data);
void RequestCalc(const std::vector<u8>& request_data);
void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data);
// Inline Software Keyboard Replies
void ReplyFinishedInitialize();
void ReplyDefault();
void ReplyChangedString();
void ReplyMovedCursor();
void ReplyMovedTab();
void ReplyDecidedEnter();
void ReplyDecidedCancel();
void ReplyChangedStringUtf8();
void ReplyMovedCursorUtf8();
void ReplyDecidedEnterUtf8();
void ReplyUnsetCustomizeDic();
void ReplyReleasedUserWordInfo();
void ReplyUnsetCustomizedDictionaries();
void ReplyChangedStringV2();
void ReplyMovedCursorV2();
void ReplyChangedStringUtf8V2();
void ReplyMovedCursorUtf8V2();
Core::Frontend::SoftwareKeyboardApplet& frontend;
Core::System& system;
SwkbdAppletVersion swkbd_applet_version;
SwkbdConfigCommon swkbd_config_common;
SwkbdConfigOld swkbd_config_old;
SwkbdConfigOld2 swkbd_config_old2;
SwkbdConfigNew swkbd_config_new;
std::u16string initial_text;
SwkbdState swkbd_state{SwkbdState::NotInitialized};
SwkbdInitializeArg swkbd_initialize_arg;
SwkbdCalcArg swkbd_calc_arg;
bool use_changed_string_v2{false};
bool use_moved_cursor_v2{false};
bool inline_use_utf8{false};
s32 current_cursor_position{};
std::u16string current_text;
bool is_background{false};
bool complete{false};
ResultCode status{ResultSuccess};
};
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,295 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
namespace Service::AM::Applets {
constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
enum class SwkbdAppletVersion : u32_le {
Version5 = 0x5, // 1.0.0
Version65542 = 0x10006, // 2.0.0 - 2.3.0
Version196615 = 0x30007, // 3.0.0 - 3.0.2
Version262152 = 0x40008, // 4.0.0 - 4.1.0
Version327689 = 0x50009, // 5.0.0 - 5.1.0
Version393227 = 0x6000B, // 6.0.0 - 7.0.1
Version524301 = 0x8000D, // 8.0.0+
};
enum class SwkbdType : u32 {
Normal,
NumberPad,
Qwerty,
Unknown3,
Latin,
SimplifiedChinese,
TraditionalChinese,
Korean,
};
enum class SwkbdInitialCursorPosition : u32 {
Start,
End,
};
enum class SwkbdPasswordMode : u32 {
Disabled,
Enabled,
};
enum class SwkbdTextDrawType : u32 {
Line,
Box,
DownloadCode,
};
enum class SwkbdResult : u32 {
Ok,
Cancel,
};
enum class SwkbdTextCheckResult : u32 {
Success,
Failure,
Confirm,
Silent,
};
enum class SwkbdState : u32 {
NotInitialized = 0x0,
InitializedIsHidden = 0x1,
InitializedIsAppearing = 0x2,
InitializedIsShown = 0x3,
InitializedIsDisappearing = 0x4,
};
enum class SwkbdRequestCommand : u32 {
Finalize = 0x4,
SetUserWordInfo = 0x6,
SetCustomizeDic = 0x7,
Calc = 0xA,
SetCustomizedDictionaries = 0xB,
UnsetCustomizedDictionaries = 0xC,
SetChangedStringV2Flag = 0xD,
SetMovedCursorV2Flag = 0xE,
};
enum class SwkbdReplyType : u32 {
FinishedInitialize = 0x0,
Default = 0x1,
ChangedString = 0x2,
MovedCursor = 0x3,
MovedTab = 0x4,
DecidedEnter = 0x5,
DecidedCancel = 0x6,
ChangedStringUtf8 = 0x7,
MovedCursorUtf8 = 0x8,
DecidedEnterUtf8 = 0x9,
UnsetCustomizeDic = 0xA,
ReleasedUserWordInfo = 0xB,
UnsetCustomizedDictionaries = 0xC,
ChangedStringV2 = 0xD,
MovedCursorV2 = 0xE,
ChangedStringUtf8V2 = 0xF,
MovedCursorUtf8V2 = 0x10,
};
struct SwkbdKeyDisableFlags {
union {
u32 raw{};
BitField<1, 1, u32> space;
BitField<2, 1, u32> at;
BitField<3, 1, u32> percent;
BitField<4, 1, u32> slash;
BitField<5, 1, u32> backslash;
BitField<6, 1, u32> numbers;
BitField<7, 1, u32> download_code;
BitField<8, 1, u32> username;
};
};
static_assert(sizeof(SwkbdKeyDisableFlags) == 0x4, "SwkbdKeyDisableFlags has incorrect size.");
struct SwkbdConfigCommon {
SwkbdType type{};
std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
char16_t left_optional_symbol_key{};
char16_t right_optional_symbol_key{};
bool use_prediction{};
INSERT_PADDING_BYTES(1);
SwkbdKeyDisableFlags key_disable_flags{};
SwkbdInitialCursorPosition initial_cursor_position{};
std::array<char16_t, MAX_HEADER_TEXT_LENGTH + 1> header_text{};
std::array<char16_t, MAX_SUB_TEXT_LENGTH + 1> sub_text{};
std::array<char16_t, MAX_GUIDE_TEXT_LENGTH + 1> guide_text{};
u32 max_text_length{};
u32 min_text_length{};
SwkbdPasswordMode password_mode{};
SwkbdTextDrawType text_draw_type{};
bool enable_return_button{};
bool use_utf8{};
bool use_blur_background{};
INSERT_PADDING_BYTES(1);
u32 initial_string_offset{};
u32 initial_string_length{};
u32 user_dictionary_offset{};
u32 user_dictionary_entries{};
bool use_text_check{};
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(SwkbdConfigCommon) == 0x3D4, "SwkbdConfigCommon has incorrect size.");
#pragma pack(push, 4)
// SwkbdAppletVersion 0x5, 0x10006
struct SwkbdConfigOld {
INSERT_PADDING_WORDS(1);
VAddr text_check_callback{};
};
static_assert(sizeof(SwkbdConfigOld) == 0x3E0 - sizeof(SwkbdConfigCommon),
"SwkbdConfigOld has incorrect size.");
// SwkbdAppletVersion 0x30007, 0x40008, 0x50009
struct SwkbdConfigOld2 {
INSERT_PADDING_WORDS(1);
VAddr text_check_callback{};
std::array<u32, 8> text_grouping{};
};
static_assert(sizeof(SwkbdConfigOld2) == 0x400 - sizeof(SwkbdConfigCommon),
"SwkbdConfigOld2 has incorrect size.");
// SwkbdAppletVersion 0x6000B, 0x8000D
struct SwkbdConfigNew {
std::array<u32, 8> text_grouping{};
std::array<u64, 24> customized_dictionary_set_entries{};
u8 total_customized_dictionary_set_entries{};
bool disable_cancel_button{};
INSERT_PADDING_BYTES(18);
};
static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon),
"SwkbdConfigNew has incorrect size.");
#pragma pack(pop)
struct SwkbdTextCheck {
SwkbdTextCheckResult text_check_result{};
std::array<char16_t, STRING_BUFFER_SIZE / 2> text_check_message{};
};
static_assert(sizeof(SwkbdTextCheck) == 0x7D8, "SwkbdTextCheck has incorrect size.");
struct SwkbdCalcArgFlags {
union {
u64 raw{};
BitField<0, 1, u64> set_initialize_arg;
BitField<1, 1, u64> set_volume;
BitField<2, 1, u64> appear;
BitField<3, 1, u64> set_input_text;
BitField<4, 1, u64> set_cursor_position;
BitField<5, 1, u64> set_utf8_mode;
BitField<6, 1, u64> unset_customize_dic;
BitField<7, 1, u64> disappear;
BitField<8, 1, u64> unknown;
BitField<9, 1, u64> set_key_top_translate_scale;
BitField<10, 1, u64> unset_user_word_info;
BitField<11, 1, u64> set_disable_hardware_keyboard;
};
};
static_assert(sizeof(SwkbdCalcArgFlags) == 0x8, "SwkbdCalcArgFlags has incorrect size.");
struct SwkbdInitializeArg {
u32 unknown{};
bool library_applet_mode_flag{};
bool is_above_hos_500{};
INSERT_PADDING_BYTES(2);
};
static_assert(sizeof(SwkbdInitializeArg) == 0x8, "SwkbdInitializeArg has incorrect size.");
struct SwkbdAppearArg {
SwkbdType type{};
std::array<char16_t, MAX_OK_TEXT_LENGTH + 1> ok_text{};
char16_t left_optional_symbol_key{};
char16_t right_optional_symbol_key{};
bool use_prediction{};
bool disable_cancel_button{};
SwkbdKeyDisableFlags key_disable_flags{};
u32 max_text_length{};
u32 min_text_length{};
bool enable_return_button{};
INSERT_PADDING_BYTES(3);
u32 flags{};
INSERT_PADDING_WORDS(6);
};
static_assert(sizeof(SwkbdAppearArg) == 0x48, "SwkbdAppearArg has incorrect size.");
struct SwkbdCalcArg {
u32 unknown{};
u16 calc_arg_size{};
INSERT_PADDING_BYTES(2);
SwkbdCalcArgFlags flags{};
SwkbdInitializeArg initialize_arg{};
f32 volume{};
s32 cursor_position{};
SwkbdAppearArg appear_arg{};
std::array<char16_t, 0x1FA> input_text{};
bool utf8_mode{};
INSERT_PADDING_BYTES(1);
bool enable_backspace_button{};
INSERT_PADDING_BYTES(3);
bool key_top_as_floating{};
bool footer_scalable{};
bool alpha_enabled_in_input_mode{};
u8 input_mode_fade_type{};
bool disable_touch{};
bool disable_hardware_keyboard{};
INSERT_PADDING_BYTES(8);
f32 key_top_scale_x{};
f32 key_top_scale_y{};
f32 key_top_translate_x{};
f32 key_top_translate_y{};
f32 key_top_bg_alpha{};
f32 footer_bg_alpha{};
f32 balloon_scale{};
INSERT_PADDING_WORDS(4);
u8 se_group{};
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(SwkbdCalcArg) == 0x4A0, "SwkbdCalcArg has incorrect size.");
struct SwkbdChangedStringArg {
u32 text_length{};
s32 dictionary_start_cursor_position{};
s32 dictionary_end_cursor_position{};
s32 cursor_position{};
};
static_assert(sizeof(SwkbdChangedStringArg) == 0x10, "SwkbdChangedStringArg has incorrect size.");
struct SwkbdMovedCursorArg {
u32 text_length{};
s32 cursor_position{};
};
static_assert(sizeof(SwkbdMovedCursorArg) == 0x8, "SwkbdMovedCursorArg has incorrect size.");
struct SwkbdMovedTabArg {
u32 text_length{};
s32 cursor_position{};
};
static_assert(sizeof(SwkbdMovedTabArg) == 0x8, "SwkbdMovedTabArg has incorrect size.");
struct SwkbdDecidedEnterArg {
u32 text_length{};
};
static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,474 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs_vector.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/pl_u.h"
namespace Service::AM::Applets {
namespace {
template <typename T>
void ParseRawValue(T& value, const std::vector<u8>& data) {
static_assert(std::is_trivially_copyable_v<T>,
"It's undefined behavior to use memcpy with non-trivially copyable objects");
std::memcpy(&value, data.data(), data.size());
}
template <typename T>
T ParseRawValue(const std::vector<u8>& data) {
T value;
ParseRawValue(value, data);
return value;
}
std::string ParseStringValue(const std::vector<u8>& data) {
return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast<const char*>(data.data()),
data.size());
}
std::string GetMainURL(const std::string& url) {
const auto index = url.find('?');
if (index == std::string::npos) {
return url;
}
return url.substr(0, index);
}
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
if (web_arg.size() == sizeof(WebArgHeader)) {
return {};
}
WebArgInputTLVMap input_tlv_map;
u64 current_offset = sizeof(WebArgHeader);
for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
return input_tlv_map;
}
WebArgInputTLV input_tlv;
std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
current_offset += sizeof(WebArgInputTLV);
if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
return input_tlv_map;
}
std::vector<u8> data(input_tlv.arg_data_size);
std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
current_offset += input_tlv.arg_data_size;
input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
}
return input_tlv_map;
}
FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
FileSys::ContentRecordType nca_type) {
if (nca_type == FileSys::ContentRecordType::Data) {
const auto nca =
system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type);
if (nca == nullptr) {
LOG_ERROR(Service_AM,
"NCA of type={} with title_id={:016X} is not found in the System NAND!",
nca_type, title_id);
return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
}
return nca->GetRomFS();
} else {
const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type);
if (nca == nullptr) {
LOG_ERROR(Service_AM,
"NCA of type={} with title_id={:016X} is not found in the ContentProvider!",
nca_type, title_id);
return nullptr;
}
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
return pm.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), nca_type);
}
}
void ExtractSharedFonts(Core::System& system) {
static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{
"FontStandard.ttf",
"FontChineseSimplified.ttf",
"FontExtendedChineseSimplified.ttf",
"FontChineseTraditional.ttf",
"FontKorean.ttf",
"FontNintendoExtended.ttf",
"FontNintendoExtended2.ttf",
};
const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts";
for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) {
const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i];
if (Common::FS::Exists(font_file_path)) {
continue;
}
const auto font = NS::SHARED_FONTS[i];
const auto font_title_id = static_cast<u64>(font.first);
const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry(
font_title_id, FileSys::ContentRecordType::Data);
FileSys::VirtualFile romfs;
if (!nca) {
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id);
} else {
romfs = nca->GetRomFS();
}
if (!romfs) {
LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!",
font_title_id);
continue;
}
const auto extracted_romfs = FileSys::ExtractRomFS(romfs);
if (!extracted_romfs) {
LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!",
font_title_id);
continue;
}
const auto font_file = extracted_romfs->GetFile(font.second);
if (!font_file) {
LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!",
font_title_id, font.second);
continue;
}
std::vector<u32> font_data_u32(font_file->GetSize() / sizeof(u32));
font_file->ReadBytes<u32>(font_data_u32.data(), font_file->GetSize());
std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(),
Common::swap32);
std::vector<u8> decrypted_data(font_file->GetSize() - 8);
NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data);
FileSys::VirtualFile decrypted_font = std::make_shared<FileSys::VectorVfsFile>(
std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]);
const auto temp_dir = system.GetFilesystem()->CreateDirectory(
Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite);
const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]);
FileSys::VfsRawCopy(decrypted_font, out_file);
}
}
} // namespace
WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::WebBrowserApplet& frontend_)
: Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {}
WebBrowser::~WebBrowser() = default;
void WebBrowser::Initialize() {
Applet::Initialize();
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
LOG_DEBUG(Service_AM,
"Initializing Applet with common_args: arg_version={}, lib_version={}, "
"play_startup_sound={}, size={}, system_tick={}, theme_color={}",
common_args.arguments_version, common_args.library_version,
common_args.play_startup_sound, common_args.size, common_args.system_tick,
common_args.theme_color);
web_applet_version = WebAppletVersion{common_args.library_version};
const auto web_arg_storage = broker.PopNormalDataToApplet();
ASSERT(web_arg_storage != nullptr);
const auto& web_arg = web_arg_storage->GetData();
ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; });
web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header);
LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}",
web_arg_header.total_tlv_entries, web_arg_header.shim_kind);
ExtractSharedFonts(system);
switch (web_arg_header.shim_kind) {
case ShimKind::Shop:
InitializeShop();
break;
case ShimKind::Login:
InitializeLogin();
break;
case ShimKind::Offline:
InitializeOffline();
break;
case ShimKind::Share:
InitializeShare();
break;
case ShimKind::Web:
InitializeWeb();
break;
case ShimKind::Wifi:
InitializeWifi();
break;
case ShimKind::Lobby:
InitializeLobby();
break;
default:
UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
break;
}
}
bool WebBrowser::TransactionComplete() const {
return complete;
}
ResultCode WebBrowser::GetStatus() const {
return status;
}
void WebBrowser::ExecuteInteractive() {
UNIMPLEMENTED_MSG("WebSession is not implemented");
}
void WebBrowser::Execute() {
switch (web_arg_header.shim_kind) {
case ShimKind::Shop:
ExecuteShop();
break;
case ShimKind::Login:
ExecuteLogin();
break;
case ShimKind::Offline:
ExecuteOffline();
break;
case ShimKind::Share:
ExecuteShare();
break;
case ShimKind::Web:
ExecuteWeb();
break;
case ShimKind::Wifi:
ExecuteWifi();
break;
case ShimKind::Lobby:
ExecuteLobby();
break;
default:
UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
WebBrowserExit(WebExitReason::EndButtonPressed);
break;
}
}
void WebBrowser::ExtractOfflineRomFS() {
LOG_DEBUG(Service_AM, "Extracting RomFS to {}",
Common::FS::PathToUTF8String(offline_cache_dir));
const auto extracted_romfs_dir =
FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
const auto temp_dir = system.GetFilesystem()->CreateDirectory(
Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite);
FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir);
}
void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) {
if ((web_arg_header.shim_kind == ShimKind::Share &&
web_applet_version >= WebAppletVersion::Version196608) ||
(web_arg_header.shim_kind == ShimKind::Web &&
web_applet_version >= WebAppletVersion::Version524288)) {
// TODO: Push Output TLVs instead of a WebCommonReturnValue
}
WebCommonReturnValue web_common_return_value;
web_common_return_value.exit_reason = exit_reason;
std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size());
web_common_return_value.last_url_size = last_url.size();
LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}",
exit_reason, last_url, last_url.size());
complete = true;
std::vector<u8> out_data(sizeof(WebCommonReturnValue));
std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
}
bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const {
return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end();
}
std::optional<std::vector<u8>> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) {
const auto map_it = web_arg_input_tlv_map.find(input_tlv_type);
if (map_it == web_arg_input_tlv_map.end()) {
return std::nullopt;
}
return map_it->second;
}
void WebBrowser::InitializeShop() {}
void WebBrowser::InitializeLogin() {}
void WebBrowser::InitializeOffline() {
const auto document_path =
ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value());
const auto document_kind =
ParseRawValue<DocumentKind>(GetInputTLVData(WebArgInputTLVType::DocumentKind).value());
std::string additional_paths;
switch (document_kind) {
case DocumentKind::OfflineHtmlPage:
default:
title_id = system.CurrentProcess()->GetTitleID();
nca_type = FileSys::ContentRecordType::HtmlDocument;
additional_paths = "html-document";
break;
case DocumentKind::ApplicationLegalInformation:
title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::ApplicationID).value());
nca_type = FileSys::ContentRecordType::LegalInformation;
break;
case DocumentKind::SystemDataPage:
title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::SystemDataID).value());
nca_type = FileSys::ContentRecordType::Data;
break;
}
static constexpr std::array<const char*, 3> RESOURCE_TYPES{
"manual",
"legal_information",
"system_data",
};
offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
fmt::format("offline_web_applet_{}/{:016X}",
RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id);
offline_document = Common::FS::ConcatPathSafe(
offline_cache_dir, fmt::format("{}/{}", additional_paths, document_path));
}
void WebBrowser::InitializeShare() {}
void WebBrowser::InitializeWeb() {
external_url = ParseStringValue(GetInputTLVData(WebArgInputTLVType::InitialURL).value());
}
void WebBrowser::InitializeWifi() {}
void WebBrowser::InitializeLobby() {}
void WebBrowser::ExecuteShop() {
LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
void WebBrowser::ExecuteLogin() {
LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
void WebBrowser::ExecuteOffline() {
const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document));
if (!Common::FS::Exists(main_url)) {
offline_romfs = GetOfflineRomFS(system, title_id, nca_type);
if (offline_romfs == nullptr) {
LOG_ERROR(Service_AM,
"RomFS with title_id={:016X} and nca_type={} cannot be extracted!", title_id,
nca_type);
WebBrowserExit(WebExitReason::WindowClosed);
return;
}
}
LOG_INFO(Service_AM, "Opening offline document at {}",
Common::FS::PathToUTF8String(offline_document));
frontend.OpenLocalWebPage(
Common::FS::PathToUTF8String(offline_document), [this] { ExtractOfflineRomFS(); },
[this](WebExitReason exit_reason, std::string last_url) {
WebBrowserExit(exit_reason, last_url);
});
}
void WebBrowser::ExecuteShare() {
LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
void WebBrowser::ExecuteWeb() {
LOG_INFO(Service_AM, "Opening external URL at {}", external_url);
frontend.OpenExternalWebPage(external_url,
[this](WebExitReason exit_reason, std::string last_url) {
WebBrowserExit(exit_reason, last_url);
});
}
void WebBrowser::ExecuteWifi() {
LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
void WebBrowser::ExecuteLobby() {
LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
WebBrowserExit(WebExitReason::EndButtonPressed);
}
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,88 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <filesystem>
#include <optional>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applet_web_browser_types.h"
#include "core/hle/service/am/applets/applets.h"
namespace Core {
class System;
}
namespace FileSys {
enum class ContentRecordType : u8;
}
namespace Service::AM::Applets {
class WebBrowser final : public Applet {
public:
WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::WebBrowserApplet& frontend_);
~WebBrowser() override;
void Initialize() override;
bool TransactionComplete() const override;
ResultCode GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void ExtractOfflineRomFS();
void WebBrowserExit(WebExitReason exit_reason, std::string last_url = "");
private:
bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const;
std::optional<std::vector<u8>> GetInputTLVData(WebArgInputTLVType input_tlv_type);
// Initializers for the various types of browser applets
void InitializeShop();
void InitializeLogin();
void InitializeOffline();
void InitializeShare();
void InitializeWeb();
void InitializeWifi();
void InitializeLobby();
// Executors for the various types of browser applets
void ExecuteShop();
void ExecuteLogin();
void ExecuteOffline();
void ExecuteShare();
void ExecuteWeb();
void ExecuteWifi();
void ExecuteLobby();
const Core::Frontend::WebBrowserApplet& frontend;
bool complete{false};
ResultCode status{ResultSuccess};
WebAppletVersion web_applet_version{};
WebArgHeader web_arg_header{};
WebArgInputTLVMap web_arg_input_tlv_map;
u64 title_id{};
FileSys::ContentRecordType nca_type{};
std::filesystem::path offline_cache_dir;
std::filesystem::path offline_document;
FileSys::VirtualFile offline_romfs;
std::string external_url;
Core::System& system;
};
} // namespace Service::AM::Applets

View File

@@ -0,0 +1,178 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <unordered_map>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
namespace Service::AM::Applets {
enum class WebAppletVersion : u32_le {
Version0 = 0x0, // Only used by WifiWebAuthApplet
Version131072 = 0x20000, // 1.0.0 - 2.3.0
Version196608 = 0x30000, // 3.0.0 - 4.1.0
Version327680 = 0x50000, // 5.0.0 - 5.1.0
Version393216 = 0x60000, // 6.0.0 - 7.0.1
Version524288 = 0x80000, // 8.0.0+
};
enum class ShimKind : u32 {
Shop = 1,
Login = 2,
Offline = 3,
Share = 4,
Web = 5,
Wifi = 6,
Lobby = 7,
};
enum class WebExitReason : u32 {
EndButtonPressed = 0,
BackButtonPressed = 1,
ExitRequested = 2,
CallbackURL = 3,
WindowClosed = 4,
ErrorDialog = 7,
};
enum class WebArgInputTLVType : u16 {
InitialURL = 0x1,
CallbackURL = 0x3,
CallbackableURL = 0x4,
ApplicationID = 0x5,
DocumentPath = 0x6,
DocumentKind = 0x7,
SystemDataID = 0x8,
ShareStartPage = 0x9,
Whitelist = 0xA,
News = 0xB,
UserID = 0xE,
AlbumEntry0 = 0xF,
ScreenShotEnabled = 0x10,
EcClientCertEnabled = 0x11,
PlayReportEnabled = 0x13,
BootDisplayKind = 0x17,
BackgroundKind = 0x18,
FooterEnabled = 0x19,
PointerEnabled = 0x1A,
LeftStickMode = 0x1B,
KeyRepeatFrame1 = 0x1C,
KeyRepeatFrame2 = 0x1D,
BootAsMediaPlayerInverted = 0x1E,
DisplayURLKind = 0x1F,
BootAsMediaPlayer = 0x21,
ShopJumpEnabled = 0x22,
MediaAutoPlayEnabled = 0x23,
LobbyParameter = 0x24,
ApplicationAlbumEntry = 0x26,
JsExtensionEnabled = 0x27,
AdditionalCommentText = 0x28,
TouchEnabledOnContents = 0x29,
UserAgentAdditionalString = 0x2A,
AdditionalMediaData0 = 0x2B,
MediaPlayerAutoCloseEnabled = 0x2C,
PageCacheEnabled = 0x2D,
WebAudioEnabled = 0x2E,
YouTubeVideoWhitelist = 0x31,
FooterFixedKind = 0x32,
PageFadeEnabled = 0x33,
MediaCreatorApplicationRatingAge = 0x34,
BootLoadingIconEnabled = 0x35,
PageScrollIndicatorEnabled = 0x36,
MediaPlayerSpeedControlEnabled = 0x37,
AlbumEntry1 = 0x38,
AlbumEntry2 = 0x39,
AlbumEntry3 = 0x3A,
AdditionalMediaData1 = 0x3B,
AdditionalMediaData2 = 0x3C,
AdditionalMediaData3 = 0x3D,
BootFooterButton = 0x3E,
OverrideWebAudioVolume = 0x3F,
OverrideMediaAudioVolume = 0x40,
BootMode = 0x41,
WebSessionEnabled = 0x42,
MediaPlayerOfflineEnabled = 0x43,
};
enum class WebArgOutputTLVType : u16 {
ShareExitReason = 0x1,
LastURL = 0x2,
LastURLSize = 0x3,
SharePostResult = 0x4,
PostServiceName = 0x5,
PostServiceNameSize = 0x6,
PostID = 0x7,
PostIDSize = 0x8,
MediaPlayerAutoClosedByCompletion = 0x9,
};
enum class DocumentKind : u32 {
OfflineHtmlPage = 1,
ApplicationLegalInformation = 2,
SystemDataPage = 3,
};
enum class ShareStartPage : u32 {
Default,
Settings,
};
enum class BootDisplayKind : u32 {
Default,
White,
Black,
};
enum class BackgroundKind : u32 {
Default,
};
enum class LeftStickMode : u32 {
Pointer,
Cursor,
};
enum class WebSessionBootMode : u32 {
AllForeground,
AllForegroundInitiallyHidden,
};
struct WebArgHeader {
u16 total_tlv_entries{};
INSERT_PADDING_BYTES(2);
ShimKind shim_kind{};
};
static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
struct WebArgInputTLV {
WebArgInputTLVType input_tlv_type{};
u16 arg_data_size{};
INSERT_PADDING_WORDS(1);
};
static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size.");
struct WebArgOutputTLV {
WebArgOutputTLVType output_tlv_type{};
u16 arg_data_size{};
INSERT_PADDING_WORDS(1);
};
static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size.");
struct WebCommonReturnValue {
WebExitReason exit_reason{};
INSERT_PADDING_WORDS(1);
std::array<char, 0x1000> last_url{};
u64 last_url_size{};
};
static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
} // namespace Service::AM::Applets

View File

@@ -17,13 +17,13 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/applets/applet_software_keyboard.h"
#include "core/hle/service/am/applets/applet_web_browser.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/applets/controller.h"
#include "core/hle/service/am/applets/error.h"
#include "core/hle/service/am/applets/general_backend.h"
#include "core/hle/service/am/applets/profile_select.h"
#include "core/hle/service/am/applets/software_keyboard.h"
#include "core/hle/service/am/applets/web_browser.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Applets {