Qt: Refactor to make non-SDL gamepad input possible

This commit is contained in:
Jeffrey Pfau 2015-04-27 01:40:00 -07:00
parent 6ebef8dc16
commit 711c7e9903
8 changed files with 205 additions and 164 deletions

View File

@ -96,10 +96,8 @@ GameController::GameController(QObject* parent)
controller->m_audioProcessor->setInput(context);
context->gba->luminanceSource = &controller->m_lux;
context->gba->rtcSource = &controller->m_rtc;
#ifdef BUILD_SDL
context->gba->rumble = controller->m_inputController->rumble();
context->gba->rotationSource = controller->m_inputController->rotationSource();
#endif
controller->gameStarted(context);
};
@ -154,10 +152,7 @@ GameController::GameController(QObject* parent)
connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause()));
connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start()));
#ifdef BUILD_SDL
connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
#endif
connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(pollEvents()));
}
GameController::~GameController() {
@ -283,9 +278,7 @@ void GameController::openGame() {
m_threadContext.patch = VFileOpen(m_patch.toLocal8Bit().constData(), O_RDONLY);
}
#ifdef BUILD_SDL
m_inputController->recalibrateAxes();
#endif
if (!GBAThreadStart(&m_threadContext)) {
m_gameOpen = false;
@ -663,9 +656,7 @@ void GameController::setFakeEpoch(const QDateTime& time) {
void GameController::updateKeys() {
int activeKeys = m_activeKeys;
#ifdef BUILD_SDL
activeKeys |= m_activeButtons;
#endif
activeKeys &= ~m_inactiveKeys;
m_threadContext.activeKeys = activeKeys;
}
@ -705,13 +696,11 @@ void GameController::disableLogLevel(int levels) {
threadContinue();
}
#ifdef BUILD_SDL
void GameController::testSDLEvents() {
void GameController::pollEvents() {
if (!m_inputController) {
return;
}
m_activeButtons = m_inputController->testSDLEvents();
m_activeButtons = m_inputController->pollEvents();
updateKeys();
}
#endif

View File

@ -146,13 +146,7 @@ public slots:
private slots:
void crashGame(const QString& crashMessage);
#ifdef BUILD_SDL
void testSDLEvents();
private:
GBASDLEvents m_sdlEvents;
int m_activeButtons;
#endif
void pollEvents();
private:
void updateKeys();
@ -163,6 +157,7 @@ private:
GBAVideoSoftwareRenderer* m_renderer;
GBACheatDevice m_cheatDevice;
int m_activeKeys;
int m_activeButtons;
int m_inactiveKeys;
int m_logLevels;

View File

@ -11,7 +11,7 @@ using namespace QGBA;
QEvent::Type GamepadAxisEvent::s_type = QEvent::None;
GamepadAxisEvent::GamepadAxisEvent(int axis, Direction direction, bool isNew, InputController* controller)
GamepadAxisEvent::GamepadAxisEvent(int axis, Direction direction, bool isNew, int type, InputController* controller)
: QEvent(Type())
, m_axis(axis)
, m_direction(direction)
@ -20,11 +20,9 @@ GamepadAxisEvent::GamepadAxisEvent(int axis, Direction direction, bool isNew, In
, m_key(GBA_KEY_NONE)
{
ignore();
#ifdef BUILD_SDL
if (controller) {
m_key = GBAInputMapAxis(controller->map(), SDL_BINDING_BUTTON, axis, direction * INT_MAX);
m_key = GBAInputMapAxis(controller->map(), type, axis, direction * INT_MAX);
}
#endif
}
QEvent::Type GamepadAxisEvent::Type() {

View File

@ -24,7 +24,7 @@ public:
NEGATIVE = -1
};
GamepadAxisEvent(int axis, Direction direction, bool isNew, InputController* controller = nullptr);
GamepadAxisEvent(int axis, Direction direction, bool isNew, int type, InputController* controller = nullptr);
int axis() const { return m_axis; }
Direction direction() const { return m_direction; }

View File

@ -12,18 +12,16 @@ 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)
GamepadButtonEvent::GamepadButtonEvent(QEvent::Type pressType, int button, int type, InputController* controller)
: QEvent(pressType)
, 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);
m_key = GBAInputMapKey(controller->map(), type, button);
}
#endif
}
QEvent::Type GamepadButtonEvent::Down() {

View File

@ -18,7 +18,7 @@ class InputController;
class GamepadButtonEvent : public QEvent {
public:
GamepadButtonEvent(Type type, int button, InputController* controller = nullptr);
GamepadButtonEvent(Type pressType, int button, int type, InputController* controller = nullptr);
int value() const { return m_button; }
GBAKey gbaKey() const { return m_key; }

View File

@ -43,12 +43,16 @@ InputController::InputController(int playerId, QObject* parent)
++s_sdlInited;
m_sdlPlayer.bindings = &m_inputMap;
GBASDLInitBindings(&m_inputMap);
#endif
m_gamepadTimer = new QTimer(this);
connect(m_gamepadTimer, SIGNAL(timeout()), this, SLOT(testGamepad()));
#ifdef BUILD_SDL
connect(m_gamepadTimer, &QTimer::timeout, [this]() {
testGamepad(SDL_BINDING_BUTTON);
});
#endif
m_gamepadTimer->setInterval(50);
m_gamepadTimer->start();
#endif
GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A);
GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B);
@ -103,9 +107,7 @@ void InputController::loadConfiguration(uint32_t type) {
void InputController::loadProfile(uint32_t type, const QString& profile) {
GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toLocal8Bit().constData());
#ifdef BUILD_SDL
recalibrateAxes();
#endif
}
void InputController::saveConfiguration() {
@ -144,74 +146,122 @@ const char* InputController::profileForType(uint32_t type) {
return 0;
}
#ifdef BUILD_SDL
QStringList InputController::connectedGamepads(uint32_t type) const {
UNUSED(type);
if (type != SDL_BINDING_BUTTON) {
return QStringList();
}
QStringList pads;
for (size_t i = 0; i < s_sdlEvents.nJoysticks; ++i) {
const char* name;
#ifdef BUILD_SDL
if (type == SDL_BINDING_BUTTON) {
QStringList pads;
for (size_t i = 0; i < s_sdlEvents.nJoysticks; ++i) {
const char* name;
#if SDL_VERSION_ATLEAST(2, 0, 0)
name = SDL_JoystickName(s_sdlEvents.joysticks[i]);
name = SDL_JoystickName(s_sdlEvents.joysticks[i]);
#else
name = SDL_JoystickName(SDL_JoystickIndex(s_sdlEvents.joysticks[i]));
name = SDL_JoystickName(SDL_JoystickIndex(s_sdlEvents.joysticks[i]));
#endif
if (name) {
pads.append(QString(name));
} else {
pads.append(QString());
if (name) {
pads.append(QString(name));
} else {
pads.append(QString());
}
}
return pads;
}
return pads;
#endif
return QStringList();
}
int InputController::gamepad(uint32_t type) const {
#ifdef BUILD_SDL
if (type == SDL_BINDING_BUTTON) {
return m_sdlPlayer.joystickIndex;
}
#endif
return 0;
}
void InputController::setGamepad(uint32_t type, int index) {
#ifdef BUILD_SDL
if (type == SDL_BINDING_BUTTON) {
GBASDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index);
}
#endif
}
void InputController::setPreferredGamepad(uint32_t type, const QString& device) {
if (!m_config) {
return;
}
GBAInputSetPreferredDevice(m_config->input(), type, m_sdlPlayer.playerId, device.toLocal8Bit().constData());
GBAInputSetPreferredDevice(m_config->input(), type, m_playerId, device.toLocal8Bit().constData());
}
GBARumble* InputController::rumble() {
return &m_sdlPlayer.rumble.d;
#ifdef BUILD_SDL
if (m_playerAttached) {
return &m_sdlPlayer.rumble.d;
}
#endif
return nullptr;
}
GBARotationSource* InputController::rotationSource() {
return &m_sdlPlayer.rotation.d;
#ifdef BUILD_SDL
if (m_playerAttached) {
return &m_sdlPlayer.rotation.d;
}
#endif
return nullptr;
}
void InputController::registerTiltAxisX(int axis) {
m_sdlPlayer.rotation.axisX = axis;
#ifdef BUILD_SDL
if (m_playerAttached) {
m_sdlPlayer.rotation.axisX = axis;
}
#endif
}
void InputController::registerTiltAxisY(int axis) {
m_sdlPlayer.rotation.axisY = axis;
#ifdef BUILD_SDL
if (m_playerAttached) {
m_sdlPlayer.rotation.axisY = axis;
}
#endif
}
void InputController::registerGyroAxisX(int axis) {
m_sdlPlayer.rotation.gyroX = axis;
#ifdef BUILD_SDL
if (m_playerAttached) {
m_sdlPlayer.rotation.gyroX = axis;
}
#endif
}
void InputController::registerGyroAxisY(int axis) {
m_sdlPlayer.rotation.gyroY = axis;
#ifdef BUILD_SDL
if (m_playerAttached) {
m_sdlPlayer.rotation.gyroY = axis;
}
#endif
}
float InputController::gyroSensitivity() const {
return m_sdlPlayer.rotation.gyroSensitivity;
#ifdef BUILD_SDL
if (m_playerAttached) {
return m_sdlPlayer.rotation.gyroSensitivity;
}
#endif
return 0;
}
void InputController::setGyroSensitivity(float sensitivity) {
m_sdlPlayer.rotation.gyroSensitivity = sensitivity;
}
#else
GBARumble* InputController::rumble() {
return nullptr;
}
GBARotationSource* InputController::rotationSource() {
return nullptr;
}
#ifdef BUILD_SDL
if (m_playerAttached) {
m_sdlPlayer.rotation.gyroSensitivity = sensitivity;
}
#endif
}
GBAKey InputController::mapKeyboard(int key) const {
return GBAInputMapKey(&m_inputMap, KEYBOARD, key);
@ -221,104 +271,119 @@ 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_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
int InputController::pollEvents() {
int activeButtons = 0;
int i;
for (i = 0; i < numButtons; ++i) {
GBAKey key = GBAInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i);
if (key == GBA_KEY_NONE) {
continue;
#ifdef BUILD_SDL
if (m_playerAttached) {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
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)) {
activeButtons |= 1 << key;
}
}
if (hasPendingEvent(key)) {
continue;
int numHats = SDL_JoystickNumHats(joystick);
for (i = 0; i < numHats; ++i) {
int hat = SDL_JoystickGetHat(joystick, i);
if (hat & SDL_HAT_UP) {
activeButtons |= 1 << GBA_KEY_UP;
}
if (hat & SDL_HAT_LEFT) {
activeButtons |= 1 << GBA_KEY_LEFT;
}
if (hat & SDL_HAT_DOWN) {
activeButtons |= 1 << GBA_KEY_DOWN;
}
if (hat & SDL_HAT_RIGHT) {
activeButtons |= 1 << GBA_KEY_RIGHT;
}
}
if (SDL_JoystickGetButton(joystick, i)) {
activeButtons |= 1 << key;
}
}
int numHats = SDL_JoystickNumHats(joystick);
for (i = 0; i < numHats; ++i) {
int hat = SDL_JoystickGetHat(joystick, i);
if (hat & SDL_HAT_UP) {
activeButtons |= 1 << GBA_KEY_UP;
}
if (hat & SDL_HAT_LEFT) {
activeButtons |= 1 << GBA_KEY_LEFT;
}
if (hat & SDL_HAT_DOWN) {
activeButtons |= 1 << GBA_KEY_DOWN;
}
if (hat & SDL_HAT_RIGHT) {
activeButtons |= 1 << GBA_KEY_RIGHT;
}
}
int numAxes = SDL_JoystickNumAxes(joystick);
for (i = 0; i < numAxes; ++i) {
int value = SDL_JoystickGetAxis(joystick, i);
int numAxes = SDL_JoystickNumAxes(joystick);
for (i = 0; i < numAxes; ++i) {
int value = SDL_JoystickGetAxis(joystick, i);
enum GBAKey key = GBAInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value);
if (key != GBA_KEY_NONE) {
activeButtons |= 1 << key;
enum GBAKey key = GBAInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value);
if (key != GBA_KEY_NONE) {
activeButtons |= 1 << key;
}
}
}
#endif
return activeButtons;
}
QSet<int> InputController::activeGamepadButtons() {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
QSet<int> InputController::activeGamepadButtons(int type) {
QSet<int> activeButtons;
int i;
for (i = 0; i < numButtons; ++i) {
if (SDL_JoystickGetButton(joystick, i)) {
activeButtons.insert(i);
#ifdef BUILD_SDL
if (m_playerAttached && type == SDL_BINDING_BUTTON) {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numButtons = SDL_JoystickNumButtons(joystick);
int i;
for (i = 0; i < numButtons; ++i) {
if (SDL_JoystickGetButton(joystick, i)) {
activeButtons.insert(i);
}
}
}
#endif
return activeButtons;
}
void InputController::recalibrateAxes() {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numAxes = SDL_JoystickNumAxes(joystick);
if (numAxes < 1) {
return;
}
m_deadzones.resize(numAxes);
int i;
for (i = 0; i < numAxes; ++i) {
m_deadzones[i] = SDL_JoystickGetAxis(joystick, i);
}
}
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes() {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numAxes = SDL_JoystickNumAxes(joystick);
QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;
if (numAxes < 1) {
return activeAxes;
}
m_deadzones.resize(numAxes);
int i;
for (i = 0; i < numAxes; ++i) {
int32_t axis = SDL_JoystickGetAxis(joystick, i);
axis -= m_deadzones[i];
if (axis >= AXIS_THRESHOLD || axis <= -AXIS_THRESHOLD) {
activeAxes.insert(qMakePair(i, axis > 0 ? GamepadAxisEvent::POSITIVE : GamepadAxisEvent::NEGATIVE));
#ifdef BUILD_SDL
if (m_playerAttached) {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numAxes = SDL_JoystickNumAxes(joystick);
if (numAxes < 1) {
return;
}
m_deadzones.resize(numAxes);
int i;
for (i = 0; i < numAxes; ++i) {
m_deadzones[i] = SDL_JoystickGetAxis(joystick, i);
}
}
#endif
}
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes(int type) {
QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;
#ifdef BUILD_SDL
if (m_playerAttached && type == SDL_BINDING_BUTTON) {
SDL_Joystick* joystick = m_sdlPlayer.joystick;
SDL_JoystickUpdate();
int numAxes = SDL_JoystickNumAxes(joystick);
if (numAxes < 1) {
return activeAxes;
}
m_deadzones.resize(numAxes);
int i;
for (i = 0; i < numAxes; ++i) {
int32_t axis = SDL_JoystickGetAxis(joystick, i);
axis -= m_deadzones[i];
if (axis >= AXIS_THRESHOLD || axis <= -AXIS_THRESHOLD) {
activeAxes.insert(qMakePair(i, axis > 0 ? GamepadAxisEvent::POSITIVE : GamepadAxisEvent::NEGATIVE));
}
}
}
#endif
return activeAxes;
}
void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, GBAKey key) {
const GBAAxis* old = GBAInputQueryAxis(&m_inputMap, SDL_BINDING_BUTTON, axis);
const GBAAxis* old = GBAInputQueryAxis(&m_inputMap, type, axis);
GBAAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD };
if (old) {
description = *old;
@ -335,17 +400,15 @@ void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direct
default:
return;
}
GBAInputBindAxis(&m_inputMap, SDL_BINDING_BUTTON, axis, &description);
GBAInputBindAxis(&m_inputMap, type, axis, &description);
}
#endif
void InputController::testGamepad() {
#ifdef BUILD_SDL
auto activeAxes = activeGamepadAxes();
void InputController::testGamepad(int type) {
auto activeAxes = activeGamepadAxes(type);
auto oldAxes = m_activeAxes;
m_activeAxes = activeAxes;
auto activeButtons = activeGamepadButtons();
auto activeButtons = activeGamepadButtons(type);
auto oldButtons = m_activeButtons;
m_activeButtons = activeButtons;
@ -359,7 +422,7 @@ void InputController::testGamepad() {
for (auto& axis : m_activeAxes) {
bool newlyAboveThreshold = activeAxes.contains(axis);
if (newlyAboveThreshold) {
GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, newlyAboveThreshold, this);
GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, newlyAboveThreshold, type, this);
postPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
if (!event->isAccepted()) {
@ -368,7 +431,7 @@ void InputController::testGamepad() {
}
}
for (auto axis : oldAxes) {
GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, false, this);
GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, false, type, this);
clearPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
}
@ -381,7 +444,7 @@ void InputController::testGamepad() {
oldButtons.subtract(m_activeButtons);
for (int button : activeButtons) {
GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Down(), button, this);
GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Down(), button, type, this);
postPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
if (!event->isAccepted()) {
@ -389,11 +452,10 @@ void InputController::testGamepad() {
}
}
for (int button : oldButtons) {
GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Up(), button, this);
GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Up(), button, type, this);
clearPendingEvent(event->gbaKey());
QApplication::sendEvent(QApplication::focusWidget(), event);
}
#endif
}
void InputController::postPendingEvent(GBAKey key) {

View File

@ -52,19 +52,18 @@ public:
const GBAInputMap* map() const { return &m_inputMap; }
#ifdef BUILD_SDL
static const int32_t AXIS_THRESHOLD = 0x3000;
int pollEvents();
int testSDLEvents();
QSet<int> activeGamepadButtons();
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes();
static const int32_t AXIS_THRESHOLD = 0x3000;
QSet<int> activeGamepadButtons(int type);
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(int type);
void recalibrateAxes();
void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, GBAKey);
QStringList connectedGamepads(uint32_t type) const;
int gamepad(uint32_t type) const { return m_sdlPlayer.joystickIndex; }
void setGamepad(uint32_t type, int index) { GBASDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); }
int gamepad(uint32_t type) const;
void setGamepad(uint32_t type, int index);
void setPreferredGamepad(uint32_t type, const QString& device);
void registerTiltAxisX(int axis);
@ -74,13 +73,12 @@ public:
float gyroSensitivity() const;
void setGyroSensitivity(float sensitivity);
#endif
GBARumble* rumble();
GBARotationSource* rotationSource();
public slots:
void testGamepad();
void testGamepad(int type);
private:
void postPendingEvent(GBAKey);
@ -97,9 +95,10 @@ private:
static GBASDLEvents s_sdlEvents;
GBASDLPlayer m_sdlPlayer;
bool m_playerAttached;
QVector<int> m_deadzones;
#endif
QVector<int> m_deadzones;
QSet<int> m_activeButtons;
QSet<QPair<int, GamepadAxisEvent::Direction>> m_activeAxes;
QTimer* m_gamepadTimer;