diff --git a/core/libs/prx/libSceKeyboard/include/keyboard_structs.h b/core/libs/prx/libSceKeyboard/include/keyboard_structs.h index 326fa4b84..c219f233d 100644 --- a/core/libs/prx/libSceKeyboard/include/keyboard_structs.h +++ b/core/libs/prx/libSceKeyboard/include/keyboard_structs.h @@ -18,6 +18,7 @@ constexpr std::int32_t KEYBOARD_ARRANGEMENT_106 = 1; constexpr std::uint32_t KEYBOARD_LED_NUM_LOCK = 1; constexpr std::uint32_t KEYBOARD_LED_CAPS_LOCK = 2; constexpr std::uint32_t KEYBOARD_LED_SCROLL_LOCK = 4; +constexpr std::uint32_t KEYBOARD_LED_KANA = 16; constexpr std::uint32_t KEYBOARD_MOD_LEFT_SHIFT = 2; constexpr std::uint32_t KEYBOARD_MOD_RIGHT_SHIFT = 32; diff --git a/core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp b/core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp index 7bc369767..2bb6273e7 100644 --- a/core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp +++ b/core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp @@ -21,6 +21,8 @@ int keyCount = 0; constexpr char US_NORMAL[] = "1234567890\n\0\b\t -=[]\\\0;'`,./"; constexpr char US_SHIFTED[] = "!@#$%^&*()\n\0\b\t _+{}|\0:\"~<>?"; +constexpr char JIS_NORMAL[] = "1234567890\n\0\b\t -^@[]];:\0,./"; +constexpr char JIS_SHIFTED[] = "!\"#$%&'()\0\n\0\b\t =~`{}}+*\0<>?"; constexpr char KEYPAD_DIGITS[] = "1234567890."; KeyboardData snapshot() { @@ -69,15 +71,18 @@ bool updateKey(std::uint16_t keyCode, bool pressed) { return true; } -std::uint16_t usCharacter(std::uint32_t ledState, std::uint32_t modifierKey, std::uint16_t keyCode) { +std::uint16_t character(bool jis, std::uint32_t ledState, std::uint32_t modifierKey, std::uint16_t keyCode) { const bool shift = (modifierKey & (KEYBOARD_MOD_LEFT_SHIFT | KEYBOARD_MOD_RIGHT_SHIFT)) != 0; if (keyCode >= 0x04 && keyCode <= 0x1d) { const bool upper = shift != ((ledState & KEYBOARD_LED_CAPS_LOCK) != 0); return static_cast((upper ? 'A' : 'a') + keyCode - 0x04); } if (keyCode >= 0x1e && keyCode <= 0x38) { - return static_cast((shift ? US_SHIFTED : US_NORMAL)[keyCode - 0x1e]); + const char* table = jis ? (shift ? JIS_SHIFTED : JIS_NORMAL) : (shift ? US_SHIFTED : US_NORMAL); + return static_cast(table[keyCode - 0x1e]); } + if (jis && keyCode == 0x87) return shift ? '_' : '\\'; + if (jis && keyCode == 0x89) return shift ? '|' : '\\'; switch (keyCode) { case 0x54: return '/'; case 0x55: return '*'; @@ -155,13 +160,13 @@ int GetKey2Char(std::int32_t handle, std::int32_t arrange, std::uint32_t ledStat if (handle != KEYBOARD_HANDLE || !opened) return KEYBOARD_ERROR_INVALID_HANDLE; } if (charData == nullptr) return KEYBOARD_ERROR_INVALID_ARG; - if (arrange == KEYBOARD_ARRANGEMENT_106) { + if (arrange != KEYBOARD_ARRANGEMENT_101 && arrange != KEYBOARD_ARRANGEMENT_106) return KEYBOARD_ERROR_INVALID_ARG; + if (arrange == KEYBOARD_ARRANGEMENT_106 && (ledState & KEYBOARD_LED_KANA) != 0) { NotImplemented_nid_no_patch(__func__); return KEYBOARD_ERROR_INVALID_ARG; } - if (arrange != KEYBOARD_ARRANGEMENT_101) return KEYBOARD_ERROR_INVALID_ARG; *charData = {}; - charData->char_code = usCharacter(ledState, modifierKey, keyCode); + charData->char_code = character(arrange == KEYBOARD_ARRANGEMENT_106, ledState, modifierKey, keyCode); charData->processed = charData->char_code != 0; charData->length = charData->processed ? 1 : 0; return KEYBOARD_OK; diff --git a/core/libs/prx/libSceKeyboard/tests/Keyboard.cpp b/core/libs/prx/libSceKeyboard/tests/Keyboard.cpp index 3b633176d..802e1da75 100644 --- a/core/libs/prx/libSceKeyboard/tests/Keyboard.cpp +++ b/core/libs/prx/libSceKeyboard/tests/Keyboard.cpp @@ -27,13 +27,17 @@ static SDL_Event KeyEvent(Uint32 type, SDL_Scancode scancode, Uint16 mod = 0, Ui return event; } -static std::uint16_t Char(std::uint32_t led, std::uint32_t modifierKey, std::uint16_t keyCode) { +static std::uint16_t Char(std::uint32_t led, std::uint32_t modifierKey, std::uint16_t keyCode, std::int32_t arrange = KEYBOARD_ARRANGEMENT_101) { KeyboardCharData data{}; - Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_101, led, modifierKey, keyCode, &data) == KEYBOARD_OK); + Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, arrange, led, modifierKey, keyCode, &data) == KEYBOARD_OK); Require(data.processed == (data.char_code != 0) && data.length == (data.processed ? 1 : 0)); return data.char_code; } +static std::uint16_t Jis(std::uint32_t modifierKey, std::uint16_t keyCode, std::uint32_t led = 0) { + return Char(led, modifierKey, keyCode, KEYBOARD_ARRANGEMENT_106); +} + int main() { KeyboardData data[16]{}; KeyboardCharData charData{}; @@ -115,7 +119,22 @@ int main() { Require(Char(0, 0, 0x59) == 0 && Char(KEYBOARD_LED_NUM_LOCK, 0, 0x59) == '1'); Require(Char(KEYBOARD_LED_NUM_LOCK, 0, 0x62) == '0' && Char(KEYBOARD_LED_NUM_LOCK, 0, 0x63) == '.'); Require(Char(0, 0, 0x54) == '/' && Char(0, 0, 0x57) == '+' && Char(0, 0, 0x58) == '\n'); + Require(Char(0, 0, 0x87) == 0 && Char(0, 0, 0x89) == 0); + + constexpr std::uint32_t shift = KEYBOARD_MOD_LEFT_SHIFT; + Require(Jis(0, 0x04) == 'a' && Jis(shift, 0x04) == 'A' && Jis(KEYBOARD_MOD_RIGHT_SHIFT, 0x04, KEYBOARD_LED_CAPS_LOCK) == 'a'); + Require(Jis(0, 0x1e) == '1' && Jis(shift, 0x1e) == '!' && Jis(shift, 0x1f) == '"' && Jis(shift, 0x23) == '&'); + Require(Jis(shift, 0x24) == '\'' && Jis(shift, 0x25) == '(' && Jis(shift, 0x26) == ')' && Jis(0, 0x27) == '0' && Jis(shift, 0x27) == 0); + Require(Jis(0, 0x28) == '\n' && Jis(0, 0x29) == 0 && Jis(0, 0x2a) == '\b' && Jis(0, 0x2b) == '\t' && Jis(shift, 0x2c) == ' '); + Require(Jis(0, 0x2d) == '-' && Jis(shift, 0x2d) == '=' && Jis(0, 0x2e) == '^' && Jis(shift, 0x2e) == '~'); + Require(Jis(0, 0x2f) == '@' && Jis(shift, 0x2f) == '`' && Jis(0, 0x30) == '[' && Jis(shift, 0x30) == '{'); + Require(Jis(0, 0x31) == ']' && Jis(shift, 0x31) == '}' && Jis(0, 0x32) == ']' && Jis(shift, 0x32) == '}'); + Require(Jis(0, 0x33) == ';' && Jis(shift, 0x33) == '+' && Jis(0, 0x34) == ':' && Jis(shift, 0x34) == '*'); + Require(Jis(0, 0x35) == 0 && Jis(shift, 0x35) == 0 && Jis(0, 0x36) == ',' && Jis(shift, 0x37) == '>' && Jis(shift, 0x38) == '?'); + Require(Jis(0, 0x87) == '\\' && Jis(shift, 0x87) == '_' && Jis(0, 0x89) == '\\' && Jis(shift, 0x89) == '|'); + Require(Jis(0, 0x59, KEYBOARD_LED_NUM_LOCK) == '1' && Jis(0, 0x59) == 0 && Jis(0, 0x55) == '*' && Jis(0, 0xe1) == 0); Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_101, 0, 0, 0x04, nullptr) == KEYBOARD_ERROR_INVALID_ARG); + Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_106, 0, 0, 0x04, nullptr) == KEYBOARD_ERROR_INVALID_ARG); Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, 2, 0, 0, 0x04, &charData) == KEYBOARD_ERROR_INVALID_ARG); Require(sceKeyboardClose(KEYBOARD_HANDLE) == KEYBOARD_OK); diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 645d976a4..96ffc1403 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -159,7 +159,7 @@ Throughout the project, every function at every stage either **does exactly what - [DCC display buffers](../../core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp) are presented only from uniform uncompressed or fast-clear keys; other keys, and register-clear keys over a pending image, throw. Keys are read as one byte per 256 bytes (the driver's model), not in the console's layout. - `--to-intel` guest module trampolines are covered only by a synthetic relinker test; no game title has been verified with them on Linux or Windows. - `--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. +- [sceKeyboardGetKey2Char](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) (libSceKeyboard) translates the 101-key (US) arrangement and the alphanumeric layer of the 106-key (Japanese) one, which follows the JIS layout of the HID usages: the Yen (0x89) and Ro (0x87) keys return `\` (0x5C) unshifted, as JIS X 0201 places the yen sign there; whether the console returns U+00A5 instead is unverified. With the Kana LED (bit 4, the HID position) set the 106-key arrangement throws, as the kana the console returns are unknown. 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.