Add support for justifiers and multitap.

This commit is contained in:
Themaister 2011-01-10 16:53:37 +01:00
parent dbd15a1d09
commit 422ba8a801
7 changed files with 247 additions and 37 deletions

View File

@ -183,5 +183,59 @@ static const struct snes_keybind snes_keybinds_2[] = {
{ -1 }
};
// Player 3
static const struct snes_keybind snes_keybinds_3[] = {
// SNES button | keyboard key | js btn | js axis |
{ SNES_DEVICE_ID_JOYPAD_A, SDLK_b, 1, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_B, SDLK_v, 0, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_X, SDLK_g, 3, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_Y, SDLK_f, 2, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_L, SDLK_r, 4, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_R, SDLK_t, 5, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_LEFT, SDLK_j, 11, AXIS_NEG(0) },
{ SNES_DEVICE_ID_JOYPAD_RIGHT, SDLK_l, 12, AXIS_POS(0) },
{ SNES_DEVICE_ID_JOYPAD_UP, SDLK_i, 13, AXIS_NEG(1) },
{ SNES_DEVICE_ID_JOYPAD_DOWN, SDLK_k, 14, AXIS_POS(1) },
{ SNES_DEVICE_ID_JOYPAD_START, SDLK_p, 6, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_SELECT, SDLK_o, 7, AXIS_NONE },
{ -1 }
};
// Player 4
static const struct snes_keybind snes_keybinds_4[] = {
// SNES button | keyboard key | js btn | js axis |
{ SNES_DEVICE_ID_JOYPAD_A, SDLK_b, 1, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_B, SDLK_v, 0, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_X, SDLK_g, 3, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_Y, SDLK_f, 2, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_L, SDLK_r, 4, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_R, SDLK_t, 5, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_LEFT, SDLK_j, 11, AXIS_NEG(0) },
{ SNES_DEVICE_ID_JOYPAD_RIGHT, SDLK_l, 12, AXIS_POS(0) },
{ SNES_DEVICE_ID_JOYPAD_UP, SDLK_i, 13, AXIS_NEG(1) },
{ SNES_DEVICE_ID_JOYPAD_DOWN, SDLK_k, 14, AXIS_POS(1) },
{ SNES_DEVICE_ID_JOYPAD_START, SDLK_p, 6, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_SELECT, SDLK_o, 7, AXIS_NONE },
{ -1 }
};
// Player 5
static const struct snes_keybind snes_keybinds_5[] = {
// SNES button | keyboard key | js btn | js axis |
{ SNES_DEVICE_ID_JOYPAD_A, SDLK_b, 1, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_B, SDLK_v, 0, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_X, SDLK_g, 3, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_Y, SDLK_f, 2, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_L, SDLK_r, 4, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_R, SDLK_t, 5, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_LEFT, SDLK_j, 11, AXIS_NEG(0) },
{ SNES_DEVICE_ID_JOYPAD_RIGHT, SDLK_l, 12, AXIS_POS(0) },
{ SNES_DEVICE_ID_JOYPAD_UP, SDLK_i, 13, AXIS_NEG(1) },
{ SNES_DEVICE_ID_JOYPAD_DOWN, SDLK_k, 14, AXIS_POS(1) },
{ SNES_DEVICE_ID_JOYPAD_START, SDLK_p, 6, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_SELECT, SDLK_o, 7, AXIS_NONE },
{ -1 }
};
#endif

View File

@ -33,8 +33,9 @@
#endif
#define MAX_PLAYERS 2 // Should be 5 when multi-tap stuff is added ...
#define MAX_PLAYERS 5
#define MAX_BINDS 18 // Needs to be increased every time there are new binds added.
#define SSNES_NO_JOYPAD 0xFFFF
struct settings
{
struct
@ -71,7 +72,7 @@ struct settings
char driver[32];
struct snes_keybind binds[MAX_PLAYERS][MAX_BINDS];
float axis_threshold;
unsigned joypad_map[2];
unsigned joypad_map[MAX_PLAYERS];
} input;
char libsnes[256];
@ -86,6 +87,9 @@ struct global
bool has_mouse[2];
bool has_scope[2];
bool has_justifier;
bool has_justifiers;
bool has_multitap;
FILE *rom_file;
char config_path[256];

