all repos — mgba @ 33c4b179415269bb31f45b1875ff307b2b434448

mGBA Game Boy Advance Emulator

Qt: Add GamepadButtonEvent and remove signal associated; use this for button controls in emulator
Jeffrey Pfau jeffrey@endrift.com
Sun, 04 Jan 2015 04:23:20 -0800
commit

33c4b179415269bb31f45b1875ff307b2b434448

parent

53c586044d76775bb0226a6c92ca61f0c1844467

M src/platform/qt/CMakeLists.txtsrc/platform/qt/CMakeLists.txt

@@ -44,6 +44,7 @@ GBAKeyEditor.cpp

GIFView.cpp GameController.cpp GamePakView.cpp + GamepadButtonEvent.cpp InputController.cpp KeyEditor.cpp LoadSaveState.cpp
M src/platform/qt/GBAKeyEditor.cppsrc/platform/qt/GBAKeyEditor.cpp

@@ -112,7 +112,6 @@ setAll->setFocus();

#ifdef BUILD_SDL if (type == SDL_BINDING_BUTTON) { - connect(m_controller, SIGNAL(buttonPressed(int)), this, SLOT(setButton(int))); connect(m_controller, SIGNAL(axisChanged(int, int32_t)), this, SLOT(setAxisValue(int, int32_t))); } #endif

@@ -236,14 +235,6 @@ return;

} KeyEditor* focused = *m_currentKey; focused->setValueAxis(axis, value); -} - -void GBAKeyEditor::setButton(int button) { - if (!findFocus()) { - return; - } - KeyEditor* focused = *m_currentKey; - focused->setValueButton(button); } #endif
M src/platform/qt/GBAKeyEditor.hsrc/platform/qt/GBAKeyEditor.h

@@ -40,7 +40,6 @@ void setNext();

void save(); #ifdef BUILD_SDL void setAxisValue(int axis, int32_t value); - void setButton(int button); #endif private:
A src/platform/qt/GamepadButtonEvent.cpp

@@ -0,0 +1,41 @@

