Rewrite retroarch-joyconfig.

Rewrites a large chunk of retroarch-joyconfig to work with "any" joypad
driver. This allows e.g. the tool to work without X. SDL event pumps
require X to work (for some reason).
This commit is contained in:
Themaister 2012-09-29 21:57:03 +02:00
parent 55573b4726
commit d40cd53e24
9 changed files with 199 additions and 110 deletions

View File

@ -21,9 +21,10 @@ OBJ = retroarch.o \
input/null.o \
screenshot.o
JOYCONFIG_OBJ := tools/retroarch-joyconfig.o \
JOYCONFIG_OBJ = tools/retroarch-joyconfig.o \
conf/config_file.o \
compat/compat.o
compat/compat.o \
input/input_common.o
HEADERS = $(wildcard */*.h) $(wildcard *.h)
@ -52,6 +53,7 @@ endif
ifneq ($(findstring Linux,$(OS)),)
LIBS += -lrt
OBJ += input/linuxraw_input.o input/linuxraw_joypad.o
JOYCONFIG_OBJ += input/linuxraw_joypad.o
endif
ifeq ($(HAVE_THREADS), 1)
@ -147,6 +149,7 @@ endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/sdl_gfx.o input/sdl_input.o input/sdl_joypad.o audio/sdl_audio.o
JOYCONFIG_OBJ += input/sdl_joypad.o
DEFINES += $(SDL_CFLAGS) $(BSD_LOCAL_INC)
LIBS += $(SDL_LIBS)

View File

@ -24,7 +24,10 @@ OBJ = retroarch.o \
JOBJ := conf/config_file.o \
tools/retroarch-joyconfig.o \
compat/compat.o
compat/compat.o \
input/input_common.o \
input/dinput.o \
input/sdl_joypad.o
CC = gcc
CXX = g++

View File

@ -150,10 +150,14 @@ typedef struct audio_driver
#define NO_BTN UINT16_C(0xFFFF) // I hope no joypad will ever have this many buttons ... ;)
#define HAT_UP_MASK (1 << 15)
#define HAT_DOWN_MASK (1 << 14)
#define HAT_LEFT_MASK (1 << 13)
#define HAT_RIGHT_MASK (1 << 12)
#define HAT_UP_SHIFT 15
#define HAT_DOWN_SHIFT 14
#define HAT_LEFT_SHIFT 13
#define HAT_RIGHT_SHIFT 12
#define HAT_UP_MASK (1 << HAT_UP_SHIFT)
#define HAT_DOWN_MASK (1 << HAT_DOWN_SHIFT)
#define HAT_LEFT_MASK (1 << HAT_LEFT_SHIFT)
#define HAT_RIGHT_MASK (1 << HAT_RIGHT_SHIFT)
#define HAT_MAP(x, hat) ((x & ((1 << 12) - 1)) | hat)
#define HAT_MASK (HAT_UP_MASK | HAT_DOWN_MASK | HAT_LEFT_MASK | HAT_RIGHT_MASK)

View File

@ -246,8 +246,14 @@ static void dinput_poll(void)
}
}
static bool dinput_query_pad(unsigned pad)
{
return pad < MAX_PLAYERS && g_pads[pad].joypad;
}
const rarch_joypad_driver_t dinput_joypad = {
dinput_init,
dinput_query_pad,
dinput_destroy,
dinput_button,
dinput_axis,

View File

@ -26,12 +26,12 @@ static const rarch_joypad_driver_t *joypad_drivers[] = {
#ifdef HAVE_DINPUT
&dinput_joypad,
#endif
#ifdef __linux
&linuxraw_joypad,
#endif
#ifdef HAVE_SDL
&sdl_joypad,
#endif
#ifdef __linux
&linuxraw_joypad,
#endif
};
const rarch_joypad_driver_t *input_joypad_find_driver(const char *ident)
@ -40,7 +40,7 @@ const rarch_joypad_driver_t *input_joypad_find_driver(const char *ident)
{
if (strcmp(ident, joypad_drivers[i]->ident) == 0)
{
RARCH_LOG("Found joypad driver: %s\n", joypad_drivers[i]->ident);
RARCH_LOG("Found joypad driver: \"%s\".\n", joypad_drivers[i]->ident);
return joypad_drivers[i];
}
}
@ -54,7 +54,7 @@ const rarch_joypad_driver_t *input_joypad_init_first(void)
{
if (joypad_drivers[i]->init())
{
RARCH_LOG("Found joypad driver: %s\n", joypad_drivers[i]->ident);
RARCH_LOG("Found joypad driver: \"%s\".\n", joypad_drivers[i]->ident);
return joypad_drivers[i];
}
}
@ -121,3 +121,30 @@ int16_t input_joypad_analog(const rarch_joypad_driver_t *driver,
return digital_right + digital_left;
}
int16_t input_joypad_axis_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned axis)
{
if (!driver)
return 0;
return driver->axis(joypad, AXIS_POS(axis)) + driver->axis(joypad, AXIS_NEG(axis));
}
bool input_joypad_button_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned button)
{
if (!driver)
return false;
return driver->button(joypad, button);
}
bool input_joypad_hat_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned hat_dir, unsigned hat)
{
if (!driver)
return false;
return driver->button(joypad, HAT_MAP(hat, hat_dir));
}

View File

@ -49,6 +49,7 @@ static inline void input_conv_analog_id_to_bind_id(unsigned index, unsigned id,
typedef struct rarch_joypad_driver
{
bool (*init)(void);
bool (*query_pad)(unsigned);
void (*destroy)(void);
bool (*button)(unsigned, uint16_t);
int16_t (*axis)(unsigned, uint32_t);
@ -66,6 +67,13 @@ bool input_joypad_pressed(const rarch_joypad_driver_t *driver,
int16_t input_joypad_analog(const rarch_joypad_driver_t *driver,
unsigned port, unsigned index, unsigned id, const struct retro_keybind *binds);
int16_t input_joypad_axis_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned axis);
bool input_joypad_button_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned button);
bool input_joypad_hat_raw(const rarch_joypad_driver_t *driver,
unsigned joypad, unsigned hat_dir, unsigned hat);
void input_joypad_poll(const rarch_joypad_driver_t *driver);
extern const rarch_joypad_driver_t dinput_joypad;

View File

@ -133,8 +133,14 @@ static int16_t linuxraw_joypad_axis(unsigned port, uint32_t joyaxis)
return val;
}
static bool linuxraw_joypad_query_pad(unsigned pad)
{
return pad < MAX_PLAYERS && g_pads[pad].fd >= 0;
}
const rarch_joypad_driver_t linuxraw_joypad = {
linuxraw_joypad_init,
linuxraw_joypad_query_pad,
linuxraw_joypad_destroy,
linuxraw_joypad_button,
linuxraw_joypad_axis,

View File

@ -150,8 +150,14 @@ static void sdl_joypad_poll(void)
SDL_JoystickUpdate();
}
static bool sdl_joypad_query_pad(unsigned pad)
{
return pad < MAX_PLAYERS && g_pads[pad].joypad;
}
const rarch_joypad_driver_t sdl_joypad = {
sdl_joypad_init,
sdl_joypad_query_pad,
sdl_joypad_destroy,
sdl_joypad_button,
sdl_joypad_axis,

View File

@ -17,19 +17,22 @@
#include "config.h"
#endif
#ifdef HAVE_SDL
#include "SDL.h"
#endif
#include "conf/config_file.h"
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "../compat/getopt_rarch.h"
#include "../boolean.h"
#include "general.h"
#include "../input/input_common.h"
#include "../general.h"
#include <assert.h>
#include "../compat/posix_string.h"
// Need to be present for build to work, but it's not *really* used.
// Better than having to build special versions of lots of objects with special #ifdefs.
struct settings g_settings;
struct global g_extern;
driver_t driver;
static int g_player = 1;
static int g_joypad = 0;
static char *g_in_path = NULL;
@ -118,41 +121,69 @@ static struct bind binds[] = {
MISC_BIND("Slow motion", slowmotion),
};
#define MAX_BUTTONS 32
#define MAX_AXES 32
#define MAX_HATS 32
struct poll_data
{
bool buttons[MAX_BUTTONS];
int16_t axes[MAX_AXES];
uint16_t hats[MAX_HATS];
};
static void poll_joypad(const rarch_joypad_driver_t *driver,
unsigned pad,
struct poll_data *data)
{
input_joypad_poll(driver);
for (unsigned i = 0; i < MAX_BUTTONS; i++)
data->buttons[i] = input_joypad_button_raw(driver, pad, i);
for (unsigned i = 0; i < MAX_AXES; i++)
data->axes[i] = input_joypad_axis_raw(driver, pad, i);
for (unsigned i = 0; i < MAX_HATS; i++)
{
uint16_t hat = 0;
hat |= input_joypad_hat_raw(driver, pad, HAT_UP_MASK, i) << HAT_UP_SHIFT;
hat |= input_joypad_hat_raw(driver, pad, HAT_DOWN_MASK, i) << HAT_DOWN_SHIFT;
hat |= input_joypad_hat_raw(driver, pad, HAT_LEFT_MASK, i) << HAT_LEFT_SHIFT;
hat |= input_joypad_hat_raw(driver, pad, HAT_RIGHT_MASK, i) << HAT_RIGHT_SHIFT;
data->hats[i] = hat;
}
}
static void get_binds(config_file_t *conf, int player, int joypad)
{
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) < 0)
const rarch_joypad_driver_t *driver = input_joypad_init_first();
if (!driver)
{
fprintf(stderr, "Failed to init joystick subsystem.\n");
fprintf(stderr, "Cannot find any valid input driver.\n");
exit(1);
}
SDL_Joystick *joystick;
int num = SDL_NumJoysticks();
if (joypad >= num)
if (!driver->query_pad(joypad))
{
fprintf(stderr, "Cannot find joystick at index #%d, only have %d joystick(s) available ...\n", joypad, num);
fprintf(stderr, "Couldn't open joystick #%u.\n", joypad);
exit(1);
}
joystick = SDL_JoystickOpen(joypad);
if (!joystick)
{
fprintf(stderr, "Cannot open joystick.\n");
exit(1);
}
fprintf(stderr, "Found joypad driver: %s\n", driver->ident);
int last_axis = -1;
int16_t initial_axes[MAX_AXES] = {0};
struct poll_data old_poll = {{0}};
struct poll_data new_poll = {{0}};
int last_axis = -1;
bool block_axis = false;
int num_axes = SDL_JoystickNumAxes(joystick);
int *initial_axes = (int*)calloc(num_axes, sizeof(int));
assert(initial_axes);
poll_joypad(driver, joypad, &old_poll);
SDL_PumpEvents();
SDL_JoystickUpdate();
for (int i = 0; i < num_axes; i++)
for (int i = 0; i < MAX_AXES; i++)
{
Sint16 initial = SDL_JoystickGetAxis(joystick, i);
int16_t initial = input_joypad_axis_raw(driver, joypad, i);
if (abs(initial) < 20000)
initial = 0;
@ -161,116 +192,111 @@ static void get_binds(config_file_t *conf, int player, int joypad)
// If default negative, we can't trigger on the negative axis, and similar with defaulted positive axes.
if (initial)
fprintf(stderr, "Axis %d is defaulted to %s axis value of %d\n", i, initial > 0 ? "positive" : "negative", (int)initial);
fprintf(stderr, "Axis %d is defaulted to %s axis value of %d\n", i, initial > 0 ? "positive" : "negative", initial);
initial_axes[i] = initial;
}
fprintf(stderr, "Configuring binds for player #%d on joypad #%d (%s)\n",
player + 1, joypad, SDL_JoystickName(joypad));
fprintf(stderr, "Press Ctrl-C to exit early.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Configuring binds for player #%d on joypad #%d.\n\n",
player + 1, joypad);
for (unsigned i = 0; i < sizeof(binds) / sizeof(struct bind) && (g_use_misc || !binds[i].is_misc) ; i++)
for (unsigned i = 0; i < sizeof(binds) / sizeof(binds[0]) && (g_use_misc || !binds[i].is_misc) ; i++)
{
fprintf(stderr, "%s\n", binds[i].keystr);
bool done = false;
SDL_Event event;
int value;
const char *quark;
unsigned player_index = binds[i].is_misc ? 0 : player;
while (SDL_WaitEvent(&event) && !done)
for (;;)
{
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_index], event.jbutton.button);
break;
old_poll = new_poll;
case SDL_JOYAXISMOTION:
// To avoid pegging CPU.
// Ideally use an event-based joypad scheme,
// but it adds far more complexity, so, meh.
rarch_sleep(10);
poll_joypad(driver, joypad, &new_poll);
for (unsigned j = 0; j < MAX_BUTTONS; j++)
{
if (new_poll.buttons[j] && !old_poll.buttons[j])
{
bool same_axis = last_axis == event.jaxis.axis;
bool require_negative = initial_axes[event.jaxis.axis] > 0;
bool require_positive = initial_axes[event.jaxis.axis] < 0;
fprintf(stderr, "\tJoybutton pressed: %u\n", j);
config_set_int(conf, binds[i].confbtn[player_index], j);
goto out;
}
}
for (unsigned j = 0; j < MAX_AXES; j++)
{
if (new_poll.axes[j] != old_poll.axes[j])
{
int16_t value = new_poll.axes[j];
bool same_axis = last_axis == j;
bool require_negative = initial_axes[j] > 0;
bool require_positive = initial_axes[j] < 0;
// Block the axis config until we're sure axes have returned to their neutral state.
if (same_axis)
{
if (abs(event.jaxis.value) < 10000 ||
(require_positive && event.jaxis.value < 0) ||
(require_negative && event.jaxis.value > 0))
if (abs(value) < 10000 ||
(require_positive && value < 0) ||
(require_negative && value > 0))
block_axis = false;
}
// If axes are in their neutral state, we can't allow it.
if (require_negative && event.jaxis.value >= 0)
break;
if (require_positive && event.jaxis.value <= 0)
break;
if (require_negative && value >= 0)
continue;
if (require_positive && value <= 0)
continue;
if (block_axis)
break;
continue;
if (abs(event.jaxis.value) > 20000)
if (abs(value) > 20000)
{
last_axis = event.jaxis.axis;
fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", (int)event.jaxis.axis, (int)event.jaxis.value);
done = true;
block_axis = true;
last_axis = j;
fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", j, value);
char buf[8];
snprintf(buf, sizeof(buf), event.jaxis.value > 0 ? "+%d" : "-%d", event.jaxis.axis);
snprintf(buf, sizeof(buf),
value > 0 ? "+%d" : "-%d", j);
config_set_string(conf, binds[i].confaxis[player_index], buf);
block_axis = true;
goto out;
}
break;
}
}
case SDL_KEYDOWN:
fprintf(stderr, ":V\n");
break;
for (unsigned j = 0; j < MAX_HATS; j++)
{
const char *quark = NULL;
uint16_t value = new_poll.hats[j];
uint16_t old_value = old_poll.hats[j];
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;
if ((value & HAT_UP_MASK) && !(old_value & HAT_UP_MASK))
quark = "up";
else if ((value & HAT_LEFT_MASK) && !(old_value & HAT_LEFT_MASK))
quark = "left";
else if ((value & HAT_RIGHT_MASK) && !(old_value & HAT_RIGHT_MASK))
quark = "right";
else if ((value & HAT_DOWN_MASK) && !(old_value & HAT_DOWN_MASK))
quark = "down";
fprintf(stderr, "\tJoyhat moved: Hat %d, direction %s\n", (int)event.jhat.hat, quark);
done = true;
if (quark)
{
fprintf(stderr, "\tJoyhat moved: Hat %d, direction %s\n", j, quark);
char buf[16];
snprintf(buf, sizeof(buf), "h%d%s", event.jhat.hat, quark);
snprintf(buf, sizeof(buf), "h%d%s", j, quark);
config_set_string(conf, binds[i].confbtn[player_index], buf);
break;
case SDL_QUIT:
goto end;
default:
break;
goto out;
}
}
}
out:
old_poll = new_poll;
}
free(initial_axes);
end:
SDL_JoystickClose(joystick);
SDL_Quit();
}
static void parse_input(int argc, char *argv[])