Qt: Begin revamping profiles

This commit is contained in:
Vicki Pfau 2017-07-02 22:05:03 -07:00
parent 53690f7a83
commit ac2e7b6447
8 changed files with 218 additions and 346 deletions

View File

@ -185,18 +185,11 @@ void InputController::loadConfiguration(uint32_t type) {
}
void InputController::loadProfile(uint32_t type, const QString& profile) {
if (m_activeKeyInfo) {
bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData());
if (!loaded) {
const InputProfile* ip = InputProfile::findProfile(profile);
if (ip) {
ip->apply(this);
}
}
}
recalibrateAxes();
m_inputIndex.loadProfile(profile);
m_keyIndex.loadProfile(profile);
emit profileLoaded(profile);
}

View File

@ -6,7 +6,6 @@
#include "InputIndex.h"
#include "ConfigController.h"
#include "InputProfile.h"
using namespace QGBA;
@ -62,6 +61,9 @@ void InputIndex::rebuild(const InputIndex* root) {
break;
}
}
if (!newItem) {
continue;
}
newItem->setShortcut(item->shortcut());
newItem->setButton(item->button());
newItem->setAxis(item->axis(), item->direction());
@ -121,29 +123,16 @@ void InputIndex::loadGamepadShortcuts(InputItem* item) {
if (item->name().isNull()) {
return;
}
QVariant button = m_config->getQtOption(item->name(), !m_profileName.isNull() ? BUTTON_PROFILE_SECTION + m_profileName : BUTTON_SECTION);
if (button.isNull() && m_profile) {
int buttonInt;
if (m_profile->lookupShortcutButton(item->name(), &buttonInt)) {
button = buttonInt;
}
}
QVariant button = m_config->getQtOption(item->name(), BUTTON_SECTION);
if (!button.isNull()) {
item->setButton(button.toInt());
}
QVariant axis = m_config->getQtOption(item->name(), !m_profileName.isNull() ? AXIS_PROFILE_SECTION + m_profileName : AXIS_SECTION);
QVariant axis = m_config->getQtOption(item->name(), AXIS_SECTION);
int oldAxis = item->axis();
if (oldAxis >= 0) {
item->setAxis(-1, GamepadAxisEvent::NEUTRAL);
}
if (axis.isNull() && m_profile) {
int axisInt;
GamepadAxisEvent::Direction direction;
if (m_profile->lookupShortcutAxis(item->name(), &axisInt, &direction)) {
axis = QLatin1String(direction == GamepadAxisEvent::Direction::NEGATIVE ? "-" : "+") + QString::number(axisInt);
}
}
if (!axis.isNull()) {
QString axisDesc = axis.toString();
if (axisDesc.size() >= 2) {
@ -240,14 +229,6 @@ int InputIndex::toModifierKey(int key) {
return modifiers;
}
void InputIndex::loadProfile(const QString& profile) {
m_profileName = profile;
m_profile = InputProfile::findProfile(profile);
for (auto& item : m_items) {
loadShortcuts(item);
}
}
void InputIndex::saveConfig() {
for (auto& item : m_items) {
m_config->setQtOption(item->name(), QKeySequence(item->shortcut()).toString(), KEY_SECTION);

View File

@ -17,7 +17,6 @@ class QMenu;
namespace QGBA {
class ConfigController;
class InputProfile;
class InputIndex {
private:
@ -25,10 +24,6 @@ private:
constexpr static const char* const BUTTON_SECTION = "shortcutButton";
constexpr static const char* const AXIS_SECTION = "shortcutAxis";
constexpr static const char* const HAT_SECTION = "shortcutHat";
constexpr static const char* const KEY_PROFILE_SECTION = "shortcutProfileKey.";
constexpr static const char* const BUTTON_PROFILE_SECTION = "shortcutProfileButton.";
constexpr static const char* const AXIS_PROFILE_SECTION = "shortcutProfileAxis.";
constexpr static const char* const HAT_PROFILE_SECTION = "shortcutProfileHat.";
public:
void setConfigController(ConfigController* controller);
@ -60,8 +55,6 @@ public:
static bool isModifierKey(int key);
static int toModifierKey(int key);
void loadProfile(const QString& profile);
void saveConfig();
private:
@ -79,8 +72,6 @@ private:
QMap<QPair<int, GamepadAxisEvent::Direction>, InputItem*> m_axes;
ConfigController* m_config = nullptr;
QString m_profileName;
const InputProfile* m_profile = nullptr;
};
}

View File

@ -7,262 +7,93 @@
#include "InputController.h"
#include <QRegExp>
#include <QSettings>
using namespace QGBA;
const InputProfile InputProfile::s_defaultMaps[] = {
{
"XInput Controller #\\d+", // XInput (Windows)
{
/*keyA */ 11,
/*keyB */ 10,
/*keySelect */ 5,
/*keyStart */ 4,
/*keyRight */ 3,
/*keyLeft */ 2,
/*keyUp */ 0,
/*keyDown */ 1,
/*keyR */ 9,
/*keyL */ 8
},
{
/*loadState */ 12,
/*saveState */ 13,
/*holdFastForward */ -1,
/*holdRewind */ -1,
},
{
/*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5},
/*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 4},
}
},
{
"(Microsoft X-Box 360 pad|Xbox Gamepad \\(userspace driver\\))", // Linux
{
/*keyA */ 1,
/*keyB */ 0,
/*keySelect */ 6,
/*keyStart */ 7,
/*keyRight */ -1,
/*keyLeft */ -1,
/*keyUp */ -1,
/*keyDown */ -1,
/*keyR */ 5,
/*keyL */ 4
},
{
/*loadState */ 2,
/*saveState */ 3,
/*holdFastForward */ -1,
/*holdRewind */ -1,
},
{
/*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5},
/*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 2},
}
},
{
"Xbox 360 Wired Controller", // OS X
{
/*keyA */ 1,
/*keyB */ 0,
/*keySelect */ 9,
/*keyStart */ 8,
/*keyRight */ 14,
/*keyLeft */ 13,
/*keyUp */ 11,
/*keyDown */ 12,
/*keyR */ 5,
/*keyL */ 4
},
{
/*loadState */ 2,
/*saveState */ 3,
/*holdFastForward */ -1,
/*holdRewind */ -1,
},
{
/*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1},
/*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5},
/*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 2},
}
},
{
"(Sony Computer Entertainment )?Wireless Controller", // The DualShock 4 device ID is cut off on Windows
{
/*keyA */ 1,
/*keyB */ 2,
/*keySelect */ 8,
/*keyStart */ 9,
/*keyRight */ -1,
/*keyLeft */ -1,
/*keyUp */ -1,
/*keyDown */ -1,
/*keyR */ 5,
/*keyL */ 4
},
{
/*loadState */ 0,
/*saveState */ 3,
/*holdFastForward */ 7,
/*holdRewind */ 6,
},
},
{
"PLAYSTATION\\(R\\)3 Controller", // DualShock 3 (OS X)
{
/*keyA */ 13,
/*keyB */ 14,
/*keySelect */ 0,
/*keyStart */ 3,
/*keyRight */ 5,
/*keyLeft */ 7,
/*keyUp */ 4,
/*keyDown */ 6,
/*keyR */ 11,
/*keyL */ 10
},
{
/*loadState */ 15,
/*saveState */ 12,
/*holdFastForward */ 9,
/*holdRewind */ 8,
},
},
{
"Wiimote \\(..-..-..-..-..-..\\)", // WJoy (OS X)
{
/*keyA */ 15,
/*keyB */ 16,
/*keySelect */ 7,
/*keyStart */ 6,
/*keyRight */ 14,
/*keyLeft */ 13,
/*keyUp */ 11,
/*keyDown */ 12,
/*keyR */ 20,
/*keyL */ 19
},
{
/*loadState */ 18,
/*saveState */ 17,
/*holdFastForward */ 22,
/*holdRewind */ 21,
},
},
};
QList<InputProfile> InputProfile::s_profiles;
constexpr InputProfile::InputProfile(const char* name,
const KeyList<int> keys,
const Shortcuts<int> shortcutButtons,
const Shortcuts<Axis> shortcutAxes,
const KeyList<AxisValue> axes,
const struct Coord& tiltAxis,
const struct Coord& gyroAxis,
float gyroSensitivity)
InputProfile::InputProfile(const QString& name)
: m_profileName(name)
, m_keys {
keys.keyA,
keys.keyB,
keys.keySelect,
keys.keyStart,
keys.keyRight,
keys.keyLeft,
keys.keyUp,
keys.keyDown,
keys.keyR,
keys.keyL,
}
, m_axes {
axes.keyA,
axes.keyB,
axes.keySelect,
axes.keyStart,
axes.keyRight,
axes.keyLeft,
axes.keyUp,
axes.keyDown,
axes.keyR,
axes.keyL,
}
, m_shortcutButtons(shortcutButtons)
, m_shortcutAxes(shortcutAxes)
, m_tiltAxis(tiltAxis)
, m_gyroAxis(gyroAxis)
, m_gyroSensitivity(gyroSensitivity)
{
}
void InputProfile::loadDefaultProfiles() {
loadProfiles(":/input/default-profiles.ini");
}
void InputProfile::loadProfiles(const QString& path) {
QSettings profileIni(path, QSettings::IniFormat);
for (const auto& group : profileIni.childGroups()) {
}
profileIni.beginGroup(PROFILE_SECTION);
for (const auto& group : profileIni.childGroups()) {
loadProfile(profileIni, group);
}
profileIni.endGroup();
}
void InputProfile::loadProfile(QSettings& profileIni, const QString& name) {
profileIni.beginGroup(name);
s_profiles.append(name);
InputProfile& profile = s_profiles.last();
for (const auto& group : profileIni.childGroups()) {
profileIni.beginGroup(group);
if (group == MATCH_SECTION) {
for (const auto& key : profileIni.childKeys()) {
profile.m_match.append(QRegExp(profileIni.value(key).toString()));
}
}
for (const auto& key : profileIni.childKeys()) {
InputItem* item = profile.m_inputIndex.itemAt(key);
if (!item) {
item = profile.m_inputIndex.addItem(QString(), key);
}
if (group == BUTTON_SECTION) {
item->setButton(profileIni.value(key).toInt());
}
if (group == AXIS_SECTION) {
QString axisDescription = profileIni.value(key).toString();
GamepadAxisEvent::Direction direction = GamepadAxisEvent::POSITIVE;
int axis = profileIni.value(key).toInt();
if (axisDescription[0] == '-') {
direction = GamepadAxisEvent::NEGATIVE;
axis = -axis;
}
item->setAxis(axis, direction);
}
if (group == KEY_SECTION) {
item->setShortcut(profileIni.value(key).toInt());
}
}
profileIni.endGroup();
}
profile.m_inputIndex.rebuild();
profileIni.endGroup();
}
const InputProfile* InputProfile::findProfile(const QString& name) {
for (size_t i = 0; i < sizeof(s_defaultMaps) / sizeof(*s_defaultMaps); ++i) {
QRegExp re(s_defaultMaps[i].m_profileName);
if (re.exactMatch(name)) {
return &s_defaultMaps[i];
if (s_profiles.isEmpty()) {
loadDefaultProfiles();
}
for (const InputProfile& profile : s_profiles) {
for (const auto& match : profile.m_match) {
if (match.exactMatch(name)) {
return &profile;
}
}
}
return nullptr;
}
void InputProfile::apply(InputController* controller) const {
for (size_t i = 0; i < GBA_KEY_MAX; ++i) {
#ifdef BUILD_SDL
controller->bindKey(SDL_BINDING_BUTTON, m_keys[i], GBAInputInfo.keyId[i]);
controller->bindAxis(SDL_BINDING_BUTTON, m_axes[i].axis, m_axes[i].direction, GBAInputInfo.keyId[i]);
#endif
}
controller->rebuildIndex(&m_inputIndex);
controller->rebuildKeyIndex(&m_inputIndex);
controller->registerTiltAxisX(m_tiltAxis.x);
controller->registerTiltAxisY(m_tiltAxis.y);
controller->registerGyroAxisX(m_gyroAxis.x);
controller->registerGyroAxisY(m_gyroAxis.y);
controller->setGyroSensitivity(m_gyroSensitivity);
}
bool InputProfile::lookupShortcutButton(const QString& shortcutName, int* button) const {
if (shortcutName == QLatin1String("loadState")) {
*button = m_shortcutButtons.loadState;
return true;
}
if (shortcutName == QLatin1String("saveState")) {
*button = m_shortcutButtons.saveState;
return true;
}
if (shortcutName == QLatin1String("holdFastForward")) {
*button = m_shortcutButtons.holdFastForward;
return true;
}
if (shortcutName == QLatin1String("holdRewind")) {
*button = m_shortcutButtons.holdRewind;
return true;
}
return false;
}
bool InputProfile::lookupShortcutAxis(const QString& shortcutName, int* axis, GamepadAxisEvent::Direction* direction) const {
if (shortcutName == QLatin1String("loadState")) {
*axis = m_shortcutAxes.loadState.axis;
*direction = m_shortcutAxes.loadState.direction;
return true;
}
if (shortcutName == QLatin1String("saveState")) {
*axis = m_shortcutAxes.saveState.axis;
*direction = m_shortcutAxes.saveState.direction;
return true;
}
if (shortcutName == QLatin1String("holdFastForward")) {
*axis = m_shortcutAxes.holdFastForward.axis;
*direction = m_shortcutAxes.holdFastForward.direction;
return true;
}
if (shortcutName == QLatin1String("holdRewind")) {
*axis = m_shortcutAxes.holdRewind.axis;
*direction = m_shortcutAxes.holdRewind.direction;
return true;
}
return false;
}

View File

@ -7,91 +7,52 @@
#define QGBA_INPUT_PROFILE
#include "GamepadAxisEvent.h"
#include "InputIndex.h"
#include <mgba/core/core.h>
#include <mgba/gba/interface.h>
#include <QRegExp>
class QSettings;
namespace QGBA {
class InputController;
class InputProfile {
public:
constexpr static const char* const PROFILE_SECTION = "profiles";
constexpr static const char* const MATCH_SECTION = "match";
constexpr static const char* const KEY_SECTION = "keys";
constexpr static const char* const BUTTON_SECTION = "buttons";
constexpr static const char* const AXIS_SECTION = "axes";
constexpr static const char* const HAT_SECTION = "hats";
static const InputProfile* findProfile(const QString& name);
static void loadProfiles(const QString& path);
void apply(InputController*) const;
bool lookupShortcutButton(const QString& shortcut, int* button) const;
bool lookupShortcutAxis(const QString& shortcut, int* axis, GamepadAxisEvent::Direction* direction) const;
private:
InputProfile(const QString&);
struct Coord {
int x;
int y;
};
struct AxisValue {
GamepadAxisEvent::Direction direction;
int axis;
};
static void loadDefaultProfiles();
static void loadProfile(QSettings&, const QString& name);
template <typename T> struct Shortcuts {
T loadState;
T saveState;
T holdFastForward;
T holdRewind;
};
static QList<InputProfile> s_profiles;
struct Axis {
GamepadAxisEvent::Direction direction;
int axis;
};
QString m_profileName;
QList<QRegExp> m_match;
template <typename T> struct KeyList {
T keyA;
T keyB;
T keySelect;
T keyStart;
T keyRight;
T keyLeft;
T keyUp;
T keyDown;
T keyR;
T keyL;
};
constexpr InputProfile(const char* name,
const KeyList<int> keys,
const Shortcuts<int> shortcutButtons = { -1, -1, -1, -1},
const Shortcuts<Axis> shortcutAxes = {
{GamepadAxisEvent::Direction::NEUTRAL, -1},
{GamepadAxisEvent::Direction::NEUTRAL, -1},
{GamepadAxisEvent::Direction::NEUTRAL, -1},
{GamepadAxisEvent::Direction::NEUTRAL, -1}},
const KeyList<AxisValue> axes = {
{ GamepadAxisEvent::Direction::NEUTRAL, -1 },
{ GamepadAxisEvent::Direction::NEUTRAL, -1 },
{ GamepadAxisEvent::Direction::NEUTRAL, -1 },
{ GamepadAxisEvent::Direction::NEUTRAL, -1 },
{ GamepadAxisEvent::Direction::POSITIVE, 0 },
{ GamepadAxisEvent::Direction::NEGATIVE, 0 },
{ GamepadAxisEvent::Direction::NEGATIVE, 1 },
{ GamepadAxisEvent::Direction::POSITIVE, 1 },
{ GamepadAxisEvent::Direction::NEUTRAL, -1 },
{ GamepadAxisEvent::Direction::NEUTRAL, -1 }},
const struct Coord& tiltAxis = { 2, 3 },
const struct Coord& gyroAxis = { 0, 1 },
float gyroSensitivity = 2e+09f);
static const InputProfile s_defaultMaps[];
const char* m_profileName;
const int m_keys[GBA_KEY_MAX];
const AxisValue m_axes[GBA_KEY_MAX];
const Shortcuts<int> m_shortcutButtons;
const Shortcuts<Axis> m_shortcutAxes;
Coord m_tiltAxis;
Coord m_gyroAxis;
float m_gyroSensitivity;
Coord m_tiltAxis = { 2, 3 };
Coord m_gyroAxis = { 0, 1 };
float m_gyroSensitivity = 2e+09f;
InputIndex m_inputIndex;
};
}

View File

@ -0,0 +1,114 @@
[profiles/XInput (Windows)/match]
0=XInput Controller #\\d+
[profiles/XInput (Windows)/buttons]
keyA=11
keyB=10
keySelect=5
keyStart=4
keyRight=3
keyLeft=2
keyUp=0
keyDown=1
keyR=9
keyL=8
loadState=12
saveState=13
[profiles/XInput (Windows)/axes]
holdFastForward=+5
holdRewind=+4
[profiles/XInput (Linux)/match]
0=Microsoft X-Box 360 pad
1=Xbox Gamepad \\(userspace driver\\)
[profiles/XInput (Linux)/buttons]
keyA=1
keyB=0
keySelect=6
keyStart=7
keyR=5
keyL=4
loadState=2
saveState=3
[profiles/XInput (Linux)/axes]
holdFastForward=+5
holdRewind=+2
[profiles/XInput (macOS)/match]
0=Xbox 360 Wired Controller
[profiles/XInput (macOS)/buttons]
keyA=1
keyB=0
keySelect=9
keyStart=8
keyRight=14
keyLeft=13
keyUp=11
keyDown=12
keyR=5
keyL=4
loadState=2
saveState=3
[profiles/XInput (macOS)/axes]
holdFastForward=+5
holdRewind=+2
[profiles/DualShock 4/match]
0=Sony Computer Entertainment Wireless Controller
1=Wireless Controller
[profiles/DualShock 4/buttons]
keyA=1
keyB=2
keySelect=8
keyStart=9
keyR=5
keyL=4
loadState=0
saveState=3
holdFastForward=7
holdRewind=6
[profiles/DualShock 3/match]
0=PLAYSTATION\\(R\\)3 Controller
[profiles/DualShock 3/buttons]
keyA=13
keyB=14
keySelect=0
keyStart=3
keyRight=5
keyLeft=7
keyUp=4
keyDown=6
keyR=11
keyL=10
loadState=15
saveState=12
holdFastForward=9
holdRewind=8
[profiles/Wii Remote/match]
0=Wiimote \\(..-..-..-..-..-..\\)
[profiles/Wii Remote/buttons]
keyA=15
keyB=16
keySelect=7
keyStart=6
keyRight=14
keyLeft=13
keyUp=11
keyDown=12
keyR=20
keyL=19
loadState=18
saveState=17
holdFastForward=22
holdRewind=21

View File

@ -3,5 +3,6 @@
<file>../../../res/mgba-1024.png</file>
<file>../../../res/keymap.qpic</file>
<file>../../../res/patrons.txt</file>
<file>input/default-profiles.ini</file>
</qresource>
</RCC>

View File

@ -350,7 +350,7 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
}
if (events->preferredJoysticks[i] && strcmp(events->preferredJoysticks[i], joystickName) == 0) {
events->players[i]->joystick = joystick;
if (config) {
if (config && events->players[i]->bindings) {
mInputProfileLoad(events->players[i]->bindings, SDL_BINDING_BUTTON, config, joystickName);
}
return;
@ -361,7 +361,7 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
continue;
}
events->players[i]->joystick = joystick;
if (config) {
if (config && events->players[i]->bindings) {
mInputProfileLoad(events->players[i]->bindings, SDL_BINDING_BUTTON, config, joystickName);
}
break;