Skip to content

feat(libSceImeDialog): take the dialog's text from the host keyboard - #6504

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
0xRickx:feat/libsceimedialog-host-keyboard
Oct 19, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
0xRickx:feat/libsceimedialog-host-keyboard

Conversation

@0xRickx

@0xRickx 0xRickx commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

What

sceImeDialogInit writes "Slayer" into an empty text buffer, and the dialog finishes on its second status poll (Export.cpp). A title that asks the user for text never gets any: it gets "Slayer", or its own text back, at once. 26 titles of the homebrew catalog import the dialog, for search boxes, server addresses and sign-in names.

ProsperoRadio (PPSA99001) opens it for its station search and searches whatever comes back (search_screen.cpp, radio_ime.cpp). On main its search field fills itself with "Slayer" and no station matches:

ProsperoRadio search on main and with this PR

The dialog now runs until the user answers on the host keyboard, the way #4756 made sceImeOpen's panel-less IME take its text:

  • libSceIme's host input (ImePublishInput, fed by the game window's ImeTextInput) hands the text and editing keys to a sink that the dialog registers while no IME panel is open. ImeCapturesKeyboard stays true while the dialog runs, so the keys do not also act as pad buttons.
  • Typing edits the text up to maxTextLength without splitting a surrogate pair, as sceImeOpen does, and Backspace, Delete, Left, Right, Home and End edit it. Enter writes the text to the title's buffer and finishes with end status 0. Escape finishes with 1 (user canceled) and leaves the buffer as it was. sceImeDialogAbort still finishes with 2.
  • sceImeDialogInit reports busy (0x80bc0001) while a dialog is open, and refuses a null parameter (0x80bc0031), a maximum length outside 1 to 2048 (0x80bc0016) and a null buffer (0x80bc0017), as shadPS4 does (ime_dialog.cpp, parameters, length).
  • The debug prints are gone.

No dialog is drawn, as with sceImeOpen: the text is typed without a panel and reaches the title when Enter accepts it. That, and where the error codes still differ from shadPS4, are recorded in the new docs/dev/debt/libSceImeDialog.md. A title that relied on the "Slayer" text to get past a name entry now waits for the player, as it does on the console.

Tested

