RetroArch/tools/ssnes-joyconfig.c

285 lines
8.1 KiB
C
Raw Normal View History

2011-01-17 19:54:58 +00:00
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
2011-01-09 14:44:35 +00:00
* Copyright (C) 2010 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2011-01-09 14:44:35 +00:00
#ifdef HAVE_SDL
#include "SDL.h"
#endif
#include "conf/config_file.h"
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "general.h"
2011-01-09 14:44:35 +00:00
2011-01-09 14:44:35 +00:00
static int g_player = 1;
2011-01-15 15:52:45 +00:00
static int g_joypad = 0;
2011-01-09 14:44:35 +00:00
static char *g_in_path = NULL;
static char *g_out_path = NULL;
static void print_help(void)
{
puts("==================");
puts("ssnes-joyconfig");
puts("==================");
puts("Usage: ssnes-joyconfig [ -p/--player <1-5> | -j/--joypad <num> | -i/--input <file> | -o/--output <file> | -h/--help ]");
2011-01-09 14:44:35 +00:00
puts("");
puts("-p/--player: Which player to configure for (1 up to and including 5).");
puts("-j/--joypad: Which joypad to use when configuring (first joypad is 0).");
2011-01-09 14:44:35 +00:00
puts("-i/--input: Input file to configure with. Binds will be added on or overwritten.");
puts("\tIf not selected, an empty config will be used as a base.");
puts("-o/--output: Output file to write to. If not selected, config file will be dumped to stdout.");
puts("-h/--help: This help.");
}
struct bind
{
char *keystr;
char *confbtn[MAX_PLAYERS];
char *confaxis[MAX_PLAYERS];
2011-01-09 14:44:35 +00:00
};
#define BIND(x, k) { x, { "input_player1_" #k "_btn", "input_player2_" #k "_btn", "input_player3_" #k "_btn", "input_player4_" #k "_btn", "input_player5_" #k "_btn" }, {"input_player1_" #k "_axis", "input_player2_" #k "_axis", "input_player3_" #k "_axis", "input_player4_" #k "_axis", "input_player5_" #k "_axis"}},
2011-01-09 14:44:35 +00:00
static struct bind binds[] = {
BIND("A button (right)", a)
BIND("B button (down)", b)
BIND("X button (top)", x)
BIND("Y button (left)", y)
BIND("L button (left shoulder)", l)
BIND("R button (right shoulder)", r)
BIND("Start button", start)
BIND("Select button", select)
BIND("Left D-pad", left)
BIND("Up D-pad", up)
BIND("Right D-pad", right)
BIND("Down D-pad", down)
};
void get_binds(config_file_t *conf, int player, int joypad)
{
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) < 0)
{
fprintf(stderr, "Failed to init joystick subsystem.\n");
exit(1);
}
SDL_Joystick *joystick;
int num = SDL_NumJoysticks();
if (joypad >= num)
{
2011-01-15 15:52:45 +00:00
fprintf(stderr, "Cannot find joystick at index #%d, only have %d joystick(s) available ...\n", joypad, num);
2011-01-09 14:44:35 +00:00
exit(1);
}
joystick = SDL_JoystickOpen(joypad);
if (!joystick)
{
fprintf(stderr, "Cannot open joystick.\n");
exit(1);
}
SDL_JoystickUpdate();
int last_axis = 0xFF;
int num_axes = SDL_JoystickNumAxes(joystick);
int initial_axes[num_axes];
for (int i = 0; i < num_axes; i++)
initial_axes[i] = SDL_JoystickGetAxis(joystick, i);
fprintf(stderr, "Configuring binds for player #%d on joypad #%d (%s)\n", player + 1, joypad, SDL_JoystickName(joypad));
2011-01-09 14:44:35 +00:00
fprintf(stderr, "Press Ctrl-C to exit early.\n");
fprintf(stderr, "\n");
for (unsigned i = 0; i < sizeof(binds) / sizeof(struct bind); i++)
{
fprintf(stderr, "%s\n", binds[i].keystr);
bool done = false;
SDL_Event event;
int value;
const char *quark;
while (SDL_WaitEvent(&event) && !done)
{
switch (event.type)
{
case SDL_JOYBUTTONDOWN:
fprintf(stderr, "\tJoybutton pressed: %d\n", (int)event.jbutton.button);
done = true;
config_set_int(conf, binds[i].confbtn[player], event.jbutton.button);
break;
case SDL_JOYAXISMOTION:
if (abs(event.jaxis.value) > 20000 &&
abs((int)event.jaxis.value - initial_axes[event.jaxis.axis]) > 20000 &&
event.jaxis.axis != last_axis)
{
last_axis = event.jaxis.axis;
fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", (int)event.jaxis.axis, (int)event.jaxis.value);
done = true;
char buf[8];
snprintf(buf, sizeof(buf), event.jaxis.value > 0 ? "+%d" : "-%d", event.jaxis.axis);
config_set_string(conf, binds[i].confaxis[player], buf);
}
break;
case SDL_JOYHATMOTION:
value = event.jhat.value;
if (value & SDL_HAT_UP)
quark = "up";
else if (value & SDL_HAT_DOWN)
quark = "down";
else if (value & SDL_HAT_LEFT)
quark = "left";
else if (value & SDL_HAT_RIGHT)
quark = "right";
else
break;
fprintf(stderr, "\tJoyhat moved: Hat %d, direction %s\n", (int)event.jhat.hat, quark);
done = true;
char buf[16];
snprintf(buf, sizeof(buf), "h%d%s", event.jhat.hat, quark);
config_set_string(conf, binds[i].confbtn[player], buf);
break;
case SDL_QUIT:
goto end;
default:
break;
}
}
}
end:
SDL_JoystickClose(joystick);
SDL_Quit();
}
static void parse_input(int argc, char *argv[])
{
char optstring[] = "i:o:p:j:h";
struct option opts[] = {
{ "input", 1, NULL, 'i' },
{ "output", 1, NULL, 'o' },
{ "player", 1, NULL, 'p' },
{ "joypad", 1, NULL, 'j' },
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
int option_index = 0;
for(;;)
{
int c = getopt_long(argc, argv, optstring, opts, &option_index);
if (c == -1)
break;
switch (c)
{
case 'h':
print_help();
exit(0);
case 'i':
g_in_path = strdup(optarg);
break;
case 'o':
g_out_path = strdup(optarg);
break;
case 'j':
g_joypad = strtol(optarg, NULL, 0);
if (g_joypad < 0)
2011-01-09 14:44:35 +00:00
{
fprintf(stderr, "Joypad number can't be negative!\n");
2011-01-09 14:44:35 +00:00
exit(1);
}
break;
case 'p':
g_player = strtol(optarg, NULL, 0);
if (g_player < 1)
{
fprintf(stderr, "Player number must be at least 1!\n");
exit(1);
}
else if (g_player > MAX_PLAYERS)
2011-01-09 14:44:35 +00:00
{
fprintf(stderr, "Player number must be from 1 to %d.\n", MAX_PLAYERS);
2011-01-09 14:44:35 +00:00
exit(1);
}
break;
default:
break;
}
}
if (optind < argc)
{
print_help();
exit(1);
}
}
2011-01-09 18:50:23 +00:00
// Windows is being bitchy. Cannot include SDL.h with a file that has main() it seems ... It simply won't run at all even with -lSDLmain.
2011-01-09 18:37:55 +00:00
#ifdef _WIN32
int real_main(int argc, char *argv[])
#else
2011-01-09 14:44:35 +00:00
int main(int argc, char *argv[])
2011-01-09 18:37:55 +00:00
#endif
2011-01-09 14:44:35 +00:00
{
parse_input(argc, argv);
config_file_t *conf = config_file_new(g_in_path);
2011-01-10 07:55:34 +00:00
if (!conf)
{
fprintf(stderr, "Couldn't open config file ...\n");
return 1;
}
const char *index_list[] = {
"input_player1_joypad_index",
"input_player2_joypad_index",
"input_player3_joypad_index",
"input_player4_joypad_index",
"input_player5_joypad_index"
};
config_set_int(conf, index_list[g_player - 1], g_joypad);
2011-01-10 07:55:34 +00:00
get_binds(conf, g_player - 1, g_joypad);
2011-01-09 14:44:35 +00:00
config_file_write(conf, g_out_path);
config_file_free(conf);
if (g_in_path)
free(g_in_path);
if (g_out_path)
free(g_out_path);
2011-01-09 16:24:13 +00:00
return 0;
2011-01-09 14:44:35 +00:00
}