mirror of
https://github.com/libretro/mgba.git
synced 2024-11-27 10:11:00 +00:00
This commit is contained in:
commit
a94db33a8c
2
CHANGES
2
CHANGES
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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]) {
|
||||
|
@ -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("/"));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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));
|
||||
|
@ -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/>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -315,6 +315,7 @@ void Window::openShortcutWindow() {
|
||||
#endif
|
||||
ShortcutView* shortcutView = new ShortcutView();
|
||||
shortcutView->setController(m_shortcutController);
|
||||
shortcutView->setInputController(&m_inputController);
|
||||
openView(shortcutView);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user