2018-11-10 02:12:12 +01:00
|
|
|
// Copyright 2018 yuzu emulator team
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2018-11-11 22:39:25 +01:00
|
|
|
#include <cstring>
|
2018-11-10 02:12:12 +01:00
|
|
|
#include "common/assert.h"
|
|
|
|
#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 {
|
|
|
|
|
|
|
|
constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
|
2018-11-11 22:39:25 +01:00
|
|
|
constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
|
2018-11-10 02:12:12 +01:00
|
|
|
constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
|
2018-11-11 22:39:25 +01:00
|
|
|
constexpr bool INTERACTIVE_STATUS_OK = false;
|
2018-11-10 02:12:12 +01:00
|
|
|
|
2018-11-11 22:39:25 +01:00
|
|
|
static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
|
2018-11-10 02:12:12 +01:00
|
|
|
KeyboardConfig config, std::u16string initial_text) {
|
2018-11-11 22:39:25 +01:00
|
|
|
Core::Frontend::SoftwareKeyboardParameters params{};
|
2018-11-10 02:12:12 +01:00
|
|
|
|
|
|
|
params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
|
|
|
config.submit_text.data(), config.submit_text.size());
|
|
|
|
params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
|
|
|
config.header_text.data(), config.header_text.size());
|
|
|
|
params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
|
|
|
|
config.sub_text.size());
|
|
|
|
params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
|
|
|
|
config.guide_text.size());
|
|
|
|
params.initial_text = initial_text;
|
|
|
|
params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
|
|
|
|
params.password = static_cast<bool>(config.is_password);
|
|
|
|
params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
|
|
|
|
params.value = static_cast<u8>(config.keyset_disable_bitmask);
|
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
|
2018-11-11 22:39:25 +01:00
|
|
|
SoftwareKeyboard::SoftwareKeyboard() = default;
|
|
|
|
|
|
|
|
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
|
|
|
|
2018-11-10 02:12:12 +01:00
|
|
|
void SoftwareKeyboard::Initialize(std::vector<std::shared_ptr<IStorage>> storage_) {
|
|
|
|
Applet::Initialize(std::move(storage_));
|
|
|
|
|
|
|
|
ASSERT(storage_stack.size() >= 2);
|
|
|
|
const auto& keyboard_config = storage_stack[1]->GetData();
|
|
|
|
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
|
|
|
|
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
|
|
|
|
|
|
|
|
const auto& work_buffer = storage_stack[2]->GetData();
|
2018-11-11 22:41:31 +01:00
|
|
|
|
|
|
|
if (config.initial_string_size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::vector<char16_t> string(config.initial_string_size);
|
|
|
|
std::memcpy(string.data(), work_buffer.data() + 4, string.size() * 2);
|
|
|
|
initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SoftwareKeyboard::TransactionComplete() const {
|
|
|
|
return complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResultCode SoftwareKeyboard::GetStatus() const {
|
|
|
|
return RESULT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) {
|
|
|
|
if (complete)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const auto data = storage->GetData();
|
|
|
|
const auto status = static_cast<bool>(data[0]);
|
|
|
|
|
|
|
|
if (status == INTERACTIVE_STATUS_OK) {
|
|
|
|
complete = true;
|
|
|
|
} else {
|
|
|
|
const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
|
|
|
|
|
|
|
|
std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
|
|
|
|
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
|
|
|
|
frontend.SendTextCheckDialog(
|
|
|
|
Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()));
|
|
|
|
}
|
2018-11-10 02:12:12 +01:00
|
|
|
}
|
|
|
|
|
2018-11-12 02:16:38 +01:00
|
|
|
void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
|
|
|
|
AppletStorageProxyFunction out_interactive_data) {
|
2018-11-11 22:41:31 +01:00
|
|
|
if (complete)
|
2018-11-12 02:16:38 +01:00
|
|
|
return;
|
2018-11-11 22:41:31 +01:00
|
|
|
|
|
|
|
const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
|
2018-11-10 02:12:12 +01:00
|
|
|
|
|
|
|
const auto parameters = ConvertToFrontendParameters(config, initial_text);
|
|
|
|
|
2018-11-12 02:16:38 +01:00
|
|
|
const auto res = frontend.GetText(parameters);
|
2018-11-10 02:12:12 +01:00
|
|
|
|
|
|
|
std::vector<u8> output(SWKBD_OUTPUT_BUFFER_SIZE);
|
|
|
|
|
2018-11-12 02:16:38 +01:00
|
|
|
if (res.has_value()) {
|
2018-11-11 22:41:31 +01:00
|
|
|
if (config.text_check) {
|
2018-11-12 02:16:38 +01:00
|
|
|
const auto size = static_cast<u32>(res->size() * 2 + 4);
|
2018-11-11 22:41:31 +01:00
|
|
|
std::memcpy(output.data(), &size, sizeof(u32));
|
|
|
|
} else {
|
|
|
|
output[0] = 1;
|
|
|
|
}
|
|
|
|
|
2018-11-12 02:16:38 +01:00
|
|
|
std::memcpy(output.data() + 4, res->data(),
|
|
|
|
std::min(res->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
|
2018-11-11 22:41:31 +01:00
|
|
|
} else {
|
|
|
|
complete = true;
|
2018-11-12 02:16:38 +01:00
|
|
|
out_data(IStorage{output});
|
|
|
|
return;
|
2018-11-11 22:41:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
complete = !config.text_check;
|
|
|
|
|
2018-11-12 02:16:38 +01:00
|
|
|
(complete ? out_data : out_interactive_data)(IStorage{output});
|
2018-11-10 02:12:12 +01:00
|
|
|
}
|
|
|
|
} // namespace Service::AM::Applets
|