Functional implementation

This commit is contained in:
Lander Gallastegi 2024-10-06 01:34:38 +02:00
parent de06bd38a5
commit c10a06422f
4 changed files with 362 additions and 89 deletions

View file

@ -1,28 +1,76 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <magic_enum.hpp>
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "ime_dialog.h"
#include "ime_dialog_ui.h"
static constexpr float MAX_X_POSITIONS[] = {3840.0f, 1920.0f};
static constexpr float MAX_Y_POSITIONS[] = {2160.0f, 1080.0f};
namespace Libraries::ImeDialog {
static OrbisImeDialogStatus g_ime_dlg_status = OrbisImeDialogStatus::NONE;
static OrbisImeDialogResult g_ime_dlg_result{};
static ImeDialogState g_ime_dlg_state{};
static ImeDialogUi g_ime_dlg_ui;
int PS4_SYSV_ABI sceImeDialogAbort() {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
return ORBIS_OK;
static bool IsValidOption(OrbisImeDialogOption option, OrbisImeType type) {
if (False(~option & (OrbisImeDialogOption::MULTILINE | OrbisImeDialogOption::NO_AUTO_COMPLETION))) {
return false;
}
if (True(option & OrbisImeDialogOption::MULTILINE) && type != OrbisImeType::DEFAULT && type != OrbisImeType::BASIC_LATIN) {
return false;
}
if (True(option & OrbisImeDialogOption::NO_AUTO_COMPLETION) && type != OrbisImeType::NUMBER && type != OrbisImeType::BASIC_LATIN ) {
return false;
}
return true;
}
int PS4_SYSV_ABI sceImeDialogForceClose() {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
return ORBIS_OK;
// static bool IsMemZero(const void* ptr, size_t size) {
// return std::all_of(static_cast<const u8*>(ptr), static_cast<const u8*>(ptr) + size, [](u8 c) { return c == 0; });
// }
Error PS4_SYSV_ABI sceImeDialogAbort() {
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
return Error::DIALOG_NOT_IN_USE;
}
if (g_ime_dlg_status != OrbisImeDialogStatus::RUNNING) {
LOG_INFO(Lib_ImeDialog, "IME dialog not running");
return Error::DIALOG_NOT_RUNNING;
}
g_ime_dlg_status = OrbisImeDialogStatus::FINISHED;
g_ime_dlg_result.endstatus = OrbisImeDialogEndStatus::ABORTED;
return Error::OK;
}
int PS4_SYSV_ABI sceImeDialogForTestFunction() {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
return ORBIS_OK;
Error PS4_SYSV_ABI sceImeDialogForceClose() {
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
return Error::DIALOG_NOT_IN_USE;
}
g_ime_dlg_status = OrbisImeDialogStatus::NONE;
g_ime_dlg_ui = ImeDialogUi();
g_ime_dlg_state = ImeDialogState();
return Error::OK;
}
Error PS4_SYSV_ABI sceImeDialogForTestFunction() {
return Error::INTERNAL;
}
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState() {
@ -45,26 +93,134 @@ int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result) {
result->endstatus = OrbisImeDialogEndStatus::OK;
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
return ORBIS_OK;
Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result) {
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
LOG_INFO(Lib_ImeDialog, "IME dialog is not running");
return Error::DIALOG_NOT_IN_USE;
}
if (result == nullptr) {
LOG_INFO(Lib_ImeDialog, "called with result (NULL)");
return Error::INVALID_ADDRESS;
}
// if (!IsMemZero(result->reserved, 12)) {
// LOG_INFO(Lib_ImeDialog, "Invalid result->reserved");
// return Error::INVALID_RESERVED;
// }
result->endstatus = g_ime_dlg_result.endstatus;
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
return Error::DIALOG_NOT_FINISHED;
}
g_ime_dlg_state.CopyTextToOrbisBuffer();
return Error::OK;
}
OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() {
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
return OrbisImeDialogStatus::FINISHED;
g_ime_dlg_state.CallTextFilter();
}
return g_ime_dlg_status;
}
int PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
const std::wstring_view text = L"shadPS4";
param->maxTextLength = text.size();
std::memcpy(param->inputTextBuffer, text.data(), text.size() * sizeof(wchar_t));
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) {
if (g_ime_dlg_status != OrbisImeDialogStatus::NONE) {
LOG_INFO(Lib_ImeDialog, "IME dialog is already running");
return Error::BUSY;
}
if (param == nullptr) {
LOG_INFO(Lib_ImeDialog, "called with param (NULL)");
return Error::INVALID_ADDRESS;
}
if (!magic_enum::enum_contains(param->type)) {
LOG_INFO(Lib_ImeDialog, "Invalid param->type");
return Error::INVALID_ADDRESS;
}
//TODO: do correct param->option validation
//TODO: do correct param->supportedLanguages validation
if (param->posx < 0.0f || param->posx >= MAX_X_POSITIONS[False(param->option & OrbisImeDialogOption::LARGE_RESOLUTION)]) {
LOG_INFO(Lib_ImeDialog, "Invalid param->posx");
return Error::INVALID_POSX;
}
if (param->posy < 0.0f || param->posy >= MAX_Y_POSITIONS[False(param->option & OrbisImeDialogOption::LARGE_RESOLUTION)]) {
LOG_INFO(Lib_ImeDialog, "Invalid param->posy");
return Error::INVALID_POSY;
}
if (!magic_enum::enum_contains(param->horizontalAlignment)) {
LOG_INFO(Lib_ImeDialog, "Invalid param->horizontalAlignment");
return Error::INVALID_HORIZONTALIGNMENT;
}
if (!magic_enum::enum_contains(param->verticalAlignment)) {
LOG_INFO(Lib_ImeDialog, "Invalid param->verticalAlignment");
return Error::INVALID_VERTICALALIGNMENT;
}
if (!IsValidOption(param->option, param->type)) {
LOG_INFO(Lib_ImeDialog, "Invalid param->option");
return Error::INVALID_PARAM;
}
if (param->userId != 1) { //We only support user 1 for now
LOG_INFO(Lib_ImeDialog, "Invalid param->userId");
return Error::INVALID_USER_ID;
}
// if (IsMemZero(param->reserved, 16)) {
// LOG_INFO(Lib_ImeDialog, "Invalid param->reserved");
// return Error::INVALID_RESERVED;
// }
if (param->inputTextBuffer == nullptr) {
LOG_INFO(Lib_ImeDialog, "Invalid param->inputTextBuffer");
return Error::INVALID_INPUT_TEXT_BUFFER;
}
if (extended) {
if (magic_enum::enum_contains(extended->priority)) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->priority");
return Error::INVALID_EXTENDED;
}
//TODO: do correct extended->option validation
// if (IsMemZero(extended->reserved, 60)) {
// LOG_INFO(Lib_ImeDialog, "Invalid extended->reserved");
// return Error::INVALID_EXTENDED;
// }
if ((extended->extKeyboardMode & 0xe3fffffc) != 0) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->extKeyboardMode");
return Error::INVALID_EXTENDED;
}
if (extended->disableDevice > 7) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->disableDevice");
return Error::INVALID_EXTENDED;
}
}
if (param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) {
LOG_INFO(Lib_ImeDialog, "Invalid param->maxTextLength");
return Error::INVALID_MAX_TEXT_LENGTH;
}
g_ime_dlg_result = {};
g_ime_dlg_state = ImeDialogState(param, extended);
g_ime_dlg_status = OrbisImeDialogStatus::RUNNING;
return ORBIS_OK;
g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result);
return Error::OK;
}
int PS4_SYSV_ABI sceImeDialogInitInternal() {
@ -87,10 +243,22 @@ int PS4_SYSV_ABI sceImeDialogSetPanelPosition() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceImeDialogTerm() {
LOG_ERROR(Lib_ImeDialog, "(STUBBED) called");
Error PS4_SYSV_ABI sceImeDialogTerm() {
if (g_ime_dlg_status == OrbisImeDialogStatus::NONE) {
LOG_INFO(Lib_ImeDialog, "IME dialog not in use");
return Error::DIALOG_NOT_IN_USE;
}
if (g_ime_dlg_status == OrbisImeDialogStatus::RUNNING) {
LOG_INFO(Lib_ImeDialog, "IME dialog is still running");
return Error::DIALOG_NOT_FINISHED;
}
g_ime_dlg_status = OrbisImeDialogStatus::NONE;
return ORBIS_OK;
g_ime_dlg_ui = ImeDialogUi();
g_ime_dlg_state = ImeDialogState();
return Error::OK;
}
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym) {

View file

@ -68,13 +68,13 @@ enum class OrbisImeDialogEndStatus : u32 {
ABORTED = 2
};
enum class OrbisImeType : u32 {
DEFAULT = 0,
BASIC_LATIN = 1,
URL = 2,
MAIL = 3,
NUMBER = 4
};
enum class OrbisImeType : u32 {
DEFAULT = 0,
BASIC_LATIN = 1,
URL = 2,
MAIL = 3,
NUMBER = 4
};
enum class OrbisImeEnterLabel : u32 {
DEFAULT = 0,
@ -87,7 +87,9 @@ enum class OrbisImeDialogOption : u32 {
DEFAULT = 0,
MULTILINE = 1,
NO_AUTO_CORRECTION = 2,
NO_AUTO_COMPLETION = 4
NO_AUTO_COMPLETION = 4,
// TODO: Document missing options
LARGE_RESOLUTION = 1024
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDialogOption)
@ -222,21 +224,21 @@ struct OrbisImeParamExtended {
int8_t reserved[60];
};
int PS4_SYSV_ABI sceImeDialogAbort();
int PS4_SYSV_ABI sceImeDialogForceClose();
int PS4_SYSV_ABI sceImeDialogForTestFunction();
Error PS4_SYSV_ABI sceImeDialogAbort();
Error PS4_SYSV_ABI sceImeDialogForceClose();
Error PS4_SYSV_ABI sceImeDialogForTestFunction();
int PS4_SYSV_ABI sceImeDialogGetCurrentStarState();
int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm();
int PS4_SYSV_ABI sceImeDialogGetPanelSize();
int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended();
int PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result);
Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result);
OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus();
int PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended);
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended);
int PS4_SYSV_ABI sceImeDialogInitInternal();
int PS4_SYSV_ABI sceImeDialogInitInternal2();
int PS4_SYSV_ABI sceImeDialogInitInternal3();
int PS4_SYSV_ABI sceImeDialogSetPanelPosition();
int PS4_SYSV_ABI sceImeDialogTerm();
Error PS4_SYSV_ABI sceImeDialogTerm();
void RegisterlibSceImeDialog(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::ImeDialog

View file

@ -32,6 +32,7 @@ ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param, const OrbisImeP
userId = param->userId;
is_multiLine = True(param->option & OrbisImeDialogOption::MULTILINE);
is_numeric = param->type == OrbisImeType::NUMBER;
type = param->type;
enter_label = param->enterLabel;
text_filter = param->filter;
@ -47,48 +48,108 @@ ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param, const OrbisImeP
ASSERT_MSG(utf8_to_orbis != (iconv_t)-1, "Failed to open iconv utf8_to_orbis");
#endif
std::size_t title_len = std::char_traits<char16_t>::length(param->title);
title = new char[title_len * 4 + 1];
if (param->title) {
std::size_t title_len = std::char_traits<char16_t>::length(param->title);
title = new char[title_len * 4 + 1];
if (!ConvertOrbisToUTF8(param->title, title_len, title, title_len)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert title to utf8 encoding");
return;
if (!ConvertOrbisToUTF8(param->title, title_len, title, title_len)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert title to utf8 encoding");
}
}
if (!param->placeholder) {
return;
if (param->placeholder) {
std::size_t placeholder_len = std::char_traits<char16_t>::length(param->placeholder);
placeholder = new char[placeholder_len * 4 + 1];
if (!ConvertOrbisToUTF8(param->placeholder, placeholder_len, placeholder, placeholder_len)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert placeholder to utf8 encoding");
}
}
std::size_t placeholder_len = std::char_traits<char16_t>::length(param->placeholder);
placeholder = new char[placeholder_len * 4 + 1];
if (!ConvertOrbisToUTF8(param->placeholder, placeholder_len, placeholder, placeholder_len)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert placeholder to utf8 encoding");
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text, max_text_length)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
}
}
ImeDialogState::~ImeDialogState() {
Free();
}
ImeDialogState::ImeDialogState(ImeDialogState&& other) noexcept
: userId(other.userId),
is_multiLine(other.is_multiLine),
is_numeric(other.is_numeric),
type(other.type),
enter_label(other.enter_label),
text_filter(other.text_filter),
keyboard_filter(other.keyboard_filter),
max_text_length(other.max_text_length),
text_buffer(other.text_buffer),
title(other.title),
placeholder(other.placeholder),
input_changed(other.input_changed) {
std::memcpy(current_text, other.current_text, sizeof(current_text));
#ifndef _WIN32
if (orbis_to_utf8 != (iconv_t)-1) {
iconv_close(orbis_to_utf8);
}
if (utf8_to_orbis != (iconv_t)-1) {
iconv_close(utf8_to_orbis);
}
orbis_to_utf8 = other.orbis_to_utf8;
utf8_to_orbis = other.utf8_to_orbis;
other.orbis_to_utf8 = (iconv_t)-1;
other.utf8_to_orbis = (iconv_t)-1;
#endif
if (title) {
delete[] title;
other.text_buffer = nullptr;
other.title = nullptr;
other.placeholder = nullptr;
}
ImeDialogState& ImeDialogState::operator=(ImeDialogState&& other) {
if (this != &other) {
Free();
userId = other.userId;
is_multiLine = other.is_multiLine;
is_numeric = other.is_numeric;
type = other.type;
enter_label = other.enter_label;
text_filter = other.text_filter;
keyboard_filter = other.keyboard_filter;
max_text_length = other.max_text_length;
text_buffer = other.text_buffer;
title = other.title;
placeholder = other.placeholder;
input_changed = other.input_changed;
std::memcpy(current_text, other.current_text, sizeof(current_text));
#ifndef _WIN32
orbis_to_utf8 = other.orbis_to_utf8;
utf8_to_orbis = other.utf8_to_orbis;
other.orbis_to_utf8 = (iconv_t)-1;
other.utf8_to_orbis = (iconv_t)-1;
#endif
other.text_buffer = nullptr;
other.title = nullptr;
other.placeholder = nullptr;
}
if (placeholder) {
delete[] placeholder;
return *this;
}
bool ImeDialogState::CopyTextToOrbisBuffer() {
if (!text_buffer) {
return false;
}
std::size_t text_len = std::char_traits<char>::length(current_text);
return ConvertUTF8ToOrbis(current_text, text_len, text_buffer, max_text_length);
}
bool ImeDialogState::CallTextFilter() {
std::scoped_lock lock(mutex);
if (!text_filter || !input_changed) {
return true;
}
@ -120,6 +181,25 @@ bool ImeDialogState::CallTextFilter() {
return true;
}
void ImeDialogState::Free() {
#ifndef _WIN32
if (orbis_to_utf8 != (iconv_t)-1) {
iconv_close(orbis_to_utf8);
}
if (utf8_to_orbis != (iconv_t)-1) {
iconv_close(utf8_to_orbis);
}
#endif
if (title) {
delete[] title;
}
if (placeholder) {
delete[] placeholder;
}
}
bool ImeDialogState::CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status) {
if (!keyboard_filter) {
return true;
@ -259,14 +339,15 @@ ImeDialogUi::ImeDialogUi(ImeDialogState* state, OrbisImeDialogStatus* status, Or
}
ImeDialogUi::~ImeDialogUi() {
RemoveLayer(this);
std::scoped_lock lock(draw_mutex);
Free();
}
ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept
: state(other.state), status(other.status), result(other.result) {
if (state) std::scoped_lock lock(state->mutex);
if (other.state) std::scoped_lock lock2(other.state->mutex);
std::scoped_lock lock(draw_mutex, other.draw_mutex);
other.state = nullptr;
other.status = nullptr;
other.result = nullptr;
@ -276,27 +357,35 @@ ImeDialogUi::ImeDialogUi(ImeDialogUi&& other) noexcept
}
}
ImeDialogUi& ImeDialogUi::operator=(ImeDialogUi other) {
if (state) std::scoped_lock lock(state->mutex);
if (other.state) std::scoped_lock lock2(other.state->mutex);
std::swap(state, other.state);
std::swap(status, other.status);
std::swap(result, other.result);
ImeDialogUi& ImeDialogUi::operator=(ImeDialogUi&& other) {
std::scoped_lock lock(draw_mutex, other.draw_mutex);
Free();
if (state) {
state = other.state;
status = other.status;
result = other.result;
other.state = nullptr;
other.status = nullptr;
other.result = nullptr;
if (state && *status == OrbisImeDialogStatus::RUNNING) {
AddLayer(this);
}
return *this;
}
void ImeDialogUi::Free() {
RemoveLayer(this);
}
void ImeDialogUi::Draw() {
std::unique_lock lock{draw_mutex};
if (!state) {
return;
}
std::unique_lock lock{state->mutex};
if (!status || *status != OrbisImeDialogStatus::RUNNING) {
return;
}
@ -322,7 +411,7 @@ void ImeDialogUi::Draw() {
first_render = false;
if (Begin("IME Dialog#ImeDialog", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
if (Begin("IME Dialog##ImeDialog", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
DrawPrettyBackground();
Separator();
@ -345,17 +434,17 @@ void ImeDialogUi::Draw() {
switch (state->enter_label) {
case OrbisImeEnterLabel::GO:
button_text = "Go#ImeDialogOK";
button_text = "Go##ImeDialogOK";
break;
case OrbisImeEnterLabel::SEARCH:
button_text = "Search#ImeDialogOK";
button_text = "Search##ImeDialogOK";
break;
case OrbisImeEnterLabel::SEND:
button_text = "Send#ImeDialogOK";
button_text = "Send##ImeDialogOK";
break;
case OrbisImeEnterLabel::DEFAULT:
default:
button_text = "OK#ImeDialogOK";
button_text = "OK##ImeDialogOK";
break;
}
@ -364,7 +453,7 @@ void ImeDialogUi::Draw() {
result->endstatus = OrbisImeDialogEndStatus::OK;
}
if (Button("Cancel#ImeDialogCancel", BUTTON_SIZE)) {
if (Button("Cancel##ImeDialogCancel", BUTTON_SIZE)) {
*status = OrbisImeDialogStatus::FINISHED;
result->endstatus = OrbisImeDialogEndStatus::USER_CANCELED;
@ -374,7 +463,7 @@ void ImeDialogUi::Draw() {
}
void ImeDialogUi::DrawInputText() {
if (InputTextEx("##ImeDialogInput", state->placeholder, state->current_text, ORBIS_IME_DIALOG_MAX_TEXT_LENGTH, ImVec2(0, 0), ImGuiInputTextFlags_CallbackCharFilter, InputTextCallback, this)) {
if (InputTextEx("##ImeDialogInput", state->placeholder, state->current_text, state->max_text_length, ImVec2(0, 0), ImGuiInputTextFlags_CallbackCharFilter, InputTextCallback, this)) {
state->input_changed = true;
}
}
@ -382,7 +471,7 @@ void ImeDialogUi::DrawInputText() {
void ImeDialogUi::DrawMultiLineInputText() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
if (InputTextEx("##ImeDialogInput", state->placeholder, state->current_text, ORBIS_IME_DIALOG_MAX_TEXT_LENGTH, ImVec2(380.0f, 100.0f), ImGuiInputTextFlags_CallbackCharFilter | ImGuiInputTextFlags_Multiline, InputTextCallback, this)) {
if (InputTextEx("##ImeDialogInput", state->placeholder, state->current_text, state->max_text_length, ImVec2(380.0f, 100.0f), ImGuiInputTextFlags_CallbackCharFilter | ImGuiInputTextFlags_Multiline, InputTextCallback, this)) {
state->input_changed = true;
}
#pragma clang diagnostic pop
@ -393,8 +482,17 @@ int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
ASSERT(ui);
// Should we filter punctuation?
if (ui->state->is_numeric && (data->EventChar < '0' || data->EventChar > '9') && data->EventChar != '\b' && data->EventChar != ',' && data->EventChar != '.') {
return 1;
}
if (!ui->state->keyboard_filter) {
return 0;
}
// ImGui encodes ImWchar32 as multi-byte UTF-8 characters
char* event_char = reinterpret_cast<char*>(data->EventChar);
char* event_char = reinterpret_cast<char*>(&data->EventChar);
// Call the keyboard filter
OrbisImeKeycode src_keycode = {

View file

@ -7,7 +7,7 @@
#ifndef _WIN32
#include <iconv.h>
#endif
#include <imgui.h>
#include "core/libraries/dialogs/ime_dialog.h"
#include "common/types.h"
#include "imgui/imgui_layer.h"
@ -23,6 +23,7 @@ class ImeDialogState final {
s32 userId{};
bool is_multiLine{};
bool is_numeric{};
OrbisImeType type{};
OrbisImeEnterLabel enter_label{};
OrbisImeTextFilter text_filter{};
@ -34,20 +35,22 @@ class ImeDialogState final {
// A character can hold up to 4 bytes in UTF-8
char current_text[ORBIS_IME_DIALOG_MAX_TEXT_LENGTH * 4] = {0};
std::mutex mutex;
#ifndef _WIN32
iconv_t orbis_to_utf8 = (iconv_t)-1;
iconv_t utf8_to_orbis = (iconv_t)-1;
#endif
public:
ImeDialogState(const OrbisImeDialogParam* param = nullptr, const OrbisImeParamExtended* extended = nullptr);
~ImeDialogState();
ImeDialogState(const ImeDialogState& other) = delete;
ImeDialogState(ImeDialogState&& other) noexcept;
ImeDialogState& operator=(ImeDialogState&& other);
ImeDialogState() = default;
~ImeDialogState();
bool CopyTextToOrbisBuffer();
bool CallTextFilter();
private:
void Free();
bool CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status);
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text, std::size_t native_text_len);
@ -62,17 +65,19 @@ class ImeDialogUi final : public ImGui::Layer {
OrbisImeDialogResult* result{};
bool first_render = true;
std::mutex draw_mutex;
public:
explicit ImeDialogUi(ImeDialogState* state = nullptr, OrbisImeDialogStatus* status = nullptr, OrbisImeDialogResult* result = nullptr);
~ImeDialogUi() override;
ImeDialogUi(const ImeDialogUi& other) = delete;
ImeDialogUi(ImeDialogUi&& other) noexcept;
ImeDialogUi& operator=(ImeDialogUi other);
ImeDialogUi& operator=(ImeDialogUi&& other);
void Draw() override;
private:
void Free();
void DrawInputText();
void DrawMultiLineInputText();