all repos — mgba @ afae3c8b807577123c93f32f1145422fc55500af

mGBA Game Boy Advance Emulator

Qt: Allow configuring arbitrary attached gamepads (fixes #204)
Jeffrey Pfau jeffrey@endrift.com
Sat, 21 Mar 2015 17:09:15 -0700
commit

afae3c8b807577123c93f32f1145422fc55500af

parent

d4ef56cd16bf35a47dfcd26d52fbd0b1909c163c

M src/gba/input.csrc/gba/input.c

@@ -482,3 +482,21 @@ snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile);

sectionName[SECTION_NAME_MAX - 1] = '\0'; _saveAll(map, type, sectionName, config); } + +const char* GBAInputGetPreferredDevice(const struct Configuration* config, uint32_t type, int playerId) { + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(sectionName, SECTION_NAME_MAX, type); + + char deviceId[KEY_NAME_MAX]; + snprintf(deviceId, sizeof(deviceId), "device%i", playerId); + return ConfigurationGetValue(config, sectionName, deviceId); +} + +void GBAInputSetPreferredDevice(struct Configuration* config, uint32_t type, int playerId, const char* deviceName) { + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(sectionName, SECTION_NAME_MAX, type); + + char deviceId[KEY_NAME_MAX]; + snprintf(deviceId, sizeof(deviceId), "device%i", playerId); + return ConfigurationSetValue(config, sectionName, deviceId, deviceName); +}
M src/gba/input.hsrc/gba/input.h

@@ -48,4 +48,7 @@

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); +const char* GBAInputGetPreferredDevice(const struct Configuration*, uint32_t type, int playerId); +void GBAInputSetPreferredDevice(struct Configuration*, uint32_t type, int playerId, const char* deviceName); + #endif
M src/platform/qt/GBAKeyEditor.cppsrc/platform/qt/GBAKeyEditor.cpp

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GBAKeyEditor.h" +#include <QComboBox> #include <QPaintEvent> #include <QPainter> #include <QPushButton>

@@ -20,8 +21,9 @@ 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, const char* profile, QWidget* parent) +GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString& profile, QWidget* parent) : QWidget(parent) + , m_profileSelect(nullptr) , m_type(type) , m_profile(profile) , m_controller(controller)

@@ -42,19 +44,26 @@ m_keyB = new KeyEditor(this);

m_keyL = new KeyEditor(this); m_keyR = new KeyEditor(this); - lookupBinding(map, m_keyDU, GBA_KEY_UP); - lookupBinding(map, m_keyDD, GBA_KEY_DOWN); - lookupBinding(map, m_keyDL, GBA_KEY_LEFT); - lookupBinding(map, m_keyDR, GBA_KEY_RIGHT); - lookupBinding(map, m_keySelect, GBA_KEY_SELECT); - lookupBinding(map, m_keyStart, GBA_KEY_START); - lookupBinding(map, m_keyA, GBA_KEY_A); - lookupBinding(map, m_keyB, GBA_KEY_B); - lookupBinding(map, m_keyL, GBA_KEY_L); - lookupBinding(map, m_keyR, GBA_KEY_R); + refresh(); #ifdef BUILD_SDL lookupAxes(map); + + if (type == SDL_BINDING_BUTTON) { + m_profileSelect = new QComboBox(this); + m_profileSelect->addItems(controller->connectedGamepads(type)); + int activeGamepad = controller->gamepad(type); + if (activeGamepad > 0) { + m_profileSelect->setCurrentIndex(activeGamepad); + } + + connect(m_profileSelect, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this] (int i) { + m_controller->setGamepad(m_type, i); + m_profile = m_profileSelect->currentText(); + m_controller->loadProfile(m_type, m_profile); + refresh(); + }); + } #endif connect(m_keyDU, SIGNAL(valueChanged(int)), this, SLOT(setNext()));

@@ -129,6 +138,10 @@ setLocation(m_keyA, 0.826, 0.451);

