Files
AnyPS5/core/libs/tests/GuestImeDialog.cpp
erickerxhalliandClaude Opus 5.5 bdebcbde96 feat(libSceImeDialog): close an open dialog in sceImeDialogForceClose
sceImeDialogForceClose threw. It now closes a running or finished
dialog the way sceImeDialogTerm does, without writing the typed text to
the title's buffer, and returns NOT_IN_USE (0x80bc0107) when no dialog
is open. The behaviour follows shadPS4 and the error code is the one
SharpProspero lists for PS5. The ImeDialog guest test covers each case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Arbzg9c2DA4DEFKVSvRgYv
2026-10-20 13:39:58 +00:00

190 lines
6.0 KiB
C++

#include "SceTypes.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceIme/include/ImeInput.hpp"
#include "prx/libSceVideoOut/include/ImeTextInput.hpp"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
extern "C" {
int APS5_VABI sceImeDialogInit(const Param*, const ExtendedParam*);
int APS5_VABI sceImeDialogGetStatus(void);
int APS5_VABI sceImeDialogGetResult(Result*);
int APS5_VABI sceImeDialogAbort(void);
int APS5_VABI sceImeDialogTerm(void);
int APS5_VABI sceImeDialogForceClose(void);
}
namespace {
constexpr int StatusNone = 0;
constexpr int StatusRunning = 1;
constexpr int StatusFinished = 2;
constexpr std::uint32_t EndStatusOk = 0;
constexpr std::uint32_t EndStatusUserCanceled = 1;
constexpr std::uint32_t EndStatusAborted = 2;
constexpr int ErrorBusy = static_cast<int>(0x80bc0001u);
constexpr int ErrorNotOpened = static_cast<int>(0x80bc0002u);
constexpr int ErrorNotInUse = static_cast<int>(0x80bc0107u);
constexpr int ErrorInvalidMaxTextLength = static_cast<int>(0x80bc0016u);
constexpr int ErrorInvalidInputTextBuffer = static_cast<int>(0x80bc0017u);
constexpr int ErrorInvalidAddress = static_cast<int>(0x80bc0031u);
void Require(bool value) { if (!value) std::abort(); }
constexpr unsigned WindowId = 7;
ImeTextInput g_window;
void Type(const char* utf8) {
SDL_Event event{};
event.type = SDL_TEXTINPUT;
event.text.windowID = WindowId;
std::strncpy(event.text.text, utf8, sizeof(event.text.text) - 1);
g_window.HandleEvent(event, WindowId);
}
void Press(SDL_Scancode scancode) {
SDL_Event event{};
event.type = SDL_KEYDOWN;
event.key.windowID = WindowId;
event.key.keysym.scancode = scancode;
g_window.HandleEvent(event, WindowId);
}
Param DialogParam(char16_t* buffer, std::uint32_t maxLength) {
Param param{};
param.max_text_length = maxLength;
param.input_text_buffer = buffer;
return param;
}
std::uint32_t EndStatus() {
Result result{};
Require(sceImeDialogGetResult(&result) == 0);
return result.endstatus;
}
void Open(const Param& param) {
Require(sceImeDialogInit(&param, nullptr) == 0);
Require(sceImeDialogGetStatus() == StatusRunning);
Require(ImeCapturesKeyboard_nid_postfix());
}
void Close() {
Require(sceImeDialogTerm() == 0);
Require(sceImeDialogGetStatus() == StatusNone);
}
}
int main() {
char16_t buffer[16] = u"Hi";
const Param param = DialogParam(buffer, 8);
Require(!ImeCapturesKeyboard_nid_postfix());
Require(sceImeDialogGetStatus() == StatusNone);
Require(sceImeDialogTerm() == ErrorNotOpened);
Open(param);
for (int poll = 0; poll < 8; ++poll) Require(sceImeDialogGetStatus() == StatusRunning);
Require(sceImeDialogInit(&param, nullptr) == ErrorBusy);
Result early{};
Require(sceImeDialogGetResult(&early) == ErrorNotOpened);
Type("\xc3\xa9");
Type("\xf0\x9f\x98\x80");
Require(std::u16string(buffer) == u"Hi");
Press(SDL_SCANCODE_RETURN);
Require(sceImeDialogGetStatus() == StatusFinished);
Require(!ImeCapturesKeyboard_nid_postfix());
Require(EndStatus() == EndStatusOk);
Require(std::u16string(buffer) == u"Hi\u00e9\U0001F600");
Require(sceImeDialogAbort() == ErrorNotOpened);
Close();
Require(sceImeDialogTerm() == ErrorNotOpened);
buffer[0] = u'\0';
Open(param);
Type("abc");
Press(SDL_SCANCODE_HOME);
Press(SDL_SCANCODE_DELETE);
Press(SDL_SCANCODE_END);
Type("\xf0\x9f\x98\x80");
Press(SDL_SCANCODE_BACKSPACE);
Press(SDL_SCANCODE_LEFT);
Type("X");
Type("1234");
Press(SDL_SCANCODE_END);
Type("\xf0\x9f\x98\x80");
Type("98");
Type("Z");
Press(SDL_SCANCODE_RETURN);
Require(EndStatus() == EndStatusOk);
Require(std::u16string(buffer) == u"bX1234c9");
Close();
buffer[0] = u'\0';
Open(param);
Press(SDL_SCANCODE_RETURN);
Require(EndStatus() == EndStatusOk);
Require(buffer[0] == u'\0');
Close();
std::memcpy(buffer, u"keep", sizeof(u"keep"));
Open(param);
Type("zz");
Press(SDL_SCANCODE_ESCAPE);
Require(sceImeDialogGetStatus() == StatusFinished);
Require(EndStatus() == EndStatusUserCanceled);
Require(std::u16string(buffer) == u"keep");
Close();
Open(param);
Require(sceImeDialogAbort() == 0);
Require(sceImeDialogGetStatus() == StatusFinished);
Require(!ImeCapturesKeyboard_nid_postfix());
Require(EndStatus() == EndStatusAborted);
Type("ignored");
Press(SDL_SCANCODE_RETURN);
Require(std::u16string(buffer) == u"keep");
Close();
Require(sceImeDialogForceClose() == ErrorNotInUse);
Open(param);
Type("zz");
Require(sceImeDialogForceClose() == 0);
Require(sceImeDialogGetStatus() == StatusNone);
Require(!ImeCapturesKeyboard_nid_postfix());
Type("ignored");
Press(SDL_SCANCODE_RETURN);
Require(std::u16string(buffer) == u"keep");
Result closed{};
Require(sceImeDialogGetResult(&closed) == ErrorNotOpened);
Require(sceImeDialogTerm() == ErrorNotOpened);
Require(sceImeDialogForceClose() == ErrorNotInUse);
Open(param);
Type("!");
Press(SDL_SCANCODE_RETURN);
Require(sceImeDialogGetStatus() == StatusFinished);
Require(sceImeDialogForceClose() == 0);
Require(sceImeDialogGetStatus() == StatusNone);
Require(std::u16string(buffer) == u"keep!");
Open(param);
Require(sceImeDialogAbort() == 0);
Require(sceImeDialogForceClose() == 0);
Require(sceImeDialogGetStatus() == StatusNone);
Open(param);
Close();
Require(sceImeDialogInit(nullptr, nullptr) == ErrorInvalidAddress);
const Param empty = DialogParam(buffer, 0);
Require(sceImeDialogInit(&empty, nullptr) == ErrorInvalidMaxTextLength);
const Param tooLong = DialogParam(buffer, 2049);
Require(sceImeDialogInit(&tooLong, nullptr) == ErrorInvalidMaxTextLength);
const Param noBuffer = DialogParam(nullptr, 8);
Require(sceImeDialogInit(&noBuffer, nullptr) == ErrorInvalidInputTextBuffer);
Require(sceImeDialogGetStatus() == StatusNone);
Require(!ImeCapturesKeyboard_nid_postfix());
}