Qt: Shortcut view now supports held events

This commit is contained in:
Jeffrey Pfau 2015-01-04 16:49:10 -08:00
parent a1480e2698
commit 811ad23e61
5 changed files with 135 additions and 13 deletions

View File

@ -8,6 +8,7 @@
#include "GamepadButtonEvent.h"
#include <QAction>
#include <QKeyEvent>
#include <QMenu>
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<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 @@ 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<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 @@ 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);
}
}

View File

@ -7,8 +7,12 @@
#define QGBA_SHORTCUT_MODEL
#include <QAbstractItemModel>
#include <QKeySequence>
#include <functional>
class QAction;
class QKeyEvent;
class QMenu;
class QString;
@ -20,11 +24,16 @@ Q_OBJECT
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 @@ 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<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;
};
}

View File

@ -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

View File

@ -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);
}

View File

@ -11,6 +11,8 @@
#include <QMainWindow>
#include <QTimer>
#include <functional>
extern "C" {
#include "gba.h"
}