From ee1424186e0be592a681f79859e468685389ed6a Mon Sep 17 00:00:00 2001 From: w1naenator Date: Mon, 7 Jul 2025 17:00:23 +0300 Subject: [PATCH 01/10] IME fixes - Moved enums, flags, and structs to ime_common.h to simplify usage with Ime and ImeDialog - Updated Ime to use an enum as the return type, consistent with ImeDialog - Removed duplicate definition of OrbisImeKeycode - Added OrbisImeLanguage as a flags enum - Added missing options to OrbisImeOption - Removed OrbisImeDialogOption; OrbisImeOption should be used instead - Added OrbisImeTextAreaMode - Updated OrbisImeTextAreaMode - Fixed OrbisImeEventParam by adding the missing member OrbisImePanelType panel_type - Updated the sceImeOpen declaration to use extended parameters (not yet implemented) -Fixed Diablo III (CUSA00434) assertion failure on ImeDialog initialization --- src/core/libraries/ime/ime.cpp | 68 +++---- src/core/libraries/ime/ime.h | 80 +------- src/core/libraries/ime/ime_common.h | 232 ++++++++++++++++++++++- src/core/libraries/ime/ime_dialog.cpp | 49 +++-- src/core/libraries/ime/ime_dialog.h | 120 ------------ src/core/libraries/ime/ime_dialog_ui.cpp | 32 +++- src/core/libraries/ime/ime_ui.cpp | 2 +- 7 files changed, 325 insertions(+), 258 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 1c61bc276..54e856e87 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -43,8 +43,8 @@ public: openEvent.param.rect.x = m_param.ime.posx; openEvent.param.rect.y = m_param.ime.posy; } else { - openEvent.param.resource_id_array.userId = 1; - openEvent.param.resource_id_array.resourceId[0] = 1; + openEvent.param.resource_id_array.user_id = 1; + openEvent.param.resource_id_array.resource_id[0] = 1; } // Are we supposed to call the event handler on init with @@ -59,10 +59,10 @@ public: } } - s32 Update(OrbisImeEventHandler handler) { + Error Update(OrbisImeEventHandler handler) { if (!m_ime_mode) { /* We don't handle any events for ImeKeyboard */ - return ORBIS_OK; + return Error::OK; } std::unique_lock lock{g_ime_state.queue_mutex}; @@ -73,7 +73,7 @@ public: Execute(handler, &event, false); } - return ORBIS_OK; + return Error::OK; } void Execute(OrbisImeEventHandler handler, OrbisImeEvent* event, bool use_param_handler) { @@ -94,14 +94,14 @@ public: } } - s32 SetText(const char16_t* text, u32 length) { + Error SetText(const char16_t* text, u32 length) { g_ime_state.SetText(text, length); - return ORBIS_OK; + return Error::OK; } - s32 SetCaret(const OrbisImeCaret* caret) { + Error SetCaret(const OrbisImeCaret* caret) { g_ime_state.SetCaret(caret->index); - return ORBIS_OK; + return Error::OK; } bool IsIme() { @@ -222,11 +222,11 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { +Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { LOG_INFO(Lib_Ime, "called"); if (!width || !height) { - return ORBIS_IME_ERROR_INVALID_ADDRESS; + return Error::INVALID_ADDRESS; } switch (param->type) { @@ -244,18 +244,18 @@ s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* break; } - return ORBIS_OK; + return Error::OK; } -s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { +Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { LOG_INFO(Lib_Ime, "(STUBBED) called"); if (!g_keyboard_handler) { - return ORBIS_IME_ERROR_NOT_OPENED; + return Error::NOT_OPENED; } g_keyboard_handler.release(); - return ORBIS_OK; + return Error::OK; } int PS4_SYSV_ABI sceImeKeyboardGetInfo() { @@ -268,25 +268,25 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { +Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); if (!param) { - return ORBIS_IME_ERROR_INVALID_ADDRESS; + return Error::INVALID_ADDRESS; } if (!param->arg) { - return ORBIS_IME_ERROR_INVALID_ARG; + return Error::INVALID_ARG; } if (!param->handler) { - return ORBIS_IME_ERROR_INVALID_HANDLER; + return Error::INVALID_HANDLER; } if (g_keyboard_handler) { - return ORBIS_IME_ERROR_BUSY; + return Error::BUSY; } g_keyboard_handler = std::make_unique(param); - return ORBIS_OK; + return Error::OK; } int PS4_SYSV_ABI sceImeKeyboardOpenInternal() { @@ -304,18 +304,18 @@ int PS4_SYSV_ABI sceImeKeyboardUpdate() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended) { +Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExtended* extended) { LOG_INFO(Lib_Ime, "called"); if (!param) { - return ORBIS_IME_ERROR_INVALID_ADDRESS; + return Error::INVALID_ADDRESS; } if (g_ime_handler) { - return ORBIS_IME_ERROR_BUSY; + return Error::BUSY; } g_ime_handler = std::make_unique(param); - return ORBIS_OK; + return Error::OK; } int PS4_SYSV_ABI sceImeOpenInternal() { @@ -339,27 +339,27 @@ int PS4_SYSV_ABI sceImeSetCandidateIndex() { return ORBIS_OK; } -int PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) { +Error PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) { LOG_TRACE(Lib_Ime, "called"); if (!g_ime_handler) { - return ORBIS_IME_ERROR_NOT_OPENED; + return Error::NOT_OPENED; } if (!caret) { - return ORBIS_IME_ERROR_INVALID_ADDRESS; + return Error::INVALID_ADDRESS; } return g_ime_handler->SetCaret(caret); } -s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length) { +Error 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; + return Error::NOT_OPENED; } if (!text) { - return ORBIS_IME_ERROR_INVALID_ADDRESS; + return Error::INVALID_ADDRESS; } return g_ime_handler->SetText(text, length); @@ -370,7 +370,7 @@ int PS4_SYSV_ABI sceImeSetTextGeometry() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) { +Error PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) { if (g_ime_handler) { g_ime_handler->Update(handler); } @@ -380,10 +380,10 @@ s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) { } if (!g_ime_handler || !g_keyboard_handler) { - return ORBIS_IME_ERROR_NOT_OPENED; + return Error::NOT_OPENED; } - return ORBIS_OK; + return Error::OK; } int PS4_SYSV_ABI sceImeVshClearPreedit() { diff --git a/src/core/libraries/ime/ime.h b/src/core/libraries/ime/ime.h index fcf381048..c2b80809c 100644 --- a/src/core/libraries/ime/ime.h +++ b/src/core/libraries/ime/ime.h @@ -13,72 +13,6 @@ class SymbolsResolver; namespace Libraries::Ime { -constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; - -enum class OrbisImeKeyboardOption : u32 { - Default = 0, - Repeat = 1, - RepeatEachKey = 2, - AddOsk = 4, - EffectiveWithIme = 8, - DisableResume = 16, - DisableCapslockWithoutShift = 32, -}; -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]; - void* arg; - OrbisImeEventHandler handler; - s8 reserved2[8]; -}; - -struct OrbisImeParam { - s32 user_id; - OrbisImeType type; - u64 supported_languages; - OrbisImeEnterLabel enter_label; - OrbisImeInputMethod input_method; - OrbisImeTextFilter filter; - OrbisImeOption option; - u32 maxTextLength; - char16_t* inputTextBuffer; - float posx; - float posy; - OrbisImeHorizontalAlignment horizontal_alignment; - OrbisImeVerticalAlignment vertical_alignment; - 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 InitializeImeModule(); int PS4_SYSV_ABI sceImeCheckFilterText(); @@ -98,22 +32,22 @@ int PS4_SYSV_ABI sceImeDisableController(); int PS4_SYSV_ABI sceImeFilterText(); int PS4_SYSV_ABI sceImeForTestFunction(); int PS4_SYSV_ABI sceImeGetPanelPositionAndForm(); -s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); -s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId); +Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); +Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId); int PS4_SYSV_ABI sceImeKeyboardGetInfo(); int PS4_SYSV_ABI sceImeKeyboardGetResourceId(); -s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param); +Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param); int PS4_SYSV_ABI sceImeKeyboardOpenInternal(); int PS4_SYSV_ABI sceImeKeyboardSetMode(); int PS4_SYSV_ABI sceImeKeyboardUpdate(); -s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended); +Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExtended* extended); 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); -s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length); +Error PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret); +Error PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length); int PS4_SYSV_ABI sceImeSetTextGeometry(); -s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler); +Error PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler); int PS4_SYSV_ABI sceImeVshClearPreedit(); int PS4_SYSV_ABI sceImeVshClose(); int PS4_SYSV_ABI sceImeVshConfirmPreedit(); diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 96f073dc5..5c0030030 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -3,9 +3,108 @@ #pragma once +#include "common/enum.h" #include "common/types.h" #include "core/libraries/rtc/rtc.h" +constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; +constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; + +enum class Error : u32 { + OK = 0x0, + BUSY = 0x80bc0001, + NOT_OPENED = 0x80bc0002, + NO_MEMORY = 0x80bc0003, + CONNECTION_FAILED = 0x80bc0004, + TOO_MANY_REQUESTS = 0x80bc0005, + INVALID_TEXT = 0x80bc0006, + EVENT_OVERFLOW = 0x80bc0007, + NOT_ACTIVE = 0x80bc0008, + IME_SUSPENDING = 0x80bc0009, + DEVICE_IN_USE = 0x80bc000a, + INVALID_USER_ID = 0x80bc0010, + INVALID_TYPE = 0x80bc0011, + INVALID_SUPPORTED_LANGUAGES = 0x80bc0012, + INVALID_ENTER_LABEL = 0x80bc0013, + INVALID_INPUT_METHOD = 0x80bc0014, + INVALID_OPTION = 0x80bc0015, + INVALID_MAX_TEXT_LENGTH = 0x80bc0016, + INVALID_INPUT_TEXT_BUFFER = 0x80bc0017, + INVALID_POSX = 0x80bc0018, + INVALID_POSY = 0x80bc0019, + INVALID_HORIZONTALIGNMENT = 0x80bc001a, + INVALID_VERTICALALIGNMENT = 0x80bc001b, + INVALID_EXTENDED = 0x80bc001c, + INVALID_KEYBOARD_TYPE = 0x80bc001d, + INVALID_WORK = 0x80bc0020, + INVALID_ARG = 0x80bc0021, + INVALID_HANDLER = 0x80bc0022, + NO_RESOURCE_ID = 0x80bc0023, + INVALID_MODE = 0x80bc0024, + INVALID_PARAM = 0x80bc0030, + INVALID_ADDRESS = 0x80bc0031, + INVALID_RESERVED = 0x80bc0032, + INVALID_TIMING = 0x80bc0033, + INTERNAL = 0x80bc00ff, + DIALOG_INVALID_TITLE = 0x80bc0101, + DIALOG_NOT_RUNNING = 0x80bc0105, + DIALOG_NOT_FINISHED = 0x80bc0106, + DIALOG_NOT_IN_USE = 0x80bc0107 +}; + +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_COPY_PASTE = 128, + 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); + +enum class OrbisImeLanguage : u64 { + DANISH = 0x0000000000000001, + GERMAN = 0x0000000000000002, + ENGLISH_US = 0x0000000000000004, + SPANISH = 0x0000000000000008, + FRENCH = 0x0000000000000010, + ITALIAN = 0x0000000000000020, + DUTCH = 0x0000000000000040, + NORWEGIAN = 0x0000000000000080, + POLISH = 0x0000000000000100, + PORTUGUESE_PT = 0x0000000000000200, + RUSSIAN = 0x0000000000000400, + FINNISH = 0x0000000000000800, + SWEDISH = 0x0000000000001000, + JAPANESE = 0x0000000000002000, + KOREAN = 0x0000000000004000, + SIMPLIFIED_CHINESE = 0x0000000000008000, + TRADITIONAL_CHINESE = 0x0000000000010000, + PORTUGUESE_BR = 0x0000000000020000, + ENGLISH_GB = 0x0000000000040000, + TURKISH = 0x0000000000080000, + SPANISH_LA = 0x0000000000100000, + ARABIC = 0x0000000001000000, + FRENCH_CA = 0x0000000002000000, + THAI = 0x0000000004000000, + CZECH = 0x0000000008000000, + GREEK = 0x0000000010000000, + INDONESIAN = 0x0000000020000000, + VIETNAMESE = 0x0000000040000000, + ROMANIAN = 0x0000000080000000, + HUNGARIAN = 0x0000000100000000, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage); + enum class OrbisImeType : u32 { Default = 0, BasicLatin = 1, @@ -41,6 +140,7 @@ enum class OrbisImeEventId : u32 { Open = 0, UpdateText = 1, UpdateCaret = 2, + ChangeSize = 3, PressClose = 4, PressEnter = 5, Abort = 6, @@ -51,6 +151,10 @@ enum class OrbisImeEventId : u32 { CandidateDone = 11, CandidateCancel = 12, ChangeDevice = 14, + JumpToNextObject = 15, + JumpToBeforeObject = 16, + ChangeWindowType = 17, + ChangeInputMethodState = 18, KeyboardOpen = 256, @@ -110,6 +214,13 @@ enum class OrbisImeDeviceType : u32 { RemoteOsk = 3, }; +enum class OrbisImePanelPriority : u32 { + Default = 0, + Alphabet = 1, + Symbol = 2, + Accent = 3, +}; + struct OrbisImeRect { f32 x; f32 y; @@ -117,8 +228,22 @@ struct OrbisImeRect { u32 height; }; +struct OrbisImeColor { + u8 r; + u8 g; + u8 b; + u8 a; +}; + +enum class OrbisImeTextAreaMode : u32 { + Disable = 0, + Edit = 1, + Preedit = 2, + Select = 3, +}; + struct OrbisImeTextAreaProperty { - u32 mode; // OrbisImeTextAreaMode + OrbisImeTextAreaMode mode; u32 index; s32 length; }; @@ -135,14 +260,14 @@ struct OrbisImeKeycode { char16_t character; u32 status; OrbisImeKeyboardType type; - s32 user_id; + s32 user_id; // Todo: switch to OrbisUserServiceUserId u32 resource_id; Libraries::Rtc::OrbisRtcTick timestamp; }; struct OrbisImeKeyboardResourceIdArray { - s32 userId; - u32 resourceId[5]; + s32 user_id; // Todo: switch to OrbisUserServiceUserId + u32 resource_id[5]; }; enum class OrbisImeCaretMovementDirection : u32 { @@ -159,6 +284,16 @@ enum class OrbisImeCaretMovementDirection : u32 { Bottom = 10, }; +enum class OrbisImePanelType : u32 { + Hide = 0, + Osk = 1, + Dialog = 2, + Candidate = 3, + Edit = 4, + EditAndCandidate = 5, + Accessibility = 6, +}; + union OrbisImeEventParam { OrbisImeRect rect; OrbisImeEditText text; @@ -168,6 +303,7 @@ union OrbisImeEventParam { char16_t* candidate_word; s32 candidate_index; OrbisImeDeviceType device_type; + OrbisImePanelType panel_type; u32 input_method_state; s8 reserved[64]; }; @@ -177,7 +313,95 @@ struct OrbisImeEvent { OrbisImeEventParam param; }; +using OrbisImeExtKeyboardFilter = PS4_SYSV_ABI int (*)(const OrbisImeKeycode* srcKeycode, + u16* outKeycode, u32* outStatus, + void* reserved); + using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength, const char16_t* srcText, u32 srcTextLength); using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e); + +enum class OrbisImeKeyboardOption : u32 { + Default = 0, + Repeat = 1, + RepeatEachKey = 2, + AddOsk = 4, + EffectiveWithIme = 8, + DisableResume = 16, + DisableCapslockWithoutShift = 32, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption) + +struct OrbisImeKeyboardParam { + OrbisImeKeyboardOption option; + s8 reserved1[4]; + void* arg; + OrbisImeEventHandler handler; + s8 reserved2[8]; +}; + +struct OrbisImeParam { + s32 user_id; // Todo: switch to OrbisUserServiceUserId + OrbisImeType type; + u64 supported_languages; // OrbisImeLanguage flags + OrbisImeEnterLabel enter_label; + OrbisImeInputMethod input_method; + OrbisImeTextFilter filter; + OrbisImeOption option; + u32 maxTextLength; + char16_t* inputTextBuffer; + f32 posx; + f32 posy; + OrbisImeHorizontalAlignment horizontal_alignment; + OrbisImeVerticalAlignment vertical_alignment; + void* work; + void* arg; + OrbisImeEventHandler handler; + s8 reserved[8]; +}; + +struct OrbisImeCaret { + f32 x; + f32 y; + u32 height; + u32 index; +}; + +struct OrbisImeDialogParam { + s32 user_id; + OrbisImeType type; + u64 supported_languages; // OrbisImeLanguage flags + OrbisImeEnterLabel enter_label; + OrbisImeInputMethod input_method; + OrbisImeTextFilter filter; + OrbisImeOption option; + u32 max_text_length; + char16_t* input_text_buffer; + f32 posx; + f32 posy; + OrbisImeHorizontalAlignment horizontal_alignment; + OrbisImeVerticalAlignment vertical_alignment; + const char16_t* placeholder; + const char16_t* title; + s8 reserved[16]; +}; + +struct OrbisImeParamExtended { + u32 option; // OrbisImeExtOption flags + OrbisImeColor color_base; + OrbisImeColor color_line; + OrbisImeColor color_text_field; + OrbisImeColor color_preedit; + OrbisImeColor color_button_default; + OrbisImeColor color_button_function; + OrbisImeColor color_button_symbol; + OrbisImeColor color_text; + OrbisImeColor color_special; + OrbisImePanelPriority priority; + char* additional_dictionary_path; + OrbisImeExtKeyboardFilter ext_keyboard_filter; + u32 disable_device; + u32 ext_keyboard_mode; + s8 reserved[60]; +}; diff --git a/src/core/libraries/ime/ime_dialog.cpp b/src/core/libraries/ime/ime_dialog.cpp index bee185787..6f808636b 100644 --- a/src/core/libraries/ime/ime_dialog.cpp +++ b/src/core/libraries/ime/ime_dialog.cpp @@ -20,19 +20,19 @@ static OrbisImeDialogResult g_ime_dlg_result{}; static ImeDialogState g_ime_dlg_state{}; static ImeDialogUi g_ime_dlg_ui; -static bool IsValidOption(OrbisImeDialogOption option, OrbisImeType type) { - if (False(~option & - (OrbisImeDialogOption::Multiline | OrbisImeDialogOption::NoAutoCompletion))) { +static bool IsValidOption(OrbisImeOption option, OrbisImeType type) { + if (False(~option & (OrbisImeOption::MULTILINE | + OrbisImeOption::NO_AUTO_CAPITALIZATION /* NoAutoCompletion */))) { return false; } - if (True(option & OrbisImeDialogOption::Multiline) && type != OrbisImeType::Default && + if (True(option & OrbisImeOption::MULTILINE) && type != OrbisImeType::Default && type != OrbisImeType::BasicLatin) { return false; } - if (True(option & OrbisImeDialogOption::NoAutoCompletion) && type != OrbisImeType::Number && - type != OrbisImeType::BasicLatin) { + if (True(option & OrbisImeOption::NO_AUTO_CAPITALIZATION /* NoAutoCompletion */) && + type != OrbisImeType::Number && type != OrbisImeType::BasicLatin) { return false; } @@ -96,7 +96,7 @@ Error PS4_SYSV_ABI sceImeDialogGetPanelSize(const OrbisImeDialogParam* param, u3 case OrbisImeType::Url: case OrbisImeType::Mail: *width = 500; // original: 793 - if (True(param->option & OrbisImeDialogOption::Multiline)) { + if (True(param->option & OrbisImeOption::MULTILINE)) { *height = 300; // original: 576 } else { *height = 150; // original: 476 @@ -149,18 +149,20 @@ OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() { } Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) { + LOG_INFO(Lib_ImeDialog, ">> sceImeDialogInit: entering, param={}, extended={}", + static_cast(param), static_cast(extended)); if (g_ime_dlg_status != OrbisImeDialogStatus::None) { - LOG_INFO(Lib_ImeDialog, "IME dialog is already running"); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: busy (status=%u)", (u32)g_ime_dlg_status); return Error::BUSY; } if (param == nullptr) { - LOG_INFO(Lib_ImeDialog, "called with param (NULL)"); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: param is null"); return Error::INVALID_ADDRESS; } if (!magic_enum::enum_contains(param->type)) { - LOG_INFO(Lib_ImeDialog, "Invalid param->type"); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid param->type=%u", (u32)param->type); return Error::INVALID_ADDRESS; } @@ -168,16 +170,14 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt // TODO: do correct param->supportedLanguages validation if (param->posx < 0.0f || - param->posx >= - MAX_X_POSITIONS[False(param->option & OrbisImeDialogOption::LargeResolution)]) { - LOG_INFO(Lib_ImeDialog, "Invalid param->posx"); + param->posx >= MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx=%f", param->posx); return Error::INVALID_POSX; } if (param->posy < 0.0f || - param->posy >= - MAX_Y_POSITIONS[False(param->option & OrbisImeDialogOption::LargeResolution)]) { - LOG_INFO(Lib_ImeDialog, "Invalid param->posy"); + param->posy >= MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy=%f", param->posy); return Error::INVALID_POSY; } @@ -192,12 +192,13 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt } if (!IsValidOption(param->option, param->type)) { - LOG_INFO(Lib_ImeDialog, "Invalid param->option"); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid option=0x%X for type=%u", + static_cast(param->option), (u32)param->type); return Error::INVALID_PARAM; } if (param->input_text_buffer == nullptr) { - LOG_INFO(Lib_ImeDialog, "Invalid param->inputTextBuffer"); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: input_text_buffer is null"); return Error::INVALID_INPUT_TEXT_BUFFER; } @@ -220,16 +221,24 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt } } - if (param->max_text_length > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) { - LOG_INFO(Lib_ImeDialog, "Invalid param->maxTextLength"); + if (param->max_text_length == 0 || param->max_text_length > ORBIS_IME_MAX_TEXT_LENGTH) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid max_text_length=%u", + param->max_text_length); return Error::INVALID_MAX_TEXT_LENGTH; } + // Title string validation + if (param->title != nullptr && !std::char_traits::length(param->title)) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: title is empty"); + return Error::INVALID_PARAM; + } + g_ime_dlg_result = {}; g_ime_dlg_state = ImeDialogState(param, extended); g_ime_dlg_status = OrbisImeDialogStatus::Running; g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result); + LOG_INFO(Lib_ImeDialog, "<< sceImeDialogInit: successful, status now=Running"); return Error::OK; } diff --git a/src/core/libraries/ime/ime_dialog.h b/src/core/libraries/ime/ime_dialog.h index 526e5f022..a056fdd5e 100644 --- a/src/core/libraries/ime/ime_dialog.h +++ b/src/core/libraries/ime/ime_dialog.h @@ -13,50 +13,6 @@ class SymbolsResolver; namespace Libraries::ImeDialog { -constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; - -enum class Error : u32 { - OK = 0x0, - BUSY = 0x80bc0001, - NOT_OPENED = 0x80bc0002, - NO_MEMORY = 0x80bc0003, - CONNECTION_FAILED = 0x80bc0004, - TOO_MANY_REQUESTS = 0x80bc0005, - INVALID_TEXT = 0x80bc0006, - EVENT_OVERFLOW = 0x80bc0007, - NOT_ACTIVE = 0x80bc0008, - IME_SUSPENDING = 0x80bc0009, - DEVICE_IN_USE = 0x80bc000a, - INVALID_USER_ID = 0x80bc0010, - INVALID_TYPE = 0x80bc0011, - INVALID_SUPPORTED_LANGUAGES = 0x80bc0012, - INVALID_ENTER_LABEL = 0x80bc0013, - INVALID_INPUT_METHOD = 0x80bc0014, - INVALID_OPTION = 0x80bc0015, - INVALID_MAX_TEXT_LENGTH = 0x80bc0016, - INVALID_INPUT_TEXT_BUFFER = 0x80bc0017, - INVALID_POSX = 0x80bc0018, - INVALID_POSY = 0x80bc0019, - INVALID_HORIZONTALIGNMENT = 0x80bc001a, - INVALID_VERTICALALIGNMENT = 0x80bc001b, - INVALID_EXTENDED = 0x80bc001c, - INVALID_KEYBOARD_TYPE = 0x80bc001d, - INVALID_WORK = 0x80bc0020, - INVALID_ARG = 0x80bc0021, - INVALID_HANDLER = 0x80bc0022, - NO_RESOURCE_ID = 0x80bc0023, - INVALID_MODE = 0x80bc0024, - INVALID_PARAM = 0x80bc0030, - INVALID_ADDRESS = 0x80bc0031, - INVALID_RESERVED = 0x80bc0032, - INVALID_TIMING = 0x80bc0033, - INTERNAL = 0x80bc00ff, - DIALOG_INVALID_TITLE = 0x80bc0101, - DIALOG_NOT_RUNNING = 0x80bc0105, - DIALOG_NOT_FINISHED = 0x80bc0106, - DIALOG_NOT_IN_USE = 0x80bc0107, -}; - enum class OrbisImeDialogStatus : u32 { None = 0, Running = 1, @@ -69,87 +25,11 @@ enum class OrbisImeDialogEndStatus : u32 { Aborted = 2, }; -enum class OrbisImeDialogOption : u32 { - Default = 0, - Multiline = 1, - NoAutoCorrection = 2, - NoAutoCompletion = 4, - // TODO: Document missing options - LargeResolution = 1024, -}; -DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDialogOption) - -enum class OrbisImePanelPriority : u32 { - Default = 0, - Alphabet = 1, - Symbol = 2, - Accent = 3, -}; - -struct OrbisImeColor { - u8 r; - u8 g; - u8 b; - u8 a; -}; - struct OrbisImeDialogResult { OrbisImeDialogEndStatus endstatus; s32 reserved[12]; }; -struct OrbisImeKeycode { - u16 keycode; - char16_t character; - u32 status; - OrbisImeKeyboardType type; - s32 user_id; - u32 resource_id; - u64 timestamp; -}; - -using OrbisImeExtKeyboardFilter = PS4_SYSV_ABI int (*)(const OrbisImeKeycode* srcKeycode, - u16* outKeycode, u32* outStatus, - void* reserved); - -struct OrbisImeDialogParam { - s32 user_id; - OrbisImeType type; - u64 supported_languages; - OrbisImeEnterLabel enter_label; - OrbisImeInputMethod input_method; - OrbisImeTextFilter filter; - OrbisImeDialogOption option; - u32 max_text_length; - char16_t* input_text_buffer; - float posx; - float posy; - OrbisImeHorizontalAlignment horizontal_alignment; - OrbisImeVerticalAlignment vertical_alignment; - const char16_t* placeholder; - const char16_t* title; - s8 reserved[16]; -}; - -struct OrbisImeParamExtended { - u32 option; // OrbisImeDialogOptionExtended - OrbisImeColor color_base; - OrbisImeColor color_line; - OrbisImeColor color_text_field; - OrbisImeColor color_preedit; - OrbisImeColor color_button_default; - OrbisImeColor color_button_function; - OrbisImeColor color_button_symbol; - OrbisImeColor color_text; - OrbisImeColor color_special; - OrbisImePanelPriority priority; - char* additional_dictionary_path; - OrbisImeExtKeyboardFilter ext_keyboard_filter; - uint32_t disable_device; - uint32_t ext_keyboard_mode; - int8_t reserved[60]; -}; - Error PS4_SYSV_ABI sceImeDialogAbort(); Error PS4_SYSV_ABI sceImeDialogForceClose(); Error PS4_SYSV_ABI sceImeDialogForTestFunction(); diff --git a/src/core/libraries/ime/ime_dialog_ui.cpp b/src/core/libraries/ime/ime_dialog_ui.cpp index 51183c79b..746a2c8d3 100644 --- a/src/core/libraries/ime/ime_dialog_ui.cpp +++ b/src/core/libraries/ime/ime_dialog_ui.cpp @@ -21,12 +21,16 @@ namespace Libraries::ImeDialog { ImeDialogState::ImeDialogState(const OrbisImeDialogParam* param, const OrbisImeParamExtended* extended) { + LOG_INFO(Lib_ImeDialog, ">> ImeDialogState::Ctor: param={}, text_buffer={}", + static_cast(param), + static_cast(param ? param->input_text_buffer : nullptr)); if (!param) { + LOG_ERROR(Lib_ImeDialog, " param==nullptr, returning without init"); return; } user_id = param->user_id; - is_multi_line = True(param->option & OrbisImeDialogOption::Multiline); + is_multi_line = True(param->option & OrbisImeOption::MULTILINE); is_numeric = param->type == OrbisImeType::Number; type = param->type; enter_label = param->enter_label; @@ -220,6 +224,7 @@ void ImeDialogUi::Free() { void ImeDialogUi::Draw() { std::unique_lock lock{draw_mutex}; + LOG_INFO(Lib_ImeDialog, ">> ImeDialogUi::Draw: first_render=%d", first_render); if (!state) { return; @@ -259,9 +264,13 @@ void ImeDialogUi::Draw() { } if (state->is_multi_line) { + LOG_INFO(Lib_ImeDialog, " Drawing multi-line widget…"); DrawMultiLineInputText(); + LOG_INFO(Lib_ImeDialog, " Done DrawMultiLineInputText"); } else { + LOG_INFO(Lib_ImeDialog, " Drawing input text widget…"); DrawInputText(); + LOG_INFO(Lib_ImeDialog, " Done DrawInputText"); } SetCursorPosY(GetCursorPosY() + 10.0f); @@ -306,6 +315,7 @@ void ImeDialogUi::Draw() { End(); first_render = false; + LOG_INFO(Lib_ImeDialog, "<< ImeDialogUi::Draw complete"); } void ImeDialogUi::DrawInputText() { @@ -316,7 +326,7 @@ void ImeDialogUi::DrawInputText() { } const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data(); if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(), - state->max_text_length, input_size, ImGuiInputTextFlags_CallbackCharFilter, + state->max_text_length + 1, input_size, ImGuiInputTextFlags_CallbackCharFilter, InputTextCallback, this)) { state->input_changed = true; } @@ -332,7 +342,7 @@ void ImeDialogUi::DrawMultiLineInputText() { } const char* placeholder = state->placeholder.empty() ? nullptr : state->placeholder.data(); if (InputTextEx("##ImeDialogInput", placeholder, state->current_text.begin(), - state->max_text_length, input_size, flags, InputTextCallback, this)) { + state->max_text_length + 1, input_size, flags, InputTextCallback, this)) { state->input_changed = true; } } @@ -341,13 +351,19 @@ int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) { ImeDialogUi* ui = static_cast(data->UserData); ASSERT(ui); + LOG_DEBUG(Lib_ImeDialog, ">> InputTextCallback: EventFlag={}, EventChar={}", data->EventFlag, + data->EventChar); + // Should we filter punctuation? if (ui->state->is_numeric && (data->EventChar < '0' || data->EventChar > '9') && data->EventChar != '\b' && data->EventChar != ',' && data->EventChar != '.') { + LOG_INFO(Lib_ImeDialog, "InputTextCallback: rejecting non-digit char '{}'", + static_cast(data->EventChar)); return 1; } if (!ui->state->keyboard_filter) { + LOG_DEBUG(Lib_ImeDialog, "InputTextCallback: no keyboard_filter, accepting char"); return 0; } @@ -367,16 +383,20 @@ int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) { }; if (!ui->state->ConvertUTF8ToOrbis(event_char, 4, &src_keycode.character, 1)) { - LOG_ERROR(Lib_ImeDialog, "Failed to convert orbis char to utf8"); + LOG_ERROR(Lib_ImeDialog, "InputTextCallback: ConvertUTF8ToOrbis failed"); return 0; } + LOG_DEBUG(Lib_ImeDialog, "InputTextCallback: converted to Orbis char={:#X}", + static_cast(src_keycode.character)); src_keycode.keycode = src_keycode.character; // TODO set this to the correct value u16 out_keycode; u32 out_status; - ui->state->CallKeyboardFilter(&src_keycode, &out_keycode, &out_status); - + bool keep = ui->state->CallKeyboardFilter(&src_keycode, &out_keycode, &out_status); + LOG_DEBUG(Lib_ImeDialog, + "InputTextCallback: CallKeyboardFilter returned %s (keycode=0x%X, status=0x%X)", + keep ? "true" : "false", out_keycode, out_status); // TODO. set the keycode return 0; diff --git a/src/core/libraries/ime/ime_ui.cpp b/src/core/libraries/ime/ime_ui.cpp index 37f25e200..c49c70ede 100644 --- a/src/core/libraries/ime/ime_ui.cpp +++ b/src/core/libraries/ime/ime_ui.cpp @@ -199,7 +199,7 @@ int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) { eventParam.caret_index = data->CursorPos; eventParam.area_num = 1; - eventParam.text_area[0].mode = 1; // Edit mode + eventParam.text_area[0].mode = OrbisImeTextAreaMode::Edit; eventParam.text_area[0].index = data->CursorPos; eventParam.text_area[0].length = data->BufTextLen; From 7881bd352bcbd916f84e320650b7e974e6cdff2d Mon Sep 17 00:00:00 2001 From: w1naenator Date: Tue, 15 Jul 2025 01:40:27 +0300 Subject: [PATCH 02/10] Ime lib fixes - Updated functions to consistently use the Error enum type for return values. - Added detailed logging to aid future IME/OSK development and debugging. - Now use OrbisUserServiceUserId (s32) and OrbisImeKeycodeState in relevant functions and structs. - Introduced a generic template method to generate full bitmasks for all Orbis flag-style enums, simplifying validation and mask creation. - Implemented additional parameter validations in sceImeOpen. - Added missing enums: OrbisDisableDevice, OrbisImeInputMethodState, OrbisImeInitExtKeyboardMode, OrbisImeKeycodeState, and other USB keyboard-related enums. - Fixed incorrect usage of format specifiers in calls to logging macros (LOG_*). --- src/core/libraries/ime/ime.cpp | 215 +++++++++++++++++++++-- src/core/libraries/ime/ime.h | 7 +- src/core/libraries/ime/ime_common.h | 194 +++++++++++++++++--- src/core/libraries/ime/ime_dialog.cpp | 65 +++++-- src/core/libraries/ime/ime_dialog_ui.cpp | 2 +- 5 files changed, 432 insertions(+), 51 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 54e856e87..e144a622c 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -144,17 +144,17 @@ int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceImeClose() { - LOG_INFO(Lib_Ime, "(STUBBED) called"); +Error PS4_SYSV_ABI sceImeClose() { + LOG_INFO(Lib_Ime, "called"); if (!g_ime_handler) { - return ORBIS_IME_ERROR_NOT_OPENED; + return Error::NOT_OPENED; } g_ime_handler.release(); g_ime_ui = ImeUi(); g_ime_state = ImeState(); - return ORBIS_OK; + return Error::OK; } int PS4_SYSV_ABI sceImeConfigGet() { @@ -223,32 +223,68 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() { } Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { - LOG_INFO(Lib_Ime, "called"); + LOG_INFO(Lib_Ime, "sceImeGetPanelSize called"); - if (!width || !height) { + if (!param) { + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: param is NULL"); return Error::INVALID_ADDRESS; } + if (!width) { + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: width pointer is NULL"); + return Error::INVALID_ADDRESS; + } + if (!height) { + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: height pointer is NULL"); + return Error::INVALID_ADDRESS; + } + + if (static_cast(param->option) & ~0x7BFF) { // Basic check for invalid options + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid option 0x{:X}", + static_cast(param->option)); + return Error::INVALID_OPTION; + } switch (param->type) { case OrbisImeType::Default: + *width = 500; // dummy value + *height = 100; // dummy value + LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Default ({})", + static_cast(param->type)); + break; case OrbisImeType::BasicLatin: + *width = 500; // dummy value + *height = 100; // dummy value + LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type BasicLatin ({})", + static_cast(param->type)); + break; case OrbisImeType::Url: + *width = 500; // dummy value + *height = 100; // dummy value + LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Url ({})", static_cast(param->type)); + break; case OrbisImeType::Mail: // We set our custom sizes, commented sizes are the original ones *width = 500; // 793 *height = 100; // 408 + LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Mail ({})", static_cast(param->type)); break; case OrbisImeType::Number: *width = 370; *height = 402; + LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Number ({})", + static_cast(param->type)); break; + default: + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid IME type ({})", + static_cast(param->type)); + return Error::INVALID_TYPE; } return Error::OK; } -Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { - LOG_INFO(Lib_Ime, "(STUBBED) called"); +Error PS4_SYSV_ABI sceImeKeyboardClose(OrbisUserServiceUserId userId) { + LOG_INFO(Lib_Ime, "called"); if (!g_keyboard_handler) { return Error::NOT_OPENED; @@ -268,9 +304,12 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { return ORBIS_OK; } -Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { +Error PS4_SYSV_ABI sceImeKeyboardOpen(OrbisUserServiceUserId userId, + const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); + LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask=0x{:X}", kValidImeDialogExtOptionMask); + if (!param) { return Error::INVALID_ADDRESS; } @@ -308,13 +347,169 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt LOG_INFO(Lib_Ime, "called"); if (!param) { + LOG_ERROR(Lib_Ime, "sceImeOpen: param is null"); return Error::INVALID_ADDRESS; + } else { + // LOG_DEBUG values for debugging purposes + LOG_DEBUG(Lib_Ime, "param: user_id={}", param->user_id); + LOG_DEBUG(Lib_Ime, "param: type={}", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param: supported_languages={:064b}", + static_cast(param->supported_languages)); + LOG_DEBUG(Lib_Ime, "param: enter_label={}", static_cast(param->enter_label)); + LOG_DEBUG(Lib_Ime, "param: input_method={}", static_cast(param->input_method)); + LOG_DEBUG(Lib_Ime, "param: filter={:p}", reinterpret_cast(param->filter)); + LOG_DEBUG(Lib_Ime, "param: option={:032b}", static_cast(param->option)); + LOG_DEBUG(Lib_Ime, "param: maxTextLength={}", param->maxTextLength); + LOG_DEBUG(Lib_Ime, "param: inputTextBuffer={:p}", + static_cast(param->inputTextBuffer)); + LOG_DEBUG(Lib_Ime, "param: posx={}", param->posx); + LOG_DEBUG(Lib_Ime, "param: posy={}", param->posy); + LOG_DEBUG(Lib_Ime, "param: horizontal_alignment={}", + static_cast(param->horizontal_alignment)); + LOG_DEBUG(Lib_Ime, "param: vertical_alignment={}", + static_cast(param->vertical_alignment)); + LOG_DEBUG(Lib_Ime, "param: work={:p}", param->work); + LOG_DEBUG(Lib_Ime, "param: arg={:p}", param->arg); + LOG_DEBUG(Lib_Ime, "param: handler={:p}", reinterpret_cast(param->handler)); } + + if (!extended) { + LOG_INFO(Lib_Ime, "sceImeOpen: extended is null"); + } else { + // LOG_DEBUG values for debugging purposes + LOG_DEBUG(Lib_Ime, "extended: option={:032b}", static_cast(extended->option)); + LOG_DEBUG(Lib_Ime, "extended: color_base={{{},{},{},{}}}", extended->color_base.r, + extended->color_base.g, extended->color_base.b, extended->color_base.a); + LOG_DEBUG(Lib_Ime, "extended: color_line={{{},{},{},{}}}", extended->color_line.r, + extended->color_line.g, extended->color_line.b, extended->color_line.a); + LOG_DEBUG(Lib_Ime, "extended: color_text_field={{{},{},{},{}}}", + extended->color_text_field.r, extended->color_text_field.g, + extended->color_text_field.b, extended->color_text_field.a); + LOG_DEBUG(Lib_Ime, "extended: color_preedit={{{},{},{},{}}}", extended->color_preedit.r, + extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a); + LOG_DEBUG(Lib_Ime, "extended: color_button_default={{{},{},{},{}}}", + extended->color_button_default.r, extended->color_button_default.g, + extended->color_button_default.b, extended->color_button_default.a); + LOG_DEBUG(Lib_Ime, "extended: color_button_function={{{},{},{},{}}}", + extended->color_button_function.r, extended->color_button_function.g, + extended->color_button_function.b, extended->color_button_function.a); + LOG_DEBUG(Lib_Ime, "extended: color_button_symbol={{{},{},{},{}}}", + extended->color_button_symbol.r, extended->color_button_symbol.g, + extended->color_button_symbol.b, extended->color_button_symbol.a); + LOG_DEBUG(Lib_Ime, "extended: color_text={{{},{},{},{}}}", extended->color_text.r, + extended->color_text.g, extended->color_text.b, extended->color_text.a); + LOG_DEBUG(Lib_Ime, "extended: color_special={{{},{},{},{}}}", extended->color_special.r, + extended->color_special.g, extended->color_special.b, extended->color_special.a); + LOG_DEBUG(Lib_Ime, "extended: priority={}", static_cast(extended->priority)); + LOG_DEBUG(Lib_Ime, "extended: additional_dictionary_path={:p}", + static_cast(extended->additional_dictionary_path)); + LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_filter={:p}", + reinterpret_cast(extended->ext_keyboard_filter)); + LOG_DEBUG(Lib_Ime, "extended: disable_device={:032b}", + static_cast(extended->disable_device)); + LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_mode={}", extended->ext_keyboard_mode); + } + + if (param->user_id < 1 || param->user_id > 4) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid user_id ({})", static_cast(param->user_id)); + return Error::INVALID_USER_ID; + } + + if (!magic_enum::enum_contains(param->type)) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid type ({})", static_cast(param->type)); + return Error::INVALID_TYPE; + } + + if (static_cast(param->supported_languages) & ~kValidOrbisImeLanguageMask) { + LOG_ERROR(Lib_Ime, "sceImeOpen: supported_languages has invalid bits (0x{:016X})", + static_cast(param->supported_languages)); + return Error::INVALID_SUPPORTED_LANGUAGES; + } + + if (!magic_enum::enum_contains(param->enter_label)) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid enter_label ({})", + static_cast(param->enter_label)); + return Error::INVALID_ENTER_LABEL; + } + + if (!magic_enum::enum_contains(param->input_method)) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid input_method ({})", + static_cast(param->input_method)); + return Error::INVALID_INPUT_METHOD; + } + + if (static_cast(param->option) & ~kValidImeOptionMask) { + LOG_ERROR(Lib_Ime, "sceImeOpen: option has invalid bits set (0x{:X}), mask=(0x{:X})", + static_cast(param->option), kValidImeOptionMask); + return Error::INVALID_OPTION; + } + + if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) { + LOG_ERROR(Lib_Ime, "sceImeOpen: maxTextLength invalid ({})", param->maxTextLength); + return Error::INVALID_MAX_TEXT_LENGTH; + } + + if (!param->inputTextBuffer) { + LOG_ERROR(Lib_Ime, "sceImeOpen: inputTextBuffer is NULL"); + return Error::INVALID_INPUT_TEXT_BUFFER; + } + + bool useHighRes = True(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES); + const float maxWidth = useHighRes ? 3840.0f : 1920.0f; + const float maxHeight = useHighRes ? 2160.0f : 1080.0f; + + if (param->posx < 0.0f || param->posx >= maxWidth) { + LOG_ERROR(Lib_Ime, "sceImeOpen: posx out of range (%.2f), max allowed %.0f", param->posx, + maxWidth); + return Error::INVALID_POSX; + } + if (param->posy < 0.0f || param->posy >= maxHeight) { + LOG_ERROR(Lib_Ime, "sceImeOpen: posy out of range (%.2f), max allowed %.0f", param->posy, + maxHeight); + return Error::INVALID_POSY; + } + + if (!magic_enum::enum_contains(param->horizontal_alignment)) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid horizontal_alignment ({})", + static_cast(param->horizontal_alignment)); + return Error::INVALID_HORIZONTALIGNMENT; + } + if (!magic_enum::enum_contains(param->vertical_alignment)) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid vertical_alignment ({})", + static_cast(param->vertical_alignment)); + return Error::INVALID_VERTICALALIGNMENT; + } + + if (extended) { + u32 ext_option_value = static_cast(extended->option); + if (ext_option_value & ~kValidImeExtOptionMask) { + LOG_ERROR(Lib_Ime, "sceImeOpen: extended->option has invalid bits set (0x{:X})", + ext_option_value); + return Error::INVALID_EXTENDED; + } + } + + if (!param->work) { + LOG_ERROR(Lib_Ime, "sceImeOpen: work buffer is NULL"); + return Error::INVALID_WORK; + } + + for (unsigned i = 0; i < sizeof(param->reserved); ++i) { + if (param->reserved[i] != 0) { + LOG_ERROR(Lib_Ime, "sceImeOpen: reserved field must be zeroed"); + return Error::INVALID_RESERVED; + } + } + + // Todo: validate arg and handler + if (g_ime_handler) { + LOG_ERROR(Lib_Ime, "sceImeOpen: Error BUSY"); return Error::BUSY; } g_ime_handler = std::make_unique(param); + LOG_INFO(Lib_Ime, "sceImeOpen: OK"); return Error::OK; } @@ -324,7 +519,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() { } void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) { - LOG_INFO(Lib_Ime, "called"); + LOG_INFO(Lib_Ime, "sceImeParamInit called"); if (!param) { return; diff --git a/src/core/libraries/ime/ime.h b/src/core/libraries/ime/ime.h index c2b80809c..5fd6943a6 100644 --- a/src/core/libraries/ime/ime.h +++ b/src/core/libraries/ime/ime.h @@ -18,7 +18,7 @@ int PS4_SYSV_ABI InitializeImeModule(); int PS4_SYSV_ABI sceImeCheckFilterText(); int PS4_SYSV_ABI sceImeCheckRemoteEventParam(); int PS4_SYSV_ABI sceImeCheckUpdateTextInfo(); -int PS4_SYSV_ABI sceImeClose(); +Error PS4_SYSV_ABI sceImeClose(); int PS4_SYSV_ABI sceImeConfigGet(); int PS4_SYSV_ABI sceImeConfigSet(); int PS4_SYSV_ABI sceImeConfirmCandidate(); @@ -33,10 +33,11 @@ int PS4_SYSV_ABI sceImeFilterText(); int PS4_SYSV_ABI sceImeForTestFunction(); int PS4_SYSV_ABI sceImeGetPanelPositionAndForm(); Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); -Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId); +Error PS4_SYSV_ABI sceImeKeyboardClose(OrbisUserServiceUserId userId); int PS4_SYSV_ABI sceImeKeyboardGetInfo(); int PS4_SYSV_ABI sceImeKeyboardGetResourceId(); -Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param); +Error PS4_SYSV_ABI sceImeKeyboardOpen(OrbisUserServiceUserId userId, + const OrbisImeKeyboardParam* param); int PS4_SYSV_ABI sceImeKeyboardOpenInternal(); int PS4_SYSV_ABI sceImeKeyboardSetMode(); int PS4_SYSV_ABI sceImeKeyboardUpdate(); diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 5c0030030..941a8f910 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -3,6 +3,7 @@ #pragma once +#include #include "common/enum.h" #include "common/types.h" #include "core/libraries/rtc/rtc.h" @@ -10,8 +11,28 @@ constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; +using OrbisUserServiceUserId = s32; + +template +constexpr std::underlying_type_t generate_full_mask() { + static_assert(std::is_enum_v, "E must be an enum type."); + static_assert(magic_enum::customize::enum_range::is_flags, + "E must be marked as is_flags = true."); + + using U = std::underlying_type_t; + U mask = 0; + + for (E value : magic_enum::enum_values()) { + mask |= static_cast(value); + } + + return mask; +} + enum class Error : u32 { OK = 0x0, + + // ImeDialog library BUSY = 0x80bc0001, NOT_OPENED = 0x80bc0002, NO_MEMORY = 0x80bc0003, @@ -46,6 +67,8 @@ enum class Error : u32 { INVALID_RESERVED = 0x80bc0032, INVALID_TIMING = 0x80bc0033, INTERNAL = 0x80bc00ff, + + // Ime library DIALOG_INVALID_TITLE = 0x80bc0101, DIALOG_NOT_RUNNING = 0x80bc0105, DIALOG_NOT_FINISHED = 0x80bc0106, @@ -67,9 +90,44 @@ enum class OrbisImeOption : u32 { DISABLE_POSITION_ADJUSTMENT = 2048, EXPANDED_PREEDIT_BUFFER = 4096, USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192, - USE_2K_COORDINATES = 16384, + USE_OVER_2K_COORDINATES = 16384, }; DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidImeOptionMask = generate_full_mask(); + +enum class OrbisImeExtOption : u32 { + DEFAULT = 0x00000000, + SET_PRIORITY = 0x00000002, + PRIORITY_FULL_WIDTH = 0x00000008, + PRIORITY_FIXED_PANEL = 0x00000010, + DISABLE_POINTER = 0x00000040, + ENABLE_ADDITIONAL_DICTIONARY = 0x00000080, + DISABLE_STARTUP_SE = 0x00000100, + DISABLE_LIST_FOR_EXT_KEYBOARD = 0x00000200, + HIDE_KEYPANEL_IF_EXT_KEYBOARD = 0x00000400, + INIT_EXT_KEYBOARD_MODE = 0x00000800, + + ENABLE_ACCESSIBILITY = 0x00001000, // ImeDialog unly + ADDITIONAL_DICTIONARY_PRIORITY_MODE = 0x00004000, // ImeDialog only +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeExtOption); + +constexpr u32 kValidImeExtOptionMask = static_cast( + OrbisImeExtOption::SET_PRIORITY | OrbisImeExtOption::PRIORITY_FULL_WIDTH | + OrbisImeExtOption::PRIORITY_FIXED_PANEL | OrbisImeExtOption::DISABLE_POINTER | + OrbisImeExtOption::ENABLE_ADDITIONAL_DICTIONARY | OrbisImeExtOption::DISABLE_STARTUP_SE | + OrbisImeExtOption::DISABLE_LIST_FOR_EXT_KEYBOARD | + OrbisImeExtOption::HIDE_KEYPANEL_IF_EXT_KEYBOARD | OrbisImeExtOption::INIT_EXT_KEYBOARD_MODE); + +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidImeDialogExtOptionMask = generate_full_mask(); enum class OrbisImeLanguage : u64 { DANISH = 0x0000000000000001, @@ -105,6 +163,113 @@ enum class OrbisImeLanguage : u64 { }; DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u64 kValidOrbisImeLanguageMask = generate_full_mask(); + +enum class OrbisImeDisableDevice : u32 { + DEFAULT = 0x00000000, + CONTROLLER = 0x00000001, + EXT_KEYBOARD = 0x00000002, + REMOTE_OSK = 0x00000004, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDisableDevice); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidOrbisImeDisableDeviceMask = generate_full_mask(); + +enum class OrbisImeInputMethodState : u32 { + PREEDIT = 0x01000000, + SELECTED = 0x02000000, + NATIVE = 0x04000000, + NATIVE2 = 0x08000000, + FULL_WIDTH = 0x10000000, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInputMethodState); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidOrbisImeInputMethodStateMask = generate_full_mask(); + +enum class OrbisImeInitExtKeyboardMode : u32 { + ISABLE_ARABIC_INDIC_NUMERALS = 0x00000001, + ENABLE_FORMAT_CHARACTERS = 0x00000002, + INPUT_METHOD_STATE_NATIVE = 0x04000000, + INPUT_METHOD_STATE_NATIVE2 = 0x08000000, + INPUT_METHOD_STATE_FULL_WIDTH = 0x10000000, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInitExtKeyboardMode); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidOrbisImeInitExtKeyboardModeMask = + generate_full_mask(); + +enum class OrbisImeKeycodeState : u32 { + KEYCODE_VALID = 0x00000001, + CHARACTER_VALID = 0x00000002, + WITH_IME = 0x00000004, + FROM_OSK = 0x00000008, + FROM_OSK_SHORTCUT = 0x00000010, + FROM_IME_OPERATION = 0x00000020, + REPLACE_CHARACTER = 0x00000040, + CONTINUOUS_EVENT = 0x00000080, + MODIFIER_L_CTRL = 0x00000100, + MODIFIER_L_SHIFT = 0x00000200, + MODIFIER_L_ALT = 0x00000400, + MODIFIER_L_GUI = 0x00000800, + MODIFIER_R_CTRL = 0x00001000, + MODIFIER_R_SHIFT = 0x00002000, + MODIFIER_R_ALT = 0x00004000, + MODIFIER_R_GUI = 0x00008000, + LED_NUM_LOCK = 0x00010000, + LED_CAPS_LOCK = 0x00020000, + LED_SCROLL_LOCK = 0x00040000, + RESERVED1 = 0x00080000, + RESERVED2 = 0x00100000, + FROM_IME_INPUT = 0x00200000, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeycodeState); +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidOrbisImeKeycodeStateMask = generate_full_mask(); + +enum class OrbisImeKeyboardOption : u32 { + Default = 0, + Repeat = 1, + RepeatEachKey = 2, + AddOsk = 4, + EffectiveWithIme = 8, + DisableResume = 16, + DisableCapslockWithoutShift = 32, +}; +DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption) +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; +constexpr u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask(); + +enum class OrbisImeKeyboardMode : u32 { + Auto = 0, + Manual = 1, + Alphabet = 0, + Native = 2, + Part = 4, + Katakana = 8, + Hkana = 16, + ArabicIndicNumerals = 32, + DisableFormatCharacters = 64, +}; + enum class OrbisImeType : u32 { Default = 0, BasicLatin = 1, @@ -260,13 +425,13 @@ struct OrbisImeKeycode { char16_t character; u32 status; OrbisImeKeyboardType type; - s32 user_id; // Todo: switch to OrbisUserServiceUserId + OrbisUserServiceUserId user_id; u32 resource_id; Libraries::Rtc::OrbisRtcTick timestamp; }; struct OrbisImeKeyboardResourceIdArray { - s32 user_id; // Todo: switch to OrbisUserServiceUserId + OrbisUserServiceUserId user_id; u32 resource_id[5]; }; @@ -322,17 +487,6 @@ using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextL using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e); -enum class OrbisImeKeyboardOption : u32 { - Default = 0, - Repeat = 1, - RepeatEachKey = 2, - AddOsk = 4, - EffectiveWithIme = 8, - DisableResume = 16, - DisableCapslockWithoutShift = 32, -}; -DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption) - struct OrbisImeKeyboardParam { OrbisImeKeyboardOption option; s8 reserved1[4]; @@ -342,9 +496,9 @@ struct OrbisImeKeyboardParam { }; struct OrbisImeParam { - s32 user_id; // Todo: switch to OrbisUserServiceUserId + OrbisUserServiceUserId user_id; OrbisImeType type; - u64 supported_languages; // OrbisImeLanguage flags + OrbisImeLanguage supported_languages; OrbisImeEnterLabel enter_label; OrbisImeInputMethod input_method; OrbisImeTextFilter filter; @@ -369,9 +523,9 @@ struct OrbisImeCaret { }; struct OrbisImeDialogParam { - s32 user_id; + OrbisUserServiceUserId user_id; OrbisImeType type; - u64 supported_languages; // OrbisImeLanguage flags + OrbisImeLanguage supported_languages; OrbisImeEnterLabel enter_label; OrbisImeInputMethod input_method; OrbisImeTextFilter filter; @@ -388,7 +542,7 @@ struct OrbisImeDialogParam { }; struct OrbisImeParamExtended { - u32 option; // OrbisImeExtOption flags + OrbisImeExtOption option; OrbisImeColor color_base; OrbisImeColor color_line; OrbisImeColor color_text_field; @@ -401,7 +555,7 @@ struct OrbisImeParamExtended { OrbisImePanelPriority priority; char* additional_dictionary_path; OrbisImeExtKeyboardFilter ext_keyboard_filter; - u32 disable_device; + OrbisImeDisableDevice disable_device; u32 ext_keyboard_mode; s8 reserved[60]; }; diff --git a/src/core/libraries/ime/ime_dialog.cpp b/src/core/libraries/ime/ime_dialog.cpp index 6f808636b..6d29be046 100644 --- a/src/core/libraries/ime/ime_dialog.cpp +++ b/src/core/libraries/ime/ime_dialog.cpp @@ -149,20 +149,47 @@ OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() { } Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) { - LOG_INFO(Lib_ImeDialog, ">> sceImeDialogInit: entering, param={}, extended={}", + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: entering, param={}, extended={}", static_cast(param), static_cast(extended)); - if (g_ime_dlg_status != OrbisImeDialogStatus::None) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: busy (status=%u)", (u32)g_ime_dlg_status); - return Error::BUSY; - } if (param == nullptr) { LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: param is null"); return Error::INVALID_ADDRESS; + } else { + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.user_id = {}", + static_cast(param->user_id)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.type = {}", static_cast(param->type)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.supported_languages = 0x{:X}", + static_cast(param->supported_languages)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.enter_label = {}", + static_cast(param->enter_label)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.input_method = {}", + static_cast(param->input_method)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.filter = {}", (void*)param->filter); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.option = 0x{:X}", + static_cast(param->option)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.max_text_length = {}", + param->max_text_length); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.input_text_buffer = {}", + (void*)param->input_text_buffer); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.posx = {}", param->posx); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.posy = {}", param->posy); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.horizontal_alignment = {}", + static_cast(param->horizontal_alignment)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.vertical_alignment = {}", + static_cast(param->vertical_alignment)); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.placeholder = {}", + param->placeholder ? "" : "NULL"); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.title = {}", + param->title ? "" : "NULL"); + } + if (g_ime_dlg_status != OrbisImeDialogStatus::None) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: busy (status={})", (u32)g_ime_dlg_status); + return Error::BUSY; } if (!magic_enum::enum_contains(param->type)) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid param->type=%u", (u32)param->type); + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid param->type={}", (u32)param->type); return Error::INVALID_ADDRESS; } @@ -170,14 +197,16 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt // TODO: do correct param->supportedLanguages validation if (param->posx < 0.0f || - param->posx >= MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx=%f", param->posx); + param->posx >= + MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES)]) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx={}", param->posx); return Error::INVALID_POSX; } if (param->posy < 0.0f || - param->posy >= MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy=%f", param->posy); + param->posy >= + MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES)]) { + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy={}", param->posy); return Error::INVALID_POSY; } @@ -192,7 +221,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt } if (!IsValidOption(param->option, param->type)) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid option=0x%X for type=%u", + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid option=0x{:X}for type={}", static_cast(param->option), (u32)param->type); return Error::INVALID_PARAM; } @@ -204,25 +233,27 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt if (extended) { if (!magic_enum::enum_contains(extended->priority)) { - LOG_INFO(Lib_ImeDialog, "Invalid extended->priority"); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: Invalid extended->priority"); return Error::INVALID_EXTENDED; } // TODO: do correct extended->option validation if ((extended->ext_keyboard_mode & 0xe3fffffc) != 0) { - LOG_INFO(Lib_ImeDialog, "Invalid extended->extKeyboardMode"); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: Invalid extended->extKeyboardMode"); return Error::INVALID_EXTENDED; } - if (extended->disable_device > 7) { - LOG_INFO(Lib_ImeDialog, "Invalid extended->disableDevice"); + if (static_cast(extended->disable_device) & ~kValidOrbisImeDisableDeviceMask) { + LOG_ERROR(Lib_ImeDialog, + "sceImeDialogInit: disable_device has invalid bits set (0x{:X})", + static_cast(extended->disable_device)); return Error::INVALID_EXTENDED; } } if (param->max_text_length == 0 || param->max_text_length > ORBIS_IME_MAX_TEXT_LENGTH) { - LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid max_text_length=%u", + LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid max_text_length={}", param->max_text_length); return Error::INVALID_MAX_TEXT_LENGTH; } @@ -238,7 +269,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt g_ime_dlg_status = OrbisImeDialogStatus::Running; g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result); - LOG_INFO(Lib_ImeDialog, "<< sceImeDialogInit: successful, status now=Running"); + LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: successful, status now=Running"); return Error::OK; } diff --git a/src/core/libraries/ime/ime_dialog_ui.cpp b/src/core/libraries/ime/ime_dialog_ui.cpp index 746a2c8d3..800ba1124 100644 --- a/src/core/libraries/ime/ime_dialog_ui.cpp +++ b/src/core/libraries/ime/ime_dialog_ui.cpp @@ -379,7 +379,7 @@ int ImeDialogUi::InputTextCallback(ImGuiInputTextCallbackData* data) { // the current language?) .user_id = ui->state->user_id, .resource_id = 0, - .timestamp = 0, + .timestamp = {0}, }; if (!ui->state->ConvertUTF8ToOrbis(event_char, 4, &src_keycode.character, 1)) { From 6d1d760682637af3b663edce74c6d874fb1144dc Mon Sep 17 00:00:00 2001 From: w1naenator Date: Wed, 16 Jul 2025 10:25:38 +0300 Subject: [PATCH 03/10] Data Type Fixes - Replaced the use of the type alias OrbisUserServiceUserId = s32 with Libraries::UserService::OrbisUserServiceUserId directly. --- src/core/libraries/ime/ime.cpp | 4 ++-- src/core/libraries/ime/ime.h | 4 ++-- src/core/libraries/ime/ime_common.h | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index e144a622c..bc6234db7 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -283,7 +283,7 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3 return Error::OK; } -Error PS4_SYSV_ABI sceImeKeyboardClose(OrbisUserServiceUserId userId) { +Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId) { LOG_INFO(Lib_Ime, "called"); if (!g_keyboard_handler) { @@ -304,7 +304,7 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { return ORBIS_OK; } -Error PS4_SYSV_ABI sceImeKeyboardOpen(OrbisUserServiceUserId userId, +Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId, const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); diff --git a/src/core/libraries/ime/ime.h b/src/core/libraries/ime/ime.h index 5fd6943a6..228544af5 100644 --- a/src/core/libraries/ime/ime.h +++ b/src/core/libraries/ime/ime.h @@ -33,10 +33,10 @@ int PS4_SYSV_ABI sceImeFilterText(); int PS4_SYSV_ABI sceImeForTestFunction(); int PS4_SYSV_ABI sceImeGetPanelPositionAndForm(); Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); -Error PS4_SYSV_ABI sceImeKeyboardClose(OrbisUserServiceUserId userId); +Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId); int PS4_SYSV_ABI sceImeKeyboardGetInfo(); int PS4_SYSV_ABI sceImeKeyboardGetResourceId(); -Error PS4_SYSV_ABI sceImeKeyboardOpen(OrbisUserServiceUserId userId, +Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId, const OrbisImeKeyboardParam* param); int PS4_SYSV_ABI sceImeKeyboardOpenInternal(); int PS4_SYSV_ABI sceImeKeyboardSetMode(); diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 941a8f910..c1b18422d 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "common/enum.h" #include "common/types.h" @@ -11,8 +12,6 @@ constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; -using OrbisUserServiceUserId = s32; - template constexpr std::underlying_type_t generate_full_mask() { static_assert(std::is_enum_v, "E must be an enum type."); @@ -425,13 +424,13 @@ struct OrbisImeKeycode { char16_t character; u32 status; OrbisImeKeyboardType type; - OrbisUserServiceUserId user_id; + Libraries::UserService::OrbisUserServiceUserId user_id; u32 resource_id; Libraries::Rtc::OrbisRtcTick timestamp; }; struct OrbisImeKeyboardResourceIdArray { - OrbisUserServiceUserId user_id; + Libraries::UserService::OrbisUserServiceUserId user_id; u32 resource_id[5]; }; @@ -496,7 +495,7 @@ struct OrbisImeKeyboardParam { }; struct OrbisImeParam { - OrbisUserServiceUserId user_id; + Libraries::UserService::OrbisUserServiceUserId user_id; OrbisImeType type; OrbisImeLanguage supported_languages; OrbisImeEnterLabel enter_label; @@ -523,7 +522,7 @@ struct OrbisImeCaret { }; struct OrbisImeDialogParam { - OrbisUserServiceUserId user_id; + Libraries::UserService::OrbisUserServiceUserId user_id; OrbisImeType type; OrbisImeLanguage supported_languages; OrbisImeEnterLabel enter_label; From bfd93028414034d9fcb722eb97b6e0571778d6fc Mon Sep 17 00:00:00 2001 From: w1naenator Date: Wed, 16 Jul 2025 11:31:19 +0300 Subject: [PATCH 04/10] Fixed IDE warnings - generate_full_mask now returns const instead of constexpr. - Added argument list to std::unique_lock construction for clarity. --- src/core/libraries/ime/ime.cpp | 2 +- src/core/libraries/ime/ime_common.h | 37 ++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index bc6234db7..1297093bf 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -65,7 +65,7 @@ public: return Error::OK; } - std::unique_lock lock{g_ime_state.queue_mutex}; + std::unique_lock lock{g_ime_state.queue_mutex}; while (!g_ime_state.event_queue.empty()) { OrbisImeEvent event = g_ime_state.event_queue.front(); diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index c1b18422d..fbd2ee35b 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -12,6 +12,7 @@ constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; +/* template constexpr std::underlying_type_t generate_full_mask() { static_assert(std::is_enum_v, "E must be an enum type."); @@ -27,6 +28,26 @@ constexpr std::underlying_type_t generate_full_mask() { return mask; } +*/ + +template +const std::underlying_type_t generate_full_mask() { + static_assert(std::is_enum_v, "E must be an enum type."); + static_assert(magic_enum::customize::enum_range::is_flags, + "E must be marked as is_flags = true."); + + using U = std::underlying_type_t; + const auto values = magic_enum::enum_values(); + U mask = 0; + + // Use index-based loop for better constexpr compatibility + for (std::size_t i = 0; i < values.size(); ++i) { + mask |= static_cast(values[i]); + } + + return mask; +} + enum class Error : u32 { OK = 0x0, @@ -96,7 +117,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidImeOptionMask = generate_full_mask(); +const u32 kValidImeOptionMask = generate_full_mask(); enum class OrbisImeExtOption : u32 { DEFAULT = 0x00000000, @@ -126,7 +147,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidImeDialogExtOptionMask = generate_full_mask(); +const u32 kValidImeDialogExtOptionMask = generate_full_mask(); enum class OrbisImeLanguage : u64 { DANISH = 0x0000000000000001, @@ -166,7 +187,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u64 kValidOrbisImeLanguageMask = generate_full_mask(); +const u64 kValidOrbisImeLanguageMask = generate_full_mask(); enum class OrbisImeDisableDevice : u32 { DEFAULT = 0x00000000, @@ -179,7 +200,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidOrbisImeDisableDeviceMask = generate_full_mask(); +const u32 kValidOrbisImeDisableDeviceMask = generate_full_mask(); enum class OrbisImeInputMethodState : u32 { PREEDIT = 0x01000000, @@ -193,7 +214,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidOrbisImeInputMethodStateMask = generate_full_mask(); +const u32 kValidOrbisImeInputMethodStateMask = generate_full_mask(); enum class OrbisImeInitExtKeyboardMode : u32 { ISABLE_ARABIC_INDIC_NUMERALS = 0x00000001, @@ -207,7 +228,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidOrbisImeInitExtKeyboardModeMask = +const u32 kValidOrbisImeInitExtKeyboardModeMask = generate_full_mask(); enum class OrbisImeKeycodeState : u32 { @@ -239,7 +260,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidOrbisImeKeycodeStateMask = generate_full_mask(); +const u32 kValidOrbisImeKeycodeStateMask = generate_full_mask(); enum class OrbisImeKeyboardOption : u32 { Default = 0, @@ -255,7 +276,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -constexpr u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask(); +const u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask(); enum class OrbisImeKeyboardMode : u32 { Auto = 0, From 4b02d231e138f273475f609084ef4803a9e84f9f Mon Sep 17 00:00:00 2001 From: w1naenator Date: Wed, 16 Jul 2025 11:36:22 +0300 Subject: [PATCH 05/10] Clang fixes --- src/core/libraries/ime/ime_common.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index fbd2ee35b..9195b3580 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -12,7 +12,7 @@ constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; -/* +/* template constexpr std::underlying_type_t generate_full_mask() { static_assert(std::is_enum_v, "E must be an enum type."); @@ -48,7 +48,6 @@ const std::underlying_type_t generate_full_mask() { return mask; } - enum class Error : u32 { OK = 0x0, @@ -228,8 +227,7 @@ template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; -const u32 kValidOrbisImeInitExtKeyboardModeMask = - generate_full_mask(); +const u32 kValidOrbisImeInitExtKeyboardModeMask = generate_full_mask(); enum class OrbisImeKeycodeState : u32 { KEYCODE_VALID = 0x00000001, From b098438270a4fef19776428e90345ad79331bb65 Mon Sep 17 00:00:00 2001 From: w1naenator Date: Wed, 16 Jul 2025 18:19:25 +0300 Subject: [PATCH 06/10] Removed unneccessary comment --- src/core/libraries/ime/ime_common.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 9195b3580..13f2bfa8f 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -12,24 +12,6 @@ constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; -/* -template -constexpr std::underlying_type_t generate_full_mask() { - static_assert(std::is_enum_v, "E must be an enum type."); - static_assert(magic_enum::customize::enum_range::is_flags, - "E must be marked as is_flags = true."); - - using U = std::underlying_type_t; - U mask = 0; - - for (E value : magic_enum::enum_values()) { - mask |= static_cast(value); - } - - return mask; -} -*/ - template const std::underlying_type_t generate_full_mask() { static_assert(std::is_enum_v, "E must be an enum type."); From e86afb1154aa364e170be97087c0ab5d777cd9c2 Mon Sep 17 00:00:00 2001 From: w1naenator Date: Fri, 18 Jul 2025 14:47:40 +0300 Subject: [PATCH 07/10] some fixes - added log spam - fixed typo - fixed log texts --- src/core/libraries/ime/ime.cpp | 92 +++++++++++++++++------------ src/core/libraries/ime/ime_common.h | 2 +- src/core/libraries/ime/ime_ui.cpp | 4 +- 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 360f0fc54..2c494f59a 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -18,9 +18,11 @@ static ImeUi g_ime_ui; class ImeHandler { public: ImeHandler(const OrbisImeKeyboardParam* param) { + LOG_INFO(Lib_Ime, "Creating ImeHandler for keyboard"); Init(param, false); } ImeHandler(const OrbisImeParam* param) { + LOG_INFO(Lib_Ime, "Creating ImeHandler for IME"); Init(param, true); } ~ImeHandler() = default; @@ -38,8 +40,13 @@ public: openEvent.id = (ime_mode ? OrbisImeEventId::Open : OrbisImeEventId::KeyboardOpen); if (ime_mode) { - sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width, - &openEvent.param.rect.height); + LOG_INFO(Lib_Ime, "calling sceImeGetPanelSize"); + Error e = sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width, + &openEvent.param.rect.height); + if (e != Error::OK) { + LOG_ERROR(Lib_Ime, "sceImeGetPanelSize returned 0x{:X}", static_cast(e)); + } + openEvent.param.rect.x = m_param.ime.posx; openEvent.param.rect.y = m_param.ime.posy; } else { @@ -223,24 +230,23 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() { } Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { - LOG_INFO(Lib_Ime, "sceImeGetPanelSize called"); + LOG_INFO(Lib_Ime, "called"); if (!param) { - LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: param is NULL"); + LOG_ERROR(Lib_Ime, "param is NULL"); return Error::INVALID_ADDRESS; } if (!width) { - LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: width pointer is NULL"); + LOG_ERROR(Lib_Ime, "width pointer is NULL"); return Error::INVALID_ADDRESS; } if (!height) { - LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: height pointer is NULL"); + LOG_ERROR(Lib_Ime, "height pointer is NULL"); return Error::INVALID_ADDRESS; } if (static_cast(param->option) & ~0x7BFF) { // Basic check for invalid options - LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid option 0x{:X}", - static_cast(param->option)); + LOG_ERROR(Lib_Ime, "Invalid option 0x{:X}", static_cast(param->option)); return Error::INVALID_OPTION; } @@ -248,35 +254,31 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3 case OrbisImeType::Default: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Default ({})", - static_cast(param->type)); + LOG_INFO(Lib_Ime, "IME type Default ({})", static_cast(param->type)); break; case OrbisImeType::BasicLatin: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type BasicLatin ({})", - static_cast(param->type)); + LOG_INFO(Lib_Ime, "IME type BasicLatin ({})", static_cast(param->type)); break; case OrbisImeType::Url: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Url ({})", static_cast(param->type)); + LOG_INFO(Lib_Ime, "IME type Url ({})", static_cast(param->type)); break; case OrbisImeType::Mail: // We set our custom sizes, commented sizes are the original ones *width = 500; // 793 *height = 100; // 408 - LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Mail ({})", static_cast(param->type)); + LOG_INFO(Lib_Ime, "IME type Mail ({})", static_cast(param->type)); break; case OrbisImeType::Number: *width = 370; *height = 402; - LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Number ({})", - static_cast(param->type)); + LOG_INFO(Lib_Ime, "IME type Number ({})", static_cast(param->type)); break; default: - LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid IME type ({})", - static_cast(param->type)); + LOG_ERROR(Lib_Ime, "Invalid IME type ({})", static_cast(param->type)); return Error::INVALID_TYPE; } @@ -287,9 +289,11 @@ Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceU LOG_INFO(Lib_Ime, "called"); if (!g_keyboard_handler) { + LOG_ERROR(Lib_Ime, "No keyboard handler is open"); return Error::NOT_OPENED; } + LOG_INFO(Lib_Ime, "Closing keyboard handler for user ID: {}", userId); g_keyboard_handler.release(); return Error::OK; } @@ -308,23 +312,33 @@ Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUs const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); - LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask=0x{:X}", kValidImeDialogExtOptionMask); + LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask={:032b}", kValidImeDialogExtOptionMask); if (!param) { + LOG_ERROR(Lib_Ime, "param is null"); return Error::INVALID_ADDRESS; } if (!param->arg) { + LOG_ERROR(Lib_Ime, "param->arg is null"); return Error::INVALID_ARG; } if (!param->handler) { + LOG_ERROR(Lib_Ime, "param->handler is null"); return Error::INVALID_HANDLER; } if (g_keyboard_handler) { + LOG_ERROR(Lib_Ime, "Keyboard handler is already open"); return Error::BUSY; } g_keyboard_handler = std::make_unique(param); + if (!g_keyboard_handler) { + LOG_ERROR(Lib_Ime, "Failed to create keyboard handler"); + return Error::NO_MEMORY; + } else { + LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId); + } return Error::OK; } @@ -347,7 +361,7 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt LOG_INFO(Lib_Ime, "called"); if (!param) { - LOG_ERROR(Lib_Ime, "sceImeOpen: param is null"); + LOG_ERROR(Lib_Ime, "param is null"); return Error::INVALID_ADDRESS; } else { // LOG_DEBUG values for debugging purposes @@ -374,7 +388,7 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt } if (!extended) { - LOG_INFO(Lib_Ime, "sceImeOpen: extended is null"); + LOG_INFO(Lib_Ime, "extended is null"); } else { // LOG_DEBUG values for debugging purposes LOG_DEBUG(Lib_Ime, "extended: option={:032b}", static_cast(extended->option)); @@ -411,46 +425,46 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt } if (param->user_id < 1 || param->user_id > 4) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid user_id ({})", static_cast(param->user_id)); + LOG_ERROR(Lib_Ime, "Invalid user_id ({})", static_cast(param->user_id)); return Error::INVALID_USER_ID; } if (!magic_enum::enum_contains(param->type)) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid type ({})", static_cast(param->type)); + LOG_ERROR(Lib_Ime, "Invalid type ({})", static_cast(param->type)); return Error::INVALID_TYPE; } if (static_cast(param->supported_languages) & ~kValidOrbisImeLanguageMask) { - LOG_ERROR(Lib_Ime, "sceImeOpen: supported_languages has invalid bits (0x{:016X})", + LOG_ERROR(Lib_Ime, "supported_languages has invalid bits (0x{:016X})", static_cast(param->supported_languages)); return Error::INVALID_SUPPORTED_LANGUAGES; } if (!magic_enum::enum_contains(param->enter_label)) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid enter_label ({})", + LOG_ERROR(Lib_Ime, "Invalid enter_label ({})", static_cast(param->enter_label)); return Error::INVALID_ENTER_LABEL; } if (!magic_enum::enum_contains(param->input_method)) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid input_method ({})", + LOG_ERROR(Lib_Ime, "Invalid input_method ({})", static_cast(param->input_method)); return Error::INVALID_INPUT_METHOD; } if (static_cast(param->option) & ~kValidImeOptionMask) { - LOG_ERROR(Lib_Ime, "sceImeOpen: option has invalid bits set (0x{:X}), mask=(0x{:X})", + LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=(0x{:X})", static_cast(param->option), kValidImeOptionMask); return Error::INVALID_OPTION; } if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) { - LOG_ERROR(Lib_Ime, "sceImeOpen: maxTextLength invalid ({})", param->maxTextLength); + LOG_ERROR(Lib_Ime, "maxTextLength invalid ({})", param->maxTextLength); return Error::INVALID_MAX_TEXT_LENGTH; } if (!param->inputTextBuffer) { - LOG_ERROR(Lib_Ime, "sceImeOpen: inputTextBuffer is NULL"); + LOG_ERROR(Lib_Ime, "inputTextBuffer is NULL"); return Error::INVALID_INPUT_TEXT_BUFFER; } @@ -459,23 +473,23 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt const float maxHeight = useHighRes ? 2160.0f : 1080.0f; if (param->posx < 0.0f || param->posx >= maxWidth) { - LOG_ERROR(Lib_Ime, "sceImeOpen: posx out of range (%.2f), max allowed %.0f", param->posx, + LOG_ERROR(Lib_Ime, "posx out of range (%.2f), max allowed %.0f", param->posx, maxWidth); return Error::INVALID_POSX; } if (param->posy < 0.0f || param->posy >= maxHeight) { - LOG_ERROR(Lib_Ime, "sceImeOpen: posy out of range (%.2f), max allowed %.0f", param->posy, + LOG_ERROR(Lib_Ime, "posy out of range (%.2f), max allowed %.0f", param->posy, maxHeight); return Error::INVALID_POSY; } if (!magic_enum::enum_contains(param->horizontal_alignment)) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid horizontal_alignment ({})", + LOG_ERROR(Lib_Ime, "Invalid horizontal_alignment ({})", static_cast(param->horizontal_alignment)); return Error::INVALID_HORIZONTALIGNMENT; } if (!magic_enum::enum_contains(param->vertical_alignment)) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid vertical_alignment ({})", + LOG_ERROR(Lib_Ime, "Invalid vertical_alignment ({})", static_cast(param->vertical_alignment)); return Error::INVALID_VERTICALALIGNMENT; } @@ -483,20 +497,20 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt if (extended) { u32 ext_option_value = static_cast(extended->option); if (ext_option_value & ~kValidImeExtOptionMask) { - LOG_ERROR(Lib_Ime, "sceImeOpen: extended->option has invalid bits set (0x{:X})", + LOG_ERROR(Lib_Ime, "extended->option has invalid bits set (0x{:X})", ext_option_value); return Error::INVALID_EXTENDED; } } if (!param->work) { - LOG_ERROR(Lib_Ime, "sceImeOpen: work buffer is NULL"); + LOG_ERROR(Lib_Ime, "work buffer is NULL"); return Error::INVALID_WORK; } for (unsigned i = 0; i < sizeof(param->reserved); ++i) { if (param->reserved[i] != 0) { - LOG_ERROR(Lib_Ime, "sceImeOpen: reserved field must be zeroed"); + LOG_ERROR(Lib_Ime, "reserved field must be zeroed"); return Error::INVALID_RESERVED; } } @@ -504,12 +518,12 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt // Todo: validate arg and handler if (g_ime_handler) { - LOG_ERROR(Lib_Ime, "sceImeOpen: Error BUSY"); + LOG_ERROR(Lib_Ime, "Error BUSY"); return Error::BUSY; } g_ime_handler = std::make_unique(param); - LOG_INFO(Lib_Ime, "sceImeOpen: OK"); + LOG_INFO(Lib_Ime, "OK"); return Error::OK; } @@ -519,7 +533,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() { } void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) { - LOG_INFO(Lib_Ime, "sceImeParamInit called"); + LOG_INFO(Lib_Ime, "called"); if (!param) { return; diff --git a/src/core/libraries/ime/ime_common.h b/src/core/libraries/ime/ime_common.h index 13f2bfa8f..457748a2d 100644 --- a/src/core/libraries/ime/ime_common.h +++ b/src/core/libraries/ime/ime_common.h @@ -323,7 +323,7 @@ enum class OrbisImeEventId : u32 { ChangeInputMethodState = 18, KeyboardOpen = 256, - KeyboardKeycodeDoen = 257, + KeyboardKeycodeDown = 257, KeyboardKeycodeUp = 258, KeyboardKeycodeRepeat = 259, KeyboardConnection = 260, diff --git a/src/core/libraries/ime/ime_ui.cpp b/src/core/libraries/ime/ime_ui.cpp index c49c70ede..bf4f06507 100644 --- a/src/core/libraries/ime/ime_ui.cpp +++ b/src/core/libraries/ime/ime_ui.cpp @@ -44,7 +44,7 @@ ImeState& ImeState::operator=(ImeState&& other) noexcept { } void ImeState::SendEvent(OrbisImeEvent* event) { - std::unique_lock lock{queue_mutex}; + std::unique_lock lock{queue_mutex}; event_queue.push(*event); } @@ -108,7 +108,7 @@ ImeUi& ImeUi::operator=(ImeUi&& other) { } void ImeUi::Draw() { - std::unique_lock lock{draw_mutex}; + std::unique_lock lock{draw_mutex}; if (!state) { return; From e2aec427315a8f73c82ffe081b208a042430119f Mon Sep 17 00:00:00 2001 From: w1naenator Date: Sat, 19 Jul 2025 02:29:36 +0300 Subject: [PATCH 08/10] implement temporary fixes to prevent log spam in Unity Engine games. --- src/core/libraries/ime/ime.cpp | 235 +++++++++++++++++++++------------ 1 file changed, 153 insertions(+), 82 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 2c494f59a..6d1cc0490 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -159,8 +159,13 @@ Error PS4_SYSV_ABI sceImeClose() { } g_ime_handler.release(); + if (g_keyboard_handler) { + return Error::INTERNAL; + } g_ime_ui = ImeUi(); g_ime_state = ImeState(); + + LOG_INFO(Lib_Ime, "IME closed successfully"); return Error::OK; } @@ -233,15 +238,16 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3 LOG_INFO(Lib_Ime, "called"); if (!param) { - LOG_ERROR(Lib_Ime, "param is NULL"); + LOG_ERROR(Lib_Ime, "Invalid param: NULL"); return Error::INVALID_ADDRESS; } + if (!width) { - LOG_ERROR(Lib_Ime, "width pointer is NULL"); + LOG_ERROR(Lib_Ime, "Invalid *width: NULL"); return Error::INVALID_ADDRESS; } if (!height) { - LOG_ERROR(Lib_Ime, "height pointer is NULL"); + LOG_ERROR(Lib_Ime, "Invalid *height: NULL"); return Error::INVALID_ADDRESS; } @@ -254,34 +260,35 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3 case OrbisImeType::Default: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "IME type Default ({})", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->type: Default ({})", static_cast(param->type)); break; case OrbisImeType::BasicLatin: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "IME type BasicLatin ({})", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->type: BasicLatin ({})", static_cast(param->type)); break; case OrbisImeType::Url: *width = 500; // dummy value *height = 100; // dummy value - LOG_INFO(Lib_Ime, "IME type Url ({})", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->type: Url ({})", static_cast(param->type)); break; case OrbisImeType::Mail: // We set our custom sizes, commented sizes are the original ones *width = 500; // 793 *height = 100; // 408 - LOG_INFO(Lib_Ime, "IME type Mail ({})", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->type: Mail ({})", static_cast(param->type)); break; case OrbisImeType::Number: *width = 370; *height = 402; - LOG_INFO(Lib_Ime, "IME type Number ({})", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->type: Number ({})", static_cast(param->type)); break; default: - LOG_ERROR(Lib_Ime, "Invalid IME type ({})", static_cast(param->type)); + LOG_ERROR(Lib_Ime, "Invalid param->type: ({})", static_cast(param->type)); return Error::INVALID_TYPE; } + LOG_INFO(Lib_Ime, "IME panel size: width={}, height={}", *width, *height); return Error::OK; } @@ -293,8 +300,19 @@ Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceU return Error::NOT_OPENED; } - LOG_INFO(Lib_Ime, "Closing keyboard handler for user ID: {}", userId); + if (userId < 0 || userId > 4) { // Todo: check valid user IDs + // Maybe g_keyboard_handler should hold a user ID and I must compare it here? + LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId); + return Error::INVALID_USER_ID; + } + g_keyboard_handler.release(); + if (g_ime_handler) { + LOG_ERROR(Lib_Ime, "failed to close keyboard handler, IME handler is still open"); + return Error::INTERNAL; + } + + LOG_INFO(Lib_Ime, "Keyboard handler closed successfully for user ID: {}", userId); return Error::OK; } @@ -312,19 +330,53 @@ Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUs const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); - LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask={:032b}", kValidImeDialogExtOptionMask); - if (!param) { - LOG_ERROR(Lib_Ime, "param is null"); + LOG_ERROR(Lib_Ime, "Invalid param: NULL"); return Error::INVALID_ADDRESS; } - if (!param->arg) { - LOG_ERROR(Lib_Ime, "param->arg is null"); + + if (!param->handler) { + LOG_ERROR(Lib_Ime, "Invalid param->handler: NULL"); + return Error::INVALID_HANDLER; + } + + // seems like arg is optional, need to check if it is used in the handler + if (!param->arg && false) { // Todo: check if arg is used in the handler, temporarily disabled + LOG_ERROR(Lib_Ime, "Invalid param->arg: NULL"); return Error::INVALID_ARG; } - if (!param->handler) { - LOG_ERROR(Lib_Ime, "param->handler is null"); - return Error::INVALID_HANDLER; + + if (static_cast(param->option) & ~kValidOrbisImeKeyboardOptionMask) { + LOG_ERROR(Lib_Ime, + "Invalid param->option\n" + "option: {:032b}\n" + "validMask: {:032b}", + static_cast(param->option), kValidOrbisImeKeyboardOptionMask); + return Error::INVALID_OPTION; + } + + if (userId < 0 || userId > 4) { // Todo: check valid user IDs + LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId); + return Error::INVALID_USER_ID; + } + + for (size_t i = 0; i < sizeof(param->reserved1); ++i) { + if (param->reserved1[i] != 0) { + LOG_ERROR(Lib_Ime, "Invalid reserved1: not zeroed"); + return Error::INVALID_RESERVED; + } + } + + for (size_t i = 0; i < sizeof(param->reserved2); ++i) { + if (param->reserved2[i] != 0) { + LOG_ERROR(Lib_Ime, "Invalid reserved2: not zeroed"); + return Error::INVALID_RESERVED; + } + } + + if (false) { // Todo: check if usb keyboard is connected, always true for now + LOG_ERROR(Lib_Ime, "USB keyboard is not connected"); + return Error::CONNECTION_FAILED; } if (g_keyboard_handler) { @@ -335,10 +387,10 @@ Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUs g_keyboard_handler = std::make_unique(param); if (!g_keyboard_handler) { LOG_ERROR(Lib_Ime, "Failed to create keyboard handler"); - return Error::NO_MEMORY; - } else { - LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId); + return Error::INTERNAL; // or Error::NO_MEMORY; } + + LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId); return Error::OK; } @@ -361,110 +413,113 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt LOG_INFO(Lib_Ime, "called"); if (!param) { - LOG_ERROR(Lib_Ime, "param is null"); + LOG_ERROR(Lib_Ime, "Invalid param: NULL"); return Error::INVALID_ADDRESS; } else { // LOG_DEBUG values for debugging purposes - LOG_DEBUG(Lib_Ime, "param: user_id={}", param->user_id); - LOG_DEBUG(Lib_Ime, "param: type={}", static_cast(param->type)); - LOG_DEBUG(Lib_Ime, "param: supported_languages={:064b}", + LOG_DEBUG(Lib_Ime, "param->user_id: {}", param->user_id); + LOG_DEBUG(Lib_Ime, "param->type: {}", static_cast(param->type)); + LOG_DEBUG(Lib_Ime, "param->supported_languages: {:064b}", static_cast(param->supported_languages)); - LOG_DEBUG(Lib_Ime, "param: enter_label={}", static_cast(param->enter_label)); - LOG_DEBUG(Lib_Ime, "param: input_method={}", static_cast(param->input_method)); - LOG_DEBUG(Lib_Ime, "param: filter={:p}", reinterpret_cast(param->filter)); - LOG_DEBUG(Lib_Ime, "param: option={:032b}", static_cast(param->option)); - LOG_DEBUG(Lib_Ime, "param: maxTextLength={}", param->maxTextLength); - LOG_DEBUG(Lib_Ime, "param: inputTextBuffer={:p}", + LOG_DEBUG(Lib_Ime, "param->enter_label: {}", static_cast(param->enter_label)); + LOG_DEBUG(Lib_Ime, "param->input_method: {}", static_cast(param->input_method)); + LOG_DEBUG(Lib_Ime, "param->filter: {:p}", reinterpret_cast(param->filter)); + LOG_DEBUG(Lib_Ime, "param->option: {:032b}", static_cast(param->option)); + LOG_DEBUG(Lib_Ime, "param->maxTextLength: {}", param->maxTextLength); + LOG_DEBUG(Lib_Ime, "param->inputTextBuffer: {:p}", static_cast(param->inputTextBuffer)); - LOG_DEBUG(Lib_Ime, "param: posx={}", param->posx); - LOG_DEBUG(Lib_Ime, "param: posy={}", param->posy); - LOG_DEBUG(Lib_Ime, "param: horizontal_alignment={}", + LOG_DEBUG(Lib_Ime, "param->posx: {}", param->posx); + LOG_DEBUG(Lib_Ime, "param->posy: {}", param->posy); + LOG_DEBUG(Lib_Ime, "param->horizontal_alignment: {}", static_cast(param->horizontal_alignment)); - LOG_DEBUG(Lib_Ime, "param: vertical_alignment={}", + LOG_DEBUG(Lib_Ime, "param->vertical_alignment: {}", static_cast(param->vertical_alignment)); - LOG_DEBUG(Lib_Ime, "param: work={:p}", param->work); - LOG_DEBUG(Lib_Ime, "param: arg={:p}", param->arg); - LOG_DEBUG(Lib_Ime, "param: handler={:p}", reinterpret_cast(param->handler)); + LOG_DEBUG(Lib_Ime, "param->work: {:p}", param->work); + LOG_DEBUG(Lib_Ime, "param->arg: {:p}", param->arg); + LOG_DEBUG(Lib_Ime, "param->handler: {:p}", reinterpret_cast(param->handler)); } if (!extended) { - LOG_INFO(Lib_Ime, "extended is null"); + LOG_INFO(Lib_Ime, "Not used extended: NULL"); } else { - // LOG_DEBUG values for debugging purposes - LOG_DEBUG(Lib_Ime, "extended: option={:032b}", static_cast(extended->option)); - LOG_DEBUG(Lib_Ime, "extended: color_base={{{},{},{},{}}}", extended->color_base.r, + LOG_DEBUG(Lib_Ime, "extended->option: {:032b}", static_cast(extended->option)); + LOG_DEBUG(Lib_Ime, "extended->color_base: {{{},{},{},{}}}", extended->color_base.r, extended->color_base.g, extended->color_base.b, extended->color_base.a); - LOG_DEBUG(Lib_Ime, "extended: color_line={{{},{},{},{}}}", extended->color_line.r, + LOG_DEBUG(Lib_Ime, "extended->color_line: {{{},{},{},{}}}", extended->color_line.r, extended->color_line.g, extended->color_line.b, extended->color_line.a); - LOG_DEBUG(Lib_Ime, "extended: color_text_field={{{},{},{},{}}}", + LOG_DEBUG(Lib_Ime, "extended->color_text_field: {{{},{},{},{}}}", extended->color_text_field.r, extended->color_text_field.g, extended->color_text_field.b, extended->color_text_field.a); - LOG_DEBUG(Lib_Ime, "extended: color_preedit={{{},{},{},{}}}", extended->color_preedit.r, + LOG_DEBUG(Lib_Ime, "extended->color_preedit: {{{},{},{},{}}}", extended->color_preedit.r, extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a); - LOG_DEBUG(Lib_Ime, "extended: color_button_default={{{},{},{},{}}}", + LOG_DEBUG(Lib_Ime, "extended->color_button_default: {{{},{},{},{}}}", extended->color_button_default.r, extended->color_button_default.g, extended->color_button_default.b, extended->color_button_default.a); - LOG_DEBUG(Lib_Ime, "extended: color_button_function={{{},{},{},{}}}", + LOG_DEBUG(Lib_Ime, "extended->color_button_function: {{{},{},{},{}}}", extended->color_button_function.r, extended->color_button_function.g, extended->color_button_function.b, extended->color_button_function.a); - LOG_DEBUG(Lib_Ime, "extended: color_button_symbol={{{},{},{},{}}}", + LOG_DEBUG(Lib_Ime, "extended->color_button_symbol: {{{},{},{},{}}}", extended->color_button_symbol.r, extended->color_button_symbol.g, extended->color_button_symbol.b, extended->color_button_symbol.a); - LOG_DEBUG(Lib_Ime, "extended: color_text={{{},{},{},{}}}", extended->color_text.r, + LOG_DEBUG(Lib_Ime, "extended->color_text: {{{},{},{},{}}}", extended->color_text.r, extended->color_text.g, extended->color_text.b, extended->color_text.a); - LOG_DEBUG(Lib_Ime, "extended: color_special={{{},{},{},{}}}", extended->color_special.r, + LOG_DEBUG(Lib_Ime, "extended->color_special: {{{},{},{},{}}}", extended->color_special.r, extended->color_special.g, extended->color_special.b, extended->color_special.a); - LOG_DEBUG(Lib_Ime, "extended: priority={}", static_cast(extended->priority)); - LOG_DEBUG(Lib_Ime, "extended: additional_dictionary_path={:p}", + LOG_DEBUG(Lib_Ime, "extended->priority: {}", static_cast(extended->priority)); + LOG_DEBUG(Lib_Ime, "extended->additional_dictionary_path: {:p}", static_cast(extended->additional_dictionary_path)); - LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_filter={:p}", + LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_filter: {:p}", reinterpret_cast(extended->ext_keyboard_filter)); - LOG_DEBUG(Lib_Ime, "extended: disable_device={:032b}", + LOG_DEBUG(Lib_Ime, "extended->disable_device: {:032b}", static_cast(extended->disable_device)); - LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_mode={}", extended->ext_keyboard_mode); + LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_mode: {}", extended->ext_keyboard_mode); } - if (param->user_id < 1 || param->user_id > 4) { - LOG_ERROR(Lib_Ime, "Invalid user_id ({})", static_cast(param->user_id)); + if (param->user_id < 1 || param->user_id > 4) { // Todo: check valid user IDs + LOG_ERROR(Lib_Ime, "Invalid user_id: {}", static_cast(param->user_id)); return Error::INVALID_USER_ID; } if (!magic_enum::enum_contains(param->type)) { - LOG_ERROR(Lib_Ime, "Invalid type ({})", static_cast(param->type)); + LOG_ERROR(Lib_Ime, "Invalid type: {}", static_cast(param->type)); return Error::INVALID_TYPE; } if (static_cast(param->supported_languages) & ~kValidOrbisImeLanguageMask) { - LOG_ERROR(Lib_Ime, "supported_languages has invalid bits (0x{:016X})", - static_cast(param->supported_languages)); + LOG_ERROR(Lib_Ime, + "Invalid supported_languages\n" + "supported_languages: {:064b}\n" + "valid_mask: {:064b}", + static_cast(param->supported_languages), kValidOrbisImeLanguageMask); return Error::INVALID_SUPPORTED_LANGUAGES; } if (!magic_enum::enum_contains(param->enter_label)) { - LOG_ERROR(Lib_Ime, "Invalid enter_label ({})", - static_cast(param->enter_label)); + LOG_ERROR(Lib_Ime, "Invalid enter_label: {}", static_cast(param->enter_label)); return Error::INVALID_ENTER_LABEL; } if (!magic_enum::enum_contains(param->input_method)) { - LOG_ERROR(Lib_Ime, "Invalid input_method ({})", - static_cast(param->input_method)); + LOG_ERROR(Lib_Ime, "Invalid input_method: {}", static_cast(param->input_method)); return Error::INVALID_INPUT_METHOD; } if (static_cast(param->option) & ~kValidImeOptionMask) { - LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=(0x{:X})", + LOG_ERROR(Lib_Ime, + "Invalid option\n" + "option: {:032b}\n" + "valid_mask: {:032b}", static_cast(param->option), kValidImeOptionMask); return Error::INVALID_OPTION; } if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) { - LOG_ERROR(Lib_Ime, "maxTextLength invalid ({})", param->maxTextLength); + LOG_ERROR(Lib_Ime, "Invalid maxTextLength: {}", param->maxTextLength); return Error::INVALID_MAX_TEXT_LENGTH; } if (!param->inputTextBuffer) { - LOG_ERROR(Lib_Ime, "inputTextBuffer is NULL"); + LOG_ERROR(Lib_Ime, "Invalid inputTextBuffer: NULL"); return Error::INVALID_INPUT_TEXT_BUFFER; } @@ -473,23 +528,21 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt const float maxHeight = useHighRes ? 2160.0f : 1080.0f; if (param->posx < 0.0f || param->posx >= maxWidth) { - LOG_ERROR(Lib_Ime, "posx out of range (%.2f), max allowed %.0f", param->posx, - maxWidth); + LOG_ERROR(Lib_Ime, "Invalid posx: {}, range: 0.0 - {}", param->posx, maxWidth); return Error::INVALID_POSX; } if (param->posy < 0.0f || param->posy >= maxHeight) { - LOG_ERROR(Lib_Ime, "posy out of range (%.2f), max allowed %.0f", param->posy, - maxHeight); + LOG_ERROR(Lib_Ime, "Invalid posy: {}, range: 0.0 - {}", param->posy, maxHeight); return Error::INVALID_POSY; } if (!magic_enum::enum_contains(param->horizontal_alignment)) { - LOG_ERROR(Lib_Ime, "Invalid horizontal_alignment ({})", + LOG_ERROR(Lib_Ime, "Invalid horizontal_alignment: {}", static_cast(param->horizontal_alignment)); return Error::INVALID_HORIZONTALIGNMENT; } if (!magic_enum::enum_contains(param->vertical_alignment)) { - LOG_ERROR(Lib_Ime, "Invalid vertical_alignment ({})", + LOG_ERROR(Lib_Ime, "Invalid vertical_alignment: {}", static_cast(param->vertical_alignment)); return Error::INVALID_VERTICALALIGNMENT; } @@ -497,33 +550,51 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt if (extended) { u32 ext_option_value = static_cast(extended->option); if (ext_option_value & ~kValidImeExtOptionMask) { - LOG_ERROR(Lib_Ime, "extended->option has invalid bits set (0x{:X})", - ext_option_value); + LOG_ERROR(Lib_Ime, + "Invalid extended->option\n" + "option: {:032b}\n" + "valid_mask: {:032b}", + ext_option_value, kValidImeExtOptionMask); return Error::INVALID_EXTENDED; } } if (!param->work) { - LOG_ERROR(Lib_Ime, "work buffer is NULL"); + LOG_ERROR(Lib_Ime, "Invalid work: NULL"); return Error::INVALID_WORK; } - for (unsigned i = 0; i < sizeof(param->reserved); ++i) { + // Todo: validate arg + if (false) { + LOG_ERROR(Lib_Ime, "Invalid arg: NULL"); + return Error::INVALID_ARG; + } + + // Todo: validate handler + if (false) { + LOG_ERROR(Lib_Ime, "Invalid handler: NULL"); + return Error::INVALID_HANDLER; + } + + for (size_t i = 0; i < sizeof(param->reserved); ++i) { if (param->reserved[i] != 0) { - LOG_ERROR(Lib_Ime, "reserved field must be zeroed"); + LOG_ERROR(Lib_Ime, "Invalid reserved: not zeroed"); return Error::INVALID_RESERVED; } } - // Todo: validate arg and handler - if (g_ime_handler) { - LOG_ERROR(Lib_Ime, "Error BUSY"); + LOG_ERROR(Lib_Ime, "IME handler is already open"); return Error::BUSY; } g_ime_handler = std::make_unique(param); - LOG_INFO(Lib_Ime, "OK"); + if (!g_ime_handler) { + LOG_ERROR(Lib_Ime, "Failed to create IME handler"); + return Error::NO_MEMORY; // or Error::INTERNAL + } + + LOG_INFO(Lib_Ime, "IME handler created successfully"); return Error::OK; } From b76300241beca63c651ca95a027fc679a7a743cd Mon Sep 17 00:00:00 2001 From: w1naenator Date: Sat, 19 Jul 2025 02:53:33 +0300 Subject: [PATCH 09/10] Fix clang --- src/core/libraries/ime/ime.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index c5d81ebbb..906a9596a 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -330,7 +330,6 @@ Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUs const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); - if (!param) { LOG_ERROR(Lib_Ime, "Invalid param: NULL"); return Error::INVALID_ADDRESS; From b9507359d9d41ca3dd02f485f68d93e753a0d3e5 Mon Sep 17 00:00:00 2001 From: w1naenator Date: Sat, 19 Jul 2025 14:27:53 +0300 Subject: [PATCH 10/10] Clang fox, second try. --- src/core/libraries/ime/ime.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 906a9596a..090a9726d 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -329,23 +329,19 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId, const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); - if (!param) { LOG_ERROR(Lib_Ime, "Invalid param: NULL"); return Error::INVALID_ADDRESS; } - if (!param->handler) { LOG_ERROR(Lib_Ime, "Invalid param->handler: NULL"); return Error::INVALID_HANDLER; } - // seems like arg is optional, need to check if it is used in the handler if (!param->arg && false) { // Todo: check if arg is used in the handler, temporarily disabled LOG_ERROR(Lib_Ime, "Invalid param->arg: NULL"); return Error::INVALID_ARG; } - if (static_cast(param->option) & ~kValidOrbisImeKeyboardOptionMask) { LOG_ERROR(Lib_Ime, "Invalid param->option\n" @@ -354,42 +350,35 @@ Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUs static_cast(param->option), kValidOrbisImeKeyboardOptionMask); return Error::INVALID_OPTION; } - if (userId < 0 || userId > 4) { // Todo: check valid user IDs LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId); return Error::INVALID_USER_ID; } - for (size_t i = 0; i < sizeof(param->reserved1); ++i) { if (param->reserved1[i] != 0) { LOG_ERROR(Lib_Ime, "Invalid reserved1: not zeroed"); return Error::INVALID_RESERVED; } } - for (size_t i = 0; i < sizeof(param->reserved2); ++i) { if (param->reserved2[i] != 0) { LOG_ERROR(Lib_Ime, "Invalid reserved2: not zeroed"); return Error::INVALID_RESERVED; } } - if (false) { // Todo: check if usb keyboard is connected, always true for now LOG_ERROR(Lib_Ime, "USB keyboard is not connected"); return Error::CONNECTION_FAILED; } - if (g_keyboard_handler) { LOG_ERROR(Lib_Ime, "Keyboard handler is already open"); return Error::BUSY; } - g_keyboard_handler = std::make_unique(param); if (!g_keyboard_handler) { LOG_ERROR(Lib_Ime, "Failed to create keyboard handler"); return Error::INTERNAL; // or Error::NO_MEMORY; } - LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId); return Error::OK; }