From bf98a453bb814564ccf848d76d06c4b544cfa998 Mon Sep 17 00:00:00 2001
From: Andrew Church <achurch@achurch.org>
Date: Mon, 25 Feb 2019 11:21:03 +1100
Subject: [PATCH] dinput: Allow remapping of joystick buttons

Changed
- Change the array to store the origial button.
- Remove lookup loops.
- Changed max Buttons to 32 to match DIJOYSTATE structure.

Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=35815
---
 dlls/dinput/joystick.c            | 29 +++++++++++++++++++++++++++++
 dlls/dinput/joystick_linux.c      |  7 +++++--
 dlls/dinput/joystick_linuxinput.c |  2 ++
 dlls/dinput/joystick_osx.c        |  2 ++
 dlls/dinput/joystick_private.h    |  4 ++++
 5 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c
index 0ec1ceb..b8b0027 100644
--- a/dlls/dinput/joystick.c
+++ b/dlls/dinput/joystick.c
@@ -950,6 +950,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
     int tokens = 0;
     int axis = 0;
     int pov = 0;
+    int button;
 
     get_app_key(&hkey, &appkey);
 
@@ -961,6 +962,34 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
         TRACE("setting default deadzone to: \"%s\" %d\n", buffer, This->deadzone);
     }
 
+    for (button = 0; button < MAX_MAP_BUTTONS; button++)
+        This->button_map[button] = button;
+
+    if (!get_config_key(hkey, appkey, "ButtonMap", buffer, sizeof(buffer)))
+    {
+        static const char *delim = ",";
+        int button = 0;
+        char *token;
+
+        TRACE("ButtonMap = \"%s\"\n", buffer);
+        for (token = strtok(buffer, delim);
+             token != NULL && button < MAX_MAP_BUTTONS;
+             token = strtok(NULL, delim), button++)
+        {
+            char *s;
+            int value = strtol(token, &s, 10);
+            if (value < 0 || *s != '\0')
+            {
+                ERR("invalid button number: \"%s\"", token);
+            }
+            else
+            {
+                TRACE("mapping physical button %d to DInput button %d", value, button);
+                This->button_map[value] = button;
+            }
+        }
+    }
+
     This->axis_map = HeapAlloc(GetProcessHeap(), 0, This->device_axis_count * sizeof(int));
     if (!This->axis_map) return DIERR_OUTOFMEMORY;
 
diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c
index 963e62f..6286746 100644
--- a/dlls/dinput/joystick_linux.c
+++ b/dlls/dinput/joystick_linux.c
@@ -807,10 +807,13 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
               jse.type,jse.number,jse.value);
         if (jse.type & JS_EVENT_BUTTON)
         {
+            int button;
             if (jse.number >= This->generic.devcaps.dwButtons) return;
 
-            inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON;
-            This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00;
+            button = This->generic.button_map[jse.number];
+
+            inst_id = DIDFT_MAKEINSTANCE(button) | DIDFT_PSHBUTTON;
+            This->generic.js.rgbButtons[button] = value = jse.value ? 0x80 : 0x00;
         }
         else if (jse.type & JS_EVENT_AXIS)
         {
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index 910e755..8ea268e 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -836,6 +836,8 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
             if (btn & 0x80)
             {
                 btn &= 0x7F;
+                btn = This->generic.button_map[btn];
+
                 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
                 This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
             }
diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c
index 0701b9f..224e203 100644
--- a/dlls/dinput/joystick_osx.c
+++ b/dlls/dinput/joystick_osx.c
@@ -809,6 +809,8 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
                         TRACE("valueRef %s val %d oldVal %d newVal %d\n", debugstr_cf(valueRef), val, oldVal, newVal);
                         if (oldVal != newVal)
                         {
+                            button_idx = device->generic.button_map[button_idx];
+
                             inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON;
                             queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
                         }
diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h
index e758cac..4a382c2 100644
--- a/dlls/dinput/joystick_private.h
+++ b/dlls/dinput/joystick_private.h
@@ -33,6 +33,9 @@
 #define MAX_PROPS 164
 struct JoystickGenericImpl;
 
+/* Number of buttons for which to allow remapping */
+#define MAX_MAP_BUTTONS 32
+
 typedef void joy_polldev_handler(LPDIRECTINPUTDEVICE8A iface);
 
 typedef struct JoystickGenericImpl
@@ -47,6 +50,7 @@ typedef struct JoystickGenericImpl
     char        *name;
     int         device_axis_count;      /* Total number of axes in the device */
     int        *axis_map;               /* User axes remapping */
+    int         button_map[MAX_MAP_BUTTONS]; /* User button remapping */
     LONG        deadzone;               /* Default dead-zone */
 
     joy_polldev_handler *joy_polldev;
-- 
1.9.1

