Atlas - SDL_hidapi_gamecube.c

Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 23580 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#include "SDL_internal.h" 22 23#ifdef SDL_JOYSTICK_HIDAPI 24 25#include "../../SDL_hints_c.h" 26#include "../../misc/SDL_libusb.h" 27#include "../SDL_sysjoystick.h" 28#include "SDL_hidapijoystick_c.h" 29#include "SDL_hidapi_rumble.h" 30#include "../../hidapi/SDL_hidapi_c.h" 31 32#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE 33 34// Define this if you want to log all packets from the controller 35#if 0 36#define DEBUG_GAMECUBE_PROTOCOL 37#endif 38 39#define MAX_CONTROLLERS 4 40 41typedef struct 42{ 43 bool pc_mode; 44 SDL_JoystickID joysticks[MAX_CONTROLLERS]; 45 Uint8 wireless[MAX_CONTROLLERS]; 46 Uint8 min_axis[MAX_CONTROLLERS * SDL_GAMEPAD_AXIS_COUNT]; 47 Uint8 max_axis[MAX_CONTROLLERS * SDL_GAMEPAD_AXIS_COUNT]; 48 Uint8 rumbleAllowed[MAX_CONTROLLERS]; 49 Uint8 rumble[1 + MAX_CONTROLLERS]; 50 // Without this variable, hid_write starts to lag a TON 51 bool rumbleUpdate; 52 bool useRumbleBrake; 53} SDL_DriverGameCube_Context; 54 55static void HIDAPI_DriverGameCube_RegisterHints(SDL_HintCallback callback, void *userdata) 56{ 57 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata); 58} 59 60static void HIDAPI_DriverGameCube_UnregisterHints(SDL_HintCallback callback, void *userdata) 61{ 62 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata); 63} 64 65static bool HIDAPI_DriverGameCube_IsEnabled(void) 66{ 67 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, 68 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, 69 SDL_HIDAPI_DEFAULT)); 70} 71 72static bool HIDAPI_DriverGameCube_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) 73{ 74 if (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) { 75 // Nintendo Co., Ltd. Wii U GameCube Controller Adapter 76 return true; 77 } 78 if (vendor_id == USB_VENDOR_DRAGONRISE && 79 (product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER1 || 80 product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2 || 81 product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3)) { 82 // EVORETRO GameCube Controller Adapter 83 return true; 84 } 85 return false; 86} 87 88static void ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index) 89{ 90 SDL_memset(&ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_COUNT], 128 - 88, SDL_GAMEPAD_AXIS_COUNT); 91 SDL_memset(&ctx->max_axis[joystick_index * SDL_GAMEPAD_AXIS_COUNT], 128 + 88, SDL_GAMEPAD_AXIS_COUNT); 92 93 // Trigger axes may have a higher resting value 94 ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_COUNT + SDL_GAMEPAD_AXIS_LEFT_TRIGGER] = 40; 95 ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_COUNT + SDL_GAMEPAD_AXIS_RIGHT_TRIGGER] = 40; 96} 97 98static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 99{ 100 if (hint) { 101 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)userdata; 102 ctx->useRumbleBrake = SDL_GetStringBoolean(hint, false); 103 } 104} 105 106static bool HIDAPI_DriverGameCube_EnableAdapter(SDL_HIDAPI_Device *device) 107{ 108#ifdef HAVE_LIBUSB 109 // Need to close the device while sending USB commands to it 110 SDL_hid_close(device->dev); 111 112 // This is needed to enable input for Nyko and EVORETRO GameCube adapters 113 SDL_LibUSBContext *libusb_ctx; 114 if (SDL_InitLibUSB(&libusb_ctx)) { 115 libusb_context *context = NULL; 116 libusb_device **devs = NULL; 117 libusb_device_handle *handle = NULL; 118 struct libusb_device_descriptor desc; 119 ssize_t i, num_devs; 120 bool kernel_detached = false; 121 122 if (libusb_ctx->init(&context) == 0) { 123 num_devs = libusb_ctx->get_device_list(context, &devs); 124 for (i = 0; i < num_devs; ++i) { 125 if (libusb_ctx->get_device_descriptor(devs[i], &desc) != 0) { 126 continue; 127 } 128 129 if (desc.idVendor != USB_VENDOR_NINTENDO || 130 desc.idProduct != USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) { 131 continue; 132 } 133 134 if (libusb_ctx->open(devs[i], &handle) != 0) { 135 continue; 136 } 137 138 if (libusb_ctx->kernel_driver_active(handle, 0)) { 139 if (libusb_ctx->detach_kernel_driver(handle, 0) == 0) { 140 kernel_detached = true; 141 } 142 } 143 144 if (libusb_ctx->claim_interface(handle, 0) == 0) { 145 libusb_ctx->control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000); 146 libusb_ctx->release_interface(handle, 0); 147 } 148 149 if (kernel_detached) { 150 libusb_ctx->attach_kernel_driver(handle, 0); 151 } 152 153 libusb_ctx->close(handle); 154 } 155 156 libusb_ctx->free_device_list(devs, 1); 157 158 libusb_ctx->exit(context); 159 } 160 SDL_QuitLibUSB(); 161 } 162 163 // Reopen the device now that we're done 164 device->dev = SDL_hid_open_path(device->path); 165 if (!device->dev) { 166 return false; 167 } 168#endif // HAVE_LIBUSB 169 170 Uint8 initMagic = 0x13; 171 if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) { 172 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 173 "HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028"); 174 return false; 175 } 176 177 // Wait for the adapter to initialize 178 SDL_Delay(10); 179 180 return true; 181} 182 183static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) 184{ 185 SDL_DriverGameCube_Context *ctx; 186 Uint8 packet[37]; 187 Uint8 *curSlot; 188 Uint8 i; 189 int size; 190 Uint8 rumbleMagic = 0x11; 191 192 ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx)); 193 if (!ctx) { 194 return false; 195 } 196 device->context = ctx; 197 198 ctx->rumble[0] = rumbleMagic; 199 200 if (device->vendor_id != USB_VENDOR_NINTENDO) { 201 ctx->pc_mode = true; 202 } 203 204 if (ctx->pc_mode) { 205#ifdef SDL_PLATFORM_WIN32 206 // We get a separate device for each slot 207 ResetAxisRange(ctx, 0); 208 HIDAPI_JoystickConnected(device, &ctx->joysticks[0]); 209#else 210 for (i = 0; i < MAX_CONTROLLERS; ++i) { 211 ResetAxisRange(ctx, i); 212 HIDAPI_JoystickConnected(device, &ctx->joysticks[i]); 213 } 214#endif 215 } else { 216 if (!HIDAPI_DriverGameCube_EnableAdapter(device)) { 217 return false; 218 } 219 220 // Add all the applicable joysticks 221 while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) { 222#ifdef DEBUG_GAMECUBE_PROTOCOL 223 HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size); 224#endif 225 if (size < 37 || packet[0] != 0x21) { 226 continue; // Nothing to do yet...? 227 } 228 229 // Go through all 4 slots 230 curSlot = packet + 1; 231 for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) { 232 ctx->wireless[i] = (curSlot[0] & 0x20) != 0; 233 234 // Only allow rumble if the adapter's second USB cable is connected 235 ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) && !ctx->wireless[i]; 236 237 if (curSlot[0] & 0x30) { // 0x10 - Wired, 0x20 - Wireless 238 if (ctx->joysticks[i] == 0) { 239 ResetAxisRange(ctx, i); 240 HIDAPI_JoystickConnected(device, &ctx->joysticks[i]); 241 } 242 } else { 243 if (ctx->joysticks[i] != 0) { 244 HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]); 245 ctx->joysticks[i] = 0; 246 } 247 continue; 248 } 249 } 250 } 251 } 252 253 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE_RUMBLE_BRAKE, 254 SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); 255 256 HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller"); 257 258 return true; 259} 260 261static int HIDAPI_DriverGameCube_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 262{ 263 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 264 Uint8 i; 265 266 for (i = 0; i < 4; ++i) { 267 if (instance_id == ctx->joysticks[i]) { 268 return i; 269 } 270 } 271 return -1; 272} 273 274static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 275{ 276} 277 278static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, Uint8 slot, const Uint8 *packet, bool invert_c_stick) 279{ 280 SDL_Joystick *joystick; 281 Uint8 i; 282 Uint8 v; 283 Sint16 axis_value; 284 Uint64 timestamp = SDL_GetTicksNS(); 285 286#ifdef SDL_PLATFORM_WIN32 287 // We get a separate device for each slot 288 i = 0; 289#else 290 i = slot; 291 if (i >= MAX_CONTROLLERS) { 292 // Invalid packet? 293 return; 294 } 295#endif 296 297 joystick = SDL_GetJoystickFromID(ctx->joysticks[i]); 298 if (!joystick) { 299 // Hasn't been opened yet, skip 300 return; 301 } 302 303#define READ_BUTTON(off, flag, button) \ 304 SDL_SendJoystickButton( \ 305 timestamp, \ 306 joystick, \ 307 button, \ 308 ((packet[off] & flag) != 0)); 309 READ_BUTTON(0, 0x02, 0) // A 310 READ_BUTTON(0, 0x04, 1) // B 311 READ_BUTTON(0, 0x08, 3) // Y 312 READ_BUTTON(0, 0x01, 2) // X 313 READ_BUTTON(1, 0x80, 4) // DPAD_LEFT 314 READ_BUTTON(1, 0x20, 5) // DPAD_RIGHT 315 READ_BUTTON(1, 0x40, 6) // DPAD_DOWN 316 READ_BUTTON(1, 0x10, 7) // DPAD_UP 317 READ_BUTTON(1, 0x02, 8) // START 318 READ_BUTTON(0, 0x80, 9) // RIGHTSHOULDER 319 /* These two buttons are for the bottoms of the analog triggers. 320 * More than likely, you're going to want to read the axes instead! 321 * -flibit 322 */ 323 READ_BUTTON(0, 0x20, 10) // TRIGGERRIGHT 324 READ_BUTTON(0, 0x10, 11) // TRIGGERLEFT 325#undef READ_BUTTON 326 327#define READ_AXIS(off, axis, invert) \ 328 v = (invert) ? (0xff - packet[off]) : packet[off]; \ 329 if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \ 330 ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \ 331 if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \ 332 ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \ 333 axis_value = (Sint16)HIDAPI_RemapVal(v, ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \ 334 SDL_SendJoystickAxis( \ 335 timestamp, \ 336 joystick, \ 337 axis, axis_value); 338 READ_AXIS(2, SDL_GAMEPAD_AXIS_LEFTX, 0) 339 READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTY, 1) 340 READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX, invert_c_stick ? 1 : 0) 341 READ_AXIS(4, SDL_GAMEPAD_AXIS_RIGHTY, invert_c_stick ? 0 : 1) 342 READ_AXIS(6, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0) 343 READ_AXIS(7, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0) 344#undef READ_AXIS 345} 346 347static void HIDAPI_DriverGameCube_HandleNintendoPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, Uint8 *packet, int size) 348{ 349 SDL_Joystick *joystick; 350 Uint8 *curSlot; 351 Uint8 i; 352 Sint16 axis_value; 353 Uint64 timestamp = SDL_GetTicksNS(); 354 355 if (size < 37 || packet[0] != 0x21) { 356 return; // Nothing to do right now...? 357 } 358 359 // Go through all 4 slots 360 curSlot = packet + 1; 361 for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) { 362 ctx->wireless[i] = (curSlot[0] & 0x20) != 0; 363 364 // Only allow rumble if the adapter's second USB cable is connected 365 ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) && !ctx->wireless[i]; 366 367 if (curSlot[0] & 0x30) { // 0x10 - Wired, 0x20 - Wireless 368 if (ctx->joysticks[i] == 0) { 369 ResetAxisRange(ctx, i); 370 HIDAPI_JoystickConnected(device, &ctx->joysticks[i]); 371 } 372 joystick = SDL_GetJoystickFromID(ctx->joysticks[i]); 373 374 // Hasn't been opened yet, skip 375 if (!joystick) { 376 continue; 377 } 378 } else { 379 if (ctx->joysticks[i] != 0) { 380 HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]); 381 ctx->joysticks[i] = 0; 382 } 383 continue; 384 } 385 386#define READ_BUTTON(off, flag, button) \ 387 SDL_SendJoystickButton( \ 388 timestamp, \ 389 joystick, \ 390 button, \ 391 ((curSlot[off] & flag) != 0)); 392 READ_BUTTON(1, 0x01, 0) // A 393 READ_BUTTON(1, 0x02, 1) // B 394 READ_BUTTON(1, 0x04, 2) // X 395 READ_BUTTON(1, 0x08, 3) // Y 396 READ_BUTTON(1, 0x10, 4) // DPAD_LEFT 397 READ_BUTTON(1, 0x20, 5) // DPAD_RIGHT 398 READ_BUTTON(1, 0x40, 6) // DPAD_DOWN 399 READ_BUTTON(1, 0x80, 7) // DPAD_UP 400 READ_BUTTON(2, 0x01, 8) // START 401 READ_BUTTON(2, 0x02, 9) // RIGHTSHOULDER 402 /* These two buttons are for the bottoms of the analog triggers. 403 * More than likely, you're going to want to read the axes instead! 404 * -flibit 405 */ 406 READ_BUTTON(2, 0x04, 10) // TRIGGERRIGHT 407 READ_BUTTON(2, 0x08, 11) // TRIGGERLEFT 408#undef READ_BUTTON 409 410#define READ_AXIS(off, axis) \ 411 if (curSlot[off] < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \ 412 ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = curSlot[off]; \ 413 if (curSlot[off] > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \ 414 ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = curSlot[off]; \ 415 axis_value = (Sint16)HIDAPI_RemapVal(curSlot[off], ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \ 416 SDL_SendJoystickAxis( \ 417 timestamp, \ 418 joystick, \ 419 axis, axis_value); 420 READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX) 421 READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY) 422 READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX) 423 READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTY) 424 READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) 425 READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) 426#undef READ_AXIS 427 } 428} 429 430static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device) 431{ 432 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 433 Uint8 packet[USB_PACKET_LENGTH]; 434 int size; 435 436 // Read input packet 437 while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) { 438#ifdef DEBUG_GAMECUBE_PROTOCOL 439 HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size); 440#endif 441 if (ctx->pc_mode) { 442 if (size == 10) { 443 // This is the older firmware 444 // The first byte is the index of the connected controller 445 // The C stick has an inverted value range compared to the left stick 446 HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet[0] - 1, &packet[1], true); 447 } else if (size == 9) { 448 // This is the newer firmware (version 0x7) 449 // The C stick has the same value range compared to the left stick 450 HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, 0, packet, false); 451 } else { 452 // How do we handle this packet? 453 } 454 } else { 455 HIDAPI_DriverGameCube_HandleNintendoPacket(device, ctx, packet, size); 456 } 457 } 458 459 // Write rumble packet 460 if (ctx->rumbleUpdate) { 461 SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble)); 462 ctx->rumbleUpdate = false; 463 } 464 465 // If we got here, nothing bad happened! 466 return true; 467} 468 469static bool HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 470{ 471 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 472 Uint8 i; 473 474 SDL_AssertJoysticksLocked(); 475 476 for (i = 0; i < MAX_CONTROLLERS; i += 1) { 477 if (joystick->instance_id == ctx->joysticks[i]) { 478 joystick->nbuttons = 12; 479 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 480 if (ctx->wireless[i]) { 481 joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS; 482 } else { 483 joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED; 484 } 485 return true; 486 } 487 } 488 return false; // Should never get here! 489} 490 491static bool HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 492{ 493 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 494 Uint8 i, val; 495 496 SDL_AssertJoysticksLocked(); 497 498 if (ctx->pc_mode) { 499 return SDL_Unsupported(); 500 } 501 502 for (i = 0; i < MAX_CONTROLLERS; i += 1) { 503 if (joystick->instance_id == ctx->joysticks[i]) { 504 if (ctx->wireless[i]) { 505 return SDL_SetError("Nintendo GameCube WaveBird controllers do not support rumble"); 506 } 507 if (!ctx->rumbleAllowed[i]) { 508 return SDL_SetError("Second USB cable for WUP-028 not connected"); 509 } 510 if (ctx->useRumbleBrake) { 511 if (low_frequency_rumble == 0 && high_frequency_rumble > 0) { 512 val = 0; // if only low is 0 we want to do a regular stop 513 } else if (low_frequency_rumble == 0 && high_frequency_rumble == 0) { 514 val = 2; // if both frequencies are 0 we want to do a hard stop 515 } else { 516 val = 1; // normal rumble 517 } 518 } else { 519 val = (low_frequency_rumble > 0 || high_frequency_rumble > 0); 520 } 521 if (val != ctx->rumble[i + 1]) { 522 ctx->rumble[i + 1] = val; 523 ctx->rumbleUpdate = true; 524 } 525 return true; 526 } 527 } 528 529 // Should never get here! 530 return SDL_SetError("Couldn't find joystick"); 531} 532 533static bool HIDAPI_DriverGameCube_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 534{ 535 return SDL_Unsupported(); 536} 537 538static Uint32 HIDAPI_DriverGameCube_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 539{ 540 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 541 Uint32 result = 0; 542 543 SDL_AssertJoysticksLocked(); 544 545 if (!ctx->pc_mode) { 546 Uint8 i; 547 548 for (i = 0; i < MAX_CONTROLLERS; i += 1) { 549 if (joystick->instance_id == ctx->joysticks[i]) { 550 if (!ctx->wireless[i] && ctx->rumbleAllowed[i]) { 551 result |= SDL_JOYSTICK_CAP_RUMBLE; 552 break; 553 } 554 } 555 } 556 } 557 558 return result; 559} 560 561static bool HIDAPI_DriverGameCube_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 562{ 563 return SDL_Unsupported(); 564} 565 566static bool HIDAPI_DriverGameCube_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) 567{ 568 return SDL_Unsupported(); 569} 570 571static bool HIDAPI_DriverGameCube_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 572{ 573 return SDL_Unsupported(); 574} 575 576static void HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 577{ 578 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 579 580 // Stop rumble activity 581 if (ctx->rumbleUpdate) { 582 SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble)); 583 ctx->rumbleUpdate = false; 584 } 585} 586 587static void HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device) 588{ 589 SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context; 590 591 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE_RUMBLE_BRAKE, 592 SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); 593} 594 595SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube = { 596 SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, 597 true, 598 HIDAPI_DriverGameCube_RegisterHints, 599 HIDAPI_DriverGameCube_UnregisterHints, 600 HIDAPI_DriverGameCube_IsEnabled, 601 HIDAPI_DriverGameCube_IsSupportedDevice, 602 HIDAPI_DriverGameCube_InitDevice, 603 HIDAPI_DriverGameCube_GetDevicePlayerIndex, 604 HIDAPI_DriverGameCube_SetDevicePlayerIndex, 605 HIDAPI_DriverGameCube_UpdateDevice, 606 HIDAPI_DriverGameCube_OpenJoystick, 607 HIDAPI_DriverGameCube_RumbleJoystick, 608 HIDAPI_DriverGameCube_RumbleJoystickTriggers, 609 HIDAPI_DriverGameCube_GetJoystickCapabilities, 610 HIDAPI_DriverGameCube_SetJoystickLED, 611 HIDAPI_DriverGameCube_SendJoystickEffect, 612 HIDAPI_DriverGameCube_SetJoystickSensorsEnabled, 613 HIDAPI_DriverGameCube_CloseJoystick, 614 HIDAPI_DriverGameCube_FreeDevice, 615}; 616 617#endif // SDL_JOYSTICK_HIDAPI_GAMECUBE 618 619#endif // SDL_JOYSTICK_HIDAPI 620
[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.