Files
AnyPS5/docs/dev/debt/libSceIme.md
T
Adrià 477adc58cc Merge pull request #15132 from xecedemon/feat/libSceIme-pending-exports
docs(libSceIme): record pending-export contracts as unknown
2026-11-07 00:48:20 +01:00

21 KiB

libSceIme technical debt

Additional callable exports

  • Additional callable exports - 2 entries observed in the 3.20 export inventory and present in the later 13.60-labelled inventory are import-resolution declarations only. The later inventory label does not authenticate a retail firmware version. Parameter lists, return types and behavior are unverified; parameterless int declarations are placeholders, not verified ABI contracts. Every entry throws through NotImplemented_nid_no_patch. Unidentified names use literal NID aliases. No runtime functionality is implemented.
Name NID
Unknown NbbzN9GRg+c
Unknown aChMGUoc7QI

Silent stubs

  • sceImeOpen (libSceIme) shows no panel: the text is typed on the host keyboard, which ImeTextInput forwards from the game window (SDL text input, Backspace, Delete, Left, Right, Home, End, Enter and Escape), and the controller cannot type. While a panel is open, key presses do not reach the keyboard-to-pad bindings of PadInput, as the console's panel takes the controller; key releases still do. Minecraft Preview (PPSA19639, #1277) opens it when entering a world. The external keyboard filter is accepted and never called because no keycode events are produced

