Merge pull request #1076 from TideOPL/fix/pad-read-debt-note

fix(libScePad): queue input states for scePadRead
This commit is contained in:
Adrià 2026-10-11 10:49:44 +02:00 committed by GitHub
commit 7feed2748a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 62 additions and 13 deletions

View File

@ -156,14 +156,10 @@ int APS5_VABI scePadSetFeatureReport() { NotImplemented_nid_no_patch(__func__);
int APS5_VABI scePadOutputReport() { NotImplemented_nid_no_patch(__func__); return 0; }
int APS5_VABI scePadReadState(int handle, PadData* data);
int APS5_VABI scePadRead_nid_postfix(int handle, PadData* data, int num) {
// The title drains the queued states; one current state is reported per call.
if (data == nullptr || num <= 0) APS5_INVALID_ARG_EX;
const int result = scePadReadState(handle, data);
if (result != 0) return result;
return 1;
if (handle != PAD_HANDLE) return PAD_ERROR_INVALID_HANDLE;
if (data == nullptr || num <= 0) APS5_INVALID_ARG_EX;
return Pad::Read(data, num);
}
int APS5_VABI scePadReadState(int handle, PadData* data) {

View File

@ -51,6 +51,7 @@ struct PadOutputState {
namespace Pad {
void Initialize();
PadData ReadState();
int Read(PadData* data, int num);
void SetVibration(std::uint8_t large, std::uint8_t small);
void SetVibrationMode(int mode);
void SetLightBar(bool valid, std::uint8_t r, std::uint8_t g, std::uint8_t b);

View File

@ -4,6 +4,7 @@
#include <algorithm>
#include <cmath>
#include <cstring>
#include <deque>
#include <mutex>
#include <stdexcept>
@ -12,6 +13,13 @@ namespace {
PadInputState state;
PadOutputState output;
std::uint64_t timestamp = 0;
struct QueuedInput {
PadInputState input;
std::uint64_t timestamp = 0;
};
constexpr std::size_t kQueueCapacity = 64;
std::deque<QueuedInput> queue;
std::exception_ptr failure;
bool initialized = false;
@ -93,15 +101,13 @@ void Pad::Initialize() {
if (!initialized) {
timestamp = sceKernelGetProcessTime();
lastFuseTime = timestamp;
queue.clear();
}
initialized = true;
}
PadData Pad::ReadState() {
std::lock_guard lock(stateMutex);
if (failure) std::rethrow_exception(failure);
if (!initialized) throw std::runtime_error("Pad: read before initialization");
const std::uint64_t now = sceKernelGetProcessTime();
namespace {
PadData BuildData(const PadInputState& state, std::uint64_t changeTime, std::uint64_t now) {
PadData data{};
data.buttons = state.buttons;
data.left_stick_x = state.sticks[0];
@ -138,7 +144,7 @@ PadData Pad::ReadState() {
data.connected = true;
data.connected_count = 1;
data.timestamp = timestamp;
data.timestamp = changeTime;
std::uint8_t touchNum = 0;
for (int i = 0; i < 2; ++i) {
@ -163,6 +169,33 @@ PadData Pad::ReadState() {
data.touch_data_touch_num = touchNum;
return data;
}
}
PadData Pad::ReadState() {
std::lock_guard lock(stateMutex);
if (failure) std::rethrow_exception(failure);
if (!initialized) throw std::runtime_error("Pad: read before initialization");
return BuildData(state, timestamp, sceKernelGetProcessTime());
}
int Pad::Read(PadData* data, int num) {
if (data == nullptr || num <= 0) throw std::invalid_argument("Pad: invalid read buffer");
std::lock_guard lock(stateMutex);
if (failure) std::rethrow_exception(failure);
if (!initialized) throw std::runtime_error("Pad: read before initialization");
const std::uint64_t now = sceKernelGetProcessTime();
if (queue.empty()) {
data[0] = BuildData(state, timestamp, now);
return 1;
}
int count = 0;
while (count < num && !queue.empty()) {
const QueuedInput& entry = queue.front();
data[count++] = BuildData(entry.input, entry.timestamp, now);
queue.pop_front();
}
return count;
}
void Pad::SetVibration(std::uint8_t large, std::uint8_t small) {
std::lock_guard lock(stateMutex);
@ -280,6 +313,8 @@ extern "C" void PadPublishInput_nid_postfix(const PadInputState& input) {
state.touch == input.touch && state.deviceKind == input.deviceKind) return;
state = input;
timestamp = sceKernelGetProcessTime();
if (queue.size() == kQueueCapacity) queue.pop_front();
queue.push_back({input, timestamp});
}
extern "C" void PadReportInputFailure_nid_postfix(std::exception_ptr error) {

View File

@ -63,6 +63,22 @@ static void CheckTouchContact() {
Pad::ReadState();
}
static void CheckReadQueue(int handle) {
PadData drained[64]{};
scePadRead_nid_postfix(handle, drained, 64);
PadInputState pressed;
pressed.buttons = static_cast<std::uint32_t>(Pad::PadButton::Cross);
PadPublishInput_nid_postfix(pressed);
PadPublishInput_nid_postfix(PadInputState{});
PadData data[4]{};
Require(scePadRead_nid_postfix(handle, data, 4) == 2);
Require((data[0].buttons & pressed.buttons) != 0);
Require((data[1].buttons & pressed.buttons) == 0);
Require(data[0].timestamp <= data[1].timestamp);
Require(scePadRead_nid_postfix(handle, data, 4) == 1);
Require(data[0].buttons == 0);
}
static void CheckReadStateHandle(int handle) {
PadData data{};
Require(scePadReadState(0, &data) == PAD_ERROR_INVALID_HANDLE);
@ -99,6 +115,7 @@ int main() {
Require(scePadGetHandle(user, 2, 0) == handle);
CheckTiltCorrection(handle);
CheckTouchContact();
CheckReadQueue(handle);
CheckReadStateHandle(handle);
CheckRemoteController(handle);
Require(scePadSetVibrationMode(handle, 1) == 0);