GBA: Controller profiles

This commit is contained in:
Jeffrey Pfau 2015-03-15 19:33:38 -07:00
parent b2c2a9acf7
commit 0b38dd1289
9 changed files with 138 additions and 81 deletions

View File

@ -27,6 +27,7 @@ Features:
- Runtime configurable audio driver
- Debugger: Add CLI function for writing a register
- Libretro core for use with RetroArch and other front-ends
- Controller profiles for setting different bindings for different controllers
Bugfixes:
- ARM7: Extend prefetch by one stage
- GBA Audio: Support 16-bit writes to FIFO audio

View File

@ -24,7 +24,7 @@ struct GBAInputMapImpl {
struct GBAAxisSave {
struct Configuration* config;
uint32_t type;
const char* sectionName;
};
struct GBAAxisEnumerate {
@ -45,6 +45,11 @@ const char* GBAKeyNames[] = {
"L"
};
static void _makeSectionName(char* sectionName, size_t len, uint32_t type) {
snprintf(sectionName, len, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[len - 1] = '\0';
}
static bool _getIntValue(const struct Configuration* config, const char* section, const char* key, int* value) {
const char* strValue = ConfigurationGetValue(config, section, key);
if (!strValue) {
@ -122,11 +127,7 @@ static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t t
return impl;
}
static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey key, const char* keyName) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
static void _loadKey(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, enum GBAKey key, const char* keyName) {
char keyKey[KEY_NAME_MAX];
snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
keyKey[KEY_NAME_MAX - 1] = '\0';
@ -138,11 +139,7 @@ static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Config
GBAInputBindKey(map, type, value, key);
}
static void _loadAxis(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey direction, const char* axisName) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
static void _loadAxis(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, enum GBAKey direction, const char* axisName) {
char axisKey[KEY_NAME_MAX];
snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName);
axisKey[KEY_NAME_MAX - 1] = '\0';
@ -179,11 +176,7 @@ static void _loadAxis(struct GBAInputMap* map, uint32_t type, const struct Confi
GBAInputBindAxis(map, type, axis, &realDescription);
}
static void _saveKey(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, enum GBAKey key, const char* keyName) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
static void _saveKey(const struct GBAInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config, enum GBAKey key, const char* keyName) {
char keyKey[KEY_NAME_MAX];
snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
keyKey[KEY_NAME_MAX - 1] = '\0';
@ -195,11 +188,7 @@ static void _saveKey(const struct GBAInputMap* map, uint32_t type, struct Config
ConfigurationSetValue(config, sectionName, keyKey, keyValue);
}
static void _clearAxis(uint32_t type, struct Configuration* config, const char* axisName) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
static void _clearAxis(const char* sectionName, struct Configuration* config, const char* axisName) {
char axisKey[KEY_NAME_MAX];
snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName);
axisKey[KEY_NAME_MAX - 1] = '\0';
@ -214,10 +203,7 @@ static void _saveAxis(uint32_t axis, void* dp, void* up) {
struct GBAAxisSave* user = up;
const struct GBAAxis* description = dp;
uint32_t type = user->type;
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
sectionName[SECTION_NAME_MAX - 1] = '\0';
const char* sectionName = user->sectionName;
if (description->lowDirection != GBA_KEY_NONE) {
const char* keyName = GBAKeyNames[description->lowDirection];
@ -271,6 +257,64 @@ void _unbindAxis(uint32_t axis, void* dp, void* user) {
}
}
static void _loadAll(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) {
_loadKey(map, type, sectionName, config, GBA_KEY_A, "A");
_loadKey(map, type, sectionName, config, GBA_KEY_B, "B");
_loadKey(map, type, sectionName, config, GBA_KEY_L, "L");
_loadKey(map, type, sectionName, config, GBA_KEY_R, "R");
_loadKey(map, type, sectionName, config, GBA_KEY_START, "Start");
_loadKey(map, type, sectionName, config, GBA_KEY_SELECT, "Select");
_loadKey(map, type, sectionName, config, GBA_KEY_UP, "Up");
_loadKey(map, type, sectionName, config, GBA_KEY_DOWN, "Down");
_loadKey(map, type, sectionName, config, GBA_KEY_LEFT, "Left");
_loadKey(map, type, sectionName, config, GBA_KEY_RIGHT, "Right");
_loadAxis(map, type, sectionName, config, GBA_KEY_A, "A");
_loadAxis(map, type, sectionName, config, GBA_KEY_B, "B");
_loadAxis(map, type, sectionName, config, GBA_KEY_L, "L");
_loadAxis(map, type, sectionName, config, GBA_KEY_R, "R");
_loadAxis(map, type, sectionName, config, GBA_KEY_START, "Start");
_loadAxis(map, type, sectionName, config, GBA_KEY_SELECT, "Select");
_loadAxis(map, type, sectionName, config, GBA_KEY_UP, "Up");
_loadAxis(map, type, sectionName, config, GBA_KEY_DOWN, "Down");
_loadAxis(map, type, sectionName, config, GBA_KEY_LEFT, "Left");
_loadAxis(map, type, sectionName, config, GBA_KEY_RIGHT, "Right");
}
static void _saveAll(const struct GBAInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config) {
_saveKey(map, type, sectionName, config, GBA_KEY_A, "A");
_saveKey(map, type, sectionName, config, GBA_KEY_B, "B");
_saveKey(map, type, sectionName, config, GBA_KEY_L, "L");
_saveKey(map, type, sectionName, config, GBA_KEY_R, "R");
_saveKey(map, type, sectionName, config, GBA_KEY_START, "Start");
_saveKey(map, type, sectionName, config, GBA_KEY_SELECT, "Select");
_saveKey(map, type, sectionName, config, GBA_KEY_UP, "Up");
_saveKey(map, type, sectionName, config, GBA_KEY_DOWN, "Down");
_saveKey(map, type, sectionName, config, GBA_KEY_LEFT, "Left");
_saveKey(map, type, sectionName, config, GBA_KEY_RIGHT, "Right");
_clearAxis(sectionName, config, "A");
_clearAxis(sectionName, config, "B");
_clearAxis(sectionName, config, "L");
_clearAxis(sectionName, config, "R");
_clearAxis(sectionName, config, "Start");
_clearAxis(sectionName, config, "Select");
_clearAxis(sectionName, config, "Up");
_clearAxis(sectionName, config, "Down");
_clearAxis(sectionName, config, "Left");
_clearAxis(sectionName, config, "Right");
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return;
}
struct GBAAxisSave save = {
config,
sectionName
};
TableEnumerate(&impl->axes, _saveAxis, &save);
}
void GBAInputMapInit(struct GBAInputMap* map) {
map->maps = 0;
map->numMaps = 0;
@ -414,59 +458,27 @@ void GBAInputEnumerateAxes(const struct GBAInputMap* map, uint32_t type, void (h
}
void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) {
_loadKey(map, type, config, GBA_KEY_A, "A");
_loadKey(map, type, config, GBA_KEY_B, "B");
_loadKey(map, type, config, GBA_KEY_L, "L");
_loadKey(map, type, config, GBA_KEY_R, "R");
_loadKey(map, type, config, GBA_KEY_START, "Start");
_loadKey(map, type, config, GBA_KEY_SELECT, "Select");
_loadKey(map, type, config, GBA_KEY_UP, "Up");
_loadKey(map, type, config, GBA_KEY_DOWN, "Down");
_loadKey(map, type, config, GBA_KEY_LEFT, "Left");
_loadKey(map, type, config, GBA_KEY_RIGHT, "Right");
_loadAxis(map, type, config, GBA_KEY_A, "A");
_loadAxis(map, type, config, GBA_KEY_B, "B");
_loadAxis(map, type, config, GBA_KEY_L, "L");
_loadAxis(map, type, config, GBA_KEY_R, "R");
_loadAxis(map, type, config, GBA_KEY_START, "Start");
_loadAxis(map, type, config, GBA_KEY_SELECT, "Select");
_loadAxis(map, type, config, GBA_KEY_UP, "Up");
_loadAxis(map, type, config, GBA_KEY_DOWN, "Down");
_loadAxis(map, type, config, GBA_KEY_LEFT, "Left");
_loadAxis(map, type, config, GBA_KEY_RIGHT, "Right");
char sectionName[SECTION_NAME_MAX];
_makeSectionName(sectionName, SECTION_NAME_MAX, type);
_loadAll(map, type, sectionName, config);
}
void GBAInputMapSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config) {
_saveKey(map, type, config, GBA_KEY_A, "A");
_saveKey(map, type, config, GBA_KEY_B, "B");
_saveKey(map, type, config, GBA_KEY_L, "L");
_saveKey(map, type, config, GBA_KEY_R, "R");
_saveKey(map, type, config, GBA_KEY_START, "Start");
_saveKey(map, type, config, GBA_KEY_SELECT, "Select");
_saveKey(map, type, config, GBA_KEY_UP, "Up");
_saveKey(map, type, config, GBA_KEY_DOWN, "Down");
_saveKey(map, type, config, GBA_KEY_LEFT, "Left");
_saveKey(map, type, config, GBA_KEY_RIGHT, "Right");
_clearAxis(type, config, "A");
_clearAxis(type, config, "B");
_clearAxis(type, config, "L");
_clearAxis(type, config, "R");
_clearAxis(type, config, "Start");
_clearAxis(type, config, "Select");
_clearAxis(type, config, "Up");
_clearAxis(type, config, "Down");
_clearAxis(type, config, "Left");
_clearAxis(type, config, "Right");
const struct GBAInputMapImpl* impl = _lookupMapConst(map, type);
if (!impl) {
return;
}
struct GBAAxisSave save = {
config,
type
};
TableEnumerate(&impl->axes, _saveAxis, &save);
char sectionName[SECTION_NAME_MAX];
_makeSectionName(sectionName, SECTION_NAME_MAX, type);
_saveAll(map, type, sectionName, config);
}
void GBAInputProfileLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, const char* profile) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile);
sectionName[SECTION_NAME_MAX - 1] = '\0';
_loadAll(map, type, sectionName, config);
}
void GBAInputProfileSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, const char* profile) {
char sectionName[SECTION_NAME_MAX];
snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile);
sectionName[SECTION_NAME_MAX - 1] = '\0';
_saveAll(map, type, sectionName, config);
}

