Qt: Default controller profiles, with a few included already
jump to
@@ -26,6 +26,7 @@ - Thumb-drive mode by putting a file called portable.ini in the same folder
- Configurable display driver, between software and OpenGL - Undo-able savestate loading and saving - Controller profiles now store shortcut settings + - Default controller profiles for several common controllers Bugfixes: - ARM7: Fix SWI and IRQ timings - GBA Audio: Force audio FIFOs to 32-bit
@@ -257,7 +257,10 @@ description->lowDirection = GBA_KEY_NONE;
} } -static void _loadAll(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) { +static bool _loadAll(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) { + if (!ConfigurationHasSection(config, sectionName)) { + return false; + } _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");@@ -279,6 +282,7 @@ _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"); + return true; } static void _saveAll(const struct GBAInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config) {@@ -469,11 +473,11 @@ _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) { +bool 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); + return _loadAll(map, type, sectionName, config); } void GBAInputProfileSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, const char* profile) {
@@ -45,7 +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); +bool 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);
@@ -61,6 +61,7 @@ GameController.cpp
GamepadAxisEvent.cpp GamepadButtonEvent.cpp InputController.cpp + InputProfile.cpp KeyEditor.cpp LoadSaveState.cpp LogController.cpp
@@ -8,6 +8,7 @@
#include "ConfigController.h" #include "GamepadAxisEvent.h" #include "GamepadButtonEvent.h" +#include "InputProfile.h" #include <QApplication> #include <QTimer>@@ -106,8 +107,14 @@ #endif
} void InputController::loadProfile(uint32_t type, const QString& profile) { - GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + bool loaded = GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); recalibrateAxes(); + if (!loaded) { + const InputProfile* ip = InputProfile::findProfile(profile); + if (ip) { + ip->apply(this); + } + } emit profileLoaded(profile); }
@@ -0,0 +1,170 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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 "InputProfile.h" + +#include "InputController.h" + +#include <QRegExp> + +using namespace QGBA; + +const InputProfile InputProfile::s_defaultMaps[] = { + { + "PLAYSTATION\\(R\\)3 Controller", // DualShock 3 (OS X) + (int[GBA_KEY_MAX]) { + /*keyA */ 13, + /*keyB */ 14, + /*keySelect */ 0, + /*keyStart */ 3, + /*keyRight */ -1, + /*keyLeft */ -1, + /*keyUp */ -1, + /*keyDown */ -1, + /*keyR */ 11, + /*keyL */ 10 + }, + (ShortcutButton[]) { + {"loadState", 15}, + {"saveState", 12}, + {"holdFastForward", 9}, + {"holdRewind", 8}, + {} + } + }, + { + "Wiimote \\(..-..-..-..-..-..\\)", // WJoy (OS X) + (int[GBA_KEY_MAX]) { + /*keyA */ 15, + /*keyB */ 16, + /*keySelect */ 7, + /*keyStart */ 6, + /*keyRight */ -1, + /*keyLeft */ -1, + /*keyUp */ -1, + /*keyDown */ -1, + /*keyR */ 20, + /*keyL */ 19 + }, + (ShortcutButton[]) { + {"loadState", 18}, + {"saveState", 17}, + {"holdFastForward", 22}, + {"holdRewind", 21}, + {} + } + }, + { + "Controller", // The Xbox 360 controller drivers on OS X are vague... + (int[GBA_KEY_MAX]) { + /*keyA */ 1, + /*keyB */ 0, + /*keySelect */ 9, + /*keyStart */ 8, + /*keyRight */ -1, + /*keyLeft */ -1, + /*keyUp */ -1, + /*keyDown */ -1, + /*keyR */ 5, + /*keyL */ 4 + }, + (ShortcutButton[]) { + {"loadState", 2}, + {"saveState", 3}, + {} + }, + (ShortcutAxis[]) { + {"holdFastForward", GamepadAxisEvent::Direction::POSITIVE, 5}, + {"holdRewind", GamepadAxisEvent::Direction::POSITIVE, 2}, + {} + } + }, +}; + +constexpr InputProfile::InputProfile(const char* name, + int keys[GBA_KEY_MAX], + const ShortcutButton* shortcutButtons, + const ShortcutAxis* shortcutAxes, + AxisValue axes[GBA_KEY_MAX], + const struct Coord& tiltAxis, + const struct Coord& gyroAxis, + float gyroSensitivity) + : m_profileName(name) + , m_keys { + keys[GBA_KEY_A], + keys[GBA_KEY_B], + keys[GBA_KEY_SELECT], + keys[GBA_KEY_START], + keys[GBA_KEY_RIGHT], + keys[GBA_KEY_LEFT], + keys[GBA_KEY_UP], + keys[GBA_KEY_DOWN], + keys[GBA_KEY_R], + keys[GBA_KEY_L] + } + , m_shortcutButtons(shortcutButtons) + , m_shortcutAxes(shortcutAxes) + , m_axes { + axes[GBA_KEY_A], + axes[GBA_KEY_B], + axes[GBA_KEY_SELECT], + axes[GBA_KEY_START], + axes[GBA_KEY_RIGHT], + axes[GBA_KEY_LEFT], + axes[GBA_KEY_UP], + axes[GBA_KEY_DOWN], + axes[GBA_KEY_R], + axes[GBA_KEY_L] + } + , m_tiltAxis(tiltAxis) + , m_gyroAxis(gyroAxis) + , m_gyroSensitivity(gyroSensitivity) +{ +} + +const InputProfile* InputProfile::findProfile(const QString& name) { + for (size_t i = 0; i < sizeof(s_defaultMaps) / sizeof(*s_defaultMaps); ++i) { + QRegExp re(s_defaultMaps[i].m_profileName); + if (re.exactMatch(name)) { + return &s_defaultMaps[i]; + } + } + return nullptr; +} + +void InputProfile::apply(InputController* controller) const { + for (size_t i = 0; i < GBA_KEY_MAX; ++i) { + controller->bindKey(SDL_BINDING_BUTTON, m_keys[i], static_cast<GBAKey>(i)); + controller->bindAxis(SDL_BINDING_BUTTON, m_axes[i].axis, m_axes[i].direction, static_cast<GBAKey>(i)); + } + controller->registerTiltAxisX(m_tiltAxis.x); + controller->registerTiltAxisY(m_tiltAxis.y); + controller->registerGyroAxisX(m_gyroAxis.x); + controller->registerGyroAxisY(m_gyroAxis.y); + controller->setGyroSensitivity(m_gyroSensitivity); +} + +bool InputProfile::lookupShortcutButton(const QString& shortcutName, int* button) const { + for (size_t i = 0; m_shortcutButtons[i].shortcut; ++i) { + const ShortcutButton& shortcut = m_shortcutButtons[i]; + if (QLatin1String(shortcut.shortcut) == shortcutName) { + *button = shortcut.button; + return true; + } + } + return false; +} + +bool InputProfile::lookupShortcutAxis(const QString& shortcutName, int* axis, GamepadAxisEvent::Direction* direction) const { + for (size_t i = 0; m_shortcutAxes[i].shortcut; ++i) { + const ShortcutAxis& shortcut = m_shortcutAxes[i]; + if (QLatin1String(shortcut.shortcut) == shortcutName) { + *axis = shortcut.axis; + *direction = shortcut.direction; + return true; + } + } + return false; +}
@@ -0,0 +1,78 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ +#ifndef QGBA_INPUT_PROFILE +#define QGBA_INPUT_PROFILE + +#include "GamepadAxisEvent.h" + +extern "C" { +#include "gba/interface.h" +} + +namespace QGBA { + +class InputController; + +class InputProfile { +public: + static const InputProfile* findProfile(const QString& name); + + void apply(InputController*) const; + bool lookupShortcutButton(const QString& shortcut, int* button) const; + bool lookupShortcutAxis(const QString& shortcut, int* axis, GamepadAxisEvent::Direction* direction) const; + +private: + struct Coord { + int x; + int y; + }; + + struct AxisValue { + GamepadAxisEvent::Direction direction; + int axis; + }; + + struct ShortcutButton { + const char* shortcut; + int button; + }; + + struct ShortcutAxis { + const char* shortcut; + GamepadAxisEvent::Direction direction; + int axis; + }; + + constexpr InputProfile(const char* name, + int keys[GBA_KEY_MAX], + const ShortcutButton* shortcutButtons = (ShortcutButton[]) {{}}, + const ShortcutAxis* shortcutAxes = (ShortcutAxis[]) {{}}, + AxisValue axes[GBA_KEY_MAX] = (AxisValue[GBA_KEY_MAX]) { + {}, {}, {}, {}, + { GamepadAxisEvent::Direction::POSITIVE, 0 }, + { GamepadAxisEvent::Direction::NEGATIVE, 0 }, + { GamepadAxisEvent::Direction::NEGATIVE, 1 }, + { GamepadAxisEvent::Direction::POSITIVE, 1 }, + {}, {}}, + const struct Coord& tiltAxis = { 2, 3 }, + const struct Coord& gyroAxis = { 0, 1 }, + float gyroSensitivity = 2e+09f); + + static const InputProfile s_defaultMaps[]; + + const char* m_profileName; + const int m_keys[GBA_KEY_MAX]; + const AxisValue m_axes[GBA_KEY_MAX]; + const ShortcutButton* m_shortcutButtons; + const ShortcutAxis* m_shortcutAxes; + Coord m_tiltAxis; + Coord m_gyroAxis; + float m_gyroSensitivity; +}; + +} + +#endif
@@ -7,6 +7,7 @@ #include "ShortcutController.h"
#include "ConfigController.h" #include "GamepadButtonEvent.h" +#include "InputProfile.h" #include <QAction> #include <QKeyEvent>@@ -18,6 +19,7 @@ ShortcutController::ShortcutController(QObject* parent)
: QAbstractItemModel(parent) , m_rootMenu(nullptr) , m_config(nullptr) + , m_profile(nullptr) { }@@ -239,8 +241,8 @@ m_buttons[button] = item;
} if (m_config) { m_config->setQtOption(item->name(), button, BUTTON_SECTION); - if (!m_profile.isNull()) { - m_config->setQtOption(item->name(), button, BUTTON_PROFILE_SECTION + m_profile); + if (!m_profileName.isNull()) { + m_config->setQtOption(item->name(), button, BUTTON_PROFILE_SECTION + m_profileName); } } emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),@@ -275,8 +277,8 @@ if (direction == GamepadAxisEvent::NEGATIVE) {
d = '-'; } m_config->setQtOption(item->name(), QString("%1%2").arg(d).arg(axis), AXIS_SECTION); - if (!m_profile.isNull()) { - m_config->setQtOption(item->name(), QString("%1%2").arg(d).arg(axis), AXIS_PROFILE_SECTION + m_profile); + if (!m_profileName.isNull()) { + m_config->setQtOption(item->name(), QString("%1%2").arg(d).arg(axis), AXIS_PROFILE_SECTION + m_profileName); } } emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),@@ -393,23 +395,36 @@ void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
if (item->name().isNull()) { return; } - QVariant button = m_config->getQtOption(item->name(), !m_profile.isNull() ? BUTTON_PROFILE_SECTION + m_profile : BUTTON_SECTION); + QVariant button = m_config->getQtOption(item->name(), !m_profileName.isNull() ? BUTTON_PROFILE_SECTION + m_profileName : BUTTON_SECTION); int oldButton = item->button(); if (oldButton >= 0) { m_buttons.take(oldButton); item->setButton(-1); } + if (button.isNull() && m_profile) { + int buttonInt; + if (m_profile->lookupShortcutButton(item->name(), &buttonInt)) { + button = buttonInt; + } + } if (!button.isNull()) { item->setButton(button.toInt()); m_buttons[button.toInt()] = item; } - QVariant axis = m_config->getQtOption(item->name(), !m_profile.isNull() ? AXIS_PROFILE_SECTION + m_profile : AXIS_SECTION); + QVariant axis = m_config->getQtOption(item->name(), !m_profileName.isNull() ? AXIS_PROFILE_SECTION + m_profileName : AXIS_SECTION); int oldAxis = item->axis(); GamepadAxisEvent::Direction oldDirection = item->direction(); if (oldAxis >= 0) { m_axes.take(qMakePair(oldAxis, oldDirection)); item->setAxis(-1, GamepadAxisEvent::NEUTRAL); + } + if (axis.isNull() && m_profile) { + int axisInt; + GamepadAxisEvent::Direction direction; + if (m_profile->lookupShortcutAxis(item->name(), &axisInt, &direction)) { + axis = QLatin1String(direction == GamepadAxisEvent::Direction::NEGATIVE ? "-" : "+") + QString::number(axisInt); + } } if (!axis.isNull()) { QString axisDesc = axis.toString();@@ -452,7 +467,8 @@ return QKeySequence(modifier + key);
} void ShortcutController::loadProfile(const QString& profile) { - m_profile = profile; + m_profileName = profile; + m_profile = InputProfile::findProfile(profile); onSubitems(&m_rootMenu, [this](ShortcutItem* item) { loadGamepadShortcuts(item); });
@@ -21,6 +21,7 @@
namespace QGBA { class ConfigController; +class InputProfile; class ShortcutController : public QAbstractItemModel { Q_OBJECT@@ -133,7 +134,8 @@ QMap<int, ShortcutItem*> m_buttons;
QMap<QPair<int, GamepadAxisEvent::Direction>, ShortcutItem*> m_axes; QMap<QKeySequence, ShortcutItem*> m_heldKeys; ConfigController* m_config; - QString m_profile; + QString m_profileName; + const InputProfile* m_profile; }; }
@@ -100,6 +100,10 @@ }
HashTableRemove(currentSection, key); } +bool ConfigurationHasSection(const struct Configuration* configuration, const char* section) { + return HashTableLookup(&configuration->sections, section); +} + const char* ConfigurationGetValue(const struct Configuration* configuration, const char* section, const char* key) { const struct Table* currentSection = &configuration->root; if (section) {
@@ -23,6 +23,7 @@ void ConfigurationSetIntValue(struct Configuration*, const char* section, const char* key, int value);
void ConfigurationSetUIntValue(struct Configuration*, const char* section, const char* key, unsigned value); void ConfigurationSetFloatValue(struct Configuration*, const char* section, const char* key, float value); +bool ConfigurationHasSection(const struct Configuration*, const char* section); const char* ConfigurationGetValue(const struct Configuration*, const char* section, const char* key); void ConfigurationClearValue(struct Configuration*, const char* section, const char* key);