shithub: choc

Download patch

ref: 05f22d03aa25c55f5b7251d474eee16054f37e9e
parent: 4890591ba50bfc8b11cda684b223cb7c551e6dd3
author: Simon Howard <fraggle@gmail.com>
date: Wed Apr 30 20:19:51 EDT 2014

setup: Configure joystick buttons with virtual mapping.

Refactor how joystick buttons are reassigned. Define a fixed
mapping from joyb* variables to virtual buttons, and change the
button assignments at the virtual->physical mapping level.

--- a/src/m_controls.h
+++ b/src/m_controls.h
@@ -157,8 +157,6 @@
 extern int joybprevweapon;
 extern int joybnextweapon;
 
-extern int joy_physical_buttons[10];
-
 extern int joybmenu;
 
 extern int dclick_use;
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -90,18 +90,12 @@
 static int joystick_strafe_invert = 0;
 
 // Virtual to physical mapping.
-static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
+int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 };
 
 static txt_button_t *joystick_button;
 
-static int *all_joystick_buttons[] = {
-    &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed,
-    &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon, &joybjump,
-    &joybmenu,
-};
-
 //
 // Calibration 
 //
@@ -580,27 +574,7 @@
     SetCalibrationLabel();
 }
 
-void JoyButtonSetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable))
-{
-    TXT_CAST_ARG(int, variable);
-    unsigned int i;
-
-    // Only allow a button to be bound to one action at a time.  If 
-    // we assign a key that another action is using, set that other action
-    // to -1.
-
-    for (i=0; i<arrlen(all_joystick_buttons); ++i)
-    {
-        if (variable != all_joystick_buttons[i]
-         && *variable == *all_joystick_buttons[i])
-        {
-            *all_joystick_buttons[i] = -1;
-        }
-    }
-}
-
-
-// 
+//
 // GUI
 //
 
@@ -621,8 +595,6 @@
 
     TXT_AddWidget(table, TXT_NewLabel(label));
     TXT_AddWidget(table, joy_input);
-
-    TXT_SignalConnect(joy_input, "set", JoyButtonSetCallback, var);
 }
 
 void ConfigJoystick(void)
--- a/src/setup/txt_joybinput.c
+++ b/src/setup/txt_joybinput.c
@@ -27,6 +27,9 @@
 
 #include "doomkeys.h"
 #include "joystick.h"
+#include "i_joystick.h"
+#include "i_system.h"
+#include "m_controls.h"
 #include "m_misc.h"
 
 #include "txt_joybinput.h"
@@ -38,6 +41,111 @@
 
 #define JOYSTICK_INPUT_WIDTH 10
 
