mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-22 04:24:44 +00:00
Functional implementation
This commit is contained in:
parent
de06bd38a5
commit
c10a06422f
4 changed files with 362 additions and 89 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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 = {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue