From 15366896223b87c91379b1d3fb6ace551c1a89a0 Mon Sep 17 00:00:00 2001 From: KernelPanicNT <76663133+KernelPanicNT@users.noreply.github.com> Date: Wed, 14 Oct 2026 12:04:51 +0000 Subject: [PATCH] feat(libSceSystemGesture): implement sceSystemGestureGetTouchRecognizerInformation sceSystemGestureCreateTouchRecognizer now records the gesture type and rectangle in the title-owned recognizer buffer, and sceSystemGestureUpdateTouchRecognizerRectangle replaces the stored rectangle. sceSystemGestureGetTouchRecognizerInformation reports them back with updated_time 0, since no recognizer is ever updated with input. Recognizers that were not created by sceSystemGestureCreateTouchRecognizer, or that have no rectangle, throw because the console's result for them is unknown. The guest test now passes full-size recognizer and rectangle structures instead of an int. Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libSceSystemGesture/Export.cpp | 57 +++++++++++++++--- core/libs/tests/GuestSystemGesture.cpp | 62 +++++++++++++++++++- docs/dev/debt/libSceSystemGesture.md | 2 +- 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/core/libs/prx/libSceSystemGesture/Export.cpp b/core/libs/prx/libSceSystemGesture/Export.cpp index 9c71e1031b..ec9799ca72 100644 --- a/core/libs/prx/libSceSystemGesture/Export.cpp +++ b/core/libs/prx/libSceSystemGesture/Export.cpp @@ -2,6 +2,9 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include +#include +#include // No touch input is emulated: recognizers exist but never report events. static constexpr int32_t GESTURE_HANDLE = 1; @@ -9,6 +12,30 @@ static constexpr int SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT = static_cast(0x80D10003); static constexpr int SCE_SYSTEM_GESTURE_ERROR_INDEX_OUT_OF_ARRAY = static_cast(0x80D10005); +namespace { + +constexpr std::uint64_t RECOGNIZER_STATE_MAGIC = 0x41505335'47455354ULL; + +struct RecognizerState { + std::uint64_t magic; + std::int32_t gestureType; + std::uint32_t hasRectangle; + SystemGestureRectangle rectangle; +}; + +static_assert(sizeof(RecognizerState) <= sizeof(SystemGestureTouchRecognizer)); + +void storeRecognizerState(SystemGestureTouchRecognizer* recognizer, const RecognizerState& state) { + std::memcpy(recognizer->reserve, &state, sizeof(state)); +} + +bool loadRecognizerState(const SystemGestureTouchRecognizer* recognizer, RecognizerState& state) { + std::memcpy(&state, recognizer->reserve, sizeof(state)); + return state.magic == RECOGNIZER_STATE_MAGIC; +} + +} + extern "C" { int APS5_VABI sceSystemGestureAppendTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer) { @@ -22,11 +49,15 @@ int APS5_VABI sceSystemGestureClose(int32_t gesture_handle) { } int APS5_VABI sceSystemGestureCreateTouchRecognizer(int32_t gesture_handle, SystemGestureTouchRecognizer* recognizer, int32_t type, const SystemGestureRectangle* rectangle, const void* param) { - (void)type; - (void)rectangle; (void)param; if (gesture_handle != GESTURE_HANDLE) return SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; if (!recognizer) return SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT; + RecognizerState state{}; + state.magic = RECOGNIZER_STATE_MAGIC; + state.gestureType = type; + state.hasRectangle = rectangle ? 1 : 0; + if (rectangle) state.rectangle = *rectangle; + storeRecognizerState(recognizer, state); return 0; } @@ -95,11 +126,17 @@ int APS5_VABI sceSystemGestureGetTouchEventsCount(int32_t gesture_handle, const } int APS5_VABI sceSystemGestureGetTouchRecognizerInformation(int32_t gesture_handle, const SystemGestureTouchRecognizer* recognizer, SystemGestureTouchRecognizerInformation* information) { - (void)gesture_handle; - (void)recognizer; - (void)information; - NotImplemented_nid_no_patch(__func__); - return 0; + if (gesture_handle != GESTURE_HANDLE) return SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; + if (!recognizer || !information) return SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT; + RecognizerState state{}; + if (!loadRecognizerState(recognizer, state)) + throw std::runtime_error(std::string(__func__) + ": recognizer was not created by sceSystemGestureCreateTouchRecognizer"); + if (!state.hasRectangle) + throw std::runtime_error(std::string(__func__) + ": recognizer was created without a rectangle"); + information->gesture_type = state.gestureType; + information->rectangle = state.rectangle; + information->updated_time = 0; + return 0; } int APS5_VABI sceSystemGestureInitializePrimitiveTouchRecognizer(const void* param) { @@ -151,6 +188,12 @@ int APS5_VABI sceSystemGestureUpdateTouchRecognizerRectangle(int32_t gesture_han if (gesture_handle != GESTURE_HANDLE) return SCE_SYSTEM_GESTURE_ERROR_INVALID_HANDLE; if (!recognizer) return SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT; if (!rectangle) return SCE_SYSTEM_GESTURE_ERROR_INVALID_ARGUMENT; + RecognizerState state{}; + if (loadRecognizerState(recognizer, state)) { + state.hasRectangle = 1; + state.rectangle = *rectangle; + storeRecognizerState(recognizer, state); + } return 0; } diff --git a/core/libs/tests/GuestSystemGesture.cpp b/core/libs/tests/GuestSystemGesture.cpp index 037b9e885a..ee6e1d7e52 100644 --- a/core/libs/tests/GuestSystemGesture.cpp +++ b/core/libs/tests/GuestSystemGesture.cpp @@ -1,8 +1,12 @@ +#include "SceTypes.hpp" #include "prx/libc/include/general/VabiMacros.hpp" +#include #include #include #include +#include +#include extern "C" { std::int32_t APS5_VABI sceSystemGestureOpen(std::int32_t, const void*); @@ -11,6 +15,8 @@ int APS5_VABI sceSystemGestureGetPrimitiveTouchEventsCount(std::int32_t); int APS5_VABI sceSystemGestureGetTouchEvents(std::int32_t, const void*, void*, std::uint32_t, std::uint32_t*); int APS5_VABI sceSystemGestureGetPrimitiveTouchEventByIndex(std::int32_t, std::uint32_t, void*); int APS5_VABI sceSystemGestureAppendTouchRecognizer(std::int32_t, void*); +int APS5_VABI sceSystemGestureCreateTouchRecognizer(std::int32_t, void*, std::int32_t, const void*, const void*); +int APS5_VABI sceSystemGestureGetTouchRecognizerInformation(std::int32_t, const void*, void*); int APS5_VABI sceSystemGestureRemoveTouchRecognizer(std::int32_t, void*); int APS5_VABI sceSystemGestureResetTouchRecognizer(std::int32_t, void*); int APS5_VABI sceSystemGestureUpdateTouchRecognizer(std::int32_t, void*); @@ -22,6 +28,56 @@ int APS5_VABI sceSystemGestureUpdatePrimitiveTouchRecognizer(std::int32_t, const static void Require(bool value) { if (!value) std::abort(); } +static bool SameRectangle(const SystemGestureRectangle& left, const SystemGestureRectangle& right) { + return std::memcmp(&left, &right, sizeof(SystemGestureRectangle)) == 0; +} + +template +static bool Throws(TCall call) { + try { + call(); + } catch (const std::runtime_error&) { + return true; + } + return false; +} + +static void TestTouchRecognizerInformation(std::int32_t handle, int invalidArgument, int invalidHandle) { + constexpr std::int32_t gestureType = 2; + const SystemGestureRectangle area{10.0f, 20.0f, 300.0f, 400.0f, {}}; + const SystemGestureRectangle moved{40.0f, 50.0f, 60.0f, 70.0f, {}}; + + SystemGestureTouchRecognizer recognizer{}; + Require(sceSystemGestureCreateTouchRecognizer(handle, &recognizer, gestureType, &area, nullptr) == 0); + + SystemGestureTouchRecognizerInformation information; + std::memset(&information, 0x5a, sizeof(information)); + Require(sceSystemGestureGetTouchRecognizerInformation(handle, &recognizer, &information) == 0); + Require(information.gesture_type == gestureType); + Require(SameRectangle(information.rectangle, area)); + Require(information.updated_time == 0); + Require(std::all_of(std::begin(information.reserve), std::end(information.reserve), [](std::uint8_t value) { return value == 0x5a; })); + + Require(sceSystemGestureUpdateTouchRecognizerRectangle(handle, &recognizer, &moved) == 0); + Require(sceSystemGestureGetTouchRecognizerInformation(handle, &recognizer, &information) == 0); + Require(information.gesture_type == gestureType); + Require(SameRectangle(information.rectangle, moved)); + + Require(sceSystemGestureGetTouchRecognizerInformation(handle + 1, &recognizer, &information) == invalidHandle); + Require(sceSystemGestureGetTouchRecognizerInformation(handle, nullptr, &information) == invalidArgument); + Require(sceSystemGestureGetTouchRecognizerInformation(handle, &recognizer, nullptr) == invalidArgument); + + SystemGestureTouchRecognizer uncreated{}; + Require(Throws([&] { sceSystemGestureGetTouchRecognizerInformation(handle, &uncreated, &information); })); + + SystemGestureTouchRecognizer withoutRectangle{}; + Require(sceSystemGestureCreateTouchRecognizer(handle, &withoutRectangle, gestureType, nullptr, nullptr) == 0); + Require(Throws([&] { sceSystemGestureGetTouchRecognizerInformation(handle, &withoutRectangle, &information); })); + Require(sceSystemGestureUpdateTouchRecognizerRectangle(handle, &withoutRectangle, &area) == 0); + Require(sceSystemGestureGetTouchRecognizerInformation(handle, &withoutRectangle, &information) == 0); + Require(SameRectangle(information.rectangle, area)); +} + int main() { constexpr int invalidArgument = static_cast(0x80D10002); constexpr int invalidHandle = static_cast(0x80D10003); @@ -44,8 +100,8 @@ int main() { Require(sceSystemGestureGetPrimitiveTouchEventsCount(handle + 1) == invalidHandle); constexpr int indexOutOfArray = static_cast(0x80D10005); - int recognizer = 0; - int rectangle = 0; + SystemGestureTouchRecognizer recognizer{}; + SystemGestureRectangle rectangle{}; count = 7; Require(sceSystemGestureGetTouchEvents(handle, &recognizer, buffer.data(), 4, &count) == 0 && count == 0); Require(sceSystemGestureGetTouchEvents(handle, &recognizer, buffer.data(), 4, nullptr) == invalidArgument); @@ -76,5 +132,7 @@ int main() { Require(sceSystemGestureResetPrimitiveTouchRecognizer(handle + 1) == invalidHandle); Require(sceSystemGestureUpdateAllTouchRecognizer(handle + 1) == invalidHandle); Require(sceSystemGestureUpdatePrimitiveTouchRecognizer(handle + 1, nullptr) == invalidHandle); + + TestTouchRecognizerInformation(handle, invalidArgument, invalidHandle); return 0; } diff --git a/docs/dev/debt/libSceSystemGesture.md b/docs/dev/debt/libSceSystemGesture.md index 838de9ac99..98903ec7d4 100644 --- a/docs/dev/debt/libSceSystemGesture.md +++ b/docs/dev/debt/libSceSystemGesture.md @@ -2,4 +2,4 @@ ### Silent stubs -- [System gesture recognizers](../../../core/libs/prx/libSceSystemGesture/Export.cpp) (libSceSystemGesture) - `sceSystemGestureGetPrimitiveTouchEvents`, `GetPrimitiveTouchEventsCount`, `GetTouchEvents`, `GetPrimitiveTouchEventByIndex` and the recognizer append, remove, reset and update calls report that no touch input exists and keep no recognizer state, so a title never receives a gesture event. Handle and pointer arguments are still checked. Error codes follow the 0x80D1 values main already uses in this file; KytyPS5 uses 0x8089 (INVALID_ARGUMENT 0x80890001, INVALID_HANDLE 0x80890006), and which one the console returns is not verified +- [System gesture recognizers](../../../core/libs/prx/libSceSystemGesture/Export.cpp) (libSceSystemGesture) - `sceSystemGestureGetPrimitiveTouchEvents`, `GetPrimitiveTouchEventsCount`, `GetTouchEvents`, `GetPrimitiveTouchEventByIndex` and the recognizer append, remove, reset and update calls report that no touch input exists, so a title never receives a gesture event. Handle and pointer arguments are still checked. Error codes follow the 0x80D1 values main already uses in this file; KytyPS5 uses 0x8089 (INVALID_ARGUMENT 0x80890001, INVALID_HANDLE 0x80890006), and which one the console returns is not verified. `sceSystemGestureGetTouchRecognizerInformation` returns the gesture type and rectangle given to `sceSystemGestureCreateTouchRecognizer` or `UpdateTouchRecognizerRectangle`, stored in the title's recognizer buffer in a layout private to this file, and always reports `updated_time` 0 because no recognizer is ever updated with input. It throws for a recognizer that was not created by `sceSystemGestureCreateTouchRecognizer` or has no rectangle, since the console's result in those cases is not known