Unknown function info

  • sceImeVshOpen (libSceIme) - VSH context, UTF-16 text and dictionary argument registers are recovered. The VSH parameter is copied as 256 bytes; preedit metadata is eight bytes. Dictionary operations transfer 224-byte records, with a fixed 11200-byte output for GetWords; the 64-bit dictionary selector and record fields still need receiver-side identification. These payload types remain incomplete. UpdateTextInfo and RemoteEventParam use the existing 64-byte ImeEditText and event payload at offset eight; their byte-sized repair flag permits correcting invalid text ranges and caret positions.

  • sceImeGetPanelPositionAndForm (libSceIme) - the output is taken to be the PositionAndForm that sceImeDialogGetPanelPositionAndForm fills. While a panel is open it reports the type, position and alignments passed to sceImeOpen and the size sceImeGetPanelSize gives; the console's values for a panel moved by its own position adjustment are unknown.

  • sceImeFilterText (libSceIme) - the behaviour follows the disassembly of libSceIme.sprx from firmware 13.60 and is differential-tested against that function in an emulator, not measured on a console. ImeFilterCodepages.hpp holds the two codepage checks (helpers at 0x4850 and 0x48f0), rebuilt from Unicode's public CP932 and CP936 tables plus the Latin-1, CJK Extension A and a few other units the firmware also accepts (listed in the PR). The parameter layout beyond type is inferred: mask is the allowed-class bitmask, and version and variant derive it when it is 0. sceImeCheckFilterText throws, as its contract is unknown

  • sceImeOpen, sceImeUpdate, sceImeSetText, sceImeSetCaret, sceImeClose (libSceIme) - the event ids (Open 0, UpdateText 1, UpdateCaret 2, PressClose 4, PressEnter 5), the caret directions (left 1, right 2), the error codes and the text event payload follow the PS4 reimplementation in shadPS4; none is measured on a PS5. Events are queued and delivered by sceImeUpdate only when it is passed the handler given to sceImeOpen, with that call's arg. A text event points str at a copy of the text kept in work, and inputTextBuffer holds the same text; both are terminated, caret_index is the caret after the edit and the one edit area has the edit position and the change in UTF-16 units (0 for Enter and Close). An edit sends one UpdateText; a caret move sends one UpdateCaret per UTF-16 unit, as shadPS4 does. Enter inserts a line break with the multiline option and sends PressEnter otherwise; Escape sends PressClose. Typed text is cut to maxTextLength without splitting a surrogate pair, line breaks are dropped without the multiline option, and the BasicLatin, URL, mail and number types do not filter characters. sceImeOpen checks, in shadPS4's order, the user, type, enter label, input method, option bits (the sceImeGetPanelSize mask), maxTextLength (1 to 2048), the text buffer, the position (below 1920x1080, or 3840x2160 with the over-2K option), the alignments, the extended priority and reserved bytes, work (non-null, 4-byte aligned), the handler, the reserved bytes and the initial text (no unpaired surrogate, no line break without the multiline option); shadPS4's SDK-dependent option, language and extended-option masks and its work-overlap check are not applied, and only the text copy is written to work. sceImeSetText keeps the caret unless the text became shorter, sceImeSetCaret rejects an index past the text with 0x80bc0030, and neither sends an event. sceImeSetTextGeometry accepts any geometry while a panel is open, since no panel is drawn

  • sceImeUpdate and sceImeKeyboardOpen (libSceIme) - returning 0x80BC0031 (ErrorInvalidAddress) for a null parameter in sceImeKeyboardOpen follows the reimplementations in shadPS4 and KytyPS5. Returning 0x80BC0022 (ErrorInvalidHandler) from sceImeUpdate(nullptr) while a session or keyboard is open is an assumption from the code's name; the next entry covers nothing open.

  • sceImeUpdate and sceImeKeyboardOpen with nothing open (libSceIme) - with no IME session and no keyboard open, sceImeUpdate returns NOT_OPENED (0x80BC0002) before it looks at the handler, a null one included, and sceImeKeyboardOpen refuses user -1 with 0x80BC0010, as obSCEne measured in its own title on a PS5 with system software 12.40 (census, keyboard); shadPS4 and KytyPS5 return NOT_OPENED there too

  • sceImeForTestFunction returns a constant error without consuming arguments in the supplied module; unused argument types cannot be recovered from that body.

  • sceImeConfigSet and sceImeConfigGet preserve the native argument slots: an unused first slot, a 64-bit configuration value, a 32-bit key and, for set, a 32-bit value. The service receives a 24-byte request; configuration/key semantics and unused argument types remain unresolved. The getter advertises one output transfer but does not initialize its descriptor in this module. Protected bodies remain unchanged.

  • libSceIme pending exports - 2 named callable exports are listed in the PS5 3.20 export table and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through NotImplemented_nid_no_patch.

  • ModalDialog (libSceIme) - the session that message and error dialogs share is a host design, not a console behaviour: one dialog at a time, owned by the library that opened it, which alone can poll, close or reset it; the IME keyboard or pad capture hides the dialog and takes its input until it ends; an opening is refused while another dialog shows. Closes when: measured on a PS5

  • sceImeVshUpdate, sceImeVshClose, sceImeVshSetParam, sceImeVshGetPanelPositionAndForm, sceImeVshSetPanelPosition (libSceIme) - the VSH panel lifecycle stays NotImplemented. Each call takes the context that sceImeVshOpen returns, and VshGetPanelPositionAndForm would fill the same PositionAndForm that sceImeGetPanelPositionAndForm fills for a title panel. Nothing beyond that is known: Update's event delivery, Close's results, SetParam's validation and SetPanelPosition's coordinate space are unrecovered, no disassembled title calls them, shadPS4 registers the names as constant-zero stubs and KytyPS5 registers none. The host has no system shell to serve, so no host mapping exists; every one throws through NotImplemented_nid_no_patch.

  • sceImeVshUpdateContext, sceImeVshUpdateContext2, sceImeVshNotifySetText, sceImeVshSetSelectionText, sceImeVshInformConfirmdString, sceImeVshInformConfirmdString2, sceImeVshNotifyDeleteText, sceImeVshNotifyUpdateCaretText (libSceIme) - the VSH text-passing exports stay NotImplemented. Their argument registers are recovered (context, UTF-16 string, 32-bit length, caret or parameter slots), but which side produces and which consumes each string, and what the integer parameters index, is unknown; the assembly-confirmed shapes of the sceImeVshNotifyCurrentTextInfo pair are the only measured part. No disassembled title calls them, shadPS4 @ b72489d8 registers five of the eight as constant-zero stubs and carries the other three, and KytyPS5 registers none; the host has no system shell, so no host mapping exists and every one throws.

  • sceImeVshClearPreedit, sceImeVshConfirmPreedit, sceImeVshSetCaretIndexInPreedit, sceImeVshSetCaretGeometry, sceImeVshSetPreeditGeometry, sceImeVshSetSelectGeometry, sceImeVshSendTextInfo, sceImeVshCheckAutoReConvertingPreeditText, sceImeVshNotifyPreeditMetaInfo (libSceIme) - the VSH preedit and geometry exports stay NotImplemented. The geometry parameters use the 16-byte caret and text rectangles, the preedit metadata is the eight-byte block noted under sceImeVshOpen and SendTextInfo carries a size, but which component measures, clips or validates them, and what a call returns, is unknown. No disassembled title calls them, shadPS4 @ b72489d8 registers seven of the nine as constant-zero stubs and carries the other two, and KytyPS5 registers none; the host draws no system-shell preedit, so no host mapping exists and every one throws.

  • sceImeSetCandidateIndex, sceImeConfirmCandidate, sceImeDisableController, sceImeSetVoiceDictationEnabled, sceImeSetEditEventWithRemotePlayEnabled, sceImeSetConsecutiveClauseConversionEnabled (libSceIme) - the panel-behaviour switches stay NotImplemented. On the console they drive the system panel: choosing and confirming a conversion candidate, taking the controller from the panel, voice dictation, edit events over remote play and consecutive-clause conversion. The host shows no panel, keeps no candidate list and delivers no dictation or remote-play events, so there is no behaviour to model, and the 13.42 module's result codes for these are readable but unmapped; shadPS4 @ b72489d8 returns a constant zero for three of the names and carries the other three, and KytyPS5 registers none. A silent zero would be a made-up success, so every one throws.

  • sceImeDisableController (libSceIme) - the readable firmware 13.42 module system/common/lib/libSceIme.sprx (sha256 afed93700c9c434b73c51302fae00c17939dee4dc3c3b76274a619497ec2ec3b) gives it a complete result ladder at 0x1de0, read in review and unmapped here: a negative other than 0x8002000b yields 0x80bc00ff; 0x80bc0002 unless byte 0x40040 is 1; 0x80bc0009 when the call at 0xed10 returns true; the call at 0xf1e0 maps its result — non-negative or 0x80bc0005 to 0, 0x80bc0033 unchanged, else 0x80bc00ff. Other pending exports in this file also have real bodies (e.g. InitializeImeModule 0xe0, 0x102 bytes; sceImeKeyboardUpdate 0x5d80, 0x62b bytes); their result codes are readable but unmapped.

  • sceImeKeyboardUpdate, sceImeKeyboardOpenInternal (libSceIme) - sceImeKeyboardUpdate has no verified contract: shadPS4 returns a constant zero for it and KytyPS5 does not register it, while KytyPS5's shared update delivers a keyboard-open event (id 256) that this library deliberately does not deliver, so the two reimplementations disagree on whether keyboard events reach a handler at all. sceImeKeyboardOpenInternal's user, handler and parameter registers are recovered, but its relation to sceImeKeyboardOpen is unknown and neither reimplementation carries a body. Both throw. Closes when: the keyboard event delivery is measured on a console

  • InitializeImeModule, FinalizeImeModule (libSceIme) - the module entry points stay NotImplemented: who calls them on the console and what they may fail with is unknown, shadPS4 returns a constant zero for both and KytyPS5 registers neither. The library needs no set-up of its own, as its state is empty-initialized globals and a session or keyboard opens per call, but that fact does not establish the native contract, so a silent zero would be a made-up success and both throw.

  • sceImeDicGetWords, sceImeDicAddWord, sceImeDicDeleteWord, sceImeDicReplaceWord, sceImeDicDeleteLearnDics, sceImeDicDeleteUserDics (libSceIme) - the user-dictionary exports stay NotImplemented. The 224-byte record transfer, the fixed 11200-byte GetWords output — confirmed by the readable 13.42 module, whose sceImeDicGetWords (0xf620) passes 0x2bc0 as the output size — and the 64-bit dictionary selector are recovered under sceImeVshOpen, but the record fields, the selector values, the per-call results and the store they change are unread in that module; no disassembled title calls them, shadPS4 registers the names as constant-zero stubs and KytyPS5 registers none. The host keeps no learned or user dictionary, so no host mapping exists, and a silent zero would hide a failed store operation; every one throws.

  • sceImeCheckUpdateTextInfo, sceImeCheckRemoteEventParam (libSceIme) - both checkers stay NotImplemented. They reuse the 64-byte ImeEditText and the event payload at offset eight, and their byte-sized repair flag permits correcting invalid text ranges and caret positions, but what counts as invalid, what a repair rewrites, whether the input is changed in place and what is returned on each outcome is unknown; shadPS4 registers the names as constant-zero stubs and KytyPS5 registers none. sceImeCheckFilterText's contract is equally unknown (see its entry), so all three checkers throw.