View File

@ -45,4 +45,7 @@ void GBAInputEnumerateAxes(const struct GBAInputMap*, uint32_t type, void (handl
void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*);
void GBAInputMapSave(const struct GBAInputMap*, uint32_t type, struct Configuration*);
void GBAInputProfileLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*, const char* profile);
void GBAInputProfileSave(const struct GBAInputMap*, uint32_t type, struct Configuration*, const char* profile);
#endif

View File

@ -20,9 +20,10 @@ const qreal GBAKeyEditor::DPAD_CENTER_Y = 0.431;
const qreal GBAKeyEditor::DPAD_WIDTH = 0.1;
const qreal GBAKeyEditor::DPAD_HEIGHT = 0.1;
GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, QWidget* parent)
GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const char* profile, QWidget* parent)
: QWidget(parent)
, m_type(type)
, m_profile(profile)
, m_controller(controller)
{
setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);
@ -163,6 +164,10 @@ void GBAKeyEditor::save() {
bindKey(m_keyL, GBA_KEY_L);
bindKey(m_keyR, GBA_KEY_R);
m_controller->saveConfiguration(m_type);
if (m_profile) {
m_controller->saveProfile(m_type, m_profile);
}
}
void GBAKeyEditor::lookupBinding(const GBAInputMap* map, KeyEditor* keyEditor, GBAKey key) {

View File

@ -26,7 +26,7 @@ class GBAKeyEditor : public QWidget {
Q_OBJECT
public:
GBAKeyEditor(InputController* controller, int type, QWidget* parent = nullptr);
GBAKeyEditor(InputController* controller, int type, const char* profile = nullptr, QWidget* parent = nullptr);
public slots:
void setAll();
@ -76,6 +76,7 @@ private:
QList<KeyEditor*>::iterator m_currentKey;
uint32_t m_type;
const char* m_profile;
InputController* m_controller;
QPicture m_background;

View File

@ -63,6 +63,7 @@ void InputController::setConfiguration(ConfigController* config) {
loadConfiguration(KEYBOARD);
#ifdef BUILD_SDL
loadConfiguration(SDL_BINDING_BUTTON);
loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
#endif
}
@ -70,11 +71,34 @@ void InputController::loadConfiguration(uint32_t type) {
GBAInputMapLoad(&m_inputMap, type, m_config->configuration());
}
void InputController::loadProfile(uint32_t type, const char* profile) {
GBAInputProfileLoad(&m_inputMap, type, m_config->configuration(), profile);
}
void InputController::saveConfiguration(uint32_t type) {
GBAInputMapSave(&m_inputMap, type, m_config->configuration());
m_config->write();
}
void InputController::saveProfile(uint32_t type, const char* profile) {
GBAInputProfileSave(&m_inputMap, type, m_config->configuration(), profile);
m_config->write();
}
const char* InputController::profileForType(uint32_t type) {
UNUSED(type);
#ifdef BUILD_SDL
if (type == SDL_BINDING_BUTTON) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
return SDL_JoystickName(m_sdlEvents.joystick);
#else
return SDL_JoystickName(SDL_JoystickIndex(m_sdlEvents.joystick));
#endif
}
#endif
return 0;
}
GBAKey InputController::mapKeyboard(int key) const {
return GBAInputMapKey(&m_inputMap, KEYBOARD, key);
}

View File

@ -36,7 +36,10 @@ public:
void setConfiguration(ConfigController* config);
void loadConfiguration(uint32_t type);
void loadProfile(uint32_t type, const char* profile);
void saveConfiguration(uint32_t type = KEYBOARD);
void saveProfile(uint32_t type, const char* profile);
const char* profileForType(uint32_t type);
GBAKey mapKeyboard(int key) const;

View File

@ -255,7 +255,8 @@ void Window::openCheatsWindow() {
#ifdef BUILD_SDL
void Window::openGamepadWindow() {
GBAKeyEditor* keyEditor = new GBAKeyEditor(&m_inputController, SDL_BINDING_BUTTON);
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
GBAKeyEditor* keyEditor = new GBAKeyEditor(&m_inputController, SDL_BINDING_BUTTON, profile);
connect(this, SIGNAL(shutdown()), keyEditor, SLOT(close()));
keyEditor->setAttribute(Qt::WA_DeleteOnClose);
keyEditor->show();

View File

@ -78,7 +78,14 @@ void GBASDLInitBindings(struct GBAInputMap* inputMap) {
void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) {
GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config);
GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
if (context->joystick) {
GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config);
#if SDL_VERSION_ATLEAST(2, 0, 0)
GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, SDL_JoystickName(context->joystick));
#else
GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, SDL_JoystickName(SDL_JoystickIndex(context->joystick)));
#endif
}
}
void GBASDLDeinitEvents(struct GBASDLEvents* context) {