Merge pull request #1076 from TideOPL/fix/pad-read-debt-note
fix(libScePad): queue input states for scePadRead
This commit is contained in:
commit
7feed2748a
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue