feat(libSceIme): implement keyboard info and mode queries
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bc24783e5b
commit
58263b5075
|
|
@ -18,4 +18,14 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_ime_parameters PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_ime_keyboard_tests ${LIBS_INCLUDE_DIR}/tests/GuestImeKeyboard.cpp)
|
||||
target_include_directories(guest_ime_keyboard_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_ime_keyboard_tests PRIVATE libSceIme libc)
|
||||
configure_windows_unwind(guest_ime_keyboard_tests)
|
||||
add_test(NAME guest_ime_keyboard COMMAND guest_ime_keyboard_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_ime_keyboard PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -10,12 +10,18 @@
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr int ErrorNotOpened = static_cast<int>(0x80bc0002u);
|
||||
constexpr int ErrorInvalidUserId = static_cast<int>(0x80bc0010u);
|
||||
constexpr int ErrorInvalidType = static_cast<int>(0x80bc0011u);
|
||||
constexpr int ErrorInvalidOption = static_cast<int>(0x80bc0015u);
|
||||
constexpr int ErrorInvalidAddress = static_cast<int>(0x80bc0031u);
|
||||
constexpr int ErrorNoResourceId = static_cast<int>(0x80bc0023u);
|
||||
constexpr int ErrorInvalidMode = static_cast<int>(0x80bc0024u);
|
||||
constexpr uint32_t ValidKeyboardModes = 0x0000007f;
|
||||
constexpr uint32_t TypeNumber = 4;
|
||||
constexpr uint32_t ValidOptions = 0x00007bff;
|
||||
constexpr uint32_t OptionUseOver2K = 0x00004000;
|
||||
constexpr int32_t UserIdInvalid = -1;
|
||||
|
||||
std::mutex g_keyboardMutex;
|
||||
std::set<int32_t> g_openKeyboards;
|
||||
|
|
@ -47,9 +53,9 @@ int APS5_VABI sceImeKeyboardClose(int32_t user_id) {
|
|||
|
||||
int APS5_VABI sceImeKeyboardGetInfo(uint32_t resource_id, KeyboardInfo* info) {
|
||||
(void)resource_id;
|
||||
(void)info;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (!info) return ErrorInvalidAddress;
|
||||
std::lock_guard lock(g_keyboardMutex);
|
||||
return g_openKeyboards.empty() ? ErrorNotOpened : ErrorNoResourceId;
|
||||
}
|
||||
|
||||
int APS5_VABI sceImeKeyboardGetResourceId(int32_t user_id, KeyboardResourceIdArray* resource_ids) {
|
||||
|
|
@ -67,10 +73,10 @@ int APS5_VABI sceImeKeyboardOpen(int32_t user_id, const KeyboardParam* param) {
|
|||
}
|
||||
|
||||
int APS5_VABI sceImeKeyboardSetMode(int32_t user_id, uint32_t mode) {
|
||||
(void)user_id;
|
||||
(void)mode;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (user_id == UserIdInvalid) return ErrorInvalidUserId;
|
||||
std::lock_guard lock(g_keyboardMutex);
|
||||
if (!g_openKeyboards.contains(user_id)) return ErrorNotOpened;
|
||||
return (mode & ~ValidKeyboardModes) == 0 ? 0 : ErrorInvalidMode;
|
||||
}
|
||||
|
||||
int APS5_VABI sceImeOpen_nid_postfix(const Param* param, const ExtendedParam* extended) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceImeKeyboardOpen(int32_t user_id, const KeyboardParam* param);
|
||||
int APS5_VABI sceImeKeyboardClose(int32_t user_id);
|
||||
int APS5_VABI sceImeKeyboardGetInfo(uint32_t resource_id, KeyboardInfo* info);
|
||||
int APS5_VABI sceImeKeyboardSetMode(int32_t user_id, uint32_t mode);
|
||||
}
|
||||
|
||||
static_assert(sizeof(KeyboardInfo) == 36);
|
||||
|
||||
constexpr int NotOpened = static_cast<int>(0x80bc0002u);
|
||||
constexpr int InvalidUserId = static_cast<int>(0x80bc0010u);
|
||||
constexpr int NoResourceId = static_cast<int>(0x80bc0023u);
|
||||
constexpr int InvalidMode = static_cast<int>(0x80bc0024u);
|
||||
constexpr int InvalidAddress = static_cast<int>(0x80bc0031u);
|
||||
|
||||
static void Require(bool value, const char* message) {
|
||||
if (value) return;
|
||||
std::fprintf(stderr, "%s\n", message);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
static void RequireUntouched(const KeyboardInfo& info) {
|
||||
const auto* bytes = reinterpret_cast<const unsigned char*>(&info);
|
||||
for (size_t i = 0; i < sizeof(info); ++i) Require(bytes[i] == 0xa5, "keyboard info written");
|
||||
}
|
||||
|
||||
static void CheckClosed() {
|
||||
KeyboardInfo info;
|
||||
std::memset(&info, 0xa5, sizeof(info));
|
||||
Require(sceImeKeyboardGetInfo(0, nullptr) == InvalidAddress, "null info");
|
||||
Require(sceImeKeyboardGetInfo(0, &info) == NotOpened, "info without an open keyboard");
|
||||
RequireUntouched(info);
|
||||
Require(sceImeKeyboardSetMode(-1, 0) == InvalidUserId, "set mode invalid user");
|
||||
Require(sceImeKeyboardSetMode(1, 0) == NotOpened, "set mode without an open keyboard");
|
||||
Require(sceImeKeyboardSetMode(1, 0x80) == NotOpened, "set mode checks the mode before the keyboard");
|
||||
}
|
||||
|
||||
static void CheckOpened() {
|
||||
KeyboardParam param{};
|
||||
Require(sceImeKeyboardOpen(1, ¶m) == 0, "keyboard open failed");
|
||||
KeyboardInfo info;
|
||||
std::memset(&info, 0xa5, sizeof(info));
|
||||
Require(sceImeKeyboardGetInfo(0, nullptr) == InvalidAddress, "null info with an open keyboard");
|
||||
Require(sceImeKeyboardGetInfo(0, &info) == NoResourceId, "resource id 0 reported as a keyboard");
|
||||
Require(sceImeKeyboardGetInfo(0x12345678, &info) == NoResourceId, "unknown resource id reported as a keyboard");
|
||||
RequireUntouched(info);
|
||||
Require(sceImeKeyboardSetMode(-1, 0) == InvalidUserId, "set mode invalid user with an open keyboard");
|
||||
Require(sceImeKeyboardSetMode(2, 0) == NotOpened, "set mode for a user without an open keyboard");
|
||||
Require(sceImeKeyboardSetMode(1, 0) == 0, "mode 0 rejected");
|
||||
Require(sceImeKeyboardSetMode(1, 0x7f) == 0, "all mode bits rejected");
|
||||
Require(sceImeKeyboardSetMode(1, 0x41) == 0, "manual mode without format characters rejected");
|
||||
Require(sceImeKeyboardSetMode(1, 0x80) == InvalidMode, "mode bit 7 accepted");
|
||||
Require(sceImeKeyboardSetMode(1, 0x80000001u) == InvalidMode, "mode bit 31 accepted");
|
||||
Require(sceImeKeyboardClose(1) == 0, "keyboard close failed");
|
||||
Require(sceImeKeyboardGetInfo(0, &info) == NotOpened, "info after close");
|
||||
Require(sceImeKeyboardSetMode(1, 0) == NotOpened, "set mode after close");
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckClosed();
|
||||
CheckOpened();
|
||||
}
|
||||
|
|
@ -120,6 +120,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- `--to-intel` replaces the approximate VEX.128 register forms of VRSQRTPS and VRCPPS with [correctly rounded](../../core/relinker/codegen/src/x86/ReciprocalLowering.cpp) 1/sqrt(x) and 1/x, not with the AMD approximation: its tables are not public. Intel's approximation of 1/sqrt(1.0) is 0x3F7FF000, and two Newton-Raphson steps on it settle on 0.99999994 instead of 1.0; a renormalised identity quaternion then turns into a NaN axis in PPSA21564, which the console does not show. Refined results now reach the exact value; unrefined ones can still differ from the console in the low bits. Each site costs an out-of-line stub (two jumps, a spill below the red zone, SQRTPS/DIVPS). The 256-bit, scalar, legacy and memory forms keep the native instruction, as does a 4-byte site with no movable instruction after it for the jump (5 sites in PPSA21564).
|
||||
- [sceKeyboardGetKey2Char](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) (libSceKeyboard) translates only the 101-key (US) arrangement and throws for the 106-key (Japanese) one; Ctrl and Alt do not change the character.
|
||||
- [sceAudioOut2Set3DLatency](../../core/libs/prx/libSceAudioOut/src/AudioOut2System.cpp) and [sceAudioOut2MasteringInit](../../core/libs/prx/libSceAudioOut/src/AudioOut2Mastering.cpp) (libSceAudioOut) have no effect: there is no 3D rendering or mastering stage.
|
||||
- [sceImeKeyboardGetInfo](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) returns `0x80bc0023` (no resource id) for every id while a keyboard is open, since the IME keyboard never reports a connected device. [sceImeKeyboardSetMode](../../core/libs/prx/libSceIme/Export.cpp) validates the mode bits but the mode has no effect, as no IME keyboard events are delivered.
|
||||
- [libSceAudiodec](../../core/libs/prx/libSceAudiodec/Export.cpp) throws for the 24-bit PCM word size (`iBwPcm` 0): its sample layout is unknown. ATRAC9 decoding is covered only by configuration and error tests, as no ATRAC9 encoder is available for a fixture.
|
||||
- [sceAjmDecMp3ParseFrame](../../core/libs/prx/libSceAjm.native/src/Ajm.cpp) (libSceAjm.native) throws when the original file length is requested (`parse_ofl` non-zero): reading it from the frame's Xing/Info, VBRI or Fraunhofer data is not implemented.
|
||||
- The [output modifier](../../core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp) (`mul:2`, `mul:4`, `div:2`) follows the hardware with the IEEE mode off and f32 denormals flushed, the LLVM graphics default; the shader's MODE register is not read, and the hardware ignores the modifier in the other modes. On f16 results it is ignored, as on the hardware while f16 denormals are enabled; with them flushed the hardware applies it.
|
||||
|
|
|
|||
Loading…
Reference in New Issue