From 78abb2b46a2ddfa775225b8cce2ff2e1d3591b60 Mon Sep 17 00:00:00 2001 From: hugodearaujo Date: Sun, 11 Oct 2026 20:35:58 -0300 Subject: [PATCH] fix(libSceUserService): report the console's default accessibility settings On a PS5 (firmware 13.60) a user with every accessibility setting at its default reads chat transcription 0, press-and-hold delay 0, trigger effect 1, vibration 1, zoom 0 and zoom follow focus 1; all six read 0 here. A user who is not logged in returns 0x80960009 with or without an output, as sceUserServiceGetAgeLevel does. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libSceUserService/Export.cpp | 47 ++++++++-------------- core/libs/tests/GuestUserService.cpp | 30 ++++++++++++++ docs/dev/TechnicalDebt.md | 1 + 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/core/libs/prx/libSceUserService/Export.cpp b/core/libs/prx/libSceUserService/Export.cpp index 07190caa3..8331ab7d1 100644 --- a/core/libs/prx/libSceUserService/Export.cpp +++ b/core/libs/prx/libSceUserService/Export.cpp @@ -6,54 +6,41 @@ #include #include "prx/libSceUserService/UserService.hpp" +static int ReportAccessibilitySetting(int user_id, int32_t* setting, int32_t value) { + if (user_id != USER_SERVICE_INITIAL_USER_ID) { + return USER_SERVICE_ERROR_NOT_LOGGED_IN; + } + if (setting == nullptr) { + return USER_SERVICE_ERROR_INVALID_ARGUMENT; + } + *setting = value; + return USER_SERVICE_OK; +} + extern "C" { int APS5_VABI sceUserServiceGetAccessibilityChatTranscription(int user_id, int32_t* chat_transcription) { - if (chat_transcription == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *chat_transcription = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, chat_transcription, 0); } int APS5_VABI sceUserServiceGetAccessibilityPressAndHoldDelay(int user_id, int32_t* press_and_hold_delay) { - if (press_and_hold_delay == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *press_and_hold_delay = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, press_and_hold_delay, 0); } int APS5_VABI sceUserServiceGetAccessibilityTriggerEffect(int user_id, int32_t* trigger_effect) { - if (trigger_effect == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *trigger_effect = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, trigger_effect, 1); } int APS5_VABI sceUserServiceGetAccessibilityVibration(int user_id, int32_t* vibration) { - if (vibration == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *vibration = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, vibration, 1); } int APS5_VABI sceUserServiceGetAccessibilityZoomEnabled(int user_id, int32_t* zoom_enabled) { - if (zoom_enabled == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *zoom_enabled = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, zoom_enabled, 0); } int APS5_VABI sceUserServiceGetAccessibilityZoomFollowFocus(int user_id, int32_t* zoom_follow_focus) { - if (zoom_follow_focus == nullptr || user_id != USER_SERVICE_INITIAL_USER_ID) { - return USER_SERVICE_ERROR_INVALID_ARGUMENT; - } - *zoom_follow_focus = 0; - return USER_SERVICE_OK; + return ReportAccessibilitySetting(user_id, zoom_follow_focus, 1); } int APS5_VABI sceUserServiceGetAgeLevel(int user_id, uint32_t* age_level) { diff --git a/core/libs/tests/GuestUserService.cpp b/core/libs/tests/GuestUserService.cpp index 1931f036f..83d7afc73 100644 --- a/core/libs/tests/GuestUserService.cpp +++ b/core/libs/tests/GuestUserService.cpp @@ -9,6 +9,12 @@ int APS5_VABI sceUserServiceGetRegisteredUserIdList(UserServiceRegisteredUserIdL int APS5_VABI sceUserServiceGetUserColor(int user_id, int* color); int APS5_VABI sceUserServiceGetNpAccountId(int user_id, std::uint64_t* account_id); int APS5_VABI sceUserServiceGetAgeLevel(int user_id, std::uint32_t* age_level); +int APS5_VABI sceUserServiceGetAccessibilityChatTranscription(int user_id, std::int32_t* value); +int APS5_VABI sceUserServiceGetAccessibilityPressAndHoldDelay(int user_id, std::int32_t* value); +int APS5_VABI sceUserServiceGetAccessibilityTriggerEffect(int user_id, std::int32_t* value); +int APS5_VABI sceUserServiceGetAccessibilityVibration(int user_id, std::int32_t* value); +int APS5_VABI sceUserServiceGetAccessibilityZoomEnabled(int user_id, std::int32_t* value); +int APS5_VABI sceUserServiceGetAccessibilityZoomFollowFocus(int user_id, std::int32_t* value); } namespace { @@ -53,4 +59,28 @@ int main() { } Require(sceUserServiceGetAgeLevel(USER_SERVICE_INITIAL_USER_ID, &age_level) == USER_SERVICE_OK); Require(age_level == 0xffffffffu); + + struct Setting { + int (APS5_VABI *get)(int, std::int32_t*); + std::int32_t value; + }; + const Setting settings[] = { + {sceUserServiceGetAccessibilityChatTranscription, 0}, + {sceUserServiceGetAccessibilityPressAndHoldDelay, 0}, + {sceUserServiceGetAccessibilityTriggerEffect, 1}, + {sceUserServiceGetAccessibilityVibration, 1}, + {sceUserServiceGetAccessibilityZoomEnabled, 0}, + {sceUserServiceGetAccessibilityZoomFollowFocus, 1}, + }; + for (const Setting& setting : settings) { + std::int32_t value = 0x5a5a5a5a; + Require(setting.get(USER_SERVICE_INITIAL_USER_ID, nullptr) == USER_SERVICE_ERROR_INVALID_ARGUMENT); + for (int user_id : absent_users) { + Require(setting.get(user_id, &value) == USER_SERVICE_ERROR_NOT_LOGGED_IN); + Require(value == 0x5a5a5a5a); + Require(setting.get(user_id, nullptr) == USER_SERVICE_ERROR_NOT_LOGGED_IN); + } + Require(setting.get(USER_SERVICE_INITIAL_USER_ID, &value) == USER_SERVICE_OK); + Require(value == setting.value); + } } diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 6999b4c00..e09ae367d 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -275,6 +275,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceNpSessionSignalingGetMemoryInfo](../../core/libs/prx/libSceNpSessionSignaling/Export.cpp) (libSceNpSessionSignaling) - unknown signature - [sceNpSessionSignalingGetConnectionStatistics](../../core/libs/prx/libSceNpSessionSignaling/Export.cpp) (libSceNpSessionSignaling) - unknown signature - [sceUserServiceGetAgeLevel](../../core/libs/prx/libSceUserService/Export.cpp) (libSceUserService) - on a PS5 (firmware 13.60) the value is the age set in the user's parental restriction (0, 7, 12 and 15 were measured) and `0xFFFFFFFF` without one; a user who is not logged in returns `0x80960009` with or without an output. Parental restrictions are not modelled, so the initial user is always reported as unrestricted. PPSA12544 (Unity) only stores the value for its user profile +- [sceUserServiceGetAccessibilityChatTranscription, PressAndHoldDelay, TriggerEffect, Vibration, ZoomEnabled, ZoomFollowFocus](../../core/libs/prx/libSceUserService/Export.cpp) (libSceUserService) - report 0, 0, 1, 1, 0 and 1, what a PS5 (firmware 13.60) reports for a user whose accessibility settings are all at their defaults; the console reports the user's own settings (a changed vibration intensity read 3), which are not modelled. What each number means is unknown. A user who is not logged in returns `0x80960009` with or without an output - [sceGameUpdateGetAddcontLatestVersion](../../core/libs/prx/libSceGameUpdate/Export.cpp) (libSceGameUpdate) - a null `entitlement_label` throws: KytyPS5 accepts it, prosper returns `0x80412803`. Bytes after `found` are zeroed as in KytyPS5; prosper leaves them untouched - [sceSystemServiceParamGetString](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - the system name (parameter 6) is the fixed `PS5`, not the console's name; other parameters and buffers of 1 to 64 bytes throw - [sceSystemServiceParamGetInt](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - console language numbers 0 to 29 follow the PS4 SDK enum in [OpenOrbis](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/06fcf7fd108fa080035cdd3259ed22eb07e0508c/include/orbis/_types/sys_service.h#L54-L83) (21 Arabic). 30 (Ukrainian) is not in it and follows PPSA99505 ([Jelly5](https://github.com/02dnot/Jelly5/blob/552b866d89b2a58b27f7f7b0484dc743ce235526/app/src/app/i18n.cpp#L29-L60)) and PPSA99002 ([ProsperoLight](https://github.com/blackbearreloaded/ProsperoLight/blob/b708bbde3457bef1073a9ab6959957cb691e8e2f/include/i18n.hpp#L252-L309)), whose numbers agree with the enum. Not confirmed on a console, and neither title starts on `main` yet. Without `ANYPS5_LANGUAGE` the language is English (United States); the date format, time format, time zone, summer time and enter button stay fixed