all repos — mgba @ 811ad23e6175142fabaaee031ad3e6d58e2bb910

mGBA Game Boy Advance Emulator

Qt: Shortcut view now supports held events
Jeffrey Pfau jeffrey@endrift.com
Sun, 04 Jan 2015 16:49:10 -0800
commit

811ad23e6175142fabaaee031ad3e6d58e2bb910

parent

a1480e269807f977f523712856137a3408718bd3

M src/platform/qt/ShortcutController.cppsrc/platform/qt/ShortcutController.cpp

@@ -8,6 +8,7 @@

#include "GamepadButtonEvent.h" #include <QAction> +#include <QKeyEvent> #include <QMenu> using namespace QGBA;

@@ -28,10 +29,7 @@ switch (index.column()) {

case 0: return item->visibleName(); case 1: - if (item->action()) { - return item->action()->shortcut().toString(QKeySequence::NativeText); - } - break; + return item->shortcut().toString(QKeySequence::NativeText); case 2: if (item->button() >= 0) { return item->button();

@@ -104,6 +102,22 @@ ShortcutItem* item = &smenu->items().last();

emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); } +void ShortcutController::addFunctions(QMenu* menu, std::function<void ()> press, std::function<void ()> release, const QKeySequence& shortcut, const QString& visibleName, const QString& name) { + ShortcutItem* smenu = m_menuMap[menu]; + if (!smenu) { + return; + } + ShortcutItem* pmenu = smenu->parent(); + int row = pmenu->items().indexOf(*smenu); + QModelIndex parent = createIndex(row, 0, smenu); + beginInsertRows(parent, smenu->items().count(), smenu->items().count()); + smenu->addFunctions(qMakePair(press, release), shortcut, visibleName, name); + endInsertRows(); + ShortcutItem* item = &smenu->items().last(); + m_heldKeys[shortcut] = item; + emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); +} + void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) { ShortcutItem* smenu = m_menuMap[parentMenu]; if (!smenu) {

@@ -154,7 +168,14 @@ if (!parent.isValid()) {

return; } ShortcutItem* item = itemAt(index); - item->action()->setShortcut(keySequence); + if (item->functions().first) { + QKeySequence oldShortcut = item->shortcut(); + if (!oldShortcut.isEmpty()) { + m_heldKeys.take(oldShortcut); + } + m_heldKeys[keySequence] = item; + } + item->setShortcut(keySequence); emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer())); }

@@ -177,23 +198,82 @@ emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer()));

} bool ShortcutController::eventFilter(QObject*, QEvent* event) { + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); + if (keyEvent->isAutoRepeat()) { + return false; + } + auto item = m_heldKeys.find(keyEventToSequence(keyEvent)); + if (item == m_heldKeys.end()) { + return false; + } + ShortcutItem::Functions pair = item.value()->functions(); + if (event->type() == QEvent::KeyPress) { + if (pair.first) { + pair.first(); + } + } else { + if (pair.second) { + pair.second(); + } + } + event->accept(); + return true; + } if (event->type() == GamepadButtonEvent::Down()) { auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value()); if (item == m_buttons.end()) { return false; } QAction* action = item.value()->action(); - if (action->isEnabled()) { + if (action && action->isEnabled()) { action->trigger(); } + ShortcutItem::Functions pair = item.value()->functions(); + if (pair.first) { + pair.first(); + } + event->accept(); + return true; + } + if (event->type() == GamepadButtonEvent::Up()) { + auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value()); + if (item == m_buttons.end()) { + return false; + } + ShortcutItem::Functions pair = item.value()->functions(); + if (pair.second) { + pair.second(); + } event->accept(); return true; } return false; } +QKeySequence ShortcutController::keyEventToSequence(const QKeyEvent* event) { + QString modifier = QString::null; + + if (event->modifiers() & Qt::ShiftModifier) { + modifier += "Shift+"; + } + if (event->modifiers() & Qt::ControlModifier) { + modifier += "Ctrl+"; + } + if (event->modifiers() & Qt::AltModifier) { + modifier += "Alt+"; + } + if (event->modifiers() & Qt::MetaModifier) { + modifier += "Meta+"; + } + + QString key = QKeySequence(event->key()).toString(); + return QKeySequence(modifier + key); +} + ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent) : m_action(action) + , m_shortcut(action->shortcut()) , m_menu(nullptr) , m_name(name) , m_button(-1)

@@ -204,6 +284,18 @@ .remove(QRegExp("&(?!&)"))

.remove("..."); } +ShortcutController::ShortcutItem::ShortcutItem(ShortcutController::ShortcutItem::Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name, ShortcutItem* parent) + : m_action(nullptr) + , m_shortcut(shortcut) + , m_functions(functions) + , m_menu(nullptr) + , m_name(name) + , m_visibleName(visibleName) + , m_button(-1) + , m_parent(parent) +{ +} + ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent) : m_action(nullptr) , m_menu(menu)

