fix(keyboard): preserve raw keys and ignore the Kana LED

This commit is contained in:
Danigamer05 committed 2026-10-24 02:46:30 +02:00
1 parent e2b9700a98
commit aaa33a3f3e
3 files changed
+69 -10

No files matched your search

@@ -175,17 +175,15 @@ int GetKey2Char(std::int32_t handle, std::int32_t arrange, std::uint32_t ledStat
{
std::lock_guard lock(keyboardMutex);
if (!initialized) return KEYBOARD_ERROR_NOT_INITIALIZED;
if (keyCode < 4 || keyCode > 231) return KEYBOARD_ERROR_INVALID_ARG;
if (handle != KEYBOARD_HANDLE || !opened) return KEYBOARD_ERROR_INVALID_HANDLE;
}
if (charData == nullptr) return KEYBOARD_ERROR_INVALID_ARG;
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;
}
*charData = {};
charData->char_code = character(arrange == KEYBOARD_ARRANGEMENT_106, ledState, modifierKey, keyCode);
charData->processed = charData->char_code != 0;
const std::uint16_t converted = character(arrange == KEYBOARD_ARRANGEMENT_106, ledState, modifierKey, keyCode);
charData->char_code = converted != 0 ? converted : keyCode;
charData->processed = converted != 0;
charData->length = charData->processed ? 1 : 0;
return KEYBOARD_OK;
}
@@ -4,7 +4,11 @@
#include "SDL_events.h"
#include "SDL_keyboard.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <source_location>
#include <stdexcept>
extern "C" {
@@ -19,7 +23,11 @@ int APS5_VABI sceKeyboardConnectPort(void);
int APS5_VABI sceKeyboardDisconnectAll(void);
}
static void Require(bool value) { if (!value) std::abort(); }
static void Require(bool value, std::source_location location = std::source_location::current()) {
if (value) return;
std::fprintf(stderr, "%s:%u: keyboard assertion failed\n", location.file_name(), location.line());
std::abort();
}
static SDL_Event KeyEvent(Uint32 type, SDL_Scancode scancode, Uint16 mod = 0, Uint8 repeat = 0) {
SDL_Event event{};
@@ -34,14 +42,63 @@ static SDL_Event KeyEvent(Uint32 type, SDL_Scancode scancode, Uint16 mod = 0, Ui
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, arrange, led, modifierKey, keyCode, &data) == KEYBOARD_OK);
Require(data.processed == (data.char_code != 0) && data.length == (data.processed ? 1 : 0));
return data.char_code;
Require(data.processed ? data.char_code != 0 : data.char_code == keyCode);
Require(data.length == (data.processed ? 1 : 0));
return data.processed ? data.char_code : 0;
}
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);
}
static void CheckInvalidKeys(bool opened) {
constexpr std::uint16_t invalidKeys[] = {0, 1, 2, 3, 232, 255, 256, 65535};
for (const auto key : invalidKeys) {
for (const auto handle : {KEYBOARD_HANDLE, 42}) {
KeyboardCharData data;
std::memset(&data, 0xa5, sizeof(data));
unsigned char before[sizeof(data)];
std::memcpy(before, &data, sizeof(data));
Require(sceKeyboardGetKey2Char(handle, KEYBOARD_ARRANGEMENT_101, 0, 0, key, &data) == KEYBOARD_ERROR_INVALID_ARG);
Require(std::memcmp(&data, before, sizeof(data)) == 0);
Require(sceKeyboardGetKey2Char(handle, KEYBOARD_ARRANGEMENT_106, KEYBOARD_LED_KANA, 0, key, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
}
}
for (const auto key : {std::uint16_t{4}, std::uint16_t{231}}) {
KeyboardCharData data{};
const auto expected = opened ? KEYBOARD_OK : KEYBOARD_ERROR_INVALID_HANDLE;
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_101, 0, 0, key, &data) == expected);
}
}
static void CheckUnconvertedKeys() {
constexpr std::uint16_t unconvertedKeys[] = {0x29, 0x39, 0x3a, 0x4f, 0x59, 0x88, 0xe0, 0xe7};
for (const auto arrange : {KEYBOARD_ARRANGEMENT_101, KEYBOARD_ARRANGEMENT_106}) {
for (const auto key : unconvertedKeys) {
KeyboardCharData data{};
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, arrange, 0, 0, key, &data) == KEYBOARD_OK);
Require(!data.processed && data.char_code == key);
}
}
}
static void CheckKanaLed() {
for (const auto arrange : {KEYBOARD_ARRANGEMENT_101, KEYBOARD_ARRANGEMENT_106}) {
for (const auto modifier : {std::uint8_t{0}, std::uint8_t{KEYBOARD_MOD_LEFT_SHIFT}, std::uint8_t{KEYBOARD_MOD_RIGHT_SHIFT}}) {
for (const auto led : {std::uint8_t{0}, std::uint8_t{KEYBOARD_LED_NUM_LOCK | KEYBOARD_LED_CAPS_LOCK}}) {
for (std::uint16_t key = 4; key <= 231; ++key) {
KeyboardCharData withoutKana{};
KeyboardCharData withKana{};
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, arrange, led, modifier, key, &withoutKana) == KEYBOARD_OK);
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, arrange, led | KEYBOARD_LED_KANA, modifier, key, &withKana) == KEYBOARD_OK);
Require(withKana.processed == withoutKana.processed);
Require(withKana.length == withoutKana.length && withKana.char_code == withoutKana.char_code);
}
}
}
}
}
int main() {
KeyboardData data[16]{};
KeyboardCharData charData{};
@@ -50,11 +107,15 @@ int main() {
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_ERROR_NOT_INITIALIZED);
Require(sceKeyboardInit() == KEYBOARD_OK);
Require(sceKeyboardInit() == KEYBOARD_OK);
CheckInvalidKeys(false);
Require(sceKeyboardOpen(1, 0, 1, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
Require(sceKeyboardOpen(1, 1, 0, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_101, 0, 0, 0x04, &charData) == KEYBOARD_ERROR_INVALID_HANDLE);
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_ERROR_INVALID_HANDLE);
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_HANDLE);
CheckInvalidKeys(true);
CheckUnconvertedKeys();
CheckKanaLed();
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_ERROR_ALREADY_OPENED);
Require(sceKeyboardGetConnection(42, &connected) == KEYBOARD_ERROR_INVALID_HANDLE);
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
+1 -1
View File
@@ -2,7 +2,7 @@
### Functional
- [sceKeyboardGetKey2Char](../../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp): the original validates HID usages 4 through 231 before the handle and preserves unconverted HID usages in the output with `processed == 0`. The host instead accepts out-of-range usages and writes zero for unconverted keys. The original ignores the Kana LED, while the host throws for it. This partially implemented function contains `NotImplemented_nid_no_patch(__func__)`; its body is preserved under the requested restriction. One title (PPSA15246) disassembled for this entry calls it once with an output buffer cleared to 24 bytes, uses a character only when the result is 0 and the first output byte is nonzero, and then reads the 16-bit value at offset 8, which agrees with `processed` and `char_code` as laid out here. Which other output fields it reads and what its other arguments mean are not shown.
- [sceKeyboardGetKey2Char](../../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp): initialization, output length and reserved bytes remain unverified on a console; unconverted keys retain the host's length of 0. One title (PPSA15246) disassembled for this entry checks the first output byte and reads the 16-bit value at offset 8. Which other output fields it reads and what its other arguments mean are not shown.
### Unknown function info