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