2012-08-15 02:41:21 +02:00
|
|
|
/*
|
|
|
|
* This software is licensed under the terms of the MIT-License
|
2017-02-11 04:52:08 +01:00
|
|
|
* See COPYING for further information.
|
2012-08-15 02:41:21 +02:00
|
|
|
* ---
|
|
|
|
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
2012-08-15 02:48:19 +02:00
|
|
|
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
|
2012-08-15 02:41:21 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gamepad.h"
|
|
|
|
#include "taisei_err.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "events.h"
|
2012-08-15 16:36:39 +02:00
|
|
|
#include "global.h"
|
2012-08-15 02:41:21 +02:00
|
|
|
|
|
|
|
static struct {
|
|
|
|
int initialized;
|
|
|
|
SDL_Joystick *device;
|
2017-02-27 23:58:47 +01:00
|
|
|
signed char *axis;
|
2012-08-15 02:41:21 +02:00
|
|
|
} gamepad;
|
|
|
|
|
|
|
|
void gamepad_init(void) {
|
|
|
|
memset(&gamepad, 0, sizeof(gamepad));
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(!config_get_int(CONFIG_GAMEPAD_ENABLED))
|
2012-08-15 02:41:21 +02:00
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
if(gamepad.initialized)
|
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
|
|
|
|
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
int i, cnt = gamepad_devicecount();
|
2012-08-17 14:59:06 +02:00
|
|
|
printf("gamepad_init(): found %i devices\n", cnt);
|
2012-08-15 02:41:21 +02:00
|
|
|
for(i = 0; i < cnt; ++i)
|
2017-02-04 03:56:40 +01:00
|
|
|
printf("%i: %s\n", i, SDL_JoystickNameForIndex(i));
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int dev = config_get_int(CONFIG_GAMEPAD_DEVICE);
|
2012-08-15 02:41:21 +02:00
|
|
|
if(dev < 0 || dev >= cnt) {
|
|
|
|
warnx("gamepad_init(): device %i is not available\n", dev);
|
|
|
|
gamepad_shutdown();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
gamepad.device = SDL_JoystickOpen(dev);
|
|
|
|
if(!gamepad.device) {
|
2012-08-16 23:35:48 +02:00
|
|
|
warnx("gamepad_init(): failed to open device %i [%s]", dev, gamepad_devicename(dev));
|
2012-08-15 02:41:21 +02:00
|
|
|
gamepad_shutdown();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
gamepad.axis = malloc(SDL_JoystickNumAxes(gamepad.device));
|
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
printf("gamepad_init(): using device #%i: %s\n", dev, gamepad_devicename(dev));
|
2012-08-15 02:41:21 +02:00
|
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
gamepad.initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_shutdown(void) {
|
2012-08-17 14:59:06 +02:00
|
|
|
if(!gamepad.initialized)
|
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-17 14:59:06 +02:00
|
|
|
if(gamepad.initialized != 2)
|
|
|
|
printf("gamepad_shutdown(): disabled the gamepad subsystem\n");
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(gamepad.device)
|
|
|
|
SDL_JoystickClose(gamepad.device);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
free(gamepad.axis);
|
|
|
|
gamepad.axis = NULL;
|
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
SDL_JoystickEventState(SDL_IGNORE);
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
|
|
gamepad.initialized = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_restart(void) {
|
|
|
|
gamepad_shutdown();
|
|
|
|
gamepad_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
int gamepad_axis2gamekey(int id, int val) {
|
2017-02-04 14:41:15 +01:00
|
|
|
val *= SIGN(gamepad_axis_sens(id));
|
|
|
|
|
|
|
|
if(!val) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR)) {
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_LEFT ? KEY_LEFT : KEY_RIGHT;
|
2017-02-04 14:41:15 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD)) {
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_UP ? KEY_UP : KEY_DOWN;
|
2017-02-04 14:41:15 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
return -1;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int gamepad_axis2menuevt(int id, int val) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR))
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_LEFT ? E_CursorLeft : E_CursorRight;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD))
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_UP ? E_CursorUp : E_CursorDown;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
return -1;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
int gamepad_axis2gameevt(int id) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR))
|
2012-08-15 16:36:39 +02:00
|
|
|
return E_PlrAxisLR;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD))
|
2012-08-15 16:36:39 +02:00
|
|
|
return E_PlrAxisUD;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
float gamepad_axis_sens(int id) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR))
|
|
|
|
return config_get_float(CONFIG_GAMEPAD_AXIS_LR_SENS);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD))
|
|
|
|
return config_get_float(CONFIG_GAMEPAD_AXIS_UD_SENS);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
void gamepad_axis(int id, int raw, EventHandler handler, EventFlags flags, void *arg) {
|
2017-02-27 23:58:47 +01:00
|
|
|
signed char *a = gamepad.axis;
|
|
|
|
signed char val = AXISVAL(raw);
|
|
|
|
bool free = config_get_int(CONFIG_GAMEPAD_AXIS_FREE);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
bool menu = flags & EF_Menu;
|
|
|
|
bool game = flags & EF_Game;
|
|
|
|
bool gp = flags & EF_Gamepad;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
//printf("axis: %i %i %i\n", id, val, raw);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
if(game && free) {
|
|
|
|
int evt = gamepad_axis2gameevt(id);
|
2017-02-04 14:41:15 +01:00
|
|
|
if(evt >= 0) {
|
|
|
|
double sens = gamepad_axis_sens(id);
|
|
|
|
int sens_sign = SIGN(sens);
|
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
double x = raw / (double)GAMEPAD_AXIS_MAX;
|
2017-02-04 14:41:15 +01:00
|
|
|
int in_sign = SIGN(x);
|
|
|
|
|
|
|
|
x = pow(fabs(x), 1.0 / fabs(sens)) * in_sign * sens_sign;
|
|
|
|
x = x ? x : 0;
|
2017-02-27 23:58:47 +01:00
|
|
|
x = clamp(x * GAMEPAD_AXIS_MAX, GAMEPAD_AXIS_MIN, GAMEPAD_AXIS_MAX);
|
2017-02-04 14:41:15 +01:00
|
|
|
|
|
|
|
handler(evt, x, arg);
|
|
|
|
}
|
2012-08-15 16:36:39 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(val) { // simulate press
|
|
|
|
if(!a[id]) {
|
|
|
|
a[id] = val;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
if(game && !free) {
|
2012-08-15 14:33:32 +02:00
|
|
|
int key = gamepad_axis2gamekey(id, val);
|
|
|
|
if(key >= 0)
|
|
|
|
handler(E_PlrKeyDown, key, arg);
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
if(menu) {
|
|
|
|
int evt = gamepad_axis2menuevt(id, val);
|
|
|
|
if(evt >= 0)
|
|
|
|
handler(evt, 0, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
} else { // simulate release
|
2012-08-15 14:33:32 +02:00
|
|
|
if(game) {
|
|
|
|
int key = gamepad_axis2gamekey(id, a[id]);
|
|
|
|
handler(E_PlrKeyUp, key, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
a[id] = AXISVAL_NULL;
|
|
|
|
}
|
2017-02-27 23:58:47 +01:00
|
|
|
|
|
|
|
if(gp) {
|
|
|
|
// we probably need a better way to pass more than an int to the handler...
|
|
|
|
handler(E_GamepadAxis, id, arg);
|
|
|
|
handler(E_GamepadAxisValue, raw, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_button(int button, int state, EventHandler handler, EventFlags flags, void *arg) {
|
|
|
|
int menu = flags & EF_Menu;
|
|
|
|
int game = flags & EF_Game;
|
2012-08-17 00:41:33 +02:00
|
|
|
int gpad = flags & EF_Gamepad;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int gpkey = config_gamepad_key_from_gamepad_button(button);
|
|
|
|
int key = config_key_from_gamepad_key(gpkey);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
//printf("button: %i %i\n", button, state);
|
|
|
|
//printf("gpkey: %i\n", gpkey);
|
|
|
|
//printf("key: %i\n", key);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(state == SDL_PRESSED) {
|
|
|
|
if(game) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(gpkey == GAMEPAD_KEY_PAUSE) {
|
2012-08-15 02:41:21 +02:00
|
|
|
handler(E_Pause, 0, arg);
|
2017-02-17 17:03:49 +01:00
|
|
|
} else if(key >= 0) {
|
2012-08-15 02:41:21 +02:00
|
|
|
handler(E_PlrKeyDown, key, arg);
|
2017-02-17 17:03:49 +01:00
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(menu) switch(key) {
|
|
|
|
case KEY_UP: handler(E_CursorUp, 0, arg); break;
|
|
|
|
case KEY_DOWN: handler(E_CursorDown, 0, arg); break;
|
|
|
|
case KEY_LEFT: handler(E_CursorLeft, 0, arg); break;
|
|
|
|
case KEY_RIGHT: handler(E_CursorRight, 0, arg); break;
|
|
|
|
case KEY_FOCUS: handler(E_MenuAbort, 0, arg); break;
|
|
|
|
case KEY_SHOT: handler(E_MenuAccept, 0, arg); break;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
if(gpad)
|
|
|
|
handler(E_GamepadKeyDown, button, arg);
|
|
|
|
} else {
|
|
|
|
if(game && key >= 0)
|
|
|
|
handler(E_PlrKeyUp, key, arg);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
if(gpad)
|
|
|
|
handler(E_GamepadKeyUp, button, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_event(SDL_Event *event, EventHandler handler, EventFlags flags, void *arg) {
|
|
|
|
if(!gamepad.initialized)
|
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
int val;
|
2017-02-27 23:58:47 +01:00
|
|
|
int sens = clamp(config_get_float(CONFIG_GAMEPAD_AXIS_DEADZONE), 0, 1) * GAMEPAD_AXIS_MAX;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
switch(event->type) {
|
|
|
|
case SDL_JOYAXISMOTION:
|
|
|
|
val = event->jaxis.value;
|
2012-08-15 16:36:39 +02:00
|
|
|
if(val < -sens || val > sens || !val)
|
|
|
|
gamepad_axis(event->jaxis.axis, val, handler, flags, arg);
|
2012-08-15 02:41:21 +02:00
|
|
|
break;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP:
|
|
|
|
gamepad_button(event->jbutton.button, event->jbutton.state, handler, flags, arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-16 23:35:48 +02:00
|
|
|
|
|
|
|
int gamepad_devicecount(void) {
|
|
|
|
return SDL_NumJoysticks();
|
|
|
|
}
|
|
|
|
|
|
|
|
char* gamepad_devicename(int id) {
|
2017-02-04 03:56:40 +01:00
|
|
|
return (char*)SDL_JoystickNameForIndex(id);
|
2012-08-16 23:35:48 +02:00
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
bool gamepad_buttonpressed(int btn) {
|
2012-08-17 20:58:23 +02:00
|
|
|
return SDL_JoystickGetButton(gamepad.device, btn);
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
bool gamepad_gamekeypressed(KeyIndex key) {
|
2012-08-17 20:58:23 +02:00
|
|
|
if(!gamepad.initialized)
|
2017-02-17 17:03:49 +01:00
|
|
|
return false;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int gpkey = config_gamepad_key_from_key(key);
|
2017-02-27 23:04:30 +01:00
|
|
|
|
|
|
|
if(gpkey < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int cfgidx = GPKEYIDX_TO_CFGIDX(gpkey);
|
|
|
|
int button = config_get_int(cfgidx);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
return gamepad_buttonpressed(button);
|
2012-08-17 20:58:23 +02:00
|
|
|
}
|
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
void gamepad_init_bare(void) {
|
|
|
|
if(gamepad.initialized)
|
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
|
|
|
|
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
gamepad.initialized = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_shutdown_bare(void) {
|
|
|
|
if(gamepad.initialized == 2)
|
|
|
|
gamepad_shutdown();
|
|
|
|
}
|