summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/am/am.cpp10
-rw-r--r--src/core/hle/service/am/applets/applet_controller.cpp272
-rw-r--r--src/core/hle/service/am/applets/applet_controller.h148
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp194
-rw-r--r--src/core/hle/service/am/applets/applet_error.h (renamed from src/core/hle/service/am/applets/error.h)0
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.cpp255
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.h (renamed from src/core/hle/service/am/applets/general_backend.h)0
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.cpp78
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.h (renamed from src/core/hle/service/am/applets/profile_select.h)0
-rw-r--r--src/core/hle/service/am/applets/applet_software_keyboard.cpp1082
-rw-r--r--src/core/hle/service/am/applets/applet_software_keyboard.h166
-rw-r--r--src/core/hle/service/am/applets/applet_software_keyboard_types.h (renamed from src/core/hle/service/am/applets/software_keyboard_types.h)0
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp487
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.h88
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser_types.h (renamed from src/core/hle/service/am/applets/web_types.h)0
-rw-r--r--src/core/hle/service/am/applets/applets.cpp12
-rw-r--r--src/core/hle/service/am/applets/controller.cpp253
-rw-r--r--src/core/hle/service/am/applets/controller.h137
-rw-r--r--src/core/hle/service/am/applets/error.cpp194
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp255
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp78
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp1082
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h166
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp474
-rw-r--r--src/core/hle/service/am/applets/web_browser.h88
25 files changed, 2781 insertions, 2738 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 23ebc1138..a538f82e3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -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"
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp
new file mode 100644
index 000000000..2721679c1
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_controller.cpp
@@ -0,0 +1,272 @@
+// 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;
+ case sizeof(ControllerKeyRemappingArg):
+ controller_private_arg.mode =
+ ControllerSupportMode::ShowControllerKeyRemappingForSystem;
+ 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.mode ==
+ ControllerSupportMode::ShowControllerKeyRemappingForSystem)) {
+ 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:
+ case ControllerAppletVersion::Version8:
+ 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;
+ }
+ case ControllerSupportMode::ShowControllerKeyRemappingForSystem: {
+ const auto remapping_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(remapping_arg_storage != nullptr);
+
+ const auto& remapping_arg = remapping_arg_storage->GetData();
+ ASSERT(remapping_arg.size() == sizeof(ControllerKeyRemappingArg));
+
+ std::memcpy(&controller_key_remapping_arg, remapping_arg.data(), remapping_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:
+ case ControllerAppletVersion::Version8:
+ 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:
+ case ControllerSupportMode::ShowControllerKeyRemappingForSystem:
+ 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
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h
new file mode 100644
index 000000000..0a34c4fc0
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_controller.h
@@ -0,0 +1,148 @@
+// 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 - 10.2.0
+ Version8 = 0x8, // 11.0.0+
+};
+
+enum class ControllerSupportMode : u8 {
+ ShowControllerSupport,
+ ShowControllerStrapGuide,
+ ShowControllerFirmwareUpdate,
+ ShowControllerKeyRemappingForSystem,
+
+ 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, 0x8
+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 ControllerKeyRemappingArg {
+ u64 unknown{};
+ u32 unknown_2{};
+ INSERT_PADDING_WORDS(1);
+};
+static_assert(sizeof(ControllerKeyRemappingArg) == 0x10,
+ "ControllerKeyRemappingArg 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;
+ ControllerKeyRemappingArg controller_key_remapping_arg;
+ bool complete{false};
+ ResultCode status{ResultSuccess};
+ bool is_single_mode{false};
+ std::vector<u8> out_data;
+};
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
new file mode 100644
index 000000000..ef6854d62
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -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
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/applet_error.h
index 8aa9046a5..8aa9046a5 100644
--- a/src/core/hle/service/am/applets/error.h
+++ b/src/core/hle/service/am/applets/applet_error.h
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp
new file mode 100644
index 000000000..0f413f9a0
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_general_backend.cpp
@@ -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
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/applet_general_backend.h
index 7496ded88..7496ded88 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/applet_general_backend.h
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp
new file mode 100644
index 000000000..bdc21778e
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_profile_select.cpp
@@ -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
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h
index 8fb76e6c4..8fb76e6c4 100644
--- a/src/core/hle/service/am/applets/profile_select.h
+++ b/src/core/hle/service/am/applets/applet_profile_select.h
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp
new file mode 100644
index 000000000..7cae90609
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp
@@ -0,0 +1,1082 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/frontend/applets/software_keyboard.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/applet_software_keyboard.h"
+
+namespace Service::AM::Applets {
+
+namespace {
+
+// The maximum number of UTF-16 characters that can be input into the swkbd text field.
+constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500;
+
+constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType);
+constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4;
+constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC;
+
+constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) {
+ switch (text_check_result) {
+ case SwkbdTextCheckResult::Success:
+ return "Success";
+ case SwkbdTextCheckResult::Failure:
+ return "Failure";
+ case SwkbdTextCheckResult::Confirm:
+ return "Confirm";
+ case SwkbdTextCheckResult::Silent:
+ return "Silent";
+ default:
+ UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result);
+ return "Unknown";
+ }
+}
+
+void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply_type) {
+ std::memcpy(reply.data(), &state, sizeof(SwkbdState));
+ std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType));
+}
+
+} // Anonymous namespace
+
+SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
+ Core::Frontend::SoftwareKeyboardApplet& frontend_)
+ : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
+
+SoftwareKeyboard::~SoftwareKeyboard() = default;
+
+void SoftwareKeyboard::Initialize() {
+ Applet::Initialize();
+
+ LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
+ applet_mode);
+
+ 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);
+
+ swkbd_applet_version = SwkbdAppletVersion{common_args.library_version};
+
+ switch (applet_mode) {
+ case LibraryAppletMode::AllForeground:
+ InitializeForeground();
+ break;
+ case LibraryAppletMode::Background:
+ case LibraryAppletMode::BackgroundIndirectDisplay:
+ InitializeBackground(applet_mode);
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode);
+ break;
+ }
+}
+
+bool SoftwareKeyboard::TransactionComplete() const {
+ return complete;
+}
+
+ResultCode SoftwareKeyboard::GetStatus() const {
+ return status;
+}
+
+void SoftwareKeyboard::ExecuteInteractive() {
+ if (complete) {
+ return;
+ }
+
+ if (is_background) {
+ ProcessInlineKeyboardRequest();
+ } else {
+ ProcessTextCheck();
+ }
+}
+
+void SoftwareKeyboard::Execute() {
+ if (complete) {
+ return;
+ }
+
+ if (is_background) {
+ return;
+ }
+
+ ShowNormalKeyboard();
+}
+
+void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
+ if (complete) {
+ return;
+ }
+
+ if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
+ SubmitForTextCheck(submitted_text);
+ } else {
+ SubmitNormalOutputAndExit(result, submitted_text);
+ }
+}
+
+void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
+ s32 cursor_position) {
+ if (complete) {
+ return;
+ }
+
+ current_text = std::move(submitted_text);
+ current_cursor_position = cursor_position;
+
+ if (inline_use_utf8) {
+ switch (reply_type) {
+ case SwkbdReplyType::ChangedString:
+ reply_type = SwkbdReplyType::ChangedStringUtf8;
+ break;
+ case SwkbdReplyType::MovedCursor:
+ reply_type = SwkbdReplyType::MovedCursorUtf8;
+ break;
+ case SwkbdReplyType::DecidedEnter:
+ reply_type = SwkbdReplyType::DecidedEnterUtf8;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (use_changed_string_v2) {
+ switch (reply_type) {
+ case SwkbdReplyType::ChangedString:
+ reply_type = SwkbdReplyType::ChangedStringV2;
+ break;
+ case SwkbdReplyType::ChangedStringUtf8:
+ reply_type = SwkbdReplyType::ChangedStringUtf8V2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (use_moved_cursor_v2) {
+ switch (reply_type) {
+ case SwkbdReplyType::MovedCursor:
+ reply_type = SwkbdReplyType::MovedCursorV2;
+ break;
+ case SwkbdReplyType::MovedCursorUtf8:
+ reply_type = SwkbdReplyType::MovedCursorUtf8V2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ SendReply(reply_type);
+}
+
+void SoftwareKeyboard::InitializeForeground() {
+ LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet.");
+
+ is_background = false;
+
+ const auto swkbd_config_storage = broker.PopNormalDataToApplet();
+ ASSERT(swkbd_config_storage != nullptr);
+
+ const auto& swkbd_config_data = swkbd_config_storage->GetData();
+ ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon));
+
+ std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon));
+
+ switch (swkbd_applet_version) {
+ case SwkbdAppletVersion::Version5:
+ case SwkbdAppletVersion::Version65542:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld));
+ std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigOld));
+ break;
+ case SwkbdAppletVersion::Version196615:
+ case SwkbdAppletVersion::Version262152:
+ case SwkbdAppletVersion::Version327689:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2));
+ std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigOld2));
+ break;
+ case SwkbdAppletVersion::Version393227:
+ case SwkbdAppletVersion::Version524301:
+ ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
+ std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigNew));
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version,
+ swkbd_config_data.size());
+ ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
+ std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
+ sizeof(SwkbdConfigNew));
+ break;
+ }
+
+ const auto work_buffer_storage = broker.PopNormalDataToApplet();
+ ASSERT(work_buffer_storage != nullptr);
+
+ if (swkbd_config_common.initial_string_length == 0) {
+ InitializeFrontendKeyboard();
+ return;
+ }
+
+ const auto& work_buffer = work_buffer_storage->GetData();
+
+ std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length);
+
+ std::memcpy(initial_string.data(),
+ work_buffer.data() + swkbd_config_common.initial_string_offset,
+ swkbd_config_common.initial_string_length * sizeof(char16_t));
+
+ initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(),
+ initial_string.size());
+
+ LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text));
+
+ InitializeFrontendKeyboard();
+}
+
+void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
+ LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
+
+ is_background = true;
+
+ const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
+ ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
+
+ const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
+ ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg));
+
+ std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(),
+ swkbd_inline_initialize_arg.size());
+
+ if (swkbd_initialize_arg.library_applet_mode_flag) {
+ ASSERT(library_applet_mode == LibraryAppletMode::Background);
+ } else {
+ ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
+ }
+}
+
+void SoftwareKeyboard::ProcessTextCheck() {
+ const auto text_check_storage = broker.PopInteractiveDataToApplet();
+ ASSERT(text_check_storage != nullptr);
+
+ const auto& text_check_data = text_check_storage->GetData();
+ ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck));
+
+ SwkbdTextCheck swkbd_text_check;
+
+ std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
+
+ std::u16string text_check_message =
+ swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
+ swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm
+ ? Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_text_check.text_check_message.data(),
+ swkbd_text_check.text_check_message.size())
+ : u"";
+
+ LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
+ GetTextCheckResultName(swkbd_text_check.text_check_result),
+ Common::UTF16ToUTF8(text_check_message));
+
+ switch (swkbd_text_check.text_check_result) {
+ case SwkbdTextCheckResult::Success:
+ SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text);
+ break;
+ case SwkbdTextCheckResult::Failure:
+ ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message));
+ break;
+ case SwkbdTextCheckResult::Confirm:
+ ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message));
+ break;
+ case SwkbdTextCheckResult::Silent:
+ default:
+ break;
+ }
+}
+
+void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
+ const auto request_data_storage = broker.PopInteractiveDataToApplet();
+ ASSERT(request_data_storage != nullptr);
+
+ const auto& request_data = request_data_storage->GetData();
+ ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand));
+
+ SwkbdRequestCommand request_command;
+
+ std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand));
+
+ switch (request_command) {
+ case SwkbdRequestCommand::Finalize:
+ RequestFinalize(request_data);
+ break;
+ case SwkbdRequestCommand::SetUserWordInfo:
+ RequestSetUserWordInfo(request_data);
+ break;
+ case SwkbdRequestCommand::SetCustomizeDic:
+ RequestSetCustomizeDic(request_data);
+ break;
+ case SwkbdRequestCommand::Calc:
+ RequestCalc(request_data);
+ break;
+ case SwkbdRequestCommand::SetCustomizedDictionaries:
+ RequestSetCustomizedDictionaries(request_data);
+ break;
+ case SwkbdRequestCommand::UnsetCustomizedDictionaries:
+ RequestUnsetCustomizedDictionaries(request_data);
+ break;
+ case SwkbdRequestCommand::SetChangedStringV2Flag:
+ RequestSetChangedStringV2Flag(request_data);
+ break;
+ case SwkbdRequestCommand::SetMovedCursorV2Flag:
+ RequestSetMovedCursorV2Flag(request_data);
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command);
+ break;
+ }
+}
+
+void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
+ std::u16string submitted_text) {
+ std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE);
+
+ if (swkbd_config_common.use_utf8) {
+ std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text);
+
+ LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result,
+ utf8_submitted_text);
+
+ std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
+ std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(),
+ utf8_submitted_text.size());
+ } else {
+ LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result,
+ Common::UTF16ToUTF8(submitted_text));
+
+ std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
+ std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(),
+ submitted_text.size() * sizeof(char16_t));
+ }
+
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+
+ ExitKeyboard();
+}
+
+void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
+ current_text = std::move(submitted_text);
+
+ std::vector<u8> out_data(sizeof(u64) + STRING_BUFFER_SIZE);
+
+ if (swkbd_config_common.use_utf8) {
+ std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text);
+ const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size();
+
+ LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size,
+ utf8_submitted_text);
+
+ std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
+ std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(),
+ utf8_submitted_text.size());
+ } else {
+ const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t);
+
+ LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size,
+ Common::UTF16ToUTF8(current_text));
+
+ std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
+ std::memcpy(out_data.data() + sizeof(u64), current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ }
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+}
+
+void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
+ switch (reply_type) {
+ case SwkbdReplyType::FinishedInitialize:
+ ReplyFinishedInitialize();
+ break;
+ case SwkbdReplyType::Default:
+ ReplyDefault();
+ break;
+ case SwkbdReplyType::ChangedString:
+ ReplyChangedString();
+ break;
+ case SwkbdReplyType::MovedCursor:
+ ReplyMovedCursor();
+ break;
+ case SwkbdReplyType::MovedTab:
+ ReplyMovedTab();
+ break;
+ case SwkbdReplyType::DecidedEnter:
+ ReplyDecidedEnter();
+ break;
+ case SwkbdReplyType::DecidedCancel:
+ ReplyDecidedCancel();
+ break;
+ case SwkbdReplyType::ChangedStringUtf8:
+ ReplyChangedStringUtf8();
+ break;
+ case SwkbdReplyType::MovedCursorUtf8:
+ ReplyMovedCursorUtf8();
+ break;
+ case SwkbdReplyType::DecidedEnterUtf8:
+ ReplyDecidedEnterUtf8();
+ break;
+ case SwkbdReplyType::UnsetCustomizeDic:
+ ReplyUnsetCustomizeDic();
+ break;
+ case SwkbdReplyType::ReleasedUserWordInfo:
+ ReplyReleasedUserWordInfo();
+ break;
+ case SwkbdReplyType::UnsetCustomizedDictionaries:
+ ReplyUnsetCustomizedDictionaries();
+ break;
+ case SwkbdReplyType::ChangedStringV2:
+ ReplyChangedStringV2();
+ break;
+ case SwkbdReplyType::MovedCursorV2:
+ ReplyMovedCursorV2();
+ break;
+ case SwkbdReplyType::ChangedStringUtf8V2:
+ ReplyChangedStringUtf8V2();
+ break;
+ case SwkbdReplyType::MovedCursorUtf8V2:
+ ReplyMovedCursorUtf8V2();
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type);
+ ReplyDefault();
+ break;
+ }
+}
+
+void SoftwareKeyboard::ChangeState(SwkbdState state) {
+ swkbd_state = state;
+
+ ReplyDefault();
+}
+
+void SoftwareKeyboard::InitializeFrontendKeyboard() {
+ if (is_background) {
+ const auto& appear_arg = swkbd_calc_arg.appear_arg;
+
+ std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ appear_arg.ok_text.data(), appear_arg.ok_text.size());
+
+ const u32 max_text_length =
+ appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? appear_arg.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length =
+ appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
+
+ const s32 initial_cursor_position =
+ current_cursor_position > 0 ? current_cursor_position : 0;
+
+ const auto text_draw_type =
+ max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
+
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters{
+ .ok_text{std::move(ok_text)},
+ .header_text{},
+ .sub_text{},
+ .guide_text{},
+ .initial_text{current_text},
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .initial_cursor_position{initial_cursor_position},
+ .type{appear_arg.type},
+ .password_mode{SwkbdPasswordMode::Disabled},
+ .text_draw_type{text_draw_type},
+ .key_disable_flags{appear_arg.key_disable_flags},
+ .use_blur_background{false},
+ .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
+ .enable_return_button{appear_arg.enable_return_button},
+ .disable_cancel_button{appear_arg.disable_cancel_button},
+ };
+
+ frontend.InitializeKeyboard(
+ true, std::move(initialize_parameters), {},
+ [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
+ SubmitTextInline(reply_type, submitted_text, cursor_position);
+ });
+ } else {
+ std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
+
+ std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
+
+ std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
+
+ std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
+
+ const u32 max_text_length =
+ swkbd_config_common.max_text_length > 0 &&
+ swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? swkbd_config_common.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
+ ? swkbd_config_common.min_text_length
+ : 0;
+
+ const s32 initial_cursor_position = [this] {
+ switch (swkbd_config_common.initial_cursor_position) {
+ case SwkbdInitialCursorPosition::Start:
+ default:
+ return 0;
+ case SwkbdInitialCursorPosition::End:
+ return static_cast<s32>(initial_text.size());
+ }
+ }();
+
+ const auto text_draw_type = [this, max_text_length] {
+ switch (swkbd_config_common.text_draw_type) {
+ case SwkbdTextDrawType::Line:
+ default:
+ return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
+ case SwkbdTextDrawType::Box:
+ case SwkbdTextDrawType::DownloadCode:
+ return swkbd_config_common.text_draw_type;
+ }
+ }();
+
+ const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box
+ ? swkbd_config_common.enable_return_button
+ : false;
+
+ const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
+ ? swkbd_config_new.disable_cancel_button
+ : false;
+
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters{
+ .ok_text{std::move(ok_text)},
+ .header_text{std::move(header_text)},
+ .sub_text{std::move(sub_text)},
+ .guide_text{std::move(guide_text)},
+ .initial_text{initial_text},
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .initial_cursor_position{initial_cursor_position},
+ .type{swkbd_config_common.type},
+ .password_mode{swkbd_config_common.password_mode},
+ .text_draw_type{text_draw_type},
+ .key_disable_flags{swkbd_config_common.key_disable_flags},
+ .use_blur_background{swkbd_config_common.use_blur_background},
+ .enable_backspace_button{true},
+ .enable_return_button{enable_return_button},
+ .disable_cancel_button{disable_cancel_button},
+ };
+
+ frontend.InitializeKeyboard(false, std::move(initialize_parameters),
+ [this](SwkbdResult result, std::u16string submitted_text) {
+ SubmitTextNormal(result, submitted_text);
+ },
+ {});
+ }
+}
+
+void SoftwareKeyboard::ShowNormalKeyboard() {
+ frontend.ShowNormalKeyboard();
+}
+
+void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) {
+ frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message));
+}
+
+void SoftwareKeyboard::ShowInlineKeyboard() {
+ if (swkbd_state != SwkbdState::InitializedIsHidden) {
+ return;
+ }
+
+ ChangeState(SwkbdState::InitializedIsAppearing);
+
+ const auto& appear_arg = swkbd_calc_arg.appear_arg;
+
+ const u32 max_text_length =
+ appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
+ ? appear_arg.max_text_length
+ : DEFAULT_MAX_TEXT_LENGTH;
+
+ const u32 min_text_length =
+ appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
+
+ Core::Frontend::InlineAppearParameters appear_parameters{
+ .max_text_length{max_text_length},
+ .min_text_length{min_text_length},
+ .key_top_scale_x{swkbd_calc_arg.key_top_scale_x},
+ .key_top_scale_y{swkbd_calc_arg.key_top_scale_y},
+ .key_top_translate_x{swkbd_calc_arg.key_top_translate_x},
+ .key_top_translate_y{swkbd_calc_arg.key_top_translate_y},
+ .type{appear_arg.type},
+ .key_disable_flags{appear_arg.key_disable_flags},
+ .key_top_as_floating{swkbd_calc_arg.key_top_as_floating},
+ .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
+ .enable_return_button{appear_arg.enable_return_button},
+ .disable_cancel_button{appear_arg.disable_cancel_button},
+ };
+
+ frontend.ShowInlineKeyboard(std::move(appear_parameters));
+
+ ChangeState(SwkbdState::InitializedIsShown);
+}
+
+void SoftwareKeyboard::HideInlineKeyboard() {
+ if (swkbd_state != SwkbdState::InitializedIsShown) {
+ return;
+ }
+
+ ChangeState(SwkbdState::InitializedIsDisappearing);
+
+ frontend.HideInlineKeyboard();
+
+ ChangeState(SwkbdState::InitializedIsHidden);
+}
+
+void SoftwareKeyboard::InlineTextChanged() {
+ Core::Frontend::InlineTextParameters text_parameters{
+ .input_text{current_text},
+ .cursor_position{current_cursor_position},
+ };
+
+ frontend.InlineTextChanged(std::move(text_parameters));
+}
+
+void SoftwareKeyboard::ExitKeyboard() {
+ complete = true;
+ status = ResultSuccess;
+
+ frontend.ExitKeyboard();
+
+ broker.SignalStateChanged();
+}
+
+// Inline Software Keyboard Requests
+
+void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: Finalize");
+
+ ChangeState(SwkbdState::NotInitialized);
+
+ ExitKeyboard();
+}
+
+void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
+}
+
+void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented.");
+}
+
+void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: Calc");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg));
+
+ std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand),
+ sizeof(SwkbdCalcArg));
+
+ if (swkbd_calc_arg.flags.set_input_text) {
+ current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size());
+ }
+
+ if (swkbd_calc_arg.flags.set_cursor_position) {
+ current_cursor_position = swkbd_calc_arg.cursor_position;
+ }
+
+ if (swkbd_calc_arg.flags.set_utf8_mode) {
+ inline_use_utf8 = swkbd_calc_arg.utf8_mode;
+ }
+
+ if (swkbd_state <= SwkbdState::InitializedIsHidden &&
+ swkbd_calc_arg.flags.unset_customize_dic) {
+ ReplyUnsetCustomizeDic();
+ }
+
+ if (swkbd_state <= SwkbdState::InitializedIsHidden &&
+ swkbd_calc_arg.flags.unset_user_word_info) {
+ ReplyReleasedUserWordInfo();
+ }
+
+ if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) {
+ InitializeFrontendKeyboard();
+
+ ChangeState(SwkbdState::InitializedIsHidden);
+
+ ReplyFinishedInitialize();
+ }
+
+ if (!swkbd_calc_arg.flags.set_initialize_arg &&
+ (swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) {
+ InlineTextChanged();
+ }
+
+ if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) {
+ ShowInlineKeyboard();
+ return;
+ }
+
+ if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) {
+ HideInlineKeyboard();
+ return;
+ }
+}
+
+void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented.");
+}
+
+void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) {
+ LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries");
+
+ ReplyUnsetCustomizedDictionaries();
+}
+
+void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
+
+ std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
+}
+
+void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data) {
+ LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag");
+
+ ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
+
+ std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
+}
+
+// Inline Software Keyboard Replies
+
+void SoftwareKeyboard::ReplyFinishedInitialize() {
+ LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDefault() {
+ LOG_DEBUG(Service_AM, "Sending Reply: Default");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedString() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedString");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursor() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedTab() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedTab");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab);
+
+ const SwkbdMovedTabArg moved_tab_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
+ sizeof(SwkbdMovedTabArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDecidedEnter() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter);
+
+ const SwkbdDecidedEnterArg decided_enter_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
+ sizeof(SwkbdDecidedEnterArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyDecidedCancel() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyChangedStringUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursorUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
+ LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg));
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdDecidedEnterArg decided_enter_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ };
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
+ sizeof(SwkbdDecidedEnterArg));
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+
+ HideInlineKeyboard();
+}
+
+void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
+ LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
+ LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedStringV2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursorV2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
+ current_text.size() * sizeof(char16_t));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdChangedStringArg changed_string_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .dictionary_start_cursor_position{-1},
+ .dictionary_end_cursor_position{-1},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
+ sizeof(SwkbdChangedStringArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
+ LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2");
+
+ std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
+
+ SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2);
+
+ std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
+
+ const SwkbdMovedCursorArg moved_cursor_arg{
+ .text_length{static_cast<u32>(current_text.size())},
+ .cursor_position{current_cursor_position},
+ };
+
+ constexpr u8 flag = 0;
+
+ std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
+ sizeof(SwkbdMovedCursorArg));
+ std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
+ &flag, 1);
+
+ broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/applets/applet_software_keyboard.h
new file mode 100644
index 000000000..9aef1bf11
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_software_keyboard.h
@@ -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
diff --git a/src/core/hle/service/am/applets/software_keyboard_types.h b/src/core/hle/service/am/applets/applet_software_keyboard_types.h
index 21aa8e800..21aa8e800 100644
--- a/src/core/hle/service/am/applets/software_keyboard_types.h
+++ b/src/core/hle/service/am/applets/applet_software_keyboard_types.h
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
new file mode 100644
index 000000000..35f194961
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -0,0 +1,487 @@
+// 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);
+}
+
+std::string ResolveURL(const std::string& url) {
+ const auto index = url.find_first_of('%');
+
+ if (index == std::string::npos) {
+ return url;
+ }
+
+ return url.substr(0, index) + "lp1" + url.substr(index + 1);
+}
+
+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());
+
+ // Resolve Nintendo CDN URLs.
+ external_url = ResolveURL(external_url);
+}
+
+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
diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h
new file mode 100644
index 000000000..4f9e81b79
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_web_browser.h
@@ -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
diff --git a/src/core/hle/service/am/applets/web_types.h b/src/core/hle/service/am/applets/applet_web_browser_types.h
index 419c2bf79..419c2bf79 100644
--- a/src/core/hle/service/am/applets/web_types.h
+++ b/src/core/hle/service/am/applets/applet_web_browser_types.h
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index ae995df6b..2b7685d42 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -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 {
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
deleted file mode 100644
index 218c8d1e4..000000000
--- a/src/core/hle/service/am/applets/controller.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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/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
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
deleted file mode 100644
index 20617e91f..000000000
--- a/src/core/hle/service/am/applets/controller.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
deleted file mode 100644
index c724e5d5b..000000000
--- a/src/core/hle/service/am/applets/error.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-// 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/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
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
deleted file mode 100644
index 9fcb9f95b..000000000
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-// 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/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
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
deleted file mode 100644
index 37048be26..000000000
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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/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
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
deleted file mode 100644
index 00dfe1675..000000000
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ /dev/null
@@ -1,1082 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/frontend/applets/software_keyboard.h"
-#include "core/hle/service/am/am.h"
-#include "core/hle/service/am/applets/software_keyboard.h"
-
-namespace Service::AM::Applets {
-
-namespace {
-
-// The maximum number of UTF-16 characters that can be input into the swkbd text field.
-constexpr u32 DEFAULT_MAX_TEXT_LENGTH = 500;
-
-constexpr std::size_t REPLY_BASE_SIZE = sizeof(SwkbdState) + sizeof(SwkbdReplyType);
-constexpr std::size_t REPLY_UTF8_SIZE = 0x7D4;
-constexpr std::size_t REPLY_UTF16_SIZE = 0x3EC;
-
-constexpr const char* GetTextCheckResultName(SwkbdTextCheckResult text_check_result) {
- switch (text_check_result) {
- case SwkbdTextCheckResult::Success:
- return "Success";
- case SwkbdTextCheckResult::Failure:
- return "Failure";
- case SwkbdTextCheckResult::Confirm:
- return "Confirm";
- case SwkbdTextCheckResult::Silent:
- return "Silent";
- default:
- UNIMPLEMENTED_MSG("Unknown TextCheckResult={}", text_check_result);
- return "Unknown";
- }
-}
-
-void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply_type) {
- std::memcpy(reply.data(), &state, sizeof(SwkbdState));
- std::memcpy(reply.data() + sizeof(SwkbdState), &reply_type, sizeof(SwkbdReplyType));
-}
-
-} // Anonymous namespace
-
-SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
- Core::Frontend::SoftwareKeyboardApplet& frontend_)
- : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
-
-SoftwareKeyboard::~SoftwareKeyboard() = default;
-
-void SoftwareKeyboard::Initialize() {
- Applet::Initialize();
-
- LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
- applet_mode);
-
- 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);
-
- swkbd_applet_version = SwkbdAppletVersion{common_args.library_version};
-
- switch (applet_mode) {
- case LibraryAppletMode::AllForeground:
- InitializeForeground();
- break;
- case LibraryAppletMode::Background:
- case LibraryAppletMode::BackgroundIndirectDisplay:
- InitializeBackground(applet_mode);
- break;
- default:
- UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode);
- break;
- }
-}
-
-bool SoftwareKeyboard::TransactionComplete() const {
- return complete;
-}
-
-ResultCode SoftwareKeyboard::GetStatus() const {
- return status;
-}
-
-void SoftwareKeyboard::ExecuteInteractive() {
- if (complete) {
- return;
- }
-
- if (is_background) {
- ProcessInlineKeyboardRequest();
- } else {
- ProcessTextCheck();
- }
-}
-
-void SoftwareKeyboard::Execute() {
- if (complete) {
- return;
- }
-
- if (is_background) {
- return;
- }
-
- ShowNormalKeyboard();
-}
-
-void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
- if (complete) {
- return;
- }
-
- if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
- SubmitForTextCheck(submitted_text);
- } else {
- SubmitNormalOutputAndExit(result, submitted_text);
- }
-}
-
-void SoftwareKeyboard::SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
- s32 cursor_position) {
- if (complete) {
- return;
- }
-
- current_text = std::move(submitted_text);
- current_cursor_position = cursor_position;
-
- if (inline_use_utf8) {
- switch (reply_type) {
- case SwkbdReplyType::ChangedString:
- reply_type = SwkbdReplyType::ChangedStringUtf8;
- break;
- case SwkbdReplyType::MovedCursor:
- reply_type = SwkbdReplyType::MovedCursorUtf8;
- break;
- case SwkbdReplyType::DecidedEnter:
- reply_type = SwkbdReplyType::DecidedEnterUtf8;
- break;
- default:
- break;
- }
- }
-
- if (use_changed_string_v2) {
- switch (reply_type) {
- case SwkbdReplyType::ChangedString:
- reply_type = SwkbdReplyType::ChangedStringV2;
- break;
- case SwkbdReplyType::ChangedStringUtf8:
- reply_type = SwkbdReplyType::ChangedStringUtf8V2;
- break;
- default:
- break;
- }
- }
-
- if (use_moved_cursor_v2) {
- switch (reply_type) {
- case SwkbdReplyType::MovedCursor:
- reply_type = SwkbdReplyType::MovedCursorV2;
- break;
- case SwkbdReplyType::MovedCursorUtf8:
- reply_type = SwkbdReplyType::MovedCursorUtf8V2;
- break;
- default:
- break;
- }
- }
-
- SendReply(reply_type);
-}
-
-void SoftwareKeyboard::InitializeForeground() {
- LOG_INFO(Service_AM, "Initializing Normal Software Keyboard Applet.");
-
- is_background = false;
-
- const auto swkbd_config_storage = broker.PopNormalDataToApplet();
- ASSERT(swkbd_config_storage != nullptr);
-
- const auto& swkbd_config_data = swkbd_config_storage->GetData();
- ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon));
-
- std::memcpy(&swkbd_config_common, swkbd_config_data.data(), sizeof(SwkbdConfigCommon));
-
- switch (swkbd_applet_version) {
- case SwkbdAppletVersion::Version5:
- case SwkbdAppletVersion::Version65542:
- ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld));
- std::memcpy(&swkbd_config_old, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
- sizeof(SwkbdConfigOld));
- break;
- case SwkbdAppletVersion::Version196615:
- case SwkbdAppletVersion::Version262152:
- case SwkbdAppletVersion::Version327689:
- ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigOld2));
- std::memcpy(&swkbd_config_old2, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
- sizeof(SwkbdConfigOld2));
- break;
- case SwkbdAppletVersion::Version393227:
- case SwkbdAppletVersion::Version524301:
- ASSERT(swkbd_config_data.size() == sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
- std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
- sizeof(SwkbdConfigNew));
- break;
- default:
- UNIMPLEMENTED_MSG("Unknown SwkbdConfig revision={} with size={}", swkbd_applet_version,
- swkbd_config_data.size());
- ASSERT(swkbd_config_data.size() >= sizeof(SwkbdConfigCommon) + sizeof(SwkbdConfigNew));
- std::memcpy(&swkbd_config_new, swkbd_config_data.data() + sizeof(SwkbdConfigCommon),
- sizeof(SwkbdConfigNew));
- break;
- }
-
- const auto work_buffer_storage = broker.PopNormalDataToApplet();
- ASSERT(work_buffer_storage != nullptr);
-
- if (swkbd_config_common.initial_string_length == 0) {
- InitializeFrontendKeyboard();
- return;
- }
-
- const auto& work_buffer = work_buffer_storage->GetData();
-
- std::vector<char16_t> initial_string(swkbd_config_common.initial_string_length);
-
- std::memcpy(initial_string.data(),
- work_buffer.data() + swkbd_config_common.initial_string_offset,
- swkbd_config_common.initial_string_length * sizeof(char16_t));
-
- initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(initial_string.data(),
- initial_string.size());
-
- LOG_DEBUG(Service_AM, "\nInitial Text: {}", Common::UTF16ToUTF8(initial_text));
-
- InitializeFrontendKeyboard();
-}
-
-void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
- LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
-
- is_background = true;
-
- const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet();
- ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
-
- const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
- ASSERT(swkbd_inline_initialize_arg.size() == sizeof(SwkbdInitializeArg));
-
- std::memcpy(&swkbd_initialize_arg, swkbd_inline_initialize_arg.data(),
- swkbd_inline_initialize_arg.size());
-
- if (swkbd_initialize_arg.library_applet_mode_flag) {
- ASSERT(library_applet_mode == LibraryAppletMode::Background);
- } else {
- ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
- }
-}
-
-void SoftwareKeyboard::ProcessTextCheck() {
- const auto text_check_storage = broker.PopInteractiveDataToApplet();
- ASSERT(text_check_storage != nullptr);
-
- const auto& text_check_data = text_check_storage->GetData();
- ASSERT(text_check_data.size() == sizeof(SwkbdTextCheck));
-
- SwkbdTextCheck swkbd_text_check;
-
- std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
-
- std::u16string text_check_message =
- swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
- swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm
- ? Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_text_check.text_check_message.data(),
- swkbd_text_check.text_check_message.size())
- : u"";
-
- LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
- GetTextCheckResultName(swkbd_text_check.text_check_result),
- Common::UTF16ToUTF8(text_check_message));
-
- switch (swkbd_text_check.text_check_result) {
- case SwkbdTextCheckResult::Success:
- SubmitNormalOutputAndExit(SwkbdResult::Ok, current_text);
- break;
- case SwkbdTextCheckResult::Failure:
- ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message));
- break;
- case SwkbdTextCheckResult::Confirm:
- ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message));
- break;
- case SwkbdTextCheckResult::Silent:
- default:
- break;
- }
-}
-
-void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
- const auto request_data_storage = broker.PopInteractiveDataToApplet();
- ASSERT(request_data_storage != nullptr);
-
- const auto& request_data = request_data_storage->GetData();
- ASSERT(request_data.size() >= sizeof(SwkbdRequestCommand));
-
- SwkbdRequestCommand request_command;
-
- std::memcpy(&request_command, request_data.data(), sizeof(SwkbdRequestCommand));
-
- switch (request_command) {
- case SwkbdRequestCommand::Finalize:
- RequestFinalize(request_data);
- break;
- case SwkbdRequestCommand::SetUserWordInfo:
- RequestSetUserWordInfo(request_data);
- break;
- case SwkbdRequestCommand::SetCustomizeDic:
- RequestSetCustomizeDic(request_data);
- break;
- case SwkbdRequestCommand::Calc:
- RequestCalc(request_data);
- break;
- case SwkbdRequestCommand::SetCustomizedDictionaries:
- RequestSetCustomizedDictionaries(request_data);
- break;
- case SwkbdRequestCommand::UnsetCustomizedDictionaries:
- RequestUnsetCustomizedDictionaries(request_data);
- break;
- case SwkbdRequestCommand::SetChangedStringV2Flag:
- RequestSetChangedStringV2Flag(request_data);
- break;
- case SwkbdRequestCommand::SetMovedCursorV2Flag:
- RequestSetMovedCursorV2Flag(request_data);
- break;
- default:
- UNIMPLEMENTED_MSG("Unknown SwkbdRequestCommand={}", request_command);
- break;
- }
-}
-
-void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
- std::u16string submitted_text) {
- std::vector<u8> out_data(sizeof(SwkbdResult) + STRING_BUFFER_SIZE);
-
- if (swkbd_config_common.use_utf8) {
- std::string utf8_submitted_text = Common::UTF16ToUTF8(submitted_text);
-
- LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-8 Submitted Text: {}", result,
- utf8_submitted_text);
-
- std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
- std::memcpy(out_data.data() + sizeof(SwkbdResult), utf8_submitted_text.data(),
- utf8_submitted_text.size());
- } else {
- LOG_DEBUG(Service_AM, "\nSwkbdResult: {}\nUTF-16 Submitted Text: {}", result,
- Common::UTF16ToUTF8(submitted_text));
-
- std::memcpy(out_data.data(), &result, sizeof(SwkbdResult));
- std::memcpy(out_data.data() + sizeof(SwkbdResult), submitted_text.data(),
- submitted_text.size() * sizeof(char16_t));
- }
-
- broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
-
- ExitKeyboard();
-}
-
-void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
- current_text = std::move(submitted_text);
-
- std::vector<u8> out_data(sizeof(u64) + STRING_BUFFER_SIZE);
-
- if (swkbd_config_common.use_utf8) {
- std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text);
- const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size();
-
- LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size,
- utf8_submitted_text);
-
- std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
- std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(),
- utf8_submitted_text.size());
- } else {
- const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t);
-
- LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size,
- Common::UTF16ToUTF8(current_text));
-
- std::memcpy(out_data.data(), &buffer_size, sizeof(u64));
- std::memcpy(out_data.data() + sizeof(u64), current_text.data(),
- current_text.size() * sizeof(char16_t));
- }
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
-}
-
-void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
- switch (reply_type) {
- case SwkbdReplyType::FinishedInitialize:
- ReplyFinishedInitialize();
- break;
- case SwkbdReplyType::Default:
- ReplyDefault();
- break;
- case SwkbdReplyType::ChangedString:
- ReplyChangedString();
- break;
- case SwkbdReplyType::MovedCursor:
- ReplyMovedCursor();
- break;
- case SwkbdReplyType::MovedTab:
- ReplyMovedTab();
- break;
- case SwkbdReplyType::DecidedEnter:
- ReplyDecidedEnter();
- break;
- case SwkbdReplyType::DecidedCancel:
- ReplyDecidedCancel();
- break;
- case SwkbdReplyType::ChangedStringUtf8:
- ReplyChangedStringUtf8();
- break;
- case SwkbdReplyType::MovedCursorUtf8:
- ReplyMovedCursorUtf8();
- break;
- case SwkbdReplyType::DecidedEnterUtf8:
- ReplyDecidedEnterUtf8();
- break;
- case SwkbdReplyType::UnsetCustomizeDic:
- ReplyUnsetCustomizeDic();
- break;
- case SwkbdReplyType::ReleasedUserWordInfo:
- ReplyReleasedUserWordInfo();
- break;
- case SwkbdReplyType::UnsetCustomizedDictionaries:
- ReplyUnsetCustomizedDictionaries();
- break;
- case SwkbdReplyType::ChangedStringV2:
- ReplyChangedStringV2();
- break;
- case SwkbdReplyType::MovedCursorV2:
- ReplyMovedCursorV2();
- break;
- case SwkbdReplyType::ChangedStringUtf8V2:
- ReplyChangedStringUtf8V2();
- break;
- case SwkbdReplyType::MovedCursorUtf8V2:
- ReplyMovedCursorUtf8V2();
- break;
- default:
- UNIMPLEMENTED_MSG("Unknown SwkbdReplyType={}", reply_type);
- ReplyDefault();
- break;
- }
-}
-
-void SoftwareKeyboard::ChangeState(SwkbdState state) {
- swkbd_state = state;
-
- ReplyDefault();
-}
-
-void SoftwareKeyboard::InitializeFrontendKeyboard() {
- if (is_background) {
- const auto& appear_arg = swkbd_calc_arg.appear_arg;
-
- std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- appear_arg.ok_text.data(), appear_arg.ok_text.size());
-
- const u32 max_text_length =
- appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
- ? appear_arg.max_text_length
- : DEFAULT_MAX_TEXT_LENGTH;
-
- const u32 min_text_length =
- appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
-
- const s32 initial_cursor_position =
- current_cursor_position > 0 ? current_cursor_position : 0;
-
- const auto text_draw_type =
- max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
-
- Core::Frontend::KeyboardInitializeParameters initialize_parameters{
- .ok_text{std::move(ok_text)},
- .header_text{},
- .sub_text{},
- .guide_text{},
- .initial_text{current_text},
- .max_text_length{max_text_length},
- .min_text_length{min_text_length},
- .initial_cursor_position{initial_cursor_position},
- .type{appear_arg.type},
- .password_mode{SwkbdPasswordMode::Disabled},
- .text_draw_type{text_draw_type},
- .key_disable_flags{appear_arg.key_disable_flags},
- .use_blur_background{false},
- .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
- .enable_return_button{appear_arg.enable_return_button},
- .disable_cancel_button{appear_arg.disable_cancel_button},
- };
-
- frontend.InitializeKeyboard(
- true, std::move(initialize_parameters), {},
- [this](SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position) {
- SubmitTextInline(reply_type, submitted_text, cursor_position);
- });
- } else {
- std::u16string ok_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_config_common.ok_text.data(), swkbd_config_common.ok_text.size());
-
- std::u16string header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_config_common.header_text.data(), swkbd_config_common.header_text.size());
-
- std::u16string sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_config_common.sub_text.data(), swkbd_config_common.sub_text.size());
-
- std::u16string guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_config_common.guide_text.data(), swkbd_config_common.guide_text.size());
-
- const u32 max_text_length =
- swkbd_config_common.max_text_length > 0 &&
- swkbd_config_common.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
- ? swkbd_config_common.max_text_length
- : DEFAULT_MAX_TEXT_LENGTH;
-
- const u32 min_text_length = swkbd_config_common.min_text_length <= max_text_length
- ? swkbd_config_common.min_text_length
- : 0;
-
- const s32 initial_cursor_position = [this] {
- switch (swkbd_config_common.initial_cursor_position) {
- case SwkbdInitialCursorPosition::Start:
- default:
- return 0;
- case SwkbdInitialCursorPosition::End:
- return static_cast<s32>(initial_text.size());
- }
- }();
-
- const auto text_draw_type = [this, max_text_length] {
- switch (swkbd_config_common.text_draw_type) {
- case SwkbdTextDrawType::Line:
- default:
- return max_text_length <= 32 ? SwkbdTextDrawType::Line : SwkbdTextDrawType::Box;
- case SwkbdTextDrawType::Box:
- case SwkbdTextDrawType::DownloadCode:
- return swkbd_config_common.text_draw_type;
- }
- }();
-
- const auto enable_return_button = text_draw_type == SwkbdTextDrawType::Box
- ? swkbd_config_common.enable_return_button
- : false;
-
- const auto disable_cancel_button = swkbd_applet_version >= SwkbdAppletVersion::Version393227
- ? swkbd_config_new.disable_cancel_button
- : false;
-
- Core::Frontend::KeyboardInitializeParameters initialize_parameters{
- .ok_text{std::move(ok_text)},
- .header_text{std::move(header_text)},
- .sub_text{std::move(sub_text)},
- .guide_text{std::move(guide_text)},
- .initial_text{initial_text},
- .max_text_length{max_text_length},
- .min_text_length{min_text_length},
- .initial_cursor_position{initial_cursor_position},
- .type{swkbd_config_common.type},
- .password_mode{swkbd_config_common.password_mode},
- .text_draw_type{text_draw_type},
- .key_disable_flags{swkbd_config_common.key_disable_flags},
- .use_blur_background{swkbd_config_common.use_blur_background},
- .enable_backspace_button{true},
- .enable_return_button{enable_return_button},
- .disable_cancel_button{disable_cancel_button},
- };
-
- frontend.InitializeKeyboard(false, std::move(initialize_parameters),
- [this](SwkbdResult result, std::u16string submitted_text) {
- SubmitTextNormal(result, submitted_text);
- },
- {});
- }
-}
-
-void SoftwareKeyboard::ShowNormalKeyboard() {
- frontend.ShowNormalKeyboard();
-}
-
-void SoftwareKeyboard::ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
- std::u16string text_check_message) {
- frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message));
-}
-
-void SoftwareKeyboard::ShowInlineKeyboard() {
- if (swkbd_state != SwkbdState::InitializedIsHidden) {
- return;
- }
-
- ChangeState(SwkbdState::InitializedIsAppearing);
-
- const auto& appear_arg = swkbd_calc_arg.appear_arg;
-
- const u32 max_text_length =
- appear_arg.max_text_length > 0 && appear_arg.max_text_length <= DEFAULT_MAX_TEXT_LENGTH
- ? appear_arg.max_text_length
- : DEFAULT_MAX_TEXT_LENGTH;
-
- const u32 min_text_length =
- appear_arg.min_text_length <= max_text_length ? appear_arg.min_text_length : 0;
-
- Core::Frontend::InlineAppearParameters appear_parameters{
- .max_text_length{max_text_length},
- .min_text_length{min_text_length},
- .key_top_scale_x{swkbd_calc_arg.key_top_scale_x},
- .key_top_scale_y{swkbd_calc_arg.key_top_scale_y},
- .key_top_translate_x{swkbd_calc_arg.key_top_translate_x},
- .key_top_translate_y{swkbd_calc_arg.key_top_translate_y},
- .type{appear_arg.type},
- .key_disable_flags{appear_arg.key_disable_flags},
- .key_top_as_floating{swkbd_calc_arg.key_top_as_floating},
- .enable_backspace_button{swkbd_calc_arg.enable_backspace_button},
- .enable_return_button{appear_arg.enable_return_button},
- .disable_cancel_button{appear_arg.disable_cancel_button},
- };
-
- frontend.ShowInlineKeyboard(std::move(appear_parameters));
-
- ChangeState(SwkbdState::InitializedIsShown);
-}
-
-void SoftwareKeyboard::HideInlineKeyboard() {
- if (swkbd_state != SwkbdState::InitializedIsShown) {
- return;
- }
-
- ChangeState(SwkbdState::InitializedIsDisappearing);
-
- frontend.HideInlineKeyboard();
-
- ChangeState(SwkbdState::InitializedIsHidden);
-}
-
-void SoftwareKeyboard::InlineTextChanged() {
- Core::Frontend::InlineTextParameters text_parameters{
- .input_text{current_text},
- .cursor_position{current_cursor_position},
- };
-
- frontend.InlineTextChanged(std::move(text_parameters));
-}
-
-void SoftwareKeyboard::ExitKeyboard() {
- complete = true;
- status = ResultSuccess;
-
- frontend.ExitKeyboard();
-
- broker.SignalStateChanged();
-}
-
-// Inline Software Keyboard Requests
-
-void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
- LOG_DEBUG(Service_AM, "Processing Request: Finalize");
-
- ChangeState(SwkbdState::NotInitialized);
-
- ExitKeyboard();
-}
-
-void SoftwareKeyboard::RequestSetUserWordInfo(const std::vector<u8>& request_data) {
- LOG_WARNING(Service_AM, "SetUserWordInfo is not implemented.");
-}
-
-void SoftwareKeyboard::RequestSetCustomizeDic(const std::vector<u8>& request_data) {
- LOG_WARNING(Service_AM, "SetCustomizeDic is not implemented.");
-}
-
-void SoftwareKeyboard::RequestCalc(const std::vector<u8>& request_data) {
- LOG_DEBUG(Service_AM, "Processing Request: Calc");
-
- ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + sizeof(SwkbdCalcArg));
-
- std::memcpy(&swkbd_calc_arg, request_data.data() + sizeof(SwkbdRequestCommand),
- sizeof(SwkbdCalcArg));
-
- if (swkbd_calc_arg.flags.set_input_text) {
- current_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
- swkbd_calc_arg.input_text.data(), swkbd_calc_arg.input_text.size());
- }
-
- if (swkbd_calc_arg.flags.set_cursor_position) {
- current_cursor_position = swkbd_calc_arg.cursor_position;
- }
-
- if (swkbd_calc_arg.flags.set_utf8_mode) {
- inline_use_utf8 = swkbd_calc_arg.utf8_mode;
- }
-
- if (swkbd_state <= SwkbdState::InitializedIsHidden &&
- swkbd_calc_arg.flags.unset_customize_dic) {
- ReplyUnsetCustomizeDic();
- }
-
- if (swkbd_state <= SwkbdState::InitializedIsHidden &&
- swkbd_calc_arg.flags.unset_user_word_info) {
- ReplyReleasedUserWordInfo();
- }
-
- if (swkbd_state == SwkbdState::NotInitialized && swkbd_calc_arg.flags.set_initialize_arg) {
- InitializeFrontendKeyboard();
-
- ChangeState(SwkbdState::InitializedIsHidden);
-
- ReplyFinishedInitialize();
- }
-
- if (!swkbd_calc_arg.flags.set_initialize_arg &&
- (swkbd_calc_arg.flags.set_input_text || swkbd_calc_arg.flags.set_cursor_position)) {
- InlineTextChanged();
- }
-
- if (swkbd_state == SwkbdState::InitializedIsHidden && swkbd_calc_arg.flags.appear) {
- ShowInlineKeyboard();
- return;
- }
-
- if (swkbd_state == SwkbdState::InitializedIsShown && swkbd_calc_arg.flags.disappear) {
- HideInlineKeyboard();
- return;
- }
-}
-
-void SoftwareKeyboard::RequestSetCustomizedDictionaries(const std::vector<u8>& request_data) {
- LOG_WARNING(Service_AM, "SetCustomizedDictionaries is not implemented.");
-}
-
-void SoftwareKeyboard::RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data) {
- LOG_WARNING(Service_AM, "(STUBBED) Processing Request: UnsetCustomizedDictionaries");
-
- ReplyUnsetCustomizedDictionaries();
-}
-
-void SoftwareKeyboard::RequestSetChangedStringV2Flag(const std::vector<u8>& request_data) {
- LOG_DEBUG(Service_AM, "Processing Request: SetChangedStringV2Flag");
-
- ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
-
- std::memcpy(&use_changed_string_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
-}
-
-void SoftwareKeyboard::RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data) {
- LOG_DEBUG(Service_AM, "Processing Request: SetMovedCursorV2Flag");
-
- ASSERT(request_data.size() == sizeof(SwkbdRequestCommand) + 1);
-
- std::memcpy(&use_moved_cursor_v2, request_data.data() + sizeof(SwkbdRequestCommand), 1);
-}
-
-// Inline Software Keyboard Replies
-
-void SoftwareKeyboard::ReplyFinishedInitialize() {
- LOG_DEBUG(Service_AM, "Sending Reply: FinishedInitialize");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + 1);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyDefault() {
- LOG_DEBUG(Service_AM, "Sending Reply: Default");
-
- std::vector<u8> reply(REPLY_BASE_SIZE);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyChangedString() {
- LOG_DEBUG(Service_AM, "Sending Reply: ChangedString");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedString);
-
- const SwkbdChangedStringArg changed_string_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .dictionary_start_cursor_position{-1},
- .dictionary_end_cursor_position{-1},
- .cursor_position{current_cursor_position},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
- sizeof(SwkbdChangedStringArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyMovedCursor() {
- LOG_DEBUG(Service_AM, "Sending Reply: MovedCursor");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursor);
-
- const SwkbdMovedCursorArg moved_cursor_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .cursor_position{current_cursor_position},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
- sizeof(SwkbdMovedCursorArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyMovedTab() {
- LOG_DEBUG(Service_AM, "Sending Reply: MovedTab");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedTabArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedTab);
-
- const SwkbdMovedTabArg moved_tab_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .cursor_position{current_cursor_position},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
- sizeof(SwkbdMovedTabArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyDecidedEnter() {
- LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnter");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdDecidedEnterArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnter);
-
- const SwkbdDecidedEnterArg decided_enter_arg{
- .text_length{static_cast<u32>(current_text.size())},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
- sizeof(SwkbdDecidedEnterArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-
- HideInlineKeyboard();
-}
-
-void SoftwareKeyboard::ReplyDecidedCancel() {
- LOG_DEBUG(Service_AM, "Sending Reply: DecidedCancel");
-
- std::vector<u8> reply(REPLY_BASE_SIZE);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-
- HideInlineKeyboard();
-}
-
-void SoftwareKeyboard::ReplyChangedStringUtf8() {
- LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8);
-
- std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
-
- const SwkbdChangedStringArg changed_string_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .dictionary_start_cursor_position{-1},
- .dictionary_end_cursor_position{-1},
- .cursor_position{current_cursor_position},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
- sizeof(SwkbdChangedStringArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyMovedCursorUtf8() {
- LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8);
-
- std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
-
- const SwkbdMovedCursorArg moved_cursor_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .cursor_position{current_cursor_position},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
- sizeof(SwkbdMovedCursorArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
- LOG_DEBUG(Service_AM, "Sending Reply: DecidedEnterUtf8");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdDecidedEnterArg));
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedEnterUtf8);
-
- std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
-
- const SwkbdDecidedEnterArg decided_enter_arg{
- .text_length{static_cast<u32>(current_text.size())},
- };
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
- sizeof(SwkbdDecidedEnterArg));
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-
- HideInlineKeyboard();
-}
-
-void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
- LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizeDic");
-
- std::vector<u8> reply(REPLY_BASE_SIZE);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
- LOG_DEBUG(Service_AM, "Sending Reply: ReleasedUserWordInfo");
-
- std::vector<u8> reply(REPLY_BASE_SIZE);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
- LOG_DEBUG(Service_AM, "Sending Reply: UnsetCustomizedDictionaries");
-
- std::vector<u8> reply(REPLY_BASE_SIZE);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyChangedStringV2() {
- LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringV2");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg) + 1);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringV2);
-
- const SwkbdChangedStringArg changed_string_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .dictionary_start_cursor_position{-1},
- .dictionary_end_cursor_position{-1},
- .cursor_position{current_cursor_position},
- };
-
- constexpr u8 flag = 0;
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
- sizeof(SwkbdChangedStringArg));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
- &flag, 1);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyMovedCursorV2() {
- LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorV2");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorV2);
-
- const SwkbdMovedCursorArg moved_cursor_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .cursor_position{current_cursor_position},
- };
-
- constexpr u8 flag = 0;
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, current_text.data(),
- current_text.size() * sizeof(char16_t));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
- sizeof(SwkbdMovedCursorArg));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
- &flag, 1);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
- LOG_DEBUG(Service_AM, "Sending Reply: ChangedStringUtf8V2");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg) + 1);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::ChangedStringUtf8V2);
-
- std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
-
- const SwkbdChangedStringArg changed_string_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .dictionary_start_cursor_position{-1},
- .dictionary_end_cursor_position{-1},
- .cursor_position{current_cursor_position},
- };
-
- constexpr u8 flag = 0;
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
- sizeof(SwkbdChangedStringArg));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
- &flag, 1);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
- LOG_DEBUG(Service_AM, "Sending Reply: MovedCursorUtf8V2");
-
- std::vector<u8> reply(REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg) + 1);
-
- SetReplyBase(reply, swkbd_state, SwkbdReplyType::MovedCursorUtf8V2);
-
- std::string utf8_current_text = Common::UTF16ToUTF8(current_text);
-
- const SwkbdMovedCursorArg moved_cursor_arg{
- .text_length{static_cast<u32>(current_text.size())},
- .cursor_position{current_cursor_position},
- };
-
- constexpr u8 flag = 0;
-
- std::memcpy(reply.data() + REPLY_BASE_SIZE, utf8_current_text.data(), utf8_current_text.size());
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
- sizeof(SwkbdMovedCursorArg));
- std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
- &flag, 1);
-
- broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
-}
-
-} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
deleted file mode 100644
index e3fc733d0..000000000
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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/applets.h"
-#include "core/hle/service/am/applets/software_keyboard_types.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
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
deleted file mode 100644
index 3b28e829b..000000000
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-// 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/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
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
deleted file mode 100644
index 9f81214b6..000000000
--- a/src/core/hle/service/am/applets/web_browser.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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/applets.h"
-#include "core/hle/service/am/applets/web_types.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