This commit is contained in:
twinaphex 2015-07-28 04:48:49 +02:00
commit a94db33a8c
25 changed files with 395 additions and 142 deletions

View File

@ -63,6 +63,7 @@ Bugfixes:
- Qt: Fix window being too tall after exiting fullscreen
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
- GBA Cheats: Fix Pro Action Replay and GameShark issues when used together
- Qt: Fix analog buttons not getting unmapped
Misc:
- Qt: Handle saving input settings better
- Debugger: Free watchpoints in addition to breakpoints
@ -107,6 +108,7 @@ Misc:
- GBA: Savedata is now synced shortly after data finishes being written
- GBA Input: Allow axes and buttons to be mapped to the same key
- GBA BIOS: Stub out SoundBias
- Qt: Gamepads can now have both buttons and analog axes mapped to the same key
0.2.1: (2015-05-13)
Bugfixes:

View File

@ -785,7 +785,9 @@ void GBAFrameEnded(struct GBA* gba) {
gba->stream->postVideoFrame(gba->stream, gba->video.renderer);
}
GBAHardwarePlayerUpdate(gba);
if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) {
GBAHardwarePlayerUpdate(gba);
}
struct GBAThread* thread = GBAThreadGetContext();
if (!thread) {

View File

@ -44,6 +44,16 @@ static const int RTC_BYTES[8] = {
void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
hw->gpioBase = base;
GBAHardwareClear(hw);
hw->gbpCallback.d.readKeys = _gbpRead;
hw->gbpCallback.p = hw;
hw->gbpDriver.d.init = 0;
hw->gbpDriver.d.deinit = 0;
hw->gbpDriver.d.load = 0;
hw->gbpDriver.d.unload = 0;
hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister;
hw->gbpDriver.d.processEvents = _gbpSioProcessEvents;
hw->gbpDriver.p = hw;
}
void GBAHardwareClear(struct GBACartridgeHardware* hw) {
@ -518,15 +528,6 @@ void GBAHardwarePlayerUpdate(struct GBA* gba) {
}
if (GBAHardwarePlayerCheckScreen(&gba->video)) {
gba->memory.hw.devices |= HW_GB_PLAYER;
gba->memory.hw.gbpCallback.d.readKeys = _gbpRead;
gba->memory.hw.gbpCallback.p = &gba->memory.hw;
gba->memory.hw.gbpDriver.d.init = 0;
gba->memory.hw.gbpDriver.d.deinit = 0;
gba->memory.hw.gbpDriver.d.load = 0;
gba->memory.hw.gbpDriver.d.unload = 0;
gba->memory.hw.gbpDriver.d.writeRegister = _gbpSioWriteRegister;
gba->memory.hw.gbpDriver.d.processEvents = _gbpSioProcessEvents;
gba->memory.hw.gbpDriver.p = &gba->memory.hw;
gba->memory.hw.gbpInputsPosted = 0;
gba->memory.hw.gbpNextEvent = INT_MAX;
gba->keyCallback = &gba->memory.hw.gbpCallback.d;

View File

@ -34,7 +34,8 @@ enum GBAHardwareDevice {
HW_LIGHT_SENSOR = 4,
HW_GYRO = 8,
HW_TILT = 16,
HW_GB_PLAYER = 32
HW_GB_PLAYER = 32,
HW_GB_PLAYER_DETECTION = 64
};
enum GPIORegister {

View File

@ -352,6 +352,20 @@ enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key
return GBA_KEY_NONE;
}
int GBAInputMapKeyBits(const struct GBAInputMap* map, uint32_t type, uint32_t bits, unsigned offset) {
int keys = 0;
for (; bits; bits >>= 1, ++offset) {
if (bits & 1) {
enum GBAKey key = GBAInputMapKey(map, type, offset);
if (key == GBA_KEY_NONE) {
continue;
}
keys |= 1 << key;
}
}
return keys;
}
void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKey input) {
struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
GBAInputUnbindKey(map, type, input);
@ -366,7 +380,6 @@ void GBAInputUnbindKey(struct GBAInputMap* map, uint32_t type, enum GBAKey input
if (impl) {
impl->map[input] = GBA_NO_MAPPING;
}
TableEnumerate(&impl->axes, _unbindAxis, &input);
}
int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) {
@ -420,6 +433,8 @@ int GBAInputClearAxis(const struct GBAInputMap* map, uint32_t type, int axis, in
void GBAInputBindAxis(struct GBAInputMap* map, uint32_t type, int axis, const struct GBAAxis* description) {
struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
TableEnumerate(&impl->axes, _unbindAxis, &description->highDirection);
TableEnumerate(&impl->axes, _unbindAxis, &description->lowDirection);
struct GBAAxis* dup = malloc(sizeof(struct GBAAxis));
*dup = *description;
TableInsert(&impl->axes, axis, dup);

View File

@ -30,6 +30,7 @@ void GBAInputMapInit(struct GBAInputMap*);
void GBAInputMapDeinit(struct GBAInputMap*);
enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key);
int GBAInputMapKeyBits(const struct GBAInputMap* map, uint32_t type, uint32_t bits, unsigned offset);
void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input);
void GBAInputUnbindKey(struct GBAInputMap*, uint32_t type, enum GBAKey input);
int GBAInputQueryBinding(const struct GBAInputMap*, uint32_t type, enum GBAKey input);

View File

@ -116,13 +116,21 @@ bool GBAConfigLoad(struct GBAConfig* config) {
char path[PATH_MAX];
GBAConfigDirectory(path, PATH_MAX);
strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path));
return ConfigurationRead(&config->configTable, path);
return GBAConfigLoadPath(config, path);
}
bool GBAConfigSave(const struct GBAConfig* config) {
char path[PATH_MAX];
GBAConfigDirectory(path, PATH_MAX);
strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path));
return GBAConfigSavePath(config, path);
}
bool GBAConfigLoadPath(struct GBAConfig* config, const char* path) {
return ConfigurationRead(&config->configTable, path);
}
bool GBAConfigSavePath(const struct GBAConfig* config, const char* path) {
return ConfigurationWrite(&config->configTable, path);
}