setLocation(m_keyB, 0.667, 0.490); setLocation(m_keyL, 0.1, 0.1); setLocation(m_keyR, 0.9, 0.1); + + if (m_profileSelect) { + setLocation(m_profileSelect, 0.5, 0.7); + } } void GBAKeyEditor::paintEvent(QPaintEvent* event) {

@@ -165,9 +178,29 @@ bindKey(m_keyL, GBA_KEY_L);

bindKey(m_keyR, GBA_KEY_R); m_controller->saveConfiguration(m_type); - if (m_profile) { +#ifdef BUILD_SDL + if (m_profileSelect) { + m_controller->setPreferredGamepad(m_type, m_profileSelect->currentText()); + } +#endif + + if (!m_profile.isNull()) { m_controller->saveProfile(m_type, m_profile); } +} + +void GBAKeyEditor::refresh() { + const GBAInputMap* map = m_controller->map(); + lookupBinding(map, m_keyDU, GBA_KEY_UP); + lookupBinding(map, m_keyDD, GBA_KEY_DOWN); + lookupBinding(map, m_keyDL, GBA_KEY_LEFT); + lookupBinding(map, m_keyDR, GBA_KEY_RIGHT); + lookupBinding(map, m_keySelect, GBA_KEY_SELECT); + lookupBinding(map, m_keyStart, GBA_KEY_START); + lookupBinding(map, m_keyA, GBA_KEY_A); + lookupBinding(map, m_keyB, GBA_KEY_B); + lookupBinding(map, m_keyL, GBA_KEY_L); + lookupBinding(map, m_keyR, GBA_KEY_R); } void GBAKeyEditor::lookupBinding(const GBAInputMap* map, KeyEditor* keyEditor, GBAKey key) {
M src/platform/qt/GBAKeyEditor.hsrc/platform/qt/GBAKeyEditor.h

@@ -15,6 +15,7 @@ extern "C" {

#include "gba/input.h" } +class QComboBox; class QTimer; namespace QGBA {

@@ -26,7 +27,7 @@ class GBAKeyEditor : public QWidget {

Q_OBJECT public: - GBAKeyEditor(InputController* controller, int type, const char* profile = nullptr, QWidget* parent = nullptr); + GBAKeyEditor(InputController* controller, int type, const QString& profile = QString(), QWidget* parent = nullptr); public slots: void setAll();

@@ -38,6 +39,7 @@

private slots: void setNext(); void save(); + void refresh(); #ifdef BUILD_SDL void setAxisValue(int axis, int32_t value); #endif

@@ -61,6 +63,7 @@ #endif

KeyEditor* keyById(GBAKey); + QComboBox* m_profileSelect; QWidget* m_buttons; KeyEditor* m_keyDU; KeyEditor* m_keyDD;

@@ -76,7 +79,7 @@ QList<KeyEditor*> m_keyOrder;

QList<KeyEditor*>::iterator m_currentKey; uint32_t m_type; - const char* m_profile; + QString m_profile; InputController* m_controller; QPicture m_background;
M src/platform/qt/InputController.cppsrc/platform/qt/InputController.cpp

@@ -85,8 +85,8 @@ void InputController::loadConfiguration(uint32_t type) {

GBAInputMapLoad(&m_inputMap, type, m_config->input()); } -void InputController::loadProfile(uint32_t type, const char* profile) { - GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile); +void InputController::loadProfile(uint32_t type, const QString& profile) { + GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toLocal8Bit().constData()); } void InputController::saveConfiguration(uint32_t type) {

@@ -94,8 +94,8 @@ 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->input(), profile); +void InputController::saveProfile(uint32_t type, const QString& profile) { + GBAInputProfileSave(&m_inputMap, type, m_config->input(), profile.toLocal8Bit().constData()); m_config->write(); }

@@ -112,6 +112,38 @@ }

#endif return 0; } + +#ifdef BUILD_SDL +QStringList InputController::connectedGamepads(uint32_t type) const { + UNUSED(type); + if (type != SDL_BINDING_BUTTON) { + return QStringList(); + } + + QStringList pads; + for (size_t i = 0; i < s_sdlEvents.nJoysticks; ++i) { + const char* name; +#if SDL_VERSION_ATLEAST(2, 0, 0) + name = SDL_JoystickName(s_sdlEvents.joysticks[i]); +#else + name = SDL_JoystickName(SDL_JoystickIndex(s_sdlEvents.joysticks[i])); +#endif + if (name) { + pads.append(QString(name)); + } else { + pads.append(QString()); + } + } + return pads; +} + +void InputController::setPreferredGamepad(uint32_t type, const QString& device) { + if (!m_config) { + return; + } + GBAInputSetPreferredDevice(m_config->input(), type, m_sdlPlayer.playerId, device.toLocal8Bit().constData()); +} +#endif GBAKey InputController::mapKeyboard(int key) const { return GBAInputMapKey(&m_inputMap, KEYBOARD, key);
M src/platform/qt/InputController.hsrc/platform/qt/InputController.h

@@ -36,9 +36,9 @@ ~InputController();

void setConfiguration(ConfigController* config); void loadConfiguration(uint32_t type); - void loadProfile(uint32_t type, const char* profile); + void loadProfile(uint32_t type, const QString& profile); void saveConfiguration(uint32_t type = KEYBOARD); - void saveProfile(uint32_t type, const char* profile); + void saveProfile(uint32_t type, const QString& profile); const char* profileForType(uint32_t type); GBAKey mapKeyboard(int key) const;

@@ -55,6 +55,11 @@ QSet<int> activeGamepadButtons();

QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(); void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, GBAKey); + + QStringList connectedGamepads(uint32_t type) const; + int gamepad(uint32_t type) const { return m_sdlPlayer.joystickIndex; } + void setGamepad(uint32_t type, int index) { GBASDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); } + void setPreferredGamepad(uint32_t type, const QString& device); #endif public slots:
M src/platform/sdl/sdl-events.csrc/platform/sdl/sdl-events.c

