SDL: Gamepads can now be preferentially loaded

This commit is contained in:
Jeffrey Pfau 2015-03-21 16:27:00 -07:00
parent c1d02a1369
commit d4ef56cd16
11 changed files with 173 additions and 56 deletions

View File

@ -79,6 +79,8 @@ public:
Configuration* overrides() { return GBAConfigGetOverrides(&m_config); }
void saveOverride(const GBACartridgeOverride&);
Configuration* input() { return GBAConfigGetInput(&m_config); }
public slots:
void setOption(const char* key, bool value);
void setOption(const char* key, int value);
@ -90,11 +92,8 @@ public slots:
void write();
private:
Configuration* configuration() { return &m_config.configTable; }
Configuration* defaults() { return &m_config.defaultsTable; }
friend class InputController; // TODO: Do this without friends
GBAConfig m_config;
GBAOptions m_opts;

View File

@ -19,6 +19,9 @@ extern "C" {
using namespace QGBA;
int InputController::s_sdlInited = 0;
GBASDLEvents InputController::s_sdlEvents;
InputController::InputController(int playerId, QObject* parent)
: QObject(parent)
, m_playerId(playerId)
@ -28,8 +31,11 @@ InputController::InputController(int playerId, QObject* parent)
GBAInputMapInit(&m_inputMap);
#ifdef BUILD_SDL
m_sdlEvents.bindings = &m_inputMap;
GBASDLInitEvents(&m_sdlEvents, playerId);
if (s_sdlInited == 0) {
GBASDLInitEvents(&s_sdlEvents);
}
++s_sdlInited;
m_sdlPlayer.bindings = &m_inputMap;
GBASDLInitBindings(&m_inputMap);
m_gamepadTimer = new QTimer(this);
@ -54,7 +60,10 @@ InputController::~InputController() {
GBAInputMapDeinit(&m_inputMap);
#ifdef BUILD_SDL
GBASDLDeinitEvents(&m_sdlEvents);
--s_sdlInited;
if (s_sdlInited == 0) {
GBASDLDeinitEvents(&s_sdlEvents);
}
#endif
}
@ -62,26 +71,31 @@ void InputController::setConfiguration(ConfigController* config) {
m_config = config;
loadConfiguration(KEYBOARD);
#ifdef BUILD_SDL
GBASDLEventsLoadConfig(&s_sdlEvents, config->input());
if (!m_playerAttached) {
GBASDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer);
m_playerAttached = true;
}
loadConfiguration(SDL_BINDING_BUTTON);
loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
#endif
}
void InputController::loadConfiguration(uint32_t type) {
GBAInputMapLoad(&m_inputMap, type, m_config->configuration());
GBAInputMapLoad(&m_inputMap, type, m_config->input());
}
void InputController::loadProfile(uint32_t type, const char* profile) {
GBAInputProfileLoad(&m_inputMap, type, m_config->configuration(), profile);
GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile);
}
void InputController::saveConfiguration(uint32_t type) {
GBAInputMapSave(&m_inputMap, type, m_config->configuration());
GBAInputMapSave(&m_inputMap, type, m_config->input());
m_config->write();
}
void InputController::saveProfile(uint32_t type, const char* profile) {
GBAInputProfileSave(&m_inputMap, type, m_config->configuration(), profile);
GBAInputProfileSave(&m_inputMap, type, m_config->input(), profile);
m_config->write();
}
@ -90,9 +104,9 @@ const char* InputController::profileForType(uint32_t type) {
#ifdef BUILD_SDL
if (type == SDL_BINDING_BUTTON) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
return SDL_JoystickName(m_sdlEvents.joystick);
return SDL_JoystickName(m_sdlPlayer.joystick);
#else
return SDL_JoystickName(SDL_JoystickIndex(m_sdlEvents.joystick));
return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick));
#endif
}
#endif
@ -109,7 +123,7 @@ void InputController::bindKey(uint32_t type, int key, GBAKey gbaKey) {
#ifdef BUILD_SDL
int InputController::testSDLEvents() {
SDL_Joystick* joystick = m_sdlEvents.joystick;
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
int activeButtons = 0;
@ -156,7 +170,7 @@ int InputController::testSDLEvents() {
}
QSet<int> InputController::activeGamepadButtons() {
SDL_Joystick* joystick = m_sdlEvents.joystick;
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
QSet<int> activeButtons;
@ -170,7 +184,7 @@ QSet<int> InputController::activeGamepadButtons() {
}
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes() {
SDL_Joystick* joystick = m_sdlEvents.joystick;
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumAxes(joystick);
QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;

View File

@ -70,7 +70,10 @@ private:
int m_playerId;
#ifdef BUILD_SDL
GBASDLEvents m_sdlEvents;
static int s_sdlInited;
static GBASDLEvents s_sdlEvents;
GBASDLPlayer m_sdlPlayer;
bool m_playerAttached;
#endif
QSet<int> m_activeButtons;

View File

@ -136,7 +136,7 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->events, &event);
GBASDLHandleEvent(context, &renderer->player, &event);
}
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {

View File

@ -65,11 +65,11 @@ bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
renderer->window = SDL_CreateWindow(PROJECT_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->events.fullscreen));
renderer->window = SDL_CreateWindow(PROJECT_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
SDL_GL_CreateContext(renderer->window);
SDL_GL_SetSwapInterval(1);
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
renderer->events.window = renderer->window;
renderer->player.window = renderer->window;
#else
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
#ifdef COLOR_16_BIT
@ -123,13 +123,13 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1);
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->events, &event);
GBASDLHandleEvent(context, &renderer->player, &event);
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Event handling can change the size of the screen
if (renderer->events.windowUpdated) {
if (renderer->player.windowUpdated) {
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer);
renderer->events.windowUpdated = 0;
renderer->player.windowUpdated = 0;
}
#endif
}

