Added support for SDL_GameController with fallback to default method.

This commit is contained in:
David Salvisberg 2015-01-04 14:46:13 +01:00
parent 02f19c03c9
commit 160bfc0702
9 changed files with 188 additions and 14 deletions

View file

@ -23,6 +23,7 @@
#include <SDL_events.h>
#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>
#include <SDL_messagebox.h>
#include <SDL_timer.h>
#include <SDL_thread.h>
@ -99,7 +100,9 @@ void EventThread::process(RGSSThreadData &rtData)
bool terminate = false;
SDL_Joystick *js = 0;
if (SDL_NumJoysticks() > 0)
if (rtData.gamecontroller != NULL)
js = SDL_GameControllerGetJoystick(rtData.gamecontroller);
else if (SDL_NumJoysticks() > 0)
js = SDL_JoystickOpen(0);
char buffer[128];
@ -286,7 +289,19 @@ void EventThread::process(RGSSThreadData &rtData)
if (event.jdevice.which > 0)
break;
js = SDL_JoystickOpen(0);
if (SDL_IsGameController(0))
rtData.gamecontroller = SDL_GameControllerOpen(0);
if (rtData.gamecontroller != NULL)
{
js = SDL_GameControllerGetJoystick(rtData.gamecontroller);
/* generate new default bindings if a new controller is connected and
* the user hasn't set a custom set of keybinds yet */
rtData.bindingUpdateMsg.post(loadBindings(rtData.config, rtData.gamecontroller));
}
else
{
js = SDL_JoystickOpen(0);
}
break;
case SDL_JOYDEVICEREMOVED :
@ -358,7 +373,9 @@ void EventThread::process(RGSSThreadData &rtData)
break;
}
if (SDL_JoystickGetAttached(js))
if (rtData.gamecontroller != NULL && SDL_GameControllerGetAttached(rtData.gamecontroller))
SDL_GameControllerClose(rtData.gamecontroller);
else if (SDL_JoystickGetAttached(js))
SDL_JoystickClose(js);
delete sMenu;

View file

