$OpenBSD: patch-source_mupen64plus-input-sdl_src_config_c,v 1.1.1.1 2011/12/26 13:38:27 stsp Exp $
--- src/config.c.orig	Sun Dec 18 23:50:44 2011
+++ src/config.c	Sun Dec 18 23:52:30 2011
@@ -29,6 +29,8 @@
 #include "autoconfig.h"
 #include "plugin.h"
 
+#include "config.h"
+
 #define HAT_POS_NAME( hat )         \
        ((hat == SDL_HAT_UP) ? "Up" :        \
        ((hat == SDL_HAT_DOWN) ? "Down" :    \
@@ -94,6 +96,7 @@ static void clear_controller(int iCtrlIdx)
     }
     for( b = 0; b < 2; b++ )
     {
+        controller[iCtrlIdx].mouse_sens[b] = 2.0;
         controller[iCtrlIdx].axis_deadzone[b] = 4096;
         controller[iCtrlIdx].axis_peak[b] = 32768;
         controller[iCtrlIdx].axis[b].button_a = controller[iCtrlIdx].axis[b].button_b = -1;
@@ -143,12 +146,20 @@ static const char * get_sdl_joystick_name(int iCtrlIdx
         return JoyName;
 }
 
+/////////////////////////////////////
+// load_controller_config()
+// return value: 1 = OK
+//               0 = fail: couldn't open config section
+//              -1 = fail: stored configuration incomplete - missing parameters
+//              -2 = fail: AutoKeyboard stored in mupen64plus.cfg file
+//              -3 = fail: joystick name stored in mupen64plus.cfg doesn't match SDL joystick name for given SDL joystick #
+
 static int load_controller_config(const char *SectionName, int i)
 {
     m64p_handle pConfig;
     char input_str[256], value1_str[16], value2_str[16];
     const char *config_ptr;
-    int readOK, j;
+    int j;
 
     /* Open the configuration section for this controller */
     if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
@@ -156,103 +167,132 @@ static int load_controller_config(const char *SectionN
         DebugMessage(M64MSG_ERROR, "Couldn't open config section '%s'", SectionName);
         return 0;
     }
-    /* try to read all of the configuration values */
-    for (readOK = 0; readOK == 0; readOK = 1)
+    /* check for the required parameters */
+    if (ConfigGetParameter(pConfig, "plugged", M64TYPE_BOOL, &controller[i].control->Present, sizeof(int)) != M64ERR_SUCCESS)
+        return -1;
+    if (ConfigGetParameter(pConfig, "plugin", M64TYPE_INT, &controller[i].control->Plugin, sizeof(int)) != M64ERR_SUCCESS)
+        return -1;
+    if (ConfigGetParameter(pConfig, "device", M64TYPE_INT, &controller[i].device, sizeof(int)) != M64ERR_SUCCESS)
+        return -1;
+    /* Name validation only applies to stored configurations (not auto-configs) */
+    if (strncmp(SectionName, "AutoConfig", 10) != 0)
     {
-        /* check for the required parameters */
-        if (ConfigGetParameter(pConfig, "plugged", M64TYPE_BOOL, &controller[i].control->Present, sizeof(int)) != M64ERR_SUCCESS)
-            break;
-        if (ConfigGetParameter(pConfig, "plugin", M64TYPE_INT, &controller[i].control->Plugin, sizeof(int)) != M64ERR_SUCCESS)
-            break;
-        if (ConfigGetParameter(pConfig, "device", M64TYPE_INT, &controller[i].device, sizeof(int)) != M64ERR_SUCCESS)
-            break;
-        /* then do the optional parameters */
-        ConfigGetParameter(pConfig, "mouse", M64TYPE_BOOL, &controller[i].mouse, sizeof(int));
-        if (ConfigGetParameter(pConfig, "AnalogDeadzone", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
+        char device_name[256];
+        if (ConfigGetParameter(pConfig, "name", M64TYPE_STRING, device_name, 256) != M64ERR_SUCCESS)
+            device_name[0] = 0;
+        if (controller[i].device == DEVICE_NOT_JOYSTICK)
         {
-            if (sscanf(input_str, "%i,%i", &controller[i].axis_deadzone[0], &controller[i].axis_deadzone[1]) != 2)
-                DebugMessage(M64MSG_WARNING, "parsing error in AnalogDeadzone parameter for controller %i", i + 1);
+            /* do not load automatically generated keyboard config that was stored to disk (prefer any joysticks attached) */
+            if (strcmp(device_name, "AutoKeyboard") == 0)
+                return -2;
         }
-        if (ConfigGetParameter(pConfig, "AnalogPeak", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
+        else if (controller[i].device >= 0 && device_name[0] != 0)
         {
-            if (sscanf(input_str, "%i,%i", &controller[i].axis_peak[0], &controller[i].axis_peak[1]) != 2)
-                DebugMessage(M64MSG_WARNING, "parsing error in AnalogPeak parameter for controller %i", i + 1);
-        }
-        /* load configuration for all the digital buttons */
-        for (j = 0; j < X_AXIS; j++)
-        {
-            if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
-                continue;
-            if ((config_ptr = strstr(input_str, "key")) != NULL)
-                if (sscanf(config_ptr, "key(%i)", (int *) &controller[i].button[j].key) != 1)
-                    DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of button '%s' for controller %i", button_names[j], i + 1);
-            if ((config_ptr = strstr(input_str, "button")) != NULL)
-                if (sscanf(config_ptr, "button(%i)", &controller[i].button[j].button) != 1)
-                    DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of button '%s' for controller %i", button_names[j], i + 1);
-            if ((config_ptr = strstr(input_str, "axis")) != NULL)
+            /* check that the SDL device name matches the name stored in the config section */
+            const char *sdl_name = get_sdl_joystick_name(controller[i].device);
+            if (sdl_name == NULL || strncmp(device_name, sdl_name, 255) != 0)
             {
-                char chAxisDir;
-                if (sscanf(config_ptr, "axis(%d%c,%d", &controller[i].button[j].axis, &chAxisDir, &controller[i].button[j].axis_deadzone) != 3 &&
-                    sscanf(config_ptr, "axis(%i%c", &controller[i].button[j].axis, &chAxisDir) != 2)
-                    DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of button '%s' for controller %i", button_names[j], i + 1);
-                controller[i].button[j].axis_dir = (chAxisDir == '+' ? 1 : (chAxisDir == '-' ? -1 : 0));
+                DebugMessage(M64MSG_WARNING, "N64 Controller #%i: SDL joystick name '%s' doesn't match stored configuration name '%s'", i + 1, sdl_name, device_name);
+                return -3;
             }
-            if ((config_ptr = strstr(input_str, "hat")) != NULL)
-            {
-                char *lastchar = NULL;
-                if (sscanf(config_ptr, "hat(%i %15s", &controller[i].button[j].hat, value1_str) != 2)
-                    DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of button '%s' for controller %i", button_names[j], i + 1);
-                value1_str[15] = 0;
-                /* chop off the last character of value1_str if it is the closing parenthesis */
-                lastchar = &value1_str[strlen(value1_str) - 1];
-                if (lastchar > value1_str && *lastchar == ')') *lastchar = 0;
-                controller[i].button[j].hat_pos = get_hat_pos_by_name(value1_str);
-            }
-            if ((config_ptr = strstr(input_str, "mouse")) != NULL)
-                if (sscanf(config_ptr, "mouse(%i)", &controller[i].button[j].mouse) != 1)
-                    DebugMessage(M64MSG_WARNING, "parsing error in mouse() parameter of button '%s' for controller %i", button_names[j], i + 1);
         }
-        /* load configuration for the 2 analog joystick axes */
-        for (j = X_AXIS; j <= Y_AXIS; j++)
+    }
+    /* then do the optional parameters */
+    ConfigGetParameter(pConfig, "mouse", M64TYPE_BOOL, &controller[i].mouse, sizeof(int));
+    if (ConfigGetParameter(pConfig, "MouseSensitivity", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
+    {
+        if (sscanf(input_str, "%f,%f", &controller[i].mouse_sens[0], &controller[i].mouse_sens[1]) != 2)
+            DebugMessage(M64MSG_WARNING, "parsing error in MouseSensitivity parameter for controller %i", i + 1);
+    }
+    if (ConfigGetParameter(pConfig, "AnalogDeadzone", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
+    {
+        if (sscanf(input_str, "%i,%i", &controller[i].axis_deadzone[0], &controller[i].axis_deadzone[1]) != 2)
+            DebugMessage(M64MSG_WARNING, "parsing error in AnalogDeadzone parameter for controller %i", i + 1);
+    }
+    if (ConfigGetParameter(pConfig, "AnalogPeak", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
+    {
+        if (sscanf(input_str, "%i,%i", &controller[i].axis_peak[0], &controller[i].axis_peak[1]) != 2)
+            DebugMessage(M64MSG_WARNING, "parsing error in AnalogPeak parameter for controller %i", i + 1);
+    }
+    /* load configuration for all the digital buttons */
+    for (j = 0; j < X_AXIS; j++)
+    {
+        if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
         {
-            int axis_idx = j - X_AXIS;
-            if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
-                continue;
-            if ((config_ptr = strstr(input_str, "key")) != NULL)
-                if (sscanf(config_ptr, "key(%i,%i)", (int *) &controller[i].axis[axis_idx].key_a, (int *) &controller[i].axis[axis_idx].key_b) != 2)
-                    DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of axis '%s' for controller %i", button_names[j], i + 1);
-            if ((config_ptr = strstr(input_str, "button")) != NULL)
-                if (sscanf(config_ptr, "button(%i,%i)", &controller[i].axis[axis_idx].button_a, &controller[i].axis[axis_idx].button_b) != 2)
-                    DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of axis '%s' for controller %i", button_names[j], i + 1);
-            if ((config_ptr = strstr(input_str, "axis")) != NULL)
-            {
-                char chAxisDir1, chAxisDir2;
-                if (sscanf(config_ptr, "axis(%i%c,%i%c)", &controller[i].axis[axis_idx].axis_a, &chAxisDir1,
-                                                          &controller[i].axis[axis_idx].axis_b, &chAxisDir2) != 4)
-                    DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of axis '%s' for controller %i", button_names[j], i + 1);
-                controller[i].axis[axis_idx].axis_dir_a = (chAxisDir1 == '+' ? 1 : (chAxisDir1 == '-' ? -1 : 0));
-                controller[i].axis[axis_idx].axis_dir_b = (chAxisDir2 == '+' ? 1 : (chAxisDir2 == '-' ? -1 : 0));
-            }
-            if ((config_ptr = strstr(input_str, "hat")) != NULL)
-            {
-                char *lastchar = NULL;
-                if (sscanf(config_ptr, "hat(%i %15s %15s", &controller[i].axis[axis_idx].hat, value1_str, value2_str) != 3)
-                    DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of axis '%s' for controller %i", button_names[j], i + 1);
-                value1_str[15] = value2_str[15] = 0;
-                /* chop off the last character of value2_str if it is the closing parenthesis */
-                lastchar = &value2_str[strlen(value2_str) - 1];
-                if (lastchar > value2_str && *lastchar == ')') *lastchar = 0;
-                controller[i].axis[axis_idx].hat_pos_a = get_hat_pos_by_name(value1_str);
-                controller[i].axis[axis_idx].hat_pos_b = get_hat_pos_by_name(value2_str);
-            }
+            DebugMessage(M64MSG_WARNING, "missing config key '%s' for controller %i button %i", button_names[j], i+1, j);
+            continue;
         }
+        if ((config_ptr = strstr(input_str, "key")) != NULL)
+            if (sscanf(config_ptr, "key(%i)", (int *) &controller[i].button[j].key) != 1)
+                DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of button '%s' for controller %i", button_names[j], i + 1);
+        if ((config_ptr = strstr(input_str, "button")) != NULL)
+            if (sscanf(config_ptr, "button(%i)", &controller[i].button[j].button) != 1)
+                DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of button '%s' for controller %i", button_names[j], i + 1);
+        if ((config_ptr = strstr(input_str, "axis")) != NULL)
+        {
+            char chAxisDir;
+            if (sscanf(config_ptr, "axis(%d%c,%d", &controller[i].button[j].axis, &chAxisDir, &controller[i].button[j].axis_deadzone) != 3 &&
+                sscanf(config_ptr, "axis(%i%c", &controller[i].button[j].axis, &chAxisDir) != 2)
+                DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of button '%s' for controller %i", button_names[j], i + 1);
+            controller[i].button[j].axis_dir = (chAxisDir == '+' ? 1 : (chAxisDir == '-' ? -1 : 0));
+        }
+        if ((config_ptr = strstr(input_str, "hat")) != NULL)
+        {
+            char *lastchar = NULL;
+            if (sscanf(config_ptr, "hat(%i %15s", &controller[i].button[j].hat, value1_str) != 2)
+                DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of button '%s' for controller %i", button_names[j], i + 1);
+            value1_str[15] = 0;
+            /* chop off the last character of value1_str if it is the closing parenthesis */
+            lastchar = &value1_str[strlen(value1_str) - 1];
+            if (lastchar > value1_str && *lastchar == ')') *lastchar = 0;
+            controller[i].button[j].hat_pos = get_hat_pos_by_name(value1_str);
+        }
+        if ((config_ptr = strstr(input_str, "mouse")) != NULL)
+            if (sscanf(config_ptr, "mouse(%i)", &controller[i].button[j].mouse) != 1)
+                DebugMessage(M64MSG_WARNING, "parsing error in mouse() parameter of button '%s' for controller %i", button_names[j], i + 1);
     }
+    /* load configuration for the 2 analog joystick axes */
+    for (j = X_AXIS; j <= Y_AXIS; j++)
+    {
+        int axis_idx = j - X_AXIS;
+        if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
+        {
+            DebugMessage(M64MSG_WARNING, "missing config key '%s' for controller %i axis %i", button_names[j], i+1, axis_idx);
+            continue;
+        }
+        if ((config_ptr = strstr(input_str, "key")) != NULL)
+            if (sscanf(config_ptr, "key(%i,%i)", (int *) &controller[i].axis[axis_idx].key_a, (int *) &controller[i].axis[axis_idx].key_b) != 2)
+                DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of axis '%s' for controller %i", button_names[j], i + 1);
+        if ((config_ptr = strstr(input_str, "button")) != NULL)
+            if (sscanf(config_ptr, "button(%i,%i)", &controller[i].axis[axis_idx].button_a, &controller[i].axis[axis_idx].button_b) != 2)
+                DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of axis '%s' for controller %i", button_names[j], i + 1);
+        if ((config_ptr = strstr(input_str, "axis")) != NULL)
+        {
+            char chAxisDir1, chAxisDir2;
+            if (sscanf(config_ptr, "axis(%i%c,%i%c)", &controller[i].axis[axis_idx].axis_a, &chAxisDir1,
+                                                      &controller[i].axis[axis_idx].axis_b, &chAxisDir2) != 4)
+                DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of axis '%s' for controller %i", button_names[j], i + 1);
+            controller[i].axis[axis_idx].axis_dir_a = (chAxisDir1 == '+' ? 1 : (chAxisDir1 == '-' ? -1 : 0));
+            controller[i].axis[axis_idx].axis_dir_b = (chAxisDir2 == '+' ? 1 : (chAxisDir2 == '-' ? -1 : 0));
+        }
+        if ((config_ptr = strstr(input_str, "hat")) != NULL)
+        {
+            char *lastchar = NULL;
+            if (sscanf(config_ptr, "hat(%i %15s %15s", &controller[i].axis[axis_idx].hat, value1_str, value2_str) != 3)
+                DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of axis '%s' for controller %i", button_names[j], i + 1);
+            value1_str[15] = value2_str[15] = 0;
+            /* chop off the last character of value2_str if it is the closing parenthesis */
+            lastchar = &value2_str[strlen(value2_str) - 1];
+            if (lastchar > value2_str && *lastchar == ')') *lastchar = 0;
+            controller[i].axis[axis_idx].hat_pos_a = get_hat_pos_by_name(value1_str);
+            controller[i].axis[axis_idx].hat_pos_b = get_hat_pos_by_name(value2_str);
+        }
+    }
 
-    return readOK;
+    return 1;
 }
 
-/* global functions */
-void save_controller_config(int iCtrlIdx)
+static void save_controller_config(int iCtrlIdx, const char *pccDeviceName)
 {
     m64p_handle pConfig;
     char SectionName[32], Param[32], ParamString[128];
@@ -273,7 +313,10 @@ void save_controller_config(int iCtrlIdx)
     ConfigSetDefaultInt(pConfig, "plugin", controller[iCtrlIdx].control->Plugin, "Specifies which type of expansion pak is in the controller: 1=None, 2=Mem pak, 5=Rumble pak");
     ConfigSetDefaultBool(pConfig, "mouse", controller[iCtrlIdx].mouse, "If True, then mouse buttons may be used with this controller");
     ConfigSetDefaultInt(pConfig, "device", controller[iCtrlIdx].device, "Specifies which joystick is bound to this controller: -2=Keyboard/mouse, -1=Auto config, 0 or more= SDL Joystick number");
+    ConfigSetDefaultString(pConfig, "name", pccDeviceName, "SDL joystick name (name check disabled if this is empty string)");
 
+    sprintf(Param, "%.2f,%.2f", controller[iCtrlIdx].mouse_sens[0], controller[iCtrlIdx].mouse_sens[1]);
+    ConfigSetDefaultString(pConfig, "MouseSensitivity", Param, "Scaling factor for mouse movements.  For X, Y axes.");
     sprintf(Param, "%i,%i", controller[iCtrlIdx].axis_deadzone[0], controller[iCtrlIdx].axis_deadzone[1]);
     ConfigSetDefaultString(pConfig, "AnalogDeadzone", Param, "The minimum absolute value of the SDL analog joystick axis to move the N64 controller axis value from 0.  For X, Y axes.");
     sprintf(Param, "%i,%i", controller[iCtrlIdx].axis_peak[0], controller[iCtrlIdx].axis_peak[1]);
@@ -367,6 +410,30 @@ void save_controller_config(int iCtrlIdx)
 
 }
 
+static void force_controller_keyboard(int n64CtrlIdx)
+{
+    if (n64CtrlIdx < 0 || n64CtrlIdx > 3)
+    {
+        DebugMessage(M64MSG_ERROR, "internal assert in ForceControllerKeyboard.  n64CtrlIdx=%i", n64CtrlIdx);
+        return;
+    }
+
+    DebugMessage(M64MSG_INFO, "N64 Controller #%i: Forcing default keyboard configuration", n64CtrlIdx+1);
+    auto_set_defaults(DEVICE_NOT_JOYSTICK, "Keyboard");
+    if (load_controller_config("AutoConfig0", n64CtrlIdx) > 0)
+    {
+        /* use ConfigSetDefault*() to save this auto-config if config section was empty */
+        save_controller_config(n64CtrlIdx, "AutoKeyboard");
+    }
+    else
+    {
+        DebugMessage(M64MSG_ERROR, "Autoconfig keyboard setup invalid");
+    }
+    ConfigDeleteSection("AutoConfig0");
+}
+
+/* global functions */
+
 /* The reason why the architecture of this config-handling code is so wacky is that it tries to balance
  * several different user scenarios.  From a high-level perspective, it works like this:
  * 1. If there is a valid configuration setup already in the config file, it should not be changed
@@ -388,38 +455,56 @@ void load_configuration(int bPrintSummary)
     const char *JoyName;
     int joy_found = 0, joy_plugged = 0;
     int readOK;
-    int i, j;
+    int n64CtrlIdx, sdlCtrlIdx, j;
 
     /* loop through all 4 simulated N64 controllers */
-    for (i = 0; i < 4; i++)
+    for (n64CtrlIdx=0,sdlCtrlIdx=0; n64CtrlIdx < 4; n64CtrlIdx++)
     {
         /* reset the controller configuration */
-        clear_controller(i);
+        clear_controller(n64CtrlIdx);
         /* try to load the config from the core's configuration api */
-        sprintf(SectionName, "Input-SDL-Control%i", i + 1);
-        readOK = load_controller_config(SectionName, i);
+        sprintf(SectionName, "Input-SDL-Control%i", n64CtrlIdx + 1);
+        readOK = load_controller_config(SectionName, n64CtrlIdx);
 
-        JoyName = get_sdl_joystick_name(i);
-        if (!readOK || controller[i].device == DEVICE_AUTO)
+        if (readOK <= 0 || controller[n64CtrlIdx].device == DEVICE_AUTO)
         {
             int ControllersFound = 0;
+            /* make sure that SDL device number hasn't already been used for a different N64 controller */
+            for (j = 0; j < n64CtrlIdx; j++)
+            {
+                if (controller[j].device == sdlCtrlIdx)
+                {
+                    sdlCtrlIdx++;
+                    j = -1;
+                }
+            }
+            /* if auto / bad config, get joystick name based on SDL order */
+            JoyName = get_sdl_joystick_name(sdlCtrlIdx);
             /* reset the controller configuration again and try to auto-configure */
-            ControllersFound = auto_set_defaults(i, JoyName);
-            if (ControllersFound > 0)
+            ControllersFound = auto_set_defaults(sdlCtrlIdx, JoyName);
+            sdlCtrlIdx++;
+            if (ControllersFound == 0)
             {
+                controller[n64CtrlIdx].device = DEVICE_AUTO;
+                controller[n64CtrlIdx].control->Present = 0;
+                DebugMessage(M64MSG_WARNING, "N64 Controller #%i: Disabled, SDL joystick %i is not available", n64CtrlIdx+1, sdlCtrlIdx-1);
+            }
+            else
+            {
                 for (j = 0; j < ControllersFound; j++) /* a USB device may have > 1 controller */
                 {
                     sprintf(SectionName, "AutoConfig%i", j);
-                    if (i + j > 3)
+                    if (n64CtrlIdx + j > 3)
                     {
                         ConfigDeleteSection(SectionName);
                         continue;
                     }
-                    clear_controller(i + j);
-                    if (load_controller_config(SectionName, i + j))
+                    clear_controller(n64CtrlIdx + j);
+                    if (load_controller_config(SectionName, n64CtrlIdx + j) > 0)
                     {
                         /* use ConfigSetDefault*() to save this auto-config if config section was empty */
-                        save_controller_config(i + j);
+                        save_controller_config(n64CtrlIdx + j, JoyName);
+                        DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using auto-config for SDL joystick %i ('%s')", n64CtrlIdx+1, controller[n64CtrlIdx].device, JoyName);
                     }
                     else
                     {
@@ -427,36 +512,38 @@ void load_configuration(int bPrintSummary)
                     }
                     ConfigDeleteSection(SectionName);
                 }
-                i += ControllersFound - 1;
+                n64CtrlIdx += ControllersFound - 1;
                 continue;
             }
         }
-        else if (controller[i].device >= 0)
+        else if (controller[n64CtrlIdx].device >= 0)
         {
+            /* if joystick found in cfg, take its SDL number from there */
+            JoyName = get_sdl_joystick_name(controller[n64CtrlIdx].device);
             /* valid joystick configuration was read; check if the specified joystick is available in SDL */
             if (JoyName == NULL)
             {
-                controller[i].device = DEVICE_AUTO;
-                controller[i].control->Present = 0;
-                DebugMessage(M64MSG_INFO, "N64 Controller #%i: Disabled, SDL joystick is not available", i+1);
+                controller[n64CtrlIdx].device = DEVICE_AUTO;
+                controller[n64CtrlIdx].control->Present = 0;
+                DebugMessage(M64MSG_WARNING, "N64 Controller #%i: Disabled, SDL joystick %i is not available", n64CtrlIdx+1, controller[n64CtrlIdx].device);
             }
             else
-                DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using SDL joystick %i ('%s')", i+1, controller[i].device, JoyName);
+                DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using stored config for SDL joystick %i ('%s')", n64CtrlIdx+1, controller[n64CtrlIdx].device, JoyName);
         }
         else /* controller is configured for keyboard/mouse */
         {
-            DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using keyboard/mouse", i+1);
+            DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using keyboard/mouse", n64CtrlIdx+1);
         }
     }
 
     /* see how many joysticks were found */
     joy_found = 0, joy_plugged = 0;
-    for (i = 0; i < 4; i++)
+    for (j = 0; j < 4; j++)
     {
-        if (controller[i].device >= 0 || controller[i].device == DEVICE_NOT_JOYSTICK)
+        if (controller[j].device >= 0 || controller[j].device == DEVICE_NOT_JOYSTICK)
         {
             joy_found++;
-            if (controller[i].control->Present)
+            if (controller[j].control->Present)
                 joy_plugged++;
         }
     }
@@ -464,18 +551,7 @@ void load_configuration(int bPrintSummary)
     /* fallback to keyboard if no joysticks are available and 'plugged in' */
     if (joy_found == 0 || joy_plugged == 0)
     {
-        DebugMessage(M64MSG_INFO, "N64 Controller #1: Forcing default keyboard configuration");
-        auto_set_defaults(DEVICE_NOT_JOYSTICK, "Keyboard");
-        if (load_controller_config("AutoConfig0", 0))
-        {
-            /* use ConfigSetDefault*() to save this auto-config if config section was empty */
-            save_controller_config(0);
-        }
-        else
-        {
-            DebugMessage(M64MSG_ERROR, "Autoconfig keyboard setup invalid");
-        }
-        ConfigDeleteSection("AutoConfig0");
+        force_controller_keyboard(0);
     }
 
     if (bPrintSummary)