View File

@ -51,6 +51,8 @@ void GBAConfigDeinit(struct GBAConfig*);
bool GBAConfigLoad(struct GBAConfig*);
bool GBAConfigSave(const struct GBAConfig*);
bool GBAConfigLoadPath(struct GBAConfig*, const char* path);
bool GBAConfigSavePath(const struct GBAConfig*, const char* path);
void GBAConfigMakePortable(const struct GBAConfig*);
void GBAConfigDirectory(char* out, size_t outLength);

View File

@ -285,6 +285,12 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri
if (override->hardware & HW_TILT) {
GBAHardwareInitTilt(&gba->memory.hw);
}
if (override->hardware & HW_GB_PLAYER_DETECTION) {
gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION;
} else {
gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION;
}
}
if (override->idleLoop != IDLE_LOOP_NONE) {
@ -294,3 +300,12 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri
}
}
}
void GBAOverrideApplyDefaults(struct GBA* gba) {
struct GBACartridgeOverride override;
const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
memcpy(override.id, &cart->id, sizeof(override.id));
if (GBAOverrideFind(0, &override)) {
GBAOverrideApply(gba, &override);
}
}

View File

@ -25,5 +25,6 @@ void GBAOverrideSave(struct Configuration*, const struct GBACartridgeOverride* o
struct GBA;
void GBAOverrideApply(struct GBA*, const struct GBACartridgeOverride*);
void GBAOverrideApplyDefaults(struct GBA*);
#endif

View File

@ -239,13 +239,7 @@ bool retro_load_game(const struct retro_game_info* game) {
save = VFileFromMemory(savedata, SIZE_CART_FLASH1M);
GBALoadROM(&gba, rom, save, game->path);
struct GBACartridgeOverride override;
const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom;
memcpy(override.id, &cart->id, sizeof(override.id));
if (GBAOverrideFind(0, &override)) {
GBAOverrideApply(&gba, &override);
}
GBAOverrideApplyDefaults(&gba);
ARMReset(&cpu);
return true;

View File

@ -6,6 +6,7 @@
#include "GBAKeyEditor.h"
#include <QComboBox>
#include <QHBoxLayout>
#include <QPaintEvent>
#include <QPainter>
#include <QPushButton>
@ -24,6 +25,7 @@ const qreal GBAKeyEditor::DPAD_HEIGHT = 0.1;
GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString& profile, QWidget* parent)
: QWidget(parent)
, m_profileSelect(nullptr)
, m_clear(nullptr)
, m_type(type)
, m_profile(profile)
, m_controller(controller)
@ -32,6 +34,7 @@ GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString&
setMinimumSize(300, 300);
const GBAInputMap* map = controller->map();
controller->stealFocus(this);
m_keyDU = new KeyEditor(this);
m_keyDD = new KeyEditor(this);
@ -64,31 +67,36 @@ GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString&
m_controller->loadProfile(m_type, m_profile);
refresh();
});
m_clear = new QWidget(this);
QHBoxLayout* layout = new QHBoxLayout;
m_clear->setLayout(layout);
layout->setSpacing(6);
QPushButton* clearButton = new QPushButton(tr("Clear Button"));
layout->addWidget(clearButton);
connect(clearButton, &QAbstractButton::pressed, [this]() {
if (!findFocus()) {
return;
}
bool signalsBlocked = (*m_currentKey)->blockSignals(true);
(*m_currentKey)->clearButton();
(*m_currentKey)->blockSignals(signalsBlocked);
});
QPushButton* clearAxis = new QPushButton(tr("Clear Analog"));
layout->addWidget(clearAxis);
connect(clearAxis, &QAbstractButton::pressed, [this]() {
if (!findFocus()) {
return;
}
bool signalsBlocked = (*m_currentKey)->blockSignals(true);
(*m_currentKey)->clearAxis();
(*m_currentKey)->blockSignals(signalsBlocked);
});
}
#endif
connect(m_keyDU, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyDD, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyDL, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyDR, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keySelect, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyStart, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyA, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyB, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyL, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyR, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(m_keyDU, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyDD, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyDL, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyDR, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keySelect, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyStart, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyA, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyB, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyL, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
connect(m_keyR, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
m_buttons = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout;
m_buttons->setLayout(layout);
@ -115,6 +123,11 @@ GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString&
m_keyR
};
for (auto& key : m_keyOrder) {
connect(key, SIGNAL(valueChanged(int)), this, SLOT(setNext()));
connect(key, SIGNAL(axisChanged(int, int)), this, SLOT(setNext()));
}
m_currentKey = m_keyOrder.end();
m_background.load(":/res/keymap.qpic");
@ -141,7 +154,11 @@ void GBAKeyEditor::resizeEvent(QResizeEvent* event) {
setLocation(m_keyR, 0.9, 0.1);
if (m_profileSelect) {
setLocation(m_profileSelect, 0.5, 0.7);
setLocation(m_profileSelect, 0.5, 0.67);
}
if (m_clear) {
setLocation(m_clear, 0.5, 0.77);
}
}
@ -151,6 +168,19 @@ void GBAKeyEditor::paintEvent(QPaintEvent* event) {
painter.drawPicture(0, 0, m_background);
}
void GBAKeyEditor::closeEvent(QCloseEvent*) {
m_controller->releaseFocus(this);
}
bool GBAKeyEditor::event(QEvent* event) {
if (event->type() == QEvent::WindowActivate) {
m_controller->stealFocus(this);
} else if (event->type() == QEvent::WindowDeactivate) {
m_controller->releaseFocus(this);
}
return QWidget::event(event);
}
void GBAKeyEditor::setNext() {
findFocus();
@ -167,6 +197,10 @@ void GBAKeyEditor::setNext() {
}
void GBAKeyEditor::save() {
#ifdef BUILD_SDL
m_controller->unbindAllAxes(m_type);
#endif
bindKey(m_keyDU, GBA_KEY_UP);
bindKey(m_keyDD, GBA_KEY_DOWN);
bindKey(m_keyDL, GBA_KEY_LEFT);
@ -239,14 +273,11 @@ void GBAKeyEditor::lookupAxes(const GBAInputMap* map) {
void GBAKeyEditor::bindKey(const KeyEditor* keyEditor, GBAKey key) {
#ifdef BUILD_SDL
if (keyEditor->direction() != GamepadAxisEvent::NEUTRAL) {
m_controller->bindAxis(m_type, keyEditor->value(), keyEditor->direction(), key);
} else {
#endif
m_controller->bindKey(m_type, keyEditor->value(), key);
#ifdef BUILD_SDL
if (m_type == SDL_BINDING_BUTTON) {
m_controller->bindAxis(m_type, keyEditor->axis(), keyEditor->direction(), key);
}
#endif
m_controller->bindKey(m_type, keyEditor->value(), key);
}
bool GBAKeyEditor::findFocus() {

View File

@ -35,6 +35,8 @@ public slots:
protected:
virtual void resizeEvent(QResizeEvent*) override;
virtual void paintEvent(QPaintEvent*) override;
virtual bool event(QEvent*) override;
virtual void closeEvent(QCloseEvent*) override;
private slots:
void setNext();
@ -64,6 +66,7 @@ private:
KeyEditor* keyById(GBAKey);
QComboBox* m_profileSelect;
QWidget* m_clear;
QWidget* m_buttons;
KeyEditor* m_keyDU;
KeyEditor* m_keyDD;

View File

@ -519,7 +519,9 @@ void GameController::startRewinding() {
return;
}
m_wasPaused = isPaused();
bool signalsBlocked = blockSignals(true);
setPaused(true);
blockSignals(signalsBlocked);
m_rewindTimer.start();
}
@ -528,7 +530,9 @@ void GameController::stopRewinding() {
return;
}
m_rewindTimer.stop();
bool signalsBlocked = blockSignals(true);
setPaused(m_wasPaused);
blockSignals(signalsBlocked);
}
void GameController::keyPressed(int key) {

View File

@ -35,6 +35,7 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
#endif
, m_allowOpposing(false)
, m_topLevel(topLevel)
, m_focusParent(topLevel)
{
GBAInputMapInit(&m_inputMap);
@ -412,6 +413,10 @@ void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direct
GBAInputBindAxis(&m_inputMap, type, axis, &description);
}
void InputController::unbindAllAxes(uint32_t type) {
GBAInputUnbindAllAxes(&m_inputMap, type);
}
void InputController::testGamepad(int type) {
auto activeAxes = activeGamepadAxes(type);
auto oldAxes = m_activeAxes;
@ -469,10 +474,10 @@ void InputController::testGamepad(int type) {
void InputController::sendGamepadEvent(QEvent* event) {
QWidget* focusWidget = nullptr;
if (m_topLevel) {
focusWidget = m_topLevel->focusWidget();
if (m_focusParent) {
focusWidget = m_focusParent->focusWidget();
if (!focusWidget) {
focusWidget = m_topLevel;
focusWidget = m_focusParent;
}
} else {
focusWidget = QApplication::focusWidget();
@ -505,3 +510,13 @@ void InputController::setScreensaverSuspendable(bool suspendable) {
GBASDLSetScreensaverSuspendable(&s_sdlEvents, suspendable);
}
#endif
void InputController::stealFocus(QWidget* focus) {
m_focusParent = focus;
}
void InputController::releaseFocus(QWidget* focus) {
if (focus == m_focusParent) {
m_focusParent = m_topLevel;
}
}

View File

@ -60,6 +60,7 @@ public:
void recalibrateAxes();
void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, GBAKey);
void unbindAllAxes(uint32_t type);
QStringList connectedGamepads(uint32_t type) const;
int gamepad(uint32_t type) const;
@ -74,6 +75,9 @@ public:
float gyroSensitivity() const;
void setGyroSensitivity(float sensitivity);
void stealFocus(QWidget* focus);
void releaseFocus(QWidget* focus);
GBARumble* rumble();
GBARotationSource* rotationSource();
@ -101,6 +105,7 @@ private:
int m_playerId;
bool m_allowOpposing;
QWidget* m_topLevel;
QWidget* m_focusParent;
#ifdef BUILD_SDL
static int s_sdlInited;

View File

@ -37,6 +37,31 @@ const InputProfile InputProfile::s_defaultMaps[] = {
{}
}
},
{
"(Microsoft X-Box 360 pad|Xbox Gamepad \\(userspace driver\\))", // Linux
(int[GBA_KEY_MAX]) {
/*keyA */ 1,
/*keyB */ 0,
/*keySelect */ 6,
/*keyStart */ 7,
/*keyRight */ -1,
/*keyLeft */ -1,
/*keyUp */ -1,
/*keyDown */ -1,
/*keyR */ 5,
/*keyL */ 4
},
(ShortcutButton[]) {
{"loadState", 2},
{"saveState", 3},
{}
},
(ShortcutAxis[]) {
{"holdFastForward", GamepadAxisEvent::Direction::POSITIVE, 5},
{"holdRewind", GamepadAxisEvent::Direction::POSITIVE, 2},
{}
}
},
{
"Controller", // The Xbox 360 controller drivers on OS X are vague...
(int[GBA_KEY_MAX]) {

View File

@ -15,22 +15,20 @@ using namespace QGBA;
KeyEditor::KeyEditor(QWidget* parent)
: QLineEdit(parent)
, m_direction(GamepadAxisEvent::NEUTRAL)
, m_key(-1)
, m_axis(-1)
, m_button(false)
{
setAlignment(Qt::AlignCenter);
}
void KeyEditor::setValue(int key) {
m_key = key;
if (m_button) {
if (key < 0) {
clear();
} else {
setText(QString::number(key));
}
updateButtonText();
} else {
setText(QKeySequence(key).toString(QKeySequence::NativeText));
}
m_key = key;
emit valueChanged(key);
}
@ -41,18 +39,30 @@ void KeyEditor::setValueKey(int key) {
void KeyEditor::setValueButton(int button) {
m_button = true;
m_direction = GamepadAxisEvent::NEUTRAL;
setValue(button);
}
void KeyEditor::setValueAxis(int axis, int32_t value) {
m_button = true;
m_key = axis;
m_axis = axis;
m_direction = value < 0 ? GamepadAxisEvent::NEGATIVE : GamepadAxisEvent::POSITIVE;
setText((value < 0 ? "-" : "+") + QString::number(axis));
updateButtonText();
emit axisChanged(axis, m_direction);
}
void KeyEditor::clearButton() {
m_button = true;
setValue(-1);
}
void KeyEditor::clearAxis() {
m_button = true;
m_axis = -1;
m_direction = GamepadAxisEvent::NEUTRAL;
updateButtonText();
emit axisChanged(m_axis, m_direction);
}
QSize KeyEditor::sizeHint() const {
QSize hint = QLineEdit::sizeHint();
hint.setWidth(40);
@ -85,3 +95,18 @@ bool KeyEditor::event(QEvent* event) {
}
return QWidget::event(event);
}
void KeyEditor::updateButtonText() {
QStringList text;
if (m_key >= 0) {
text.append(QString::number(m_key));
}
if (m_direction != GamepadAxisEvent::NEUTRAL) {
text.append((m_direction == GamepadAxisEvent::NEGATIVE ? "-" : "+") + QString::number(m_axis));
}
if (text.isEmpty()) {
setText(tr("---"));
} else {
setText(text.join("/"));
}
}

View File

@ -20,6 +20,7 @@ public:
int value() const { return m_key; }
GamepadAxisEvent::Direction direction() const { return m_direction; }
int axis() const { return m_axis; }
virtual QSize sizeHint() const override;
@ -28,6 +29,8 @@ public slots:
void setValueKey(int key);
void setValueButton(int button);
void setValueAxis(int axis, int32_t value);
void clearButton();
void clearAxis();
signals:
void valueChanged(int key);
@ -38,7 +41,10 @@ protected:
virtual bool event(QEvent* event) override;
private:
void updateButtonText();
int m_key;
int m_axis;
bool m_button;
GamepadAxisEvent::Direction m_direction;
};

View File

@ -39,6 +39,7 @@ OverrideView::OverrideView(GameController* controller, ConfigController* config,
connect(m_ui.hwLight, SIGNAL(clicked()), this, SLOT(updateOverrides()));
connect(m_ui.hwTilt, SIGNAL(clicked()), this, SLOT(updateOverrides()));
connect(m_ui.hwRumble, SIGNAL(clicked()), this, SLOT(updateOverrides()));
connect(m_ui.hwGBPlayer, SIGNAL(clicked()), this, SLOT(updateOverrides()));
connect(m_ui.save, SIGNAL(clicked()), this, SLOT(saveOverride()));
@ -80,6 +81,9 @@ void OverrideView::updateOverrides() {
m_override.hardware |= HW_RUMBLE;
}
}
if (m_ui.hwGBPlayer->isChecked()) {
m_override.hardware |= HW_GB_PLAYER_DETECTION;
}
bool ok;
uint32_t parsedIdleLoop = m_ui.idleLoop->text().toInt(&ok, 16);
@ -115,6 +119,7 @@ void OverrideView::gameStarted(GBAThread* thread) {
m_ui.hwLight->setChecked(thread->gba->memory.hw.devices & HW_LIGHT_SENSOR);
m_ui.hwTilt->setChecked(thread->gba->memory.hw.devices & HW_TILT);
m_ui.hwRumble->setChecked(thread->gba->memory.hw.devices & HW_RUMBLE);
m_ui.hwGBPlayer->setChecked(thread->gba->memory.hw.devices & HW_GB_PLAYER_DETECTION);
if (thread->gba->idleLoop != IDLE_LOOP_NONE) {
m_ui.idleLoop->setText(QString::number(thread->gba->idleLoop, 16));

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>409</width>
<height>228</height>
<width>401</width>
<height>203</height>
</rect>
</property>
<property name="sizePolicy">
@ -23,13 +23,19 @@
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item row="2" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
@ -44,7 +50,135 @@
</item>
</layout>
</item>
<item row="0" column="0" rowspan="3">
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Save type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="savetype">
<item>
<property name="text">
<string>Autodetect</string>
</property>
</item>
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>SRAM</string>
</property>
</item>
<item>
<property name="text">
<string>Flash 512kb</string>
</property>
</item>
<item>
<property name="text">
<string>Flash 1Mb</string>
</property>
</item>
<item>
<property name="text">
<string>EEPROM</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Idle loop</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="idleLoop"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="hwGBPlayer">
<property name="text">
<string>Game Boy Player features</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" rowspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string/>
@ -113,83 +247,6 @@
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string/>
</property>
<layout class="QFormLayout" name="formLayout_5">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Save type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="savetype">
<item>
<property name="text">
<string>Autodetect</string>
</property>
</item>
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>SRAM</string>
</property>
</item>
<item>
<property name="text">
<string>Flash 512kb</string>
</property>
</item>
<item>
<property name="text">
<string>Flash 1Mb</string>
</property>
</item>
<item>
<property name="text">
<string>EEPROM</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Idle loop</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="idleLoop"/>
</item>
<item row="1" column="1">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>

View File

@ -6,6 +6,7 @@
#include "ShortcutView.h"
#include "GamepadButtonEvent.h"
#include "InputController.h"
#include "ShortcutController.h"
#include <QKeyEvent>
@ -15,6 +16,7 @@ using namespace QGBA;
ShortcutView::ShortcutView(QWidget* parent)
: QWidget(parent)
, m_controller(nullptr)
, m_input(nullptr)
{
m_ui.setupUi(this);
m_ui.keyEdit->setValueButton(-1);
@ -32,6 +34,14 @@ void ShortcutView::setController(ShortcutController* controller) {
m_ui.shortcutTable->setModel(controller);
}
void ShortcutView::setInputController(InputController* controller) {
if (m_input) {
m_input->releaseFocus(this);
}
m_input = controller;
m_input->stealFocus(this);
}
bool ShortcutView::eventFilter(QObject*, QEvent* event) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
@ -111,3 +121,20 @@ void ShortcutView::updateAxis(int axis, int direction) {
m_controller->updateAxis(m_ui.shortcutTable->selectionModel()->currentIndex(), axis,
static_cast<GamepadAxisEvent::Direction>(direction));
}
void ShortcutView::closeEvent(QCloseEvent*) {
if (m_input) {
m_input->releaseFocus(this);
}
}
bool ShortcutView::event(QEvent* event) {
if (m_input) {
if (event->type() == QEvent::WindowActivate) {
m_input->stealFocus(this);
} else if (event->type() == QEvent::WindowDeactivate) {
m_input->releaseFocus(this);
}
}
return QWidget::event(event);
}

View File

@ -14,6 +14,7 @@
namespace QGBA {
class InputController;
class ShortcutController;
class ShortcutView : public QWidget {
@ -23,9 +24,12 @@ public:
ShortcutView(QWidget* parent = nullptr);
void setController(ShortcutController* controller);
void setInputController(InputController* input);
protected:
virtual bool eventFilter(QObject* obj, QEvent* event) override;
virtual bool event(QEvent*) override;
virtual void closeEvent(QCloseEvent*) override;
private slots:
void load(const QModelIndex&);
@ -38,6 +42,7 @@ private:
Ui::ShortcutView m_ui;
ShortcutController* m_controller;
InputController* m_input;
};
}

View File

@ -315,6 +315,7 @@ void Window::openShortcutWindow() {
#endif
ShortcutView* shortcutView = new ShortcutView();
shortcutView->setController(m_shortcutController);
shortcutView->setInputController(&m_inputController);
openView(shortcutView);
}

View File

@ -95,6 +95,7 @@ struct VDir* VDirOpen7z(const char* path, int flags) {
SzArEx_Init(&vd->db);
SRes res = SzArEx_Open(&vd->db, &vd->lookStream.s, &vd->allocImp, &vd->allocTempImp);
if (res != SZ_OK) {
File_Close(&vd->archiveStream.file);
free(vd);
return 0;
}
@ -115,6 +116,7 @@ struct VDir* VDirOpen7z(const char* path, int flags) {
bool _vf7zClose(struct VFile* vf) {
struct VFile7z* vf7z = (struct VFile7z*) vf;
IAlloc_Free(&vf7z->vd->allocImp, vf7z->outBuffer);
File_Close(&vf7z->vd->archiveStream.file);
return true;
}