Windows 11 (26200), WinLibs GCC 15.2.0 r7, Release, main fa9365c (rebased onto 03c4cb5 afterwards, no conflicts):

  • New guest_ime_dialog test. It sends SDL text and key events through ImeTextInput, the game window's path:

    • the dialog stays running over 8 status polls, a second Init reports busy, and GetResult refuses before the end;
    • a two-byte character and an emoji (a surrogate pair) typed after the initial "Hi" reach the buffer only on Enter, with end status 0, and the keyboard is released when the dialog finishes;
    • Home, Delete, End, Backspace (which removes a surrogate pair whole) and Left edit the text; at maxTextLength an emoji that does not fit whole is dropped and "98" is cut to "9";
    • Enter on an empty buffer leaves it empty (no "Slayer"), Escape returns end status 1 and keeps the buffer, and Abort returns 2 and ignores later keys;
    • the four parameter errors.

    With main's libSceImeDialog and libSceIme it aborts (the dialog finishes on the second poll); with the change it passes.

  • guest_ime_open, guest_ime_keyboard, guest_ime_parameters, keyboard_input and patched_libraries pass; the patched libSceImeDialog resolves its import from libSceIme.

  • tools/check_conventions.py --base upstream/main passes.

  • main does not build fully on Windows right now (an AGC test asks for a 64 KiB alignment that MinGW's object format refuses; test(agc): align the indirect arguments block at run time #6452 and fix(agc): allocate indirect arguments test block dynamically on Windows #6478 fix it), so I built the libraries and these tests instead of the full suite.

  • ProsperoRadio (PPSA99001, catalog 01.000.010), relinked with this main, driven with its scripted-test hook (triangle opens the search screen, cross opens the dialog) and captured with APS5_DUMP_FRAMES, with a local catalogue of three stations (Rock Classics, Jazz Lounge, News 24). The image above is frame 12 of each run:

    • main: the field fills itself with "Slayer": "0 stations", "No stations match".
    • this PR: while the dialog waits, the field stays empty with its caret and the three stations stay listed.
    • I did not type into the window itself during the run: SDL gives the window keyboard focus only when it is the foreground window. The test above sends the same SDL events through ImeTextInput.
  • Linux (Ubuntu 24.04 in WSL, GCC 13.3, Release, the CI's configure options, lavapipe), merged onto main 03c4cb5:

    • the same six tests pass; with only this PR's test and CMakeLists.txt on that main, guest_ime_dialog aborts;
    • full ctest: 1265/1276. The eleven failures (ten agc_* tests and guest_socket_read_write) fail the same way on plain main 03c4cb5 in this setup.
  • git merge-tree: merges cleanly with main and with the two open pull requests that touch libSceIme/Export.cpp (fix(libSceIme): return error codes instead of throwing on duplicate open or close #5856, fix: complete compatibility gaps #6447).

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: PPSA99001 ProsperoRadio (PPSA99001) #5192 (its station search)
  • AI-assisted: yes

🤖 Generated with Claude Code

sceImeDialogInit wrote "Slayer" into an empty text buffer and the
dialog finished on the second status poll, so a title never got text
from the user: ProsperoRadio's search typed "Slayer" by itself and
found no station.

The dialog now runs until the user answers on the host keyboard, the
way boykopovar#4756 made sceImeOpen's panel-less IME take it. While no IME panel
is open, libSceIme hands the game window's text and editing keys to
a sink that the dialog registers. Typing edits the text up to
maxTextLength without splitting a surrogate pair, Enter writes it to
the title's buffer and finishes with end status 0, and Escape finishes
with 1. Abort still finishes with 2. A second Init reports busy, and a
null parameter or buffer or a maximum length outside 1 to 2048 is
refused, as in shadPS4.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@screamm

screamm commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Cross-validation on Windows 11 Pro 26220, NVIDIA RTX 4070 (596.21), MinGW GCC 15.2, PR head 6c5686d7e merged on main 5d9dcc42d (together with #6507, no overlap, no conflicts):

  • Build: only the known 64 KiB alignas AGC test fails (test(agc): align the indirect arguments block at run time #6452/fix(agc): allocate indirect arguments test block dynamically on Windows #6478); the libs build cleanly.
  • guest_ime_dialog, guest_ime_open, guest_ime_keyboard, guest_ime_parameters, keyboard_input, patched_libraries, --repeat until-fail:3: all pass.
  • Negative control: the PR's guest_ime_dialog_tests run against main's libSceIme/libSceImeDialog aborts 3 of 3 (the old two-poll finish); against the PR's libs it passes 3 of 3. (Test binary against main's libraries, not a source revert.)
  • Non-GPU suite: 838 tests, 13 timeouts under heavy host load; all pass on a serial rerun (two python tests exceed their own 20/30 s limit here and pass when run directly). None touches ime.
  • tools/check_conventions.py --base origin/main and git diff --check: pass. No PS5 export is added; the built libs gain only host-side names (ImeSetHostTextSink_nid_no_patch in libSceIme, one incidental mangled std::u16string symbol in libSceImeDialog).
  • ProsperoRadio PPSA99001 (01.000.010), same scripted run on both builds (its dev/request.txt hook: triangle opens the search screen, cross opens the dialog), 120 s: on main the search field fills itself with "Slayer" (0 stations · Slayer); with this PR the field stays empty with its placeholder while the dialog waits, 5536 frames, no stop line. Reproduced in a second run. The catalogue was empty on my side (Radio Browser unreachable from the harness), so I only compared the field, not station results.
  • Not verified: typing and Enter in the title. SDL only gives the window keyboard focus when it is the foreground window; posting WM_CHAR/Enter to the window had no effect, and I did not use real SendInput on a shared desktop. The unit test's SDL events are the only evidence for the typed-text path.

One question: 24 titles in my local set import sceImeDialogInit. With a gamepad only, the dialog can no longer finish (main finishes it after two polls), so a title that opens it and waits for the answer blocks until a key reaches the window. Is that intended, or should a pad button cancel it? I ran only PPSA99001.

Written with Claude Code assistance (validation by a subagent, reviewed in this session).

@github-actions

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 7658 core/libs/prx/libSceIme/Export.cpp

@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit 8a526d4 into boykopovar:main Oct 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build docs prx unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants