mirror of https://github.com/mgba-emu/mgba.git
Qt: Shortcut view now supports held events
This commit is contained in:
parent
a1480e2698
commit
811ad23e61
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
|
||||
#include <functional>
|
||||
|
||||
extern "C" {
|
||||
#include "gba.h"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue