From 77600dcb87efdf8ca223a5bbb7f4e6ce445ef642 Mon Sep 17 00:00:00 2001 From: milescoviello Date: Wed, 28 Oct 2026 03:54:25 +0000 Subject: [PATCH] test(libScePad): cover the trigger commands scePadSetTriggerEffect stores Seven of the titles here import scePadSetTriggerEffect and no test reaches it. Pin the requests it leaves in the port's output state: a weapon and a feedback command as their DualSense effect bytes and fallback strengths, the trigger mask leaving the other trigger as it was, an off command, and a special handle leaving the output alone. Co-Authored-By: Claude Opus 5.5 --- core/libs/tests/GuestPad.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core/libs/tests/GuestPad.cpp b/core/libs/tests/GuestPad.cpp index ca20015351..3e5501d7d9 100644 --- a/core/libs/tests/GuestPad.cpp +++ b/core/libs/tests/GuestPad.cpp @@ -3,6 +3,7 @@ #include "prx/libScePad/include/PadState.hpp" #include "prx/libScePad/include/InputCommandFile.hpp" #include "prx/libc/include/general/VabiMacros.hpp" +#include #include #include #include @@ -559,6 +560,38 @@ static void CheckVibrationForce(int user, int handle) { Require(scePadSetVibrationForce(handle, &off) == PAD_OK && VibrationIs(0, 0, 0)); } +static bool TriggerIs(int trigger, bool valid, std::uint32_t mode, const std::array& effect, std::uint8_t fallback) { + const PadOutputState output = OutputOf(0); + const PadTriggerRequest& request = output.trigger[trigger]; + return request.valid == valid && request.mode == mode && std::memcmp(request.effect, effect.data(), effect.size()) == 0 && request.fallback == fallback; +} + +static void CheckTriggerEffect(int user, int handle) { + std::array param{}; + const auto command = [&](int trigger, std::uint32_t mode, const std::array& data) { + std::memcpy(param.data() + 8 + 56 * trigger, &mode, sizeof(mode)); + std::copy(data.begin(), data.end(), param.begin() + 16 + 56 * trigger); + }; + const std::array weapon{0x25, 0x24, 0x00, 0x07}; + const std::array feedback{0x21, 0x80, 0x03, 0x00, 0x00, 0x40, 0x12}; + const std::array off{0x05}; + command(0, 2, {2, 5, 8}); + command(1, 1, {7, 3, 0}); + param[0] = 0x1; + Require(scePadSetTriggerEffect(handle, param.data()) == PAD_OK && TriggerIs(0, true, 2, weapon, 255) && TriggerIs(1, false, 0, {}, 0)); + command(0, 0, {0, 0, 0}); + param[0] = 0x2; + Require(scePadSetTriggerEffect(handle, param.data()) == PAD_OK && TriggerIs(0, true, 2, weapon, 255) && TriggerIs(1, true, 1, feedback, 96)); + command(1, 0, {0, 0, 0}); + param[0] = 0x3; + Require(scePadSetTriggerEffect(handle, param.data()) == PAD_OK && TriggerIs(0, false, 0, off, 0) && TriggerIs(1, false, 0, off, 0)); + const int special = scePadOpen_nid_postfix(user, PAD_PORT_TYPE_SPECIAL, 0, nullptr); + Require(special >= PAD_SPECIAL_HANDLE); + command(0, 2, {2, 5, 8}); + Require(scePadSetTriggerEffect(special, param.data()) == PAD_OK && TriggerIs(0, false, 0, off, 0)); + Require(scePadClose_nid_postfix(special) == PAD_OK); +} + static void CheckAccessibilityControllerState(int handle) { std::uint32_t state = 7; Require(scePadGetAccessibilityControllerState(handle + 1, nullptr) == PAD_ERROR_INVALID_ARG); @@ -783,6 +816,7 @@ int main() { CheckIsValidHandle(user, handle); CheckLightBarResets(user, handle); CheckVibrationForce(user, handle); + CheckTriggerEffect(user, handle); CheckControllerType(handle); CheckInjectedState(commandPath); CheckInjectedQueueTimes(commandPath);