+extern int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS];
+
+// Joystick button variables.
+// The ordering of this array is important. We will always try to map
+// each variable to the virtual button with the same array index. For
+// example: joybfire should always be 0, and then we change
+// joystick_physical_buttons[0] to point to the physical joystick
+// button that the user wants to use for firing. We do this so that
+// the menus work (the game code is hard coded to interpret
+// button #0 = select menu item, button #1 = go back to previous menu).
+static int *all_joystick_buttons[] =
+{
+    &joybfire,
+    &joybuse,
+    &joybstrafe,
+    &joybspeed,
+    &joybstrafeleft,
+    &joybstraferight,
+    &joybprevweapon,
+    &joybnextweapon,
+    &joybjump,
+    &joybmenu,
+};
+
+static int PhysicalForVirtualButton(int vbutton)
+{
+    if (vbutton < NUM_VIRTUAL_BUTTONS)
+    {
+        return joystick_physical_buttons[vbutton];
+    }
+    else
+    {
+        return vbutton;
+    }
+}
+
+// Get the virtual button number for the given variable, ie. the
+// variable's index in all_joystick_buttons[].
+static int VirtualButtonForVariable(int *variable)
+{
+    int i;
+
+    for (i = 0; i < arrlen(all_joystick_buttons); ++i)
+    {
+        if (variable == all_joystick_buttons[i])
+        {
+            return i;
+        }
+    }
+
+    I_Error("Couldn't find virtual button");
+    return -1;
+}
+
+// Rearrange joystick button configuration to be in "canonical" form:
+// each joyb* variable should have a value equal to its index in
+// all_joystick_buttons[] above.
+static void CanonicalizeButtons(void)
+{
+    int new_mapping[NUM_VIRTUAL_BUTTONS];
+    int vbutton;
+    int i;
+
+    for (i = 0; i < arrlen(all_joystick_buttons); ++i)
+    {
+        vbutton = *all_joystick_buttons[i];
+
+        // Don't remap the speed key if it's bound to "always run".
+        // Also preserve "unbound" variables.
+        if ((all_joystick_buttons[i] == &joybspeed && vbutton >= 20)
+         || vbutton < 0)
+        {
+            new_mapping[i] = i;
+        }
+        else
+        {
+            new_mapping[i] = PhysicalForVirtualButton(vbutton);
+            *all_joystick_buttons[i] = i;
+        }
+    }
+
+    for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
+    {
+        joystick_physical_buttons[i] = new_mapping[i];
+    }
+}
+
+// Check all existing buttons and clear any using the specified physical
+// button.
+static void ClearVariablesUsingButton(int physbutton)
+{
+    int vbutton;
+    int i;
+
+    for (i = 0; i < arrlen(all_joystick_buttons); ++i)
+    {
+        vbutton = *all_joystick_buttons[i];
+
+        if (vbutton >= 0 && physbutton == PhysicalForVirtualButton(vbutton))
+        {
+            *all_joystick_buttons[i] = -1;
+        }
+    }
+}
+
 // Called in response to SDL events when the prompt window is open:
 
 static int EventCallback(SDL_Event *event, TXT_UNCAST_ARG(joystick_input))
@@ -48,13 +156,24 @@
 
     if (event->type == SDL_JOYBUTTONDOWN)
     {
-        *joystick_input->variable = event->jbutton.button;
+        int vbutton, physbutton;
 
+        // Before changing anything, remap button configuration into
+        // canonical form, to avoid conflicts.
+        CanonicalizeButtons();
+
+        vbutton = VirtualButtonForVariable(joystick_input->variable);
+        physbutton = event->jbutton.button;
+
         if (joystick_input->check_conflicts)
         {
-            TXT_EmitSignal(joystick_input, "set");
+            ClearVariablesUsingButton(physbutton);
         }
 
+        // Set mapping.
+        *joystick_input->variable = vbutton;
+        joystick_physical_buttons[vbutton] = physbutton;
+
         TXT_CloseWindow(joystick_input->prompt_window);
         return 1;
     }
@@ -125,9 +244,11 @@
     joystick_input->widget.h = 1;
 }
 
-static void GetJoystickButtonDescription(int button, char *buf, size_t buf_len)
+static void GetJoystickButtonDescription(int vbutton, char *buf,
+                                         size_t buf_len)
 {
-    M_snprintf(buf, buf_len, "BUTTON #%i", button + 1);
+    M_snprintf(buf, buf_len, "BUTTON #%i",
+               PhysicalForVirtualButton(vbutton) + 1);
 }
 
 static void TXT_JoystickInputDrawer(TXT_UNCAST_ARG(joystick_input))
@@ -148,9 +269,9 @@
 
     TXT_SetWidgetBG(joystick_input);
     TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
-    
+
     TXT_DrawString(buf);
-    
+
     for (i=strlen(buf); i<JOYSTICK_INPUT_WIDTH; ++i)
     {
         TXT_DrawString(" ");
@@ -185,7 +306,7 @@
 static void TXT_JoystickInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b)
 {
     TXT_CAST_ARG(txt_joystick_input_t, widget);
-            
+
     // Clicking is like pressing enter
 
     if (b == TXT_MOUSE_LEFT)