foxygit / doom Log in
commit 15c0779ec829d8a0d83ecf33ce19e681e34f1b89
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon Apr 28 21:52:24 2014 -0400
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon Apr 28 21:52:24 2014 -0400

    joystick: Add "hat axis" support.

    Just as some controllers have D-pads that are presented as a set of
    buttons, some other controllers actually present their D-pads as
    joystick hats. Add "hat axis" support where the hat number and
    axis can be packed into a single integer value.
---
 src/i_joystick.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
 src/i_joystick.h | 18 ++++++++++++++++++
 2 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/src/i_joystick.c b/src/i_joystick.c
index c363cfaa..8822f288 100644
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -96,6 +96,11 @@ static boolean IsValidAxis(int axis)
         return true;
     }

+    if (IS_HAT_AXIS(axis))
+    {
+        return HAT_AXIS_HAT(axis) < SDL_JoystickNumHats(joystick);
+    }
+
     num_axes = SDL_JoystickNumAxes(joystick);

     return axis < num_axes;
@@ -187,12 +192,13 @@ static int GetAxisState(int axis, int invert)
         return 0;
     }

-    // Is this a button axis? If so, we need to handle it specially.
+    // Is this a button axis, or a hat axis?
+    // If so, we need to handle it specially.
+
+    result = 0;

     if (IS_BUTTON_AXIS(axis))
     {
-        result = 0;
-
         if (SDL_JoystickGetButton(joystick, BUTTON_AXIS_NEG(axis)))
         {
             result -= 32767;
@@ -202,14 +208,37 @@ static int GetAxisState(int axis, int invert)
             result += 32767;
         }
     }
-    else
+    else if (IS_HAT_AXIS(axis))
     {
-        result = SDL_JoystickGetAxis(joystick, axis);
+        int direction = HAT_AXIS_DIRECTION(axis);
+        int hatval = SDL_JoystickGetHat(joystick, HAT_AXIS_HAT(axis));

-        if (invert)
+        if (direction == HAT_AXIS_HORIZONTAL)
         {
-            result = -result;
+            if ((hatval & SDL_HAT_LEFT) != 0)
+            {
+                result -= 32767;
+            }
+            else if ((hatval & SDL_HAT_RIGHT) != 0)
+            {
+                result += 32767;
+            }
         }
+        else if (direction == HAT_AXIS_VERTICAL)
+        {
+            if ((hatval & SDL_HAT_UP) != 0)
+            {
+                result -= 32767;
+            }
+            else if ((hatval & SDL_HAT_DOWN) != 0)
+            {
+                result += 32767;
+            }
+        }
+    }
+    else
+    {
+        result = SDL_JoystickGetAxis(joystick, axis);

         if (result < DEAD_ZONE && result > -DEAD_ZONE)
         {
@@ -217,6 +246,11 @@ static int GetAxisState(int axis, int invert)
         }
     }

+    if (invert)
+    {
+        result = -result;
+    }
+
     return result;
 }

diff --git a/src/i_joystick.h b/src/i_joystick.h
index 93895de7..7c28eb6c 100644
--- a/src/i_joystick.h
+++ b/src/i_joystick.h
@@ -45,6 +45,24 @@
 // Create a button axis value from two button values.
 #define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8))

+// If this bit is set in an axis value, the axis is not actually a
+// joystick axis, but is a "hat" axis. This means that we read (one of)
+// the hats on the joystick.
+#define HAT_AXIS    0x20000
+
+#define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0)
+
+// Get the hat number from a hat axis value.
+#define HAT_AXIS_HAT(axis)         ((axis) & 0xff)
+// Which axis of the hat? (horizonal or vertical)
+#define HAT_AXIS_DIRECTION(axis)   (((axis) >> 8) & 0xff)
+
+#define CREATE_HAT_AXIS(hat, direction) \
+    (HAT_AXIS | (hat) | ((direction) << 8))
+
+#define HAT_AXIS_HORIZONTAL 1
+#define HAT_AXIS_VERTICAL   2
+
 void I_InitJoystick(void);
 void I_ShutdownJoystick(void);
 void I_UpdateJoystick(void);