mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-20 02:14:56 +00:00
core/libraries: IME implementation (#1436)
* core/libraries: IME implementation * Update ime_common.h --------- Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
parent
406041b7ad
commit
6e00121eb5
15 changed files with 818 additions and 130 deletions
|
@ -290,8 +290,6 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
||||||
src/core/libraries/audio3d/audio3d_error.h
|
src/core/libraries/audio3d/audio3d_error.h
|
||||||
src/core/libraries/audio3d/audio3d_impl.cpp
|
src/core/libraries/audio3d/audio3d_impl.cpp
|
||||||
src/core/libraries/audio3d/audio3d_impl.h
|
src/core/libraries/audio3d/audio3d_impl.h
|
||||||
src/core/libraries/ime/ime.cpp
|
|
||||||
src/core/libraries/ime/ime.h
|
|
||||||
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
|
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
|
||||||
src/core/libraries/game_live_streaming/gamelivestreaming.h
|
src/core/libraries/game_live_streaming/gamelivestreaming.h
|
||||||
src/core/libraries/remote_play/remoteplay.cpp
|
src/core/libraries/remote_play/remoteplay.cpp
|
||||||
|
@ -311,13 +309,17 @@ set(LIBC_SOURCES src/core/libraries/libc_internal/libc_internal.cpp
|
||||||
src/core/libraries/libc_internal/libc_internal.h
|
src/core/libraries/libc_internal/libc_internal.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(DIALOGS_LIB src/core/libraries/dialogs/error_dialog.cpp
|
set(IME_LIB src/core/libraries/ime/error_dialog.cpp
|
||||||
src/core/libraries/dialogs/error_dialog.h
|
src/core/libraries/ime/error_dialog.h
|
||||||
src/core/libraries/dialogs/ime_dialog_ui.cpp
|
src/core/libraries/ime/ime_common.h
|
||||||
src/core/libraries/dialogs/ime_dialog_ui.h
|
src/core/libraries/ime/ime_dialog_ui.cpp
|
||||||
src/core/libraries/dialogs/ime_dialog.cpp
|
src/core/libraries/ime/ime_dialog_ui.h
|
||||||
src/core/libraries/dialogs/ime_dialog.h
|
src/core/libraries/ime/ime_dialog.cpp
|
||||||
src/core/libraries/dialogs/error_codes.h
|
src/core/libraries/ime/ime_dialog.h
|
||||||
|
src/core/libraries/ime/ime_ui.cpp
|
||||||
|
src/core/libraries/ime/ime_ui.h
|
||||||
|
src/core/libraries/ime/ime.cpp
|
||||||
|
src/core/libraries/ime/ime.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PAD_LIB src/core/libraries/pad/pad.cpp
|
set(PAD_LIB src/core/libraries/pad/pad.cpp
|
||||||
|
@ -499,7 +501,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||||
${RANDOM_LIB}
|
${RANDOM_LIB}
|
||||||
${USBD_LIB}
|
${USBD_LIB}
|
||||||
${MISC_LIBS}
|
${MISC_LIBS}
|
||||||
${DIALOGS_LIB}
|
${IME_LIB}
|
||||||
${FIBER_LIB}
|
${FIBER_LIB}
|
||||||
${DEV_TOOLS}
|
${DEV_TOOLS}
|
||||||
src/core/debug_state.cpp
|
src/core/debug_state.cpp
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_NOT_INITIALIZED = 0x80ED0001; // not initialized
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_ALREADY_INITIALIZED = 0x80ED0002; // already initialized
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_PARAM_INVALID = 0x80ED0003; // Parameter is invalid
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_UNEXPECTED_FATAL = 0x80ED0004; // Unexpected fatal error
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_INVALID_STATE = 0x80ED0005; // not in a callable state
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_SERVICE_BUSY = 0x80ED0006; // Process is busy
|
|
||||||
constexpr int ORBIS_ERROR_DIALOG_ERROR_INVALID_USER_ID = 0x80ED0007; // Invalid user ID
|
|
|
@ -507,4 +507,49 @@ constexpr int ORBIS_FIBER_ERROR_ALIGNMENT = 0x80590002;
|
||||||
constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003;
|
constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003;
|
||||||
constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004;
|
constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004;
|
||||||
constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005;
|
constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005;
|
||||||
constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006;
|
constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006;
|
||||||
|
|
||||||
|
// ImeDialog library
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_NOT_INITIALIZED = 0x80ED0001;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_ALREADY_INITIALIZED = 0x80ED0002;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_PARAM_INVALID = 0x80ED0003;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_UNEXPECTED_FATAL = 0x80ED0004;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_INVALID_STATE = 0x80ED0005;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_SERVICE_BUSY = 0x80ED0006;
|
||||||
|
constexpr int ORBIS_ERROR_DIALOG_ERROR_INVALID_USER_ID = 0x80ED0007;
|
||||||
|
|
||||||
|
// Ime library
|
||||||
|
constexpr int ORBIS_IME_ERROR_BUSY = 0x80BC0001;
|
||||||
|
constexpr int ORBIS_IME_ERROR_NOT_OPENED = 0x80BC0002;
|
||||||
|
constexpr int ORBIS_IME_ERROR_NO_MEMORY = 0x80BC0003;
|
||||||
|
constexpr int ORBIS_IME_ERROR_CONNECTION_FAILED = 0x80BC0004;
|
||||||
|
constexpr int ORBIS_IME_ERROR_TOO_MANY_REQUESTS = 0x80BC0005;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_TEXT = 0x80BC0006;
|
||||||
|
constexpr int ORBIS_IME_ERROR_EVENT_OVERFLOW = 0x80BC0007;
|
||||||
|
constexpr int ORBIS_IME_ERROR_NOT_ACTIVE = 0x80BC0008;
|
||||||
|
constexpr int ORBIS_IME_ERROR_IME_SUSPENDING = 0x80BC0009;
|
||||||
|
constexpr int ORBIS_IME_ERROR_DEVICE_IN_USE = 0x80BC000A;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_USER_ID = 0x80BC0010;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_TYPE = 0x80BC0011;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_SUPPORTED_LANGUAGES = 0x80BC0012;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_ENTER_LABEL = 0x80BC0013;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_INPUT_METHOD = 0x80BC0014;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_OPTION = 0x80BC0015;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_MAX_TEXT_LENGTH = 0x80BC0016;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_INPUT_TEXT_BUFFER = 0x80BC0017;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_POSX = 0x80BC0018;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_POSY = 0x80BC0019;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_HORIZONTAL_ALIGNMENT = 0x80BC001A;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_VERTICAL_ALIGNMENT = 0x80BC001B;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_EXTENDED = 0x80BC001C;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_KEYBOARD_TYPE = 0x80BC001D;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_WORK = 0x80BC0020;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_ARG = 0x80BC0021;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_HANDLER = 0x80BC0022;
|
||||||
|
constexpr int ORBIS_IME_ERROR_NO_RESOURCE_ID = 0x80BC0023;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_MODE = 0x80BC0024;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_PARAM = 0x80BC0030;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_ADDRESS = 0x80BC0031;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_RESERVED = 0x80BC0032;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INVALID_TIMING = 0x80BC0033;
|
||||||
|
constexpr int ORBIS_IME_ERROR_INTERNAL = 0x80BC00FF;
|
|
@ -1,14 +1,108 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
#include "ime.h"
|
#include "ime.h"
|
||||||
|
#include "ime_ui.h"
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/linker.h"
|
||||||
|
|
||||||
namespace Libraries::Ime {
|
namespace Libraries::Ime {
|
||||||
|
|
||||||
|
static std::queue<OrbisImeEvent> g_ime_events;
|
||||||
|
static ImeState g_ime_state{};
|
||||||
|
static ImeUi g_ime_ui;
|
||||||
|
|
||||||
|
class ImeHandler {
|
||||||
|
public:
|
||||||
|
ImeHandler(const OrbisImeKeyboardParam* param) {
|
||||||
|
Init(param, false);
|
||||||
|
}
|
||||||
|
ImeHandler(const OrbisImeParam* param) {
|
||||||
|
Init(param, true);
|
||||||
|
}
|
||||||
|
~ImeHandler() = default;
|
||||||
|
|
||||||
|
void Init(const void* param, bool ime_mode) {
|
||||||
|
if (ime_mode) {
|
||||||
|
m_param.ime = *(OrbisImeParam*)param;
|
||||||
|
} else {
|
||||||
|
m_param.key = *(OrbisImeKeyboardParam*)param;
|
||||||
|
}
|
||||||
|
m_ime_mode = ime_mode;
|
||||||
|
|
||||||
|
// Open an event to let the game know the IME has started
|
||||||
|
OrbisImeEvent openEvent{};
|
||||||
|
openEvent.id = (ime_mode ? OrbisImeEventId::OPEN : OrbisImeEventId::KEYBOARD_OPEN);
|
||||||
|
|
||||||
|
if (ime_mode) {
|
||||||
|
sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width,
|
||||||
|
&openEvent.param.rect.height);
|
||||||
|
openEvent.param.rect.x = m_param.ime.posx;
|
||||||
|
openEvent.param.rect.y = m_param.ime.posy;
|
||||||
|
} else {
|
||||||
|
openEvent.param.resourceIdArray.userId = 1;
|
||||||
|
openEvent.param.resourceIdArray.resourceId[0] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Execute(nullptr, &openEvent, true);
|
||||||
|
|
||||||
|
if (ime_mode) {
|
||||||
|
g_ime_state = ImeState(&m_param.ime);
|
||||||
|
g_ime_ui = ImeUi(&g_ime_state, &m_param.ime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Update(OrbisImeEventHandler handler) {
|
||||||
|
std::unique_lock lock{g_ime_state.queue_mutex};
|
||||||
|
|
||||||
|
while (!g_ime_state.event_queue.empty()) {
|
||||||
|
OrbisImeEvent event = g_ime_state.event_queue.front();
|
||||||
|
g_ime_state.event_queue.pop();
|
||||||
|
Execute(handler, &event, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Execute(OrbisImeEventHandler handler, OrbisImeEvent* event, bool use_param_handler) {
|
||||||
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
|
||||||
|
if (m_ime_mode) {
|
||||||
|
OrbisImeParam param = m_param.ime;
|
||||||
|
if (use_param_handler) {
|
||||||
|
linker->ExecuteGuest(param.handler, param.arg, event);
|
||||||
|
} else {
|
||||||
|
linker->ExecuteGuest(handler, param.arg, event);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OrbisImeKeyboardParam param = m_param.key;
|
||||||
|
if (use_param_handler) {
|
||||||
|
linker->ExecuteGuest(param.handler, param.arg, event);
|
||||||
|
} else {
|
||||||
|
linker->ExecuteGuest(handler, param.arg, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsIme() {
|
||||||
|
return m_ime_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union ImeParam {
|
||||||
|
OrbisImeKeyboardParam key;
|
||||||
|
OrbisImeParam ime;
|
||||||
|
} m_param{};
|
||||||
|
bool m_ime_mode = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unique_ptr<ImeHandler> g_ime_handler;
|
||||||
|
|
||||||
int PS4_SYSV_ABI FinalizeImeModule() {
|
int PS4_SYSV_ABI FinalizeImeModule() {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
|
@ -34,8 +128,19 @@ int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeClose() {
|
s32 PS4_SYSV_ABI sceImeClose() {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_INFO(Lib_Ime, "(STUBBED) called");
|
||||||
|
|
||||||
|
if (!g_ime_handler) {
|
||||||
|
return ORBIS_IME_ERROR_NOT_OPENED;
|
||||||
|
}
|
||||||
|
if (!g_ime_handler->IsIme()) {
|
||||||
|
return ORBIS_IME_ERROR_NOT_OPENED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_handler.release();
|
||||||
|
g_ime_ui = ImeUi();
|
||||||
|
g_ime_state = ImeState();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +209,42 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeGetPanelSize() {
|
s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_INFO(Lib_Ime, "called");
|
||||||
|
|
||||||
|
if (!width || !height) {
|
||||||
|
return ORBIS_IME_ERROR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (param->type) {
|
||||||
|
case OrbisImeType::DEFAULT:
|
||||||
|
case OrbisImeType::BASIC_LATIN:
|
||||||
|
case OrbisImeType::URL:
|
||||||
|
case OrbisImeType::MAIL:
|
||||||
|
// We set our custom sizes, commented sizes are the original ones
|
||||||
|
*width = 500; // 793
|
||||||
|
*height = 100; // 408
|
||||||
|
break;
|
||||||
|
case OrbisImeType::NUMBER:
|
||||||
|
*width = 370;
|
||||||
|
*height = 402;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeKeyboardClose() {
|
s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_INFO(Lib_Ime, "(STUBBED) called");
|
||||||
|
|
||||||
|
if (!g_ime_handler) {
|
||||||
|
return ORBIS_IME_ERROR_NOT_OPENED;
|
||||||
|
}
|
||||||
|
if (g_ime_handler->IsIme()) {
|
||||||
|
return ORBIS_IME_ERROR_NOT_OPENED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_handler.release();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,9 +258,19 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeKeyboardOpen() {
|
s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
|
||||||
|
if (!param) {
|
||||||
|
return ORBIS_IME_ERROR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
if (g_ime_handler) {
|
||||||
|
return ORBIS_IME_ERROR_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// g_ime_handler = std::make_unique<ImeHandler>(param);
|
||||||
|
// return ORBIS_OK;
|
||||||
|
return ORBIS_IME_ERROR_CONNECTION_FAILED; // Fixup
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeKeyboardOpenInternal() {
|
int PS4_SYSV_ABI sceImeKeyboardOpenInternal() {
|
||||||
|
@ -144,8 +288,19 @@ int PS4_SYSV_ABI sceImeKeyboardUpdate() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeOpen() {
|
s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_INFO(Lib_Ime, "called");
|
||||||
|
|
||||||
|
if (!g_ime_handler) {
|
||||||
|
g_ime_handler = std::make_unique<ImeHandler>(param);
|
||||||
|
} else {
|
||||||
|
if (g_ime_handler->IsIme()) {
|
||||||
|
return ORBIS_IME_ERROR_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ime_handler->Init((void*)param, true);
|
||||||
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +309,15 @@ int PS4_SYSV_ABI sceImeOpenInternal() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeParamInit() {
|
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_INFO(Lib_Ime, "called");
|
||||||
return ORBIS_OK;
|
|
||||||
|
if (!param) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(param, 0, sizeof(OrbisImeParam));
|
||||||
|
param->userId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeSetCandidateIndex() {
|
int PS4_SYSV_ABI sceImeSetCandidateIndex() {
|
||||||
|
@ -164,7 +325,7 @@ int PS4_SYSV_ABI sceImeSetCandidateIndex() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeSetCaret() {
|
int PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -179,9 +340,14 @@ int PS4_SYSV_ABI sceImeSetTextGeometry() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeUpdate() {
|
s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) {
|
||||||
LOG_ERROR(Lib_Ime, "(STUBBED) called");
|
LOG_TRACE(Lib_Ime, "called");
|
||||||
return ORBIS_OK;
|
|
||||||
|
if (!g_ime_handler) {
|
||||||
|
return ORBIS_IME_ERROR_NOT_OPENED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_ime_handler->Update(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceImeVshClearPreedit() {
|
int PS4_SYSV_ABI sceImeVshClearPreedit() {
|
||||||
|
|
|
@ -5,12 +5,62 @@
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#include "ime_common.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Libraries::Ime {
|
namespace Libraries::Ime {
|
||||||
|
|
||||||
|
constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048;
|
||||||
|
|
||||||
|
enum class OrbisImeKeyboardOption : u32 {
|
||||||
|
DEFAULT = 0,
|
||||||
|
REPEAT = 1,
|
||||||
|
REPEAT_EACH_KEY = 2,
|
||||||
|
ADD_OSK = 4,
|
||||||
|
EFFECTIVE_WITH_TIME = 8,
|
||||||
|
DISABLE_RESUME = 16,
|
||||||
|
DISABLE_CAPSLOCK_WITHOUT_SHIFT = 32,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption)
|
||||||
|
|
||||||
|
struct OrbisImeKeyboardParam {
|
||||||
|
OrbisImeKeyboardOption option;
|
||||||
|
s8 reserved1[4];
|
||||||
|
void* arg;
|
||||||
|
OrbisImeEventHandler handler;
|
||||||
|
s8 reserved2[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeParam {
|
||||||
|
s32 userId;
|
||||||
|
OrbisImeType type;
|
||||||
|
u64 supportedLanguages;
|
||||||
|
OrbisImeEnterLabel enterLabel;
|
||||||
|
OrbisImeInputMethod inputMethod;
|
||||||
|
OrbisImeTextFilter filter;
|
||||||
|
u32 option;
|
||||||
|
u32 maxTextLength;
|
||||||
|
char16_t* inputTextBuffer;
|
||||||
|
float posx;
|
||||||
|
float posy;
|
||||||
|
OrbisImeHorizontalAlignment horizontalAlignment;
|
||||||
|
OrbisImeVerticalAlignment verticalAlignment;
|
||||||
|
void* work;
|
||||||
|
void* arg;
|
||||||
|
OrbisImeEventHandler handler;
|
||||||
|
s8 reserved[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeCaret {
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
u32 height;
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
int PS4_SYSV_ABI FinalizeImeModule();
|
int PS4_SYSV_ABI FinalizeImeModule();
|
||||||
int PS4_SYSV_ABI InitializeImeModule();
|
int PS4_SYSV_ABI InitializeImeModule();
|
||||||
int PS4_SYSV_ABI sceImeCheckFilterText();
|
int PS4_SYSV_ABI sceImeCheckFilterText();
|
||||||
|
@ -30,22 +80,22 @@ int PS4_SYSV_ABI sceImeDisableController();
|
||||||
int PS4_SYSV_ABI sceImeFilterText();
|
int PS4_SYSV_ABI sceImeFilterText();
|
||||||
int PS4_SYSV_ABI sceImeForTestFunction();
|
int PS4_SYSV_ABI sceImeForTestFunction();
|
||||||
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
|
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
|
||||||
int PS4_SYSV_ABI sceImeGetPanelSize();
|
s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height);
|
||||||
int PS4_SYSV_ABI sceImeKeyboardClose();
|
s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId);
|
||||||
int PS4_SYSV_ABI sceImeKeyboardGetInfo();
|
int PS4_SYSV_ABI sceImeKeyboardGetInfo();
|
||||||
int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
|
int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
|
||||||
int PS4_SYSV_ABI sceImeKeyboardOpen();
|
s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param);
|
||||||
int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
|
int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
|
||||||
int PS4_SYSV_ABI sceImeKeyboardSetMode();
|
int PS4_SYSV_ABI sceImeKeyboardSetMode();
|
||||||
int PS4_SYSV_ABI sceImeKeyboardUpdate();
|
int PS4_SYSV_ABI sceImeKeyboardUpdate();
|
||||||
int PS4_SYSV_ABI sceImeOpen();
|
s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended);
|
||||||
int PS4_SYSV_ABI sceImeOpenInternal();
|
int PS4_SYSV_ABI sceImeOpenInternal();
|
||||||
int PS4_SYSV_ABI sceImeParamInit();
|
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param);
|
||||||
int PS4_SYSV_ABI sceImeSetCandidateIndex();
|
int PS4_SYSV_ABI sceImeSetCandidateIndex();
|
||||||
int PS4_SYSV_ABI sceImeSetCaret();
|
s32 PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret);
|
||||||
int PS4_SYSV_ABI sceImeSetText();
|
int PS4_SYSV_ABI sceImeSetText();
|
||||||
int PS4_SYSV_ABI sceImeSetTextGeometry();
|
int PS4_SYSV_ABI sceImeSetTextGeometry();
|
||||||
int PS4_SYSV_ABI sceImeUpdate();
|
s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler);
|
||||||
int PS4_SYSV_ABI sceImeVshClearPreedit();
|
int PS4_SYSV_ABI sceImeVshClearPreedit();
|
||||||
int PS4_SYSV_ABI sceImeVshClose();
|
int PS4_SYSV_ABI sceImeVshClose();
|
||||||
int PS4_SYSV_ABI sceImeVshConfirmPreedit();
|
int PS4_SYSV_ABI sceImeVshConfirmPreedit();
|
||||||
|
|
184
src/core/libraries/ime/ime_common.h
Normal file
184
src/core/libraries/ime/ime_common.h
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "common/enum.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/rtc/rtc.h"
|
||||||
|
|
||||||
|
enum class OrbisImeType : u32 {
|
||||||
|
DEFAULT = 0,
|
||||||
|
BASIC_LATIN = 1,
|
||||||
|
URL = 2,
|
||||||
|
MAIL = 3,
|
||||||
|
NUMBER = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeHorizontalAlignment : u32 {
|
||||||
|
LEFT = 0,
|
||||||
|
CENTER = 1,
|
||||||
|
RIGHT = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeVerticalAlignment : u32 {
|
||||||
|
TOP = 0,
|
||||||
|
CENTER = 1,
|
||||||
|
BOTTOM = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeEnterLabel : u32 {
|
||||||
|
DEFAULT = 0,
|
||||||
|
SEND = 1,
|
||||||
|
SEARCH = 2,
|
||||||
|
GO = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeInputMethod : u32 {
|
||||||
|
DEFAULT = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeEventId : u32 {
|
||||||
|
OPEN = 0,
|
||||||
|
UPDATE_TEXT = 1,
|
||||||
|
UPDATE_CARET = 2,
|
||||||
|
PRESS_CLOSE = 4,
|
||||||
|
PRESS_ENTER = 5,
|
||||||
|
ABORT = 6,
|
||||||
|
CANDIDATE_LIST_START = 7,
|
||||||
|
CANDIDATE_LIST_END = 8,
|
||||||
|
CANDIDATE_WORD = 9,
|
||||||
|
CANDIDATE_INDEX = 10,
|
||||||
|
CANDIDATE_DONE = 11,
|
||||||
|
CANDIDATE_CANCEL = 12,
|
||||||
|
CHANGE_DEVICE = 14,
|
||||||
|
CHANGE_INPUT_METHOD_STATE = 18,
|
||||||
|
|
||||||
|
KEYBOARD_OPEN = 256,
|
||||||
|
KEYBOARD_KEYCODE_DOWN = 257,
|
||||||
|
KEYBOARD_KEYCODE_UP = 258,
|
||||||
|
KEYBOARD_KEYCODE_REPEAT = 259,
|
||||||
|
KEYBOARD_CONNECTION = 260,
|
||||||
|
KEYBOARD_DISCONNECTION = 261,
|
||||||
|
KEYBOARD_ABORT = 262,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeKeyboardType : u32 {
|
||||||
|
NONE = 0,
|
||||||
|
DANISH = 1,
|
||||||
|
GERMAN = 2,
|
||||||
|
GERMAN_SW = 3,
|
||||||
|
ENGLISH_US = 4,
|
||||||
|
ENGLISH_GB = 5,
|
||||||
|
SPANISH = 6,
|
||||||
|
SPANISH_LA = 7,
|
||||||
|
FINNISH = 8,
|
||||||
|
FRENCH = 9,
|
||||||
|
FRENCH_BR = 10,
|
||||||
|
FRENCH_CA = 11,
|
||||||
|
FRENCH_SW = 12,
|
||||||
|
ITALIAN = 13,
|
||||||
|
DUTCH = 14,
|
||||||
|
NORWEGIAN = 15,
|
||||||
|
POLISH = 16,
|
||||||
|
PORTUGUESE_BR = 17,
|
||||||
|
PORTUGUESE_PT = 18,
|
||||||
|
RUSSIAN = 19,
|
||||||
|
SWEDISH = 20,
|
||||||
|
TURKISH = 21,
|
||||||
|
JAPANESE_ROMAN = 22,
|
||||||
|
JAPANESE_KANA = 23,
|
||||||
|
KOREAN = 24,
|
||||||
|
SM_CHINESE = 25,
|
||||||
|
TR_CHINESE_ZY = 26,
|
||||||
|
TR_CHINESE_PY_HK = 27,
|
||||||
|
TR_CHINESE_PY_TW = 28,
|
||||||
|
TR_CHINESE_CG = 29,
|
||||||
|
ARABIC_AR = 30,
|
||||||
|
THAI = 31,
|
||||||
|
CZECH = 32,
|
||||||
|
GREEK = 33,
|
||||||
|
INDONESIAN = 34,
|
||||||
|
VIETNAMESE = 35,
|
||||||
|
ROMANIAN = 36,
|
||||||
|
HUNGARIAN = 37,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeDeviceType : u32 {
|
||||||
|
NONE = 0,
|
||||||
|
CONTROLLER = 1,
|
||||||
|
EXT_KEYBOARD = 2,
|
||||||
|
REMOTE_OSK = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeRect {
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeTextAreaProperty {
|
||||||
|
u32 mode; // OrbisImeTextAreaMode
|
||||||
|
u32 index;
|
||||||
|
s32 length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeEditText {
|
||||||
|
char16_t* str;
|
||||||
|
u32 caretIndex;
|
||||||
|
u32 areaNum;
|
||||||
|
OrbisImeTextAreaProperty textArea[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeKeycode {
|
||||||
|
u16 keycode;
|
||||||
|
char16_t character;
|
||||||
|
u32 status;
|
||||||
|
OrbisImeKeyboardType type;
|
||||||
|
s32 userId;
|
||||||
|
u32 resourceId;
|
||||||
|
Libraries::Rtc::OrbisRtcTick timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeKeyboardResourceIdArray {
|
||||||
|
s32 userId;
|
||||||
|
u32 resourceId[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OrbisImeCaretMovementDirection : u32 {
|
||||||
|
STILL = 0,
|
||||||
|
LEFT = 1,
|
||||||
|
RIGHT = 2,
|
||||||
|
UP = 3,
|
||||||
|
DOWN = 4,
|
||||||
|
HOME = 5,
|
||||||
|
END = 6,
|
||||||
|
PAGE_UP = 7,
|
||||||
|
PAGE_DOWN = 8,
|
||||||
|
TOP = 9,
|
||||||
|
BOTTOM = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
union OrbisImeEventParam {
|
||||||
|
OrbisImeRect rect;
|
||||||
|
OrbisImeEditText text;
|
||||||
|
OrbisImeCaretMovementDirection caretMove;
|
||||||
|
OrbisImeKeycode keycode;
|
||||||
|
OrbisImeKeyboardResourceIdArray resourceIdArray;
|
||||||
|
char16_t* candidateWord;
|
||||||
|
s32 candidateIndex;
|
||||||
|
OrbisImeDeviceType deviceType;
|
||||||
|
u32 inputMethodState;
|
||||||
|
s8 reserved[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OrbisImeEvent {
|
||||||
|
OrbisImeEventId id;
|
||||||
|
OrbisImeEventParam param;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PS4_SYSV_ABI int (*OrbisImeTextFilter)(char16_t* outText, u32* outTextLength,
|
||||||
|
const char16_t* srcText, u32 srcTextLength);
|
||||||
|
|
||||||
|
typedef PS4_SYSV_ABI void (*OrbisImeEventHandler)(void* arg, const OrbisImeEvent* e);
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "common/enum.h"
|
#include "common/enum.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "ime_common.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
|
@ -68,21 +69,6 @@ enum class OrbisImeDialogEndStatus : u32 {
|
||||||
ABORTED = 2,
|
ABORTED = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OrbisImeType : u32 {
|
|
||||||
DEFAULT = 0,
|
|
||||||
BASIC_LATIN = 1,
|
|
||||||
URL = 2,
|
|
||||||
MAIL = 3,
|
|
||||||
NUMBER = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OrbisImeEnterLabel : u32 {
|
|
||||||
DEFAULT = 0,
|
|
||||||
SEND = 1,
|
|
||||||
SEARCH = 2,
|
|
||||||
GO = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OrbisImeDialogOption : u32 {
|
enum class OrbisImeDialogOption : u32 {
|
||||||
DEFAULT = 0,
|
DEFAULT = 0,
|
||||||
MULTILINE = 1,
|
MULTILINE = 1,
|
||||||
|
@ -91,25 +77,8 @@ enum class OrbisImeDialogOption : u32 {
|
||||||
// TODO: Document missing options
|
// TODO: Document missing options
|
||||||
LARGE_RESOLUTION = 1024,
|
LARGE_RESOLUTION = 1024,
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDialogOption)
|
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDialogOption)
|
||||||
|
|
||||||
enum class OrbisImeInputMethod : u32 {
|
|
||||||
DEFAULT = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OrbisImeHorizontalAlignment : u32 {
|
|
||||||
LEFT = 0,
|
|
||||||
CENTER = 1,
|
|
||||||
RIGHT = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OrbisImeVerticalAlignment : u32 {
|
|
||||||
TOP = 0,
|
|
||||||
CENTER = 1,
|
|
||||||
BOTTOM = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OrbisImePanelPriority : u32 {
|
enum class OrbisImePanelPriority : u32 {
|
||||||
DEFAULT = 0,
|
DEFAULT = 0,
|
||||||
ALPHABET = 1,
|
ALPHABET = 1,
|
||||||
|
@ -117,47 +86,6 @@ enum class OrbisImePanelPriority : u32 {
|
||||||
ACCENT = 3,
|
ACCENT = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OrbisImeKeyboardType : u32 {
|
|
||||||
NONE = 0,
|
|
||||||
DANISH = 1,
|
|
||||||
GERMAN = 2,
|
|
||||||
GERMAN_SW = 3,
|
|
||||||
ENGLISH_US = 4,
|
|
||||||
ENGLISH_GB = 5,
|
|
||||||
SPANISH = 6,
|
|
||||||
SPANISH_LA = 7,
|
|
||||||
FINNISH = 8,
|
|
||||||
FRENCH = 9,
|
|
||||||
FRENCH_BR = 10,
|
|
||||||
FRENCH_CA = 11,
|
|
||||||
FRENCH_SW = 12,
|
|
||||||
ITALIAN = 13,
|
|
||||||
DUTCH = 14,
|
|
||||||
NORWEGIAN = 15,
|
|
||||||
POLISH = 16,
|
|
||||||
PORTUGUESE_BR = 17,
|
|
||||||
PORTUGUESE_PT = 18,
|
|
||||||
RUSSIAN = 19,
|
|
||||||
SWEDISH = 20,
|
|
||||||
TURKISH = 21,
|
|
||||||
JAPANESE_ROMAN = 22,
|
|
||||||
JAPANESE_KANA = 23,
|
|
||||||
KOREAN = 24,
|
|
||||||
SM_CHINESE = 25,
|
|
||||||
TR_CHINESE_ZY = 26,
|
|
||||||
TR_CHINESE_PY_HK = 27,
|
|
||||||
TR_CHINESE_PY_TW = 28,
|
|
||||||
TR_CHINESE_CG = 29,
|
|
||||||
ARABIC_AR = 30,
|
|
||||||
THAI = 31,
|
|
||||||
CZECH = 32,
|
|
||||||
GREEK = 33,
|
|
||||||
INDONESIAN = 34,
|
|
||||||
VIETNAMESE = 35,
|
|
||||||
ROMANIAN = 36,
|
|
||||||
HUNGARIAN = 37,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OrbisImeColor {
|
struct OrbisImeColor {
|
||||||
u8 r;
|
u8 r;
|
||||||
u8 g;
|
u8 g;
|
||||||
|
@ -180,9 +108,6 @@ struct OrbisImeKeycode {
|
||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PS4_SYSV_ABI int (*OrbisImeTextFilter)(char16_t* outText, u32* outTextLength,
|
|
||||||
const char16_t* srcText, u32 srcTextLength);
|
|
||||||
|
|
||||||
typedef PS4_SYSV_ABI int (*OrbisImeExtKeyboardFilter)(const OrbisImeKeycode* srcKeycode,
|
typedef PS4_SYSV_ABI int (*OrbisImeExtKeyboardFilter)(const OrbisImeKeycode* srcKeycode,
|
||||||
u16* outKeycode, u32* outStatus,
|
u16* outKeycode, u32* outStatus,
|
||||||
void* reserved);
|
void* reserved);
|
|
@ -9,8 +9,8 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/libraries/dialogs/ime_dialog.h"
|
#include "core/libraries/ime/ime_dialog.h"
|
||||||
#include "core/libraries/dialogs/ime_dialog_ui.h"
|
#include "core/libraries/ime/ime_dialog_ui.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "imgui/imgui_std.h"
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
|
@ -22,8 +22,9 @@ namespace Libraries::ImeDialog {
|
||||||
|
|
||||||
ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param,
|
ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param,
|
||||||
const OrbisImeParamExtended* extended) {
|
const OrbisImeParamExtended* extended) {
|
||||||
if (!param)
|
if (!param) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
userId = param->userId;
|
userId = param->userId;
|
||||||
is_multiLine = True(param->option & OrbisImeDialogOption::MULTILINE);
|
is_multiLine = True(param->option & OrbisImeDialogOption::MULTILINE);
|
||||||
|
@ -344,7 +345,6 @@ void ImeDialogUi::DrawMultiLineInputText() {
|
||||||
|
|
||||||
int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||||
ImeDialogUi* ui = static_cast<ImeDialogUi*>(data->UserData);
|
ImeDialogUi* ui = static_cast<ImeDialogUi*>(data->UserData);
|
||||||
|
|
||||||
ASSERT(ui);
|
ASSERT(ui);
|
||||||
|
|
||||||
// Should we filter punctuation?
|
// Should we filter punctuation?
|
|
@ -8,7 +8,7 @@
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include "common/cstring.h"
|
#include "common/cstring.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "core/libraries/dialogs/ime_dialog.h"
|
#include "core/libraries/ime/ime_dialog.h"
|
||||||
#include "imgui/imgui_layer.h"
|
#include "imgui/imgui_layer.h"
|
||||||
|
|
||||||
namespace Libraries::ImeDialog {
|
namespace Libraries::ImeDialog {
|
252
src/core/libraries/ime/ime_ui.cpp
Normal file
252
src/core/libraries/ime/ime_ui.cpp
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "ime_ui.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
|
namespace Libraries::Ime {
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||||
|
|
||||||
|
ImeState::ImeState(const OrbisImeParam* param) {
|
||||||
|
if (!param) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
work_buffer = param->work;
|
||||||
|
text_buffer = param->inputTextBuffer;
|
||||||
|
|
||||||
|
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
|
||||||
|
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(),
|
||||||
|
ORBIS_IME_MAX_TEXT_LENGTH * 4)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeState::ImeState(ImeState&& other) noexcept
|
||||||
|
: input_changed(other.input_changed), work_buffer(other.work_buffer),
|
||||||
|
text_buffer(other.text_buffer), current_text(std::move(other.current_text)),
|
||||||
|
event_queue(std::move(other.event_queue)) {
|
||||||
|
other.text_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeState& ImeState::operator=(ImeState&& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
input_changed = other.input_changed;
|
||||||
|
work_buffer = other.work_buffer;
|
||||||
|
text_buffer = other.text_buffer;
|
||||||
|
current_text = std::move(other.current_text);
|
||||||
|
event_queue = std::move(other.event_queue);
|
||||||
|
|
||||||
|
other.text_buffer = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeState::SendEvent(OrbisImeEvent* event) {
|
||||||
|
std::unique_lock lock{queue_mutex};
|
||||||
|
event_queue.push(*event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeState::SendEnterEvent() {
|
||||||
|
OrbisImeEvent enterEvent{};
|
||||||
|
enterEvent.id = OrbisImeEventId::PRESS_ENTER;
|
||||||
|
SendEvent(&enterEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeState::SendCloseEvent() {
|
||||||
|
OrbisImeEvent closeEvent{};
|
||||||
|
closeEvent.id = OrbisImeEventId::PRESS_CLOSE;
|
||||||
|
closeEvent.param.text.str = reinterpret_cast<char16_t*>(work_buffer);
|
||||||
|
SendEvent(&closeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
|
||||||
|
char* utf8_text, std::size_t utf8_text_len) {
|
||||||
|
std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
|
||||||
|
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
|
||||||
|
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImeState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
|
||||||
|
char16_t* orbis_text, std::size_t orbis_text_len) {
|
||||||
|
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
|
||||||
|
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeUi::ImeUi(ImeState* state, const OrbisImeParam* param) : state(state), ime_param(param) {
|
||||||
|
if (param) {
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeUi::~ImeUi() {
|
||||||
|
std::scoped_lock lock(draw_mutex);
|
||||||
|
Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImeUi& ImeUi::operator=(ImeUi&& other) {
|
||||||
|
std::scoped_lock lock(draw_mutex, other.draw_mutex);
|
||||||
|
Free();
|
||||||
|
|
||||||
|
state = other.state;
|
||||||
|
ime_param = other.ime_param;
|
||||||
|
first_render = other.first_render;
|
||||||
|
other.state = nullptr;
|
||||||
|
other.ime_param = nullptr;
|
||||||
|
|
||||||
|
AddLayer(this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeUi::Draw() {
|
||||||
|
std::unique_lock lock{draw_mutex};
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
|
// TODO: Figure out how to properly translate the positions -
|
||||||
|
// for example, if a game wants to center the IME panel,
|
||||||
|
// we have to translate the panel position in a way that it
|
||||||
|
// still becomes centered, as the game normally calculates
|
||||||
|
// the position assuming a it's running on a 1920x1080 screen,
|
||||||
|
// whereas we are running on a 1280x720 window size (by default).
|
||||||
|
//
|
||||||
|
// e.g. Panel position calculation from a game:
|
||||||
|
// param.posx = (1920 / 2) - (panelWidth / 2);
|
||||||
|
// param.posy = (1080 / 2) - (panelHeight / 2);
|
||||||
|
const auto size = GetIO().DisplaySize;
|
||||||
|
f32 pos_x = (ime_param->posx / 1920.0f * (float)size.x);
|
||||||
|
f32 pos_y = (ime_param->posy / 1080.0f * (float)size.y);
|
||||||
|
|
||||||
|
ImVec2 window_pos = {pos_x, pos_y};
|
||||||
|
ImVec2 window_size = {500.0f, 100.0f};
|
||||||
|
|
||||||
|
// SetNextWindowPos(window_pos);
|
||||||
|
SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f),
|
||||||
|
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||||
|
SetNextWindowSize(window_size);
|
||||||
|
SetNextWindowCollapsed(false);
|
||||||
|
|
||||||
|
if (first_render || !io.NavActive) {
|
||||||
|
SetNextWindowFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Begin("IME##Ime", nullptr,
|
||||||
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
DrawPrettyBackground();
|
||||||
|
|
||||||
|
DrawInputText();
|
||||||
|
SetCursorPosY(GetCursorPosY() + 10.0f);
|
||||||
|
|
||||||
|
const char* button_text;
|
||||||
|
button_text = "Done##ImeDone";
|
||||||
|
|
||||||
|
float button_spacing = 10.0f;
|
||||||
|
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing;
|
||||||
|
float button_start_pos = (window_size.x - total_button_width) / 2.0f;
|
||||||
|
|
||||||
|
SetCursorPosX(button_start_pos);
|
||||||
|
|
||||||
|
if (Button(button_text, BUTTON_SIZE) || (IsKeyPressed(ImGuiKey_Enter))) {
|
||||||
|
state->SendEnterEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine(0.0f, button_spacing);
|
||||||
|
|
||||||
|
if (Button("Close##ImeClose", BUTTON_SIZE)) {
|
||||||
|
state->SendCloseEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
first_render = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeUi::DrawInputText() {
|
||||||
|
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f};
|
||||||
|
SetCursorPosX(20.0f);
|
||||||
|
if (first_render) {
|
||||||
|
SetKeyboardFocusHere();
|
||||||
|
}
|
||||||
|
if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength,
|
||||||
|
input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) {
|
||||||
|
state->input_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||||
|
ImeUi* ui = static_cast<ImeUi*>(data->UserData);
|
||||||
|
ASSERT(ui);
|
||||||
|
|
||||||
|
static int lastCaretPos = -1;
|
||||||
|
if (lastCaretPos == -1) {
|
||||||
|
lastCaretPos = data->CursorPos;
|
||||||
|
} else if (data->CursorPos != lastCaretPos) {
|
||||||
|
OrbisImeCaretMovementDirection caretDirection = OrbisImeCaretMovementDirection::STILL;
|
||||||
|
if (data->CursorPos < lastCaretPos) {
|
||||||
|
caretDirection = OrbisImeCaretMovementDirection::LEFT;
|
||||||
|
} else if (data->CursorPos > lastCaretPos) {
|
||||||
|
caretDirection = OrbisImeCaretMovementDirection::RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbisImeEvent event{};
|
||||||
|
event.id = OrbisImeEventId::UPDATE_CARET;
|
||||||
|
event.param.caretMove = caretDirection;
|
||||||
|
|
||||||
|
lastCaretPos = data->CursorPos;
|
||||||
|
ui->state->SendEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string lastText;
|
||||||
|
std::string currentText(data->Buf, data->BufTextLen);
|
||||||
|
if (currentText != lastText) {
|
||||||
|
OrbisImeEditText eventParam{};
|
||||||
|
eventParam.str = reinterpret_cast<char16_t*>(ui->ime_param->work);
|
||||||
|
eventParam.caretIndex = data->CursorPos;
|
||||||
|
eventParam.areaNum = 1;
|
||||||
|
|
||||||
|
eventParam.textArea[0].mode = 1; // Edit mode
|
||||||
|
eventParam.textArea[0].index = data->CursorPos;
|
||||||
|
eventParam.textArea[0].length = data->BufTextLen;
|
||||||
|
|
||||||
|
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str,
|
||||||
|
ui->ime_param->maxTextLength)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen,
|
||||||
|
ui->ime_param->inputTextBuffer,
|
||||||
|
ui->ime_param->maxTextLength)) {
|
||||||
|
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbisImeEvent event{};
|
||||||
|
event.id = OrbisImeEventId::UPDATE_TEXT;
|
||||||
|
event.param.text = eventParam;
|
||||||
|
|
||||||
|
lastText = currentText;
|
||||||
|
ui->state->SendEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImeUi::Free() {
|
||||||
|
RemoveLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Libraries::Ime
|
76
src/core/libraries/ime/ime_ui.h
Normal file
76
src/core/libraries/ime/ime_ui.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <queue>
|
||||||
|
#include "imgui/imgui_layer.h"
|
||||||
|
|
||||||
|
#include "common/cstring.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#include "ime.h"
|
||||||
|
|
||||||
|
namespace Libraries::Ime {
|
||||||
|
|
||||||
|
class ImeHandler;
|
||||||
|
class ImeUi;
|
||||||
|
|
||||||
|
class ImeState {
|
||||||
|
friend class ImeHandler;
|
||||||
|
friend class ImeUi;
|
||||||
|
|
||||||
|
bool input_changed = false;
|
||||||
|
|
||||||
|
void* work_buffer{};
|
||||||
|
|
||||||
|
char16_t* text_buffer{};
|
||||||
|
|
||||||
|
// A character can hold up to 4 bytes in UTF-8
|
||||||
|
Common::CString<ORBIS_IME_MAX_TEXT_LENGTH * 4> current_text;
|
||||||
|
|
||||||
|
std::queue<OrbisImeEvent> event_queue;
|
||||||
|
std::mutex queue_mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImeState(const OrbisImeParam* param = nullptr);
|
||||||
|
ImeState(ImeState&& other) noexcept;
|
||||||
|
ImeState& operator=(ImeState&& other) noexcept;
|
||||||
|
|
||||||
|
void SendEvent(OrbisImeEvent* event);
|
||||||
|
void SendEnterEvent();
|
||||||
|
void SendCloseEvent();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
|
||||||
|
std::size_t native_text_len);
|
||||||
|
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len,
|
||||||
|
char16_t* orbis_text, std::size_t orbis_text_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImeUi : public ImGui::Layer {
|
||||||
|
ImeState* state{};
|
||||||
|
const OrbisImeParam* ime_param{};
|
||||||
|
|
||||||
|
bool first_render = true;
|
||||||
|
std::mutex draw_mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImeUi(ImeState* state = nullptr, const OrbisImeParam* param = nullptr);
|
||||||
|
~ImeUi() override;
|
||||||
|
ImeUi(const ImeUi& other) = delete;
|
||||||
|
ImeUi& operator=(ImeUi&& other);
|
||||||
|
|
||||||
|
void Draw() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Free();
|
||||||
|
|
||||||
|
void DrawInputText();
|
||||||
|
|
||||||
|
static int InputTextCallback(ImGuiInputTextCallbackData* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Libraries::Ime
|
|
@ -8,12 +8,12 @@
|
||||||
#include "core/libraries/audio/audioout.h"
|
#include "core/libraries/audio/audioout.h"
|
||||||
#include "core/libraries/audio3d/audio3d.h"
|
#include "core/libraries/audio3d/audio3d.h"
|
||||||
#include "core/libraries/avplayer/avplayer.h"
|
#include "core/libraries/avplayer/avplayer.h"
|
||||||
#include "core/libraries/dialogs/error_dialog.h"
|
|
||||||
#include "core/libraries/dialogs/ime_dialog.h"
|
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
||||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||||
|
#include "core/libraries/ime/error_dialog.h"
|
||||||
#include "core/libraries/ime/ime.h"
|
#include "core/libraries/ime/ime.h"
|
||||||
|
#include "core/libraries/ime/ime_dialog.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libpng/pngdec.h"
|
#include "core/libraries/libpng/pngdec.h"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue