Fix multi-platform compilation issues

This commit is contained in:
walle 2026-02-02 13:12:44 +08:00 committed by Sam Lantinga
parent bb8eee8fac
commit f5efba34da
2 changed files with 213 additions and 167 deletions

View file

@ -2374,7 +2374,7 @@ elseif(WINDOWS)
set(HAVE_SDL_STORAGE 1) set(HAVE_SDL_STORAGE 1)
# Libraries for Win32 native and MinGW # Libraries for Win32 native and MinGW
sdl_link_dependency(base LIBS kernel32 user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32) sdl_link_dependency(base LIBS kernel32 user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32 hid)
set(SDL_TIME_WINDOWS 1) set(SDL_TIME_WINDOWS 1)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/windows/*.c") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/windows/*.c")

View file

@ -18,7 +18,6 @@
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "SDL_internal.h" #include "SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI #ifdef SDL_JOYSTICK_HIDAPI
@ -27,6 +26,158 @@
#include "SDL_hidapijoystick_c.h" #include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h" #include "SDL_hidapi_rumble.h"
/* ========================================================================= */
/* Win32 HID helper */
/* ========================================================================= */
/* This helper requires full desktop Win32 HID APIs.
* These APIs are NOT available on GDK platforms.
*/
#if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)
#define SDL_HAS_WIN32_HID 1
#else
#define SDL_HAS_WIN32_HID 0
#endif
#if SDL_HAS_WIN32_HID
/* --- Win32 HID includes ------------------------------------------------- */
#include <windows.h>
#include <setupapi.h>
#include <hidsdi.h>
#if defined(_MSC_VER)
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib")
#endif
static char *FindHIDInterfacePath(Uint16 vid, Uint16 pid, int collection_index)
{
GUID hidGuid;
HidD_GetHidGuid(&hidGuid);
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(
&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
);
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
return NULL;
}
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
for (DWORD i = 0;
SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &hidGuid, i, &deviceInterfaceData);
i++) {
DWORD requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(
deviceInfoSet, &deviceInterfaceData,
NULL, 0, &requiredSize, NULL
);
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)SDL_malloc(requiredSize);
if (!deviceDetail) {
continue;
}
deviceDetail->cbSize = sizeof(*deviceDetail);
if (!SetupDiGetDeviceInterfaceDetail(
deviceInfoSet, &deviceInterfaceData,
deviceDetail, requiredSize, NULL, NULL)) {
SDL_free(deviceDetail);
continue;
}
HANDLE hDevice = CreateFile(
deviceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
SDL_free(deviceDetail);
continue;
}
HIDD_ATTRIBUTES attributes;
attributes.Size = sizeof(attributes);
if (!HidD_GetAttributes(hDevice, &attributes) ||
attributes.VendorID != vid ||
attributes.ProductID != pid) {
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
PHIDP_PREPARSED_DATA preparsedData = NULL;
if (!HidD_GetPreparsedData(hDevice, &preparsedData) || !preparsedData) {
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
HIDP_CAPS caps;
if (HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS) {
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
if ((caps.InputReportByteLength == 64 && caps.OutputReportByteLength == 64) ||
(caps.InputReportByteLength == 37 && caps.OutputReportByteLength == 37)) {
char col_str[16];
SDL_snprintf(col_str, sizeof(col_str), "col%02d", collection_index);
if (SDL_strcasestr(deviceDetail->DevicePath, col_str)) {
char *result = SDL_strdup(deviceDetail->DevicePath);
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return result;
}
}
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return NULL;
}
#else /* !SDL_HAS_WIN32_HID */
/* Stub for GDK / non-Win32 platforms */
#if defined(__GNUC__) || defined(__clang__)
#define SDL_UNUSED_FUNC __attribute__((unused))
#else
#define SDL_UNUSED_FUNC
#endif
static char *FindHIDInterfacePath(Uint16 vid, Uint16 pid, int collection_index) SDL_UNUSED_FUNC;
static char *FindHIDInterfacePath(Uint16 vid, Uint16 pid, int collection_index)
{
(void)vid;
(void)pid;
(void)collection_index;
return NULL;
}
#endif /* SDL_HAS_WIN32_HID */
#ifdef SDL_JOYSTICK_HIDAPI_GAMESIR #ifdef SDL_JOYSTICK_HIDAPI_GAMESIR
#define GAMESIR_PACKET_HEADER_0 0xA1 #define GAMESIR_PACKET_HEADER_0 0xA1
@ -175,109 +326,6 @@ static bool SendGameSirModeSwitch(SDL_HIDAPI_Device *device)
return true; return true;
} }
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
#include <windows.h>
#include <setupapi.h>
#include <hidsdi.h>
#if defined(SDL_PLATFORM_WIN32) && defined(_MSC_VER)
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib")
#endif
static char *FindHIDInterfacePath(USHORT vid, USHORT pid, int collection_index ) {
GUID hidGuid;
HidD_GetHidGuid(&hidGuid);
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
return NULL;
}
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &hidGuid, i, &deviceInterfaceData); i++) {
DWORD requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &requiredSize, NULL);
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)SDL_malloc(requiredSize);
if (!deviceDetail) continue;
deviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, deviceDetail, requiredSize, NULL, NULL)) {
SDL_free(deviceDetail);
continue;
}
HANDLE hDevice = CreateFile(deviceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
SDL_free(deviceDetail);
continue;
}
HIDD_ATTRIBUTES attributes;
attributes.Size = sizeof(attributes);
if (!HidD_GetAttributes(hDevice, &attributes) ||
attributes.VendorID != vid ||
attributes.ProductID != pid) {
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
PHIDP_PREPARSED_DATA preparsedData = NULL;
if (!HidD_GetPreparsedData(hDevice, &preparsedData) || !preparsedData) {
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
HIDP_CAPS caps;
if (HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS) {
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
continue;
}
if (caps.InputReportByteLength == 64 && caps.OutputReportByteLength == 64 ||
caps.InputReportByteLength == 37 && caps.OutputReportByteLength == 37) {
char col_str[16];
snprintf(col_str, sizeof(col_str), "col%02d", collection_index);
if (SDL_strcasestr(deviceDetail->DevicePath, col_str)) {
char *result = SDL_strdup(deviceDetail->DevicePath);
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return result;
}
}
HidD_FreePreparsedData(preparsedData);
CloseHandle(hDevice);
SDL_free(deviceDetail);
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return NULL;
}
#endif
static bool HIDAPI_DriverGameSir_InitDevice(SDL_HIDAPI_Device *device) static bool HIDAPI_DriverGameSir_InitDevice(SDL_HIDAPI_Device *device)
{ {
Uint16 vendor_id = device->vendor_id; Uint16 vendor_id = device->vendor_id;
@ -287,7 +335,7 @@ static bool HIDAPI_DriverGameSir_InitDevice(SDL_HIDAPI_Device *device)
struct SDL_hid_device_info *devs = SDL_hid_enumerate(vendor_id, product_id); struct SDL_hid_device_info *devs = SDL_hid_enumerate(vendor_id, product_id);
for (struct SDL_hid_device_info *info = devs; info; info = info->next) { for (struct SDL_hid_device_info *info = devs; info; info = info->next) {
if (info->interface_number == 0) { if (info->interface_number == 0) {
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_GDK)
if (!output_handle) { if (!output_handle) {
char *col02_path = FindHIDInterfacePath(vendor_id, product_id, 2); char *col02_path = FindHIDInterfacePath(vendor_id, product_id, 2);
if (col02_path) { if (col02_path) {
@ -412,14 +460,14 @@ static bool HIDAPI_DriverGameSir_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
ctx->sensor_timestamp_step_ns = SDL_NS_PER_SECOND / 125; ctx->sensor_timestamp_step_ns = SDL_NS_PER_SECOND / 125;
// 加速度计缩放因子假设范围为±2g16位带符号值-32768到32767 // Accelerometer scale factor: assume a range of ±2g, 16-bit signed values (-32768 to 32767)
// 32768对应2g所以缩放因子 = 2 * SDL_STANDARD_GRAVITY / 32768.0f // 32768 corresponds to 2g, so the scale factor = 2 * SDL_STANDARD_GRAVITY / 32768.0f
ctx->accelScale = 2.0f * SDL_STANDARD_GRAVITY / 32768.0f; ctx->accelScale = 2.0f * SDL_STANDARD_GRAVITY / 32768.0f;
// 陀螺仪缩放因子参考PS4的实现方式 // Gyro scale factor: based on the PS4 implementation
// PS4使用 (gyro_numerator / gyro_denominator) * (π / 180) // PS4 uses (gyro_numerator / gyro_denominator) * (π / 180)
// 默认值为 (1 / 16) * (π / 180),对应量程约为 ±2048 度/秒 // The default value is (1 / 16) * (π / 180), corresponding to a range of approximately ±2048 degrees/second
// 这是游戏手柄陀螺仪的常见量程 // This is a common range for gamepad gyroscopes
const float gyro_numerator = 1.0f; const float gyro_numerator = 1.0f;
const float gyro_denominator = 16.0f; const float gyro_denominator = 16.0f;
ctx->gyroScale = (gyro_numerator / gyro_denominator) * (SDL_PI_F / 180.0f); ctx->gyroScale = (gyro_numerator / gyro_denominator) * (SDL_PI_F / 180.0f);
@ -642,22 +690,19 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
return; return;
} }
// 检查数据包格式可能包含报告ID0x43作为第一个字节 // Check packet format: it may include a report ID (0x43) as the first byte
// 实际数据包格式43 a1 c8 [按钮数据...] // Actual packet format: 43 a1 c8 [button data...]
// 如果第一个字节是0x43第二个字节是0xa1第三个字节是0xc8则跳过报告ID // If the first byte is 0x43, the second is 0xA1 and the third is 0xC8, skip the report ID
Uint8 *packet_data = data;
int packet_size = size; int packet_size = size;
if (size >= 3 && data[0] == 0x43 && data[1] == GAMESIR_PACKET_HEADER_0 && data[2] == GAMESIR_PACKET_HEADER_1_GAMEPAD) { if (size >= 3 && data[0] == 0x43 && data[1] == GAMESIR_PACKET_HEADER_0 && data[2] == GAMESIR_PACKET_HEADER_1_GAMEPAD) {
// 数据包包含报告ID跳过第一个字节 // Packet contains a report ID; skip the first byte
packet_data = data + 1;
packet_size = size - 1; packet_size = size - 1;
} else if (size >= 2 && data[0] == GAMESIR_PACKET_HEADER_0 && data[1] == GAMESIR_PACKET_HEADER_1_GAMEPAD) { } else if (size >= 2 && data[0] == GAMESIR_PACKET_HEADER_0 && data[1] == GAMESIR_PACKET_HEADER_1_GAMEPAD) {
// 标准格式没有报告ID直接是头部字节 // Standard format: no report ID, header bytes directly
packet_data = data;
packet_size = size; packet_size = size;
} else { } else {
// 不匹配的数据包格式,直接返回 // Packet format does not match; return immediately
return; return;
} }
@ -671,8 +716,8 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
if (ctx->last_state[3] != data[3]) { if (ctx->last_state[3] != data[3]) {
Uint8 buttons = data[3]; Uint8 buttons = data[3];
// BTN1: A B C X Y Z L1 R1 // BTN1: A B C X Y Z L1 R1
// 使用位运算检查每个按钮是否被按下 // Use bitwise operations to check whether each button is pressed
// buttons & BTN_A 会返回 BTN_A 的值(如果按下)或 0如果未按下 // buttons & BTN_A returns the value of BTN_A (if pressed) or 0 (if not pressed)
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, buttons & BTN_A); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, buttons & BTN_A);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, buttons & BTN_B); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, buttons & BTN_B);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, buttons & BTN_X); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, buttons & BTN_X);
@ -685,8 +730,8 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
if (ctx->last_state[4] != data[4]) { if (ctx->last_state[4] != data[4]) {
Uint8 buttons = data[4]; Uint8 buttons = data[4];
// BTN2: L2 R2 SELECT START HOME L3 R3 CAPTURE // BTN2: L2 R2 SELECT START HOME L3 R3 CAPTURE
// 注意L2/R2 作为数字按钮在 data[4] 中,但实际的模拟值在 data[15]/data[16] 中 // Note: L2/R2 appear as digital buttons in data[4], but their actual analog values are in data[15]/data[16].
// 这里只处理其他按钮,扳机轴的模拟值在后面的代码中处理 // Only handle the other buttons here; trigger analog values are processed later in the code.
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, buttons & BTN_SELECT); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, buttons & BTN_SELECT);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, buttons & BTN_START); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, buttons & BTN_START);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, buttons & BTN_HOME); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, buttons & BTN_HOME);
@ -699,7 +744,7 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
if (ctx->last_state[5] != data[5]) { if (ctx->last_state[5] != data[5]) {
Uint8 buttons = data[5]; Uint8 buttons = data[5];
// BTN3: UP DOWN LEFT RIGHT M MUTE L4 R4 // BTN3: UP DOWN LEFT RIGHT M MUTE L4 R4
// 处理方向键(十字键) // Handle the directional pad (D-pad)
Uint8 hat = SDL_HAT_CENTERED; Uint8 hat = SDL_HAT_CENTERED;
@ -725,7 +770,7 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
SDL_SendJoystickHat(timestamp, joystick, 0, hat); SDL_SendJoystickHat(timestamp, joystick, 0, hat);
// 处理其他按钮 // Handle other buttons
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, buttons & BTN_L4); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, buttons & BTN_L4);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, buttons & BTN_R4); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, buttons & BTN_R4);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC2, buttons & BTN_MUTE); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC2, buttons & BTN_MUTE);
@ -746,27 +791,27 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
} }
if (is_initial_packet) { if (is_initial_packet) {
// 初始化所有摇杆轴到中心位置 // Initialize all joystick axes to center positions
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, 0); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, 0);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, 0); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, 0);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, 0); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, 0);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, 0); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, 0);
} else { } else {
// 左摇杆处理 // Left stick handling
// 左摇杆:字节 7-10 (16位值) // Left stick: bytes 7-10 (16-bit values)
// 字节 7-8: X轴 (Hi/Low组合成带符号16位值例如0x7df6) // Bytes 7-8: X axis (Hi/Low combined into a signed 16-bit value, e.g. 0x7df6)
// 字节 9-10: Y轴 (Hi/Low组合成带符号16位值) // Bytes 9-10: Y axis (Hi/Low combined into a signed 16-bit value)
if (size >= 11) { if (size >= 11) {
// 组合字节7-8为16位值例如data[7]=0x7d, data[8]=0xf6 -> 0x7df6 // Combine bytes 7-8 into a 16-bit value, e.g.: data[7]=0x7d, data[8]=0xf6 -> 0x7df6
Uint16 raw_x_unsigned = ((Uint16)data[7] << 8) | data[8]; Uint16 raw_x_unsigned = ((Uint16)data[7] << 8) | data[8];
Uint16 raw_y_unsigned = ((Uint16)data[9] << 8) | data[10]; Uint16 raw_y_unsigned = ((Uint16)data[9] << 8) | data[10];
// 将无符号16位值解释为带符号16位值 // Interpret the unsigned 16-bit value as a signed 16-bit value
Sint16 raw_x = (Sint16)raw_x_unsigned; Sint16 raw_x = (Sint16)raw_x_unsigned;
Sint16 raw_y = (Sint16)raw_y_unsigned; Sint16 raw_y = (Sint16)raw_y_unsigned;
Sint16 left_x, left_y; Sint16 left_x, left_y;
// 直接使用带符号16位值Y轴反转SDL约定向上为负值 // Use signed 16-bit values directly; invert Y-axis (SDL convention: up is negative)
left_x = raw_x; left_x = raw_x;
left_y = -raw_y; left_y = -raw_y;
@ -782,7 +827,7 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
Sint16 last_left_x, last_left_y; Sint16 last_left_x, last_left_y;
last_left_x = last_raw_x; last_left_x = last_raw_x;
last_left_y = -last_raw_y; // Y轴反转 last_left_y = -last_raw_y; // invert Y axis
Sint16 last_deadzone_x, last_deadzone_y; Sint16 last_deadzone_x, last_deadzone_y;
ApplyCircularDeadzone(last_left_x, last_left_y, &last_deadzone_x, &last_deadzone_y); ApplyCircularDeadzone(last_left_x, last_left_y, &last_deadzone_x, &last_deadzone_y);
@ -794,22 +839,22 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
} }
} }
// 右摇杆处理 // Right stick handling
// 右摇杆:字节 11-14 (16位值) // Right stick: bytes 11-14 (16-bit values)
// 字节 11-12: X轴 (Hi/Low组合成带符号16位值) // Bytes 11-12: X axis (Hi/Low combined into a signed 16-bit value)
// 字节 13-14: Y轴 (Hi/Low组合成带符号16位值) // Bytes 13-14: Y axis (Hi/Low combined into a signed 16-bit value)
if (size >= 15) { if (size >= 15) {
// 组合字节11-12为16位值 // Combine bytes 11-12 into a 16-bit value
Uint16 raw_x_unsigned = ((Uint16)data[11] << 8) | data[12]; Uint16 raw_x_unsigned = ((Uint16)data[11] << 8) | data[12];
// 组合字节13-14为16位值 // Combine bytes 13-14 into a 16-bit value
Uint16 raw_y_unsigned = ((Uint16)data[13] << 8) | data[14]; Uint16 raw_y_unsigned = ((Uint16)data[13] << 8) | data[14];
// 将无符号16位值解释为带符号16位值 // Interpret the unsigned 16-bit value as a signed 16-bit value
Sint16 raw_x = (Sint16)raw_x_unsigned; Sint16 raw_x = (Sint16)raw_x_unsigned;
Sint16 raw_y = (Sint16)raw_y_unsigned; Sint16 raw_y = (Sint16)raw_y_unsigned;
Sint16 right_x, right_y; Sint16 right_x, right_y;
// 直接使用带符号16位值Y轴反转SDL约定向上为负值 // Use signed 16-bit values directly; invert Y-axis (SDL convention: up is negative)
right_x = raw_x; right_x = raw_x;
right_y = -raw_y; right_y = -raw_y;
@ -825,7 +870,7 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
Sint16 last_right_x, last_right_y; Sint16 last_right_x, last_right_y;
last_right_x = last_raw_x; last_right_x = last_raw_x;
last_right_y = -last_raw_y; // Y轴反转 last_right_y = -last_raw_y; // invert Y axis
Sint16 last_deadzone_x, last_deadzone_y; Sint16 last_deadzone_x, last_deadzone_y;
ApplyCircularDeadzone(last_right_x, last_right_y, &last_deadzone_x, &last_deadzone_y); ApplyCircularDeadzone(last_right_x, last_right_y, &last_deadzone_x, &last_deadzone_y);
@ -837,11 +882,11 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
} }
} }
// 处理扳机轴 // Handle trigger axes
// 协议L2(15) - AXIS 左扳机模拟量 0-255弹起0/按下255 // Protocol: L2 (byte 15) - analog left trigger 0-255, 0 = released, 255 = pressed
// R2(16) - AXIS 右扳机模拟量 0-255弹起0/按下255 // R2 (byte 16) - analog right trigger 0-255, 0 = released, 255 = pressed
// SDL 范围0-327670=未按下32767=完全按下) // SDL range: 0-32767 (0 = released, 32767 = fully pressed)
// 线性映射:0-255 -> 0-32767 // Linear mapping: 0-255 -> 0-32767
if (ctx->last_state[15] != data[15]) { if (ctx->last_state[15] != data[15]) {
axis = (Sint16)(((int)data[15] * 255) - 32767); axis = (Sint16)(((int)data[15] * 255) - 32767);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
@ -861,43 +906,44 @@ static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_D
sensor_timestamp = ctx->sensor_timestamp_ns; sensor_timestamp = ctx->sensor_timestamp_ns;
ctx->sensor_timestamp_ns += ctx->sensor_timestamp_step_ns; ctx->sensor_timestamp_ns += ctx->sensor_timestamp_step_ns;
// 加速度计数据(字节 17-22 // Accelerometer data (bytes 17-22)
// 字节 17-18: Acc X (Hi/Low组合成带符号16位值) // Bytes 17-18: Acc X (Hi/Low combined into a signed 16-bit value)
// 字节 19-20: Acc Y (Hi/Low组合成带符号16位值) // Bytes 19-20: Acc Y (Hi/Low combined into a signed 16-bit value)
// 字节 21-22: Acc Z (Hi/Low组合成带符号16位值) // Bytes 21-22: Acc Z (Hi/Low combined into a signed 16-bit value)
Uint16 acc_x_unsigned = ((Uint16)data[17] << 8) | data[18]; Uint16 acc_x_unsigned = ((Uint16)data[17] << 8) | data[18];
Uint16 acc_y_unsigned = ((Uint16)data[19] << 8) | data[20]; Uint16 acc_y_unsigned = ((Uint16)data[19] << 8) | data[20];
Uint16 acc_z_unsigned = ((Uint16)data[21] << 8) | data[22]; Uint16 acc_z_unsigned = ((Uint16)data[21] << 8) | data[22];
// 将无符号16位值转换为带符号16位值 // Convert the unsigned 16-bit values to signed 16-bit values
Sint16 acc_x = (Sint16)acc_x_unsigned; Sint16 acc_x = (Sint16)acc_x_unsigned;
Sint16 acc_y = (Sint16)acc_y_unsigned; Sint16 acc_y = (Sint16)acc_y_unsigned;
Sint16 acc_z = (Sint16)acc_z_unsigned; Sint16 acc_z = (Sint16)acc_z_unsigned;
// 应用缩放因子并转换为浮点数 // Apply scale factor and convert to floating point
// 坐标系与PS4一致直接使用原始值无符号反转 // Coordinate system matches PS4; use raw values directly without sign inversion
values[0] = (float)acc_x * ctx->accelScale; // Acc X values[0] = (float)acc_x * ctx->accelScale; // Acc X
values[1] = (float)acc_y * ctx->accelScale; // Acc Y values[1] = (float)acc_y * ctx->accelScale; // Acc Y
values[2] = (float)acc_z * ctx->accelScale; // Acc Z values[2] = (float)acc_z * ctx->accelScale; // Acc Z
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, values, 3); SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, values, 3);
// 陀螺仪数据(字节 23-28 // Gyroscope data (bytes 23-28)
// 字节 23-24: Gyro X (Hi/Low组合成带符号16位值) // Bytes 23-24: Gyro X (Hi/Low combined into a signed 16-bit value)
// 字节 25-26: Gyro Y (Hi/Low组合成带符号16位值) // Bytes 25-26: Gyro Y (Hi/Low combined into a signed 16-bit value)
// 字节 27-28: Gyro Z (Hi/Low组合成带符号16位值) // Bytes 27-28: Gyro Z (Hi/Low combined into a signed 16-bit value)
Uint16 gyro_x_unsigned = ((Uint16)data[23] << 8) | data[24]; Uint16 gyro_x_unsigned = ((Uint16)data[23] << 8) | data[24];
Uint16 gyro_y_unsigned = ((Uint16)data[25] << 8) | data[26]; Uint16 gyro_y_unsigned = ((Uint16)data[25] << 8) | data[26];
Uint16 gyro_z_unsigned = ((Uint16)data[27] << 8) | data[28]; Uint16 gyro_z_unsigned = ((Uint16)data[27] << 8) | data[28];
// 将无符号16位值转换为带符号16位值 // Convert the unsigned 16-bit values to signed 16-bit values
Sint16 gyro_x = (Sint16)gyro_x_unsigned; Sint16 gyro_x = (Sint16)gyro_x_unsigned;
Sint16 gyro_y = (Sint16)gyro_y_unsigned; Sint16 gyro_y = (Sint16)gyro_y_unsigned;
Sint16 gyro_z = (Sint16)gyro_z_unsigned; Sint16 gyro_z = (Sint16)gyro_z_unsigned;
// 应用缩放因子并转换为浮点数(弧度/秒) // Apply scale factor and convert to floating point (radians/second)
// 参考PS4的实现使用 (gyro_numerator / gyro_denominator) * (π / 180) // Based on the PS4 implementation: use (gyro_numerator / gyro_denominator) * (π / 180)
// 默认配置对应量程约为 ±2048 度/秒,这是游戏手柄陀螺仪的常见量程 // The default configuration corresponds to a range of approximately ±2048 degrees/second,
// 坐标系与PS4一致直接使用原始值无符号反转 // which is a common range for gamepad gyroscopes
// Coordinate system matches the PS4; use raw values directly without sign inversion
values[0] = (float)gyro_x * ctx->gyroScale; // Gyro X (Pitch) values[0] = (float)gyro_x * ctx->gyroScale; // Gyro X (Pitch)
values[1] = (float)gyro_y * ctx->gyroScale; // Gyro Y (Yaw) values[1] = (float)gyro_y * ctx->gyroScale; // Gyro Y (Yaw)
values[2] = (float)gyro_z * ctx->gyroScale; // Gyro Z (Roll) values[2] = (float)gyro_z * ctx->gyroScale; // Gyro Z (Roll)
@ -966,7 +1012,7 @@ static bool HIDAPI_DriverGameSir_UpdateDevice(SDL_HIDAPI_Device *device)
while ((size = SDL_hid_read_timeout(handle, data, sizeof(data), 0)) > 0) { while ((size = SDL_hid_read_timeout(handle, data, sizeof(data), 0)) > 0) {
if (joystick) { if (joystick) {
// 取消注释以处理数据包 // Uncomment to handle the packet
HIDAPI_DriverGameSir_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverGameSir_HandleStatePacket(joystick, ctx, data, size);
} }
} }