Fixed GameCube controller axis and trigger ranges and X and B button being swapped
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index 197c2a3..a0e8955 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -35,12 +35,16 @@
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
+#define MAX_CONTROLLERS 4
+
typedef struct {
- SDL_JoystickID joysticks[4];
- Uint8 wireless[4];
- Uint8 rumbleAllowed[4];
- Uint8 rumble[5];
- Uint32 rumbleExpiration[4];
+ SDL_JoystickID joysticks[MAX_CONTROLLERS];
+ Uint8 wireless[MAX_CONTROLLERS];
+ Uint8 min_axis[MAX_CONTROLLERS*SDL_CONTROLLER_AXIS_MAX];
+ Uint8 max_axis[MAX_CONTROLLERS*SDL_CONTROLLER_AXIS_MAX];
+ Uint8 rumbleAllowed[MAX_CONTROLLERS];
+ Uint8 rumble[1+MAX_CONTROLLERS];
+ Uint32 rumbleExpiration[MAX_CONTROLLERS];
/* Without this variable, hid_write starts to lag a TON */
SDL_bool rumbleUpdate;
} SDL_DriverGameCube_Context;
@@ -61,6 +65,36 @@ HIDAPI_DriverGameCube_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
return "Nintendo GameCube Controller";
}
+static void
+ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index)
+{
+ SDL_memset(&ctx->min_axis[joystick_index*SDL_CONTROLLER_AXIS_MAX], 128-88, SDL_CONTROLLER_AXIS_MAX);
+ SDL_memset(&ctx->max_axis[joystick_index*SDL_CONTROLLER_AXIS_MAX], 128+88, SDL_CONTROLLER_AXIS_MAX);
+
+ /* Trigger axes may have a higher resting value */
+ ctx->min_axis[joystick_index*SDL_CONTROLLER_AXIS_MAX+SDL_CONTROLLER_AXIS_TRIGGERLEFT] = 40;
+ ctx->min_axis[joystick_index*SDL_CONTROLLER_AXIS_MAX+SDL_CONTROLLER_AXIS_TRIGGERRIGHT] = 40;
+}
+
+static float fsel(float fComparand, float fValGE, float fLT)
+{
+ return fComparand >= 0 ? fValGE : fLT;
+}
+
+static float RemapVal(float val, float A, float B, float C, float D)
+{
+ if (A == B) {
+ return fsel(val - B , D , C);
+ }
+ if (val < A) {
+ val = A;
+ }
+ if (val > B) {
+ val = B;
+ }
+ return C + (D - C) * (val - A) / (B - A);
+}
+
static SDL_bool
HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
{
@@ -109,7 +143,7 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
/* Go through all 4 slots */
curSlot = packet + 1;
- for (i = 0; i < 4; i += 1, curSlot += 9) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) {
ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
/* Only allow rumble if the adapter's second USB cable is connected */
@@ -117,6 +151,7 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
if (ctx->joysticks[i] == -1) {
+ ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
} else {
@@ -170,6 +205,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
Uint8 packet[37];
Uint8 *curSlot;
Uint8 i;
+ Sint16 axis_value;
int size;
/* Read input packet */
@@ -180,7 +216,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
/* Go through all 4 slots */
curSlot = packet + 1;
- for (i = 0; i < 4; i += 1, curSlot += 9) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) {
ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
/* Only allow rumble if the adapter's second USB cable is connected */
@@ -188,6 +224,7 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
if (ctx->joysticks[i] == -1) {
+ ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);
@@ -211,8 +248,8 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
(curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED \
);
READ_BUTTON(1, 0x01, 0) /* A */
- READ_BUTTON(1, 0x02, 1) /* B */
- READ_BUTTON(1, 0x04, 2) /* X */
+ READ_BUTTON(1, 0x04, 1) /* B */
+ READ_BUTTON(1, 0x02, 2) /* X */
READ_BUTTON(1, 0x08, 3) /* Y */
READ_BUTTON(1, 0x10, 4) /* DPAD_LEFT */
READ_BUTTON(1, 0x20, 5) /* DPAD_RIGHT */
@@ -228,25 +265,27 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
READ_BUTTON(2, 0x08, 11) /* TRIGGERLEFT */
#undef READ_BUTTON
- /* Axis math taken from SDL_xinputjoystick.c */
#define READ_AXIS(off, axis) \
+ if (axis < SDL_CONTROLLER_AXIS_TRIGGERLEFT) \
+ if (curSlot[off] < ctx->min_axis[i*SDL_CONTROLLER_AXIS_MAX+axis]) ctx->min_axis[i*SDL_CONTROLLER_AXIS_MAX+axis] = curSlot[off]; \
+ if (curSlot[off] > ctx->max_axis[i*SDL_CONTROLLER_AXIS_MAX+axis]) ctx->max_axis[i*SDL_CONTROLLER_AXIS_MAX+axis] = curSlot[off]; \
+ 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)); \
SDL_PrivateJoystickAxis( \
joystick, \
- axis, \
- (Sint16)(((int)curSlot[off] * 257) - 32768) \
+ axis, axis_value \
);
- READ_AXIS(3, 0) /* LEFTX */
- READ_AXIS(4, 1) /* LEFTY */
- READ_AXIS(5, 2) /* RIGHTX */
- READ_AXIS(6, 3) /* RIGHTY */
- READ_AXIS(7, 4) /* TRIGGERLEFT */
- READ_AXIS(8, 5) /* TRIGGERRIGHT */
+ READ_AXIS(3, SDL_CONTROLLER_AXIS_LEFTX)
+ READ_AXIS(4, SDL_CONTROLLER_AXIS_LEFTY)
+ READ_AXIS(5, SDL_CONTROLLER_AXIS_RIGHTX)
+ READ_AXIS(6, SDL_CONTROLLER_AXIS_RIGHTY)
+ READ_AXIS(7, SDL_CONTROLLER_AXIS_TRIGGERLEFT)
+ READ_AXIS(8, SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
#undef READ_AXIS
}
}
/* Write rumble packet */
- for (i = 0; i < 4; i += 1) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (ctx->rumbleExpiration[i] || (ctx->rumble[1 + i] && !ctx->rumbleAllowed[i])) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumbleExpiration[i]) || !ctx->rumbleAllowed[i]) {
@@ -270,10 +309,10 @@ HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i;
- for (i = 0; i < 4; i += 1) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
joystick->nbuttons = 12;
- joystick->naxes = 6;
+ joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = ctx->wireless[i] ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
@@ -286,7 +325,7 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i, val;
- for (i = 0; i < 4; i += 1) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (ctx->wireless[i]) {
return SDL_SetError("Ninteno GameCube WaveBird controllers do not support rumble");
@@ -323,7 +362,7 @@ HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
Uint8 i;
/* Stop rumble activity */
- for (i = 0; i < 4; i += 1) {
+ for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (!ctx->wireless[i] && ctx->rumbleAllowed[i] && ctx->rumble[1 + i] != 0) {
ctx->rumble[1 + i] = 0;