GBA: Controller profiles
@@ -27,6 +27,7 @@ - Debugger: Add CLI functions for examining memory regions
- 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
@@ -24,7 +24,7 @@ };
struct GBAAxisSave { struct Configuration* config; - uint32_t type; + const char* sectionName; }; struct GBAAxisEnumerate {@@ -44,6 +44,11 @@ "Down",
"R", "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);@@ -122,11 +127,7 @@ }
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 @@ }
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 @@ }
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 @@
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 @@ description->lowDirection = GBA_KEY_NONE;
} } +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 @@ TableEnumerate(&impl->axes, _enumerateAxis, &enumUser);
} 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"); + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(sectionName, SECTION_NAME_MAX, type); + _saveAll(map, type, sectionName, config); +} - _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"); +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); +} - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return; - } - struct GBAAxisSave save = { - config, - type - }; - TableEnumerate(&impl->axes, _saveAxis, &save); +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); }
@@ -45,4 +45,7 @@
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
@@ -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 @@ bindKey(m_keyB, GBA_KEY_B);
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) {
@@ -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 @@ QList<KeyEditor*> m_keyOrder;
QList<KeyEditor*>::iterator m_currentKey; uint32_t m_type; + const char* m_profile; InputController* m_controller; QPicture m_background;
@@ -63,6 +63,7 @@ m_config = config;
loadConfiguration(KEYBOARD); #ifdef BUILD_SDL loadConfiguration(SDL_BINDING_BUTTON); + loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON)); #endif }@@ -70,9 +71,32 @@ 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 {
@@ -36,7 +36,10 @@ ~InputController();
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;
@@ -255,7 +255,8 @@ }
#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();
@@ -78,7 +78,14 @@ }
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) {