@@ -221,6 +313,17 @@ void ShortcutController::ShortcutItem::addAction(QAction* action, const QString& name) {

m_items.append(ShortcutItem(action, name, this)); } +void ShortcutController::ShortcutItem::addFunctions(ShortcutController::ShortcutItem::Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name) { + m_items.append(ShortcutItem(functions, shortcut, visibleName, name, this)); +} + void ShortcutController::ShortcutItem::addSubmenu(QMenu* menu) { m_items.append(ShortcutItem(menu, this)); } + +void ShortcutController::ShortcutItem::setShortcut(const QKeySequence& shortcut) { + m_shortcut = shortcut; + if (m_action) { + m_action->setShortcut(shortcut); + } +}
M src/platform/qt/ShortcutController.hsrc/platform/qt/ShortcutController.h

@@ -7,8 +7,12 @@ #ifndef QGBA_SHORTCUT_MODEL

#define QGBA_SHORTCUT_MODEL #include <QAbstractItemModel> +#include <QKeySequence> + +#include <functional> class QAction; +class QKeyEvent; class QMenu; class QString;

@@ -20,11 +24,16 @@

private: class ShortcutItem { public: + typedef QPair<std::function<void ()>, std::function<void ()>> Functions; + ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent = nullptr); + ShortcutItem(Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name, ShortcutItem* parent = nullptr); ShortcutItem(QMenu* action, ShortcutItem* parent = nullptr); QAction* action() { return m_action; } const QAction* action() const { return m_action; } + const QKeySequence& shortcut() const { return m_shortcut; } + Functions functions() const { return m_functions; } QMenu* menu() { return m_menu; } const QMenu* menu() const { return m_menu; } const QString& visibleName() const { return m_visibleName; }

@@ -34,15 +43,19 @@ const QList<ShortcutItem>& items() const { return m_items; }

ShortcutItem* parent() { return m_parent; } const ShortcutItem* parent() const { return m_parent; } void addAction(QAction* action, const QString& name); + void addFunctions(Functions functions, const QKeySequence& shortcut, const QString& visibleName, const QString& name); void addSubmenu(QMenu* menu); int button() const { return m_button; } + void setShortcut(const QKeySequence& sequence); void setButton(int button) { m_button = button; } bool operator==(const ShortcutItem& other) const { return m_menu == other.m_menu && m_action == other.m_action; } private: QAction* m_action; + QKeySequence m_shortcut; QMenu* m_menu; + Functions m_functions; QString m_name; QString m_visibleName; int m_button;

@@ -63,6 +76,7 @@ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;

virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; void addAction(QMenu* menu, QAction* action, const QString& name); + void addFunctions(QMenu* menu, std::function<void ()> press, std::function<void()> release, const QKeySequence& shortcut, const QString& visibleName, const QString& name); void addMenu(QMenu* menu, QMenu* parent = nullptr); ShortcutItem* itemAt(const QModelIndex& index);

@@ -76,9 +90,11 @@ protected:

bool eventFilter(QObject*, QEvent*) override; private: + static QKeySequence keyEventToSequence(const QKeyEvent*); ShortcutItem m_rootMenu; QMap<QMenu*, ShortcutItem*> m_menuMap; QMap<int, ShortcutItem*> m_buttons; + QMap<QKeySequence, ShortcutItem*> m_heldKeys; }; }
M src/platform/qt/ShortcutView.hsrc/platform/qt/ShortcutView.h

@@ -15,7 +15,6 @@

class InputController; class ShortcutController; -// TODO: suspend shortcuts (keyboard and gamepad) while window is open class ShortcutView : public QWidget { Q_OBJECT
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -278,9 +278,6 @@ if (event->isAutoRepeat()) {

QWidget::keyPressEvent(event); return; } - if (event->key() == Qt::Key_Tab) { - m_controller->setTurbo(true, false); - } GBAKey key = m_inputController.mapKeyboard(event->key()); if (key == GBA_KEY_NONE) { QWidget::keyPressEvent(event);

@@ -294,9 +291,6 @@ void Window::keyReleaseEvent(QKeyEvent* event) {

if (event->isAutoRepeat()) { QWidget::keyReleaseEvent(event); return; - } - if (event->key() == Qt::Key_Tab) { - m_controller->setTurbo(false, false); } GBAKey key = m_inputController.mapKeyboard(event->key()); if (key == GBA_KEY_NONE) {

@@ -646,6 +640,14 @@ #endif

ConfigOption* skipBios = m_config->addOption("skipBios"); skipBios->connect([this](const QVariant& value) { m_controller->setSkipBIOS(value.toBool()); }); + + QMenu* other = new QMenu(tr("Other"), this); + m_shortcutController->addMenu(other); + m_shortcutController->addFunctions(other, [this]() { + m_controller->setTurbo(true, false); + }, [this]() { + m_controller->setTurbo(false, false); + }, QKeySequence(Qt::Key_Tab), tr("Fast Forward (held)"), "holdFastForward"); foreach (QAction* action, m_gameActions) { action->setDisabled(true);
M src/platform/qt/Window.hsrc/platform/qt/Window.h

@@ -11,6 +11,8 @@ #include <QList>

#include <QMainWindow> #include <QTimer> +#include <functional> + extern "C" { #include "gba.h" }