Input SDL plugin. Compile and run on the OpenPandora. Include config for Pandora...
[mupen64plus-pandora.git] / source / mupen64plus-input-sdl / src / config.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-input-sdl - config.c                                      *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2009-2013 Richard Goedeken                              *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include <SDL.h>
23
24 #define M64P_PLUGIN_PROTOTYPES 1
25 #include "m64p_types.h"
26 #include "m64p_plugin.h"
27 #include "m64p_config.h"
28
29 #include "osal_preproc.h"
30 #include "autoconfig.h"
31 #include "plugin.h"
32
33 #include "config.h"
34
35 #define HAT_POS_NAME( hat )         \
36        ((hat == SDL_HAT_UP) ? "Up" :        \
37        ((hat == SDL_HAT_DOWN) ? "Down" :    \
38        ((hat == SDL_HAT_LEFT) ? "Left" :    \
39        ((hat == SDL_HAT_RIGHT) ? "Right" :  \
40          "None"))))
41
42 typedef enum {
43     E_MODE_MANUAL = 0,
44     E_MODE_NAMED_AUTO,
45     E_MODE_FULL_AUTO
46  } eModeType;
47
48 static const char *button_names[] = {
49     "DPad R",       // R_DPAD
50     "DPad L",       // L_DPAD
51     "DPad D",       // D_DPAD
52     "DPad U",       // U_DPAD
53     "Start",        // START_BUTTON
54     "Z Trig",       // Z_TRIG
55     "B Button",     // B_BUTTON
56     "A Button",     // A_BUTTON
57     "C Button R",   // R_CBUTTON
58     "C Button L",   // L_CBUTTON
59     "C Button D",   // D_CBUTTON
60     "C Button U",   // U_CBUTTON
61     "R Trig",       // R_TRIG
62     "L Trig",       // L_TRIG
63     "Mempak switch",
64     "Rumblepak switch",
65     "X Axis",       // X_AXIS
66     "Y Axis"        // Y_AXIS
67 };
68
69 /* static functions */
70 static int get_hat_pos_by_name( const char *name )
71 {
72     if( !strcasecmp( name, "up" ) )
73         return SDL_HAT_UP;
74     if( !strcasecmp( name, "down" ) )
75         return SDL_HAT_DOWN;
76     if( !strcasecmp( name, "left" ) )
77         return SDL_HAT_LEFT;
78     if( !strcasecmp( name, "right" ) )
79         return SDL_HAT_RIGHT;
80     DebugMessage(M64MSG_WARNING, "get_hat_pos_by_name(): direction '%s' unknown", name);
81     return -1;
82 }
83
84 static void clear_controller(int iCtrlIdx)
85 {
86     int b;
87
88     controller[iCtrlIdx].device = DEVICE_NO_JOYSTICK;
89     controller[iCtrlIdx].control->Present = 0;
90     controller[iCtrlIdx].control->RawData = 0;
91     controller[iCtrlIdx].control->Plugin = PLUGIN_NONE;
92     for( b = 0; b < 16; b++ )
93     {
94         controller[iCtrlIdx].button[b].button = -1;
95         controller[iCtrlIdx].button[b].key = SDL_SCANCODE_UNKNOWN;
96         controller[iCtrlIdx].button[b].axis = -1;
97         controller[iCtrlIdx].button[b].axis_deadzone = -1;
98         controller[iCtrlIdx].button[b].hat = -1;
99         controller[iCtrlIdx].button[b].hat_pos = -1;
100         controller[iCtrlIdx].button[b].mouse = -1;
101     }
102     for( b = 0; b < 2; b++ )
103     {
104         controller[iCtrlIdx].mouse_sens[b] = 2.0;
105         controller[iCtrlIdx].axis_deadzone[b] = 4096;
106         controller[iCtrlIdx].axis_peak[b] = 32768;
107         controller[iCtrlIdx].axis[b].button_a = controller[iCtrlIdx].axis[b].button_b = -1;
108         controller[iCtrlIdx].axis[b].key_a = controller[iCtrlIdx].axis[b].key_b = SDL_SCANCODE_UNKNOWN;
109         controller[iCtrlIdx].axis[b].axis_a = -1;
110         controller[iCtrlIdx].axis[b].axis_dir_a = 1;
111         controller[iCtrlIdx].axis[b].axis_b = -1;
112         controller[iCtrlIdx].axis[b].axis_dir_b = 1;
113         controller[iCtrlIdx].axis[b].hat = -1;
114         controller[iCtrlIdx].axis[b].hat_pos_a = -1;
115         controller[iCtrlIdx].axis[b].hat_pos_b = -1;
116     }
117 }
118
119 static const char * get_sdl_joystick_name(int iCtrlIdx)
120 {
121     static char JoyName[256];
122     const char *joySDLName;
123     int joyWasInit = SDL_WasInit(SDL_INIT_JOYSTICK);
124     
125     /* initialize the joystick subsystem if necessary */
126     if (!joyWasInit)
127         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
128         {
129             DebugMessage(M64MSG_ERROR, "Couldn't init SDL joystick subsystem: %s", SDL_GetError() );
130             return NULL;
131         }
132
133     /* get the name of the corresponding joystick */
134     joySDLName = SDL_JoystickName(iCtrlIdx);
135
136     /* copy the name to our local string */
137     if (joySDLName != NULL)
138     {
139         strncpy(JoyName, joySDLName, 255);
140         JoyName[255] = 0;
141     }
142
143     /* quit the joystick subsystem if necessary */
144     if (!joyWasInit)
145         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
146
147     /* if the SDL function had an error, then return NULL, otherwise return local copy of joystick name */
148     if (joySDLName == NULL)
149         return NULL;
150     else
151         return JoyName;
152 }
153
154 static int get_sdl_num_joysticks(void)
155 {
156     int numJoysticks = 0;
157     int joyWasInit = SDL_WasInit(SDL_INIT_JOYSTICK);
158     
159     /* initialize the joystick subsystem if necessary */
160     if (!joyWasInit)
161         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
162         {
163             DebugMessage(M64MSG_ERROR, "Couldn't init SDL joystick subsystem: %s", SDL_GetError() );
164             return 0;
165         }
166
167     /* get thenumber of joysticks */
168     numJoysticks = SDL_NumJoysticks();
169
170     /* quit the joystick subsystem if necessary */
171     if (!joyWasInit)
172         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
173
174     return numJoysticks;
175 }
176
177 /////////////////////////////////////
178 // load_controller_config()
179 // return value: 1 = OK
180 //               0 = fail: couldn't open config section
181
182 static int load_controller_config(const char *SectionName, int i, int sdlDeviceIdx)
183 {
184     m64p_handle pConfig;
185     char input_str[256], value1_str[16], value2_str[16];
186     const char *config_ptr;
187     int j;
188
189     /* Open the configuration section for this controller */
190     if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
191     {
192         DebugMessage(M64MSG_ERROR, "Couldn't open config section '%s'", SectionName);
193         return 0;
194     }
195
196     /* set SDL device number */
197     controller[i].device = sdlDeviceIdx;
198
199     /* throw warnings if 'plugged' or 'plugin' are missing */
200     if (ConfigGetParameter(pConfig, "plugged", M64TYPE_BOOL, &controller[i].control->Present, sizeof(int)) != M64ERR_SUCCESS)
201     {
202         DebugMessage(M64MSG_WARNING, "missing 'plugged' parameter from config section %s. Setting to 1 (true).", SectionName);
203         controller[i].control->Present = 1;
204     }
205     if (ConfigGetParameter(pConfig, "plugin", M64TYPE_INT, &controller[i].control->Plugin, sizeof(int)) != M64ERR_SUCCESS)
206     {
207         DebugMessage(M64MSG_WARNING, "missing 'plugin' parameter from config section %s. Setting to 1 (none).", SectionName);
208         controller[i].control->Plugin = PLUGIN_NONE;
209     }
210     /* load optional parameters */
211     ConfigGetParameter(pConfig, "mouse", M64TYPE_BOOL, &controller[i].mouse, sizeof(int));
212     if (ConfigGetParameter(pConfig, "MouseSensitivity", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
213     {
214         if (sscanf(input_str, "%f,%f", &controller[i].mouse_sens[0], &controller[i].mouse_sens[1]) != 2)
215             DebugMessage(M64MSG_WARNING, "parsing error in MouseSensitivity parameter for controller %i", i + 1);
216     }
217     if (ConfigGetParameter(pConfig, "AnalogDeadzone", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
218     {
219         if (sscanf(input_str, "%i,%i", &controller[i].axis_deadzone[0], &controller[i].axis_deadzone[1]) != 2)
220             DebugMessage(M64MSG_WARNING, "parsing error in AnalogDeadzone parameter for controller %i", i + 1);
221     }
222     if (ConfigGetParameter(pConfig, "AnalogPeak", M64TYPE_STRING, input_str, 256) == M64ERR_SUCCESS)
223     {
224         if (sscanf(input_str, "%i,%i", &controller[i].axis_peak[0], &controller[i].axis_peak[1]) != 2)
225             DebugMessage(M64MSG_WARNING, "parsing error in AnalogPeak parameter for controller %i", i + 1);
226     }
227     /* load configuration for all the digital buttons */
228     for (j = 0; j < X_AXIS; j++)
229     {
230         if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
231         {
232             DebugMessage(M64MSG_WARNING, "missing config key '%s' for controller %i button %i", button_names[j], i+1, j);
233             continue;
234         }
235         if ((config_ptr = strstr(input_str, "key")) != NULL)
236             if (sscanf(config_ptr, "key(%i)", (int *) &controller[i].button[j].key) != 1)
237                 DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of button '%s' for controller %i", button_names[j], i + 1);
238         if ((config_ptr = strstr(input_str, "button")) != NULL)
239             if (sscanf(config_ptr, "button(%i)", &controller[i].button[j].button) != 1)
240                 DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of button '%s' for controller %i", button_names[j], i + 1);
241         if ((config_ptr = strstr(input_str, "axis")) != NULL)
242         {
243             char chAxisDir;
244             if (sscanf(config_ptr, "axis(%d%c,%d", &controller[i].button[j].axis, &chAxisDir, &controller[i].button[j].axis_deadzone) != 3 &&
245                 sscanf(config_ptr, "axis(%i%c", &controller[i].button[j].axis, &chAxisDir) != 2)
246                 DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of button '%s' for controller %i", button_names[j], i + 1);
247             controller[i].button[j].axis_dir = (chAxisDir == '+' ? 1 : (chAxisDir == '-' ? -1 : 0));
248         }
249         if ((config_ptr = strstr(input_str, "hat")) != NULL)
250         {
251             char *lastchar = NULL;
252             if (sscanf(config_ptr, "hat(%i %15s", &controller[i].button[j].hat, value1_str) != 2)
253                 DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of button '%s' for controller %i", button_names[j], i + 1);
254             value1_str[15] = 0;
255             /* chop off the last character of value1_str if it is the closing parenthesis */
256             lastchar = &value1_str[strlen(value1_str) - 1];
257             if (lastchar > value1_str && *lastchar == ')') *lastchar = 0;
258             controller[i].button[j].hat_pos = get_hat_pos_by_name(value1_str);
259         }
260         if ((config_ptr = strstr(input_str, "mouse")) != NULL)
261             if (sscanf(config_ptr, "mouse(%i)", &controller[i].button[j].mouse) != 1)
262                 DebugMessage(M64MSG_WARNING, "parsing error in mouse() parameter of button '%s' for controller %i", button_names[j], i + 1);
263     }
264     /* load configuration for the 2 analog joystick axes */
265     for (j = X_AXIS; j <= Y_AXIS; j++)
266     {
267         int axis_idx = j - X_AXIS;
268         if (ConfigGetParameter(pConfig, button_names[j], M64TYPE_STRING, input_str, 256) != M64ERR_SUCCESS)
269         {
270             DebugMessage(M64MSG_WARNING, "missing config key '%s' for controller %i axis %i", button_names[j], i+1, axis_idx);
271             continue;
272         }
273         if ((config_ptr = strstr(input_str, "key")) != NULL)
274             if (sscanf(config_ptr, "key(%i,%i)", (int *) &controller[i].axis[axis_idx].key_a, (int *) &controller[i].axis[axis_idx].key_b) != 2)
275                 DebugMessage(M64MSG_WARNING, "parsing error in key() parameter of axis '%s' for controller %i", button_names[j], i + 1);
276         if ((config_ptr = strstr(input_str, "button")) != NULL)
277             if (sscanf(config_ptr, "button(%i,%i)", &controller[i].axis[axis_idx].button_a, &controller[i].axis[axis_idx].button_b) != 2)
278                 DebugMessage(M64MSG_WARNING, "parsing error in button() parameter of axis '%s' for controller %i", button_names[j], i + 1);
279         if ((config_ptr = strstr(input_str, "axis")) != NULL)
280         {
281             char chAxisDir1, chAxisDir2;
282             if (sscanf(config_ptr, "axis(%i%c,%i%c)", &controller[i].axis[axis_idx].axis_a, &chAxisDir1,
283                                                       &controller[i].axis[axis_idx].axis_b, &chAxisDir2) != 4)
284                 DebugMessage(M64MSG_WARNING, "parsing error in axis() parameter of axis '%s' for controller %i", button_names[j], i + 1);
285             controller[i].axis[axis_idx].axis_dir_a = (chAxisDir1 == '+' ? 1 : (chAxisDir1 == '-' ? -1 : 0));
286             controller[i].axis[axis_idx].axis_dir_b = (chAxisDir2 == '+' ? 1 : (chAxisDir2 == '-' ? -1 : 0));
287         }
288         if ((config_ptr = strstr(input_str, "hat")) != NULL)
289         {
290             char *lastchar = NULL;
291             if (sscanf(config_ptr, "hat(%i %15s %15s", &controller[i].axis[axis_idx].hat, value1_str, value2_str) != 3)
292                 DebugMessage(M64MSG_WARNING, "parsing error in hat() parameter of axis '%s' for controller %i", button_names[j], i + 1);
293             value1_str[15] = value2_str[15] = 0;
294             /* chop off the last character of value2_str if it is the closing parenthesis */
295             lastchar = &value2_str[strlen(value2_str) - 1];
296             if (lastchar > value2_str && *lastchar == ')') *lastchar = 0;
297             controller[i].axis[axis_idx].hat_pos_a = get_hat_pos_by_name(value1_str);
298             controller[i].axis[axis_idx].hat_pos_b = get_hat_pos_by_name(value2_str);
299         }
300     }
301
302     return 1;
303 }
304
305 static void init_controller_config(int iCtrlIdx, const char *pccDeviceName, eModeType mode)
306 {
307     m64p_handle pConfig;
308     char SectionName[32], Param[32], ParamString[128];
309     int j;
310
311     /* Delete the configuration section for this controller, so we can use SetDefaults and save the help comments also */
312     sprintf(SectionName, "Input-SDL-Control%i", iCtrlIdx + 1);
313     ConfigDeleteSection(SectionName);
314     /* Open the configuration section for this controller (create a new one) */
315     if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
316     {
317         DebugMessage(M64MSG_ERROR, "Couldn't open config section '%s'", SectionName);
318         return;
319     }
320
321     /* save the general controller parameters */
322     ConfigSetDefaultFloat(pConfig, "version", CONFIG_VERSION, "Mupen64Plus SDL Input Plugin config parameter version number.  Please don't change this version number.");
323     ConfigSetDefaultInt(pConfig, "mode", (int) mode, "Controller configuration mode: 0=Fully Manual, 1=Auto with named SDL Device, 2=Fully automatic");
324     ConfigSetDefaultInt(pConfig, "device", controller[iCtrlIdx].device, "Specifies which joystick is bound to this controller: -1=No joystick, 0 or more= SDL Joystick number");
325     ConfigSetDefaultString(pConfig, "name", pccDeviceName, "SDL joystick name (or Keyboard)");
326     ConfigSetDefaultBool(pConfig, "plugged", controller[iCtrlIdx].control->Present, "Specifies whether this controller is 'plugged in' to the simulated N64");
327     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");
328     ConfigSetDefaultBool(pConfig, "mouse", controller[iCtrlIdx].mouse, "If True, then mouse buttons may be used with this controller");
329
330     sprintf(Param, "%.2f,%.2f", controller[iCtrlIdx].mouse_sens[0], controller[iCtrlIdx].mouse_sens[1]);
331     ConfigSetDefaultString(pConfig, "MouseSensitivity", Param, "Scaling factor for mouse movements.  For X, Y axes.");
332     sprintf(Param, "%i,%i", controller[iCtrlIdx].axis_deadzone[0], controller[iCtrlIdx].axis_deadzone[1]);
333     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.");
334     sprintf(Param, "%i,%i", controller[iCtrlIdx].axis_peak[0], controller[iCtrlIdx].axis_peak[1]);
335     ConfigSetDefaultString(pConfig, "AnalogPeak", Param, "An absolute value of the SDL joystick axis >= AnalogPeak will saturate the N64 controller axis value (at 80).  For X, Y axes. For each axis, this must be greater than the corresponding AnalogDeadzone value");
336
337     /* save configuration for all the digital buttons */
338     for (j = 0; j < X_AXIS; j++ )
339     {
340         const char *Help;
341         int len = 0;
342         ParamString[0] = 0;
343         if (controller[iCtrlIdx].button[j].key > 0)
344         {
345             sprintf(Param, "key(%i) ", controller[iCtrlIdx].button[j].key);
346             strcat(ParamString, Param);
347         }
348         if (controller[iCtrlIdx].button[j].button >= 0)
349         {
350             sprintf(Param, "button(%i) ", controller[iCtrlIdx].button[j].button);
351             strcat(ParamString, Param);
352         }
353         if (controller[iCtrlIdx].button[j].axis >= 0)
354         {
355             if (controller[iCtrlIdx].button[j].axis_deadzone >= 0)
356                 sprintf(Param, "axis(%i%c,%i) ", controller[iCtrlIdx].button[j].axis, (controller[iCtrlIdx].button[j].axis_dir == -1) ? '-' : '+',
357                         controller[iCtrlIdx].button[j].axis_deadzone);
358             else
359                 sprintf(Param, "axis(%i%c) ", controller[iCtrlIdx].button[j].axis, (controller[iCtrlIdx].button[j].axis_dir == -1) ? '-' : '+');
360             strcat(ParamString, Param);
361         }
362         if (controller[iCtrlIdx].button[j].hat >= 0)
363         {
364             sprintf(Param, "hat(%i %s) ", controller[iCtrlIdx].button[j].hat, HAT_POS_NAME(controller[iCtrlIdx].button[j].hat_pos));
365             strcat(ParamString, Param);
366         }
367         if (controller[iCtrlIdx].button[j].mouse >= 0)
368         {
369             sprintf(Param, "mouse(%i) ", controller[iCtrlIdx].button[j].mouse);
370             strcat(ParamString, Param);
371         }
372         if (j == 0)
373             Help = "Digital button configuration mappings";
374         else
375             Help = NULL;
376         /* if last character is a space, chop it off */
377         len = strlen(ParamString);
378         if (len > 0 && ParamString[len-1] == ' ')
379             ParamString[len-1] = 0;
380         ConfigSetDefaultString(pConfig, button_names[j], ParamString, Help);
381     }
382
383     /* save configuration for the 2 analog axes */
384     for (j = 0; j < 2; j++ )
385     {
386         const char *Help;
387         int len = 0;
388         ParamString[0] = 0;
389         if (controller[iCtrlIdx].axis[j].key_a > 0 && controller[iCtrlIdx].axis[j].key_b > 0)
390         {
391             sprintf(Param, "key(%i,%i) ", controller[iCtrlIdx].axis[j].key_a, controller[iCtrlIdx].axis[j].key_b);
392             strcat(ParamString, Param);
393         }
394         if (controller[iCtrlIdx].axis[j].button_a >= 0 && controller[iCtrlIdx].axis[j].button_b >= 0)
395         {
396             sprintf(Param, "button(%i,%i) ", controller[iCtrlIdx].axis[j].button_a, controller[iCtrlIdx].axis[j].button_b);
397             strcat(ParamString, Param);
398         }
399         if (controller[iCtrlIdx].axis[j].axis_a >= 0 && controller[iCtrlIdx].axis[j].axis_b >= 0)
400         {
401             sprintf(Param, "axis(%i%c,%i%c) ", controller[iCtrlIdx].axis[j].axis_a, (controller[iCtrlIdx].axis[j].axis_dir_a <= 0) ? '-' : '+',
402                                                controller[iCtrlIdx].axis[j].axis_b, (controller[iCtrlIdx].axis[j].axis_dir_b <= 0) ? '-' : '+' );
403             strcat(ParamString, Param);
404         }
405         if (controller[iCtrlIdx].axis[j].hat >= 0)
406         {
407             sprintf(Param, "hat(%i %s %s) ", controller[iCtrlIdx].axis[j].hat,
408                                              HAT_POS_NAME(controller[iCtrlIdx].axis[j].hat_pos_a),
409                                              HAT_POS_NAME(controller[iCtrlIdx].axis[j].hat_pos_b));
410             strcat(ParamString, Param);
411         }
412         if (j == 0)
413             Help = "Analog axis configuration mappings";
414         else
415             Help = NULL;
416         /* if last character is a space, chop it off */
417         len = strlen(ParamString);
418         if (len > 0 && ParamString[len-1] == ' ')
419             ParamString[len-1] = 0;
420         ConfigSetDefaultString(pConfig, button_names[X_AXIS + j], ParamString, Help);
421     }
422
423 }
424
425 static int setup_auto_controllers(int bPreConfig, int n64CtrlStart, int sdlCtrlIdx, const char *sdlJoyName, eModeType ControlMode[], eModeType OrigControlMode[], char DeviceName[][256])
426 {
427     char SectionName[32];
428     int ActiveControllers = 0;
429     int j;
430
431     /* create auto-config section(s) for this joystick (if this joystick is in the InputAutoConfig.ini) */
432     int ControllersFound = auto_set_defaults(sdlCtrlIdx, sdlJoyName);
433     if (ControllersFound == 0)
434         return 0;
435
436     /* copy the auto-config settings to the controller config section, and load our plugin joystick config from this */
437     sprintf(SectionName, "Input-SDL-Control%i", n64CtrlStart + 1);
438     if (OrigControlMode[n64CtrlStart] == E_MODE_FULL_AUTO)
439         auto_copy_inputconfig("AutoConfig0", SectionName, sdlJoyName);
440     else
441         auto_copy_inputconfig("AutoConfig0", SectionName, NULL);  // don't overwrite 'name' parameter if original mode was "named auto"
442     if (load_controller_config("AutoConfig0", n64CtrlStart, sdlCtrlIdx) > 0)
443     {
444         if (!bPreConfig)
445             DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using auto-config with SDL joystick %i ('%s')", n64CtrlStart+1, sdlCtrlIdx, sdlJoyName);
446         ActiveControllers++;
447         ConfigSaveSection(SectionName);
448     }
449     else
450     {
451         if (!bPreConfig)
452             DebugMessage(M64MSG_ERROR, "Autoconfig data invalid for SDL joystick '%s'", sdlJoyName);
453     }
454     ConfigDeleteSection("AutoConfig0");
455
456     /* we have to handle the unfortunate case of a USB device mapping more than > 1 controller */
457     if (ControllersFound > 1)
458     {
459         for (j = 1; j < ControllersFound; j++)
460         {
461             char AutoSectionName[32];
462             sprintf(AutoSectionName, "AutoConfig%i", j);
463             /* if this would be > 4th controller, then just delete the auto-config */
464             if (n64CtrlStart + j >= 4)
465             {
466                 ConfigDeleteSection(AutoSectionName);
467                 continue;
468             }
469             /* look for another N64 controller that is in AUTO mode */
470             if (ControlMode[n64CtrlStart+j] == E_MODE_FULL_AUTO ||
471                 (ControlMode[n64CtrlStart+j] == E_MODE_NAMED_AUTO && strncmp(DeviceName[n64CtrlStart+j], sdlJoyName, 255) == 0))
472             {
473                 sprintf(SectionName, "Input-SDL-Control%i", n64CtrlStart + j + 1);
474                 /* load our plugin joystick settings from the autoconfig */
475                 if (load_controller_config(AutoSectionName, n64CtrlStart+j, sdlCtrlIdx) > 0)
476                 {
477                     /* copy the auto-config settings to the controller config section */
478                     if (OrigControlMode[n64CtrlStart+j] == E_MODE_FULL_AUTO)
479                         auto_copy_inputconfig(AutoSectionName, SectionName, sdlJoyName);
480                     else
481                         auto_copy_inputconfig(AutoSectionName, SectionName, NULL);  // don't overwrite 'name' parameter if original mode was "named auto"
482                     if (!bPreConfig)
483                         DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using auto-config with SDL joystick %i ('%s')", n64CtrlStart+j+1, sdlCtrlIdx, sdlJoyName);
484                     ActiveControllers++;
485                     ConfigSaveSection(SectionName);
486                     /* set the local controller mode to Manual so that we won't re-configure this controller in the next loop */
487                     ControlMode[n64CtrlStart+j] = E_MODE_MANUAL;
488                 }
489                 else
490                 {
491                     if (!bPreConfig)
492                         DebugMessage(M64MSG_ERROR, "Autoconfig data invalid for SDL device '%s'", sdlJoyName);
493                 }
494                 /* delete the autoconfig section */
495                 ConfigDeleteSection(AutoSectionName);
496             }
497         }
498     }
499
500     return ActiveControllers;
501 }
502
503 /* global functions */
504
505 /* There are 4 special section parameters: version, mode, device, and name.  There are also 24 regular
506  * parameters: plugged, plugin, mouse, MouseSensitivity, DPad R/L/D/U, Start, Z/L/R Trigger, A/B button,
507  * C Button R/L/D/U, Mempak/Rumblepak switch, X/Y Axis, AnalogDeadzone, AnalogPeak.
508  *
509  * The N64 controller configuration behavior is regulated by the 'mode' parameter.  If this parameter is
510  * 0 (Fully Manual), then all configuration data is loaded and parsed without changes or autoconfig from
511  * the configuration section.  Any errors or warnings are printed.  If the mode parameter is 1 (Auto with
512  * named SDL Device), then the code below searches through the available SDL joysticks for one which
513  * matches with the 'name' parameter in the config section.  If a match is found, then the corresponding
514  * autoconfig is loaded and the regular parameters from the config section are updated with the
515  * autoconfig'ed settings.  If the mode parameter is 2 (Fully Auto), then the code below searches through
516  * all available detected SDL joysticks to try and find an autoconfig for each.  If an autoconfig match is
517  * found, then it is loaded and all config parameters (including device, name, and the regular parameters)
518  * are updated.
519  *
520  * This function is called with bPreConfig=true from the PluginStartup() function.  The purpose of this
521  * call is to load the 4 configuration sections with autoconfig data if necessary for a GUI front-end.
522  * When we are called with bPreConfig=true, we should only print warning/error messages and not info/status.
523  * This function is also called right before running the ROM game from InitiateControllers() with
524  * bPreConfig=false.  We should only print informational messages here, because we do not want to duplicate
525  * console output with the console-ui front-end (since the PluginStart() and InitiateControllers()
526  * functions are called in quick sequence from the console-ui).
527  */
528   
529 void load_configuration(int bPreConfig)
530 {
531     char SectionName[32];
532     int joy_plugged = 0;
533     int n64CtrlIdx, sdlCtrlIdx, j;
534     int sdlNumDevUsed = 0;
535     int sdlDevicesUsed[4];
536     eModeType OrigControlMode[4], ControlMode[4];
537     int ControlDevice[4];
538     char DeviceName[4][256];
539     int ActiveControllers = 0;
540     int sdlNumJoysticks = get_sdl_num_joysticks();
541     float fVersion = 0.0f;
542     const char *sdl_name;
543     int ControllersFound = 0;
544
545     /* tell user how many SDL joysticks are available */
546     if (!bPreConfig)
547         DebugMessage(M64MSG_INFO, "%i SDL joysticks were found.", sdlNumJoysticks);
548
549     /* loop through 4 N64 controllers, initializing and validating special section parameters */
550     for (n64CtrlIdx=0; n64CtrlIdx < 4; n64CtrlIdx++)
551     {
552         m64p_handle pConfig;
553         /* reset the controller configuration */
554         clear_controller(n64CtrlIdx);
555
556         /* Open the configuration section for this controller */
557         sprintf(SectionName, "Input-SDL-Control%i", n64CtrlIdx + 1);
558         if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
559         {
560             // this should never happen
561             DebugMessage(M64MSG_ERROR, "Couldn't open config section '%s'.  Aborting...", SectionName);
562             return;
563         }
564         /* Check version number, and if it doesn't match: delete the config section */
565         fVersion = 0.0f;
566         if (ConfigGetParameter(pConfig, "version", M64TYPE_FLOAT, &fVersion, sizeof(float)) != M64ERR_SUCCESS || ((int) fVersion) != ((int) CONFIG_VERSION))
567         {
568             DebugMessage(M64MSG_WARNING, "Missing or incompatible config section '%s'. Clearing.", SectionName);
569             ConfigDeleteSection(SectionName);
570             // set local controller default parameters
571             OrigControlMode[n64CtrlIdx] = ControlMode[n64CtrlIdx] = E_MODE_FULL_AUTO;
572             ControlDevice[n64CtrlIdx] = DEVICE_NO_JOYSTICK;
573             DeviceName[n64CtrlIdx][0] = 0;
574             // write blank config for GUI front-ends
575             init_controller_config(n64CtrlIdx, "", E_MODE_FULL_AUTO);
576             // save it to the file too
577             ConfigSaveSection(SectionName);
578         }
579         else
580         {
581             if (ConfigGetParameter(pConfig, "mode", M64TYPE_INT, &OrigControlMode[n64CtrlIdx], sizeof(int)) != M64ERR_SUCCESS ||
582                 (int) OrigControlMode[n64CtrlIdx] < 0 || (int) OrigControlMode[n64CtrlIdx] > 2)
583             {
584                 if (!bPreConfig)
585                     DebugMessage(M64MSG_WARNING, "Missing or invalid 'mode' parameter in config section '%s'.  Setting to 2 (Fully Auto)", SectionName);
586                 OrigControlMode[n64CtrlIdx] = E_MODE_FULL_AUTO;
587             }
588             ControlMode[n64CtrlIdx] = OrigControlMode[n64CtrlIdx];
589             if (ConfigGetParameter(pConfig, "device", M64TYPE_INT, &ControlDevice[n64CtrlIdx], sizeof(int)) != M64ERR_SUCCESS)
590             {
591                 if (!bPreConfig)
592                     DebugMessage(M64MSG_WARNING, "Missing 'device' parameter in config section '%s'.  Setting to -1 (No joystick)", SectionName);
593                 ControlDevice[n64CtrlIdx] = DEVICE_NO_JOYSTICK;
594             }
595             if (ConfigGetParameter(pConfig, "name", M64TYPE_STRING, DeviceName[n64CtrlIdx], 256) != M64ERR_SUCCESS)
596             {
597                 DeviceName[n64CtrlIdx][0] = 0;
598             }
599         }
600     }
601
602     /* loop through 4 N64 controllers and set up those in Fully Manual mode */
603     for (n64CtrlIdx=0; n64CtrlIdx < 4; n64CtrlIdx++)
604     {
605         if (ControlMode[n64CtrlIdx] != E_MODE_MANUAL)
606             continue;
607         /* load the stored configuration (disregard any errors) */
608         sprintf(SectionName, "Input-SDL-Control%i", n64CtrlIdx + 1);
609         load_controller_config(SectionName, n64CtrlIdx, ControlDevice[n64CtrlIdx]);
610         /* if this config uses an SDL joystick, mark it as used */
611         if (ControlDevice[n64CtrlIdx] == DEVICE_NO_JOYSTICK)
612         {
613             if (!bPreConfig)
614                 DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using manual config with no SDL joystick (keyboard/mouse only)", n64CtrlIdx+1);
615         }
616         else
617         {
618             sdlDevicesUsed[sdlNumDevUsed++] = ControlDevice[n64CtrlIdx];
619             if (!bPreConfig)
620                 DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using manual config for SDL joystick %i", n64CtrlIdx+1, ControlDevice[n64CtrlIdx]);
621         }
622         ActiveControllers++;
623     }
624
625     /* now loop through again, setting up those in Named Auto mode */
626     for (n64CtrlIdx=0; n64CtrlIdx < 4; n64CtrlIdx++)
627     {
628         if (ControlMode[n64CtrlIdx] != E_MODE_NAMED_AUTO)
629             continue;
630         /* if name is empty, then use full auto mode instead */
631         if (DeviceName[n64CtrlIdx][0] == 0)
632         {
633             ControlMode[n64CtrlIdx] = E_MODE_FULL_AUTO;
634             continue;
635         }
636         sprintf(SectionName, "Input-SDL-Control%i", n64CtrlIdx + 1);
637         /* if user is looking for a keyboard, set that up */
638         if (strcasecmp(DeviceName[n64CtrlIdx], "Keyboard") == 0)
639         {
640             auto_set_defaults(DEVICE_NO_JOYSTICK, "Keyboard");
641             if (load_controller_config("AutoConfig0", n64CtrlIdx, DEVICE_NO_JOYSTICK) > 0)
642             {
643                 if (!bPreConfig)
644                     DebugMessage(M64MSG_INFO, "N64 Controller #%i: Using auto-config for keyboard", n64CtrlIdx+1);
645                 /* copy the auto-config settings to the controller config section */
646                 auto_copy_inputconfig("AutoConfig0", SectionName, "Keyboard");
647                 ActiveControllers++;
648                 ConfigSaveSection(SectionName);
649             }
650             else
651             {
652                 DebugMessage(M64MSG_ERROR, "Autoconfig keyboard setup invalid");
653             }
654             ConfigDeleteSection("AutoConfig0");
655             continue;
656         }
657         /* search for an unused SDL device with the matching name */
658         for (sdlCtrlIdx=0; sdlCtrlIdx < sdlNumJoysticks; sdlCtrlIdx++)
659         {
660             /* check if this one is in use */
661             int deviceAlreadyUsed = 0;
662             for (j = 0; j < sdlNumDevUsed; j++)
663             {
664                 if (sdlDevicesUsed[j] == sdlCtrlIdx)
665                     deviceAlreadyUsed = 1;
666             }
667             if (deviceAlreadyUsed)
668                 continue;
669             /* check if the name matches */
670             sdl_name = get_sdl_joystick_name(sdlCtrlIdx);
671             if (sdl_name != NULL && strncmp(DeviceName[n64CtrlIdx], sdl_name, 255) == 0)
672             {
673                 /* set up one or more controllers for this SDL device, if present in InputAutoConfig.ini */
674                 int ControllersFound = setup_auto_controllers(bPreConfig, n64CtrlIdx, sdlCtrlIdx, sdl_name, ControlMode, OrigControlMode, DeviceName);
675                 if (ControllersFound == 0)
676                 {
677                     // error: no auto-config found for this SDL device
678                     DebugMessage(M64MSG_ERROR, "No auto-config found for joystick named '%s' in InputAutoConfig.ini", sdl_name);
679                     // mark this device as being used just so we don't complain about it again
680                     sdlDevicesUsed[sdlNumDevUsed++] = sdlCtrlIdx;
681                     // quit looking for SDL joysticks which match the name, because there's no valid autoconfig for that name.
682                     // this controller will be unused; skip to the next one
683                     break;
684                 }
685                 /* mark this sdl device as used */
686                 sdlDevicesUsed[sdlNumDevUsed++] = sdlCtrlIdx;
687                 ActiveControllers += ControllersFound;
688                 break;
689             }
690         }
691         /* if we didn't find a match for this joystick name, then set the controller to fully auto */
692         if (sdlCtrlIdx == sdlNumJoysticks)
693         {
694             if (!bPreConfig)
695                 DebugMessage(M64MSG_WARNING, "N64 Controller #%i: No SDL joystick found matching name '%s'.  Using full auto mode.", n64CtrlIdx+1, DeviceName[n64CtrlIdx]);
696             ControlMode[n64CtrlIdx] = E_MODE_FULL_AUTO;
697         }
698     }
699
700     /* Final loop through N64 controllers, setting up those in Full Auto mode */
701     for (n64CtrlIdx=0; n64CtrlIdx < 4; n64CtrlIdx++)
702     {
703         if (ControlMode[n64CtrlIdx] != E_MODE_FULL_AUTO)
704             continue;
705         sprintf(SectionName, "Input-SDL-Control%i", n64CtrlIdx + 1);
706         /* search for an unused SDL device */
707         for (sdlCtrlIdx=0; sdlCtrlIdx < sdlNumJoysticks; sdlCtrlIdx++)
708         {
709             /* check if this one is in use */
710             int deviceAlreadyUsed = 0;
711             for (j = 0; j < sdlNumDevUsed; j++)
712             {
713                 if (sdlDevicesUsed[j] == sdlCtrlIdx)
714                     deviceAlreadyUsed = 1;
715             }
716             if (deviceAlreadyUsed)
717                 continue;
718             /* set up one or more controllers for this SDL device, if present in InputAutoConfig.ini */
719             sdl_name = get_sdl_joystick_name(sdlCtrlIdx);
720             ControllersFound = setup_auto_controllers(bPreConfig, n64CtrlIdx, sdlCtrlIdx, sdl_name, ControlMode, OrigControlMode, DeviceName);
721             if (!bPreConfig && ControllersFound == 0)
722             {
723                 // error: no auto-config found for this SDL device
724                 DebugMessage(M64MSG_ERROR, "No auto-config found for joystick named '%s' in InputAutoConfig.ini", sdl_name);
725                 // mark this device as being used just so we don't complain about it again
726                 sdlDevicesUsed[sdlNumDevUsed++] = sdlCtrlIdx;
727                 // keep trying more SDL devices to see if we can auto-config one for this N64 controller
728                 continue;
729             }
730             /* mark this sdl device as used */
731             sdlDevicesUsed[sdlNumDevUsed++] = sdlCtrlIdx;
732             ActiveControllers += ControllersFound;
733             break;
734         }
735         /* if this N64 controller was not activated, set device to -1 */
736         if (sdlCtrlIdx == sdlNumJoysticks)
737         {
738             m64p_handle section;
739             if (ConfigOpenSection(SectionName, &section) == M64ERR_SUCCESS)
740             {
741                 const int iNoDevice = -1;
742                 ConfigSetParameter(section, "device", M64TYPE_INT, &iNoDevice);
743                 if (OrigControlMode[n64CtrlIdx] == E_MODE_FULL_AUTO)
744                     ConfigSetParameter(section, "name", M64TYPE_STRING, "");
745                 ConfigSaveSection(SectionName);
746             }
747         }
748     }
749
750     /* fallback to keyboard if no controllers were configured */
751     if (ActiveControllers == 0)
752     {
753         if (!bPreConfig)
754             DebugMessage(M64MSG_INFO, "N64 Controller #1: Forcing default keyboard configuration");
755         auto_set_defaults(DEVICE_NO_JOYSTICK, "Keyboard");
756         if (load_controller_config("AutoConfig0", 0, DEVICE_NO_JOYSTICK) > 0)
757         {
758             /* copy the auto-config settings to the controller config section */
759             if (OrigControlMode[0] == E_MODE_FULL_AUTO)
760                 auto_copy_inputconfig("AutoConfig0", "Input-SDL-Control1", "Keyboard");
761             else
762                 auto_copy_inputconfig("AutoConfig0", "Input-SDL-Control1", NULL);  // don't overwrite 'name' parameter
763             ActiveControllers++;
764             ConfigSaveSection("Input-SDL-Control1");
765         }
766         else
767         {
768             DebugMessage(M64MSG_ERROR, "Autoconfig keyboard setup invalid");
769         }
770         ConfigDeleteSection("AutoConfig0");
771     }
772
773     /* see how many joysticks are plugged in */
774     joy_plugged = 0;
775     for (j = 0; j < 4; j++)
776     {
777         if (controller[j].control->Present)
778             joy_plugged++;
779     }
780
781     /* print out summary info message */
782     if (!bPreConfig)
783     {
784         if (joy_plugged > 0)
785         {
786             DebugMessage(M64MSG_INFO, "%i controller(s) found, %i plugged in and usable in the emulator", ActiveControllers, joy_plugged);
787         }
788         else
789         {
790             if (ActiveControllers == 0)
791                 DebugMessage(M64MSG_WARNING, "No joysticks/controllers found");
792             else
793                 DebugMessage(M64MSG_WARNING, "%i controllers found, but none were 'plugged in'", ActiveControllers);
794         }
795     }
796
797 }
798
799