early-access version 1880
This commit is contained in:
@@ -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"
|
||||
|
253
src/core/hle/service/am/applets/applet_controller.cpp
Executable file
253
src/core/hle/service/am/applets/applet_controller.cpp
Executable 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
|
137
src/core/hle/service/am/applets/applet_controller.h
Executable file
137
src/core/hle/service/am/applets/applet_controller.h
Executable 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
|
194
src/core/hle/service/am/applets/applet_error.cpp
Executable file
194
src/core/hle/service/am/applets/applet_error.cpp
Executable 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
|
53
src/core/hle/service/am/applets/applet_error.h
Executable file
53
src/core/hle/service/am/applets/applet_error.h
Executable 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
|
255
src/core/hle/service/am/applets/applet_general_backend.cpp
Executable file
255
src/core/hle/service/am/applets/applet_general_backend.cpp
Executable 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
|
90
src/core/hle/service/am/applets/applet_general_backend.h
Executable file
90
src/core/hle/service/am/applets/applet_general_backend.h
Executable 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
|
78
src/core/hle/service/am/applets/applet_profile_select.cpp
Executable file
78
src/core/hle/service/am/applets/applet_profile_select.cpp
Executable 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
|
59
src/core/hle/service/am/applets/applet_profile_select.h
Executable file
59
src/core/hle/service/am/applets/applet_profile_select.h
Executable 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
|
1082
src/core/hle/service/am/applets/applet_software_keyboard.cpp
Executable file
1082
src/core/hle/service/am/applets/applet_software_keyboard.cpp
Executable file
File diff suppressed because it is too large
Load Diff
166
src/core/hle/service/am/applets/applet_software_keyboard.h
Executable file
166
src/core/hle/service/am/applets/applet_software_keyboard.h
Executable 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
|
295
src/core/hle/service/am/applets/applet_software_keyboard_types.h
Executable file
295
src/core/hle/service/am/applets/applet_software_keyboard_types.h
Executable 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
|
474
src/core/hle/service/am/applets/applet_web_browser.cpp
Executable file
474
src/core/hle/service/am/applets/applet_web_browser.cpp
Executable 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
|
88
src/core/hle/service/am/applets/applet_web_browser.h
Executable file
88
src/core/hle/service/am/applets/applet_web_browser.h
Executable 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
|
178
src/core/hle/service/am/applets/applet_web_browser_types.h
Executable file
178
src/core/hle/service/am/applets/applet_web_browser_types.h
Executable 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
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user