SDL_hidapi_gamesir.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. #ifdef SDL_JOYSTICK_HIDAPI
  20. #include "../SDL_sysjoystick.h"
  21. #include "SDL_hidapijoystick_c.h"
  22. #include "SDL_hidapi_rumble.h"
  23. #ifdef SDL_JOYSTICK_HIDAPI_GAMESIR
  24. // Define this if you want to log all packets from the controller
  25. #if 0
  26. #define DEBUG_GAMESIR_PROTOCOL
  27. #endif
  28. #define GAMESIR_PACKET_HEADER_0 0xA1
  29. #define GAMESIR_PACKET_HEADER_1_GAMEPAD 0xC8
  30. #define GAMESIR_IMU_RATE_HZ_WIRED 1000
  31. #define GAMESIR_IMU_RATE_HZ_WIRELESS 250
  32. // We can't tell whether it's connected via dongle or not...
  33. #define GAMESIR_IMU_RATE_HZ GAMESIR_IMU_RATE_HZ_WIRED
  34. #define BTN_A 0x01
  35. #define BTN_B 0x02
  36. #define BTN_C 0x04
  37. #define BTN_X 0x08
  38. #define BTN_Y 0x10
  39. #define BTN_Z 0x20
  40. #define BTN_L1 0x40
  41. #define BTN_R1 0x80
  42. #define BTN_L2 0x01
  43. #define BTN_R2 0x02
  44. #define BTN_SELECT 0x04
  45. #define BTN_START 0x08
  46. #define BTN_HOME 0x10
  47. #define BTN_L3 0x20
  48. #define BTN_R3 0x40
  49. #define BTN_CAPTURE 0x80
  50. #define BTN_UP 0x01
  51. #define BTN_UP_L 0x08
  52. #define BTN_UP_R 0x02
  53. #define BTN_DOWN 0x05
  54. #define BTN_DOWN_L 0x06
  55. #define BTN_DOWN_R 0X04
  56. #define BTN_LEFT 0x07
  57. #define BTN_RIGHT 0x03
  58. #define BTN_M 0x10
  59. #define BTN_MUTE 0x20
  60. #define BTN_L4 0x40
  61. #define BTN_R4 0x80
  62. #define BTN_L5 0x01
  63. #define BTN_R5 0x02
  64. #define BTN_L6 0x04
  65. #define BTN_R6 0x08
  66. #define BTN_L7 0x10
  67. #define BTN_R7 0x20
  68. #define BTN_L8 0x40
  69. #define BTN_R8 0x80
  70. enum
  71. {
  72. SDL_GAMEPAD_BUTTON_GAMESIR_SHARE = 11,
  73. SDL_GAMEPAD_BUTTON_GAMESIR_L4,
  74. SDL_GAMEPAD_BUTTON_GAMESIR_R4,
  75. SDL_GAMEPAD_BUTTON_GAMESIR_L5,
  76. SDL_GAMEPAD_BUTTON_GAMESIR_R5,
  77. SDL_GAMEPAD_BUTTON_GAMESIR_L6,
  78. SDL_GAMEPAD_BUTTON_GAMESIR_R6,
  79. SDL_GAMEPAD_BUTTON_GAMESIR_L7,
  80. SDL_GAMEPAD_BUTTON_GAMESIR_R7,
  81. SDL_GAMEPAD_BUTTON_GAMESIR_L8,
  82. //SDL_GAMEPAD_BUTTON_GAMESIR_R8, // This button doesn't exist?
  83. //SDL_GAMEPAD_BUTTON_GAMESIR_MUTE, // This button controls the audio mute LED and doesn't seem to be reported
  84. //SDL_GAMEPAD_BUTTON_GAMESIR_M // This button is for internal use by the firmware
  85. };
  86. typedef struct {
  87. Uint8 cmd;
  88. Uint8 mode;
  89. } Gamesir_CommandMode;
  90. typedef struct {
  91. bool sensors_supported;
  92. bool sensors_enabled;
  93. bool led_supported;
  94. Uint64 sensor_timestamp_ns;
  95. Uint64 sensor_timestamp_step_ns;
  96. float accelScale;
  97. float gyroScale;
  98. bool last_state_initialized;
  99. Uint8 last_state[USB_PACKET_LENGTH];
  100. SDL_hid_device *output_handle;
  101. } SDL_DriverGamesir_Context;
  102. static void HIDAPI_DriverGameSir_RegisterHints(SDL_HintCallback callback, void *userdata)
  103. {
  104. SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMESIR, callback, userdata);
  105. }
  106. static void HIDAPI_DriverGameSir_UnregisterHints(SDL_HintCallback callback, void *userdata)
  107. {
  108. SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMESIR, callback, userdata);
  109. }
  110. static bool HIDAPI_DriverGameSir_IsEnabled(void)
  111. {
  112. return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GAMESIR, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
  113. }
  114. static bool HIDAPI_DriverGameSir_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
  115. {
  116. return SDL_IsJoystickGameSirController(vendor_id, product_id);
  117. }
  118. static SDL_hid_device *HIDAPI_DriverGameSir_GetOutputHandle(SDL_HIDAPI_Device *device)
  119. {
  120. #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
  121. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  122. return ctx->output_handle;
  123. #else
  124. return device->dev;
  125. #endif
  126. }
  127. static SDL_hid_device *HIDAPI_DriverGameSir_GetInputHandle(SDL_HIDAPI_Device *device, SDL_DriverGamesir_Context *ctx)
  128. {
  129. #if defined(_WIN32)
  130. if (device->is_bluetooth) {
  131. return device->dev;
  132. }
  133. if (ctx->output_handle) {
  134. return ctx->output_handle;
  135. }
  136. return device->dev;
  137. #else
  138. return device->dev;
  139. #endif
  140. }
  141. static bool SendGameSirModeSwitch(SDL_HIDAPI_Device *device)
  142. {
  143. Gamesir_CommandMode cmd = { 0x01, 0x00 };
  144. Uint8 buf[64];
  145. SDL_zero(buf);
  146. buf[0] = 0xA2;
  147. SDL_memcpy(buf + 1, &cmd, sizeof(cmd));
  148. SDL_hid_device *handle = HIDAPI_DriverGameSir_GetOutputHandle(device);
  149. if (handle == NULL) {
  150. return false;
  151. }
  152. for (int attempt = 0; attempt < 3; ++attempt) {
  153. int result = SDL_hid_write(handle, buf, sizeof(buf));
  154. if (result >= 0) {
  155. return true;
  156. }
  157. SDL_Delay(1);
  158. }
  159. return false;
  160. }
  161. /* ========================================================================= */
  162. /* Win32 HID helper */
  163. /* ========================================================================= */
  164. /* This helper requires full desktop Win32 HID APIs.
  165. * These APIs are NOT available on GDK platforms.
  166. */
  167. #if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)
  168. /* --- Win32 HID includes ------------------------------------------------- */
  169. #include <windows.h>
  170. #include <setupapi.h>
  171. #include <hidsdi.h>
  172. #if defined(_MSC_VER)
  173. #pragma comment(lib, "setupapi.lib")
  174. #pragma comment(lib, "hid.lib")
  175. #endif
  176. static char *FindHIDInterfacePath(Uint16 vid, Uint16 pid, int collection_index)
  177. {
  178. GUID hidGuid;
  179. HidD_GetHidGuid(&hidGuid);
  180. HDEVINFO deviceInfoSet = SetupDiGetClassDevs(
  181. &hidGuid, NULL, NULL,
  182. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
  183. );
  184. if (deviceInfoSet == INVALID_HANDLE_VALUE) {
  185. return NULL;
  186. }
  187. SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
  188. deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
  189. for (DWORD i = 0;
  190. SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &hidGuid, i, &deviceInterfaceData);
  191. i++) {
  192. DWORD requiredSize = 0;
  193. SetupDiGetDeviceInterfaceDetail(
  194. deviceInfoSet, &deviceInterfaceData,
  195. NULL, 0, &requiredSize, NULL
  196. );
  197. PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail =
  198. (PSP_DEVICE_INTERFACE_DETAIL_DATA)SDL_malloc(requiredSize);
  199. if (!deviceDetail) {
  200. continue;
  201. }
  202. deviceDetail->cbSize = sizeof(*deviceDetail);
  203. if (!SetupDiGetDeviceInterfaceDetail(
  204. deviceInfoSet, &deviceInterfaceData,
  205. deviceDetail, requiredSize, NULL, NULL)) {
  206. SDL_free(deviceDetail);
  207. continue;
  208. }
  209. HANDLE hDevice = CreateFile(
  210. deviceDetail->DevicePath,
  211. GENERIC_READ | GENERIC_WRITE,
  212. FILE_SHARE_READ | FILE_SHARE_WRITE,
  213. NULL,
  214. OPEN_EXISTING,
  215. FILE_FLAG_OVERLAPPED,
  216. NULL
  217. );
  218. if (hDevice == INVALID_HANDLE_VALUE) {
  219. SDL_free(deviceDetail);
  220. continue;
  221. }
  222. HIDD_ATTRIBUTES attributes;
  223. attributes.Size = sizeof(attributes);
  224. if (!HidD_GetAttributes(hDevice, &attributes) ||
  225. attributes.VendorID != vid ||
  226. attributes.ProductID != pid) {
  227. CloseHandle(hDevice);
  228. SDL_free(deviceDetail);
  229. continue;
  230. }
  231. PHIDP_PREPARSED_DATA preparsedData = NULL;
  232. if (!HidD_GetPreparsedData(hDevice, &preparsedData) || !preparsedData) {
  233. CloseHandle(hDevice);
  234. SDL_free(deviceDetail);
  235. continue;
  236. }
  237. HIDP_CAPS caps;
  238. if (HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS) {
  239. HidD_FreePreparsedData(preparsedData);
  240. CloseHandle(hDevice);
  241. SDL_free(deviceDetail);
  242. continue;
  243. }
  244. if ((caps.InputReportByteLength == 64 && caps.OutputReportByteLength == 64) ||
  245. (caps.InputReportByteLength == 37 && caps.OutputReportByteLength == 37)) {
  246. char col_str[16];
  247. SDL_snprintf(col_str, sizeof(col_str), "col%02d", collection_index);
  248. if (SDL_strcasestr(deviceDetail->DevicePath, col_str)) {
  249. char *result = SDL_strdup(deviceDetail->DevicePath);
  250. HidD_FreePreparsedData(preparsedData);
  251. CloseHandle(hDevice);
  252. SDL_free(deviceDetail);
  253. SetupDiDestroyDeviceInfoList(deviceInfoSet);
  254. return result;
  255. }
  256. }
  257. HidD_FreePreparsedData(preparsedData);
  258. CloseHandle(hDevice);
  259. SDL_free(deviceDetail);
  260. }
  261. SetupDiDestroyDeviceInfoList(deviceInfoSet);
  262. return NULL;
  263. }
  264. #endif // SDL_PLATFORM_WIN32 && !SDL_PLATFORM_GDK
  265. static SDL_hid_device *GetOutputHandle(SDL_HIDAPI_Device *device)
  266. {
  267. Uint16 vendor_id = device->vendor_id;
  268. Uint16 product_id = device->product_id;
  269. SDL_hid_device *output_handle = NULL;
  270. struct SDL_hid_device_info *devs = SDL_hid_enumerate(vendor_id, product_id);
  271. for (struct SDL_hid_device_info *info = devs; info && !output_handle; info = info->next) {
  272. if (info->interface_number == 0) {
  273. #if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)
  274. char *col02_path = FindHIDInterfacePath(vendor_id, product_id, 2);
  275. if (col02_path) {
  276. output_handle = SDL_hid_open_path(col02_path);
  277. SDL_free(col02_path);
  278. }
  279. #endif
  280. } else if (info->interface_number == -1) {
  281. #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
  282. if (info->usage_page == 0x0001 && info->usage == 0x0005) {
  283. output_handle = SDL_hid_open_path(info->path);
  284. }
  285. #endif
  286. } else if (info->interface_number == 1) {
  287. output_handle = SDL_hid_open_path(info->path);
  288. }
  289. }
  290. SDL_hid_free_enumeration(devs);
  291. return output_handle;
  292. }
  293. static bool HIDAPI_DriverGameSir_InitDevice(SDL_HIDAPI_Device *device)
  294. {
  295. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)SDL_calloc(1, sizeof(*ctx));
  296. const char *name = "GameSir Controller";
  297. if (!ctx) {
  298. return false;
  299. }
  300. device->context = ctx;
  301. ctx->led_supported = true;
  302. ctx->output_handle = GetOutputHandle(device);
  303. ctx->sensor_timestamp_step_ns = SDL_NS_PER_SECOND / GAMESIR_IMU_RATE_HZ;
  304. switch (device->product_id) {
  305. case USB_PRODUCT_GAMESIR_GAMEPAD_G7_PRO_8K:
  306. name = "GameSir-G7 Pro 8K";
  307. break;
  308. case USB_PRODUCT_GAMESIR_GAMEPAD_TARANTULA_8K:
  309. name = "GameSir-Tarantula 8K";
  310. break;
  311. default:
  312. break;
  313. }
  314. HIDAPI_SetDeviceName(device, name);
  315. switch (device->product_id) {
  316. case USB_PRODUCT_GAMESIR_GAMEPAD_G7_PRO_8K:
  317. case USB_PRODUCT_GAMESIR_GAMEPAD_TARANTULA_8K:
  318. if (device->is_bluetooth) {
  319. // Sensors are not supported over Bluetooth
  320. } else {
  321. ctx->sensors_supported = true;
  322. }
  323. ctx->led_supported = false;
  324. SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GameSir: Device detected - %s (PID 0x%04X)", device->name, device->product_id);
  325. break;
  326. default:
  327. break;
  328. }
  329. return HIDAPI_JoystickConnected(device, NULL);
  330. }
  331. static int HIDAPI_DriverGameSir_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
  332. {
  333. return -1;
  334. }
  335. static void HIDAPI_DriverGameSir_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
  336. {
  337. }
  338. static int HIDAPI_DriverGameSir_GetJoystickButtonCount(SDL_HIDAPI_Device *device)
  339. {
  340. if (device->is_bluetooth) {
  341. // Extended buttons are not supported over Bluetooth
  342. return 11;
  343. }
  344. if (device->name && SDL_strcmp(device->name, "GameSir-Tarantula 8K") == 0) {
  345. return SDL_GAMEPAD_BUTTON_GAMESIR_L8 + 1;
  346. }
  347. return SDL_GAMEPAD_BUTTON_GAMESIR_R5 + 1;
  348. }
  349. static bool HIDAPI_DriverGameSir_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
  350. {
  351. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  352. SDL_AssertJoysticksLocked();
  353. if (!ctx) {
  354. return false;
  355. }
  356. SDL_zeroa(ctx->last_state);
  357. ctx->last_state_initialized = false;
  358. if (!SendGameSirModeSwitch(device)) {
  359. SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GameSir: failed to send SDL mode switch command (0xA2, 0x01)");
  360. }
  361. joystick->nbuttons = HIDAPI_DriverGameSir_GetJoystickButtonCount(device);
  362. joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
  363. joystick->nhats = 1;
  364. if (ctx->sensors_supported) {
  365. // GameSir SDL protocol packets currently don't expose an IMU timestamp.
  366. // Use a synthetic monotonic timestamp at the firmware's fixed IMU rate.
  367. ctx->sensor_timestamp_ns = SDL_GetTicksNS();
  368. // Accelerometer scale factor: assume a range of ±4g, 16-bit signed values (-32768 to 32767)
  369. // 32768 corresponds to 4g, so the scale factor = 4 * SDL_STANDARD_GRAVITY / 32768.0f
  370. ctx->accelScale = 4.0f * SDL_STANDARD_GRAVITY / 32768.0f;
  371. // Gyro scale factor: based on the PS4 implementation
  372. // PS4 uses (gyro_numerator / gyro_denominator) * (π / 180)
  373. // The default value is (1 / 16) * (π / 180), corresponding to a range of approximately ±2048 degrees/second
  374. // This is a common range for gamepad gyroscopes
  375. const float gyro_numerator = 1.0f;
  376. const float gyro_denominator = 16.0f;
  377. ctx->gyroScale = (gyro_numerator / gyro_denominator) * (SDL_PI_F / 180.0f);
  378. const float flSensorRate = (float)GAMESIR_IMU_RATE_HZ;
  379. SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, flSensorRate);
  380. SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, flSensorRate);
  381. }
  382. return true;
  383. }
  384. static bool HIDAPI_DriverGameSir_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
  385. {
  386. Uint8 buf[64];
  387. SDL_zero(buf);
  388. buf[0] = 0xA2;
  389. buf[1] = 0x03;
  390. buf[2] = (Uint8)(low_frequency_rumble >> 8);
  391. buf[3] = (Uint8)(high_frequency_rumble >> 8);
  392. SDL_hid_device *handle = HIDAPI_DriverGameSir_GetOutputHandle(device);
  393. if (handle == NULL) {
  394. return false;
  395. }
  396. int result = SDL_hid_write(handle, buf, sizeof(buf));
  397. if (result < 0) {
  398. return false;
  399. }
  400. return true;
  401. }
  402. static bool HIDAPI_DriverGameSir_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
  403. {
  404. return SDL_Unsupported();
  405. }
  406. static Uint32 HIDAPI_DriverGameSir_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
  407. {
  408. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  409. Uint32 caps = SDL_JOYSTICK_CAP_RUMBLE;
  410. if (ctx->led_supported) {
  411. caps |= SDL_JOYSTICK_CAP_RGB_LED;
  412. }
  413. return caps;
  414. }
  415. static bool HIDAPI_DriverGameSir_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
  416. {
  417. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  418. if (!ctx->led_supported) {
  419. return SDL_Unsupported();
  420. }
  421. Uint8 buf[64];
  422. SDL_zero(buf);
  423. buf[0] = 0xA2;
  424. buf[1] = 0x04;
  425. buf[2] = 0x01;
  426. buf[3] = 0x01;
  427. buf[4] = red;
  428. buf[5] = green;
  429. buf[6] = blue;
  430. SDL_hid_device *handle = HIDAPI_DriverGameSir_GetOutputHandle(device);
  431. if (handle == NULL) {
  432. return false;
  433. }
  434. int result = SDL_hid_write(handle, buf, sizeof(buf));
  435. if (result < 0) {
  436. return false;
  437. }
  438. return true;
  439. }
  440. static bool HIDAPI_DriverGameSir_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
  441. {
  442. return SDL_Unsupported();
  443. }
  444. static bool HIDAPI_DriverGameSir_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
  445. {
  446. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  447. if (ctx->sensors_supported) {
  448. ctx->sensors_enabled = enabled;
  449. if (enabled) {
  450. ctx->sensor_timestamp_ns = SDL_GetTicksNS();
  451. }
  452. return true;
  453. }
  454. return SDL_Unsupported();
  455. }
  456. static void HIDAPI_DriverGameSir_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverGamesir_Context *ctx, Uint8 *data, int size)
  457. {
  458. Sint16 axis;
  459. Uint64 timestamp = SDL_GetTicksNS();
  460. const Uint8 *last = ctx->last_state;
  461. bool is_initial_packet = !ctx->last_state_initialized;
  462. const int min_payload_size = ctx->sensors_enabled ? 26 : 14;
  463. if (size < min_payload_size) {
  464. return;
  465. }
  466. if (last[0] != data[0]) {
  467. Uint8 buttons = data[0];
  468. // BTN1: A B C X Y Z L1 R1
  469. // Use bitwise operations to check whether each button is pressed
  470. // buttons & BTN_A returns the value of BTN_A (if pressed) or 0 (if not pressed)
  471. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, buttons & BTN_A);
  472. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, buttons & BTN_B);
  473. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, buttons & BTN_X);
  474. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, buttons & BTN_Y);
  475. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, buttons & BTN_L1);
  476. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, buttons & BTN_R1);
  477. }
  478. if (last[1] != data[1]) {
  479. Uint8 buttons = data[1];
  480. // BTN2: L2 R2 SELECT START HOME L3 R3 CAPTURE
  481. // Note: L2/R2 appear as digital buttons in data[1], but their actual analog values are in data[12]/data[13].
  482. // Only handle the other buttons here; trigger analog values are processed later in the code.
  483. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, buttons & BTN_SELECT);
  484. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, buttons & BTN_START);
  485. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, buttons & BTN_HOME);
  486. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, buttons & BTN_L3);
  487. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, buttons & BTN_R3);
  488. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_SHARE, buttons & BTN_CAPTURE);
  489. }
  490. if (last[2] != data[2]) {
  491. Uint8 buttons = data[2];
  492. // BTN3: UP DOWN LEFT RIGHT M MUTE L4 R4
  493. // Handle the directional pad (D-pad)
  494. Uint8 hat = SDL_HAT_CENTERED;
  495. switch (buttons & 0x0F) {
  496. case BTN_UP_R:
  497. hat = SDL_HAT_RIGHTUP;
  498. break;
  499. case BTN_UP_L:
  500. hat = SDL_HAT_LEFTUP;
  501. break;
  502. case BTN_DOWN_R:
  503. hat = SDL_HAT_RIGHTDOWN;
  504. break;
  505. case BTN_DOWN_L:
  506. hat = SDL_HAT_LEFTDOWN;
  507. break;
  508. case BTN_UP:
  509. hat = SDL_HAT_UP;
  510. break;
  511. case BTN_DOWN:
  512. hat = SDL_HAT_DOWN;
  513. break;
  514. case BTN_LEFT:
  515. hat = SDL_HAT_LEFT;
  516. break;
  517. case BTN_RIGHT:
  518. hat = SDL_HAT_RIGHT;
  519. break;
  520. default:
  521. hat = SDL_HAT_CENTERED;
  522. break;
  523. }
  524. SDL_SendJoystickHat(timestamp, joystick, 0, hat);
  525. // Handle other buttons
  526. //SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_M, buttons & BTN_M);
  527. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_L4, buttons & BTN_L4);
  528. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_R4, buttons & BTN_R4);
  529. //SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_MUTE, buttons & BTN_MUTE);
  530. }
  531. if (last[3] != data[3]) {
  532. Uint8 buttons = data[3];
  533. // BTN4: L5 R5 L6 R6 L7 R7 L8 R8
  534. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_L5, buttons & BTN_L5);
  535. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_R5, buttons & BTN_R5);
  536. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_L6, buttons & BTN_L6);
  537. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_R6, buttons & BTN_R6);
  538. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_L7, buttons & BTN_L7);
  539. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_R7, buttons & BTN_R7);
  540. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_L8, buttons & BTN_L8);
  541. //SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GAMESIR_R8, buttons & BTN_R8);
  542. }
  543. if (is_initial_packet) {
  544. // Initialize all joystick axes to center positions
  545. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, 0);
  546. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, 0);
  547. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, 0);
  548. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, 0);
  549. } else {
  550. // Left stick handling
  551. // Left stick: payload bytes 4-7 (16-bit values)
  552. // Bytes 4-5: X axis (Hi/Low combined into a signed 16-bit value, e.g. 0x7df6)
  553. // Bytes 6-7: Y axis (Hi/Low combined into a signed 16-bit value)
  554. if (size >= 8) {
  555. // Combine bytes 4-5 into a 16-bit value, e.g.: data[4]=0x7d, data[5]=0xf6 -> 0x7df6
  556. Uint16 raw_x_unsigned = ((Uint16)data[4] << 8) | data[5];
  557. Uint16 raw_y_unsigned = ((Uint16)data[6] << 8) | data[7];
  558. // Interpret the unsigned 16-bit value as a signed 16-bit value
  559. Sint16 raw_x = (Sint16)raw_x_unsigned;
  560. Sint16 raw_y = (Sint16)raw_y_unsigned;
  561. Sint16 left_x, left_y;
  562. // Use signed 16-bit values directly; invert Y-axis (SDL convention: up is negative)
  563. // Clamp -(-32768) to 32767 to avoid Sint16 overflow wrapping back to -32768
  564. left_x = raw_x;
  565. left_y = (raw_y == SDL_MIN_SINT16) ? SDL_MAX_SINT16 : -raw_y;
  566. Uint16 last_raw_x_unsigned = ((Uint16)last[4] << 8) | last[5];
  567. Uint16 last_raw_y_unsigned = ((Uint16)last[6] << 8) | last[7];
  568. Sint16 last_raw_x = (Sint16)last_raw_x_unsigned;
  569. Sint16 last_raw_y = (Sint16)last_raw_y_unsigned;
  570. bool raw_changed = (raw_x != last_raw_x || raw_y != last_raw_y);
  571. if (raw_changed) {
  572. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, left_x);
  573. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, left_y);
  574. }
  575. }
  576. // Right stick handling
  577. // Right stick: payload bytes 8-11 (16-bit values)
  578. // Bytes 8-9: X axis (Hi/Low combined into a signed 16-bit value)
  579. // Bytes 10-11: Y axis (Hi/Low combined into a signed 16-bit value)
  580. if (size >= 12) {
  581. // Combine bytes 8-9 into a 16-bit value
  582. Uint16 raw_x_unsigned = ((Uint16)data[8] << 8) | data[9];
  583. // Combine bytes 10-11 into a 16-bit value
  584. Uint16 raw_y_unsigned = ((Uint16)data[10] << 8) | data[11];
  585. // Interpret the unsigned 16-bit value as a signed 16-bit value
  586. Sint16 raw_x = (Sint16)raw_x_unsigned;
  587. Sint16 raw_y = (Sint16)raw_y_unsigned;
  588. Sint16 right_x, right_y;
  589. // Use signed 16-bit values directly; invert Y-axis (SDL convention: up is negative)
  590. // Clamp -(-32768) to 32767 to avoid Sint16 overflow wrapping back to -32768
  591. right_x = raw_x;
  592. right_y = (raw_y == SDL_MIN_SINT16) ? SDL_MAX_SINT16 : -raw_y;
  593. Uint16 last_raw_x_unsigned = ((Uint16)last[8] << 8) | last[9];
  594. Uint16 last_raw_y_unsigned = ((Uint16)last[10] << 8) | last[11];
  595. Sint16 last_raw_x = (Sint16)last_raw_x_unsigned;
  596. Sint16 last_raw_y = (Sint16)last_raw_y_unsigned;
  597. bool raw_changed = (raw_x != last_raw_x || raw_y != last_raw_y);
  598. if (raw_changed) {
  599. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, right_x);
  600. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, right_y);
  601. }
  602. }
  603. // Handle trigger axes
  604. // Protocol: L2 (payload byte 12) - analog left trigger 0-255, 0 = released, 255 = fully pressed
  605. // R2 (payload byte 13) - analog right trigger 0-255, 0 = released, 255 = fully pressed
  606. // SDL range: -32768 to 32767 (-32768 = released, 32767 = fully pressed)
  607. // Linear mapping: 0-255 -> -32768..32767, formula: data * 257 - 32768 (same as PS4)
  608. if (last[12] != data[12]) {
  609. axis = ((int)data[12] * 257) - 32768;
  610. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
  611. }
  612. if (last[13] != data[13]) {
  613. axis = ((int)data[13] * 257) - 32768;
  614. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
  615. }
  616. }
  617. if (ctx->sensors_enabled && !is_initial_packet && size >= 26) {
  618. Uint64 sensor_timestamp;
  619. float values[3];
  620. sensor_timestamp = ctx->sensor_timestamp_ns;
  621. ctx->sensor_timestamp_ns += ctx->sensor_timestamp_step_ns;
  622. // Accelerometer data (payload bytes 14-19)
  623. // Bytes 14-15: Acc X (Hi/Low combined into a signed 16-bit value)
  624. // Bytes 16-17: Acc Y (Hi/Low combined into a signed 16-bit value)
  625. // Bytes 18-19: Acc Z (Hi/Low combined into a signed 16-bit value)
  626. Uint16 acc_x_unsigned = ((Uint16)data[14] << 8) | data[15];
  627. Uint16 acc_y_unsigned = ((Uint16)data[16] << 8) | data[17];
  628. Uint16 acc_z_unsigned = ((Uint16)data[18] << 8) | data[19];
  629. // Convert the unsigned 16-bit values to signed 16-bit values
  630. Sint16 acc_x = (Sint16)acc_x_unsigned;
  631. Sint16 acc_y = (Sint16)acc_y_unsigned;
  632. Sint16 acc_z = (Sint16)acc_z_unsigned;
  633. // Apply scale factor and convert to floating point
  634. // Coordinate system matches PS4; use raw values directly without sign inversion
  635. values[0] = (float)acc_x * ctx->accelScale; // Acc X
  636. values[1] = (float)acc_y * ctx->accelScale; // Acc Y
  637. values[2] = (float)acc_z * ctx->accelScale; // Acc Z
  638. SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, values, 3);
  639. // Gyroscope data (payload bytes 20-25)
  640. // Bytes 20-21: Gyro X (Hi/Low combined into a signed 16-bit value)
  641. // Bytes 22-23: Gyro Y (Hi/Low combined into a signed 16-bit value)
  642. // Bytes 24-25: Gyro Z (Hi/Low combined into a signed 16-bit value)
  643. Uint16 gyro_x_unsigned = ((Uint16)data[20] << 8) | data[21];
  644. Uint16 gyro_y_unsigned = ((Uint16)data[22] << 8) | data[23];
  645. Uint16 gyro_z_unsigned = ((Uint16)data[24] << 8) | data[25];
  646. // Convert the unsigned 16-bit values to signed 16-bit values
  647. Sint16 gyro_x = (Sint16)gyro_x_unsigned;
  648. Sint16 gyro_y = (Sint16)gyro_y_unsigned;
  649. Sint16 gyro_z = (Sint16)gyro_z_unsigned;
  650. // Apply scale factor and convert to floating point (radians/second)
  651. // Based on the PS4 implementation: use (gyro_numerator / gyro_denominator) * (π / 180)
  652. // The default configuration corresponds to a range of approximately ±2048 degrees/second,
  653. // which is a common range for gamepad gyroscopes
  654. // Coordinate system matches the PS4; use raw values directly without sign inversion
  655. values[0] = (float)gyro_x * ctx->gyroScale; // Gyro X (Pitch)
  656. values[1] = (float)gyro_y * ctx->gyroScale; // Gyro Y (Yaw)
  657. values[2] = (float)gyro_z * ctx->gyroScale; // Gyro Z (Roll)
  658. SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, values, 3);
  659. }
  660. if (size >= 32) {
  661. Uint16 l_touchpad_x = ((Uint16)data[26] << 4) | ((data[27] >> 4) & 0x0F);
  662. Uint16 l_touchpad_y = ((Uint16)(data[27] & 0x0F) << 8) | data[28];
  663. Uint16 r_touchpad_x = ((Uint16)data[29] << 4) | ((data[30] >> 4) & 0x0F);
  664. Uint16 r_touchpad_y = ((Uint16)(data[30] & 0x0F) << 8) | data[31];
  665. (void)l_touchpad_x;
  666. (void)l_touchpad_y;
  667. (void)r_touchpad_x;
  668. (void)r_touchpad_y;
  669. }
  670. SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
  671. ctx->last_state_initialized = true;
  672. }
  673. static void HIDAPI_DriverGameSir_HandleSimpleStatePacketBluetooth(SDL_Joystick *joystick, SDL_DriverGamesir_Context *ctx, Uint8 *data, int size)
  674. {
  675. Sint16 axis;
  676. Uint64 timestamp = SDL_GetTicksNS();
  677. const Uint8 *last = ctx->last_state;
  678. if (last[5] != data[5]) {
  679. Uint8 buttons = data[5];
  680. // BTN1: A B C X Y Z L1 R1
  681. // Use bitwise operations to check whether each button is pressed
  682. // buttons & BTN_A returns the value of BTN_A (if pressed) or 0 (if not pressed)
  683. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, buttons & BTN_A);
  684. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, buttons & BTN_B);
  685. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, buttons & BTN_X);
  686. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, buttons & BTN_Y);
  687. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, buttons & BTN_L1);
  688. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, buttons & BTN_R1);
  689. }
  690. if (last[6] != data[6]) {
  691. Uint8 buttons = data[6];
  692. // BTN2: L2 R2 SELECT START HOME L3 R3 CAPTURE
  693. // Note: L2/R2 appear as digital buttons in data[6], but their actual analog values are in data[7]/data[8].
  694. // Only handle the other buttons here; trigger analog values are processed later in the code.
  695. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, buttons & BTN_SELECT);
  696. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, buttons & BTN_START);
  697. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, buttons & BTN_HOME);
  698. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, buttons & BTN_L3);
  699. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, buttons & BTN_R3);
  700. }
  701. if (last[4] != data[4]) {
  702. Uint8 hat;
  703. switch (data[4] & 0xF) {
  704. case 0:
  705. hat = SDL_HAT_UP;
  706. break;
  707. case 1:
  708. hat = SDL_HAT_RIGHTUP;
  709. break;
  710. case 2:
  711. hat = SDL_HAT_RIGHT;
  712. break;
  713. case 3:
  714. hat = SDL_HAT_RIGHTDOWN;
  715. break;
  716. case 4:
  717. hat = SDL_HAT_DOWN;
  718. break;
  719. case 5:
  720. hat = SDL_HAT_LEFTDOWN;
  721. break;
  722. case 6:
  723. hat = SDL_HAT_LEFT;
  724. break;
  725. case 7:
  726. hat = SDL_HAT_LEFTUP;
  727. break;
  728. default:
  729. hat = SDL_HAT_CENTERED;
  730. break;
  731. }
  732. SDL_SendJoystickHat(timestamp, joystick, 0, hat);
  733. }
  734. #define READ_STICK_AXIS(offset) \
  735. (data[offset] == 0x80 ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x80), -0x80, 0xff - 0x80, SDL_MIN_SINT16, SDL_MAX_SINT16))
  736. {
  737. axis = READ_STICK_AXIS(0);
  738. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
  739. axis = READ_STICK_AXIS(1);
  740. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
  741. axis = READ_STICK_AXIS(2);
  742. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
  743. axis = READ_STICK_AXIS(3);
  744. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
  745. }
  746. #undef READ_STICK_AXIS
  747. #define READ_TRIGGER_AXIS(offset) \
  748. (Sint16)HIDAPI_RemapVal((float)data[offset], 0, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16)
  749. axis = READ_TRIGGER_AXIS(8);
  750. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
  751. axis = READ_TRIGGER_AXIS(7);
  752. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
  753. #undef READ_TRIGGER_AXIS
  754. SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
  755. }
  756. static void HIDAPI_DriverGameSir_HandleSimpleStatePacketUSB(SDL_Joystick *joystick, SDL_DriverGamesir_Context *ctx, Uint8 *data, int size)
  757. {
  758. Sint16 axis;
  759. Uint64 timestamp = SDL_GetTicksNS();
  760. const Uint8 *last = ctx->last_state;
  761. if (last[0] != data[0]) {
  762. Uint8 buttons = data[0];
  763. // BTN1: A B C X Y Z L1 R1
  764. // Use bitwise operations to check whether each button is pressed
  765. // buttons & BTN_A returns the value of BTN_A (if pressed) or 0 (if not pressed)
  766. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, buttons & BTN_A);
  767. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, buttons & BTN_B);
  768. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, buttons & BTN_X);
  769. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, buttons & BTN_Y);
  770. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, buttons & BTN_L1);
  771. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, buttons & BTN_R1);
  772. }
  773. if (last[1] != data[1]) {
  774. Uint8 buttons = data[1];
  775. // BTN2: L2 R2 SELECT START HOME L3 R3 CAPTURE
  776. // Note: L2/R2 appear as digital buttons in data[6], but their actual analog values are in data[7]/data[8].
  777. // Only handle the other buttons here; trigger analog values are processed later in the code.
  778. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, buttons & BTN_SELECT);
  779. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, buttons & BTN_START);
  780. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, buttons & BTN_HOME);
  781. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, buttons & BTN_L3);
  782. SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, buttons & BTN_R3);
  783. }
  784. if (last[2] != data[2]) {
  785. Uint8 hat;
  786. switch (data[2] & 0xF) {
  787. case 0:
  788. hat = SDL_HAT_UP;
  789. break;
  790. case 1:
  791. hat = SDL_HAT_RIGHTUP;
  792. break;
  793. case 2:
  794. hat = SDL_HAT_RIGHT;
  795. break;
  796. case 3:
  797. hat = SDL_HAT_RIGHTDOWN;
  798. break;
  799. case 4:
  800. hat = SDL_HAT_DOWN;
  801. break;
  802. case 5:
  803. hat = SDL_HAT_LEFTDOWN;
  804. break;
  805. case 6:
  806. hat = SDL_HAT_LEFT;
  807. break;
  808. case 7:
  809. hat = SDL_HAT_LEFTUP;
  810. break;
  811. default:
  812. hat = SDL_HAT_CENTERED;
  813. break;
  814. }
  815. SDL_SendJoystickHat(timestamp, joystick, 0, hat);
  816. }
  817. #define READ_STICK_AXIS(offset) \
  818. (data[offset] == 0x80 ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x80), -0x80, 0xff - 0x80, SDL_MIN_SINT16, SDL_MAX_SINT16))
  819. {
  820. axis = READ_STICK_AXIS(3);
  821. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
  822. axis = READ_STICK_AXIS(4);
  823. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
  824. axis = READ_STICK_AXIS(5);
  825. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
  826. axis = READ_STICK_AXIS(6);
  827. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
  828. }
  829. #undef READ_STICK_AXIS
  830. #define READ_TRIGGER_AXIS(offset) \
  831. (Sint16)HIDAPI_RemapVal((float)data[offset], 0, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16)
  832. axis = READ_TRIGGER_AXIS(7);
  833. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
  834. axis = READ_TRIGGER_AXIS(8);
  835. SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
  836. #undef READ_TRIGGER_AXIS
  837. SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
  838. }
  839. static bool HIDAPI_DriverGameSir_UpdateDevice(SDL_HIDAPI_Device *device)
  840. {
  841. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  842. SDL_Joystick *joystick = NULL;
  843. Uint8 data[USB_PACKET_LENGTH];
  844. int size;
  845. if (device->num_joysticks > 0) {
  846. joystick = SDL_GetJoystickFromID(device->joysticks[0]);
  847. }
  848. SDL_hid_device *handle = HIDAPI_DriverGameSir_GetInputHandle(device, ctx);
  849. if (handle == NULL) {
  850. return false;
  851. }
  852. while ((size = SDL_hid_read_timeout(handle, data, sizeof(data), 0)) > 0) {
  853. #ifdef DEBUG_GAMESIR_PROTOCOL
  854. HIDAPI_DumpPacket("GameSir packet: size = %d", data, size);
  855. #endif
  856. if (!joystick) {
  857. continue;
  858. }
  859. // Check packet format: it may include a report ID (0x43) as the first byte
  860. // Actual packet format: 43 a1 c8 [button data...]
  861. // If the first byte is 0x43, the second is 0xA1 and the third is 0xC8, skip the report ID
  862. Uint8 *payload = NULL;
  863. int payload_size = 0;
  864. if (size >= 3 && data[0] == 0x43 && data[1] == GAMESIR_PACKET_HEADER_0 && data[2] == GAMESIR_PACKET_HEADER_1_GAMEPAD) {
  865. payload = data + 3;
  866. payload_size = size - 3;
  867. HIDAPI_DriverGameSir_HandleStatePacket(joystick, ctx, payload, payload_size);
  868. } else if (size >= 2 && data[0] == GAMESIR_PACKET_HEADER_0 && data[1] == GAMESIR_PACKET_HEADER_1_GAMEPAD) {
  869. payload = data + 2;
  870. payload_size = size - 2;
  871. HIDAPI_DriverGameSir_HandleStatePacket(joystick, ctx, payload, payload_size);
  872. } else if (size >= 10 && (data[0] == 0x02 || data[0] == 0x07)) {
  873. payload = data + 1;
  874. payload_size = size - 1;
  875. HIDAPI_DriverGameSir_HandleSimpleStatePacketBluetooth(joystick, ctx, payload, payload_size);
  876. } else if (size == 9) {
  877. payload = data;
  878. payload_size = size;
  879. HIDAPI_DriverGameSir_HandleSimpleStatePacketUSB(joystick, ctx, payload, payload_size);
  880. }
  881. }
  882. if (size < 0 && device->num_joysticks > 0) {
  883. // Read error, device is disconnected
  884. HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
  885. }
  886. return (size >= 0);
  887. }
  888. static void HIDAPI_DriverGameSir_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
  889. {
  890. }
  891. static void HIDAPI_DriverGameSir_FreeDevice(SDL_HIDAPI_Device *device)
  892. {
  893. SDL_DriverGamesir_Context *ctx = (SDL_DriverGamesir_Context *)device->context;
  894. if (ctx) {
  895. if (ctx->output_handle) {
  896. SDL_hid_close(ctx->output_handle);
  897. }
  898. SDL_free(ctx);
  899. device->context = NULL;
  900. }
  901. }
  902. SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameSir = {
  903. SDL_HINT_JOYSTICK_HIDAPI_GAMESIR,
  904. true,
  905. HIDAPI_DriverGameSir_RegisterHints,
  906. HIDAPI_DriverGameSir_UnregisterHints,
  907. HIDAPI_DriverGameSir_IsEnabled,
  908. HIDAPI_DriverGameSir_IsSupportedDevice,
  909. HIDAPI_DriverGameSir_InitDevice,
  910. HIDAPI_DriverGameSir_GetDevicePlayerIndex,
  911. HIDAPI_DriverGameSir_SetDevicePlayerIndex,
  912. HIDAPI_DriverGameSir_UpdateDevice,
  913. HIDAPI_DriverGameSir_OpenJoystick,
  914. HIDAPI_DriverGameSir_RumbleJoystick,
  915. HIDAPI_DriverGameSir_RumbleJoystickTriggers,
  916. HIDAPI_DriverGameSir_GetJoystickCapabilities,
  917. HIDAPI_DriverGameSir_SetJoystickLED,
  918. HIDAPI_DriverGameSir_SendJoystickEffect,
  919. HIDAPI_DriverGameSir_SetJoystickSensorsEnabled,
  920. HIDAPI_DriverGameSir_CloseJoystick,
  921. HIDAPI_DriverGameSir_FreeDevice,
  922. };
  923. #endif // SDL_JOYSTICK_HIDAPI_GAMESIR
  924. #endif // SDL_JOYSTICK_HIDAPI