From e5879c622eb6d389d793c114ee915945ce78a180 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Tue, 3 Dec 2024 10:05:51 +0200 Subject: [PATCH] Misc Ime fixes continue (#1655) * core/libraries: Misc. Ime fixes * fixed issues --------- Co-authored-by: Daniel R <47796739+polybiusproxy@users.noreply.github.com> --- src/core/libraries/ime/ime.cpp | 95 +++++++++++++++++++---------- src/core/libraries/ime/ime.h | 26 ++++++-- src/core/libraries/ime/ime_common.h | 2 +- src/core/libraries/ime/ime_ui.cpp | 81 ++++++++++++------------ src/core/libraries/ime/ime_ui.h | 6 +- 5 files changed, 131 insertions(+), 79 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 700585ff3..dfd659db8 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -44,10 +44,14 @@ public: openEvent.param.rect.y = m_param.ime.posy; } else { openEvent.param.resource_id_array.userId = 1; - openEvent.param.resource_id_array.resource_id[0] = 1; + openEvent.param.resource_id_array.resourceId[0] = 1; } - Execute(nullptr, &openEvent, true); + // Are we supposed to call the event handler on init with + // ADD_OSK? + if (!ime_mode && False(m_param.key.option & OrbisImeKeyboardOption::AddOsk)) { + Execute(nullptr, &openEvent, true); + } if (ime_mode) { g_ime_state = ImeState(&m_param.ime); @@ -56,6 +60,11 @@ public: } s32 Update(OrbisImeEventHandler handler) { + if (!m_ime_mode) { + /* We don't handle any events for ImeKeyboard */ + return ORBIS_OK; + } + std::unique_lock lock{g_ime_state.queue_mutex}; while (!g_ime_state.event_queue.empty()) { @@ -85,6 +94,16 @@ public: } } + s32 SetText(const char16_t* text, u32 length) { + g_ime_state.SetText(text, length); + return ORBIS_OK; + } + + s32 SetCaret(const OrbisImeCaret* caret) { + g_ime_state.SetCaret(caret->index); + return ORBIS_OK; + } + bool IsIme() { return m_ime_mode; } @@ -98,6 +117,7 @@ private: }; static std::unique_ptr g_ime_handler; +static std::unique_ptr g_keyboard_handler; int PS4_SYSV_ABI FinalizeImeModule() { LOG_ERROR(Lib_Ime, "(STUBBED) called"); @@ -130,9 +150,6 @@ s32 PS4_SYSV_ABI sceImeClose() { 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(); @@ -233,14 +250,11 @@ s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { LOG_INFO(Lib_Ime, "(STUBBED) called"); - if (!g_ime_handler) { - return ORBIS_IME_ERROR_NOT_OPENED; - } - if (g_ime_handler->IsIme()) { + if (!g_keyboard_handler) { return ORBIS_IME_ERROR_NOT_OPENED; } - g_ime_handler.release(); + g_keyboard_handler.release(); return ORBIS_OK; } @@ -255,18 +269,17 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { } s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { - LOG_ERROR(Lib_Ime, "(STUBBED) called"); + LOG_INFO(Lib_Ime, "called"); if (!param) { return ORBIS_IME_ERROR_INVALID_ADDRESS; } - if (g_ime_handler) { + if (g_keyboard_handler) { return ORBIS_IME_ERROR_BUSY; } - // g_ime_handler = std::make_unique(param); - // return ORBIS_OK; - return ORBIS_IME_ERROR_CONNECTION_FAILED; // Fixup + g_keyboard_handler = std::make_unique(param); + return ORBIS_OK; } int PS4_SYSV_ABI sceImeKeyboardOpenInternal() { @@ -287,16 +300,14 @@ int PS4_SYSV_ABI sceImeKeyboardUpdate() { s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended) { LOG_INFO(Lib_Ime, "called"); - if (!g_ime_handler) { - g_ime_handler = std::make_unique(param); - } else { - if (g_ime_handler->IsIme()) { - return ORBIS_IME_ERROR_BUSY; - } - - g_ime_handler->Init((void*)param, true); + if (!param) { + return ORBIS_IME_ERROR_INVALID_ADDRESS; + } + if (g_ime_handler) { + return ORBIS_IME_ERROR_BUSY; } + g_ime_handler = std::make_unique(param); return ORBIS_OK; } @@ -322,13 +333,29 @@ int PS4_SYSV_ABI sceImeSetCandidateIndex() { } int PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) { - LOG_ERROR(Lib_Ime, "(STUBBED) called"); - return ORBIS_OK; + LOG_TRACE(Lib_Ime, "called"); + + if (!g_ime_handler) { + return ORBIS_IME_ERROR_NOT_OPENED; + } + if (!caret) { + return ORBIS_IME_ERROR_INVALID_ADDRESS; + } + + return g_ime_handler->SetCaret(caret); } -int PS4_SYSV_ABI sceImeSetText() { - LOG_ERROR(Lib_Ime, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length) { + LOG_TRACE(Lib_Ime, "called"); + + if (!g_ime_handler) { + return ORBIS_IME_ERROR_NOT_OPENED; + } + if (!text) { + return ORBIS_IME_ERROR_INVALID_ADDRESS; + } + + return g_ime_handler->SetText(text, length); } int PS4_SYSV_ABI sceImeSetTextGeometry() { @@ -337,13 +364,19 @@ int PS4_SYSV_ABI sceImeSetTextGeometry() { } s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) { - LOG_TRACE(Lib_Ime, "called"); + if (g_ime_handler) { + g_ime_handler->Update(handler); + } - if (!g_ime_handler) { + if (g_keyboard_handler) { + g_keyboard_handler->Update(handler); + } + + if (!g_ime_handler || !g_keyboard_handler) { return ORBIS_IME_ERROR_NOT_OPENED; } - return g_ime_handler->Update(handler); + return ORBIS_OK; } int PS4_SYSV_ABI sceImeVshClearPreedit() { diff --git a/src/core/libraries/ime/ime.h b/src/core/libraries/ime/ime.h index 2915b70da..448ee6896 100644 --- a/src/core/libraries/ime/ime.h +++ b/src/core/libraries/ime/ime.h @@ -26,6 +26,24 @@ enum class OrbisImeKeyboardOption : u32 { }; DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption) +enum class OrbisImeOption : u32 { + DEFAULT = 0, + MULTILINE = 1, + NO_AUTO_CAPITALIZATION = 2, + PASSWORD = 4, + LANGUAGES_FORCED = 8, + EXT_KEYBOARD = 16, + NO_LEARNING = 32, + FIXED_POSITION = 64, + DISABLE_RESUME = 256, + DISABLE_AUTO_SPACE = 512, + DISABLE_POSITION_ADJUSTMENT = 2048, + EXPANDED_PREEDIT_BUFFER = 4096, + USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192, + USE_2K_COORDINATES = 16384, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption) + struct OrbisImeKeyboardParam { OrbisImeKeyboardOption option; s8 reserved1[4]; @@ -41,9 +59,9 @@ struct OrbisImeParam { OrbisImeEnterLabel enter_label; OrbisImeInputMethod input_method; OrbisImeTextFilter filter; - u32 option; - u32 max_text_length; - char16_t* input_text_buffer; + OrbisImeOption option; + u32 maxTextLength; + char16_t* inputTextBuffer; float posx; float posy; OrbisImeHorizontalAlignment horizontal_alignment; @@ -93,7 +111,7 @@ int PS4_SYSV_ABI sceImeOpenInternal(); void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param); int PS4_SYSV_ABI sceImeSetCandidateIndex(); s32 PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret); -int PS4_SYSV_ABI sceImeSetText(); +s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length); int PS4_SYSV_ABI sceImeSetTextGeometry(); s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler); int PS4_SYSV_ABI sceImeVshClearPreedit(); diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 77f23d91d..6d4afd81d 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -142,7 +142,7 @@ struct OrbisImeKeycode { struct OrbisImeKeyboardResourceIdArray { s32 userId; - u32 resource_id[6]; + u32 resourceId[5]; }; enum class OrbisImeCaretMovementDirection : u32 { diff --git a/src/core/libraries/ime/ime_ui.cpp b/src/core/libraries/ime/ime_ui.cpp index c5f41c5e8..8eaa48178 100644 --- a/src/core/libraries/ime/ime_ui.cpp +++ b/src/core/libraries/ime/ime_ui.cpp @@ -16,7 +16,7 @@ ImeState::ImeState(const OrbisImeParam* param) { } work_buffer = param->work; - text_buffer = param->input_text_buffer; + text_buffer = param->inputTextBuffer; std::size_t text_len = std::char_traits::length(text_buffer); if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(), @@ -26,15 +26,13 @@ ImeState::ImeState(const OrbisImeParam* param) { } 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)) { + : 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); @@ -63,6 +61,10 @@ void ImeState::SendCloseEvent() { SendEvent(&closeEvent); } +void ImeState::SetText(const char16_t* text, u32 length) {} + +void ImeState::SetCaret(u32 position) {} + 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'); @@ -180,9 +182,8 @@ void ImeUi::DrawInputText() { if (first_render) { SetKeyboardFocusHere(); } - if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->max_text_length, + if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength, input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) { - state->input_changed = true; } } @@ -190,6 +191,39 @@ int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) { ImeUi* ui = static_cast(data->UserData); ASSERT(ui); + static std::string lastText; + std::string currentText(data->Buf, data->BufTextLen); + if (currentText != lastText) { + OrbisImeEditText eventParam{}; + eventParam.str = reinterpret_cast(ui->ime_param->work); + eventParam.caret_index = data->CursorPos; + eventParam.area_num = 1; + + eventParam.text_area[0].mode = 1; // Edit mode + eventParam.text_area[0].index = data->CursorPos; + eventParam.text_area[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::UpdateText; + event.param.text = eventParam; + + lastText = currentText; + ui->state->SendEvent(&event); + } + static int lastCaretPos = -1; if (lastCaretPos == -1) { lastCaretPos = data->CursorPos; @@ -209,39 +243,6 @@ int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) { ui->state->SendEvent(&event); } - static std::string lastText; - std::string currentText(data->Buf, data->BufTextLen); - if (currentText != lastText) { - OrbisImeEditText eventParam{}; - eventParam.str = reinterpret_cast(ui->ime_param->work); - eventParam.caret_index = data->CursorPos; - eventParam.area_num = 1; - - eventParam.text_area[0].mode = 1; // Edit mode - eventParam.text_area[0].index = data->CursorPos; - eventParam.text_area[0].length = data->BufTextLen; - - if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str, - ui->ime_param->max_text_length)) { - 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->input_text_buffer, - ui->ime_param->max_text_length)) { - LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8"); - return 0; - } - - OrbisImeEvent event{}; - event.id = OrbisImeEventId::UpdateText; - event.param.text = eventParam; - - lastText = currentText; - ui->state->SendEvent(&event); - } - return 0; } diff --git a/src/core/libraries/ime/ime_ui.h b/src/core/libraries/ime/ime_ui.h index ebd70a7c8..a2a806bb9 100644 --- a/src/core/libraries/ime/ime_ui.h +++ b/src/core/libraries/ime/ime_ui.h @@ -22,10 +22,7 @@ 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 @@ -43,6 +40,9 @@ public: void SendEnterEvent(); void SendCloseEvent(); + void SetText(const char16_t* text, u32 length); + void SetCaret(u32 position); + private: bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text, std::size_t native_text_len);