21 #include "../../SDL_internal.h"
23 #ifdef SDL_JOYSTICK_HIDAPI
32 #include "../../SDL_hints_c.h"
33 #include "../SDL_sysjoystick.h"
38 #ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
40 #define MAX_CONTROLLERS 4
44 Uint8 wireless[MAX_CONTROLLERS];
47 Uint8 rumbleAllowed[MAX_CONTROLLERS];
48 Uint8 rumble[1+MAX_CONTROLLERS];
52 } SDL_DriverGameCube_Context;
65 HIDAPI_DriverGameCube_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
67 return "Nintendo GameCube Controller";
71 ResetAxisRange(SDL_DriverGameCube_Context *
ctx,
int joystick_index)
81 static float fsel(
float fComparand,
float fValGE,
float fLT)
83 return fComparand >= 0 ? fValGE : fLT;
86 static float RemapVal(
float val,
float A,
float B,
float C,
float D)
89 return fsel(
val - B , D , C);
97 return C + (D - C) * (
val - A) / (B - A);
100 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(
void *userdata,
const char *
name,
const char *oldValue,
const char *hint)
102 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)userdata;
108 if (!
ctx->m_bUseButtonLabels) {
125 SDL_DriverGameCube_Context *
ctx;
130 Uint8 initMagic = 0x13;
131 Uint8 rumbleMagic = 0x11;
147 ctx->joysticks[0] = -1;
148 ctx->joysticks[1] = -1;
149 ctx->joysticks[2] = -1;
150 ctx->joysticks[3] = -1;
151 ctx->rumble[0] = rumbleMagic;
154 if (
hid_write(
device->dev, &initMagic,
sizeof(initMagic)) !=
sizeof(initMagic)) {
164 if (
size < 37 || packet[0] != 0x21) {
169 curSlot = packet + 1;
170 for (
i = 0;
i < MAX_CONTROLLERS;
i += 1, curSlot += 9) {
171 ctx->wireless[
i] = (curSlot[0] & 0x20) != 0;
174 ctx->rumbleAllowed[
i] = (curSlot[0] & 0x04) != 0 && !
ctx->wireless[
i];
176 if (curSlot[0] & 0x30) {
177 if (
ctx->joysticks[
i] == -1) {
178 ResetAxisRange(
ctx,
i);
182 if (
ctx->joysticks[
i] != -1) {
184 ctx->joysticks[
i] = -1;
192 SDL_GameControllerButtonReportingHintChanged,
ctx);
211 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
214 for (
i = 0;
i < 4; ++
i) {
215 if (instance_id ==
ctx->joysticks[
i]) {
230 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
231 SDL_Joystick *joystick;
240 if (
size < 37 || packet[0] != 0x21) {
245 curSlot = packet + 1;
246 for (
i = 0;
i < MAX_CONTROLLERS;
i += 1, curSlot += 9) {
247 ctx->wireless[
i] = (curSlot[0] & 0x20) != 0;
250 ctx->rumbleAllowed[
i] = (curSlot[0] & 0x04) != 0 && !
ctx->wireless[
i];
252 if (curSlot[0] & 0x30) {
253 if (
ctx->joysticks[
i] == -1) {
254 ResetAxisRange(
ctx,
i);
260 if (joystick ==
NULL) {
264 if (
ctx->joysticks[
i] != -1) {
266 ctx->joysticks[
i] = -1;
271 #define READ_BUTTON(off, flag, button) \
272 SDL_PrivateJoystickButton( \
274 RemapButton(ctx, button), \
275 (curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED \
277 READ_BUTTON(1, 0x01, 0)
278 READ_BUTTON(1, 0x04, 1)
279 READ_BUTTON(1, 0x02, 2)
280 READ_BUTTON(1, 0x08, 3)
281 READ_BUTTON(1, 0x10, 4)
282 READ_BUTTON(1, 0x20, 5)
283 READ_BUTTON(1, 0x40, 6)
284 READ_BUTTON(1, 0x80, 7)
285 READ_BUTTON(2, 0x01, 8)
286 READ_BUTTON(2, 0x02, 9)
291 READ_BUTTON(2, 0x04, 10)
292 READ_BUTTON(2, 0x08, 11)
295 #define READ_AXIS(off, axis) \
296 if (axis < SDL_CONTROLLER_AXIS_TRIGGERLEFT) \
297 if (curSlot[off] < ctx->min_axis[i*SDL_CONTROLLER_AXIS_MAX+axis]) ctx->min_axis[i*SDL_CONTROLLER_AXIS_MAX+axis] = curSlot[off]; \
298 if (curSlot[off] > ctx->max_axis[i*SDL_CONTROLLER_AXIS_MAX+axis]) ctx->max_axis[i*SDL_CONTROLLER_AXIS_MAX+axis] = curSlot[off]; \
299 axis_value = (Sint16)(RemapVal(curSlot[off], ctx->min_axis[i*SDL_CONTROLLER_AXIS_MAX+axis], ctx->max_axis[i*SDL_CONTROLLER_AXIS_MAX+axis], SDL_MIN_SINT16, SDL_MAX_SINT16)); \
300 SDL_PrivateJoystickAxis( \
315 if (
ctx->rumbleUpdate) {
316 SDL_HIDAPI_SendRumble(
device,
ctx->rumble,
sizeof(
ctx->rumble));
327 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
329 for (
i = 0;
i < MAX_CONTROLLERS;
i += 1) {
330 if (joystick->instance_id ==
ctx->joysticks[
i]) {
331 joystick->nbuttons = 12;
343 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
345 for (
i = 0;
i < MAX_CONTROLLERS;
i += 1) {
346 if (joystick->instance_id ==
ctx->joysticks[
i]) {
347 if (
ctx->wireless[
i]) {
348 return SDL_SetError(
"Ninteno GameCube WaveBird controllers do not support rumble");
350 if (!
ctx->rumbleAllowed[
i]) {
351 return SDL_SetError(
"Second USB cable for WUP-028 not connected");
353 val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
354 if (
val !=
ctx->rumble[
i + 1]) {
370 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
373 if (
ctx->rumbleUpdate) {
374 SDL_HIDAPI_SendRumble(
device,
ctx->rumble,
sizeof(
ctx->rumble));
382 SDL_DriverGameCube_Context *
ctx = (SDL_DriverGameCube_Context *)
device->context;
388 SDL_GameControllerButtonReportingHintChanged,
ctx);
398 HIDAPI_DriverGameCube_IsSupportedDevice,
399 HIDAPI_DriverGameCube_GetDeviceName,
400 HIDAPI_DriverGameCube_InitDevice,
401 HIDAPI_DriverGameCube_GetDevicePlayerIndex,
402 HIDAPI_DriverGameCube_SetDevicePlayerIndex,
403 HIDAPI_DriverGameCube_UpdateDevice,
404 HIDAPI_DriverGameCube_OpenJoystick,
405 HIDAPI_DriverGameCube_RumbleJoystick,
406 HIDAPI_DriverGameCube_CloseJoystick,
407 HIDAPI_DriverGameCube_FreeDevice