Qt: Add keyboard remapper

This commit is contained in:
Jeffrey Pfau 2014-11-07 03:11:44 -08:00
parent 0efe988161
commit 81e65c08d8
14 changed files with 473 additions and 0 deletions

BIN
res/keymap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

136
res/keymap.svg Normal file
View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="480px" height="480px" viewBox="0 0 480 480" enable-background="new 0 0 480 480" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="239.9995" y1="0" x2="239.9995" y2="480.0005">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M480,450c0,16.5684-13.4316,30-30,30H30c-16.5684,0-30-13.4316-30-30V30C0,13.4316,13.4316,0,30,0
h420c16.5684,0,30,13.4316,30,30V450z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="239.9995" y1="-479" x2="239.9994" y2="1159.0004">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M30,473c-12.6821,0-23-10.3174-23-23V30C7,17.3179,17.3179,7,30,7h420c12.6826,0,23,10.3179,23,23
v420c0,12.6826-10.3174,23-23,23H30z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="118.3335" y1="291.667" x2="118.3335" y2="47.9991">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M118.3335,122.333c-46.7603,0-84.667,37.9067-84.667,84.667c0,46.7607,37.9067,84.667,84.667,84.667
s84.667-37.9062,84.667-84.667C203.0005,160.2397,165.0938,122.333,118.3335,122.333z M118.334,278.7344
c-39.6172,0-71.7339-32.1172-71.7339-71.7344c0-39.6177,32.1167-71.7339,71.7339-71.7339S190.0679,167.3823,190.0679,207
C190.0679,246.6172,157.9512,278.7344,118.334,278.7344z"/>
<g>
<radialGradient id="SVGID_4_" cx="118.8335" cy="138.167" r="103.2725" fx="165.1467" fy="138.167" gradientTransform="matrix(-4.371139e-08 1 -1.42 -6.206884e-08 315.0264 19.3335)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#9C9CB3"/>
<stop offset="1" style="stop-color:#333045"/>
</radialGradient>
<path fill="url(#SVGID_4_)" d="M172.1973,207c0-9.667-3.0029-17.333-3.0029-17.333H135.667v-33.5283
c0,0-7.667-3.0029-17.3335-3.0029s-17.333,3.0029-17.333,3.0029v33.5283H67.4727c0,0-3.0029,7.666-3.0029,17.333
c0,9.666,3.0029,17.333,3.0029,17.333h33.5278v33.5273c0,0,7.6665,3.0039,17.333,3.0039s17.3335-3.0039,17.3335-3.0039V224.333
h33.5273C169.1943,224.333,172.1973,216.666,172.1973,207z"/>
<path fill="#5C567D" d="M118.3335,258.8643c-6.9185,0-12.833-1.625-15.333-2.4287V222.333h-34.103
c-0.8027-2.5-2.4277-8.4146-2.4277-15.333s1.6245-12.833,2.4277-15.333h34.103v-34.1035c2.5-0.8027,8.4146-2.4277,15.333-2.4277
c6.9453,0,12.8408,1.6226,15.3335,2.4258v34.1055h34.1025c0.8032,2.5,2.4277,8.4146,2.4277,15.333
c0,6.9448-1.6226,12.8403-2.4258,15.333H133.667v34.1025C131.167,257.2393,125.252,258.8643,118.3335,258.8643z"/>
<radialGradient id="SVGID_5_" cx="118.333" cy="220.397" r="69.7522" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#706F8A"/>
<stop offset="0.9951" style="stop-color:#2D2842"/>
</radialGradient>
<circle fill="url(#SVGID_5_)" cx="118.333" cy="207" r="21.2749"/>
</g>
<g>
<g>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="198.9673" y1="490" x2="198.9673" y2="384.981">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_6_)" d="M198.9678,387.0303c-18.8418,0-34.1162,15.2734-34.1162,34.1162
c0,18.8418,15.2744,34.1152,34.1162,34.1152c18.8408,0,34.1152-15.2734,34.1152-34.1152
C233.083,402.3037,217.8086,387.0303,198.9678,387.0303z M198.9678,445.7871c-13.6089,0-24.6401-11.0332-24.6401-24.6406
c0-13.6094,11.0312-24.6406,24.6401-24.6406c13.6074,0,24.6396,11.0312,24.6396,24.6406
C223.6074,434.7539,212.5752,445.7871,198.9678,445.7871z"/>
<g>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="198.9673" y1="437.4414" x2="198.9673" y2="404.8516">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<circle fill="url(#SVGID_7_)" cx="198.9673" cy="421.1465" r="16.2949"/>
<circle fill="#5C567D" cx="198.9673" cy="421.1465" r="15.0737"/>
</g>
</g>
<g>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="281.0312" y1="490" x2="281.0312" y2="384.981">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_8_)" d="M281.0322,387.0303c-18.8418,0-34.1162,15.2734-34.1162,34.1162
c0,18.8418,15.2744,34.1152,34.1162,34.1152c18.8408,0,34.1152-15.2734,34.1152-34.1152
C315.1475,402.3037,299.873,387.0303,281.0322,387.0303z M281.0322,445.7871c-13.6084,0-24.6396-11.0332-24.6396-24.6406
c0-13.6094,11.0312-24.6406,24.6396-24.6406c13.6074,0,24.6396,11.0312,24.6396,24.6406
C305.6719,434.7539,294.6396,445.7871,281.0322,445.7871z"/>
<g>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="281.0322" y1="437.4414" x2="281.0322" y2="404.8516">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<circle fill="url(#SVGID_9_)" cx="281.0322" cy="421.1465" r="16.2949"/>
<circle fill="#5C567D" cx="281.0317" cy="421.1465" r="15.0737"/>
</g>
</g>
</g>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="356.1787" y1="280.2178" x2="356.1787" y2="134.9952">
<stop offset="0" style="stop-color:#7A65F5"/>
<stop offset="1" style="stop-color:#302575"/>
</linearGradient>
<path fill="url(#SVGID_10_)" d="M437.9521,179.5503c-7.0088-23.9434-32.0986-37.6724-56.043-30.6646l-76.8369,22.4912
c-23.9453,7.0073-37.6748,32.0991-30.666,56.043c7.0088,23.9443,32.0996,37.6719,56.0449,30.6621l76.8369-22.4902
C431.2314,228.585,444.96,203.4946,437.9521,179.5503z M426.3311,209.6025c-4.6377,8.4756-12.2979,14.6382-21.5703,17.3516
l-76.8379,22.4902c-3.3301,0.9746-6.7559,1.4688-10.1816,1.4688c-0.001,0-0.001,0-0.002,0
c-15.9443-0.001-30.2109-10.7012-34.6953-26.0215c-2.7148-9.2729-1.6553-19.0479,2.9824-27.5244
c4.6387-8.4761,12.2998-14.6387,21.5732-17.3525l76.8379-22.4912c3.3281-0.9741,6.7539-1.4683,10.1807-1.4683
c15.9434,0,30.2109,10.7012,34.6963,26.0234C432.0283,191.3516,430.9688,201.1265,426.3311,209.6025z"/>
<g>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="395.9062" y1="217.8188" x2="395.9062" y2="166.6519">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<circle fill="url(#SVGID_11_)" cx="395.9062" cy="192.2358" r="25.584"/>
<circle fill="#5C567D" cx="395.9072" cy="192.2358" r="23.666"/>
</g>
<g>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="318.9785" y1="239.6406" x2="318.9785" y2="188.4722">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<circle fill="url(#SVGID_12_)" cx="318.979" cy="214.0571" r="25.5835"/>
<circle fill="#5C567D" cx="318.98" cy="214.0571" r="23.6665"/>
</g>
<g>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="-15.0425" y1="77.9346" x2="55.6245" y2="-5.3989">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<path fill="url(#SVGID_13_)" d="M33.6665,0H61.5c2.9697,1.0112,2.3306,7,2.3306,7l0.0581,8.4844
C63.8887,31.3535,48.9922,50,27.9922,50H7.0068c0,0-5.2197,2.312-7.0068-8.0029V30C0,11.5,12.333,0,33.6665,0z"/>
<path fill="#5C567D" d="M9.7783,49.1743c-0.2793-0.251-1.166-1.2764-1.7744-4.5308V33.0029c0-16.5234,10.813-26,29.6665-26h26.0854
c0.1318,0.709,0.1821,1.7549,0.0996,2.5908L63.835,9.8032l0.0576,8.7114c0,14.3774-13.6406,30.4883-31.8965,30.4883H10.1646
L9.7783,49.1743z"/>
</g>
<g>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="401.0615" y1="77.9336" x2="471.7285" y2="-5.3999" gradientTransform="matrix(-1 0 0 1 896.1055 0)">
<stop offset="0" style="stop-color:#333045"/>
<stop offset="1" style="stop-color:#9C9CB3"/>
</linearGradient>
<path fill="url(#SVGID_14_)" d="M446.334,0h-27.833c-2.9697,1.0112-2.3311,7-2.3311,7l-0.0576,8.4844
C416.1123,31.3535,431.0088,50,452.0088,50h20.9854c0,0,5.2197,2.312,7.0068-8.0029V30C480.001,11.5,467.668,0,446.334,0z"/>
<path fill="#5C567D" d="M470.2227,49.1743c0.2793-0.251,1.166-1.2764,1.7744-4.5308V33.0029c0-16.5234-10.8135-26-29.667-26
h-26.085c-0.1318,0.709-0.1826,1.7549-0.0996,2.5908l0.0205,0.2095l-0.0576,8.7114c0,14.3774,13.6406,30.4883,31.8965,30.4883
h21.8311L470.2227,49.1743z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -109,6 +109,27 @@ void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKe
impl->map[input] = key;
}
int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) {
if (input >= GBA_KEY_MAX) {
return 0;
}
size_t m;
const struct GBAInputMapImpl* impl = 0;
for (m = 0; m < map->numMaps; ++m) {
if (map->maps[m].type == type) {
impl = &map->maps[m];
break;
}
}
if (!impl || !impl->map) {
return 0;
}
return impl->map[input];
}
void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) {
_loadKey(map, type, config, GBA_KEY_A, "A");
_loadKey(map, type, config, GBA_KEY_B, "B");

View File

@ -15,6 +15,7 @@ void GBAInputMapDeinit(struct GBAInputMap*);
enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key);
void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input);
int GBAInputQueryBinding(const struct GBAInputMap*, uint32_t type, enum GBAKey input);
void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*);

