2021-03-16 17:59:52 +01:00
|
|
|
// Copyright 2021 yuzu Emulator Project
|
2018-11-10 02:12:12 +01:00
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
#include "common/string_util.h"
|
2018-11-11 22:39:25 +01:00
|
|
|
#include "core/core.h"
|
2018-11-10 02:12:12 +01:00
|
|
|
#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 {
|
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
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_)
|
2021-04-17 15:19:02 +02:00
|
|
|
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
|
2018-11-11 22:39:25 +01:00
|
|
|
|
|
|
|
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:04:05 +02:00
|
|
|
void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
|
2021-03-16 17:59:52 +01:00
|
|
|
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) {
|
2021-05-04 10:04:05 +02:00
|
|
|
ASSERT(library_applet_mode == LibraryAppletMode::Background);
|
2021-03-16 17:59:52 +01:00
|
|
|
} else {
|
2021-05-04 10:04:05 +02:00
|
|
|
ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
|
2021-03-16 17:59:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2021-05-28 05:13:39 +02:00
|
|
|
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"";
|
2021-03-16 17:59:52 +01:00
|
|
|
|
|
|
|
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:
|
2021-05-28 05:22:38 +02:00
|
|
|
ShowTextCheckDialog(SwkbdTextCheckResult::Failure, std::move(text_check_message));
|
2021-03-16 17:59:52 +01:00
|
|
|
break;
|
|
|
|
case SwkbdTextCheckResult::Confirm:
|
2021-05-28 05:22:38 +02:00
|
|
|
ShowTextCheckDialog(SwkbdTextCheckResult::Confirm, std::move(text_check_message));
|
2021-03-16 17:59:52 +01:00
|
|
|
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{
|
2021-05-28 05:22:38 +02:00
|
|
|
.ok_text{std::move(ok_text)},
|
2021-03-16 17:59:52 +01:00
|
|
|
.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{
|
2021-05-28 05:22:38 +02:00
|
|
|
.ok_text{std::move(ok_text)},
|
|
|
|
.header_text{std::move(header_text)},
|
|
|
|
.sub_text{std::move(sub_text)},
|
|
|
|
.guide_text{std::move(guide_text)},
|
2021-03-16 17:59:52 +01:00
|
|
|
.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) {
|
2021-05-28 05:22:38 +02:00
|
|
|
frontend.ShowTextCheckDialog(text_check_result, std::move(text_check_message));
|
2021-03-16 17:59:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2021-05-21 07:05:04 +02:00
|
|
|
status = ResultSuccess;
|
2021-03-16 17:59:52 +01:00
|
|
|
|
|
|
|
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);
|
2018-11-19 05:14:48 +01:00
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
const SwkbdMovedCursorArg moved_cursor_arg{
|
|
|
|
.text_length{static_cast<u32>(current_text.size())},
|
|
|
|
.cursor_position{current_cursor_position},
|
|
|
|
};
|
2018-11-19 05:14:48 +01:00
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
constexpr u8 flag = 0;
|
2018-11-19 05:14:48 +01:00
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
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);
|
2018-11-17 18:20:16 +01:00
|
|
|
|
2021-03-16 17:59:52 +01:00
|
|
|
broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
|
|
|
|
}
|
2018-11-17 18:20:16 +01:00
|
|
|
|
2018-11-10 02:12:12 +01:00
|
|
|
} // namespace Service::AM::Applets
|