diff --git a/core/libs/prx/libSceIme/Export.cpp b/core/libs/prx/libSceIme/Export.cpp index 480dbbd24..b105f365b 100644 --- a/core/libs/prx/libSceIme/Export.cpp +++ b/core/libs/prx/libSceIme/Export.cpp @@ -11,6 +11,7 @@ namespace { constexpr int ErrorNotOpened = static_cast(0x80bc0002u); +constexpr int ErrorConnectionFailed = static_cast(0x80bc0004u); constexpr int ErrorInvalidUserId = static_cast(0x80bc0010u); constexpr int ErrorInvalidType = static_cast(0x80bc0011u); constexpr int ErrorInvalidOption = static_cast(0x80bc0015u); @@ -58,10 +59,12 @@ int APS5_VABI sceImeKeyboardGetInfo(uint32_t resource_id, KeyboardInfo* info) { } int APS5_VABI sceImeKeyboardGetResourceId(int32_t user_id, KeyboardResourceIdArray* resource_ids) { - (void)user_id; - (void)resource_ids; - NotImplemented_nid_no_patch(__func__); - return 0; + if (!resource_ids) return ErrorInvalidAddress; + if (user_id == UserIdInvalid) return ErrorInvalidUserId; + *resource_ids = {}; + resource_ids->user_id = user_id; + std::lock_guard lock(g_keyboardMutex); + return g_openKeyboards.contains(user_id) ? ErrorConnectionFailed : ErrorNotOpened; } int APS5_VABI sceImeKeyboardOpen(int32_t user_id, const KeyboardParam* param) { diff --git a/core/libs/tests/GuestImeParameters.cpp b/core/libs/tests/GuestImeParameters.cpp index 3612fb077..f7711197d 100644 --- a/core/libs/tests/GuestImeParameters.cpp +++ b/core/libs/tests/GuestImeParameters.cpp @@ -11,6 +11,9 @@ int APS5_VABI sceImeClose_nid_postfix(void); int APS5_VABI sceImeSetCaret(const Caret* caret); int APS5_VABI sceImeSetText(const char16_t* text, uint32_t length); int APS5_VABI sceImeSetTextGeometry(TextAreaMode mode, const TextGeometry* geometry); +int APS5_VABI sceImeKeyboardOpen(int32_t user_id, const KeyboardParam* param); +int APS5_VABI sceImeKeyboardClose(int32_t user_id); +int APS5_VABI sceImeKeyboardGetResourceId(int32_t user_id, KeyboardResourceIdArray* resource_ids); } static_assert(sizeof(Param) == 96); @@ -118,9 +121,36 @@ static void CheckClosedPanel() { Require(sceImeClose_nid_postfix() == notOpened, "closing needs an open panel"); } +static void CheckKeyboardResourceIds() { + constexpr int NotOpened = static_cast(0x80bc0002u); + constexpr int ConnectionFailed = static_cast(0x80bc0004u); + constexpr int InvalidUserId = static_cast(0x80bc0010u); + constexpr int InvalidAddress = static_cast(0x80bc0031u); + KeyboardResourceIdArray ids; + std::memset(&ids, 0xa5, sizeof(ids)); + Require(sceImeKeyboardGetResourceId(1, nullptr) == InvalidAddress, "null resource id array"); + Require(sceImeKeyboardGetResourceId(-1, &ids) == InvalidUserId, "invalid user"); + const auto* bytes = reinterpret_cast(&ids); + for (size_t i = 0; i < sizeof(ids); ++i) Require(bytes[i] == 0xa5, "outputs changed on argument error"); + Require(sceImeKeyboardGetResourceId(1, &ids) == NotOpened, "keyboard not opened"); + Require(ids.user_id == 1, "user not reported for an unopened keyboard"); + for (uint32_t id : ids.resource_id) Require(id == 0, "resource id reported for an unopened keyboard"); + KeyboardParam param{}; + Require(sceImeKeyboardOpen(1, ¶m) == 0, "keyboard open failed"); + std::memset(&ids, 0xa5, sizeof(ids)); + Require(sceImeKeyboardGetResourceId(1, &ids) == ConnectionFailed, "a keyboard was reported as connected"); + Require(ids.user_id == 1, "user not reported"); + for (uint32_t id : ids.resource_id) Require(id == 0, "resource id reported without a keyboard"); + Require(sceImeKeyboardGetResourceId(2, &ids) == NotOpened, "keyboard of another user reported as opened"); + Require(ids.user_id == 2, "other user not reported"); + Require(sceImeKeyboardClose(1) == 0, "keyboard close failed"); + Require(sceImeKeyboardGetResourceId(1, &ids) == NotOpened, "closed keyboard reported as opened"); +} + int main() { CheckInitialization(); CheckPanelSizes(); CheckErrors(); CheckClosedPanel(); + CheckKeyboardResourceIds(); } diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 4e605cf32..3b845ee92 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -166,3 +166,4 @@ Throughout the project, every function at every stage either **does exactly what - [Thread exit destructors](../../core/libs/prx/libSceLibcInternal/Export.cpp) (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only `_sceLibcInternalThreadDtors` runs them, as `exit` does, else they are dropped - [sceFontOpenFontSet](../../core/libs/prx/libSceFont/src/SystemFont.cpp) (libSceFont) opens only the primary file of a system font set. Characters the console takes from the set's other files (Hangul, Thai and Arabic in Japanese and Chinese sets, Arabic in European sets) are reported as unsupported glyphs. The console file names are those of the PS4 firmware; the names of the PS5-only JG2 sets (`0x1A......`) are unknown, so they use the SSTJpPro files. When a console file is missing, an openly licensed substitute (Noto Sans, Noto Sans Mono, Noto Sans Thai, Noto Sans CJK) is loaded instead. It is not the system font: its metrics differ, so text width, line height and wrapping differ from the console. System font faces are loaded by FreeType in host memory, not in the font memory the title passes to the library: FreeType needs about 1 MiB per CJK face, which the title's font memory is not sized for. - [Font writing lines](../../core/libs/prx/libSceFont/src/WritingLine.cpp) (libSceFont) - `sceFontCreateWritingLine`, `sceFontWritingLineWritesOrder`, `sceFontWritingLineRefersRenderStep`, `sceFontWritingLineGetRenderMetrics` and `sceFontWritingLineClear` follow [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/main/src/libs/libFont.cpp): runs are placed left to right, each at the line's advance so far, with no spacing or adjustment. Only horizontal and left-to-right lines, writing attribute 0 and non-null run metrics are modelled; other values, the metrics of an empty line and unknown or null handles throw, since no reference gives their result or error code. `sceFontWritingLineGetOrderingSpace` still throws (KytyPS5's values are placeholders). Lines are allocated on the host, not in the font memory +- [sceImeKeyboardGetResourceId](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) reports that no USB keyboard is connected (`0x80bc0004`, as [shadPS4](https://github.com/shadps4-emu/shadPS4) does) because IME keyboard events are not delivered to the handler, although [libSceKeyboard](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) exposes the host keyboard