Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 41 additions & 25 deletions core/libs/prx/libScePad/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ constexpr int PAD_ERROR_UNKNOWN_USER = static_cast<int>(0x809b0081);
constexpr int PAD_ERROR_INVALID_USER_ID = static_cast<int>(0x809b0001);
constexpr int PAD_ERROR_INVALID_PORT_INDEX = static_cast<int>(0x809b0003);
constexpr int PAD_USER_ID_INVALID = -1;
constexpr int PAD_MAX_READ_COUNT = 64;

std::array<bool, PAD_MAX_CONTROLLERS> g_opened{false};
std::array<bool, PAD_MAX_CONTROLLERS> g_everOpened{false};
Expand Down Expand Up @@ -67,12 +68,11 @@ bool KnownHandle(int handle) {
return PortOf(handle) >= 0 || SpecialHandle(handle);
}

PadData SpecialData() {
PadData data{};
data.left_stick_x = data.left_stick_y = data.right_stick_x = data.right_stick_y = 0x80;
data.orientation_w = 1.0f;
data.acceleration_y = 1.0f;
return data;
void WriteRestData(PadData* data) {
std::memset(data, 0, sizeof(*data));
data->left_stick_x = data->left_stick_y = data->right_stick_x = data->right_stick_y = 0x80;
data->orientation_w = 1.0f;
data->acceleration_y = 1.0f;
}

bool SystemRemote(int userId, int type) {
Expand Down Expand Up @@ -138,30 +138,32 @@ int APS5_VABI scePadVrControllerReadCombinedState(std::int32_t leftHandle, std::
}

int APS5_VABI scePadDeviceClassGetExtendedInformation(int handle, PadDeviceClassExtendedInformation* info) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (info == nullptr) return PAD_ERROR_INVALID_ARG;
std::memset(info, 0, sizeof(*info));
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
info->deviceClass = SpecialHandle(handle) ? -1 : PAD_DEVICE_CLASS_STANDARD;
return PAD_OK;
}

int APS5_VABI scePadDeviceClassParseData(int handle, const PadData* data, PadDeviceClassData* class_data) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (data == nullptr || class_data == nullptr) return PAD_ERROR_INVALID_ARG;
std::memset(class_data, 0, sizeof(*class_data));
if (!KnownHandle(handle)) {
class_data->deviceClass = -1;
return PAD_ERROR_INVALID_HANDLE;
}
if (SpecialHandle(handle)) return PAD_OK;
class_data->deviceClass = PAD_DEVICE_CLASS_STANDARD;
class_data->dataValid = data->connected;
return PAD_OK;
}

int APS5_VABI scePadGetControllerInformation(int handle, PadControllerInformation* info) {
if (!KnownHandle(handle)) {
return PAD_ERROR_INVALID_HANDLE;
}
if (info == nullptr) {
return PAD_ERROR_INVALID_ARG;
}
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (info == nullptr) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
std::memset(info, 0, sizeof(*info));
if (SpecialHandle(handle)) return PAD_OK;
info->touchPadInfo.pixelDensity = 44.86f;
Expand Down Expand Up @@ -307,74 +309,86 @@ int APS5_VABI scePadSetFeatureReport(std::int32_t handle, std::uint8_t reportId,
int APS5_VABI scePadOutputReport(std::int32_t handle, std::uint8_t reportId, const void* data, std::uint64_t size) { NotImplemented_nid_no_patch(__func__); return 0; }

int APS5_VABI scePadRead_nid_postfix(int handle, PadData* data, int num) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (data == nullptr || num <= 0 || num > PAD_MAX_READ_COUNT) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle) && !RemoteHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (data == nullptr || num <= 0) return PAD_ERROR_INVALID_ARG;
if (RemoteHandle(handle)) {
data[0] = PadData{};
return 1;
}
if (SpecialHandle(handle)) {
data[0] = SpecialData();
WriteRestData(data);
return 1;
}
return Pad::Read(data, num, PortOf(handle));
}

int APS5_VABI scePadReadState(int handle, PadData* data) {
if (!KnownHandle(handle) && !RemoteHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (data == nullptr) return PAD_ERROR_INVALID_ARG;

*data = RemoteHandle(handle) ? PadData{} : SpecialHandle(handle) ? SpecialData() : Pad::ReadState(PortOf(handle));

return 0;
const bool initialized = Pad::IsInitialized();
if (!initialized || (!KnownHandle(handle) && !RemoteHandle(handle))) {
WriteRestData(data);
return initialized ? PAD_ERROR_INVALID_HANDLE : PAD_ERROR_NOT_INITIALIZED;
}
if (RemoteHandle(handle)) *data = PadData{};
else if (SpecialHandle(handle)) WriteRestData(data);
else *data = Pad::ReadState(PortOf(handle));
return PAD_OK;
}

int APS5_VABI scePadResetLightBar(int handle) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetLightBar(PortOf(handle), false, 0, 0, 0);
return PAD_OK;
}

