foxygit / doom Log in
commit 6d48ceda65af5e3118a43dbbfeb5b699c308cd4c
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon Apr 28 22:03:54 2014 -0400
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon Apr 28 22:03:54 2014 -0400

    setup: Detect and configure hat-based D-pads.

    As a second fallback, if all joysticks are centered and no buttons
    are pressed, look at the hats on the joystick to see if one of those
    is uncentered. Bizarre as it seems, some gamepads actually present the
    D-pad as a hat.
---
 src/setup/joystick.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/src/setup/joystick.c b/src/setup/joystick.c
index acabb61f..6fc505f6 100644
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -216,7 +216,7 @@ static void SetCalibrationLabel(void)
 }

 // Search all axes on joystick being configured; find a button that is
-// pressed (other than the calibrate button).
+// pressed (other than the calibrate button). Returns the button number.

 static int FindPressedAxisButton(void)
 {
@@ -241,6 +241,45 @@ static int FindPressedAxisButton(void)
     return -1;
 }

+// Look for a hat that isn't centered. Returns the encoded hat axis.
+
+static int FindUncenteredHat(int *axis_invert)
+{
+    SDL_Joystick *joystick;
+    int i, hatval;
+
+    joystick = all_joysticks[joystick_index];
+
+    for (i = 0; i < SDL_JoystickNumHats(joystick); ++i)
+    {
+        hatval = SDL_JoystickGetHat(joystick, i);
+
+        switch (hatval)
+        {
+            case SDL_HAT_LEFT:
+            case SDL_HAT_RIGHT:
+                *axis_invert = hatval != SDL_HAT_LEFT;
+                return CREATE_HAT_AXIS(i, HAT_AXIS_HORIZONTAL);
+
+            case SDL_HAT_UP:
+            case SDL_HAT_DOWN:
+                *axis_invert = hatval != SDL_HAT_UP;
+                return CREATE_HAT_AXIS(i, HAT_AXIS_VERTICAL);
+
+            // If the hat is centered, or is not pointing in a
+            // definite direction, then ignore it. We don't accept
+            // the hat being pointed to the upper-left for example,
+            // because it's ambiguous.
+            case SDL_HAT_CENTERED:
+            default:
+                break;
+        }
+    }
+
+    // None found.
+    return -1;
+}
+
 static boolean CalibrateAxis(int *axis_index, int *axis_invert)
 {
     SDL_Joystick *joystick;
@@ -296,6 +335,18 @@ static boolean CalibrateAxis(int *axis_index, int *axis_invert)
         return true;
     }

+    // Maybe it's a D-pad that is presented as a hat. This sounds weird
+    // but gamepads like this really do exist; an example is the
+    // Nyko AIRFLO Ex.
+
+    i = FindUncenteredHat(axis_invert);
+
+    if (i >= 0)
+    {
+        *axis_index = i;
+        return true;
+    }
+
     // User pressed the button without pushing the joystick anywhere.
     return false;
 }