@@ -63,12 +63,10 @@ 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"); + context->preferredJoysticks[0] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 0); + context->preferredJoysticks[1] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 1); + context->preferredJoysticks[2] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 2); + context->preferredJoysticks[3] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 3); } void GBASDLInitBindings(struct GBAInputMap* inputMap) {

@@ -132,7 +130,7 @@ if (events->playersAttached >= MAX_PLAYERS) {

return false; } - int playerId = events->playersAttached; + player->playerId = events->playersAttached; size_t firstUnclaimed = SIZE_MAX; size_t i;

@@ -160,7 +158,7 @@ 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) { + if (events->preferredJoysticks[player->playerId] && strcmp(events->preferredJoysticks[player->playerId], joystickName) == 0) { player->joystickIndex = i; break; }

@@ -172,7 +170,7 @@ }

if (player->joystickIndex != SIZE_MAX) { player->joystick = events->joysticks[player->joystickIndex]; - events->joysticksClaimed[playerId] = player->joystickIndex; + events->joysticksClaimed[player->playerId] = player->joystickIndex; } ++events->playersAttached;

@@ -189,6 +187,15 @@ #else

GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, SDL_JoystickName(SDL_JoystickIndex(context->joystick))); #endif } +} + +void GBASDLPlayerChangeJoystick(struct GBASDLEvents* events, struct GBASDLPlayer* player, size_t index) { + if (player->playerId > MAX_PLAYERS || index >= events->nJoysticks) { + return; + } + events->joysticksClaimed[player->playerId] = index; + player->joystickIndex = index; + player->joystick = events->joysticks[index]; } static void _pauseAfterFrame(struct GBAThread* context) {
M src/platform/sdl/sdl-events.hsrc/platform/sdl/sdl-events.h

@@ -29,6 +29,7 @@ size_t joysticksClaimed[MAX_PLAYERS];

}; struct GBASDLPlayer { + size_t playerId; struct GBAInputMap* bindings; SDL_Joystick* joystick; size_t joystickIndex;