mirror of https://github.com/mgba-emu/mgba.git
Qt: Start adding better input abstractions
This commit is contained in:
parent
be3022156f
commit
4580e8d2e9
|
@ -107,7 +107,11 @@ set(SOURCE_FILES
|
|||
GamepadButtonEvent.cpp
|
||||
GamepadHatEvent.cpp
|
||||
IOViewer.cpp
|
||||
input/Gamepad.cpp
|
||||
input/InputDriver.cpp
|
||||
input/InputSource.cpp
|
||||
input/InputMapper.cpp
|
||||
input/KeySource.cpp
|
||||
InputController.cpp
|
||||
InputProfile.cpp
|
||||
KeyEditor.cpp
|
||||
|
@ -199,6 +203,7 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5
|
|||
|
||||
set(AUDIO_SRC)
|
||||
if(BUILD_SDL)
|
||||
list(APPEND SOURCE_FILES input/SDLInputDriver.cpp)
|
||||
list(APPEND AUDIO_SRC AudioProcessorSDL.cpp)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
GBAKey mapKeyboard(int key) const;
|
||||
|
||||
mInputMap* map() { return &m_inputMap; }
|
||||
const mInputMap* map() const { return &m_inputMap; }
|
||||
|
||||
int pollEvents();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "input/Gamepad.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
Gamepad::Gamepad(InputDriver* driver, QObject* parent)
|
||||
: InputSource(driver, parent)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include "GamepadHatEvent.h"
|
||||
#include "input/InputSource.h"
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class InputDriver;
|
||||
|
||||
class Gamepad : public InputSource {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Gamepad(InputDriver* driver, QObject* parent = nullptr);
|
||||
|
||||
virtual QList<bool> currentButtons() = 0;
|
||||
virtual QList<int16_t> currentAxes() = 0;
|
||||
virtual QList<GamepadHatEvent::Direction> currentHats() = 0;
|
||||
|
||||
virtual int buttonCount() const = 0;
|
||||
virtual int axisCount() const = 0;
|
||||
virtual int hatCount() const = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "input/InputDriver.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
InputDriver::InputDriver(QObject* parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
void InputDriver::loadConfiguration(ConfigController*) {
|
||||
}
|
||||
|
||||
void InputDriver::saveConfiguration(ConfigController*) {
|
||||
}
|
||||
|
||||
void InputDriver::bindDefaults(InputController*) {
|
||||
}
|
||||
|
||||
QList<KeySource*> InputDriver::connectedKeySources() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<Gamepad*> InputDriver::connectedGamepads() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
mRumble* InputDriver::rumble() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mRotationSource* InputDriver::rotationSource() {
|
||||
return nullptr;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
|
||||
struct mRotationSource;
|
||||
struct mRumble;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class ConfigController;
|
||||
class Gamepad;
|
||||
class InputController;
|
||||
class KeySource;
|
||||
|
||||
class InputDriver : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InputDriver(QObject* parent = nullptr);
|
||||
virtual ~InputDriver() = default;
|
||||
|
||||
virtual uint32_t type() const = 0;
|
||||
virtual QString visibleName() const = 0;
|
||||
|
||||
virtual void loadConfiguration(ConfigController*);
|
||||
virtual void saveConfiguration(ConfigController*);
|
||||
|
||||
virtual void bindDefaults(InputController*);
|
||||
|
||||
virtual bool update() = 0;
|
||||
|
||||
virtual QList<KeySource*> connectedKeySources() const;
|
||||
virtual QList<Gamepad*> connectedGamepads() const;
|
||||
|
||||
virtual mRumble* rumble();
|
||||
virtual mRotationSource* rotationSource();
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "input/InputSource.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
InputSource::InputSource(InputDriver* driver, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_driver(driver)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class InputDriver;
|
||||
|
||||
class InputSource : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InputSource(InputDriver* driver, QObject* parent = nullptr);
|
||||
virtual ~InputSource() = default;
|
||||
|
||||
InputDriver* driver() { return m_driver; }
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QString visibleName() const = 0;
|
||||
|
||||
protected:
|
||||
InputDriver* const m_driver;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "input/KeySource.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
KeySource::KeySource(InputDriver* driver, QObject* parent)
|
||||
: InputSource(driver, parent)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include "input/InputSource.h"
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class InputDriver;
|
||||
|
||||
class KeySource : public InputSource {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KeySource(InputDriver* driver, QObject* parent = nullptr);
|
||||
|
||||
virtual QSet<int> currentKeys() = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "input/SDLInputDriver.h"
|
||||
|
||||
#include "ConfigController.h"
|
||||
#include "InputController.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
int s_sdlInited = 0;
|
||||
mSDLEvents s_sdlEvents;
|
||||
|
||||
SDLInputDriver::SDLInputDriver(InputController* controller, QObject* parent)
|
||||
: InputDriver(parent)
|
||||
, m_controller(controller)
|
||||
{
|
||||
if (s_sdlInited == 0) {
|
||||
mSDLInitEvents(&s_sdlEvents);
|
||||
}
|
||||
++s_sdlInited;
|
||||
m_sdlPlayer.bindings = m_controller->map();
|
||||
|
||||
for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) {
|
||||
m_gamepads.append(std::make_shared<SDLGamepad>(this, i));
|
||||
}
|
||||
}
|
||||
|
||||
SDLInputDriver::~SDLInputDriver() {
|
||||
if (m_playerAttached) {
|
||||
mSDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer);
|
||||
}
|
||||
|
||||
--s_sdlInited;
|
||||
if (s_sdlInited == 0) {
|
||||
mSDLDeinitEvents(&s_sdlEvents);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputDriver::loadConfiguration(ConfigController* config) {
|
||||
mSDLEventsLoadConfig(&s_sdlEvents, config->input());
|
||||
if (!m_playerAttached) {
|
||||
m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer);
|
||||
}
|
||||
if (m_playerAttached) {
|
||||
mSDLPlayerLoadConfig(&m_sdlPlayer, config->input());
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputDriver::saveConfiguration(ConfigController* config) {
|
||||
if (m_playerAttached) {
|
||||
mSDLPlayerSaveConfig(&m_sdlPlayer, config->input());
|
||||
}
|
||||
}
|
||||
|
||||
void SDLInputDriver::bindDefaults(InputController* controller) {
|
||||
mSDLInitBindingsGBA(controller->map());
|
||||
}
|
||||
|
||||
mRumble* SDLInputDriver::rumble() {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
if (m_playerAttached) {
|
||||
return &m_sdlPlayer.rumble.d;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mRotationSource* SDLInputDriver::rotationSource() {
|
||||
if (m_playerAttached) {
|
||||
return &m_sdlPlayer.rotation.d;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool SDLInputDriver::update() {
|
||||
if (!m_playerAttached || !m_sdlPlayer.joystick) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_JoystickUpdate();
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
updateGamepads();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<Gamepad*> SDLInputDriver::connectedGamepads() const {
|
||||
QList<Gamepad*> pads;
|
||||
for (auto& pad : m_gamepads) {
|
||||
pads.append(pad.get());
|
||||
}
|
||||
return pads;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void SDLInputDriver::updateGamepads() {
|
||||
for (int i = 0; i < m_gamepads.size(); ++i) {
|
||||
if (m_gamepads.at(i)->updateIndex()) {
|
||||
continue;
|
||||
}
|
||||
m_gamepads.removeAt(i);
|
||||
--i;
|
||||
}
|
||||
std::sort(m_gamepads.begin(), m_gamepads.end(), [](const auto& a, const auto b) {
|
||||
return a->m_index < b->m_index;
|
||||
});
|
||||
|
||||
for (size_t i = 0, j = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) {
|
||||
std::shared_ptr<SDLGamepad> gamepad = m_gamepads.at(j);
|
||||
if (gamepad->m_index == i) {
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
m_gamepads.append(std::make_shared<SDLGamepad>(this, i));
|
||||
}
|
||||
std::sort(m_gamepads.begin(), m_gamepads.end(), [](const auto& a, const auto b) {
|
||||
return a->m_index < b->m_index;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
SDLGamepad::SDLGamepad(SDLInputDriver* driver, int index, QObject* parent)
|
||||
: Gamepad(driver, parent)
|
||||
, m_index(index)
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), m_guid, sizeof(m_guid));
|
||||
#endif
|
||||
}
|
||||
|
||||
QList<bool> SDLGamepad::currentButtons() {
|
||||
if (!verify()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
QList<bool> buttons;
|
||||
|
||||
int numButtons = SDL_JoystickNumButtons(joystick);
|
||||
for (int i = 0; i < numButtons; ++i) {
|
||||
buttons.append(SDL_JoystickGetButton(joystick, i));
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
QList<int16_t> SDLGamepad::currentAxes() {
|
||||
if (!verify()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
QList<int16_t> axes;
|
||||
|
||||
int numAxes = SDL_JoystickNumAxes(joystick);
|
||||
for (int i = 0; i < numAxes; ++i) {
|
||||
axes.append(SDL_JoystickGetAxis(joystick, i));
|
||||
}
|
||||
|
||||
return axes;
|
||||
}
|
||||
|
||||
QList<GamepadHatEvent::Direction> SDLGamepad::currentHats() {
|
||||
if (!verify()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
QList<GamepadHatEvent::Direction> hats;
|
||||
|
||||
int numHats = SDL_JoystickNumHats(joystick);
|
||||
for (int i = 0; i < numHats; ++i) {
|
||||
hats.append(static_cast<GamepadHatEvent::Direction>(SDL_JoystickGetHat(joystick, i)));
|
||||
}
|
||||
|
||||
return hats;
|
||||
}
|
||||
|
||||
int SDLGamepad::buttonCount() const {
|
||||
if (!verify()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
return SDL_JoystickNumButtons(joystick);
|
||||
}
|
||||
|
||||
int SDLGamepad::axisCount() const {
|
||||
if (!verify()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
return SDL_JoystickNumAxes(joystick);
|
||||
}
|
||||
|
||||
int SDLGamepad::hatCount() const {
|
||||
if (!verify()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick;
|
||||
return SDL_JoystickNumHats(joystick);
|
||||
}
|
||||
|
||||
QString SDLGamepad::name() const {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
return m_guid;
|
||||
#else
|
||||
return visibleName();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString SDLGamepad::visibleName() const {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
return SDL_JoystickName(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick);
|
||||
#else
|
||||
return SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
bool SDLGamepad::updateIndex() {
|
||||
char guid[34];
|
||||
for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) {
|
||||
SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick;
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), guid, sizeof(guid));
|
||||
if (memcmp(guid, m_guid, 33) == 0) {
|
||||
m_index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SDLGamepad::verify() const {
|
||||
return m_index < SDL_JoystickListSize(&s_sdlEvents.joysticks);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include "input/Gamepad.h"
|
||||
#include "input/InputDriver.h"
|
||||
|
||||
#include "platform/sdl/sdl-events.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class SDLGamepad;
|
||||
|
||||
class SDLInputDriver : public InputDriver {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SDLInputDriver(InputController*, QObject* parent = nullptr);
|
||||
~SDLInputDriver();
|
||||
|
||||
uint32_t type() const override { return SDL_BINDING_BUTTON; }
|
||||
QString visibleName() const override { return QLatin1String("SDL"); }
|
||||
|
||||
void loadConfiguration(ConfigController* config) override;
|
||||
void saveConfiguration(ConfigController* config) override;
|
||||
|
||||
void bindDefaults(InputController*) override;
|
||||
|
||||
bool update() override;
|
||||
|
||||
QList<Gamepad*> connectedGamepads() const override;
|
||||
|
||||
mRumble* rumble() override;
|
||||
mRotationSource* rotationSource() override;
|
||||
|
||||
private:
|
||||
InputController* m_controller;
|
||||
mSDLPlayer m_sdlPlayer{};
|
||||
bool m_playerAttached = false;
|
||||
QList<std::shared_ptr<SDLGamepad>> m_gamepads;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void updateGamepads();
|
||||
#endif
|
||||
};
|
||||
|
||||
class SDLGamepad : public Gamepad {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SDLGamepad(SDLInputDriver*, int index, QObject* parent = nullptr);
|
||||
|
||||
QList<bool> currentButtons() override;
|
||||
QList<int16_t> currentAxes() override;
|
||||
QList<GamepadHatEvent::Direction> currentHats() override;
|
||||
|
||||
int buttonCount() const override;
|
||||
int axisCount() const override;
|
||||
int hatCount() const override;
|
||||
|
||||
QString name() const override;
|
||||
QString visibleName() const override;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
bool updateIndex();
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class SDLInputDriver;
|
||||
|
||||
size_t m_index;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
char m_guid[34]{};
|
||||
#endif
|
||||
|
||||
bool verify() const;
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue