Qt: Separate out shortcuts from controls, restore saving
jump to
@@ -145,11 +145,16 @@ updateConfig();
} }); + m_keyView = new ShortcutView(); + m_keyView->setModel(inputController->keyIndex()); + m_keyView->setInputController(inputController); m_shortcutView = new ShortcutView(); m_shortcutView->setModel(inputController->inputIndex()); m_shortcutView->setInputController(inputController); + m_ui.stackedWidget->addWidget(m_keyView); + m_ui.tabs->addItem(tr("Controls")); m_ui.stackedWidget->addWidget(m_shortcutView); - m_ui.tabs->addItem(tr("Bindings")); + m_ui.tabs->addItem(tr("Shortcuts")); } void SettingsView::selectBios(QLineEdit* bios) {@@ -237,6 +242,7 @@
m_controller->write(); m_input->rebuildIndex(m_shortcutView->root()); + m_input->rebuildKeyIndex(m_keyView->root()); m_input->saveConfiguration(); emit pathsChanged();
@@ -43,6 +43,7 @@
ConfigController* m_controller; InputController* m_input; ShortcutView* m_shortcutView; + ShortcutView* m_keyView; void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QComboBox*);
@@ -175,6 +175,9 @@ connect(this, &Window::shutdown, m_shaderView, &QWidget::hide);
connect(this, &Window::audioBufferSamplesChanged, m_controller, &GameController::setAudioBufferSamples); connect(this, &Window::sampleRateChanged, m_controller, &GameController::setAudioSampleRate); connect(this, &Window::fpsTargetChanged, m_controller, &GameController::setFPSTarget); + connect(&m_inputController, &InputController::keyPressed, m_controller, &GameController::keyPressed); + connect(&m_inputController, &InputController::keyReleased, m_controller, &GameController::keyReleased); + connect(&m_inputController, &InputController::keyAutofire, m_controller, &GameController::setAutofire); connect(&m_fpsTimer, &QTimer::timeout, this, &Window::showFPS); connect(&m_focusCheck, &QTimer::timeout, this, &Window::focusCheck); connect(m_display, &Display::hideCursor, [this]() {@@ -191,6 +194,13 @@ m_fpsTimer.setInterval(FPS_TIMER_INTERVAL);
m_focusCheck.setInterval(200); setupMenu(menuBar()); + +#ifdef M_CORE_GBA + m_inputController.addPlatform(PLATFORM_GBA, &GBAInputInfo); +#endif +#ifdef M_CORE_GB + m_inputController.addPlatform(PLATFORM_GB, &GBInputInfo); +#endif } Window::~Window() {@@ -720,6 +730,8 @@ m_focusCheck.start();
m_controller->threadInterrupt(); if (m_controller->isLoaded()) { + m_inputController.setPlatform(m_controller->platform()); + mCore* core = m_controller->thread()->core; const mCoreChannelInfo* videoLayers; const mCoreChannelInfo* audioChannels;@@ -1465,130 +1477,6 @@ QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu);
connect(exitFullScreen, &QAction::triggered, this, &Window::exitFullScreen); exitFullScreen->setShortcut(QKeySequence("Esc")); addHiddenAction(frameMenu, exitFullScreen, "exitFullScreen"); - - QMenu* autofireMenu = new QMenu(tr("Autofire"), this); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_A, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_A, false); - }), tr("Autofire A"), "autofireA", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_B, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_B, false); - }), tr("Autofire B"), "autofireB", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_L, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_L, false); - }), tr("Autofire L"), "autofireL", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_R, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_R, false); - }), tr("Autofire R"), "autofireR", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_START, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_START, false); - }), tr("Autofire Start"), "autofireStart", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_SELECT, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_SELECT, false); - }), tr("Autofire Select"), "autofireSelect", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_UP, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_UP, false); - }), tr("Autofire Up"), "autofireUp", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_RIGHT, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_RIGHT, false); - }), tr("Autofire Right"), "autofireRight", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_DOWN, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_DOWN, false); - }), tr("Autofire Down"), "autofireDown", autofireMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->setAutofire(GBA_KEY_LEFT, true); - }, [this]() { - m_controller->setAutofire(GBA_KEY_LEFT, false); - }), tr("Autofire Left"), "autofireLeft", autofireMenu); - - QMenu* bindingsMenu = new QMenu(tr("Bindings"), this); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_A); - }, [this]() { - m_controller->keyReleased(GBA_KEY_A); - }), tr("A"), "keyA", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_B); - }, [this]() { - m_controller->keyReleased(GBA_KEY_B); - }), tr("B"), "keyB", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_START); - }, [this]() { - m_controller->keyReleased(GBA_KEY_START); - }), tr("Start"), "keyStart", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_SELECT); - }, [this]() { - m_controller->keyReleased(GBA_KEY_SELECT); - }), tr("Select"), "keySelect", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_L); - }, [this]() { - m_controller->keyReleased(GBA_KEY_L); - }), tr("L"), "keyL", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_R); - }, [this]() { - m_controller->keyReleased(GBA_KEY_R); - }), tr("R"), "keyR", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_UP); - }, [this]() { - m_controller->keyReleased(GBA_KEY_UP); - }), tr("Up"), "keyUp", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_DOWN); - }, [this]() { - m_controller->keyReleased(GBA_KEY_DOWN); - }), tr("Down"), "keyDown", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_LEFT); - }, [this]() { - m_controller->keyReleased(GBA_KEY_LEFT); - }), tr("Left"), "keyLeft", bindingsMenu); - - m_inputController.inputIndex()->addItem(qMakePair([this]() { - m_controller->keyPressed(GBA_KEY_RIGHT); - }, [this]() { - m_controller->keyReleased(GBA_KEY_RIGHT); - }), tr("Right"), "keyRight", bindingsMenu); for (QAction* action : m_gameActions) { action->setDisabled(true);
@@ -22,6 +22,8 @@
#include <mgba/core/interface.h> #include <mgba-util/configuration.h> +#include <initializer_list> + using namespace QGBA; #ifdef BUILD_SDL@@ -34,6 +36,8 @@ : QObject(parent)
, m_playerId(playerId) , m_topLevel(topLevel) , m_focusParent(topLevel) + , m_bindings(new QMenu(tr("Controls"))) + , m_autofire(new QMenu(tr("Autofire"))) { #ifdef BUILD_SDL if (s_sdlInited == 0) {@@ -54,26 +58,75 @@ #endif
m_gamepadTimer.setInterval(50); m_gamepadTimer.start(); - mInputMapInit(&m_inputMap, &GBAInputInfo); + static QList<QPair<QString, int>> defaultBindings({ + qMakePair(QLatin1String("A"), Qt::Key_Z), + qMakePair(QLatin1String("B"), Qt::Key_X), + qMakePair(QLatin1String("L"), Qt::Key_A), + qMakePair(QLatin1String("R"), Qt::Key_S), + qMakePair(QLatin1String("Start"), Qt::Key_Return), + qMakePair(QLatin1String("Select"), Qt::Key_Backspace), + qMakePair(QLatin1String("Up"), Qt::Key_Up), + qMakePair(QLatin1String("Down"), Qt::Key_Down), + qMakePair(QLatin1String("Left"), Qt::Key_Left), + qMakePair(QLatin1String("Right"), Qt::Key_Right) + }); + for (auto k : defaultBindings) { + addKey(k.first); + } + m_keyIndex.rebuild(); + for (auto k : defaultBindings) { + bindKey(KEYBOARD, k.second, k.first); + } +} + +void InputController::addKey(const QString& name) { + if (itemForKey(name)) { + return; + } + m_keyIndex.addItem(qMakePair([this, name]() { + emit keyPressed(keyId(name)); + }, [this, name]() { + emit keyReleased(keyId(name)); + }), name, QString("key%0").arg(name), m_bindings.get()); + + m_keyIndex.addItem(qMakePair([this, name]() { + emit keyAutofire(keyId(name), true); + }, [this, name]() { + emit keyAutofire(keyId(name), false); + }), name, QString("autofire%1").arg(name), m_autofire.get()); +} + +void InputController::addPlatform(mPlatform platform, const mInputPlatformInfo* info) { + m_keyInfo[platform] = info; + for (size_t i = 0; i < info->nKeys; ++i) { + addKey(info->keyId[i]); + } +} + +void InputController::setPlatform(mPlatform platform) { + if (m_activeKeyInfo) { + mInputMapDeinit(&m_inputMap); + } + + m_sdlPlayer.bindings = &m_inputMap; + m_activeKeyInfo = m_keyInfo[platform]; + mInputMapInit(&m_inputMap, m_activeKeyInfo); + + loadConfiguration(KEYBOARD); #ifdef BUILD_SDL mSDLInitBindingsGBA(&m_inputMap); + loadConfiguration(SDL_BINDING_BUTTON); #endif - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_A, GBA_KEY_L); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_S, GBA_KEY_R); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Return, GBA_KEY_START); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Backspace, GBA_KEY_SELECT); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Up, GBA_KEY_UP); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Down, GBA_KEY_DOWN); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Left, GBA_KEY_LEFT); - mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Right, GBA_KEY_RIGHT); + rebuildKeyIndex(); + restoreModel(); } InputController::~InputController() { - mInputMapDeinit(&m_inputMap); + if (m_activeKeyInfo) { + mInputMapDeinit(&m_inputMap); + } #ifdef BUILD_SDL if (m_playerAttached) {@@ -89,24 +142,25 @@ }
void InputController::rebuildIndex(const InputIndex* index) { m_inputIndex.rebuild(index); +} - rebindKey(GBA_KEY_A); - rebindKey(GBA_KEY_B); - rebindKey(GBA_KEY_L); - rebindKey(GBA_KEY_R); - rebindKey(GBA_KEY_START); - rebindKey(GBA_KEY_SELECT); - rebindKey(GBA_KEY_UP); - rebindKey(GBA_KEY_DOWN); - rebindKey(GBA_KEY_LEFT); - rebindKey(GBA_KEY_RIGHT); +void InputController::rebuildKeyIndex(const InputIndex* index) { + m_keyIndex.rebuild(index); + + for (const InputItem* item : m_keyIndex.items()) { + if (!item->name().startsWith(QLatin1String("key"))) { + rebindKey(item->visibleName()); + } + } } void InputController::setConfiguration(ConfigController* config) { m_config = config; m_inputIndex.setConfigController(config); + m_keyIndex.setConfigController(config); setAllowOpposing(config->getOption("allowOpposingDirections").toInt()); loadConfiguration(KEYBOARD); + loadProfile(KEYBOARD, profileForType(KEYBOARD)); #ifdef BUILD_SDL mSDLEventsLoadConfig(&s_sdlEvents, config->input()); if (!m_playerAttached) {@@ -119,27 +173,30 @@ restoreModel();
} void InputController::loadConfiguration(uint32_t type) { + if (!m_activeKeyInfo) { + return; + } mInputMapLoad(&m_inputMap, type, m_config->input()); #ifdef BUILD_SDL if (m_playerAttached) { - mInputMap* bindings = m_sdlPlayer.bindings; - m_sdlPlayer.bindings = &m_inputMap; mSDLPlayerLoadConfig(&m_sdlPlayer, m_config->input()); - m_sdlPlayer.bindings = bindings; } #endif } void InputController::loadProfile(uint32_t type, const QString& profile) { - bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); - if (!loaded) { - const InputProfile* ip = InputProfile::findProfile(profile); - if (ip) { - ip->apply(this); + if (m_activeKeyInfo) { + bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + if (!loaded) { + const InputProfile* ip = InputProfile::findProfile(profile); + if (ip) { + ip->apply(this); + } } } recalibrateAxes(); m_inputIndex.loadProfile(profile); + m_keyIndex.loadProfile(profile); emit profileLoaded(profile); }@@ -151,17 +208,23 @@ saveProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
if (m_playerAttached) { mSDLPlayerSaveConfig(&m_sdlPlayer, m_config->input()); } - m_config->write(); #endif + m_inputIndex.saveConfig(); + m_keyIndex.saveConfig(); + m_config->write(); } void InputController::saveConfiguration(uint32_t type) { - mInputMapSave(&m_inputMap, type, m_config->input()); + if (m_activeKeyInfo) { + mInputMapSave(&m_inputMap, type, m_config->input()); + } m_config->write(); } void InputController::saveProfile(uint32_t type, const QString& profile) { - mInputProfileSave(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + if (m_activeKeyInfo) { + mInputProfileSave(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + } m_config->write(); }@@ -413,20 +476,27 @@ #endif
return activeAxes; } -void InputController::bindKey(uint32_t type, int key, int coreKey) { - InputItem* item = itemForKey(coreKey); +void InputController::bindKey(uint32_t type, int key, const QString& keyName) { + InputItem* item = itemForKey(keyName); if (type != KEYBOARD) { item->setButton(key); } else { item->setShortcut(key); } - mInputBindKey(&m_inputMap, type, key, coreKey); + if (m_activeKeyInfo) { + int coreKey = keyId(keyName); + mInputBindKey(&m_inputMap, type, key, coreKey); + } } -void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, int key) { +void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, const QString& key) { InputItem* item = itemForKey(key); item->setAxis(axis, direction); + if (!m_activeKeyInfo) { + return; + } + const mInputAxis* old = mInputQueryAxis(&m_inputMap, type, axis); mInputAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD }; if (old) {@@ -438,12 +508,12 @@ deadzone = m_deadzones[axis];
} switch (direction) { case GamepadAxisEvent::NEGATIVE: - description.lowDirection = key; + description.lowDirection = keyId(key); description.deadLow = deadzone - AXIS_THRESHOLD; break; case GamepadAxisEvent::POSITIVE: - description.highDirection = key; + description.highDirection = keyId(key); description.deadHigh = deadzone + AXIS_THRESHOLD; break; default:@@ -484,23 +554,25 @@ #endif
return activeHats; } -void InputController::bindHat(uint32_t type, int hat, GamepadHatEvent::Direction direction, int coreKey) { - //m_inputModel->updateHat(index, hat, direction); +void InputController::bindHat(uint32_t type, int hat, GamepadHatEvent::Direction direction, const QString& key) { + if (!m_activeKeyInfo) { + return; + } mInputHatBindings bindings{ -1, -1, -1, -1 }; mInputQueryHat(&m_inputMap, type, hat, &bindings); switch (direction) { case GamepadHatEvent::UP: - bindings.up = coreKey; + bindings.up = keyId(key); break; case GamepadHatEvent::RIGHT: - bindings.right = coreKey; + bindings.right = keyId(key); break; case GamepadHatEvent::DOWN: - bindings.down = coreKey; + bindings.down = keyId(key); break; case GamepadHatEvent::LEFT: - bindings.left = coreKey; + bindings.left = keyId(key); break; default: return;@@ -644,6 +716,7 @@ }
} bool InputController::eventFilter(QObject*, QEvent* event) { + event->ignore(); if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); int key = keyEvent->key();@@ -658,11 +731,16 @@ event->accept();
return true; } + event->ignore(); InputItem* item = m_inputIndex.itemForShortcut(key); if (item) { item->trigger(event->type() == QEvent::KeyPress); event->accept(); - return true; + } + item = m_keyIndex.itemForShortcut(key); + if (item) { + item->trigger(event->type() == QEvent::KeyPress); + event->accept(); } }@@ -673,7 +751,11 @@ InputItem* item = m_inputIndex.itemForButton(gbe->value());
if (item) { item->trigger(event->type() == GamepadButtonEvent::Down()); event->accept(); - return true; + } + item = m_keyIndex.itemForButton(gbe->value()); + if (item) { + item->trigger(event->type() == GamepadButtonEvent::Down()); + event->accept(); } } if (event->type() == GamepadAxisEvent::Type()) {@@ -682,23 +764,37 @@ InputItem* item = m_inputIndex.itemForAxis(gae->axis(), gae->direction());
if (item) { item->trigger(event->type() == gae->isNew()); event->accept(); - return true; + } + item = m_keyIndex.itemForAxis(gae->axis(), gae->direction()); + if (item) { + item->trigger(event->type() == gae->isNew()); + event->accept(); } } - return false; + return event->isAccepted(); +} + +InputItem* InputController::itemForKey(const QString& key) { + return m_keyIndex.itemAt(QString("key%0").arg(key)); } -InputItem* InputController::itemForKey(int key) { - if (key < 0 || key >= m_inputMap.info->nKeys) { - return nullptr; +int InputController::keyId(const QString& key) { + for (int i = 0; i < m_activeKeyInfo->nKeys; ++i) { + if (m_activeKeyInfo->keyId[i] == key) { + return i; + } } - return m_inputIndex.itemAt(QString("key%0").arg(m_inputMap.info->keyId[key])); + return -1; } void InputController::restoreModel() { + if (!m_activeKeyInfo) { + return; + } int nKeys = m_inputMap.info->nKeys; for (int i = 0; i < nKeys; ++i) { - InputItem* item = itemForKey(i); + const QString& keyName = m_inputMap.info->keyId[i]; + InputItem* item = itemForKey(keyName); if (item) { int key = mInputQueryBinding(&m_inputMap, KEYBOARD, i); if (key >= 0) {@@ -717,36 +813,34 @@ #endif
} } #ifdef BUILD_SDL - struct Context { - InputIndex* model; - InputController* controller; - } context { - &m_inputIndex, - this - }; mInputEnumerateAxes(&m_inputMap, SDL_BINDING_BUTTON, [](int axis, const struct mInputAxis* description, void* user) { - Context* context = static_cast<Context*>(user); - InputIndex* model = context->model; - InputController* controller = context->controller; + InputController* controller = static_cast<InputController*>(user); InputItem* item; + const mInputPlatformInfo* inputMap = controller->m_inputMap.info; if (description->highDirection >= 0 && description->highDirection < controller->m_inputMap.info->nKeys) { - item = controller->itemForKey(description->highDirection); - if (item) { - item->setAxis(axis, GamepadAxisEvent::POSITIVE); + int id = description->lowDirection; + if (id >= 0 && id < inputMap->nKeys) { + item = controller->itemForKey(inputMap->keyId[id]); + if (item) { + item->setAxis(axis, GamepadAxisEvent::POSITIVE); + } } } if (description->lowDirection >= 0 && description->lowDirection < controller->m_inputMap.info->nKeys) { - item = controller->itemForKey(description->lowDirection); - if (item) { - item->setAxis(axis, GamepadAxisEvent::NEGATIVE); + int id = description->highDirection; + if (id >= 0 && id < inputMap->nKeys) { + item = controller->itemForKey(inputMap->keyId[id]); + if (item) { + item->setAxis(axis, GamepadAxisEvent::NEGATIVE); + } } } - }, &context); + }, this); #endif - rebuildIndex(); + rebuildKeyIndex(); } -void InputController::rebindKey(int key) { +void InputController::rebindKey(const QString& key) { InputItem* item = itemForKey(key); bindKey(KEYBOARD, item->shortcut(), key); #ifdef BUILD_SDL
@@ -46,7 +46,13 @@ InputController(int playerId = 0, QWidget* topLevel = nullptr, QObject* parent = nullptr);
~InputController(); InputIndex* inputIndex() { return &m_inputIndex; } + InputIndex* keyIndex() { return &m_keyIndex; } void rebuildIndex(const InputIndex* = nullptr); + void rebuildKeyIndex(const InputIndex* = nullptr); + + void addPlatform(mPlatform, const mInputPlatformInfo*); + void setPlatform(mPlatform); + void addKey(const QString& name); void setConfiguration(ConfigController* config); void saveConfiguration();@@ -69,9 +75,9 @@ QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(int type);
QSet<QPair<int, GamepadHatEvent::Direction>> activeGamepadHats(int type); void recalibrateAxes(); - void bindKey(uint32_t type, int key, int); - void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, int); - void bindHat(uint32_t type, int hat, GamepadHatEvent::Direction, int); + void bindKey(uint32_t type, int key, const QString&); + void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, const QString&); + void bindHat(uint32_t type, int hat, GamepadHatEvent::Direction, const QString&); QStringList connectedGamepads(uint32_t type) const; int gamepad(uint32_t type) const;@@ -94,6 +100,9 @@ mRotationSource* rotationSource();
signals: void profileLoaded(const QString& profile); + void keyPressed(int); + void keyReleased(int); + void keyAutofire(int, bool enabled); public slots: void testGamepad(int type);@@ -113,17 +122,24 @@ void clearPendingEvent(int key);
bool hasPendingEvent(int key) const; void sendGamepadEvent(QEvent*); void restoreModel(); - void rebindKey(int key); + void rebindKey(const QString& key); - InputItem* itemForKey(int key); + InputItem* itemForKey(const QString& key); + int keyId(const QString& key); InputIndex m_inputIndex; + InputIndex m_keyIndex; mInputMap m_inputMap; ConfigController* m_config = nullptr; int m_playerId; bool m_allowOpposing = false; QWidget* m_topLevel; QWidget* m_focusParent; + QMap<mPlatform, const mInputPlatformInfo*> m_keyInfo; + const mInputPlatformInfo* m_activeKeyInfo = nullptr; + + std::unique_ptr<QMenu> m_bindings; + std::unique_ptr<QMenu> m_autofire; #ifdef BUILD_SDL static int s_sdlInited;
@@ -12,6 +12,9 @@ using namespace QGBA;
void InputIndex::setConfigController(ConfigController* controller) { m_config = controller; + for (auto& item : m_items) { + loadShortcuts(item); + } } void InputIndex::clone(InputIndex* root, bool actions) {@@ -241,7 +244,16 @@ void InputIndex::loadProfile(const QString& profile) {
m_profileName = profile; m_profile = InputProfile::findProfile(profile); for (auto& item : m_items) { - loadGamepadShortcuts(item); + loadShortcuts(item); } } +void InputIndex::saveConfig() { + for (auto& item : m_items) { + m_config->setQtOption(item->name(), QKeySequence(item->shortcut()).toString(), KEY_SECTION); + m_config->setQtOption(item->name(), item->button(), BUTTON_SECTION); + if (item->direction() != GamepadAxisEvent::NEUTRAL) { + m_config->setQtOption(item->name(), QString("%1%2").arg(GamepadAxisEvent::POSITIVE ? '+' : '-').arg(item->axis()), AXIS_SECTION); + } + } +}
@@ -24,8 +24,11 @@ private:
constexpr static const char* const KEY_SECTION = "shortcutKey"; constexpr static const char* const BUTTON_SECTION = "shortcutButton"; constexpr static const char* const AXIS_SECTION = "shortcutAxis"; + constexpr static const char* const HAT_SECTION = "shortcutHat"; + constexpr static const char* const KEY_PROFILE_SECTION = "shortcutProfileKey."; constexpr static const char* const BUTTON_PROFILE_SECTION = "shortcutProfileButton."; constexpr static const char* const AXIS_PROFILE_SECTION = "shortcutProfileAxis."; + constexpr static const char* const HAT_PROFILE_SECTION = "shortcutProfileHat."; public: void setConfigController(ConfigController* controller);@@ -58,6 +61,8 @@ static bool isModifierKey(int key);
static int toModifierKey(int key); void loadProfile(const QString& profile); + + void saveConfig(); private: bool loadShortcuts(InputItem*);
@@ -34,15 +34,6 @@ , m_menu(parent)
{ } -InputItem::InputItem(int key, const QString& visibleName, const QString& name, QMenu* parent) - : QObject(parent) - , m_key(key) - , m_name(name) - , m_visibleName(visibleName) - , m_menu(parent) -{ -} - InputItem::InputItem(const QString& visibleName, const QString& name, QMenu* parent) : QObject(parent) , m_name(name)@@ -67,7 +58,6 @@ InputItem::InputItem(InputItem& other)
: QObject(other.m_menu) , m_action(other.m_action) , m_functions(other.m_functions) - , m_key(other.m_key) , m_name(other.m_name) , m_visibleName(other.m_visibleName) , m_shortcut(other.m_shortcut)
@@ -24,7 +24,6 @@
InputItem(QAction* action, const QString& name, QMenu* parent = nullptr); InputItem(Functions functions, const QString& visibleName, const QString& name, QMenu* parent = nullptr); - InputItem(int key, const QString& name, const QString& visibleName, QMenu* parent = nullptr); InputItem(const QString& visibleName, const QString& name, QMenu* parent = nullptr); InputItem();@@ -34,7 +33,6 @@
QAction* action() { return m_action; } const QAction* action() const { return m_action; } Functions functions() const { return m_functions; } - int key() const { return m_key; } QMenu* menu() { return m_menu; } const QMenu* menu() const { return m_menu; }@@ -70,7 +68,6 @@
private: QAction* m_action = nullptr; Functions m_functions; - int m_key = -1; QMenu* m_menu = nullptr; QString m_name;
@@ -138,11 +138,11 @@ }
} QModelIndex InputModel::index(const QObject* item, int column) const { - if (!item || !item->parent()) { + if (!item) { return QModelIndex(); } const QObject* parent = item->parent(); - if (m_tree.contains(parent)) { + if (parent && m_tree.contains(parent)) { int index = m_tree[parent].indexOf(item); return createIndex(index, column, const_cast<InputModelItem*>(&m_tree[parent][index])); }
@@ -212,8 +212,8 @@
void InputProfile::apply(InputController* controller) const { for (size_t i = 0; i < GBA_KEY_MAX; ++i) { #ifdef BUILD_SDL - 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->bindKey(SDL_BINDING_BUTTON, m_keys[i], GBAInputInfo.keyId[i]); + controller->bindAxis(SDL_BINDING_BUTTON, m_axes[i].axis, m_axes[i].direction, GBAInputInfo.keyId[i]); #endif } controller->registerTiltAxisX(m_tiltAxis.x);