Qt: Split up InputModel for better isolation
jump to
@@ -78,6 +78,7 @@ GamepadHatEvent.cpp
IOViewer.cpp InputController.cpp InputItem.cpp + InputIndex.cpp InputModel.cpp InputProfile.cpp KeyEditor.cpp
@@ -9,6 +9,7 @@ #include "ConfigController.h"
#include "GameController.h" #include "GamepadAxisEvent.h" #include "GamepadButtonEvent.h" +#include "InputItem.h" #include "InputModel.h" #include "InputProfile.h"@@ -28,9 +29,8 @@ int InputController::s_sdlInited = 0;
mSDLEvents InputController::s_sdlEvents; #endif -InputController::InputController(InputModel* model, int playerId, QWidget* topLevel, QObject* parent) +InputController::InputController(int playerId, QWidget* topLevel, QObject* parent) : QObject(parent) - , m_inputModel(model) , m_playerId(playerId) , m_topLevel(topLevel) , m_focusParent(topLevel)@@ -87,8 +87,24 @@ }
#endif } +void InputController::rebuildIndex(const InputItem* 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::setConfiguration(ConfigController* config) { m_config = config; + m_inputIndex.setConfigController(config); setAllowOpposing(config->getOption("allowOpposingDirections").toInt()); loadConfiguration(KEYBOARD); #ifdef BUILD_SDL@@ -123,7 +139,7 @@ ip->apply(this);
} } recalibrateAxes(); - m_inputModel->loadProfile(profile); // TODO + m_inputIndex.loadProfile(profile); emit profileLoaded(profile); }@@ -398,21 +414,19 @@ return activeAxes;
} void InputController::bindKey(uint32_t type, int key, int coreKey) { - /*InputItem* item = m_inputModel->itemForKey(coreKey); + InputItem* item = itemForKey(coreKey); if (type != KEYBOARD) { item->setButton(key); } else { - item->setShortcut(key); - }*/ + item->setShortcut(key); + } mInputBindKey(&m_inputMap, type, key, coreKey); } void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, int key) { - //InputItem* item = m_inputModel->itemForKey(key); - bool signalsBlocked = m_inputModel->blockSignals(true); - //item->setAxis(axis, direction); - m_inputModel->blockSignals(signalsBlocked); - + InputItem* item = itemForKey(key); + item->setAxis(axis, direction); + const mInputAxis* old = mInputQueryAxis(&m_inputMap, type, axis); mInputAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD }; if (old) {@@ -629,52 +643,14 @@ m_focusParent = m_topLevel;
} } -void InputController::doBindKey(const QModelIndex& index, int key) { - int coreKey = m_inputModel->itemAt(index)->key(); - if (coreKey < 0) { - return; - } - bindKey(KEYBOARD, key, coreKey); -} - -#ifdef BUILD_SDL -void InputController::doBindButton(const QModelIndex& index, int key) { - int coreKey = m_inputModel->itemAt(index)->key(); - if (coreKey < 0) { - return; - } - bindKey(SDL_BINDING_BUTTON, key, coreKey); -} - -void InputController::doBindAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction direction) { - int coreKey = m_inputModel->itemAt(index)->key(); - if (coreKey < 0) { - return; - } - bindAxis(SDL_BINDING_BUTTON, axis, direction, coreKey); -} - -void InputController::doBindHat(const QModelIndex& index, int hat, GamepadHatEvent::Direction direction) { - int coreKey = m_inputModel->itemAt(index)->key(); - if (coreKey < 0) { - return; - } - bindHat(SDL_BINDING_BUTTON, hat, direction, coreKey); -} -#else -void InputController::bindButton(const QModelIndex& index, int key) {} -void InputController::bindAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction) {} -void InputController::bindHat(const QModelIndex& index, int hat, GamepadHatEvent::Direction) {} -#endif - bool InputController::eventFilter(QObject*, QEvent* event) { if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); int key = keyEvent->key(); - if (!InputModel::isModifierKey(key)) { + if (!InputIndex::isModifierKey(key)) { key |= (keyEvent->modifiers() & ~Qt::KeypadModifier); } else { - key = InputModel::toModifierKey(key | (keyEvent->modifiers() & ~Qt::KeypadModifier)); + key = InputIndex::toModifierKey(key | (keyEvent->modifiers() & ~Qt::KeypadModifier)); } if (keyEvent->isAutoRepeat()) {@@ -682,7 +658,7 @@ event->accept();
return true; } - InputItem* item = m_inputModel->itemForShortcut(key); + InputItem* item = m_inputIndex.itemForShortcut(key); if (item) { item->trigger(event->type() == QEvent::KeyPress); event->accept();@@ -693,7 +669,7 @@
if (event->type() == GamepadButtonEvent::Down() || event->type() == GamepadButtonEvent::Up()) { GamepadButtonEvent* gbe = static_cast<GamepadButtonEvent*>(event); - InputItem* item = m_inputModel->itemForButton(gbe->value()); + InputItem* item = m_inputIndex.itemForButton(gbe->value()); if (item) { item->trigger(event->type() == GamepadButtonEvent::Down()); event->accept();@@ -702,7 +678,7 @@ }
} if (event->type() == GamepadAxisEvent::Type()) { GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event); - InputItem* item = m_inputModel->itemForAxis(gae->axis(), gae->direction()); + InputItem* item = m_inputIndex.itemForAxis(gae->axis(), gae->direction()); if (item) { item->trigger(event->type() == gae->isNew()); event->accept();@@ -716,11 +692,10 @@ InputItem* InputController::itemForKey(int key) {
if (key < 0 || key >= m_inputMap.info->nKeys) { return nullptr; } - return m_inputModel->itemAt(QString("key%0").arg(m_inputMap.info->keyId[key])); + return m_inputIndex.itemAt(QString("key%0").arg(m_inputMap.info->keyId[key])); } void InputController::restoreModel() { - bool signalsBlocked = m_inputModel->blockSignals(true); int nKeys = m_inputMap.info->nKeys; for (int i = 0; i < nKeys; ++i) { InputItem* item = itemForKey(i);@@ -743,15 +718,15 @@ }
} #ifdef BUILD_SDL struct Context { - InputModel* model; + InputIndex* model; InputController* controller; } context { - m_inputModel, + &m_inputIndex, this }; mInputEnumerateAxes(&m_inputMap, SDL_BINDING_BUTTON, [](int axis, const struct mInputAxis* description, void* user) { Context* context = static_cast<Context*>(user); - InputModel* model = context->model; + InputIndex* model = context->model; InputController* controller = context->controller; InputItem* item; if (description->highDirection >= 0 && description->highDirection < controller->m_inputMap.info->nKeys) {@@ -768,5 +743,14 @@ }
} }, &context); #endif - m_inputModel->blockSignals(signalsBlocked); + rebuildIndex(); +} + +void InputController::rebindKey(int key) { + InputItem* item = itemForKey(key); + bindKey(KEYBOARD, item->shortcut(), key); +#ifdef BUILD_SDL + bindKey(SDL_BINDING_BUTTON, item->button(), key); + bindAxis(SDL_BINDING_BUTTON, item->axis(), item->direction(), key); +#endif }
@@ -8,6 +8,7 @@ #define QGBA_INPUT_CONTROLLER_H
#include "GamepadAxisEvent.h" #include "GamepadHatEvent.h" +#include "InputIndex.h" #include <memory>@@ -34,7 +35,6 @@
class ConfigController; class GameController; class InputItem; -class InputModel; class InputController : public QObject { Q_OBJECT@@ -42,8 +42,11 @@
public: static const uint32_t KEYBOARD = 0x51545F4B; - InputController(InputModel* model, int playerId = 0, QWidget* topLevel = nullptr, QObject* parent = nullptr); + InputController(int playerId = 0, QWidget* topLevel = nullptr, QObject* parent = nullptr); ~InputController(); + + InputIndex* inputIndex() { return &m_inputIndex; } + void rebuildIndex(const InputItem* = nullptr); void setConfiguration(ConfigController* config); void saveConfiguration();@@ -101,12 +104,6 @@ void suspendScreensaver();
void resumeScreensaver(); void setScreensaverSuspendable(bool); -private slots: - void doBindKey(const QModelIndex&, int key); - void doBindButton(const QModelIndex&, int key); - void doBindAxis(const QModelIndex&, int axis, GamepadAxisEvent::Direction); - void doBindHat(const QModelIndex&, int hat, GamepadHatEvent::Direction); - protected: bool eventFilter(QObject*, QEvent*) override;@@ -116,10 +113,11 @@ void clearPendingEvent(int key);
bool hasPendingEvent(int key) const; void sendGamepadEvent(QEvent*); void restoreModel(); + void rebindKey(int key); InputItem* itemForKey(int key); - InputModel* m_inputModel = nullptr; + InputIndex m_inputIndex; mInputMap m_inputMap; ConfigController* m_config = nullptr; int m_playerId;
@@ -0,0 +1,275 @@
+/* Copyright (c) 2013-2017 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 "InputIndex.h" + +#include "ConfigController.h" +#include "InputProfile.h" + +using namespace QGBA; + +void InputIndex::setConfigController(ConfigController* controller) { + m_config = controller; +} + +void InputIndex::clone(InputIndex* root, bool actions) { + if (!actions) { + clone(const_cast<const InputIndex*>(root)); + } else { + m_root.clear(); + onSubitems(root->root(), [this](InputItem* item, InputItem* parent, QVariant accum) -> QVariant { + InputItem* newParent = qvariant_cast<InputItem*>(accum); + InputItem* newItem = newParent->addItem(*item); + itemAdded(newItem); + return QVariant::fromValue(newItem); + }, QVariant::fromValue(&m_root)); + } +} + +void InputIndex::clone(const InputIndex* root) { + m_root.clear(); + onSubitems(root->root(), [this](const InputItem* item, const InputItem* parent, QVariant accum) -> QVariant { + InputItem* newParent = qvariant_cast<InputItem*>(accum); + InputItem* newItem = newParent->addItem(*item); + itemAdded(newItem); + return QVariant::fromValue(newItem); + }, QVariant::fromValue(&m_root)); +} + +void InputIndex::rebuild(const InputIndex* root) { + rebuild(root->root()); +} + +void InputIndex::rebuild(const InputItem* root) { + const InputItem* sourceRoot; + if (!root) { + sourceRoot = &m_root; + } else { + sourceRoot = root; + } + + m_names.clear(); + m_menus.clear(); + m_shortcuts.clear(); + m_buttons.clear(); + m_axes.clear(); + + onSubitems(sourceRoot, [this](const InputItem* item, const InputItem* parent, QVariant accum) -> QVariant { + InputItem* newParent = qvariant_cast<InputItem*>(accum); + InputItem* newItem = nullptr; + for (auto iter : newParent->items()) { + if (*iter == *item) { + newItem = iter; + break; + } + } + newItem->setShortcut(item->shortcut()); + newItem->setButton(item->button()); + newItem->setAxis(item->axis(), item->direction()); + + itemAdded(newItem); + return QVariant::fromValue(newItem); + }, QVariant::fromValue(&m_root)); +} + +InputItem* InputIndex::itemAt(const QString& name) { + return m_names[name]; +} + +const InputItem* InputIndex::itemAt(const QString& name) const { + return m_names[name]; +} + +InputItem* InputIndex::itemForMenu(const QMenu* menu) { + InputItem* item = m_menus[menu]; + return item; +} + +const InputItem* InputIndex::itemForMenu(const QMenu* menu) const { + const InputItem* item = m_menus[menu]; + return item; +} + +InputItem* InputIndex::itemForShortcut(int shortcut) { + return m_shortcuts[shortcut]; +} + +InputItem* InputIndex::itemForButton(int button) { + return m_buttons[button]; +} + +InputItem* InputIndex::itemForAxis(int axis, GamepadAxisEvent::Direction direction) { + return m_axes[qMakePair(axis, direction)]; +} + +bool InputIndex::loadShortcuts(InputItem* item) { + if (item->name().isNull()) { + return false; + } + loadGamepadShortcuts(item); + QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION); + if (!shortcut.isNull()) { + if (shortcut.toString().endsWith("+")) { + item->setShortcut(toModifierShortcut(shortcut.toString())); + } else { + item->setShortcut(QKeySequence(shortcut.toString())[0]); + } + return true; + } + return false; +} + +void InputIndex::loadGamepadShortcuts(InputItem* item) { + if (item->name().isNull()) { + return; + } + QVariant button = m_config->getQtOption(item->name(), !m_profileName.isNull() ? BUTTON_PROFILE_SECTION + m_profileName : BUTTON_SECTION); + if (button.isNull() && m_profile) { + int buttonInt; + if (m_profile->lookupShortcutButton(item->name(), &buttonInt)) { + button = buttonInt; + } + } + if (!button.isNull()) { + item->setButton(button.toInt()); + } + + QVariant axis = m_config->getQtOption(item->name(), !m_profileName.isNull() ? AXIS_PROFILE_SECTION + m_profileName : AXIS_SECTION); + int oldAxis = item->axis(); + if (oldAxis >= 0) { + 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(); + if (axisDesc.size() >= 2) { + GamepadAxisEvent::Direction direction = GamepadAxisEvent::NEUTRAL; + if (axisDesc[0] == '-') { + direction = GamepadAxisEvent::NEGATIVE; + } + if (axisDesc[0] == '+') { + direction = GamepadAxisEvent::POSITIVE; + } + bool ok; + int axis = axisDesc.mid(1).toInt(&ok); + if (ok) { + item->setAxis(axis, direction); + } + } + } +} + +int InputIndex::toModifierShortcut(const QString& shortcut) { + // Qt doesn't seem to work with raw modifier shortcuts! + QStringList modifiers = shortcut.split('+'); + int value = 0; + for (const auto& mod : modifiers) { + if (mod == QLatin1String("Shift")) { + value |= Qt::ShiftModifier; + continue; + } + if (mod == QLatin1String("Ctrl")) { + value |= Qt::ControlModifier; + continue; + } + if (mod == QLatin1String("Alt")) { + value |= Qt::AltModifier; + continue; + } + if (mod == QLatin1String("Meta")) { + value |= Qt::MetaModifier; + continue; + } + } + return value; +} + +void InputIndex::itemAdded(InputItem* child) { + const QMenu* menu = child->menu(); + if (menu) { + m_menus[menu] = child; + } + m_names[child->name()] = child; + + if (child->shortcut()) { + m_shortcuts[child->shortcut()] = child; + } + if (child->button() >= 0) { + m_buttons[child->button()] = child; + } + if (child->direction() != GamepadAxisEvent::NEUTRAL) { + m_axes[qMakePair(child->axis(), child->direction())] = child; + } +} + +bool InputIndex::isModifierKey(int key) { + switch (key) { + case Qt::Key_Shift: + case Qt::Key_Control: + case Qt::Key_Alt: + case Qt::Key_Meta: + return true; + default: + return false; + } +} + +int InputIndex::toModifierKey(int key) { + int modifiers = key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier); + key ^= modifiers; + switch (key) { + case Qt::Key_Shift: + modifiers |= Qt::ShiftModifier; + break; + case Qt::Key_Control: + modifiers |= Qt::ControlModifier; + break; + case Qt::Key_Alt: + modifiers |= Qt::AltModifier; + break; + case Qt::Key_Meta: + modifiers |= Qt::MetaModifier; + break; + default: + break; + } + return modifiers; +} + +void InputIndex::onSubitems(InputItem* item, std::function<void(InputItem*)> func) { + for (InputItem* subitem : item->items()) { + func(subitem); + onSubitems(subitem, func); + } +} + +void InputIndex::onSubitems(InputItem* item, std::function<QVariant(InputItem*, InputItem*, QVariant)> func, QVariant accum) { + for (InputItem* subitem : item->items()) { + QVariant newAccum = func(subitem, item, accum); + onSubitems(subitem, func, newAccum); + } +} + +void InputIndex::onSubitems(const InputItem* item, std::function<QVariant(const InputItem*, const InputItem*, QVariant)> func, QVariant accum) { + for (const InputItem* subitem : item->items()) { + QVariant newAccum = func(subitem, item, accum); + onSubitems(subitem, func, newAccum); + } +} + +void InputIndex::loadProfile(const QString& profile) { + m_profileName = profile; + m_profile = InputProfile::findProfile(profile); + onSubitems(&m_root, [this](InputItem* item) { + loadGamepadShortcuts(item); + }); +} +
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013-2017 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_INDEX +#define QGBA_INPUT_INDEX + +#include "GamepadAxisEvent.h" +#include "InputItem.h" + +#include <QMap> +#include <QString> + +class QMenu; + +namespace QGBA { + +class ConfigController; +class InputProfile; + +class InputIndex { +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 BUTTON_PROFILE_SECTION = "shortcutProfileButton."; + constexpr static const char* const AXIS_PROFILE_SECTION = "shortcutProfileAxis."; + +public: + void setConfigController(ConfigController* controller); + + void clone(InputIndex* root, bool actions = false); + void clone(const InputIndex* root); + void rebuild(const InputIndex* root); + void rebuild(const InputItem* root = nullptr); + + template<typename... Args> InputItem* addItem(Args... params) { + InputItem* newItem = m_root.addItem(params...); + itemAdded(newItem); + return newItem; + } + + InputItem* itemAt(const QString& name); + const InputItem* itemAt(const QString& name) const; + + InputItem* itemForMenu(const QMenu* menu); + const InputItem* itemForMenu(const QMenu* menu) const; + + InputItem* itemForShortcut(int shortcut); + InputItem* itemForButton(int button); + InputItem* itemForAxis(int axis, GamepadAxisEvent::Direction); + + static int toModifierShortcut(const QString& shortcut); + static bool isModifierKey(int key); + static int toModifierKey(int key); + + InputItem* root() { return &m_root; } + const InputItem* root() const { return &m_root; } + + void loadProfile(const QString& profile); + +private: + bool loadShortcuts(InputItem*); + void loadGamepadShortcuts(InputItem*); + void onSubitems(InputItem*, std::function<void(InputItem*)> func); + void onSubitems(InputItem*, std::function<QVariant(InputItem*, InputItem* parent, QVariant accum)> func, QVariant accum = QVariant()); + void onSubitems(const InputItem*, std::function<QVariant(const InputItem*, const InputItem* parent, QVariant accum)> func, QVariant accum = QVariant()); + + void itemAdded(InputItem*); + + InputItem m_root; + + QMap<QString, InputItem*> m_names; + QMap<const QMenu*, InputItem*> m_menus; + QMap<int, InputItem*> m_shortcuts; + QMap<int, InputItem*> m_buttons; + QMap<QPair<int, GamepadAxisEvent::Direction>, InputItem*> m_axes; + + ConfigController* m_config = nullptr; + QString m_profileName; + const InputProfile* m_profile = nullptr; +}; + +} + +#endif
@@ -9,6 +9,12 @@ #include <QMenu>
using namespace QGBA; +InputItem::InputItem() + : QObject(nullptr) + , m_parent(nullptr) +{ +} + InputItem::InputItem(QAction* action, const QString& name, InputItem* parent) : QObject(parent) , m_action(action)@@ -58,6 +64,35 @@ , m_parent(parent)
{ } +InputItem::InputItem(const InputItem& other, InputItem* parent) + : QObject(parent) + , m_menu(other.m_menu) + , m_name(other.m_name) + , m_visibleName(other.m_visibleName) + , m_shortcut(other.m_shortcut) + , m_button(other.m_button) + , m_axis(other.m_axis) + , m_direction(other.m_direction) + , m_parent(parent) +{ +} + +InputItem::InputItem(InputItem& other, InputItem* parent) + : QObject(parent) + , m_action(other.m_action) + , m_functions(other.m_functions) + , m_key(other.m_key) + , m_menu(other.m_menu) + , m_name(other.m_name) + , m_visibleName(other.m_visibleName) + , m_shortcut(other.m_shortcut) + , m_button(other.m_button) + , m_axis(other.m_axis) + , m_direction(other.m_direction) + , m_parent(parent) +{ +} + void InputItem::setShortcut(int shortcut) { m_shortcut = shortcut; if (m_action) {@@ -83,6 +118,11 @@ void InputItem::setAxis(int axis, GamepadAxisEvent::Direction direction) {
m_axis = axis; m_direction = direction; emit axisBound(this, axis, direction); +} + +void InputItem::clear() { + qDeleteAll(m_items); + m_items.clear(); } void InputItem::trigger(bool active) {
@@ -18,18 +18,24 @@
class InputItem : public QObject { Q_OBJECT -public: +private: typedef QPair<std::function<void ()>, std::function<void ()>> Functions; InputItem(QAction* action, const QString& name, InputItem* parent = nullptr); - InputItem(QMenu* action, const QString& name, InputItem* parent = nullptr); + InputItem(QMenu* menu, const QString& name, InputItem* parent = nullptr); InputItem(Functions functions, const QString& visibleName, const QString& name, InputItem* parent = nullptr); InputItem(int key, const QString& name, const QString& visibleName, InputItem* parent = nullptr); InputItem(const QString& visibleName, const QString& name, InputItem* parent = nullptr); +public: + InputItem(); + InputItem(InputItem&, InputItem* parent = nullptr); + InputItem(const InputItem&, InputItem* parent = nullptr); + QAction* action() { return m_action; } const QAction* action() const { return m_action; } + QMenu* menu() { return m_menu; } const QMenu* menu() const { return m_menu; } Functions functions() const { return m_functions; } int key() const { return m_key; }@@ -60,8 +66,10 @@ int axis() const { return m_axis; }
GamepadAxisEvent::Direction direction() const { return m_direction; } void setAxis(int axis, GamepadAxisEvent::Direction direction); + void clear(); + bool operator==(const InputItem& other) const { - return m_name == other.m_name && m_visibleName == other.m_visibleName; + return m_name == other.m_name; } public slots:@@ -75,20 +83,23 @@ void childAdded(InputItem* parent, InputItem* child);
private: QAction* m_action = nullptr; - QMenu* m_menu = nullptr; Functions m_functions; + int m_key = -1; + + QMenu* m_menu = nullptr; QString m_name; QString m_visibleName; int m_shortcut = 0; int m_button = -1; int m_axis = -1; - int m_key = -1; GamepadAxisEvent::Direction m_direction = GamepadAxisEvent::NEUTRAL; QList<InputItem*> m_items; InputItem* m_parent; }; } + +Q_DECLARE_METATYPE(QGBA::InputItem) #endif
@@ -5,9 +5,8 @@ * 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 "InputModel.h" -#include "ConfigController.h" #include "GamepadButtonEvent.h" -#include "InputProfile.h" +#include "InputIndex.h" #include <QAction> #include <QKeyEvent>@@ -15,15 +14,21 @@ #include <QMenu>
using namespace QGBA; +InputModel::InputModel(const InputIndex& index, QObject* parent) + : QAbstractItemModel(parent) +{ + m_root.clone(&index); +} + InputModel::InputModel(QObject* parent) : QAbstractItemModel(parent) - , m_rootMenu(QString(), QString()) { - connect(&m_rootMenu, &InputItem::childAdded, this, &InputModel::itemAdded); } -void InputModel::setConfigController(ConfigController* controller) { - m_config = controller; +void InputModel::clone(const InputIndex& index) { + emit beginResetModel(); + m_root.clone(&index); + emit endResetModel(); } QVariant InputModel::data(const QModelIndex& index, int role) const {@@ -74,7 +79,7 @@ return section;
} QModelIndex InputModel::index(int row, int column, const QModelIndex& parent) const { - const InputItem* pmenu = &m_rootMenu; + const InputItem* pmenu = m_root.root(); if (parent.isValid()) { pmenu = static_cast<InputItem*>(parent.internalPointer()); }@@ -102,7 +107,7 @@ }
int InputModel::rowCount(const QModelIndex& index) const { if (!index.isValid()) { - return m_rootMenu.items().count(); + return m_root.root()->items().count(); } const InputItem* item = static_cast<const InputItem*>(index.internalPointer()); return item->items().count();@@ -135,215 +140,3 @@ }
InputItem* pmenu = static_cast<InputItem*>(index.parent().internalPointer()); return pmenu->items()[index.row()]; } - -InputItem* InputModel::itemAt(const QString& name) { - return m_names[name]; -} - -const InputItem* InputModel::itemAt(const QString& name) const { - return m_names[name]; -} - -InputItem* InputModel::itemForMenu(const QMenu* menu) { - InputItem* item = m_menus[menu]; - if (!item) { - return &m_rootMenu; - } - return item; -} - -const InputItem* InputModel::itemForMenu(const QMenu* menu) const { - const InputItem* item = m_menus[menu]; - if (!item) { - return &m_rootMenu; - } - return item; -} - -InputItem* InputModel::itemForShortcut(int shortcut) { - return m_shortcuts[shortcut]; -} - -InputItem* InputModel::itemForButton(int button) { - return m_buttons[button]; -} - -InputItem* InputModel::itemForAxis(int axis, GamepadAxisEvent::Direction direction) { - return m_axes[qMakePair(axis, direction)]; -} - -bool InputModel::loadShortcuts(InputItem* item) { - if (item->name().isNull()) { - return false; - } - loadGamepadShortcuts(item); - QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION); - if (!shortcut.isNull()) { - if (shortcut.toString().endsWith("+")) { - item->setShortcut(toModifierShortcut(shortcut.toString())); - } else { - item->setShortcut(QKeySequence(shortcut.toString())[0]); - } - return true; - } - return false; -} - -void InputModel::loadGamepadShortcuts(InputItem* item) { - if (item->name().isNull()) { - return; - } - QVariant button = m_config->getQtOption(item->name(), !m_profileName.isNull() ? BUTTON_PROFILE_SECTION + m_profileName : BUTTON_SECTION); - if (button.isNull() && m_profile) { - int buttonInt; - if (m_profile->lookupShortcutButton(item->name(), &buttonInt)) { - button = buttonInt; - } - } - if (!button.isNull()) { - item->setButton(button.toInt()); - } - - QVariant axis = m_config->getQtOption(item->name(), !m_profileName.isNull() ? AXIS_PROFILE_SECTION + m_profileName : AXIS_SECTION); - int oldAxis = item->axis(); - if (oldAxis >= 0) { - 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(); - if (axisDesc.size() >= 2) { - GamepadAxisEvent::Direction direction = GamepadAxisEvent::NEUTRAL; - if (axisDesc[0] == '-') { - direction = GamepadAxisEvent::NEGATIVE; - } - if (axisDesc[0] == '+') { - direction = GamepadAxisEvent::POSITIVE; - } - bool ok; - int axis = axisDesc.mid(1).toInt(&ok); - if (ok) { - item->setAxis(axis, direction); - } - } - } -} - -void InputModel::loadProfile(const QString& profile) { - m_profileName = profile; - m_profile = InputProfile::findProfile(profile); - onSubitems(&m_rootMenu, [this](InputItem* item) { - loadGamepadShortcuts(item); - }); -} - -void InputModel::onSubitems(InputItem* item, std::function<void(InputItem*)> func) { - for (InputItem* subitem : item->items()) { - func(subitem); - onSubitems(subitem, func); - } -} - -int InputModel::toModifierShortcut(const QString& shortcut) { - // Qt doesn't seem to work with raw modifier shortcuts! - QStringList modifiers = shortcut.split('+'); - int value = 0; - for (const auto& mod : modifiers) { - if (mod == QLatin1String("Shift")) { - value |= Qt::ShiftModifier; - continue; - } - if (mod == QLatin1String("Ctrl")) { - value |= Qt::ControlModifier; - continue; - } - if (mod == QLatin1String("Alt")) { - value |= Qt::AltModifier; - continue; - } - if (mod == QLatin1String("Meta")) { - value |= Qt::MetaModifier; - continue; - } - } - return value; -} - -bool InputModel::isModifierKey(int key) { - switch (key) { - case Qt::Key_Shift: - case Qt::Key_Control: - case Qt::Key_Alt: - case Qt::Key_Meta: - return true; - default: - return false; - } -} - -int InputModel::toModifierKey(int key) { - int modifiers = key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier); - key ^= modifiers; - switch (key) { - case Qt::Key_Shift: - modifiers |= Qt::ShiftModifier; - break; - case Qt::Key_Control: - modifiers |= Qt::ControlModifier; - break; - case Qt::Key_Alt: - modifiers |= Qt::AltModifier; - break; - case Qt::Key_Meta: - modifiers |= Qt::MetaModifier; - break; - default: - break; - } - return modifiers; -} - -void InputModel::itemAdded(InputItem* parent, InputItem* child) { - const QMenu* menu = child->menu(); - if (menu) { - m_menus[menu] = child; - } - if (child->shortcut()) { - m_shortcuts[child->shortcut()] = child; - } - if (child->button() >= 0) { - m_buttons[child->button()] = child; - } - if (child->direction() != GamepadAxisEvent::NEUTRAL) { - m_axes[qMakePair(child->axis(), child->direction())] = child; - } - m_names[child->name()] = child; - connect(child, &InputItem::childAdded, this, &InputModel::itemAdded); - connect(child, &InputItem::shortcutBound, this, &InputModel::rebindShortcut); - connect(child, &InputItem::buttonBound, this, &InputModel::rebindButton); - connect(child, &InputItem::axisBound, this, &InputModel::rebindAxis); -} - -void InputModel::rebindShortcut(InputItem* item, int shortcut) { - if (shortcut) { - m_shortcuts[shortcut] = item; - } -} - -void InputModel::rebindButton(InputItem* item, int button) { - if (button >= 0) { - m_buttons[button] = item; - } -} - -void InputModel::rebindAxis(InputItem* item, int axis, GamepadAxisEvent::Direction direction) { - if (axis != GamepadAxisEvent::NEUTRAL) { - m_axes[qMakePair(axis, direction)] = item; - } -}
@@ -8,8 +8,7 @@ #define QGBA_INPUT_MODEL
#include <mgba/core/core.h> -#include "GamepadAxisEvent.h" -#include "InputItem.h" +#include "InputIndex.h" #include <QAbstractItemModel>@@ -23,28 +22,18 @@
namespace QGBA { class ConfigController; +class InputIndex; class InputProfile; class InputModel : public QAbstractItemModel { Q_OBJECT -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 BUTTON_PROFILE_SECTION = "shortcutProfileButton."; - constexpr static const char* const AXIS_PROFILE_SECTION = "shortcutProfileAxis."; - -private slots: - void itemAdded(InputItem* parent, InputItem* child); - void rebindShortcut(InputItem*, int shortcut); - void rebindButton(InputItem*, int button); - void rebindAxis(InputItem*, int axis, GamepadAxisEvent::Direction); - public: + InputModel(const InputIndex& index, QObject* parent = nullptr); InputModel(QObject* parent = nullptr); - void setConfigController(ConfigController* controller); + void clone(const InputIndex& index); + void setProfile(const QString& profile); virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;@@ -56,44 +45,16 @@
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; - template<typename... Args> InputItem* addItem(Args... params) { return m_rootMenu.addItem(params...); } - - InputItem* itemAt(const QString& name); - const InputItem* itemAt(const QString& name) const; InputItem* itemAt(const QModelIndex& index); const InputItem* itemAt(const QModelIndex& index) const; - InputItem* itemForMenu(const QMenu* menu); - const InputItem* itemForMenu(const QMenu* menu) const; - - InputItem* itemForShortcut(int shortcut); - InputItem* itemForButton(int button); - InputItem* itemForAxis(int axis, GamepadAxisEvent::Direction); - - static int toModifierShortcut(const QString& shortcut); - static bool isModifierKey(int key); - static int toModifierKey(int key); - - void loadProfile(const QString& profile); - - InputItem* root() { return &m_rootMenu; } + InputItem* root() { return m_root.root(); } private: - bool loadShortcuts(InputItem*); - void loadGamepadShortcuts(InputItem*); - void onSubitems(InputItem*, std::function<void(InputItem*)> func); - QModelIndex index(InputItem* item, int column = 0) const; - InputItem m_rootMenu; - QMap<QString, InputItem*> m_names; - QMap<const QMenu*, InputItem*> m_menus; - QMap<int, InputItem*> m_shortcuts; - QMap<int, InputItem*> m_buttons; - QMap<QPair<int, GamepadAxisEvent::Direction>, InputItem*> m_axes; - ConfigController* m_config; + InputIndex m_root; QString m_profileName; - const InputProfile* m_profile; }; }
@@ -7,7 +7,7 @@ #include "KeyEditor.h"
#include "GamepadAxisEvent.h" #include "GamepadButtonEvent.h" -#include "InputModel.h" +#include "InputIndex.h" #include <QFontMetrics> #include <QKeyEvent>@@ -99,7 +99,7 @@ m_key = 0;
} m_lastKey.start(KEY_TIME); if (m_key) { - if (InputModel::isModifierKey(m_key)) { + if (InputIndex::isModifierKey(m_key)) { switch (event->key()) { case Qt::Key_Shift: setValue(Qt::ShiftModifier);@@ -115,7 +115,7 @@ setValue(Qt::MetaModifier);
break; } } - if (InputModel::isModifierKey(event->key())) { + if (InputIndex::isModifierKey(event->key())) { switch (event->key()) { case Qt::Key_Shift: setValue(m_key | Qt::ShiftModifier);
@@ -17,9 +17,10 @@ #include <mgba/internal/gba/gba.h>
using namespace QGBA; -SettingsView::SettingsView(ConfigController* controller, InputController* inputController, InputModel* inputModel, QWidget* parent) +SettingsView::SettingsView(ConfigController* controller, InputController* inputController, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) , m_controller(controller) + , m_input(inputController) { m_ui.setupUi(this);@@ -144,10 +145,10 @@ updateConfig();
} }); - ShortcutView* shortcutView = new ShortcutView(); - shortcutView->setModel(inputModel); - shortcutView->setInputController(inputController); - m_ui.stackedWidget->addWidget(shortcutView); + m_shortcutView = new ShortcutView(); + m_shortcutView->setModel(inputController->inputIndex()); + m_shortcutView->setInputController(inputController); + m_ui.stackedWidget->addWidget(m_shortcutView); m_ui.tabs->addItem(tr("Bindings")); }@@ -234,6 +235,9 @@ emit displayDriverChanged();
} m_controller->write(); + + m_input->rebuildIndex(m_shortcutView->root()); + m_input->saveConfiguration(); emit pathsChanged(); emit biosLoaded(PLATFORM_GBA, m_ui.gbaBios->text());
@@ -16,13 +16,14 @@ namespace QGBA {
class ConfigController; class InputController; -class InputModel; +class InputIndex; +class ShortcutView; class SettingsView : public QDialog { Q_OBJECT public: - SettingsView(ConfigController* controller, InputController* inputController, InputModel* inputModel, QWidget* parent = nullptr); + SettingsView(ConfigController* controller, InputController* inputController, QWidget* parent = nullptr); signals: void biosLoaded(int platform, const QString&);@@ -41,6 +42,7 @@ Ui::SettingsView m_ui;
ConfigController* m_controller; InputController* m_input; + ShortcutView* m_shortcutView; void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QComboBox*);
@@ -15,9 +15,11 @@ using namespace QGBA;
ShortcutView::ShortcutView(QWidget* parent) : QWidget(parent) + , m_model() { m_ui.setupUi(this); m_ui.keyEdit->setValueKey(0); + m_ui.shortcutTable->setModel(&m_model); connect(m_ui.gamepadButton, &QAbstractButton::pressed, [this]() { bool signalsBlocked = m_ui.keyEdit->blockSignals(true);@@ -39,9 +41,8 @@ ShortcutView::~ShortcutView() {
m_input->releaseFocus(this); } -void ShortcutView::setModel(InputModel* model) { - m_controller = model; - m_ui.shortcutTable->setModel(model); +void ShortcutView::setModel(InputIndex* model) { + m_model.clone(*model); } void ShortcutView::setInputController(InputController* controller) {@@ -53,10 +54,10 @@ m_input->stealFocus(this);
} void ShortcutView::load(const QModelIndex& index) { - if (!m_controller) { + InputItem* item = m_model.itemAt(index); + if (!item) { return; } - InputItem* item = m_controller->itemAt(index); int shortcut = item->shortcut(); if (index.column() == 1) { m_ui.keyboardButton->click();@@ -74,11 +75,11 @@ m_ui.keyEdit->blockSignals(blockSignals);
} void ShortcutView::clear() { - if (!m_controller) { + QModelIndex index = m_ui.shortcutTable->selectionModel()->currentIndex(); + InputItem* item = m_model.itemAt(index); + if (!item) { return; } - QModelIndex index = m_ui.shortcutTable->selectionModel()->currentIndex(); - InputItem* item = m_controller->itemAt(index); if (m_ui.gamepadButton->isChecked()) { item->clearButton(); m_ui.keyEdit->setValueButton(-1);@@ -89,10 +90,10 @@ }
} void ShortcutView::updateButton(int button) { - if (!m_controller) { + InputItem* item = m_model.itemAt(m_ui.shortcutTable->selectionModel()->currentIndex()); + if (!item) { return; } - InputItem* item = m_controller->itemAt(m_ui.shortcutTable->selectionModel()->currentIndex()); if (m_ui.gamepadButton->isChecked()) { item->setButton(button); } else {@@ -101,10 +102,10 @@ }
} void ShortcutView::updateAxis(int axis, int direction) { - if (!m_controller) { + InputItem* item = m_model.itemAt(m_ui.shortcutTable->selectionModel()->currentIndex()); + if (!item) { return; } - InputItem* item = m_controller->itemAt(m_ui.shortcutTable->selectionModel()->currentIndex()); item->setAxis(axis, static_cast<GamepadAxisEvent::Direction>(direction)); }
@@ -7,6 +7,8 @@ #ifndef QGBA_SHORTCUT_VIEW
#define QGBA_SHORTCUT_VIEW #include "GamepadAxisEvent.h" +#include "InputIndex.h" +#include "InputModel.h" #include <QWidget>@@ -15,7 +17,6 @@
namespace QGBA { class InputController; -class InputModel; class ShortcutView : public QWidget { Q_OBJECT@@ -24,9 +25,11 @@ public:
ShortcutView(QWidget* parent = nullptr); ~ShortcutView(); - void setModel(InputModel* controller); + void setModel(InputIndex* model); void setInputController(InputController* input); + const InputItem* root() { return m_model.root(); } + protected: virtual bool event(QEvent*) override; virtual void closeEvent(QCloseEvent*) override;@@ -40,7 +43,7 @@
private: Ui::ShortcutView m_ui; - InputModel* m_controller = nullptr; + InputModel m_model; InputController* m_input = nullptr; };
@@ -69,8 +69,7 @@ : QMainWindow(parent)
, m_logView(new LogView(&m_log)) , m_screenWidget(new WindowBackground()) , m_config(config) - , m_inputModel(new InputModel(this)) - , m_inputController(m_inputModel, playerId, this) + , m_inputController(playerId, this) { setFocusPolicy(Qt::StrongFocus); setAcceptDrops(true);@@ -191,7 +190,6 @@ m_log.setLevels(mLOG_WARN | mLOG_ERROR | mLOG_FATAL);
m_fpsTimer.setInterval(FPS_TIMER_INTERVAL); m_focusCheck.setInterval(200); - m_inputModel->setConfigController(m_config); setupMenu(menuBar()); }@@ -456,7 +454,7 @@ }
} void Window::openSettingsWindow() { - SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController, m_inputModel); + SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController); connect(settingsWindow, &SettingsView::biosLoaded, m_controller, &GameController::loadBIOS); connect(settingsWindow, &SettingsView::audioDriverChanged, m_controller, &GameController::reloadAudioDriver); connect(settingsWindow, &SettingsView::displayDriverChanged, this, &Window::mustRestart);@@ -919,9 +917,10 @@ }
void Window::setupMenu(QMenuBar* menubar) { menubar->clear(); + installEventFilter(&m_inputController); + QMenu* fileMenu = menubar->addMenu(tr("&File")); - m_inputModel->addItem(fileMenu, "file"); - installEventFilter(&m_inputController); + m_inputController.inputIndex()->addItem(fileMenu, "file"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open), "loadROM"); #ifdef USE_SQLITE3@@ -976,8 +975,8 @@ addControlledAction(fileMenu, saveState, "saveState");
QMenu* quickLoadMenu = fileMenu->addMenu(tr("Quick load")); QMenu* quickSaveMenu = fileMenu->addMenu(tr("Quick save")); - m_inputModel->addItem(quickLoadMenu, "quickLoadMenu"); - m_inputModel->addItem(quickSaveMenu, "quickSaveMenu"); + m_inputController.inputIndex()->addItem(quickLoadMenu, "quickLoadMenu"); + m_inputController.inputIndex()->addItem(quickSaveMenu, "quickSaveMenu"); QAction* quickLoad = new QAction(tr("Load recent"), quickLoadMenu); connect(quickLoad, &QAction::triggered, m_controller, &GameController::loadState);@@ -1063,7 +1062,7 @@ addControlledAction(fileMenu, fileMenu->addAction(tr("E&xit"), this, SLOT(close()), QKeySequence::Quit), "quit");
#endif QMenu* emulationMenu = menubar->addMenu(tr("&Emulation")); - InputItem* emulationMenuItem = m_inputModel->addItem(emulationMenu, "emulation"); + InputItem* emulationMenuItem = m_inputController.inputIndex()->addItem(emulationMenu, "emulation"); QAction* reset = new QAction(tr("&Reset"), emulationMenu); reset->setShortcut(tr("Ctrl+R")); connect(reset, &QAction::triggered, m_controller, &GameController::reset);@@ -1169,7 +1168,7 @@
emulationMenu->addSeparator(); QMenu* solarMenu = emulationMenu->addMenu(tr("Solar sensor")); - m_inputModel->addItem(solarMenu, "luminance"); + m_inputController.inputIndex()->addItem(solarMenu, "luminance"); QAction* solarIncrease = new QAction(tr("Increase solar level"), solarMenu); connect(solarIncrease, &QAction::triggered, m_controller, &GameController::increaseLuminanceLevel); addControlledAction(solarMenu, solarIncrease, "increaseLuminanceLevel");@@ -1196,9 +1195,9 @@ addControlledAction(solarMenu, setSolar, QString("luminanceLevel.%1").arg(QString::number(i)));
} QMenu* avMenu = menubar->addMenu(tr("Audio/&Video")); - InputItem* avMenuItem = m_inputModel->addItem(avMenu, "av"); + InputItem* avMenuItem = m_inputController.inputIndex()->addItem(avMenu, "av"); QMenu* frameMenu = avMenu->addMenu(tr("Frame size")); - avMenuItem->addItem(frameMenu, "frameSize"); + InputItem* frameMenuItem = avMenuItem->addItem(frameMenu, "frameSize"); for (int i = 1; i <= 6; ++i) { QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu); setSize->setCheckable(true);@@ -1220,7 +1219,7 @@ setSize->setChecked(true);
setSize->blockSignals(enableSignals); }); m_frameSizes[i] = setSize; - addControlledAction(frameMenu, setSize, QString("frame%1x").arg(QString::number(i))); + addControlledAction(frameMenuItem, setSize, QString("frame%1x").arg(QString::number(i))); } QKeySequence fullscreenKeys; #ifdef Q_OS_WIN@@ -1228,7 +1227,7 @@ fullscreenKeys = QKeySequence("Alt+Return");
#else fullscreenKeys = QKeySequence("Ctrl+F"); #endif - addControlledAction(frameMenu, frameMenu->addAction(tr("Toggle fullscreen"), this, SLOT(toggleFullScreen()), fullscreenKeys), "fullscreen"); + addControlledAction(frameMenuItem, frameMenu->addAction(tr("Toggle fullscreen"), this, SLOT(toggleFullScreen()), fullscreenKeys), "fullscreen"); ConfigOption* lockAspectRatio = m_config->addOption("lockAspectRatio"); lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu);@@ -1339,7 +1338,7 @@ m_audioChannels = avMenu->addMenu(tr("Audio channels"));
avMenuItem->addItem(m_audioChannels, "audioChannels"); QMenu* toolsMenu = menubar->addMenu(tr("&Tools")); - m_inputModel->addItem(toolsMenu, "tools"); + m_inputController.inputIndex()->addItem(toolsMenu, "tools"); QAction* viewLogs = new QAction(tr("View &logs..."), toolsMenu); connect(viewLogs, &QAction::triggered, m_logView, &QWidget::show); addControlledAction(toolsMenu, viewLogs, "viewLogs");@@ -1476,10 +1475,10 @@
QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu); connect(exitFullScreen, &QAction::triggered, this, &Window::exitFullScreen); exitFullScreen->setShortcut(QKeySequence("Esc")); - addHiddenAction(frameMenu, exitFullScreen, "exitFullScreen"); + addHiddenAction(frameMenuItem, exitFullScreen, "exitFullScreen"); QMenu* autofireMenu = new QMenu(tr("Autofire"), this); - InputItem* autofireMenuItem = m_inputModel->addItem(autofireMenu, "autofire"); + InputItem* autofireMenuItem = m_inputController.inputIndex()->addItem(autofireMenu, "autofire"); autofireMenuItem->addItem(qMakePair([this]() { m_controller->setAutofire(GBA_KEY_A, true);@@ -1542,7 +1541,7 @@ m_controller->setAutofire(GBA_KEY_LEFT, false);
}), tr("Autofire Left"), "autofireLeft"); QMenu* bindingsMenu = new QMenu(tr("Bindings"), this); - InputItem* bindingsMenuItem = m_inputModel->addItem(bindingsMenu, "bindings"); + InputItem* bindingsMenuItem = m_inputController.inputIndex()->addItem(bindingsMenu, "bindings"); bindingsMenuItem->addItem(qMakePair([this]() { m_controller->keyPressed(GBA_KEY_A);@@ -1607,6 +1606,8 @@
for (QAction* action : m_gameActions) { action->setDisabled(true); } + + m_inputController.rebuildIndex(); } void Window::attachWidget(QWidget* widget) {@@ -1658,9 +1659,22 @@ menu->addAction(action);
return action; } +QAction* Window::addControlledAction(InputItem* parent, QAction* action, const QString& name) { + addHiddenAction(parent, action, name); + parent->menu()->addAction(action); + return action; +} + QAction* Window::addHiddenAction(QMenu* menu, QAction* action, const QString& name) { - InputItem* item = m_inputModel->itemForMenu(menu); - item->addItem(action, name); + InputItem* parent = m_inputController.inputIndex()->itemForMenu(menu); + parent->addItem(action, name); + action->setShortcutContext(Qt::WidgetShortcut); + addAction(action); + return action; +} + +QAction* Window::addHiddenAction(InputItem* parent, QAction* action, const QString& name) { + parent->addItem(action, name); action->setShortcutContext(Qt::WidgetShortcut); addAction(action); return action;
@@ -28,7 +28,6 @@ class Display;
class GameController; class GDBController; class GIFView; -class InputModel; class LibraryController; class LogView; class ShaderSelector;@@ -144,7 +143,9 @@ template <typename T, typename A> std::function<void()> openTView(A arg);
template <typename T> std::function<void()> openTView(); QAction* addControlledAction(QMenu* menu, QAction* action, const QString& name); + QAction* addControlledAction(InputItem* parent, QAction* action, const QString& name); QAction* addHiddenAction(QMenu* menu, QAction* action, const QString& name); + QAction* addHiddenAction(InputItem* parent, QAction* action, const QString& name); void updateTitle(float fps = -1);@@ -171,7 +172,6 @@ LoadSaveState* m_stateWindow = nullptr;
WindowBackground* m_screenWidget; QPixmap m_logo{":/res/mgba-1024.png"}; ConfigController* m_config; - InputModel* m_inputModel; InputController m_inputController; QList<QDateTime> m_frameList; QTimer m_fpsTimer;