View File

@ -72,8 +72,8 @@ int main(int argc, char** argv) {
renderer.viewportWidth = opts.width;
renderer.viewportHeight = opts.height;
#if SDL_VERSION_ATLEAST(2, 0, 0)
renderer.events.fullscreen = opts.fullscreen;
renderer.events.windowUpdated = 0;
renderer.player.fullscreen = opts.fullscreen;
renderer.player.windowUpdated = 0;
#endif
renderer.ratio = graphicsOpts.multiplier;
if (renderer.ratio == 0) {
@ -103,10 +103,12 @@ int main(int argc, char** argv) {
renderer.audio.samples = context.audioBuffers;
GBASDLInitAudio(&renderer.audio, &context);
renderer.events.bindings = &inputMap;
renderer.player.bindings = &inputMap;
GBASDLInitBindings(&inputMap);
GBASDLInitEvents(&renderer.events, 0);
GBASDLInitEvents(&renderer.events);
GBASDLEventsLoadConfig(&renderer.events, GBAConfigGetInput(&config));
GBASDLAttachPlayer(&renderer.events, &renderer.player);
GBASDLPlayerLoadConfig(&renderer.player, GBAConfigGetInput(&config));
context.overrides = GBAConfigGetOverrides(&config);
int didFail = 0;

View File

@ -39,6 +39,7 @@ struct SDLSoftwareRenderer {
struct GBAVideoSoftwareRenderer d;
struct GBASDLAudio audio;
struct GBASDLEvents events;
struct GBASDLPlayer player;
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Window* window;

View File

@ -68,7 +68,7 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->events, &event);
GBASDLHandleEvent(context, &renderer->player, &event);
}
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {

View File

@ -11,6 +11,7 @@
#include "gba/serialize.h"
#include "gba/video.h"
#include "gba/renderers/video-software.h"
#include "util/configuration.h"
#include "util/vfs.h"
#if SDL_VERSION_ATLEAST(2, 0, 0) && defined(__APPLE__)
@ -19,21 +20,57 @@
#define GUI_MOD KMOD_CTRL
#endif
static int _openContexts = 0;
bool GBASDLInitEvents(struct GBASDLEvents* context, int playerId) {
if (!_openContexts && SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
bool GBASDLInitEvents(struct GBASDLEvents* context) {
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
return false;
}
++_openContexts;
SDL_JoystickEventState(SDL_ENABLE);
context->joystick = SDL_JoystickOpen(playerId);
int nJoysticks = SDL_NumJoysticks();
if (nJoysticks > 0) {
context->nJoysticks = nJoysticks;
context->joysticks = calloc(context->nJoysticks, sizeof(SDL_Joystick*));
size_t i;
for (i = 0; i < context->nJoysticks; ++i) {
context->joysticks[i] = SDL_JoystickOpen(i);
}
} else {
context->nJoysticks = 0;
context->joysticks = 0;
}
context->playersAttached = 0;
size_t i;
for (i = 0; i < MAX_PLAYERS; ++i) {
context->preferredJoysticks[i] = 0;
context->joysticksClaimed[i] = SIZE_MAX;
}
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
#endif
return true;
}
void GBASDLDeinitEvents(struct GBASDLEvents* context) {
size_t i;
for (i = 0; i < context->nJoysticks; ++i) {
SDL_JoystickClose(context->joysticks[i]);
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
char sectionName[16];
snprintf(sectionName, sizeof(sectionName), "input.%c%c%c%c", SDL_BINDING_BUTTON >> 24, SDL_BINDING_BUTTON >> 16, SDL_BINDING_BUTTON >> 8, SDL_BINDING_BUTTON);
context->preferredJoysticks[0] = ConfigurationGetValue(config, sectionName, "device0");
context->preferredJoysticks[1] = ConfigurationGetValue(config, sectionName, "device1");
context->preferredJoysticks[2] = ConfigurationGetValue(config, sectionName, "device2");
context->preferredJoysticks[3] = ConfigurationGetValue(config, sectionName, "device3");
}
void GBASDLInitBindings(struct GBAInputMap* inputMap) {
#ifdef BUILD_PANDORA
GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_PAGEDOWN, GBA_KEY_A);
@ -87,7 +124,62 @@ void GBASDLInitBindings(struct GBAInputMap* inputMap) {
GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description);
}
void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
bool GBASDLAttachPlayer(struct GBASDLEvents* events, struct GBASDLPlayer* player) {
player->joystick = 0;
player->joystickIndex = SIZE_MAX;
if (events->playersAttached >= MAX_PLAYERS) {
return false;
}
int playerId = events->playersAttached;
size_t firstUnclaimed = SIZE_MAX;
size_t i;
for (i = 0; i < events->nJoysticks; ++i) {
bool claimed = false;
int p;
for (p = 0; p < events->playersAttached; ++p) {
if (events->joysticksClaimed[p] == i) {
claimed = true;
break;
}
}
if (claimed) {
continue;
}
if (firstUnclaimed == SIZE_MAX) {
firstUnclaimed = i;
}
const char* joystickName;
#if SDL_VERSION_ATLEAST(2, 0, 0)
joystickName = SDL_JoystickName(events->joysticks[i]);
#else
joystickName = SDL_JoystickName(SDL_JoystickIndex(events->joysticks[i]));
#endif
if (events->preferredJoysticks[playerId] && strcmp(events->preferredJoysticks[playerId], joystickName) == 0) {
player->joystickIndex = i;
break;
}
}
if (player->joystickIndex == SIZE_MAX && firstUnclaimed != SIZE_MAX) {
player->joystickIndex = firstUnclaimed;
}
if (player->joystickIndex != SIZE_MAX) {
player->joystick = events->joysticks[player->joystickIndex];
events->joysticksClaimed[playerId] = player->joystickIndex;
}
++events->playersAttached;
return true;
}
void GBASDLPlayerLoadConfig(struct GBASDLPlayer* context, const struct Configuration* config) {
GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config);
if (context->joystick) {
GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
@ -99,21 +191,12 @@ void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configura
}
}
void GBASDLDeinitEvents(struct GBASDLEvents* context) {
SDL_JoystickClose(context->joystick);
--_openContexts;
if (!_openContexts) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
}
static void _pauseAfterFrame(struct GBAThread* context) {
context->frameCallback = 0;
GBAThreadPauseFromThread(context);
}
static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) {
enum GBAKey key = GBA_KEY_NONE;
if (!event->keysym.mod) {
#if !defined(BUILD_PANDORA) && SDL_VERSION_ATLEAST(2, 0, 0)
@ -230,7 +313,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
}
}
static void _GBASDLHandleJoyButton(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyButtonEvent* event) {
static void _GBASDLHandleJoyButton(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_JoyButtonEvent* event) {
enum GBAKey key = 0;
key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button);
if (key == GBA_KEY_NONE) {
@ -264,7 +347,7 @@ static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyH
context->activeKeys |= key;
}
static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_JoyAxisEvent* event) {
static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) {
int keys = context->activeKeys;
keys = GBAInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, keys);
@ -277,7 +360,7 @@ static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLEvents*
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_WindowEvent* event) {
static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_WindowEvent* event) {
UNUSED(context);
switch (event->event) {
case SDL_WINDOWEVENT_SIZE_CHANGED:
@ -287,7 +370,7 @@ static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEve
}
#endif
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const union SDL_Event* event) {
switch (event->type) {
case SDL_QUIT:
GBAThreadEnd(context);

View File

@ -12,15 +12,26 @@
#include <SDL.h>
#define SDL_BINDING_KEY 0x53444C4B
#define SDL_BINDING_BUTTON 0x53444C42
#define SDL_BINDING_KEY 0x53444C4BU
#define SDL_BINDING_BUTTON 0x53444C42U
#define MAX_PLAYERS 4
struct GBAVideoSoftwareRenderer;
struct Configuration;
struct GBASDLEvents {
SDL_Joystick** joysticks;
size_t nJoysticks;
const char* preferredJoysticks[MAX_PLAYERS];
int playersAttached;
size_t joysticksClaimed[MAX_PLAYERS];
};
struct GBASDLPlayer {
struct GBAInputMap* bindings;
SDL_Joystick* joystick;
size_t joystickIndex;
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Window* window;
int fullscreen;
@ -28,12 +39,16 @@ struct GBASDLEvents {
#endif
};
bool GBASDLInitEvents(struct GBASDLEvents*, int playerId);
bool GBASDLInitEvents(struct GBASDLEvents*);
void GBASDLDeinitEvents(struct GBASDLEvents*);
void GBASDLInitBindings(struct GBAInputMap* inputMap);
bool GBASDLAttachPlayer(struct GBASDLEvents*, struct GBASDLPlayer*);
void GBASDLEventsLoadConfig(struct GBASDLEvents*, const struct Configuration*);
void GBASDLPlayerChangeJoystick(struct GBASDLEvents*, struct GBASDLPlayer*, size_t index);
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event);
void GBASDLInitBindings(struct GBAInputMap* inputMap);
void GBASDLPlayerLoadConfig(struct GBASDLPlayer*, const struct Configuration*);
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const union SDL_Event* event);
#endif

View File

@ -18,9 +18,9 @@ bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
renderer->window = SDL_CreateWindow(PROJECT_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->events.fullscreen));
renderer->window = SDL_CreateWindow(PROJECT_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
renderer->events.window = renderer->window;
renderer->player.window = renderer->window;
renderer->sdlRenderer = SDL_CreateRenderer(renderer->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
@ -80,7 +80,7 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
while (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->events, &event);
GBASDLHandleEvent(context, &renderer->player, &event);
}
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {