From 1d115b8962a40ae404e45c0e3c37aebbe6831f68 Mon Sep 17 00:00:00 2001 From: p3nicillin Date: Mon, 12 Oct 2026 22:29:57 +0100 Subject: [PATCH] feat(libScePad): apply the angular velocity deadband Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libScePad/Export.cpp | 2 +- core/libs/prx/libScePad/include/PadState.hpp | 1 + core/libs/prx/libScePad/src/PadState.cpp | 14 +++++++++++++- core/libs/tests/GuestPad.cpp | 20 ++++++++++++++++++++ docs/dev/debt/libScePad.md | 1 + 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libScePad/Export.cpp b/core/libs/prx/libScePad/Export.cpp index cba221154..2cf60908b 100644 --- a/core/libs/prx/libScePad/Export.cpp +++ b/core/libs/prx/libScePad/Export.cpp @@ -201,7 +201,7 @@ int APS5_VABI scePadResetOrientation(int handle) { int APS5_VABI scePadSetAngularVelocityDeadbandState(int handle, bool enable) { if (handle != PAD_HANDLE) return PAD_ERROR_INVALID_HANDLE; - if (enable) NotImplemented_nid_no_patch(__func__); + Pad::SetAngularVelocityDeadband(enable); return PAD_OK; } diff --git a/core/libs/prx/libScePad/include/PadState.hpp b/core/libs/prx/libScePad/include/PadState.hpp index 8100e33c5..d38385a70 100644 --- a/core/libs/prx/libScePad/include/PadState.hpp +++ b/core/libs/prx/libScePad/include/PadState.hpp @@ -59,6 +59,7 @@ void SetTriggerCommand(int trigger, const std::uint8_t* command); void ResetOrientation(); void SetMotionEnabled(bool enabled); void SetTiltCorrection(bool enabled); +void SetAngularVelocityDeadband(bool enabled); } extern "C" void PadPublishInput_nid_postfix(const PadInputState& input); diff --git a/core/libs/prx/libScePad/src/PadState.cpp b/core/libs/prx/libScePad/src/PadState.cpp index 9d8adf4c3..2ab3f126c 100644 --- a/core/libs/prx/libScePad/src/PadState.cpp +++ b/core/libs/prx/libScePad/src/PadState.cpp @@ -30,6 +30,8 @@ namespace { std::uint64_t lastFuseTime = 0; float biasIntegral[3] = {0.0f, 0.0f, 0.0f}; bool tiltCorrection = true; + bool angularVelocityDeadband = false; + constexpr float kAngularVelocityDeadband = 0.017453292f; std::uint8_t nextTouchId = 0; bool prevTouchActive[2] = {false, false}; std::uint8_t touchIds[2] = {0, 0}; @@ -126,7 +128,12 @@ PadData BuildData(const PadInputState& state, std::uint64_t changeTime, std::uin const bool live = state.hasMotion && output.motionEnabled; const std::array rest{0.0f, 9.80665f, 0.0f}; const std::array& accel = live ? state.accel : rest; - const std::array gyro = live ? state.gyro : std::array{0.0f, 0.0f, 0.0f}; + std::array gyro = live ? state.gyro : std::array{0.0f, 0.0f, 0.0f}; + if (angularVelocityDeadband) { + for (float& axis : gyro) { + if (axis < kAngularVelocityDeadband && axis > -kAngularVelocityDeadband) axis = 0.0f; + } + } if (live) { float dt = lastFuseTime != 0 && now > lastFuseTime ? static_cast(now - lastFuseTime) * 1e-6f : 0.0f; dt = std::min(dt, 0.1f); @@ -316,6 +323,11 @@ void Pad::SetTiltCorrection(bool enabled) { biasIntegral[0] = biasIntegral[1] = biasIntegral[2] = 0.0f; } +void Pad::SetAngularVelocityDeadband(bool enabled) { + std::lock_guard lock(stateMutex); + angularVelocityDeadband = enabled; +} + void Pad::SetMotionEnabled(bool enabled) { std::lock_guard lock(stateMutex); if (output.motionEnabled == enabled) return; diff --git a/core/libs/tests/GuestPad.cpp b/core/libs/tests/GuestPad.cpp index 4eb1d8b0b..9fa2e91b4 100644 --- a/core/libs/tests/GuestPad.cpp +++ b/core/libs/tests/GuestPad.cpp @@ -113,6 +113,24 @@ static void CheckTiltCorrection(int handle) { PadPublishInput_nid_postfix(PadInputState{}); } +static void CheckAngularVelocityDeadband(int handle) { + PadInputState moving; + moving.hasMotion = true; + moving.accel = {0.0f, 9.80665f, 0.0f}; + moving.gyro = {0.01f, 0.0175f, -0.017f}; + PadPublishInput_nid_postfix(moving); + PadData data{}; + Require(scePadReadState(handle, &data) == PAD_OK); + Require(data.angular_velocity_x == 0.01f && data.angular_velocity_y == 0.0175f && data.angular_velocity_z == -0.017f); + Require(scePadSetAngularVelocityDeadbandState(handle, true) == PAD_OK); + Require(scePadReadState(handle, &data) == PAD_OK); + Require(data.angular_velocity_x == 0.0f && data.angular_velocity_y == 0.0175f && data.angular_velocity_z == 0.0f); + Require(scePadSetAngularVelocityDeadbandState(handle, false) == PAD_OK); + Require(scePadReadState(handle, &data) == PAD_OK); + Require(data.angular_velocity_x == 0.01f && data.angular_velocity_z == -0.017f); + PadPublishInput_nid_postfix(PadInputState{}); +} + static void CheckTouchContact() { PadInputState touch; touch.buttons = static_cast(Pad::PadButton::TouchPad); @@ -253,6 +271,7 @@ int main() { Require(scePadGetHandle(user, PAD_PORT_TYPE_SPECIAL, 0) == noHandle); Require(scePadGetHandle(user, 0, 0) == handle); CheckTiltCorrection(handle); + CheckAngularVelocityDeadband(handle); CheckTouchContact(); CheckPartialTrigger(); CheckReadQueue(handle); @@ -272,6 +291,7 @@ int main() { Require(scePadSetVibrationTriggerEffectWeakWhileEmbeddedMicInUse(true) == 0); Require(scePadSetAngularVelocityDeadbandState(handle, false) == 0); Require(scePadSetAngularVelocityDeadbandState(handle + 1, false) == PAD_ERROR_INVALID_HANDLE); + Require(scePadSetAngularVelocityDeadbandState(handle + 1, true) == PAD_ERROR_INVALID_HANDLE); Require(scePadSetAngularVelocityBiasCorrectionState(handle, false) == PAD_OK); Require(scePadSetAngularVelocityBiasCorrectionState(handle + 1, false) == PAD_ERROR_INVALID_HANDLE); } diff --git a/docs/dev/debt/libScePad.md b/docs/dev/debt/libScePad.md index 975723bfc..8cfd5341d 100644 --- a/docs/dev/debt/libScePad.md +++ b/docs/dev/debt/libScePad.md @@ -2,6 +2,7 @@ ### Unknown function info +- [scePadSetAngularVelocityDeadbandState](../../../core/libs/prx/libScePad/src/PadState.cpp) (libScePad) - with the deadband on, each angular velocity axis whose magnitude is below 0.017453292 rad/s (1 degree per second) reads as 0, before the orientation is integrated; it starts off. Threshold, per-axis test and default follow [duaLib](https://github.com/WujekFoliarz/duaLib/blob/03bad1bea2a36561b520846776f2a07ced6773e0/src/source/duaLib.cpp#L44), which reimplements the PC `libScePad.dll`; the console's threshold is not measured, and the deadband is kept per library rather than per handle since one pad handle exists - [scePadOpen and scePadOpenExt](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - special ports (type 2) return `DEVICE_NOT_CONNECTED` (0x80920007) because the host has no special controller, and `scePadGetHandle` has no handle for them; whether the console opens a handle and reports the device as disconnected later is unknown. scePadOpenExt handles only special ports. PPSA01317 passes a 16-byte param that names the device by vendor and product id (`b7 0e 04 0e ...` for 0x0eb7:0x0e04) and skips the user on any negative result. Other port types throw - [scePadVrControllerReadState](../../../core/libs/prx/libScePad/Export.cpp) (libScePad, NID `iA-DdobUen8`) - the name hashes to the imported NID; the `(int handle, void* state)` signature follows [PS5VR](https://github.com/theghostonline/PS5VR/blob/0e408909ce7a39891a2e06eee3438d07a09e11e3/app/src/app_vr.c#L326-L369) (PPSA99177), which passes a PS VR2 Sense controller handle from `scePadOpen` type 3 or 4 and a 0x68-byte state it reads as buttons at 0, stick bytes at 4 and a connected byte at 0x40. The title calls it only after `sceHmd2Initialize` succeeds, which it does not here, so every call throws; the state layout is otherwise unknown - [scePadSetVibrationMode](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - modes 0 to 3 are accepted and stored; the meaning of mode 3 is unknown (PPSA21480 calls it with 3 right after `scePadOpen` and aborts on failure; [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Pad/Pad.cs) names only 1 and 2). The stored mode has no other effect