int APS5_VABI scePadResetOrientation(int handle) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::ResetOrientation(PortOf(handle));
return PAD_OK;
}

int APS5_VABI scePadSetAngularVelocityDeadbandState(int handle, bool enable) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetAngularVelocityDeadband(PortOf(handle), enable);
return PAD_OK;
}

int APS5_VABI scePadSetLightBar(int handle, const PadLightBarParam* param) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (param == nullptr) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetLightBar(PortOf(handle), true, param->r, param->g, param->b);
return PAD_OK;
}

int APS5_VABI scePadSetMotionSensorState(int handle, bool enable) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetMotionEnabled(PortOf(handle), enable);
return PAD_OK;
}

int APS5_VABI scePadSetTiltCorrectionState(int handle, bool enabled) {
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetTiltCorrection(PortOf(handle), enabled);
return PAD_OK;
}

int APS5_VABI scePadSetTriggerEffect(int handle, const void* param) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (param == nullptr) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
const std::uint8_t* bytes = static_cast<const std::uint8_t*>(param);
const std::uint8_t mask = bytes[0];
Expand All @@ -394,8 +408,9 @@ int APS5_VABI scePadSetTriggerEffect(int handle, const void* param) {
}

int APS5_VABI scePadSetVibration(int handle, const PadVibrationParam* param) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (param == nullptr) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (SpecialHandle(handle)) return PAD_OK;
Pad::SetVibration(PortOf(handle), param->large_motor, param->small_motor);
return PAD_OK;
Expand Down Expand Up @@ -449,8 +464,9 @@ int APS5_VABI scePadVrControllerSetTriggerEffects(std::int32_t leftHandle, std::
}

int APS5_VABI scePadIsRemoteController(int handle, bool* remote) {
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
if (!Pad::IsInitialized()) return PAD_ERROR_NOT_INITIALIZED;
if (remote == nullptr) return PAD_ERROR_INVALID_ARG;
if (!KnownHandle(handle)) return PAD_ERROR_INVALID_HANDLE;
*remote = false;
return 0;
}
Expand Down
82 changes: 82 additions & 0 deletions core/libs/tests/GuestPad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,86 @@ static void CheckReadStateHandle(int handle) {
Require(scePadReadState(handle, nullptr) == PAD_ERROR_INVALID_ARG);
}

static void RequireRestData(const PadData& data) {
Require(data.buttons == 0 && data.left_stick_x == 0x80 && data.left_stick_y == 0x80 && data.right_stick_x == 0x80 && data.right_stick_y == 0x80);
Require(data.analog_buttons_l2 == 0 && data.analog_buttons_r2 == 0 && data.padding[0] == 0 && data.padding[1] == 0);
Require(data.orientation_x == 0.0f && data.orientation_y == 0.0f && data.orientation_z == 0.0f && data.orientation_w == 1.0f);
Require(data.acceleration_x == 0.0f && data.acceleration_y == 1.0f && data.acceleration_z == 0.0f);
Require(data.angular_velocity_x == 0.0f && data.angular_velocity_y == 0.0f && data.angular_velocity_z == 0.0f);
Require(data.touch_data_touch_num == 0 && !data.connected && data.timestamp == 0 && data.connected_count == 0 && data.device_unique_data_len == 0);
}

