Atlas - SDL_hidapi_switch2.c
Home / ext / SDL / src / joystick / hidapi Lines: 5 | Size: 49614 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21/* This driver supports the Nintendo Switch Pro controller. 22 Code and logic contributed by Valve Corporation under the SDL zlib license. 23*/ 24#include "SDL_internal.h" 25 26#ifdef SDL_JOYSTICK_HIDAPI 27 28#include "../../SDL_hints_c.h" 29#include "../../misc/SDL_libusb.h" 30#include "../SDL_sysjoystick.h" 31#include "SDL_hidapijoystick_c.h" 32#include "SDL_hidapi_rumble.h" 33 34#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2 35 36#define RUMBLE_INTERVAL 12 37#define RUMBLE_MAX 29000 38 39// Define this if you want to log all packets from the controller 40#if 0 41#define DEBUG_SWITCH2_PROTOCOL 42#endif 43 44enum 45{ 46 SDL_GAMEPAD_BUTTON_SWITCH2_PRO_SHARE = 11, 47 SDL_GAMEPAD_BUTTON_SWITCH2_PRO_C, 48 SDL_GAMEPAD_BUTTON_SWITCH2_PRO_RIGHT_PADDLE, 49 SDL_GAMEPAD_BUTTON_SWITCH2_PRO_LEFT_PADDLE, 50 SDL_GAMEPAD_NUM_SWITCH2_PRO_BUTTONS 51}; 52 53enum 54{ 55 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_SHARE = 11, 56 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C, 57 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE1, 58 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE1, 59 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE2, 60 SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE2, 61 SDL_GAMEPAD_NUM_SWITCH2_JOYCON_BUTTONS 62}; 63 64enum 65{ 66 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_GUIDE = 4, 67 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_START, 68 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_SHOULDER, 69 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_SHOULDER, 70 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_SHARE, 71 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_C, 72 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_TRIGGER, // Full trigger pull click 73 SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_TRIGGER, // Full trigger pull click 74 SDL_GAMEPAD_NUM_SWITCH2_GAMECUBE_BUTTONS 75}; 76 77typedef struct 78{ 79 Uint16 neutral; 80 Uint16 max; 81 Uint16 min; 82} Switch2_AxisCalibration; 83 84typedef struct 85{ 86 Switch2_AxisCalibration x; 87 Switch2_AxisCalibration y; 88} Switch2_StickCalibration; 89 90typedef struct 91{ 92 SDL_HIDAPI_Device *device; 93 SDL_Joystick *joystick; 94 95 SDL_LibUSBContext *libusb; 96 libusb_device_handle *device_handle; 97 bool interface_claimed; 98 Uint8 interface_number; 99 Uint8 out_endpoint; 100 Uint8 in_endpoint; 101 102 Uint64 rumble_timestamp; 103 Uint32 rumble_seq; 104 Uint16 rumble_hi_amp; 105 Uint16 rumble_hi_freq; 106 Uint16 rumble_lo_amp; 107 Uint16 rumble_lo_freq; 108 Uint32 rumble_error; 109 bool rumble_updated; 110 111 Switch2_StickCalibration left_stick; 112 Switch2_StickCalibration right_stick; 113 Uint8 left_trigger_zero; 114 Uint8 right_trigger_zero; 115 116 float gyro_bias_x; 117 float gyro_bias_y; 118 float gyro_bias_z; 119 float accel_bias_x; 120 float accel_bias_y; 121 float accel_bias_z; 122 bool sensors_enabled; 123 bool sensors_ready; 124 int sample_count; 125 Uint64 first_sensor_timestamp; 126 Uint64 sensor_ts_coeff; 127 float gyro_coeff; 128 129 bool player_lights; 130 int player_index; 131 132 bool vertical_mode; 133 Uint8 last_state[USB_PACKET_LENGTH]; 134} SDL_DriverSwitch2_Context; 135 136static void ParseStickCalibration(Switch2_StickCalibration *stick_data, const Uint8 *data) 137{ 138 stick_data->x.neutral = data[0]; 139 stick_data->x.neutral |= (data[1] & 0x0F) << 8; 140 141 stick_data->y.neutral = data[1] >> 4; 142 stick_data->y.neutral |= data[2] << 4; 143 144 stick_data->x.max = data[3]; 145 stick_data->x.max |= (data[4] & 0x0F) << 8; 146 147 stick_data->y.max = data[4] >> 4; 148 stick_data->y.max |= data[5] << 4; 149 150 stick_data->x.min = data[6]; 151 stick_data->x.min |= (data[7] & 0x0F) << 8; 152 153 stick_data->y.min = data[7] >> 4; 154 stick_data->y.min |= data[8] << 4; 155} 156 157static int SendBulkData(SDL_DriverSwitch2_Context *ctx, const Uint8 *data, unsigned size) 158{ 159 int transferred; 160 int res = ctx->libusb->bulk_transfer(ctx->device_handle, 161 ctx->out_endpoint, 162 (Uint8 *)data, 163 size, 164 &transferred, 165 1000); 166 if (res < 0) { 167 return res; 168 } 169 return transferred; 170} 171 172static int RecvBulkData(SDL_DriverSwitch2_Context *ctx, Uint8 *data, unsigned size) 173{ 174 int transferred; 175 int total_transferred = 0; 176 int res; 177 178 while (size > 0) { 179 unsigned current_read = size; 180 if (current_read > 64) { 181 current_read = 64; 182 } 183 res = ctx->libusb->bulk_transfer(ctx->device_handle, 184 ctx->in_endpoint, 185 data, 186 current_read, 187 &transferred, 188 100); 189 if (res < 0) { 190 return res; 191 } 192 total_transferred += transferred; 193 size -= transferred; 194 data += current_read; 195 if ((unsigned) transferred < current_read) { 196 break; 197 } 198 } 199 200 return total_transferred; 201} 202 203static void MapJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, const Switch2_AxisCalibration *calib, float value, bool invert) 204{ 205 Sint16 mapped_value; 206 if (calib && calib->neutral && calib->min && calib->max) { 207 value -= calib->neutral; 208 if (value < 0) { 209 value /= calib->min; 210 } else { 211 value /= calib->max; 212 } 213 mapped_value = (Sint16) SDL_clamp(value * SDL_MAX_SINT16, SDL_MIN_SINT16, SDL_MAX_SINT16); 214 } else { 215 mapped_value = (Sint16) HIDAPI_RemapVal(value, 0, 4096, SDL_MIN_SINT16, SDL_MAX_SINT16); 216 } 217 if (invert) { 218 mapped_value = ~mapped_value; 219 } 220 SDL_SendJoystickAxis(timestamp, joystick, axis, mapped_value); 221} 222 223static void MapTriggerAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, Uint8 max, float value) 224{ 225 Sint16 mapped_value = (Sint16) HIDAPI_RemapVal( 226 SDL_clamp((value - max) / (232.f - max), 0, 1), 227 0, 1, 228 SDL_MIN_SINT16, SDL_MAX_SINT16 229 ); 230 SDL_SendJoystickAxis(timestamp, joystick, axis, mapped_value); 231} 232 233static bool UpdateSlotLED(SDL_DriverSwitch2_Context *ctx) 234{ 235 Uint8 set_led_data[] = { 236 0x09, 0x91, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 238 }; 239 Uint8 reply[8] = {0}; 240 const Uint8 player_pattern[] = { 0x1, 0x3, 0x7, 0xf, 0x9, 0x5, 0xd, 0x6 }; 241 242 if (ctx->player_lights && ctx->player_index >= 0) { 243 set_led_data[8] = player_pattern[ctx->player_index % 8]; 244 } 245 int res = SendBulkData(ctx, set_led_data, sizeof(set_led_data)); 246 if (res < 0) { 247 return SDL_SetError("Couldn't set LED data: %d\n", res); 248 } 249 return (RecvBulkData(ctx, reply, sizeof(reply)) > 0); 250} 251 252static int ReadFlashBlock(SDL_DriverSwitch2_Context *ctx, Uint32 address, Uint8 *out) 253{ 254 Uint8 flash_read_command[] = { 255 0x02, 0x91, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 257 }; 258 Uint8 buffer[0x50] = {0}; 259 int res; 260 261 flash_read_command[12] = (Uint8)address; 262 flash_read_command[13] = (Uint8)(address >> 8); 263 flash_read_command[14] = (Uint8)(address >> 16); 264 flash_read_command[15] = (Uint8)(address >> 24); 265 266 res = SendBulkData(ctx, flash_read_command, sizeof(flash_read_command)); 267 if (res < 0) { 268 return res; 269 } 270 271 res = RecvBulkData(ctx, buffer, sizeof(buffer)); 272 if (res < 0) { 273 return res; 274 } 275 276 SDL_memcpy(out, &buffer[0x10], 0x40); 277 return 0; 278} 279 280static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 281{ 282 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)userdata; 283 bool player_lights = SDL_GetStringBoolean(hint, true); 284 285 if (player_lights != ctx->player_lights) { 286 ctx->player_lights = player_lights; 287 288 UpdateSlotLED(ctx); 289 HIDAPI_UpdateDeviceProperties(ctx->device); 290 } 291} 292 293static void HIDAPI_DriverSwitch2_RegisterHints(SDL_HintCallback callback, void *userdata) 294{ 295 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH2, callback, userdata); 296} 297 298static void HIDAPI_DriverSwitch2_UnregisterHints(SDL_HintCallback callback, void *userdata) 299{ 300 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH2, callback, userdata); 301} 302 303static bool HIDAPI_DriverSwitch2_IsEnabled(void) 304{ 305 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SWITCH2, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)); 306} 307 308static bool HIDAPI_DriverSwitch2_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) 309{ 310 if (vendor_id == USB_VENDOR_NINTENDO) { 311 switch (product_id) { 312 case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER: 313 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT: 314 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT: 315 case USB_PRODUCT_NINTENDO_SWITCH2_PRO: 316 return true; 317 } 318 } 319 320 return false; 321} 322 323static bool HIDAPI_DriverSwitch2_InitBluetooth(SDL_HIDAPI_Device *device) 324{ 325 // FIXME: Need to add Bluetooth support 326 return SDL_SetError("Nintendo Switch2 controllers not supported over Bluetooth"); 327} 328 329static bool FindBulkEndpoints(SDL_LibUSBContext *libusb, libusb_device_handle *handle, Uint8 *bInterfaceNumber, Uint8 *out_endpoint, Uint8 *in_endpoint) 330{ 331 struct libusb_config_descriptor *config; 332 int found = 0; 333 334 if (libusb->get_config_descriptor(libusb->get_device(handle), 0, &config) != 0) { 335 return false; 336 } 337 338 for (int i = 0; i < config->bNumInterfaces; i++) { 339 const struct libusb_interface *iface = &config->interface[i]; 340 for (int j = 0; j < iface->num_altsetting; j++) { 341 const struct libusb_interface_descriptor *altsetting = &iface->altsetting[j]; 342 if (altsetting->bInterfaceNumber == 1) { 343 for (int k = 0; k < altsetting->bNumEndpoints; k++) { 344 const struct libusb_endpoint_descriptor *ep = &altsetting->endpoint[k]; 345 if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) { 346 *bInterfaceNumber = altsetting->bInterfaceNumber; 347 if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) { 348 *out_endpoint = ep->bEndpointAddress; 349 found |= 1; 350 } 351 if ((ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) { 352 *in_endpoint = ep->bEndpointAddress; 353 found |= 2; 354 } 355 if (found == 3) { 356 libusb->free_config_descriptor(config); 357 return true; 358 } 359 } 360 } 361 } 362 } 363 } 364 libusb->free_config_descriptor(config); 365 return false; 366} 367 368static bool HIDAPI_DriverSwitch2_InitUSB(SDL_HIDAPI_Device *device) 369{ 370 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 371 372 if (!SDL_InitLibUSB(&ctx->libusb)) { 373 return false; 374 } 375 376 ctx->device_handle = (libusb_device_handle *)SDL_GetPointerProperty(SDL_hid_get_properties(device->dev), SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER, NULL); 377 if (!ctx->device_handle) { 378 return SDL_SetError("Couldn't get libusb device handle"); 379 } 380 381 if (!FindBulkEndpoints(ctx->libusb, ctx->device_handle, &ctx->interface_number, &ctx->out_endpoint, &ctx->in_endpoint)) { 382 return SDL_SetError("Couldn't find bulk endpoints"); 383 } 384 385 ctx->libusb->set_auto_detach_kernel_driver(ctx->device_handle, true); 386 int res = ctx->libusb->claim_interface(ctx->device_handle, ctx->interface_number); 387 if (res < 0) { 388 return SDL_SetError("Couldn't claim interface %d: %d\n", ctx->interface_number, res); 389 } 390 ctx->interface_claimed = true; 391 392 const Uint8 *init_sequence[] = { 393 (Uint8[]) { // Unknown purpose 394 0x7, 0x91, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 395 }, 396 (Uint8[]) { // Set feature output bit mask 397 0x0c, 0x91, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00 398 }, 399 (Uint8[]) { // Unknown purpose 400 0x11, 0x91, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 401 }, 402 (Uint8[]) { // Set rumble data? 403 0x0a, 0x91, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 404 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 405 0xff, 0x35, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 406 0x00, 0x00, 0x00, 0x00 407 }, 408 (Uint8[]) { // Enable feature output bits 409 0x0c, 0x91, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00 410 }, 411 (Uint8[]) { // Unknown purpose 412 0x01, 0x91, 0x0, 0xc, 0x0, 0x0, 0x0, 0x0, 413 }, 414 (Uint8[]) { // Enable rumble 415 0x01, 0x91, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 416 }, 417 (Uint8[]) { // Enable grip buttons on charging grip 418 0x8, 0x91, 0x0, 0x2, 0x0, 0x4, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 419 }, 420 (Uint8[]) { // Set report format 421 0x03, 0x91, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 422 0x05, 0x00, 0x00, 0x00 423 }, 424 (Uint8[]) { // Start output 425 0x03, 0x91, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 426 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 427 }, 428 NULL, // Sentinel 429 }; 430 431 unsigned char calibration_data[0x40] = {0}; 432 433 res = ReadFlashBlock(ctx, 0x13000, calibration_data); 434 if (res < 0) { 435 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read serial number: %d", res); 436 } else { 437 char serial[0x11] = {0}; 438 SDL_strlcpy(serial, (char*)&calibration_data[2], sizeof(serial)); 439 HIDAPI_SetDeviceSerial(device, serial); 440 } 441 442 res = ReadFlashBlock(ctx, 0x13040, calibration_data); 443 if (res < 0) { 444 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); 445 } else { 446 ctx->gyro_bias_x = *(float*)&calibration_data[4]; 447 ctx->gyro_bias_y = *(float*)&calibration_data[8]; 448 ctx->gyro_bias_z = *(float*)&calibration_data[12]; 449 } 450 451 res = ReadFlashBlock(ctx, 0x13080, calibration_data); 452 if (res < 0) { 453 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); 454 } else { 455 ParseStickCalibration(&ctx->left_stick, &calibration_data[0x28]); 456 } 457 458 res = ReadFlashBlock(ctx, 0x130C0, calibration_data); 459 if (res < 0) { 460 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); 461 } else { 462 ParseStickCalibration(&ctx->right_stick, &calibration_data[0x28]); 463 } 464 465 res = ReadFlashBlock(ctx, 0x13100, calibration_data); 466 if (res < 0) { 467 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); 468 } else { 469 ctx->accel_bias_x = *(float*)&calibration_data[12]; 470 ctx->accel_bias_y = *(float*)&calibration_data[16]; 471 ctx->accel_bias_z = *(float*)&calibration_data[20]; 472 } 473 474 if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER) { 475 res = ReadFlashBlock(ctx, 0x13140, calibration_data); 476 if (res < 0) { 477 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read factory calibration data: %d", res); 478 } else { 479 ctx->left_trigger_zero = calibration_data[0]; 480 ctx->right_trigger_zero = calibration_data[1]; 481 } 482 } 483 484 res = ReadFlashBlock(ctx, 0x1FC040, calibration_data); 485 if (res < 0) { 486 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read user calibration data: %d", res); 487 } else if (calibration_data[0] == 0xb2 && calibration_data[1] == 0xa1) { 488 ParseStickCalibration(&ctx->left_stick, &calibration_data[2]); 489 } 490 491 res = ReadFlashBlock(ctx, 0x1FC080, calibration_data); 492 if (res < 0) { 493 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't read user calibration data: %d", res); 494 } else if (calibration_data[0] == 0xb2 && calibration_data[1] == 0xa1) { 495 ParseStickCalibration(&ctx->right_stick, &calibration_data[2]); 496 } 497 498 for (int i = 0; init_sequence[i]; i++) { 499 res = SendBulkData(ctx, init_sequence[i], init_sequence[i][5] + 8); 500 if (res < 0) { 501 return SDL_SetError("Couldn't send initialization data: %d\n", res); 502 } 503 RecvBulkData(ctx, calibration_data, 0x40); 504 } 505 506 return true; 507} 508 509static bool HIDAPI_DriverSwitch2_InitDevice(SDL_HIDAPI_Device *device) 510{ 511 SDL_DriverSwitch2_Context *ctx; 512 513 ctx = (SDL_DriverSwitch2_Context *)SDL_calloc(1, sizeof(*ctx)); 514 if (!ctx) { 515 return false; 516 } 517 ctx->device = device; 518 device->context = ctx; 519 520 if (device->is_bluetooth) { 521 if (!HIDAPI_DriverSwitch2_InitBluetooth(device)) { 522 return false; 523 } 524 } else { 525 if (!HIDAPI_DriverSwitch2_InitUSB(device)) { 526 return false; 527 } 528 } 529 530 ctx->sensor_ts_coeff = 10000; 531 ctx->gyro_coeff = 34.8f; 532 533 // Sometimes the device handle isn't available during enumeration so we don't get the device name, so set it explicitly 534 switch (device->product_id) { 535 case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER: 536 HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller"); 537 break; 538 case USB_PRODUCT_NINTENDO_SWITCH2_PRO: 539 HIDAPI_SetDeviceName(device, "Nintendo Switch Pro Controller"); 540 break; 541 default: 542 break; 543 } 544 return HIDAPI_JoystickConnected(device, NULL); 545} 546 547static int HIDAPI_DriverSwitch2_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 548{ 549 return -1; 550} 551 552static void HIDAPI_DriverSwitch2_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 553{ 554 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 555 556 if (!ctx->joystick) { 557 return; 558 } 559 560 ctx->player_index = player_index; 561 562 UpdateSlotLED(ctx); 563} 564 565static bool HIDAPI_DriverSwitch2_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 566{ 567 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 568 569 ctx->joystick = joystick; 570 571 // Initialize player index (needed for setting LEDs) 572 ctx->player_index = SDL_GetJoystickPlayerIndex(joystick); 573 ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, true); 574 UpdateSlotLED(ctx); 575 576 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, 577 SDL_PlayerLEDHintChanged, ctx); 578 579 // Initialize the joystick capabilities 580 if (!ctx->device->parent) { 581 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); 582 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); 583 } 584 switch (device->product_id) { 585 case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER: 586 joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_GAMECUBE_BUTTONS; 587 break; 588 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT: 589 if (ctx->device->parent) { 590 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO_L, 250.0f); 591 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL_L, 250.0f); 592 } 593 joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_JOYCON_BUTTONS; 594 break; 595 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT: 596 if (ctx->device->parent) { 597 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); 598 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); 599 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO_R, 250.0f); 600 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL_R, 250.0f); 601 } 602 joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_JOYCON_BUTTONS; 603 break; 604 case USB_PRODUCT_NINTENDO_SWITCH2_PRO: 605 joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_PRO_BUTTONS; 606 break; 607 default: 608 // FIXME: How many buttons does this have? 609 break; 610 } 611 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 612 joystick->nhats = 1; 613 614 ctx->rumble_hi_freq = 0x187; 615 ctx->rumble_lo_freq = 0x112; 616 617 // Set up for vertical mode 618 ctx->vertical_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, false); 619 620 return true; 621} 622 623static bool HIDAPI_DriverSwitch2_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 624{ 625 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 626 627 if (low_frequency_rumble != ctx->rumble_lo_amp || high_frequency_rumble != ctx->rumble_hi_amp) { 628 ctx->rumble_lo_amp = low_frequency_rumble; 629 ctx->rumble_hi_amp = high_frequency_rumble; 630 ctx->rumble_updated = true; 631 } 632 633 return true; 634} 635 636static bool HIDAPI_DriverSwitch2_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 637{ 638 return SDL_Unsupported(); 639} 640 641static Uint32 HIDAPI_DriverSwitch2_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 642{ 643 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 644 Uint32 result = SDL_JOYSTICK_CAP_RUMBLE; 645 646 if (ctx->player_lights) { 647 result |= SDL_JOYSTICK_CAP_PLAYER_LED; 648 } 649 return result; 650} 651 652static bool HIDAPI_DriverSwitch2_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 653{ 654 return SDL_Unsupported(); 655} 656 657static bool HIDAPI_DriverSwitch2_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) 658{ 659 return SDL_Unsupported(); 660} 661 662static bool HIDAPI_DriverSwitch2_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 663{ 664 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 665 if (ctx->sensors_ready) { 666 Uint8 data[] = { 667 0x0c, 0x91, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00 668 }; 669 unsigned char reply[12] = {0}; 670 671 if (enabled) { 672 data[8] |= 4; 673 } 674 int res = SendBulkData(ctx, data, sizeof(data)); 675 if (res < 0) { 676 return SDL_SetError("Couldn't set sensors enabled: %d\n", res); 677 } 678 RecvBulkData(ctx, reply, sizeof(reply)); 679 } 680 ctx->sensors_enabled = true; 681 return true; 682} 683 684static void HandleGameCubeState(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 685{ 686 687 if (data[5] != ctx->last_state[5]) { 688 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[5] & 0x01) != 0)); 689 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[5] & 0x02) != 0)); 690 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[5] & 0x04) != 0)); 691 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[5] & 0x08) != 0)); 692 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_TRIGGER, ((data[5] & 0x40) != 0)); 693 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_RIGHT_SHOULDER, ((data[5] & 0x80) != 0)); 694 } 695 696 if (data[6] != ctx->last_state[6]) { 697 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_START, ((data[6] & 0x02) != 0)); 698 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_GUIDE, ((data[6] & 0x10) != 0)); 699 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_SHARE, ((data[6] & 0x20) != 0)); 700 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_C, ((data[6] & 0x40) != 0)); 701 } 702 703 if (data[7] != ctx->last_state[7]) { 704 Uint8 hat = 0; 705 706 if (data[7] & 0x01) { 707 hat |= SDL_HAT_DOWN; 708 } 709 if (data[7] & 0x02) { 710 hat |= SDL_HAT_UP; 711 } 712 if (data[7] & 0x04) { 713 hat |= SDL_HAT_RIGHT; 714 } 715 if (data[7] & 0x08) { 716 hat |= SDL_HAT_LEFT; 717 } 718 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 719 720 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_TRIGGER, ((data[7] & 0x40) != 0)); 721 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_GAMECUBE_LEFT_SHOULDER, ((data[7] & 0x80) != 0)); 722 } 723 724 MapTriggerAxis( 725 timestamp, 726 joystick, 727 SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 728 ctx->left_trigger_zero, 729 data[61] 730 ); 731 MapTriggerAxis( 732 timestamp, 733 joystick, 734 SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 735 ctx->right_trigger_zero, 736 data[62] 737 ); 738 739 MapJoystickAxis( 740 timestamp, 741 joystick, 742 SDL_GAMEPAD_AXIS_LEFTX, 743 &ctx->left_stick.x, 744 (float) (data[11] | ((data[12] & 0x0F) << 8)), 745 false 746 ); 747 MapJoystickAxis( 748 timestamp, 749 joystick, 750 SDL_GAMEPAD_AXIS_LEFTY, 751 &ctx->left_stick.y, 752 (float) ((data[12] >> 4) | (data[13] << 4)), 753 true 754 ); 755 MapJoystickAxis( 756 timestamp, 757 joystick, 758 SDL_GAMEPAD_AXIS_RIGHTX, 759 &ctx->right_stick.x, 760 (float) (data[14] | ((data[15] & 0x0F) << 8)), 761 false 762 ); 763 MapJoystickAxis( 764 timestamp, 765 joystick, 766 SDL_GAMEPAD_AXIS_RIGHTY, 767 &ctx->right_stick.y, 768 (float)((data[15] >> 4) | (data[16] << 4)), 769 true 770 ); 771} 772 773static void HandleCombinedControllerStateL(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 774{ 775 if (data[6] != ctx->last_state[6]) { 776 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[6] & 0x01) != 0)); 777 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[6] & 0x08) != 0)); 778 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_SHARE, ((data[6] & 0x20) != 0)); 779 } 780 781 if (data[7] != ctx->last_state[7]) { 782 Uint8 hat = 0; 783 784 if (data[7] & 0x01) { 785 hat |= SDL_HAT_DOWN; 786 } 787 if (data[7] & 0x02) { 788 hat |= SDL_HAT_UP; 789 } 790 if (data[7] & 0x04) { 791 hat |= SDL_HAT_RIGHT; 792 } 793 if (data[7] & 0x08) { 794 hat |= SDL_HAT_LEFT; 795 } 796 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 797 798 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[7] & 0x40) != 0)); 799 } 800 801 if (data[8] != ctx->last_state[8]) { 802 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE1, ((data[8] & 0x02) != 0)); 803 } 804 805 Sint16 axis = (data[7] & 0x80) ? 32767 : -32768; 806 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 807 808 MapJoystickAxis( 809 timestamp, 810 joystick, 811 SDL_GAMEPAD_AXIS_LEFTX, 812 &ctx->left_stick.x, 813 (float) (data[11] | ((data[12] & 0x0F) << 8)), 814 false 815 ); 816 MapJoystickAxis( 817 timestamp, 818 joystick, 819 SDL_GAMEPAD_AXIS_LEFTY, 820 &ctx->left_stick.y, 821 (float) ((data[12] >> 4) | (data[13] << 4)), 822 true 823 ); 824} 825 826static void HandleMiniControllerStateL(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 827{ 828 if (data[6] != ctx->last_state[6]) { 829 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[6] & 0x01) != 0)); 830 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[6] & 0x08) != 0)); 831 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[6] & 0x20) != 0)); 832 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_SHARE, ((data[6] & 0x10) != 0)); 833 } 834 835 if (data[7] != ctx->last_state[7]) { 836 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[7] & 0x01) != 0)); 837 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[7] & 0x02) != 0)); 838 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[7] & 0x04) != 0)); 839 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[7] & 0x08) != 0)); 840 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[7] & 0x10) != 0)); 841 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[7] & 0x20) != 0)); 842 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE1, ((data[7] & 0x40) != 0)); 843 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_LEFT_PADDLE2, ((data[7] & 0x80) != 0)); 844 } 845 846 MapJoystickAxis( 847 timestamp, 848 joystick, 849 SDL_GAMEPAD_AXIS_LEFTX, 850 &ctx->left_stick.y, 851 (float) ((data[12] >> 4) | (data[13] << 4)), 852 true 853 ); 854 MapJoystickAxis( 855 timestamp, 856 joystick, 857 SDL_GAMEPAD_AXIS_LEFTY, 858 &ctx->left_stick.x, 859 (float) (data[11] | ((data[12] & 0x0F) << 8)), 860 true 861 ); 862} 863 864static void HandleCombinedControllerStateR(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 865{ 866 if (data[5] != ctx->last_state[5]) { 867 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[5] & 0x01) != 0)); 868 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[5] & 0x02) != 0)); 869 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[5] & 0x04) != 0)); 870 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[5] & 0x08) != 0)); 871 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[5] & 0x40) != 0)); 872 } 873 874 if (data[6] != ctx->last_state[6]) { 875 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[6] & 0x02) != 0)); 876 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[6] & 0x04) != 0)); 877 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[6] & 0x10) != 0)); 878 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C, ((data[6] & 0x40) != 0)); 879 } 880 881 if (data[8] != ctx->last_state[8]) { 882 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE1, ((data[8] & 0x01) != 0)); 883 } 884 885 Sint16 axis = (data[5] & 0x80) ? 32767 : -32768; 886 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 887 888 MapJoystickAxis( 889 timestamp, 890 joystick, 891 SDL_GAMEPAD_AXIS_RIGHTX, 892 &ctx->left_stick.x, 893 (float) (data[14] | ((data[15] & 0x0F) << 8)), 894 false 895 ); 896 MapJoystickAxis( 897 timestamp, 898 joystick, 899 SDL_GAMEPAD_AXIS_RIGHTY, 900 &ctx->left_stick.y, 901 (float)((data[15] >> 4) | (data[16] << 4)), 902 true 903 ); 904} 905 906static void HandleMiniControllerStateR(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 907{ 908 if (data[5] != ctx->last_state[5]) { 909 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[5] & 0x01) != 0)); 910 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[5] & 0x02) != 0)); 911 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[5] & 0x04) != 0)); 912 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[5] & 0x08) != 0)); 913 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[5] & 0x10) != 0)); 914 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[5] & 0x20) != 0)); 915 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE1, ((data[5] & 0x40) != 0)); 916 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_RIGHT_PADDLE2, ((data[5] & 0x80) != 0)); 917 } 918 919 if (data[6] != ctx->last_state[6]) { 920 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[6] & 0x02) != 0)); 921 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[6] & 0x04) != 0)); 922 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[6] & 0x10) != 0)); 923 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_JOYCON_C, ((data[6] & 0x40) != 0)); 924 } 925 926 MapJoystickAxis( 927 timestamp, 928 joystick, 929 SDL_GAMEPAD_AXIS_LEFTX, 930 &ctx->left_stick.y, 931 (float)((data[15] >> 4) | (data[16] << 4)), 932 false 933 ); 934 MapJoystickAxis( 935 timestamp, 936 joystick, 937 SDL_GAMEPAD_AXIS_LEFTY, 938 &ctx->left_stick.x, 939 (float) (data[14] | ((data[15] & 0x0F) << 8)), 940 false 941 ); 942} 943 944static void HandleSwitchProState(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 945{ 946 Sint16 axis; 947 948 if (data[5] != ctx->last_state[5]) { 949 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[5] & 0x01) != 0)); 950 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[5] & 0x02) != 0)); 951 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[5] & 0x04) != 0)); 952 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[5] & 0x08) != 0)); 953 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[5] & 0x40) != 0)); 954 } 955 956 if (data[6] != ctx->last_state[6]) { 957 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[6] & 0x01) != 0)); 958 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[6] & 0x02) != 0)); 959 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[6] & 0x04) != 0)); 960 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[6] & 0x08) != 0)); 961 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[6] & 0x10) != 0)); 962 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_SHARE, ((data[6] & 0x20) != 0)); 963 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_C, ((data[6] & 0x40) != 0)); 964 } 965 966 if (data[7] != ctx->last_state[7]) { 967 Uint8 hat = 0; 968 969 if (data[7] & 0x01) { 970 hat |= SDL_HAT_DOWN; 971 } 972 if (data[7] & 0x02) { 973 hat |= SDL_HAT_UP; 974 } 975 if (data[7] & 0x04) { 976 hat |= SDL_HAT_RIGHT; 977 } 978 if (data[7] & 0x08) { 979 hat |= SDL_HAT_LEFT; 980 } 981 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 982 983 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[7] & 0x40) != 0)); 984 } 985 986 if (data[8] != ctx->last_state[8]) { 987 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_RIGHT_PADDLE, ((data[8] & 0x01) != 0)); 988 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_PRO_LEFT_PADDLE, ((data[8] & 0x02) != 0)); 989 } 990 991 axis = (data[5] & 0x80) ? 32767 : -32768; 992 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 993 994 axis = (data[7] & 0x80) ? 32767 : -32768; 995 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 996 997 MapJoystickAxis( 998 timestamp, 999 joystick, 1000 SDL_GAMEPAD_AXIS_LEFTX, 1001 &ctx->left_stick.x, 1002 (float) (data[11] | ((data[12] & 0x0F) << 8)), 1003 false 1004 ); 1005 MapJoystickAxis( 1006 timestamp, 1007 joystick, 1008 SDL_GAMEPAD_AXIS_LEFTY, 1009 &ctx->left_stick.y, 1010 (float) ((data[12] >> 4) | (data[13] << 4)), 1011 true 1012 ); 1013 MapJoystickAxis( 1014 timestamp, 1015 joystick, 1016 SDL_GAMEPAD_AXIS_RIGHTX, 1017 &ctx->right_stick.x, 1018 (float) (data[14] | ((data[15] & 0x0F) << 8)), 1019 false 1020 ); 1021 MapJoystickAxis( 1022 timestamp, 1023 joystick, 1024 SDL_GAMEPAD_AXIS_RIGHTY, 1025 &ctx->right_stick.y, 1026 (float)((data[15] >> 4) | (data[16] << 4)), 1027 true 1028 ); 1029} 1030 1031static void EncodeHDRumble(Uint16 high_freq, Uint16 high_amp, Uint16 low_freq, Uint16 low_amp, Uint8 rumble_data[5]) 1032{ 1033 rumble_data[0] = (Uint8)(high_freq & 0xFF); 1034 rumble_data[1] = (Uint8)(((high_amp >> 4) & 0xfc) | ((high_freq >> 8) & 0x03)); 1035 rumble_data[2] = (Uint8)((high_amp >> 12) | (low_freq << 4)); 1036 rumble_data[3] = (Uint8)((low_amp & 0xc0) | ((low_freq >> 4) & 0x3f)); 1037 rumble_data[4] = (Uint8)(low_amp >> 8); 1038} 1039 1040static bool UpdateRumble(SDL_DriverSwitch2_Context *ctx) 1041{ 1042 if (!ctx->rumble_updated && !ctx->rumble_lo_amp && !ctx->rumble_hi_amp) { 1043 return true; 1044 } 1045 1046 Uint64 timestamp = SDL_GetTicks(); 1047 Uint64 interval = RUMBLE_INTERVAL; 1048 1049 if (timestamp < ctx->rumble_timestamp) { 1050 return true; 1051 } 1052 1053 if (!SDL_HIDAPI_LockRumble()) { 1054 return false; 1055 } 1056 1057 unsigned char rumble_data[64] = {0}; 1058 if (ctx->device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER) { 1059 Uint16 rumble_max = SDL_max(ctx->rumble_lo_amp, ctx->rumble_hi_amp); 1060 rumble_data[0x00] = 0x3; 1061 rumble_data[1] = 0x50 | (ctx->rumble_seq & 0xf); 1062 if (rumble_max == 0) { 1063 rumble_data[2] = 2; 1064 ctx->rumble_error = 0; 1065 } else { 1066 if (ctx->rumble_error < rumble_max) { 1067 rumble_data[2] = 1; 1068 ctx->rumble_error += UINT16_MAX - rumble_max; 1069 } else { 1070 rumble_data[2] = 0; 1071 ctx->rumble_error -= rumble_max; 1072 } 1073 } 1074 } else { 1075 // Rumble can get so strong that it might be dangerous to the controller... 1076 // This is a game controller, not a massage device, so let's clamp it somewhat 1077 Uint16 low_amp = (Uint16)((int)ctx->rumble_lo_amp * RUMBLE_MAX / UINT16_MAX); 1078 Uint16 high_amp = (Uint16)((int)ctx->rumble_hi_amp * RUMBLE_MAX / UINT16_MAX); 1079 rumble_data[0x01] = 0x50 | (ctx->rumble_seq & 0xf); 1080 EncodeHDRumble(ctx->rumble_hi_freq, high_amp, ctx->rumble_lo_freq, low_amp, &rumble_data[0x02]); 1081 switch (ctx->device->product_id) { 1082 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT: 1083 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT: 1084 if (ctx->device->parent) { 1085 // FIXME: This shouldn't be necessary, but the rumble thread appears to back up if we don't do this 1086 interval *= 2; 1087 } 1088 rumble_data[0] = 0x1; 1089 break; 1090 case USB_PRODUCT_NINTENDO_SWITCH2_PRO: 1091 rumble_data[0] = 0x2; 1092 SDL_memcpy(&rumble_data[0x11], &rumble_data[0x01], 6); 1093 break; 1094 } 1095 } 1096 ctx->rumble_seq++; 1097 ctx->rumble_updated = false; 1098 if (!ctx->rumble_lo_amp && !ctx->rumble_hi_amp) { 1099 ctx->rumble_timestamp = 0; 1100 } else { 1101 if (!ctx->rumble_timestamp) { 1102 ctx->rumble_timestamp = timestamp; 1103 } 1104 ctx->rumble_timestamp += interval; 1105 } 1106 1107 if (SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, rumble_data, sizeof(rumble_data)) != sizeof(rumble_data)) { 1108 return SDL_SetError("Couldn't send rumble packet"); 1109 } 1110 return true; 1111} 1112 1113static void HIDAPI_DriverSwitch2_HandleStatePacket(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_DriverSwitch2_Context *ctx, Uint8 *data, int size) 1114{ 1115 Uint64 timestamp = SDL_GetTicksNS(); 1116 1117 if (size < 64) { 1118 // We don't know how to handle this report 1119 return; 1120 } 1121 1122 switch (device->product_id) { 1123 case USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER: 1124 HandleGameCubeState(timestamp, joystick, ctx, data, size); 1125 break; 1126 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT: 1127 if (device->parent || ctx->vertical_mode) { 1128 HandleCombinedControllerStateL(timestamp, joystick, ctx, data, size); 1129 } else { 1130 HandleMiniControllerStateL(timestamp, joystick, ctx, data, size); 1131 } 1132 break; 1133 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT: 1134 if (device->parent || ctx->vertical_mode) { 1135 HandleCombinedControllerStateR(timestamp, joystick, ctx, data, size); 1136 } else { 1137 HandleMiniControllerStateR(timestamp, joystick, ctx, data, size); 1138 } 1139 break; 1140 case USB_PRODUCT_NINTENDO_SWITCH2_PRO: 1141 HandleSwitchProState(timestamp, joystick, ctx, data, size); 1142 break; 1143 default: 1144 // FIXME: Need state handling implementation 1145 break; 1146 } 1147 1148 Uint64 sensor_timestamp = (Uint32) (data[0x2b] | (data[0x2c] << 8U) | (data[0x2d] << 16U) | (data[0x2e] << 24U)); 1149 if (sensor_timestamp && !ctx->sensors_ready) { 1150 ctx->sample_count++; 1151 if (ctx->sample_count >= 5 && !ctx->first_sensor_timestamp) { 1152 ctx->first_sensor_timestamp = sensor_timestamp; 1153 ctx->sample_count = 0; 1154 } else if (ctx->sample_count == 100) { 1155 // Calculate timestamp coefficient 1156 // Timestamp are normally microseconds but sometimes it's something else for no apparent reason 1157 Uint64 coeff = 1000 * (sensor_timestamp - ctx->first_sensor_timestamp) / (ctx->sample_count * 4); 1158 if ((coeff + 100000) / 200000 == 5) { 1159 // Within 10% of 1000 1160 ctx->sensor_ts_coeff = 10000; 1161 ctx->gyro_coeff = 34.8f; 1162 ctx->sensors_ready = true; 1163 } else if (coeff != 0) { 1164 ctx->sensor_ts_coeff = 10000000000 / coeff; 1165 ctx->gyro_coeff = 40.0f; 1166 ctx->sensors_ready = true; 1167 } else { 1168 // Didn't get a valid reading, try again 1169 ctx->first_sensor_timestamp = 0; 1170 ctx->sample_count = 0; 1171 } 1172 1173 if (ctx->sensors_ready && !ctx->sensors_enabled) { 1174 Uint8 set_features[] = { 1175 0x0c, 0x91, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00 1176 }; 1177 unsigned char reply[12] = {0}; 1178 1179 SendBulkData(ctx, set_features, sizeof(set_features)); 1180 RecvBulkData(ctx, reply, sizeof(reply)); 1181 } 1182 } 1183 } 1184 if (ctx->sensors_enabled && sensor_timestamp && ctx->sensors_ready) { 1185 sensor_timestamp = sensor_timestamp * ctx->sensor_ts_coeff / 10; 1186 float accel_data[3]; 1187 float gyro_data[3]; 1188 const float g = 9.80665f; 1189 const float accel_scale = g * 8.f / INT16_MAX; 1190 1191 accel_data[0] = (Sint16)(data[0x31] | (data[0x32] << 8)) * accel_scale; 1192 accel_data[1] = (Sint16)(data[0x35] | (data[0x36] << 8)) * accel_scale; 1193 accel_data[2] = (Sint16)(data[0x33] | (data[0x34] << 8)) * -accel_scale; 1194 1195 gyro_data[0] = (Sint16)(data[0x37] | (data[0x38] << 8)) * ctx->gyro_coeff / INT16_MAX - ctx->gyro_bias_x; 1196 gyro_data[1] = (Sint16)(data[0x3b] | (data[0x3c] << 8)) * ctx->gyro_coeff / INT16_MAX - ctx->gyro_bias_z; 1197 gyro_data[2] = (Sint16)(data[0x39] | (data[0x3a] << 8)) * -ctx->gyro_coeff / INT16_MAX + ctx->gyro_bias_y; 1198 1199 switch (ctx->device->product_id) { 1200 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT: 1201 if (ctx->device->parent) { 1202 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO_L, sensor_timestamp, gyro_data, 3); 1203 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL_L, sensor_timestamp, accel_data, 3); 1204 } else { 1205 float tmp = -accel_data[0]; 1206 accel_data[0] = accel_data[2]; 1207 accel_data[2] = tmp; 1208 1209 tmp = -gyro_data[0]; 1210 gyro_data[0] = gyro_data[2]; 1211 gyro_data[2] = tmp; 1212 1213 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, gyro_data, 3); 1214 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, accel_data, 3); 1215 } 1216 break; 1217 case USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT: 1218 if (ctx->device->parent) { 1219 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, gyro_data, 3); 1220 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, accel_data, 3); 1221 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO_R, sensor_timestamp, gyro_data, 3); 1222 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL_R, sensor_timestamp, accel_data, 3); 1223 } else { 1224 float tmp = accel_data[0]; 1225 accel_data[0] = -accel_data[2]; 1226 accel_data[2] = tmp; 1227 1228 tmp = gyro_data[0]; 1229 gyro_data[0] = -gyro_data[2]; 1230 gyro_data[2] = tmp; 1231 1232 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, gyro_data, 3); 1233 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, accel_data, 3); 1234 } 1235 break; 1236 default: 1237 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, gyro_data, 3); 1238 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, accel_data, 3); 1239 break; 1240 } 1241 } 1242 1243 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 1244} 1245 1246static bool HIDAPI_DriverSwitch2_UpdateDevice(SDL_HIDAPI_Device *device) 1247{ 1248 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 1249 SDL_Joystick *joystick = NULL; 1250 Uint8 data[USB_PACKET_LENGTH]; 1251 int size = 0; 1252 1253 if (device->num_joysticks > 0) { 1254 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 1255 } else { 1256 return false; 1257 } 1258 1259 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 1260#ifdef DEBUG_SWITCH2_PROTOCOL 1261 if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT) { 1262 HIDAPI_DumpPacket("Nintendo Joy-Con(L) packet: size = %d", data, size); 1263 } else if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT) { 1264 HIDAPI_DumpPacket("Nintendo Joy-Con(R) packet: size = %d", data, size); 1265 } else { 1266 HIDAPI_DumpPacket("Nintendo Switch2 packet: size = %d", data, size); 1267 } 1268#endif 1269 if (!joystick) { 1270 continue; 1271 } 1272 1273 HIDAPI_DriverSwitch2_HandleStatePacket(device, joystick, ctx, data, size); 1274 1275 UpdateRumble(ctx); 1276 } 1277 1278 if (size < 0) { 1279 // Read error, device is disconnected 1280 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1281 } 1282 return (size >= 0); 1283} 1284 1285static void HIDAPI_DriverSwitch2_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1286{ 1287 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 1288 1289 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, 1290 SDL_PlayerLEDHintChanged, ctx); 1291 1292 ctx->joystick = NULL; 1293} 1294 1295static void HIDAPI_DriverSwitch2_FreeDevice(SDL_HIDAPI_Device *device) 1296{ 1297 SDL_DriverSwitch2_Context *ctx = (SDL_DriverSwitch2_Context *)device->context; 1298 1299 if (ctx) { 1300 if (ctx->interface_claimed) { 1301 ctx->libusb->release_interface(ctx->device_handle, ctx->interface_number); 1302 ctx->interface_claimed = false; 1303 } 1304 if (ctx->libusb) { 1305 SDL_QuitLibUSB(); 1306 ctx->libusb = NULL; 1307 } 1308 } 1309} 1310 1311SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch2 = { 1312 SDL_HINT_JOYSTICK_HIDAPI_SWITCH2, 1313 true, 1314 HIDAPI_DriverSwitch2_RegisterHints, 1315 HIDAPI_DriverSwitch2_UnregisterHints, 1316 HIDAPI_DriverSwitch2_IsEnabled, 1317 HIDAPI_DriverSwitch2_IsSupportedDevice, 1318 HIDAPI_DriverSwitch2_InitDevice, 1319 HIDAPI_DriverSwitch2_GetDevicePlayerIndex, 1320 HIDAPI_DriverSwitch2_SetDevicePlayerIndex, 1321 HIDAPI_DriverSwitch2_UpdateDevice, 1322 HIDAPI_DriverSwitch2_OpenJoystick, 1323 HIDAPI_DriverSwitch2_RumbleJoystick, 1324 HIDAPI_DriverSwitch2_RumbleJoystickTriggers, 1325 HIDAPI_DriverSwitch2_GetJoystickCapabilities, 1326 HIDAPI_DriverSwitch2_SetJoystickLED, 1327 HIDAPI_DriverSwitch2_SendJoystickEffect, 1328 HIDAPI_DriverSwitch2_SetJoystickSensorsEnabled, 1329 HIDAPI_DriverSwitch2_CloseJoystick, 1330 HIDAPI_DriverSwitch2_FreeDevice, 1331}; 1332 1333#endif // SDL_JOYSTICK_HIDAPI_SWITCH2 1334 1335#endif // SDL_JOYSTICK_HIDAPI 1336[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.