foxygit / doom Log in
commit a9be9d879ad141ba6f0153bbf7e823256495065b
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon Apr 28 20:22:08 2014 -0400
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon Apr 28 20:22:08 2014 -0400

    joystick: Add support for "button axes".

    Some gamepads, notably the PS3 SIXAXIS controller, provide the D-pad
    not as a pair of axes, but rather as four separate buttons. Define a
    special axis numbering scheme that packs two button numbers into a
    single number, and allow an axis to be defined this way.
---
 src/i_joystick.c | 57 ++++++++++++++++++++++++++++++++++++++++++++------------
 src/i_joystick.h | 18 ++++++++++++++++++
 2 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/src/i_joystick.c b/src/i_joystick.c
index 8d77c9d6..d61d6260 100644
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -82,10 +82,27 @@ void I_ShutdownJoystick(void)
     }
 }

-void I_InitJoystick(void)
+static boolean IsValidAxis(int axis)
 {
     int num_axes;

+    if (axis < 0)
+    {
+        return true;
+    }
+
+    if (IS_BUTTON_AXIS(axis))
+    {
+        return true;
+    }
+
+    num_axes = SDL_JoystickNumAxes(joystick);
+
+    return axis < num_axes;
+}
+
+void I_InitJoystick(void)
+{
     if (!usejoystick)
     {
         return;
@@ -115,11 +132,9 @@ void I_InitJoystick(void)
         return;
     }

-    num_axes = SDL_JoystickNumAxes(joystick);
-
-    if (joystick_x_axis >= num_axes
-     || joystick_y_axis >= num_axes
-     || joystick_strafe_axis >= num_axes)
+    if (!IsValidAxis(joystick_x_axis)
+     || !IsValidAxis(joystick_y_axis)
+     || !IsValidAxis(joystick_strafe_axis))
     {
         printf("I_InitJoystick: Invalid joystick axis for joystick #%i "
                "(run joystick setup again)\n",
@@ -172,16 +187,34 @@ static int GetAxisState(int axis, int invert)
         return 0;
     }

-    result = SDL_JoystickGetAxis(joystick, axis);
+    // Is this a button axis? If so, we need to handle it specially.

-    if (invert)
+    if (IS_BUTTON_AXIS(axis))
     {
-        result = -result;
-    }
+        result = 0;

-    if (result < DEAD_ZONE && result > -DEAD_ZONE)
+        if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis)))
+        {
+            result -= 32767;
+        }
+        if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_POS(axis)))
+        {
+            result += 32767;
+        }
+    }
+    else
     {
-        result = 0;
+        result = SDL_JoystickGetAxis(joystick, axis);
+
+        if (invert)
+        {
+            result = -result;
+        }
+
+        if (result < DEAD_ZONE && result > -DEAD_ZONE)
+        {
+            result = 0;
+        }
     }

     return result;
diff --git a/src/i_joystick.h b/src/i_joystick.h
index 98cd218b..93895de7 100644
--- a/src/i_joystick.h
+++ b/src/i_joystick.h
@@ -27,6 +27,24 @@
 #ifndef __I_JOYSTICK__
 #define __I_JOYSTICK__

+// If this bit is set in a configuration file axis value, the axis is
+// not actually a joystick axis, but instead is a "button axis". This
+// means that instead of reading an SDL joystick axis, we read the
+// state of two buttons to get the axis value. This is needed for eg.
+// the PS3 SIXAXIS controller, where the D-pad buttons register as
+// buttons, not as two axes.
+#define BUTTON_AXIS 0x10000
+
+// Query whether a given axis value describes a button axis.
+#define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0)
+
+// Get the individual buttons from a button axis value.
+#define BUTTON_AXIS_NEG(axis)  ((axis) & 0xff)
+#define BUTTON_AXIS_POS(axis)  (((axis) >> 8) & 0xff)
+
+// Create a button axis value from two button values.
+#define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8))
+
 void I_InitJoystick(void);
 void I_ShutdownJoystick(void);
 void I_UpdateJoystick(void);