static void CheckBeforeInit() {
PadData data;
std::memset(&data, 0x5a, sizeof(data));
Require(scePadReadState(PAD_HANDLE, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadReadState(PAD_HANDLE, &data) == PAD_ERROR_NOT_INITIALIZED);
RequireRestData(data);
Require(scePadRead_nid_postfix(PAD_HANDLE, nullptr, 1) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadRead_nid_postfix(PAD_HANDLE, &data, 0) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadRead_nid_postfix(PAD_HANDLE, &data, 65) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadGetControllerInformation(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetLightBar(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadResetLightBar(PAD_HANDLE) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetVibration(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadResetOrientation(PAD_HANDLE) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetMotionSensorState(PAD_HANDLE, true) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetTiltCorrectionState(PAD_HANDLE, true) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetAngularVelocityDeadbandState(PAD_HANDLE, true) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadSetTriggerEffect(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
bool remote = true;
Require(scePadIsRemoteController(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadIsRemoteController(PAD_HANDLE, &remote) == PAD_ERROR_NOT_INITIALIZED);
Require(remote);
PadDeviceClassExtendedInformation extended;
std::memset(&extended, 0x5a, sizeof(extended));
Require(scePadDeviceClassGetExtendedInformation(PAD_HANDLE, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadDeviceClassGetExtendedInformation(PAD_HANDLE, &extended) == PAD_ERROR_NOT_INITIALIZED);
Require(extended.reserved[0] == 0x5a);
PadDeviceClassData classData;
std::memset(&classData, 0x5a, sizeof(classData));
Require(scePadDeviceClassParseData(PAD_HANDLE, &data, nullptr) == PAD_ERROR_NOT_INITIALIZED);
Require(scePadDeviceClassParseData(PAD_HANDLE, &data, &classData) == PAD_ERROR_NOT_INITIALIZED);
Require(classData.pad[0] == 0x5a);
}

static void CheckBadHandleArguments(int handle) {
static PadData data[65];
for (const int bad : {0, -1, 0x7fffffff}) {
Require(scePadRead_nid_postfix(bad, nullptr, 1) == PAD_ERROR_INVALID_ARG);
Require(scePadRead_nid_postfix(bad, data, 0) == PAD_ERROR_INVALID_ARG);
Require(scePadRead_nid_postfix(bad, data, -1) == PAD_ERROR_INVALID_ARG);
Require(scePadRead_nid_postfix(bad, data, 65) == PAD_ERROR_INVALID_ARG);
Require(scePadRead_nid_postfix(bad, data, 64) == PAD_ERROR_INVALID_HANDLE);
Require(scePadReadState(bad, nullptr) == PAD_ERROR_INVALID_ARG);
std::memset(data, 0x5a, sizeof(data[0]));
Require(scePadReadState(bad, data) == PAD_ERROR_INVALID_HANDLE);
RequireRestData(data[0]);
PadControllerInformation info;
std::memset(&info, 0x5a, sizeof(info));
Require(scePadGetControllerInformation(bad, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadGetControllerInformation(bad, &info) == PAD_ERROR_INVALID_HANDLE);
Require(info.connectedCount == 0x5a);
Require(scePadSetLightBar(bad, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadSetVibration(bad, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadSetTriggerEffect(bad, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadIsRemoteController(bad, nullptr) == PAD_ERROR_INVALID_ARG);
PadDeviceClassExtendedInformation extended;
std::memset(&extended, 0x5a, sizeof(extended));
Require(scePadDeviceClassGetExtendedInformation(bad, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadDeviceClassGetExtendedInformation(bad, &extended) == PAD_ERROR_INVALID_HANDLE);
Require(extended.deviceClass == 0 && extended.reserved[0] == 0 && extended.reserved[3] == 0 && extended.classData.data[11] == 0);
PadDeviceClassData classData;
std::memset(&classData, 0x5a, sizeof(classData));
Require(scePadDeviceClassParseData(bad, nullptr, &classData) == PAD_ERROR_INVALID_ARG);
Require(scePadDeviceClassParseData(bad, data, nullptr) == PAD_ERROR_INVALID_ARG);
Require(scePadDeviceClassParseData(bad, data, &classData) == PAD_ERROR_INVALID_HANDLE);
Require(classData.deviceClass == -1 && !classData.dataValid && classData.pad[2] == 0 && classData.classData.data[15] == 0);
}
Require(scePadRead_nid_postfix(handle, data, 65) == PAD_ERROR_INVALID_ARG);
Require(scePadRead_nid_postfix(handle, data, 64) >= 0);
}

static void CheckSpecialPort(int user, int handle) {
constexpr int noHandle = static_cast<int>(0x80920008);
constexpr int alreadyOpened = static_cast<int>(0x80920004);
Expand Down Expand Up @@ -588,6 +668,7 @@ int main() {
Require(scePadGetControllerType(PAD_HANDLE, &controllerType) == PAD_ERROR_NOT_INITIALIZED);
Require(controllerType == -1);
Require(scePadUnknown_n3kSX62fgNo() == static_cast<int>(0x80920005));
CheckBeforeInit();
const auto path = std::filesystem::temp_directory_path() / ("anyps5-pad-state-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
struct Cleanup {
std::filesystem::path path;
Expand Down Expand Up @@ -672,6 +753,7 @@ int main() {
CheckLatchedPressAtSlowReads(handle);
CheckLatchedPressPerPort();
CheckReadStateHandle(handle);
CheckBadHandleArguments(handle);
CheckRemoteController(handle);
CheckTrackerDevices(handle);
CheckAccessibilityControllerState(handle);
Expand Down
Loading