View File

@ -34,8 +34,10 @@ set(SOURCE_FILES
ConfigController.cpp
Display.cpp
GBAApp.cpp
GBAKeyEditor.cpp
GameController.cpp
InputController.cpp
KeyEditor.cpp
LoadSaveState.cpp
LogView.cpp
SavestateButton.cpp

View File

@ -0,0 +1,171 @@
#include "GBAKeyEditor.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPicture>
#include <QPushButton>
#include "InputController.h"
#include "KeyEditor.h"
extern "C" {
#include "gba-input.h"
}
using namespace QGBA;
const qreal GBAKeyEditor::DPAD_CENTER_X = 0.247;
const qreal GBAKeyEditor::DPAD_CENTER_Y = 0.431;
const qreal GBAKeyEditor::DPAD_WIDTH = 0.1;
const qreal GBAKeyEditor::DPAD_HEIGHT = 0.1;
GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, QWidget* parent)
: QWidget(parent)
, m_background(QString(":/res/keymap.png"))
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);
setMinimumSize(300, 300);
const GBAInputMap* map = controller->map();
m_keyDU = new KeyEditor(this);
m_keyDD = new KeyEditor(this);
m_keyDL = new KeyEditor(this);
m_keyDR = new KeyEditor(this);
m_keySelect = new KeyEditor(this);
m_keyStart = new KeyEditor(this);
m_keyA = new KeyEditor(this);
m_keyB = new KeyEditor(this);
m_keyL = new KeyEditor(this);
m_keyR = new KeyEditor(this);
m_keyDU->setValue(GBAInputQueryBinding(map, type, GBA_KEY_UP));
m_keyDD->setValue(GBAInputQueryBinding(map, type, GBA_KEY_DOWN));
m_keyDL->setValue(GBAInputQueryBinding(map, type, GBA_KEY_LEFT));
m_keyDR->setValue(GBAInputQueryBinding(map, type, GBA_KEY_RIGHT));
m_keySelect->setValue(GBAInputQueryBinding(map, type, GBA_KEY_SELECT));
m_keyStart->setValue(GBAInputQueryBinding(map, type, GBA_KEY_START));
m_keyA->setValue(GBAInputQueryBinding(map, type, GBA_KEY_A));
m_keyB->setValue(GBAInputQueryBinding(map, type, GBA_KEY_B));
m_keyL->setValue(GBAInputQueryBinding(map, type, GBA_KEY_L));
m_keyR->setValue(GBAInputQueryBinding(map, type, GBA_KEY_R));
connect(m_keyDU, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_UP);
setNext();
});
connect(m_keyDD, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_DOWN);
setNext();
});
connect(m_keyDL, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_LEFT);
setNext();
});
connect(m_keyDR, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_RIGHT);
setNext();
});
connect(m_keySelect, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_SELECT);
setNext();
});
connect(m_keyStart, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_START);
setNext();
});
connect(m_keyA, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_A);
setNext();
});
connect(m_keyB, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_B);
setNext();
});
connect(m_keyL, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_L);
setNext();
});
connect(m_keyR, &KeyEditor::valueChanged, [this, type, controller](int key) {
controller->bindKey(type, key, GBA_KEY_R);
setNext();
});
m_setAll = new QPushButton(tr("Set all"), this);
connect(m_setAll, SIGNAL(pressed()), this, SLOT(setAll()));
m_keyOrder = QList<KeyEditor*>{
m_keyDU,
m_keyDR,
m_keyDD,
m_keyDL,
m_keyA,
m_keyB,
m_keySelect,
m_keyStart,
m_keyL,
m_keyR
};
m_currentKey = m_keyOrder.end();
QPixmap background(":/res/keymap.png");
m_background = background.scaled(QSize(300, 300) * devicePixelRatio(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_background.setDevicePixelRatio(devicePixelRatio());
}
void GBAKeyEditor::setAll() {
m_currentKey = m_keyOrder.begin();
(*m_currentKey)->setFocus();
}
void GBAKeyEditor::resizeEvent(QResizeEvent* event) {
setLocation(m_setAll, 0.5, 0.2);
setLocation(m_keyDU, DPAD_CENTER_X, DPAD_CENTER_Y - DPAD_HEIGHT);
setLocation(m_keyDD, DPAD_CENTER_X, DPAD_CENTER_Y + DPAD_HEIGHT);
setLocation(m_keyDL, DPAD_CENTER_X - DPAD_WIDTH, DPAD_CENTER_Y);
setLocation(m_keyDR, DPAD_CENTER_X + DPAD_WIDTH, DPAD_CENTER_Y);
setLocation(m_keySelect, 0.415, 0.93);
setLocation(m_keyStart, 0.585, 0.93);
setLocation(m_keyA, 0.826, 0.451);
setLocation(m_keyB, 0.667, 0.490);
setLocation(m_keyL, 0.1, 0.1);
setLocation(m_keyR, 0.9, 0.1);
}
void GBAKeyEditor::paintEvent(QPaintEvent* event) {
QPainter painter(this);
painter.drawPixmap(0, 0, m_background);
}
void GBAKeyEditor::setNext() {
if (m_currentKey == m_keyOrder.end()) {
return;
}
if (!(*m_currentKey)->hasFocus()) {
m_currentKey = m_keyOrder.end();
}
++m_currentKey;
if (m_currentKey != m_keyOrder.end()) {
(*m_currentKey)->setFocus();
} else {
(*(m_currentKey - 1))->clearFocus();
}
}
void GBAKeyEditor::setLocation(QWidget* widget, qreal x, qreal y) {
QSize s = size();
QSize hint = widget->sizeHint();
widget->setGeometry(s.width() * x - hint.width() / 2.0, s.height() * y - hint.height() / 2.0, hint.width(), hint.height());
}

View File

@ -0,0 +1,59 @@
#ifndef QGBA_GBA_KEY_EDITOR
#define QGBA_GBA_KEY_EDITOR
#include <QList>
#include <QPixmap>
#include <QWidget>
class QPushButton;
namespace QGBA {
class InputController;
class KeyEditor;
class GBAKeyEditor : public QWidget {
Q_OBJECT
public:
GBAKeyEditor(InputController* controller, int type, QWidget* parent = nullptr);
public slots:
void setAll();
protected:
virtual void resizeEvent(QResizeEvent*) override;
virtual void paintEvent(QPaintEvent*) override;
private:
static const qreal DPAD_CENTER_X;
static const qreal DPAD_CENTER_Y;
static const qreal DPAD_WIDTH;
static const qreal DPAD_HEIGHT;
void setNext();
void setLocation(QWidget* widget, qreal x, qreal y);
QPushButton* m_setAll;
KeyEditor* m_keyDU;
KeyEditor* m_keyDD;
KeyEditor* m_keyDL;
KeyEditor* m_keyDR;
KeyEditor* m_keySelect;
KeyEditor* m_keyStart;
KeyEditor* m_keyA;
KeyEditor* m_keyB;
KeyEditor* m_keyL;
KeyEditor* m_keyR;
QList<KeyEditor*> m_keyOrder;
QList<KeyEditor*>::iterator m_currentKey;
InputController* m_controller;
QPixmap m_background;
};
}
#endif

View File

@ -52,6 +52,10 @@ GBAKey InputController::mapKeyboard(int key) const {
return GBAInputMapKey(&m_inputMap, KEYBOARD, key);
}
void InputController::bindKey(uint32_t type, int key, GBAKey gbaKey) {
return GBAInputBindKey(&m_inputMap, type, key, gbaKey);
}
#ifdef BUILD_SDL
int InputController::testSDLEvents() {
SDL_Joystick* joystick = m_sdlEvents.joystick;

View File

@ -25,6 +25,10 @@ public:
GBAKey mapKeyboard(int key) const;
void bindKey(uint32_t type, int key, GBAKey);
const GBAInputMap* map() const { return &m_inputMap; }
#ifdef BUILD_SDL
int testSDLEvents();
#endif

View File

@ -0,0 +1,28 @@
#include "KeyEditor.h"
#include <QKeyEvent>
using namespace QGBA;
KeyEditor::KeyEditor(QWidget* parent)
: QLineEdit(parent)
{
setAlignment(Qt::AlignCenter);
}
void KeyEditor::setValue(int key) {
setText(QKeySequence(key).toString(QKeySequence::NativeText));
m_key = key;
emit valueChanged(key);
}
QSize KeyEditor::sizeHint() const {
QSize hint = QLineEdit::sizeHint();
hint.setWidth(40);
return hint;
}
void KeyEditor::keyPressEvent(QKeyEvent* event) {
setValue(event->key());
event->accept();
}

View File

@ -0,0 +1,31 @@
#ifndef QGBA_KEY_EDITOR
#define QGBA_KEY_EDITOR
#include <QLineEdit>
namespace QGBA {
class KeyEditor : public QLineEdit {
Q_OBJECT
public:
KeyEditor(QWidget* parent = nullptr);
void setValue(int key);
int value() const { return m_key; }
virtual QSize sizeHint() const override;
signals:
void valueChanged(int key);
protected:
virtual void keyPressEvent(QKeyEvent* event) override;
private:
int m_key;
};
}
#endif

View File

@ -8,6 +8,7 @@
#include "ConfigController.h"
#include "GameController.h"
#include "GBAKeyEditor.h"
#include "GDBController.h"
#include "GDBWindow.h"
#include "LoadSaveState.h"
@ -136,6 +137,13 @@ void Window::selectPatch() {
}
}
void Window::openKeymapWindow() {
GBAKeyEditor* keyEditor = new GBAKeyEditor(&m_inputController, InputController::KEYBOARD);
connect(this, SIGNAL(shutdown()), keyEditor, SLOT(close()));
keyEditor->setAttribute(Qt::WA_DeleteOnClose);
keyEditor->show();
}
#ifdef USE_FFMPEG
void Window::openVideoWindow() {
if (!m_videoView) {
@ -395,6 +403,11 @@ void Window::setupMenu(QMenuBar* menubar) {
audioSync->connect([this](const QVariant& value) { m_controller->setAudioSync(value.toBool()); });
m_config->updateOption("audioSync");
emulationMenu->addSeparator();
QAction* keymap = new QAction(tr("Remap keyboard..."), emulationMenu);
connect(keymap, SIGNAL(triggered()), this, SLOT(openKeymapWindow()));
emulationMenu->addAction(keymap);
QMenu* videoMenu = menubar->addMenu(tr("&Video"));
QMenu* frameMenu = videoMenu->addMenu(tr("Frame size"));
QAction* setSize = new QAction(tr("1x"), videoMenu);

View File

@ -50,6 +50,8 @@ public slots:
void loadConfig();
void saveConfig();
void openKeymapWindow();
#ifdef USE_FFMPEG
void openVideoWindow();
#endif

View File

@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>../../../res/mgba-1024.png</file>
<file>../../../res/keymap.png</file>
</qresource>
</RCC>