@ -29,6 +29,7 @@
#include <SDL_scancode.h>
#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>
#include <SDL_mouse.h>
#include <SDL_mutex.h>
@ -231,6 +232,8 @@ struct RGSSThreadData
Config config;
SDL_GameController *gamecontroller;
std::string rgssErrorMsg;
RGSSThreadData(EventThread *ethread,

View file

@ -45,6 +45,12 @@ struct KbBindingData
}
};
struct GcBindingData
{
SDL_GameControllerButton source;
Input::ButtonCode target;
};
struct JsBindingData
{
int source;
@ -101,6 +107,24 @@ static elementsN(defaultKbBindings);
static elementsN(defaultKbBindings1);
static elementsN(defaultKbBindings2);
static const GcBindingData defaultGcBindings[] =
{
{ SDL_CONTROLLER_BUTTON_DPAD_LEFT, Input::Left },
{ SDL_CONTROLLER_BUTTON_DPAD_RIGHT, Input::Right },
{ SDL_CONTROLLER_BUTTON_DPAD_UP, Input::Up },
{ SDL_CONTROLLER_BUTTON_DPAD_DOWN, Input::Down },
{ SDL_CONTROLLER_BUTTON_A, Input::C },
{ SDL_CONTROLLER_BUTTON_B, Input::B },
{ SDL_CONTROLLER_BUTTON_START, Input::A },
{ SDL_CONTROLLER_BUTTON_X, Input::X },
{ SDL_CONTROLLER_BUTTON_Y, Input::Y },
{ SDL_CONTROLLER_BUTTON_BACK, Input::Z },
{ SDL_CONTROLLER_BUTTON_LEFTSHOULDER, Input::L },
{ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, Input::R }
};
static elementsN(defaultGcBindings);
static const JsBindingData defaultJsBindings[] =
{
{ 0, Input::A },
@ -143,7 +167,38 @@ static void addHatBinding(BDescVec &d, uint8_t hat, uint8_t pos, Input::ButtonCo
d.push_back(desc);
}
BDescVec genDefaultBindings(const Config &conf)
static void addGcBinding(BDescVec &d, SDL_GameController *gc, SDL_GameControllerButton but, Input::ButtonCode target)
{
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(gc, but);
switch(bind.bindType)
{
case SDL_CONTROLLER_BINDTYPE_BUTTON:
SourceDesc src;
src.type = JButton;
src.d.jb = bind.value.button;
BindingDesc desc;
desc.src = src;
desc.target = target;
d.push_back(desc);
break;
case SDL_CONTROLLER_BINDTYPE_HAT:
addHatBinding(d, bind.value.hat.hat, bind.value.hat.hat_mask, target);
break;
case SDL_CONTROLLER_BINDTYPE_AXIS:
/* For now if a button turns out to be analog, let's assume positive is the correct direction */
addAxisBinding(d, bind.value.axis, Positive, target);
case SDL_CONTROLLER_BINDTYPE_NONE:
break;
}
}
BDescVec genDefaultBindings(const Config &conf, SDL_GameController *gc)
{
BDescVec d;
@ -157,13 +212,23 @@ BDescVec genDefaultBindings(const Config &conf)
for (size_t i = 0; i < defaultKbBindings2N; ++i)
defaultKbBindings2[i].add(d);
for (size_t i = 0; i < defaultJsBindingsN; ++i)
defaultJsBindings[i].add(d);
addAxisBinding(d, 0, Negative, Input::Left );
addAxisBinding(d, 0, Positive, Input::Right);
addAxisBinding(d, 1, Negative, Input::Up );
addAxisBinding(d, 1, Positive, Input::Down );
/* Try to get a sane binding through SDL_GameController
* if that doesn't work fall back to the default JS bindings */
if (gc != NULL)
{
for(size_t i = 0; i < defaultGcBindingsN; ++i)
addGcBinding(d, gc, defaultGcBindings[i].source, defaultGcBindings[i].target);
return d;
}
for (size_t i = 0; i < defaultJsBindingsN; ++i)
defaultJsBindings[i].add(d);
addHatBinding(d, 0, SDL_HAT_LEFT, Input::Left );
addHatBinding(d, 0, SDL_HAT_RIGHT, Input::Right);
@ -320,7 +385,7 @@ static bool readBindings(BDescVec &out, const std::string &dir,
return true;
}
BDescVec loadBindings(const Config &conf)
BDescVec loadBindings(const Config &conf, SDL_GameController *gc)
{
BDescVec d;
@ -330,5 +395,5 @@ BDescVec loadBindings(const Config &conf)
if (readBindings(d, conf.commonDataPath, conf.rgssVersion))
return d;
return genDefaultBindings(conf);
return genDefaultBindings(conf, gc);
}

View file

@ -26,6 +26,7 @@
#include <SDL_scancode.h>
#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>
#include <stdint.h>
#include <assert.h>
#include <vector>
@ -111,9 +112,9 @@ struct BindingDesc
typedef std::vector<BindingDesc> BDescVec;
struct Config;
BDescVec genDefaultBindings(const Config &conf);
BDescVec genDefaultBindings(const Config &conf, SDL_GameController *gc);
void storeBindings(const BDescVec &d, const Config &conf);
BDescVec loadBindings(const Config &conf);
BDescVec loadBindings(const Config &conf, SDL_GameController *gc);
#endif // KEYBINDINGS_H

View file

@ -25,6 +25,7 @@
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <SDL_sound.h>
#include <SDL_gamecontroller.h>
#include <unistd.h>
#include <string.h>
@ -41,6 +42,7 @@
#include "binding.h"
#include "icon.png.xxd"
#include "gamecontrollerdb.txt.xxd"
static void
rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
@ -175,7 +177,7 @@ static void printRgssVersion(int ver)
int main(int argc, char *argv[])
{
/* initialize SDL first */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0)
{
Debug() << "Error initializing SDL:" << SDL_GetError();
@ -276,8 +278,17 @@ int main(int argc, char *argv[])
EventThread eventThread;
RGSSThreadData rtData(&eventThread, argv[0], win, conf);
/* Add controller bindings from embedded controller DB */
SDL_RWops *controllerDB;
controllerDB = SDL_RWFromConstMem(assets_gamecontrollerdb_txt, assets_gamecontrollerdb_txt_len);
SDL_GameControllerAddMappingsFromRW(controllerDB, 1);
rtData.gamecontroller = NULL;
if (SDL_NumJoysticks() > 0 && SDL_IsGameController(0))
rtData.gamecontroller = SDL_GameControllerOpen(0);
/* Load and post key bindings */
rtData.bindingUpdateMsg.post(loadBindings(conf));
rtData.bindingUpdateMsg.post(loadBindings(conf, rtData.gamecontroller));
/* Start RGSS thread */
SDL_Thread *rgssThread =

View file

@ -706,7 +706,7 @@ struct SettingsMenuPrivate
void onResetToDefault()
{
setupBindingData(genDefaultBindings(rtData.config));
setupBindingData(genDefaultBindings(rtData.config, rtData.gamecontroller));
updateDuplicateStatus();
redraw();
}