mirror of https://github.com/mgba-emu/mgba.git
GBA: Controller profiles
This commit is contained in:
parent
b2c2a9acf7
commit
0b38dd1289
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
166
src/gba/input.c
166
src/gba/input.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue