Commit c377de54409933b19ae5eb3855fdf203448d1f98

Sam Lantinga 2019-05-19T11:56:26

Fixed bug 4436 - [OpenBSD] fix D-pad Thomas Frohwein Hi, If a gamepad lists the Dpad as 4 buttons (Dpad Up,Down, Left, Right) like with the Xbox 360 gamepad / XInput report descriptor used by OpenBSD (https://github.com/openbsd/src/blob/master/sys/dev/usb/uhid_rdesc.h#L184), this is not recognized by the SDL BSD backend and no hat or any other listing for the D-pad exists, e.g. in sdl2-jstest (https://gitlab.com/sdl-jstest/sdl-jstest). The attached diff fixes this and makes the D-pad on my Xbox 360 and Logitech F310 controllers usable. It adds a hat to nhats when usage HUG_DPAD_UP is found, reads the state of the D-pad buttons into array dpad[], and turns the value of dpad[] into an SDL hat direction (dpad_to_sdl()). Tested and works with Xbox 360 controller and Logitech F310 in XInput mode. Software-side tested with sdl2-jstest and Owlboy where this worked without problems or regressions. I don't know if this would be applicable to other *BSDs and don't have an install to test it with, therefore wrapped it in __OpenBSD__ ifdefs. Thanks, thfr

diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c
index 2f699a7..fb63263 100644
--- a/src/joystick/bsd/SDL_sysjoystick.c
+++ b/src/joystick/bsd/SDL_sysjoystick.c
@@ -80,6 +80,49 @@
 #define MAX_JOY_JOYS    2
 #define MAX_JOYS    (MAX_UHID_JOYS + MAX_JOY_JOYS)
 
+#ifdef __OpenBSD__
+
+#define HUG_DPAD_UP         0x90
+#define HUG_DPAD_DOWN       0x91
+#define HUG_DPAD_RIGHT      0x92
+#define HUG_DPAD_LEFT       0x93
+
+#define HAT_CENTERED        0x00
+#define HAT_UP              0x01
+#define HAT_RIGHT           0x02
+#define HAT_DOWN            0x04
+#define HAT_LEFT            0x08
+#define HAT_RIGHTUP         (HAT_RIGHT|HAT_UP)
+#define HAT_RIGHTDOWN       (HAT_RIGHT|HAT_DOWN)
+#define HAT_LEFTUP          (HAT_LEFT|HAT_UP)
+#define HAT_LEFTDOWN        (HAT_LEFT|HAT_DOWN)
+
+/* calculate the value from the state of the dpad */
+int
+dpad_to_sdl(Sint32 *dpad)
+{
+    if (dpad[2]) {
+        if (dpad[0])
+            return HAT_RIGHTUP;
+        else if (dpad[1])
+            return HAT_RIGHTDOWN;
+        else
+            return HAT_RIGHT;
+    } else if (dpad[3]) {
+        if (dpad[0])
+            return HAT_LEFTUP;
+        else if (dpad[1])
+            return HAT_LEFTDOWN;
+        else
+            return HAT_LEFT;
+    } else if (dpad[0]) {
+        return HAT_UP;
+    } else if (dpad[1]) {
+        return HAT_DOWN;
+    }
+    return HAT_CENTERED;
+}
+#endif
 
 struct report
 {
@@ -434,7 +477,11 @@ desc_failed:
                     int joyaxe = usage_to_joyaxe(usage);
                     if (joyaxe >= 0) {
                         hw->axis_map[joyaxe] = 1;
-                    } else if (usage == HUG_HAT_SWITCH) {
+                    } else if (usage == HUG_HAT_SWITCH
+#ifdef __OpenBSD__
+                               || usage == HUG_DPAD_UP
+#endif
+                               ) {
                         joy->nhats++;
                     }
                     break;
@@ -487,6 +534,9 @@ BSD_JoystickUpdate(SDL_Joystick * joy)
     struct report *rep;
     int nbutton, naxe = -1;
     Sint32 v;
+#ifdef __OpenBSD__
+    Sint32 dpad[4] = {0, 0, 0, 0};
+#endif
 
 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
     struct joystick gameport;
@@ -572,6 +622,16 @@ BSD_JoystickUpdate(SDL_Joystick * joy)
                                                    hatval_to_sdl(v) -
                                                    hitem.logical_minimum);
                         }
+#ifdef __OpenBSD__
+                        else if (usage == HUG_DPAD_UP)
+                            dpad[0] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
+                        else if (usage == HUG_DPAD_DOWN)
+                            dpad[1] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
+                        else if (usage == HUG_DPAD_RIGHT)
+                            dpad[2] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
+                        else if (usage == HUG_DPAD_LEFT)
+                            dpad[3] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
+#endif
                         break;
                     }
                 case HUP_BUTTON:
@@ -587,6 +647,9 @@ BSD_JoystickUpdate(SDL_Joystick * joy)
                 break;
             }
         }
+#ifdef __OpenBSD__
+        SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
+#endif
         hid_end_parse(hdata);
     }
 }