Ime lib fixes (#3244)

* 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

* 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_*).

* Data Type Fixes

- Replaced the use of the type alias OrbisUserServiceUserId = s32 with Libraries::UserService::OrbisUserServiceUserId directly.

* Fixed IDE warnings
- generate_full_mask now returns const instead of constexpr.
- Added argument list to std::unique_lock<std::mutex> construction for clarity.

* Clang fixes

* Removed unneccessary comment

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
This commit is contained in:
Valdis Bogdāns 2025-07-18 12:40:05 +03:00 committed by GitHub
parent b56039b15a
commit af67473de3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 432 additions and 51 deletions

View File

@ -65,7 +65,7 @@ public:
return Error::OK; return Error::OK;
} }
std::unique_lock lock{g_ime_state.queue_mutex}; std::unique_lock<std::mutex> lock{g_ime_state.queue_mutex};
while (!g_ime_state.event_queue.empty()) { while (!g_ime_state.event_queue.empty()) {
OrbisImeEvent event = g_ime_state.event_queue.front(); OrbisImeEvent event = g_ime_state.event_queue.front();
@ -144,17 +144,17 @@ int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeClose() { Error PS4_SYSV_ABI sceImeClose() {
LOG_INFO(Lib_Ime, "(STUBBED) called"); LOG_INFO(Lib_Ime, "called");
if (!g_ime_handler) { if (!g_ime_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; return Error::NOT_OPENED;
} }
g_ime_handler.release(); g_ime_handler.release();
g_ime_ui = ImeUi(); g_ime_ui = ImeUi();
g_ime_state = ImeState(); g_ime_state = ImeState();
return ORBIS_OK; return Error::OK;
} }
int PS4_SYSV_ABI sceImeConfigGet() { 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) { 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; 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<u32>(param->option) & ~0x7BFF) { // Basic check for invalid options
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid option 0x{:X}",
static_cast<u32>(param->option));
return Error::INVALID_OPTION;
}
switch (param->type) { switch (param->type) {
case OrbisImeType::Default: case OrbisImeType::Default:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Default ({})",
static_cast<u32>(param->type));
break;
case OrbisImeType::BasicLatin: case OrbisImeType::BasicLatin:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type BasicLatin ({})",
static_cast<u32>(param->type));
break;
case OrbisImeType::Url: case OrbisImeType::Url:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Url ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::Mail: case OrbisImeType::Mail:
// We set our custom sizes, commented sizes are the original ones // We set our custom sizes, commented sizes are the original ones
*width = 500; // 793 *width = 500; // 793
*height = 100; // 408 *height = 100; // 408
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Mail ({})", static_cast<u32>(param->type));
break; break;
case OrbisImeType::Number: case OrbisImeType::Number:
*width = 370; *width = 370;
*height = 402; *height = 402;
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Number ({})",
static_cast<u32>(param->type));
break; break;
default:
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid IME type ({})",
static_cast<u32>(param->type));
return Error::INVALID_TYPE;
} }
return Error::OK; return Error::OK;
} }
Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId) {
LOG_INFO(Lib_Ime, "(STUBBED) called"); LOG_INFO(Lib_Ime, "called");
if (!g_keyboard_handler) { if (!g_keyboard_handler) {
return Error::NOT_OPENED; return Error::NOT_OPENED;
@ -268,9 +304,12 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
return ORBIS_OK; return ORBIS_OK;
} }
Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask=0x{:X}", kValidImeDialogExtOptionMask);
if (!param) { if (!param) {
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
@ -308,13 +347,169 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
if (!param) { if (!param) {
LOG_ERROR(Lib_Ime, "sceImeOpen: param is null");
return Error::INVALID_ADDRESS; 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<u32>(param->type));
LOG_DEBUG(Lib_Ime, "param: supported_languages={:064b}",
static_cast<u64>(param->supported_languages));
LOG_DEBUG(Lib_Ime, "param: enter_label={}", static_cast<u32>(param->enter_label));
LOG_DEBUG(Lib_Ime, "param: input_method={}", static_cast<u32>(param->input_method));
LOG_DEBUG(Lib_Ime, "param: filter={:p}", reinterpret_cast<void*>(param->filter));
LOG_DEBUG(Lib_Ime, "param: option={:032b}", static_cast<u32>(param->option));
LOG_DEBUG(Lib_Ime, "param: maxTextLength={}", param->maxTextLength);
LOG_DEBUG(Lib_Ime, "param: inputTextBuffer={:p}",
static_cast<const void*>(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<u32>(param->horizontal_alignment));
LOG_DEBUG(Lib_Ime, "param: vertical_alignment={}",
static_cast<u32>(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<void*>(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<u32>(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<u32>(extended->priority));
LOG_DEBUG(Lib_Ime, "extended: additional_dictionary_path={:p}",
static_cast<const void*>(extended->additional_dictionary_path));
LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_filter={:p}",
reinterpret_cast<void*>(extended->ext_keyboard_filter));
LOG_DEBUG(Lib_Ime, "extended: disable_device={:032b}",
static_cast<u32>(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<u32>(param->user_id));
return Error::INVALID_USER_ID;
}
if (!magic_enum::enum_contains(param->type)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid type ({})", static_cast<u32>(param->type));
return Error::INVALID_TYPE;
}
if (static_cast<u64>(param->supported_languages) & ~kValidOrbisImeLanguageMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: supported_languages has invalid bits (0x{:016X})",
static_cast<u64>(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<u32>(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<u32>(param->input_method));
return Error::INVALID_INPUT_METHOD;
}
if (static_cast<u32>(param->option) & ~kValidImeOptionMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: option has invalid bits set (0x{:X}), mask=(0x{:X})",
static_cast<u32>(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<u32>(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<u32>(param->vertical_alignment));
return Error::INVALID_VERTICALALIGNMENT;
}
if (extended) {
u32 ext_option_value = static_cast<u32>(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) { if (g_ime_handler) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Error BUSY");
return Error::BUSY; return Error::BUSY;
} }
g_ime_handler = std::make_unique<ImeHandler>(param); g_ime_handler = std::make_unique<ImeHandler>(param);
LOG_INFO(Lib_Ime, "sceImeOpen: OK");
return Error::OK; return Error::OK;
} }
@ -324,7 +519,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() {
} }
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) { void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "sceImeParamInit called");
if (!param) { if (!param) {
return; return;

View File

@ -18,7 +18,7 @@ int PS4_SYSV_ABI InitializeImeModule();
int PS4_SYSV_ABI sceImeCheckFilterText(); int PS4_SYSV_ABI sceImeCheckFilterText();
int PS4_SYSV_ABI sceImeCheckRemoteEventParam(); int PS4_SYSV_ABI sceImeCheckRemoteEventParam();
int PS4_SYSV_ABI sceImeCheckUpdateTextInfo(); int PS4_SYSV_ABI sceImeCheckUpdateTextInfo();
int PS4_SYSV_ABI sceImeClose(); Error PS4_SYSV_ABI sceImeClose();
int PS4_SYSV_ABI sceImeConfigGet(); int PS4_SYSV_ABI sceImeConfigGet();
int PS4_SYSV_ABI sceImeConfigSet(); int PS4_SYSV_ABI sceImeConfigSet();
int PS4_SYSV_ABI sceImeConfirmCandidate(); int PS4_SYSV_ABI sceImeConfirmCandidate();
@ -33,10 +33,11 @@ int PS4_SYSV_ABI sceImeFilterText();
int PS4_SYSV_ABI sceImeForTestFunction(); int PS4_SYSV_ABI sceImeForTestFunction();
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm(); int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height);
Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId); Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId);
int PS4_SYSV_ABI sceImeKeyboardGetInfo(); int PS4_SYSV_ABI sceImeKeyboardGetInfo();
int PS4_SYSV_ABI sceImeKeyboardGetResourceId(); int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param); Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param);
int PS4_SYSV_ABI sceImeKeyboardOpenInternal(); int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
int PS4_SYSV_ABI sceImeKeyboardSetMode(); int PS4_SYSV_ABI sceImeKeyboardSetMode();
int PS4_SYSV_ABI sceImeKeyboardUpdate(); int PS4_SYSV_ABI sceImeKeyboardUpdate();

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <core/libraries/system/userservice.h>
#include <magic_enum/magic_enum.hpp>
#include "common/enum.h" #include "common/enum.h"
#include "common/types.h" #include "common/types.h"
#include "core/libraries/rtc/rtc.h" #include "core/libraries/rtc/rtc.h"
@ -10,8 +12,28 @@
constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048;
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048; constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048;
template <typename E>
const std::underlying_type_t<E> generate_full_mask() {
static_assert(std::is_enum_v<E>, "E must be an enum type.");
static_assert(magic_enum::customize::enum_range<E>::is_flags,
"E must be marked as is_flags = true.");
using U = std::underlying_type_t<E>;
const auto values = magic_enum::enum_values<E>();
U mask = 0;
// Use index-based loop for better constexpr compatibility
for (std::size_t i = 0; i < values.size(); ++i) {
mask |= static_cast<U>(values[i]);
}
return mask;
}
enum class Error : u32 { enum class Error : u32 {
OK = 0x0, OK = 0x0,
// ImeDialog library
BUSY = 0x80bc0001, BUSY = 0x80bc0001,
NOT_OPENED = 0x80bc0002, NOT_OPENED = 0x80bc0002,
NO_MEMORY = 0x80bc0003, NO_MEMORY = 0x80bc0003,
@ -46,6 +68,8 @@ enum class Error : u32 {
INVALID_RESERVED = 0x80bc0032, INVALID_RESERVED = 0x80bc0032,
INVALID_TIMING = 0x80bc0033, INVALID_TIMING = 0x80bc0033,
INTERNAL = 0x80bc00ff, INTERNAL = 0x80bc00ff,
// Ime library
DIALOG_INVALID_TITLE = 0x80bc0101, DIALOG_INVALID_TITLE = 0x80bc0101,
DIALOG_NOT_RUNNING = 0x80bc0105, DIALOG_NOT_RUNNING = 0x80bc0105,
DIALOG_NOT_FINISHED = 0x80bc0106, DIALOG_NOT_FINISHED = 0x80bc0106,
@ -67,9 +91,44 @@ enum class OrbisImeOption : u32 {
DISABLE_POSITION_ADJUSTMENT = 2048, DISABLE_POSITION_ADJUSTMENT = 2048,
EXPANDED_PREEDIT_BUFFER = 4096, EXPANDED_PREEDIT_BUFFER = 4096,
USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192, USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192,
USE_2K_COORDINATES = 16384, USE_OVER_2K_COORDINATES = 16384,
}; };
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption); DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption);
template <>
struct magic_enum::customize::enum_range<OrbisImeOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeOptionMask = generate_full_mask<OrbisImeOption>();
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<u32>(
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<OrbisImeExtOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeDialogExtOptionMask = generate_full_mask<OrbisImeExtOption>();
enum class OrbisImeLanguage : u64 { enum class OrbisImeLanguage : u64 {
DANISH = 0x0000000000000001, DANISH = 0x0000000000000001,
@ -105,6 +164,112 @@ enum class OrbisImeLanguage : u64 {
}; };
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage); DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage);
template <>
struct magic_enum::customize::enum_range<OrbisImeLanguage> {
static constexpr bool is_flags = true;
};
const u64 kValidOrbisImeLanguageMask = generate_full_mask<OrbisImeLanguage>();
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<OrbisImeDisableDevice> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeDisableDeviceMask = generate_full_mask<OrbisImeDisableDevice>();
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<OrbisImeInputMethodState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInputMethodStateMask = generate_full_mask<OrbisImeInputMethodState>();
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<OrbisImeInitExtKeyboardMode> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInitExtKeyboardModeMask = generate_full_mask<OrbisImeInitExtKeyboardMode>();
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<OrbisImeKeycodeState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeycodeStateMask = generate_full_mask<OrbisImeKeycodeState>();
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<OrbisImeKeyboardOption> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask<OrbisImeKeyboardOption>();
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 { enum class OrbisImeType : u32 {
Default = 0, Default = 0,
BasicLatin = 1, BasicLatin = 1,
@ -260,13 +425,13 @@ struct OrbisImeKeycode {
char16_t character; char16_t character;
u32 status; u32 status;
OrbisImeKeyboardType type; OrbisImeKeyboardType type;
s32 user_id; // Todo: switch to OrbisUserServiceUserId Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resource_id; u32 resource_id;
Libraries::Rtc::OrbisRtcTick timestamp; Libraries::Rtc::OrbisRtcTick timestamp;
}; };
struct OrbisImeKeyboardResourceIdArray { struct OrbisImeKeyboardResourceIdArray {
s32 user_id; // Todo: switch to OrbisUserServiceUserId Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resource_id[5]; 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); 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 { struct OrbisImeKeyboardParam {
OrbisImeKeyboardOption option; OrbisImeKeyboardOption option;
s8 reserved1[4]; s8 reserved1[4];
@ -342,9 +496,9 @@ struct OrbisImeKeyboardParam {
}; };
struct OrbisImeParam { struct OrbisImeParam {
s32 user_id; // Todo: switch to OrbisUserServiceUserId Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type; OrbisImeType type;
u64 supported_languages; // OrbisImeLanguage flags OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label; OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method; OrbisImeInputMethod input_method;
OrbisImeTextFilter filter; OrbisImeTextFilter filter;
@ -369,9 +523,9 @@ struct OrbisImeCaret {
}; };
struct OrbisImeDialogParam { struct OrbisImeDialogParam {
s32 user_id; Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type; OrbisImeType type;
u64 supported_languages; // OrbisImeLanguage flags OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label; OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method; OrbisImeInputMethod input_method;
OrbisImeTextFilter filter; OrbisImeTextFilter filter;
@ -388,7 +542,7 @@ struct OrbisImeDialogParam {
}; };
struct OrbisImeParamExtended { struct OrbisImeParamExtended {
u32 option; // OrbisImeExtOption flags OrbisImeExtOption option;
OrbisImeColor color_base; OrbisImeColor color_base;
OrbisImeColor color_line; OrbisImeColor color_line;
OrbisImeColor color_text_field; OrbisImeColor color_text_field;
@ -401,7 +555,7 @@ struct OrbisImeParamExtended {
OrbisImePanelPriority priority; OrbisImePanelPriority priority;
char* additional_dictionary_path; char* additional_dictionary_path;
OrbisImeExtKeyboardFilter ext_keyboard_filter; OrbisImeExtKeyboardFilter ext_keyboard_filter;
u32 disable_device; OrbisImeDisableDevice disable_device;
u32 ext_keyboard_mode; u32 ext_keyboard_mode;
s8 reserved[60]; s8 reserved[60];
}; };

View File

@ -149,20 +149,47 @@ OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() {
} }
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) { 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<void*>(param), static_cast<void*>(extended)); static_cast<void*>(param), static_cast<void*>(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) { if (param == nullptr) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: param is null"); LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: param is null");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} else {
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.user_id = {}",
static_cast<u32>(param->user_id));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.type = {}", static_cast<u32>(param->type));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.supported_languages = 0x{:X}",
static_cast<u64>(param->supported_languages));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.enter_label = {}",
static_cast<u32>(param->enter_label));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.input_method = {}",
static_cast<u32>(param->input_method));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.filter = {}", (void*)param->filter);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.option = 0x{:X}",
static_cast<u32>(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<u32>(param->horizontal_alignment));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.vertical_alignment = {}",
static_cast<u32>(param->vertical_alignment));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.placeholder = {}",
param->placeholder ? "<non-null>" : "NULL");
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.title = {}",
param->title ? "<non-null>" : "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)) { 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; return Error::INVALID_ADDRESS;
} }
@ -170,14 +197,16 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
// TODO: do correct param->supportedLanguages validation // TODO: do correct param->supportedLanguages validation
if (param->posx < 0.0f || if (param->posx < 0.0f ||
param->posx >= MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { param->posx >=
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx=%f", 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; return Error::INVALID_POSX;
} }
if (param->posy < 0.0f || if (param->posy < 0.0f ||
param->posy >= MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) { param->posy >=
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy=%f", 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; return Error::INVALID_POSY;
} }
@ -192,7 +221,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
} }
if (!IsValidOption(param->option, param->type)) { 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<u32>(param->option), (u32)param->type); static_cast<u32>(param->option), (u32)param->type);
return Error::INVALID_PARAM; return Error::INVALID_PARAM;
} }
@ -204,25 +233,27 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
if (extended) { if (extended) {
if (!magic_enum::enum_contains(extended->priority)) { 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; return Error::INVALID_EXTENDED;
} }
// TODO: do correct extended->option validation // TODO: do correct extended->option validation
if ((extended->ext_keyboard_mode & 0xe3fffffc) != 0) { 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; return Error::INVALID_EXTENDED;
} }
if (extended->disable_device > 7) { if (static_cast<u32>(extended->disable_device) & ~kValidOrbisImeDisableDeviceMask) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->disableDevice"); LOG_ERROR(Lib_ImeDialog,
"sceImeDialogInit: disable_device has invalid bits set (0x{:X})",
static_cast<u32>(extended->disable_device));
return Error::INVALID_EXTENDED; return Error::INVALID_EXTENDED;
} }
} }
if (param->max_text_length == 0 || param->max_text_length > ORBIS_IME_MAX_TEXT_LENGTH) { 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); param->max_text_length);
return Error::INVALID_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_status = OrbisImeDialogStatus::Running;
g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result); 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; return Error::OK;
} }