eden-miror/.patch/sdl3/0002-ps4-joystick-driver.patch
2026-06-29 23:11:00 +00:00

393 lines
12 KiB
Diff

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b0eeca8..171fb9c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3655,15 +3655,18 @@ if (PLATFORM_PS4)
"${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysrwlock.c" # Can be faked, if necessary
"${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c"
"${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syssem.c"
+ "${SDL3_SOURCE_DIR}/src/joystick/ps4/SDL_sysjoystick.c"
)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c")
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c")
set(HAVE_SDL_THREADS TRUE)
set(HAVE_SDL_TIMERS TRUE)
set(HAVE_SDL_TIME TRUE)
+ set(HAVE_SDL_JOYSTICK TRUE)
set(SDL_TIME_UNIX 1)
set(SDL_TIMER_UNIX 1)
set(SDL_THREAD_PTHREAD 1)
+ set(SDL_JOYSTICK_PS4 1)
endif ()
# We always need to have threads and timers around
diff --git a/build-scripts/rename_macros.py b/build-scripts/rename_macros.py
index b6063dd..363f4d4 100755
--- a/build-scripts/rename_macros.py
+++ b/build-scripts/rename_macros.py
@@ -236,6 +236,7 @@ DEPRECATED_PLATFORM_MACROS = {
"SDL_JOYSTICK_N3DS",
"SDL_JOYSTICK_OS2",
"SDL_JOYSTICK_PS2",
+ "SDL_JOYSTICK_PS4",
"SDL_JOYSTICK_PSP",
"SDL_JOYSTICK_RAWINPUT",
"SDL_JOYSTICK_USBHID",
diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake
index 520b721..087d91b 100644
--- a/include/build_config/SDL_build_config.h.cmake
+++ b/include/build_config/SDL_build_config.h.cmake
@@ -313,6 +313,7 @@
#cmakedefine SDL_JOYSTICK_MFI 1
#cmakedefine SDL_JOYSTICK_N3DS 1
#cmakedefine SDL_JOYSTICK_PS2 1
+#cmakedefine SDL_JOYSTICK_PS4 1
#cmakedefine SDL_JOYSTICK_PSP 1
#cmakedefine SDL_JOYSTICK_RAWINPUT 1
#cmakedefine SDL_JOYSTICK_USBHID 1
diff --git a/src/joystick/ps4/SDL_sysjoystick.c b/src/joystick/ps4/SDL_sysjoystick.c
new file mode 100644
index 0000000..bd67ef6
--- /dev/null
+++ b/src/joystick/ps4/SDL_sysjoystick.c
@@ -0,0 +1,339 @@
+/*
+Simple DirectMedia Layer
+Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef __INTELLISENSE__
+#define SDL_JOYSTICK_PS4 1
+#endif
+
+#if SDL_JOYSTICK_PS4
+
+/* This is the PSP implementation of the SDL joystick API */
+#include <orbis/Pad.h>
+#include <orbis/UserService.h>
+#include <orbis/libkernel.h>
+
+#include <stdio.h> /* For the definition of NULL */
+#include <stdlib.h>
+
+#include "../SDL_sysjoystick.h"
+#include "../SDL_joystick_c.h"
+
+// #include "SDL_events.h"
+// #include "SDL_error.h"
+// #include "SDL_mutex.h"
+// #include "SDL_timer.h"
+#include "../../thread/SDL_systhread.h"
+
+#define MAX_PADS 4
+#define DS4_BTN_COUNT 20
+#define DS4_AXE_COUNT 6 // lsX/Y, rsX/Y, L2, R2
+#define DS4_HAT_COUNT 1
+
+uint32_t nPads = 0;
+
+OrbisUserServiceUserId userId, pad_users[MAX_PADS];
+OrbisUserServiceLoginUserIdList userIdList;
+
+int PS4_JoystickGetCount(void)
+{
+ return nPads;
+}
+
+void PS4_JoystickDetect(void)
+{
+ if(ORBIS_OK != sceUserServiceGetLoginUserIdList(&userIdList)) {
+ printf("WARNING, sceUserServiceGetLoginUserIdList() failed for JoystickDetect()!\n");
+ }
+
+ nPads = 0;
+ for (int i = 0; i < ORBIS_USER_SERVICE_MAX_LOGIN_USERS; i++) {
+ userId = userIdList.userId[i];
+ if (ORBIS_USER_SERVICE_USER_ID_INVALID != userId) {
+ int32_t handle = scePadOpen(userId, ORBIS_PAD_PORT_TYPE_STANDARD, 0, NULL);
+ if (handle > 0 || handle== ORBIS_PAD_ERROR_ALREADY_OPENED) {
+ if(handle>0) {
+ printf("@@@@ got pad[%d] handle %X\n", nPads, handle);
+ }
+ pad_users[nPads++] = userId;
+ if (nPads >= MAX_PADS) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+//#include "SDL_hints.h"
+
+
+/* Function to scan the system for joysticks.
+* Joystick 0 should be the system default joystick.
+* It should return number of joysticks, or -1 on an unrecoverable fatal error.
+*/
+static bool PS4_JoystickInit(void)
+{
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); // Checks for keyboard focus ability, 'or something'
+
+ int32_t res = sceUserServiceInitialize(NULL);
+ if(ORBIS_OK != res && ORBIS_USER_SERVICE_ERROR_ALREADY_INITIALIZED != res) {
+ return SDL_SetError("Error sceUserServiceInitialize() failed!");
+ }
+
+ if (ORBIS_OK != sceUserServiceGetInitialUser(&userId)) {
+ return SDL_SetError("Error sceUserServiceGetInitialUser() failed!");
+ }
+
+ if(ORBIS_OK != scePadInit()) {
+ return SDL_SetError("Error scePadInit() failed!");
+ }
+
+ PS4_JoystickDetect();
+ return nPads;
+}
+
+/* Function to get the device-dependent name of a joystick */
+static const char * PS4_JoystickGetDeviceName(int device_index)
+{
+ return "Dualshock4";
+}
+
+/* Function to get the player index of a joystick */
+static int PS4_JoystickGetDevicePlayerIndex(int device_index)
+{
+ if (device_index >= MAX_PADS) {
+ device_index = MAX_PADS - 1;
+ }
+
+ for (int i = 0; i < ORBIS_USER_SERVICE_MAX_LOGIN_USERS; i++) {
+ if(pad_users[device_index] == userIdList.userId[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static SDL_GUID PS4_JoystickGetDeviceGUID(int device_index)
+{
+ if (device_index >= MAX_PADS) {
+ device_index = MAX_PADS - 1;
+ }
+
+ SDL_GUID guid;
+ SDL_zero(guid);
+ ((Uint32*)guid.data)[0] = 0x00000005; // 05000000;
+ ((Uint32*)guid.data)[0] = 0x00004c05; // 4c050000;
+ ((Uint32*)guid.data)[0] = 0x000009cc; // cc090000;
+ ((Uint32*)guid.data)[0] = 0x00008001; // 01800000;
+ // "050000004c050000cc09000001800000,PS4 Controller,
+ return guid;
+}
+
+
+/* Function to perform the mapping from device index to the instance id for this index */
+static SDL_JoystickID PS4_JoystickGetDeviceInstanceID(int device_index)
+{
+ if (device_index >= MAX_PADS) {
+ device_index = MAX_PADS - 1;
+ }
+ return scePadGetHandle(pad_users[device_index], ORBIS_PAD_PORT_TYPE_STANDARD, 0);
+}
+
+/* Function to open a joystick for use.
+The joystick to open is specified by the device index.
+This should fill the nbuttons and naxes fields of the joystick structure.
+It returns 0, or -1 if there is an error.
+*/
+static bool PS4_JoystickOpen(SDL_Joystick *joystick, int device_index)
+{
+ if (device_index >= MAX_PADS) {
+ device_index = MAX_PADS - 1;
+ }
+
+ PS4_JoystickDetect(); // should already be done but ...
+
+ int32_t handle = PS4_JoystickGetDeviceInstanceID(device_index); // They are already open ,
+ if (handle > 0) {
+ joystick->nbuttons = DS4_BTN_COUNT;
+ joystick->naxes = DS4_AXE_COUNT;
+ joystick->nhats = DS4_HAT_COUNT;
+ /* Create the joystick data structure */
+ joystick->instance_id = handle;
+ return true;
+ }
+ printf("PS4_JoystickOpen(idx: %d) failed to get handled!\n", device_index);
+ return false;
+}
+
+static bool PS4_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+{
+ return SDL_Unsupported();
+}
+
+/* Function to update the state of a joystick - called as a device poll.
+* This function shouldn't update the joystick structure directly,
+* but instead should call SDL_PrivateJoystick*() to deliver events
+* and update joystick device state.
+*/
+static void PS4_JoystickUpdate(SDL_Joystick *joystick)
+{
+ OrbisPadData data;
+
+ int ret = scePadReadState(joystick->instance_id, &data);
+ if (ret != ORBIS_OK || !data.connected) {
+ printf("Warning, Controller is not connected or failed to read data! \n");
+ return;
+ }
+
+ //a:b0,b:b1,x:b3,y:b2,leftshoulder:b4,rightshoulder:b5
+ //back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,
+ //dpdown:h0.4, dpleft:h0.8, dpright:h0.2, dpup:h0.1,
+ //leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,
+ const static uint32_t ds4_map[DS4_BTN_COUNT] = {
+ ORBIS_PAD_BUTTON_CROSS, ORBIS_PAD_BUTTON_CIRCLE, ORBIS_PAD_BUTTON_SQUARE, ORBIS_PAD_BUTTON_TRIANGLE, ORBIS_PAD_BUTTON_L1, ORBIS_PAD_BUTTON_R1,
+ 0, /* b6? */ 0, /* b7? */ 0, /* no share/back btn atm */
+ ORBIS_PAD_BUTTON_OPTIONS, 0 /* no guide button atm */, ORBIS_PAD_BUTTON_L3, ORBIS_PAD_BUTTON_R3,
+ ORBIS_PAD_BUTTON_UP, ORBIS_PAD_BUTTON_DOWN, ORBIS_PAD_BUTTON_LEFT, ORBIS_PAD_BUTTON_RIGHT,
+ ORBIS_PAD_BUTTON_TOUCH_PAD, ORBIS_PAD_BUTTON_L2, ORBIS_PAD_BUTTON_R2,
+ };
+
+ Uint32 s_btns = data.buttons;
+ Uint64 timestamp = SDL_GetTicksNS();
+
+ for (uint32_t bn = 0; bn < DS4_BTN_COUNT; bn++) {
+ SDL_SendJoystickButton(timestamp, joystick, bn, s_btns & ds4_map[bn]);
+ }
+
+#define aS16(axe) -32768 + ((axe) << 8)
+
+#define setA(n,axe) { Sint16 tmp = aS16(axe); if (tmp < -1000 || tmp > 1000) { SDL_SendJoystickButton(timestamp, joystick, (n), tmp); } }
+ setA(0, data.leftStick.x);
+ setA(1, data.leftStick.y);
+ setA(2, data.analogButtons.l2);
+
+ setA(4, data.rightStick.x);
+ setA(5, data.rightStick.y);
+ setA(6, data.analogButtons.r2);
+
+ Uint8 hat = SDL_HAT_CENTERED;
+ if (s_btns & ORBIS_PAD_BUTTON_UP) { hat |= SDL_HAT_UP; }
+ if (s_btns & ORBIS_PAD_BUTTON_DOWN) { hat |= SDL_HAT_DOWN; }
+ if (s_btns & ORBIS_PAD_BUTTON_LEFT) { hat |= SDL_HAT_LEFT; }
+ if (s_btns & ORBIS_PAD_BUTTON_RIGHT) { hat |= SDL_HAT_RIGHT; }
+ SDL_SendJoystickAxis(timestamp, joystick, 0, hat);
+}
+
+/* Function to close a joystick after use */
+void PS4_JoystickClose(SDL_Joystick *joystick)
+{
+ scePadClose(joystick->instance_id);
+#if 0
+ if (joystick->hwdata)
+ SDL_free(joystick->hwdata);
+#endif
+}
+
+/* Function to perform any system-specific joystick related cleanup */
+static void PS4_JoystickQuit(void)
+{
+ nPads = 0;
+}
+
+/* New shit in SDL3 */
+static bool PS4_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
+{
+ // We don't override any other drivers
+ return false;
+}
+
+// Function to get the device-dependent path of a joystick
+static const char *PS4_JoystickGetDevicePath(int index)
+{
+ return NULL;
+}
+
+// Function to get the Steam virtual gamepad slot of a joystick
+static int PS4_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
+{
+ return -1;
+}
+
+// Function to set the player index of a joystick
+static void PS4_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
+}
+
+// Rumble functionality
+static bool PS4_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right)
+{
+ return SDL_Unsupported();
+}
+
+// LED functionality
+static bool PS4_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+ return SDL_Unsupported();
+}
+
+// General effects
+static bool PS4_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
+// Sensor functionality
+static bool PS4_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled)
+{
+ return SDL_Unsupported();
+}
+
+static bool PS4_GetGamepadMapping(int device_index, SDL_GamepadMapping *out)
+{
+ return false;
+}
+
+SDL_JoystickDriver SDL_PS4_JoystickDriver =
+{
+ PS4_JoystickInit,
+ PS4_JoystickGetCount,
+ PS4_JoystickDetect,
+ PS4_JoystickIsDevicePresent,
+ PS4_JoystickGetDeviceName,
+ PS4_JoystickGetDevicePath,
+ PS4_JoystickGetDeviceSteamVirtualGamepadSlot,
+ PS4_JoystickGetDevicePlayerIndex,
+ PS4_JoystickSetDevicePlayerIndex,
+ PS4_JoystickGetDeviceGUID,
+ PS4_JoystickGetDeviceInstanceID,
+ PS4_JoystickOpen,
+ PS4_JoystickRumble,
+ PS4_JoystickRumbleTriggers,
+ PS4_JoystickSetLED,
+ PS4_JoystickSendEffect,
+ PS4_JoystickSetSensorsEnabled,
+ PS4_JoystickUpdate,
+ PS4_JoystickClose,
+ PS4_JoystickQuit,
+ PS4_GetGamepadMapping,
+};
+
+
+#endif /* SDL_JOYSTICK_PS4 */
\ No newline at end of file