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 <[email protected]>
This commit is contained in:
milescovielloandClaude Opus 5.5 committed 2026-10-28 04:28:40 +00:00
1 parent 82d5f01f28
commit 77600dcb87
1 file changed
+34
+34
View File
@@ -3,6 +3,7 @@
#include "prx/libScePad/include/PadState.hpp"
#include "prx/libScePad/include/InputCommandFile.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <algorithm>
#include <array>
#include <chrono>
#include <cstdlib>
@@ -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<std::uint8_t, 11>& 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<std::uint8_t, 120> param{};
const auto command = [&](int trigger, std::uint32_t mode, const std::array<std::uint8_t, 3>& 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<std::uint8_t, 11> weapon{0x25, 0x24, 0x00, 0x07};
const std::array<std::uint8_t, 11> feedback{0x21, 0x80, 0x03, 0x00, 0x00, 0x40, 0x12};
const std::array<std::uint8_t, 11> 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);