View File

@ -37,8 +37,11 @@ static void* sdl_input_init(void)
SDL_JoystickEventState(SDL_IGNORE);
sdl->num_joysticks = SDL_NumJoysticks();
for (unsigned i = 0; i < 2; i++)
for (unsigned i = 0; i < MAX_PLAYERS; i++)
{
if (g_settings.input.joypad_map[i] == SSNES_NO_JOYPAD)
continue;
if (sdl->num_joysticks > g_settings.input.joypad_map[i])
{
sdl->joysticks[i] = SDL_JoystickOpen(g_settings.input.joypad_map[i]);
@ -168,12 +171,10 @@ static bool sdl_bind_button_pressed(void *data, int key)
}
static int16_t sdl_joypad_device_state(sdl_input_t *sdl, const struct snes_keybind **binds,
bool port, unsigned device, unsigned index, unsigned id)
int port_num, unsigned device, unsigned index, unsigned id)
{
const struct snes_keybind *snes_keybinds = binds[port == SNES_PORT_1 ? 0 : 1];
const struct snes_keybind *snes_keybinds = binds[port_num];
// Checks if button is pressed.
int port_num = port == SNES_PORT_1 ? 0 : 1;
for (int i = 0; snes_keybinds[i].id != -1; i++)
{
if (snes_keybinds[i].id == (int)id)
@ -222,16 +223,44 @@ static int16_t sdl_scope_device_state(sdl_input_t *sdl, unsigned id)
}
}
// TODO: Support two players.
static int16_t sdl_justifier_device_state(sdl_input_t *sdl, unsigned index, unsigned id)
{
if (index == 0)
{
switch (id)
{
case SNES_DEVICE_ID_JUSTIFIER_X:
return sdl->mouse_x;
case SNES_DEVICE_ID_JUSTIFIER_Y:
return sdl->mouse_y;
case SNES_DEVICE_ID_JUSTIFIER_TRIGGER:
return sdl->mouse_l;
case SNES_DEVICE_ID_JUSTIFIER_START:
return sdl->mouse_r;
default:
return 0;
}
}
else
return 0;
}
static int16_t sdl_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
{
switch (device)
{
case SNES_DEVICE_JOYPAD:
return sdl_joypad_device_state(data, binds, port, device, index, id);
return sdl_joypad_device_state(data, binds, port == SNES_PORT_1 ? 0 : 1, device, index, id);
case SNES_DEVICE_MULTITAP:
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_2) ? 1 + index : 0, device, index, id);
case SNES_DEVICE_MOUSE:
return sdl_mouse_device_state(data, port, id);
case SNES_DEVICE_SUPER_SCOPE:
return sdl_scope_device_state(data, id);
case SNES_DEVICE_JUSTIFIER:
case SNES_DEVICE_JUSTIFIERS:
return sdl_justifier_device_state(data, index, id);
default:
return 0;
@ -247,7 +276,7 @@ static void sdl_input_free(void *data)
while (SDL_PollEvent(&event));
sdl_input_t *sdl = data;
for (int i = 0; i < 2; i++)
for (int i = 0; i < MAX_PLAYERS; i++)
{
if (sdl->joysticks[i])
SDL_JoystickClose(sdl->joysticks[i]);

View File

@ -19,12 +19,13 @@
#define __SSNES_SDL_INPUT_H
#include "SDL.h"
#include "general.h"
typedef struct sdl_input
{
SDL_Joystick *joysticks[2];
unsigned num_axes[2];
unsigned num_buttons[2];
unsigned num_hats[2];
SDL_Joystick *joysticks[MAX_PLAYERS];
unsigned num_axes[MAX_PLAYERS];
unsigned num_buttons[MAX_PLAYERS];
unsigned num_hats[MAX_PLAYERS];
unsigned num_joysticks;
// A video driver could pre-init with the SDL driver and have it handle resizing events...

View File

@ -108,12 +108,20 @@ static void set_defaults(void)
assert(sizeof(g_settings.input.binds[0]) >= sizeof(snes_keybinds_1));
assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_2));
assert(sizeof(g_settings.input.binds[2]) >= sizeof(snes_keybinds_3));
assert(sizeof(g_settings.input.binds[3]) >= sizeof(snes_keybinds_4));
assert(sizeof(g_settings.input.binds[4]) >= sizeof(snes_keybinds_5));
memcpy(g_settings.input.binds[0], snes_keybinds_1, sizeof(snes_keybinds_1));
memcpy(g_settings.input.binds[1], snes_keybinds_2, sizeof(snes_keybinds_2));
memcpy(g_settings.input.binds[2], snes_keybinds_3, sizeof(snes_keybinds_3));
memcpy(g_settings.input.binds[3], snes_keybinds_4, sizeof(snes_keybinds_4));
memcpy(g_settings.input.binds[4], snes_keybinds_5, sizeof(snes_keybinds_5));
g_settings.input.axis_threshold = AXIS_THRESHOLD;
g_settings.input.joypad_map[0] = 0;
g_settings.input.joypad_map[1] = 1;
for (int i = 0; i < 2; i++)
g_settings.input.joypad_map[i] = i;
for (int i = 2; i < MAX_PLAYERS; i++)
g_settings.input.joypad_map[i] = SSNES_NO_JOYPAD;
}
void parse_config(void)
@ -247,12 +255,22 @@ void parse_config(void)
if (config_get_double(conf, "input_axis_threshold", &tmp_double))
g_settings.input.axis_threshold = tmp_double;
// Joypad mapping.
if (config_get_int(conf, "input_player1_joypad_index", &tmp_int))
g_settings.input.joypad_map[0] = tmp_int;
if (config_get_int(conf, "input_player2_joypad_index", &tmp_int))
g_settings.input.joypad_map[1] = tmp_int;
if (config_get_int(conf, "input_player3_joypad_index", &tmp_int))
g_settings.input.joypad_map[2] = tmp_int;
if (config_get_int(conf, "input_player4_joypad_index", &tmp_int))
g_settings.input.joypad_map[3] = tmp_int;
if (config_get_int(conf, "input_player5_joypad_index", &tmp_int))
g_settings.input.joypad_map[4] = tmp_int;
// Audio settings.
if (config_get_bool(conf, "audio_enable", &tmp_bool))
g_settings.audio.enable = tmp_bool;
@ -321,7 +339,7 @@ struct bind_map
#define DECLARE_BIND(x, bind) { "input_" #x, "input_" #x "_btn", "input_" #x "_axis", bind },
// Big and nasty bind map... :)
static const struct bind_map bind_maps[2][MAX_BINDS - 1] = {
static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
{
DECLARE_BIND(player1_a, SNES_DEVICE_ID_JOYPAD_A)
DECLARE_BIND(player1_b, SNES_DEVICE_ID_JOYPAD_B)
@ -359,7 +377,64 @@ static const struct bind_map bind_maps[2][MAX_BINDS - 1] = {
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
}
},
{
DECLARE_BIND(player3_a, SNES_DEVICE_ID_JOYPAD_A)
DECLARE_BIND(player3_b, SNES_DEVICE_ID_JOYPAD_B)
DECLARE_BIND(player3_y, SNES_DEVICE_ID_JOYPAD_Y)
DECLARE_BIND(player3_x, SNES_DEVICE_ID_JOYPAD_X)
DECLARE_BIND(player3_start, SNES_DEVICE_ID_JOYPAD_START)
DECLARE_BIND(player3_select, SNES_DEVICE_ID_JOYPAD_SELECT)
DECLARE_BIND(player3_l, SNES_DEVICE_ID_JOYPAD_L)
DECLARE_BIND(player3_r, SNES_DEVICE_ID_JOYPAD_R)
DECLARE_BIND(player3_left, SNES_DEVICE_ID_JOYPAD_LEFT)
DECLARE_BIND(player3_right, SNES_DEVICE_ID_JOYPAD_RIGHT)
DECLARE_BIND(player3_up, SNES_DEVICE_ID_JOYPAD_UP)
DECLARE_BIND(player3_down, SNES_DEVICE_ID_JOYPAD_DOWN)
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
{
DECLARE_BIND(player4_a, SNES_DEVICE_ID_JOYPAD_A)
DECLARE_BIND(player4_b, SNES_DEVICE_ID_JOYPAD_B)
DECLARE_BIND(player4_y, SNES_DEVICE_ID_JOYPAD_Y)
DECLARE_BIND(player4_x, SNES_DEVICE_ID_JOYPAD_X)
DECLARE_BIND(player4_start, SNES_DEVICE_ID_JOYPAD_START)
DECLARE_BIND(player4_select, SNES_DEVICE_ID_JOYPAD_SELECT)
DECLARE_BIND(player4_l, SNES_DEVICE_ID_JOYPAD_L)
DECLARE_BIND(player4_r, SNES_DEVICE_ID_JOYPAD_R)
DECLARE_BIND(player4_left, SNES_DEVICE_ID_JOYPAD_LEFT)
DECLARE_BIND(player4_right, SNES_DEVICE_ID_JOYPAD_RIGHT)
DECLARE_BIND(player4_up, SNES_DEVICE_ID_JOYPAD_UP)
DECLARE_BIND(player4_down, SNES_DEVICE_ID_JOYPAD_DOWN)
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
{
DECLARE_BIND(player5_a, SNES_DEVICE_ID_JOYPAD_A)
DECLARE_BIND(player5_b, SNES_DEVICE_ID_JOYPAD_B)
DECLARE_BIND(player5_y, SNES_DEVICE_ID_JOYPAD_Y)
DECLARE_BIND(player5_x, SNES_DEVICE_ID_JOYPAD_X)
DECLARE_BIND(player5_start, SNES_DEVICE_ID_JOYPAD_START)
DECLARE_BIND(player5_select, SNES_DEVICE_ID_JOYPAD_SELECT)
DECLARE_BIND(player5_l, SNES_DEVICE_ID_JOYPAD_L)
DECLARE_BIND(player5_r, SNES_DEVICE_ID_JOYPAD_R)
DECLARE_BIND(player5_left, SNES_DEVICE_ID_JOYPAD_LEFT)
DECLARE_BIND(player5_right, SNES_DEVICE_ID_JOYPAD_RIGHT)
DECLARE_BIND(player5_up, SNES_DEVICE_ID_JOYPAD_UP)
DECLARE_BIND(player5_down, SNES_DEVICE_ID_JOYPAD_DOWN)
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
};
struct key_map
@ -436,9 +511,9 @@ static void read_keybinds(config_file_t *conf)
char *tmp_btn = NULL;
char *tmp_axis = NULL;
for (int j = 0; j < 1; j++)
for (int j = 0; j < MAX_PLAYERS; j++)
{
for (int i = 0; i < sizeof(bind_maps[j])/sizeof(struct bind_map); i++)
for (int i = 0; i < sizeof(bind_maps[0])/sizeof(struct bind_map); i++)
{
struct snes_keybind *bind = find_snes_bind(j, bind_maps[j][i].snes_key);
if (!bind)

61
ssnes.c
View File

@ -201,7 +201,10 @@ static void input_poll(void)
static int16_t input_state(bool port, unsigned device, unsigned index, unsigned id)
{
const struct snes_keybind *binds[] = { g_settings.input.binds[0], g_settings.input.binds[1] };
const struct snes_keybind *binds[MAX_PLAYERS];
for (int i = 0; i < MAX_PLAYERS; i++)
binds[i] = g_settings.input.binds[i];
return driver.input->input_state(driver.input_data, binds, port, device, index, id);
}
@ -242,6 +245,9 @@ static void print_help(void)
puts("\t-m/--mouse: Connect a virtual mouse into designated port of the SNES (1 or 2).");
puts("\tThis argument can be specified several times to connect more mice.");
puts("\t-p/--scope: Connect a virtual SuperScope into port 2 of the SNES.");
puts("\t-j/--justifier: Connect a virtual Konami Justifier into port 2 of the SNES.");
puts("\t-k/--justifiers: Daisy chain two virtual Konami Justifiers into port 2 of the SNES.");
puts("\t-4/--multitap: Connect a multitap to port 2 of the SNES.");
#ifdef HAVE_FFMPEG
puts("\t-r/--record: Path to record video file. Settings for video/audio codecs are found in config file.");
@ -268,6 +274,9 @@ static void parse_input(int argc, char *argv[])
{ "mouse", 1, NULL, 'm' },
{ "scope", 0, NULL, 'p' },
{ "savestate", 1, NULL, 't' },
{ "justifier", 0, NULL, 'j' },
{ "justifiers", 0, NULL, 'k' },
{ "multitap", 0, NULL, '4' },
{ NULL, 0, NULL, 0 }
};
@ -279,7 +288,7 @@ static void parse_input(int argc, char *argv[])
#define FFMPEG_RECORD_ARG
#endif
char optstring[] = "hs:vc:t:m:p" FFMPEG_RECORD_ARG;
char optstring[] = "hs:vc:t:m:p4jk" FFMPEG_RECORD_ARG;
for(;;)
{
int c = getopt_long(argc, argv, optstring, opts, &option_index);
@ -294,6 +303,18 @@ static void parse_input(int argc, char *argv[])
print_help();
exit(0);
case '4':
g_extern.has_multitap = true;
break;
case 'j':
g_extern.has_justifier = true;
break;
case 'k':
g_extern.has_justifiers = true;
break;
case 's':
strncpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm) - 1);
break;
@ -389,17 +410,35 @@ static void parse_input(int argc, char *argv[])
// TODO: Add rest of the controllers.
static void init_controllers(void)
{
for (int i = 0; i < 2; i++)
if (g_extern.has_justifier)
{
if (g_extern.has_mouse[i])
SSNES_LOG("Connecting Justifier to port 2.\n");
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_JUSTIFIER);
}
else if (g_extern.has_justifiers)
{
SSNES_LOG("Connecting Justifiers to port 2.\n");
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_JUSTIFIERS);
}
else if (g_extern.has_multitap)
{
SSNES_LOG("Connecting multitap to port 2.\n");
psnes_set_controller_port_device(SNES_PORT_2, SNES_DEVICE_MULTITAP);
}
else
{
for (int i = 0; i < 2; i++)
{
SSNES_LOG("Connecting mouse to port %d\n", i + 1);
psnes_set_controller_port_device(i, SNES_DEVICE_MOUSE);
}
else if (g_extern.has_scope[i])
{
SSNES_LOG("Connecting scope to port %d\n", i + 1);
psnes_set_controller_port_device(i, SNES_DEVICE_SUPER_SCOPE);
if (g_extern.has_mouse[i])
{
SSNES_LOG("Connecting mouse to port %d\n", i + 1);
psnes_set_controller_port_device(i, SNES_DEVICE_MOUSE);
}
else if (g_extern.has_scope[i])
{
SSNES_LOG("Connecting scope to port %d\n", i + 1);
psnes_set_controller_port_device(i, SNES_DEVICE_SUPER_SCOPE);
}
}
}
}

View File

@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "general.h"
static int g_player = 1;
@ -52,11 +53,11 @@ static void print_help(void)
struct bind
{
char *keystr;
char *confbtn[2];
char *confaxis[2];
char *confbtn[MAX_PLAYERS];
char *confaxis[MAX_PLAYERS];
};
#define BIND(x, k) { x, { "input_player1_" #k "_btn", "input_player2_" #k "_btn" }, {"input_player1_" #k "_axis", "input_player2_" #k "_axis"}},
#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"}},
static struct bind binds[] = {
BIND("A button (right)", a)
BIND("B button (down)", b)
@ -226,9 +227,9 @@ static void parse_input(int argc, char *argv[])
fprintf(stderr, "Player number must be at least 1!\n");
exit(1);
}
else if (g_player > 2)
else if (g_player > MAX_PLAYERS)
{
fprintf(stderr, "Player number must be 1 or 2.\n");
fprintf(stderr, "Player number must be from 1 to %d.\n", MAX_PLAYERS);
exit(1);
}
break;
@ -262,8 +263,15 @@ int main(int argc, char *argv[])
return 1;
}
config_set_int(conf, g_player == 1 ? "input_player1_joypad_index" : "input_player2_joypad_index",
g_joypad - 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 - 1);
get_binds(conf, g_player - 1, g_joypad - 1);
config_file_write(conf, g_out_path);