Fixed bug 1371 - DX joystick axis ordering fix
authorSam Lantinga <slouken@libsdl.org>
Sun, 15 Jan 2012 15:48:27 -0500
changeset 6220 c36934808194
parent 6219 8e94af244f2c
child 6221 e54f601799eb
Fixed bug 1371 - DX joystick axis ordering fix Alex Nankervis 2012-01-15 11:19:45 PST DirectX joysticks can enumerate their axis out of order. This results in some joysticks having vertical/horizontal swapped, for example (vertical axis gets assigned to axis0). Joysticks that I've tested with this problem: XBOX 360 controller, Logitech Extreme 3D Pro. Attached is a diff that fixes this by sorting the DX joystick objects by their data offsets into the DX data structs. This puts the joystick objects into a standard ordering (X axis -> axis0, Y axis -> axis1, and so on).
src/joystick/windows/SDL_dxjoystick.c
--- a/src/joystick/windows/SDL_dxjoystick.c	Sun Jan 15 03:34:14 2012 -0500
+++ b/src/joystick/windows/SDL_dxjoystick.c	Sun Jan 15 15:48:27 2012 -0500
@@ -74,6 +74,7 @@
                                            pdidInstance, VOID * pContext);
 static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
                                             LPVOID pvRef);
+static void SortDevObjects(SDL_Joystick *joystick);
 static Uint8 TranslatePOV(DWORD value);
 static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
                                        Sint16 value);
@@ -483,6 +484,10 @@
                                     EnumDevObjectsCallback, joystick,
                                     DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
 
+	/* Reorder the input objects. Some devices do not report the X axis as
+	 * the first axis, for example. */
+	SortDevObjects(joystick);
+
     dipdw.diph.dwObj = 0;
     dipdw.diph.dwHow = DIPH_DEVICE;
     dipdw.dwData = INPUT_QSIZE;
@@ -504,6 +509,55 @@
     return (0);
 }
 
+/* Sort using the data offset into the DInput struct.
+ * This gives a reasonable ordering for the inputs. */
+static int
+SortDevFunc(const void *a, const void *b)
+{
+	const input_t *inputA = (const input_t*)a;
+	const input_t *inputB = (const input_t*)b;
+
+	if (inputA->ofs < inputB->ofs)
+		return -1;
+	if (inputA->ofs > inputB->ofs)
+		return 1;
+	return 0;
+}
+
+/* Sort the input objects and recalculate the indices for each input. */
+static void
+SortDevObjects(SDL_Joystick *joystick)
+{
+	input_t *inputs = joystick->hwdata->Inputs;
+	int nButtons = 0;
+	int nHats = 0;
+	int nAxis = 0;
+	int n;
+
+	SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
+
+	for (n = 0; n < joystick->hwdata->NumInputs; n++)
+	{
+		switch (inputs[n].type)
+		{
+		case BUTTON:
+			inputs[n].num = nButtons;
+			nButtons++;
+			break;
+
+		case HAT:
+			inputs[n].num = nHats;
+			nHats++;
+			break;
+
+		case AXIS:
+			inputs[n].num = nAxis;
+			nAxis++;
+			break;
+		}
+	}
+}
+
 static BOOL CALLBACK
 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
 {