+/* Copyright (c) 2013-2015 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 "GamepadButtonEvent.h" + +#include "InputController.h" + +using namespace QGBA; + +QEvent::Type GamepadButtonEvent::s_downType = QEvent::None; +QEvent::Type GamepadButtonEvent::s_upType = QEvent::None; + +GamepadButtonEvent::GamepadButtonEvent(QEvent::Type type, int button, InputController* controller) + : QEvent(type) + , m_button(button) + , m_controller(controller) + , m_key(GBA_KEY_NONE) +{ + ignore(); +#ifdef BUILD_SDL + if (controller) { + m_key = GBAInputMapKey(controller->map(), SDL_BINDING_BUTTON, button); + } +#endif +} + +QEvent::Type GamepadButtonEvent::Down() { + if (s_downType == None) { + s_downType = static_cast<Type>(registerEventType()); + } + return s_downType; +} + +QEvent::Type GamepadButtonEvent::Up() { + if (s_upType == None) { + s_upType = static_cast<Type>(registerEventType()); + } + return s_upType; +}
A src/platform/qt/GamepadButtonEvent.h

@@ -0,0 +1,40 @@

+/* Copyright (c) 2013-2015 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_GAMEPAD_BUTTON_EVENT +#define QGBA_GAMEPAD_BUTTON_EVENT + +#include <QEvent> + +extern "C" { +#include "gba-input.h" +} + +namespace QGBA { + +class InputController; + +class GamepadButtonEvent : public QEvent { +public: + GamepadButtonEvent(Type type, int button, InputController* controller = nullptr); + + int value() const { return m_button; } + GBAKey gbaKey() const { return m_key; } + + static Type Down(); + static Type Up(); + +private: + static Type s_downType; + static Type s_upType; + + int m_button; + InputController* m_controller; + GBAKey m_key; +}; + +} + +#endif
M src/platform/qt/InputController.cppsrc/platform/qt/InputController.cpp

@@ -6,8 +6,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "InputController.h" #include "ConfigController.h" +#include "GamepadButtonEvent.h" +#include <QApplication> #include <QTimer> +#include <QWidget> extern "C" { #include "util/configuration.h"

@@ -89,6 +92,9 @@ int i;

for (i = 0; i < numButtons; ++i) { GBAKey key = GBAInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i); if (key == GBA_KEY_NONE) { + continue; + } + if (hasPendingEvent(key)) { continue; } if (SDL_JoystickGetButton(joystick, i)) {

@@ -191,10 +197,29 @@ m_activeButtons = activeButtons;

activeButtons.subtract(oldButtons); oldButtons.subtract(m_activeButtons); for (int button : activeButtons) { - emit buttonPressed(button); + GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Down(), button, this); + postPendingEvent(event->gbaKey()); + QApplication::sendEvent(QApplication::focusWidget(), event); + if (!event->isAccepted()) { + clearPendingEvent(event->gbaKey()); + } } for (int button : oldButtons) { - emit buttonReleased(button); + GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Up(), button, this); + clearPendingEvent(event->gbaKey()); + QApplication::sendEvent(QApplication::focusWidget(), event); } #endif } + +void InputController::postPendingEvent(GBAKey key) { + m_pendingEvents.insert(key); +} + +void InputController::clearPendingEvent(GBAKey key) { + m_pendingEvents.remove(key); +} + +bool InputController::hasPendingEvent(GBAKey key) const { + return m_pendingEvents.contains(key); +}
M src/platform/qt/InputController.hsrc/platform/qt/InputController.h

@@ -59,13 +59,15 @@ #endif

signals: void axisChanged(int axis, int32_t value); - void buttonPressed(int button); - void buttonReleased(int button); public slots: void testGamepad(); private: + void postPendingEvent(GBAKey); + void clearPendingEvent(GBAKey); + bool hasPendingEvent(GBAKey) const; + GBAInputMap m_inputMap; ConfigController* m_config;

@@ -76,6 +78,8 @@

QSet<int> m_activeButtons; QSet<QPair<int, int32_t>> m_activeAxes; QTimer* m_gamepadTimer; + + QSet<GBAKey> m_pendingEvents; }; }
M src/platform/qt/KeyEditor.cppsrc/platform/qt/KeyEditor.cpp

@@ -5,6 +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 "KeyEditor.h" +#include "GamepadButtonEvent.h" + #include <QKeyEvent> using namespace QGBA;

@@ -56,3 +58,15 @@ setValue(event->key());

} event->accept(); } + +bool KeyEditor::event(QEvent* event) { + if (!m_button) { + return QWidget::event(event); + } + if (event->type() == GamepadButtonEvent::Down()) { + setValueButton(static_cast<GamepadButtonEvent*>(event)->value()); + event->accept(); + return true; + } + return QWidget::event(event); +}
M src/platform/qt/KeyEditor.hsrc/platform/qt/KeyEditor.h

@@ -35,6 +35,7 @@ void axisChanged(int key, int direction);

protected: virtual void keyPressEvent(QKeyEvent* event) override; + virtual bool event(QEvent* event) override; private: int m_key;
M src/platform/qt/LoadSaveState.cppsrc/platform/qt/LoadSaveState.cpp

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "LoadSaveState.h" #include "GameController.h" +#include "GamepadButtonEvent.h" #include "VFileDevice.h" #include <QKeyEvent>

@@ -103,6 +104,40 @@ m_slots[m_currentFocus]->setFocus();

return true; } } + } + if (event->type() == GamepadButtonEvent::Down()) { + int column = m_currentFocus % 3; + int row = m_currentFocus - column; + switch (static_cast<GamepadButtonEvent*>(event)->gbaKey()) { + case GBA_KEY_UP: + row += 6; + break; + case GBA_KEY_DOWN: + row += 3; + break; + case GBA_KEY_LEFT: + column += 2; + break; + case GBA_KEY_RIGHT: + column += 1; + break; + case GBA_KEY_B: + close(); + break; + case GBA_KEY_A: + case GBA_KEY_START: + event->accept(); + triggerState(m_currentFocus + 1); + return true; + default: + return false; + } + column %= 3; + row %= 9; + m_currentFocus = column + row; + m_slots[m_currentFocus]->setFocus(); + event->accept(); + return true; } return false; }
M src/platform/qt/LoadSaveState.hsrc/platform/qt/LoadSaveState.h

@@ -13,6 +13,7 @@

namespace QGBA { class GameController; +class InputController; class SavestateButton; enum class LoadSave {

@@ -28,6 +29,7 @@ const static int NUM_SLOTS = 9;

LoadSaveState(GameController* controller, QWidget* parent = nullptr); + void setInputController(InputController* controller); void setMode(LoadSave mode); signals:

@@ -45,6 +47,7 @@ void triggerState(int slot);

Ui::LoadSaveState m_ui; GameController* m_controller; + InputController* m_inputController; SavestateButton* m_slots[NUM_SLOTS]; LoadSave m_mode;
M src/platform/qt/ShortcutController.cppsrc/platform/qt/ShortcutController.cpp

@@ -5,6 +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 "ShortcutController.h" +#include "GamepadButtonEvent.h" + #include <QAction> #include <QMenu>

@@ -166,16 +168,20 @@ m_buttons[button] = &item;

emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId())); } -void ShortcutController::pressButton(int button) { - auto item = m_buttons.find(button); - if (item == m_buttons.end()) { - return; - } - QAction* action = item.value()->action(); - if (!action->isEnabled()) { - return; +bool ShortcutController::eventFilter(QObject*, QEvent* event) { + 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()) { + action->trigger(); + } + event->accept(); + return true; } - action->trigger(); + return false; } ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name)
M src/platform/qt/ShortcutController.hsrc/platform/qt/ShortcutController.h

@@ -36,8 +36,8 @@ const QAction* actionAt(const QModelIndex& index) const;

void updateKey(const QModelIndex& index, const QKeySequence& keySequence); void updateButton(const QModelIndex& index, int button); -private slots: - void pressButton(int button); +protected: + bool eventFilter(QObject*, QEvent*) override; private: class ShortcutItem {
M src/platform/qt/ShortcutView.cppsrc/platform/qt/ShortcutView.cpp

@@ -5,6 +5,7 @@ * 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 "ShortcutView.h" +#include "GamepadButtonEvent.h" #include "ShortcutController.h" using namespace QGBA;

@@ -15,10 +16,11 @@ , m_controller(nullptr)

, m_inputController(nullptr) { m_ui.setupUi(this); + m_ui.keyEdit->setValueButton(-1); connect(m_ui.keySequenceEdit, SIGNAL(editingFinished()), this, SLOT(updateKey())); connect(m_ui.keyEdit, SIGNAL(valueChanged(int)), this, SLOT(updateButton(int))); - connect(m_ui.shortcutTable, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(loadKey(const QModelIndex&))); + connect(m_ui.shortcutTable, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(load(const QModelIndex&))); } void ShortcutView::setController(ShortcutController* controller) {

@@ -28,11 +30,19 @@ }

void ShortcutView::setInputController(InputController* controller) { m_inputController = controller; - connect(controller, SIGNAL(buttonPressed(int)), m_ui.keyEdit, SLOT(setValueButton(int))); connect(controller, SIGNAL(axisChanged(int, int32_t)), m_ui.keyEdit, SLOT(setValueAxis(int, int32_t))); } -void ShortcutView::loadKey(const QModelIndex& index) { +bool ShortcutView::event(QEvent* event) { + if (event->type() == GamepadButtonEvent::Down()) { + updateButton(static_cast<GamepadButtonEvent*>(event)->value()); + event->accept(); + return true; + } + return QWidget::event(event); +} + +void ShortcutView::load(const QModelIndex& index) { if (!m_controller) { return; }

@@ -40,8 +50,11 @@ const QAction* action = m_controller->actionAt(index);

if (!action) { return; } - m_ui.keySequenceEdit->setFocus(); - m_ui.keySequenceEdit->setKeySequence(action->shortcut()); + if (m_ui.gamepadButton->isChecked()) { + loadButton(); + } else { + loadKey(action); + } } void ShortcutView::updateKey() {

@@ -59,3 +72,12 @@ }

m_controller->updateButton(m_ui.shortcutTable->selectionModel()->currentIndex(), button); } +void ShortcutView::loadKey(const QAction* action) { + m_ui.keySequenceEdit->setFocus(); + m_ui.keySequenceEdit->setKeySequence(action->shortcut()); +} + +void ShortcutView::loadButton() { + m_ui.keyEdit->setFocus(); + m_ui.keyEdit->setValueButton(-1); // TODO: Real value +}
M src/platform/qt/ShortcutView.hsrc/platform/qt/ShortcutView.h

@@ -25,12 +25,18 @@

void setController(ShortcutController* controller); void setInputController(InputController* controller); +protected: + virtual bool event(QEvent* event) override; + private slots: - void loadKey(const QModelIndex&); + void load(const QModelIndex&); void updateKey(); void updateButton(int button); private: + void loadKey(const QAction*); + void loadButton(); + Ui::ShortcutView m_ui; ShortcutController* m_controller;
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -93,8 +93,6 @@ connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int)));

connect(this, SIGNAL(fpsTargetChanged(float)), m_controller, SLOT(setFPSTarget(float))); connect(&m_fpsTimer, SIGNAL(timeout()), this, SLOT(showFPS())); - connect(&m_inputController, SIGNAL(buttonPressed(int)), m_shortcutController, SLOT(pressButton(int))); - m_logView->setLevels(GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL); m_fpsTimer.setInterval(FPS_TIMER_INTERVAL);

@@ -431,6 +429,7 @@ void Window::setupMenu(QMenuBar* menubar) {

menubar->clear(); QMenu* fileMenu = menubar->addMenu(tr("&File")); m_shortcutController->addMenu(fileMenu); + installEventFilter(m_shortcutController); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open), "loadROM"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &patch..."), this, SLOT(selectPatch())), "loadPatch");