From 811ad23e6175142fabaaee031ad3e6d58e2bb910 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 4 Jan 2015 16:49:10 -0800 Subject: [PATCH] Qt: Shortcut view now supports held events --- src/platform/qt/ShortcutController.cpp | 115 +++++++++++++++++++++++-- src/platform/qt/ShortcutController.h | 16 ++++ src/platform/qt/ShortcutView.h | 1 - src/platform/qt/Window.cpp | 14 +-- src/platform/qt/Window.h | 2 + 5 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/platform/qt/ShortcutController.cpp b/src/platform/qt/ShortcutController.cpp index 443835ebd..8172aebb1 100644 --- a/src/platform/qt/ShortcutController.cpp +++ b/src/platform/qt/ShortcutController.cpp @@ -8,6 +8,7 @@ #include "GamepadButtonEvent.h" #include +#include #include using namespace QGBA; @@ -28,10 +29,7 @@ QVariant ShortcutController::data(const QModelIndex& index, int role) const { 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 @@ void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); } +void ShortcutController::addFunctions(QMenu* menu, std::function press, std::function 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 @@ void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& 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 @@ void ShortcutController::updateButton(const QModelIndex& index, int button) { } bool ShortcutController::eventFilter(QObject*, QEvent* event) { + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + QKeyEvent* keyEvent = static_cast(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(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(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 @@ ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& n .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& 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); + } +} diff --git a/src/platform/qt/ShortcutController.h b/src/platform/qt/ShortcutController.h index 37ce7e2dc..f854abab9 100644 --- a/src/platform/qt/ShortcutController.h +++ b/src/platform/qt/ShortcutController.h @@ -7,8 +7,12 @@ #define QGBA_SHORTCUT_MODEL #include +#include + +#include class QAction; +class QKeyEvent; class QMenu; class QString; @@ -20,11 +24,16 @@ Q_OBJECT private: class ShortcutItem { public: + typedef QPair, std::function> 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 @@ private: 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 @@ public: virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; void addAction(QMenu* menu, QAction* action, const QString& name); + void addFunctions(QMenu* menu, std::function press, std::function 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 m_menuMap; QMap m_buttons; + QMap m_heldKeys; }; } diff --git a/src/platform/qt/ShortcutView.h b/src/platform/qt/ShortcutView.h index 0c52584a6..7526a5dda 100644 --- a/src/platform/qt/ShortcutView.h +++ b/src/platform/qt/ShortcutView.h @@ -15,7 +15,6 @@ namespace QGBA { class InputController; class ShortcutController; -// TODO: suspend shortcuts (keyboard and gamepad) while window is open class ShortcutView : public QWidget { Q_OBJECT diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 30be394f7..3115dc7cd 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -278,9 +278,6 @@ void Window::keyPressEvent(QKeyEvent* event) { 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); @@ -295,9 +292,6 @@ void Window::keyReleaseEvent(QKeyEvent* event) { 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) { QWidget::keyPressEvent(event); @@ -647,6 +641,14 @@ void Window::setupMenu(QMenuBar* menubar) { 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); } diff --git a/src/platform/qt/Window.h b/src/platform/qt/Window.h index b123eab03..bfe732c78 100644 --- a/src/platform/qt/Window.h +++ b/src/platform/qt/Window.h @@ -11,6 +11,8 @@ #include #include +#include + extern "C" { #include "gba.h" }