Functional

  • sceImeKeyboardOpen, sceImeKeyboardClose (libSceIme) - opening a keyboard that is already open for the same user returns 0x80bc0001 (busy) and closing one that is not open returns 0x80bc0002, as KytyPS5 does; it tracks one keyboard for all users, while the open state is kept per user id here, and the PS5 result is unverified. Five titles disassembled for this entry have 8 Open call sites (PPSA03001 0x2073f79, PPSA07426 0x14682d9, PPSA29866 0x2d8fa8, PPSA30601 0x15e4934, PPSA04354 0xeac8b9, 0xeac8f6, 0xeac933 and 0xeac970) and 6 Close call sites, none reading the result. Open's result is tested only for 0 or ignored, except in PPSA29866: 0x80bc0001 gives an error value of its own and 0x80bc0002 an assertion output.

  • sceImeKeyboardGetInfo (libSceIme) returns 0x80bc0023 (no resource id) for every id while a keyboard is open, since the IME keyboard never reports a connected device. sceImeKeyboardSetMode validates the mode bits but the mode has no effect, as no IME keyboard events are delivered.

  • sceImeKeyboardGetResourceId (libSceIme) reports that no USB keyboard is connected (0x80bc0004, as shadPS4 does) because IME keyboard events are not delivered to the handler, although libSceKeyboard exposes the host keyboard

  • sceImeOpen text filter (libSceIme) runs on the text edits of host input - typing, backspace, forward delete and a multiline Enter - following KytyPS5, not confirmed on a PS5. The host input thread only queues the edit under the IME mutex; sceImeUpdate applies it on the title's thread, where the filter also runs with the mutex released - like the event handler, so a filter that calls back into sceIme* cannot deadlock - and the structural edit and the filtered commit are serialized under the mutex, with a commit after the session closed or reopened dropped by a session id. The filter is guest code and ImeTextFilter and ImeExtKeyboardFilter are declared APS5_VABI like EventHandler. The filter is called with the edited text, a buffer of maxTextLength UTF-16 units and its length; a nonzero return, an output longer than the capacity, an unpaired surrogate or, without the multiline option, a line break keeps the edit unfiltered. An accepted output replaces the text, the caret stays where the edit put it and is clamped to the text and normalized past a surrogate pair, and one UpdateText is sent with the minimal edit delta of the whole old and new text, as KytyPS5 computes it; an output equal to the previous text sends no event. Caret moves, PressEnter without multiline, PressClose, sceImeSetText and sceImeSetCaret do not run the filter, as in KytyPS5; a sceImeSetText or sceImeSetCaret that lands while the filter runs bumps a revision beside the session id, and the filtered commit is dropped when either changed, as KytyPS5 drops the commit when its revision changed, so the title's own text or caret setting wins, the edit is discarded and sends no event. An external keyboard filter is accepted and stored on the session: it is called only for keyboard events that carry key data, which the host input path does not produce - it delivers text and actions, as KytyPS5's host API queues external inputs with a zeroed key and skips the filter for them - so it is never called

  • sceImeVshNotifyCurrentTextInfo and sceImeVshNotifyCurrentTextInfoForReconvertText: assembly confirms seven and eight integer/pointer arguments, including the stack arguments, with no incoming SIMD parameter. Both take a context, UTF-16 string, signed 32-bit caret index and two pairs of 32-bit preedit/selection values. Pair endpoint-versus-length semantics and the reconversion option remain unresolved. Protected bodies are unchanged.

  • sceImeOpen (libSceIme) tracks a host composition (SDL_TEXTEDITING, forwarded by ImeTextInput) and never delivers it to the title: the preedit is not in the text, the buffers, the text filter or the events, and the console's delivery of a preedit to a title (a text area of mode Preedit) is not measured. While a composition is active Enter and Escape only discard it, and Backspace, Delete, the arrow keys, Home, End and paste are ignored, assuming an input method takes those keys itself; no real input method was tried on any platform. Closes when: measured with a CJK input method on Linux, Windows and macOS

  • Pasting (Ctrl+V, Shift+Insert, Command+V on macOS) into sceImeOpen (libSceIme) and sceImeDialogInit is a host feature with no console counterpart measured: the clipboard is read only on the key press, converted to UTF-16 with invalid bytes as U+FFFD, controls stripped, line breaks dropped (kept as LF for a multi-line sceImeOpen session) and cut to 64 KiB after SDL has already copied the whole text. The panel type and the password option are not modelled by the host, so a numeric or password field accepts what a typed key would; only the title's text filter shapes a paste. Copy and cut are not implemented, as there is no selection