mirror of
https://github.com/libretro/RetroArch
synced 2025-03-03 04:14:00 +00:00
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:
parent
55573b4726
commit
d40cd53e24
7
Makefile
7
Makefile
@ -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)
|
||||
|
||||
|
@ -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++
|
||||
|
12
driver.h
12
driver.h
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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[])
|
||||
|
Loading…
x
Reference in New Issue
Block a user