2024-05-20 23:25:55 -04:00
|
|
|
#include "inputconfigdialog.h"
|
|
|
|
|
|
|
|
#include <QDialogButtonBox>
|
|
|
|
#include <QKeyEvent>
|
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QLabel>
|
|
|
|
|
|
|
|
#include <vanilla.h>
|
|
|
|
|
|
|
|
InputConfigDialog::InputConfigDialog(QWidget *parent) : QDialog(parent)
|
2024-11-14 21:49:18 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
InputConfigDialog::InputConfigDialog(KeyMap *keyMap, QWidget *parent) : InputConfigDialog(parent)
|
|
|
|
{
|
|
|
|
m_keyMap = keyMap;
|
|
|
|
m_gamepadHandler = nullptr;
|
|
|
|
|
|
|
|
createLayout<InputConfigKeyButton>();
|
|
|
|
|
|
|
|
for (auto it = m_keyMap->cbegin(); it != m_keyMap->cend(); it++) {
|
|
|
|
InputConfigKeyButton *btn = static_cast<InputConfigKeyButton *>(m_buttons[it->second]);
|
|
|
|
if (btn) {
|
|
|
|
btn->setKey(it->first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
connectSoloSignals();
|
|
|
|
}
|
|
|
|
|
|
|
|
InputConfigDialog::InputConfigDialog(GamepadHandler *gamepadHandler, QWidget *parent) : InputConfigDialog(parent)
|
|
|
|
{
|
|
|
|
m_keyMap = nullptr;
|
|
|
|
m_gamepadHandler = gamepadHandler;
|
|
|
|
|
|
|
|
m_gamepadHandler->signalNextButtonOrAxis(true);
|
|
|
|
|
|
|
|
connect(m_gamepadHandler, &GamepadHandler::axisMoved, this, &InputConfigDialog::setControllerAxis);
|
|
|
|
connect(m_gamepadHandler, &GamepadHandler::buttonPressed, this, &InputConfigDialog::setControllerButton);
|
|
|
|
|
|
|
|
createLayout<InputConfigControllerButton>();
|
|
|
|
|
|
|
|
for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
|
|
|
|
SDL_GameControllerButton b = static_cast<SDL_GameControllerButton>(i);
|
|
|
|
int id = m_gamepadHandler->button(b);
|
|
|
|
if (id != -1) {
|
|
|
|
if (InputConfigControllerButton *btn = static_cast<InputConfigControllerButton *>(m_buttons[id])) {
|
|
|
|
btn->setButton(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++) {
|
|
|
|
SDL_GameControllerAxis a = static_cast<SDL_GameControllerAxis>(i);
|
|
|
|
int id = m_gamepadHandler->axis(a);
|
|
|
|
if (id != -1) {
|
|
|
|
if (InputConfigControllerButton *btn = static_cast<InputConfigControllerButton *>(m_buttons[id])) {
|
|
|
|
btn->setAxis(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
connectSoloSignals();
|
|
|
|
}
|
|
|
|
|
|
|
|
InputConfigDialog::~InputConfigDialog()
|
|
|
|
{
|
|
|
|
if (m_gamepadHandler) {
|
|
|
|
m_gamepadHandler->signalNextButtonOrAxis(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void InputConfigDialog::createLayout()
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
|
|
|
QGridLayout *layout = new QGridLayout(this);
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("L"), VANILLA_BTN_L), 2, 1);
|
|
|
|
layout->addWidget(createButton<T>(tr("ZL"), VANILLA_BTN_ZL), 3, 1);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("R"), VANILLA_BTN_R), 2, 3);
|
|
|
|
layout->addWidget(createButton<T>(tr("ZR"), VANILLA_BTN_ZR), 3, 3);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("Left Stick Up"), VANILLA_AXIS_L_UP), 4, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("Left Stick Down"), VANILLA_AXIS_L_DOWN), 5, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("Left Stick Left"), VANILLA_AXIS_L_LEFT), 6, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("Left Stick Right"), VANILLA_AXIS_L_RIGHT), 7, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("Left Stick Click"), VANILLA_BTN_L3), 8, 0);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("D-Pad Up"), VANILLA_BTN_UP), 10, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("D-Pad Down"), VANILLA_BTN_DOWN), 11, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("D-Pad Left"), VANILLA_BTN_LEFT), 12, 0);
|
|
|
|
layout->addWidget(createButton<T>(tr("D-Pad Right"), VANILLA_BTN_RIGHT), 13, 0);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("TV"), VANILLA_BTN_TV), 14, 1, 1, 1);
|
|
|
|
layout->addWidget(createButton<T>(tr("Home"), VANILLA_BTN_HOME), 14, 2);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("Right Stick Up"), VANILLA_AXIS_R_UP), 2, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Right Stick Down"), VANILLA_AXIS_R_DOWN), 3, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Right Stick Left"), VANILLA_AXIS_R_LEFT), 4, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Right Stick Right"), VANILLA_AXIS_R_RIGHT), 5, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Right Stick Click"), VANILLA_BTN_R3), 6, 4);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("A"), VANILLA_BTN_A), 8, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("B"), VANILLA_BTN_B), 9, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("X"), VANILLA_BTN_X), 10, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Y"), VANILLA_BTN_Y), 11, 4);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
layout->addWidget(createButton<T>(tr("Start/Plus"), VANILLA_BTN_PLUS), 13, 4);
|
|
|
|
layout->addWidget(createButton<T>(tr("Select/Minus"), VANILLA_BTN_MINUS), 14, 4);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
|
|
|
QLabel *imageLbl = new QLabel(this);
|
|
|
|
QPixmap imgPix;
|
|
|
|
imgPix.load(QStringLiteral(":/com.mattkc.vanilla.svg"));
|
|
|
|
imageLbl->setPixmap(imgPix);
|
2024-05-21 22:45:00 -04:00
|
|
|
layout->addWidget(imageLbl, 4, 1, 10, 3);
|
2024-05-20 23:25:55 -04:00
|
|
|
|
|
|
|
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
|
|
|
buttons->setCenterButtons(true);
|
|
|
|
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
|
|
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
2024-05-21 22:45:00 -04:00
|
|
|
layout->addWidget(buttons, 16, 0, 1, 5);
|
2024-05-20 23:25:55 -04:00
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
template<typename T>
|
|
|
|
InputConfigButtonBase *InputConfigDialog::createButton(const QString &name, int vanillaBtn)
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
2024-11-14 21:49:18 -05:00
|
|
|
InputConfigButtonBase *i = new T(name, this);
|
2024-05-20 23:25:55 -04:00
|
|
|
m_buttons[vanillaBtn] = i;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::accept()
|
|
|
|
{
|
2024-11-14 21:49:18 -05:00
|
|
|
if (m_keyMap) {
|
|
|
|
m_keyMap->clear();
|
|
|
|
|
|
|
|
for (auto it = m_buttons.cbegin(); it != m_buttons.cend(); it++) {
|
|
|
|
InputConfigKeyButton *keyBtn = static_cast<InputConfigKeyButton *>(it->second);
|
|
|
|
Qt::Key key = keyBtn->key();
|
|
|
|
if (key != Qt::Key_unknown) {
|
|
|
|
(*m_keyMap)[key] = it->first;
|
|
|
|
}
|
|
|
|
}
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
m_keyMap->save(KeyMap::getConfigFilename());
|
|
|
|
} else if (m_gamepadHandler) {
|
|
|
|
m_gamepadHandler->clear();
|
|
|
|
|
|
|
|
for (auto it = m_buttons.cbegin(); it != m_buttons.cend(); it++) {
|
|
|
|
InputConfigControllerButton *cBtn = static_cast<InputConfigControllerButton *>(it->second);
|
|
|
|
if (cBtn->button() != SDL_CONTROLLER_BUTTON_INVALID) {
|
|
|
|
m_gamepadHandler->setButton(cBtn->button(), it->first);
|
|
|
|
} else if (cBtn->axis() != SDL_CONTROLLER_AXIS_INVALID) {
|
|
|
|
m_gamepadHandler->setAxis(cBtn->axis(), it->first);
|
|
|
|
}
|
2024-05-20 23:25:55 -04:00
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
m_gamepadHandler->save();
|
|
|
|
}
|
2024-05-20 23:25:55 -04:00
|
|
|
|
|
|
|
QDialog::accept();
|
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
InputConfigButtonBase::InputConfigButtonBase(const QString &name, QWidget *parent) : QWidget(parent)
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
|
|
|
|
|
|
|
layout->addStretch();
|
|
|
|
|
|
|
|
QLabel *label = new QLabel(name, this);
|
|
|
|
layout->addWidget(label);
|
|
|
|
|
|
|
|
m_button = new QPushButton(this);
|
|
|
|
m_button->setCheckable(true);
|
2024-11-14 21:49:18 -05:00
|
|
|
connect(m_button, &QPushButton::clicked, this, &InputConfigButtonBase::buttonClicked);
|
|
|
|
connect(m_button, &QPushButton::toggled, this, &InputConfigButtonBase::toggled);
|
|
|
|
connect(m_button, &QPushButton::clicked, this, &InputConfigButtonBase::checked);
|
2024-05-20 23:25:55 -04:00
|
|
|
layout->addWidget(m_button);
|
|
|
|
|
|
|
|
layout->addStretch();
|
|
|
|
|
|
|
|
m_timer = new QTimer(this);
|
|
|
|
m_timer->setInterval(1000);
|
2024-11-14 21:49:18 -05:00
|
|
|
connect(m_timer, &QTimer::timeout, this, &InputConfigButtonBase::timerTimeout);
|
|
|
|
}
|
2024-05-20 23:25:55 -04:00
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
InputConfigKeyButton::InputConfigKeyButton(const QString &name, QWidget *parent) : InputConfigButtonBase(name, parent)
|
|
|
|
{
|
|
|
|
button()->installEventFilter(this);
|
2024-05-20 23:25:55 -04:00
|
|
|
m_key = Qt::Key_unknown;
|
|
|
|
buttonClicked(false);
|
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
void InputConfigKeyButton::setKey(Qt::Key key)
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
|
|
|
m_key = key;
|
|
|
|
buttonClicked(false);
|
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
void InputConfigButtonBase::buttonClicked(bool e)
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
|
|
|
if (e) {
|
|
|
|
m_timerState = 6;
|
|
|
|
m_timer->start();
|
|
|
|
timerTimeout();
|
|
|
|
} else {
|
|
|
|
m_timer->stop();
|
2024-11-14 21:49:18 -05:00
|
|
|
m_button->setText(text());
|
2024-05-20 23:25:55 -04:00
|
|
|
m_button->setChecked(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
void InputConfigButtonBase::setChecked(bool e)
|
|
|
|
{
|
|
|
|
m_button->setChecked(e);
|
|
|
|
buttonClicked(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString InputConfigKeyButton::text() const
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
2024-11-14 21:49:18 -05:00
|
|
|
return m_key == Qt::Key_unknown ? tr("<none>") : QKeySequence(m_key).toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InputConfigKeyButton::eventFilter(QObject *object, QEvent *event)
|
|
|
|
{
|
|
|
|
if (object == button() && button()->isChecked() && event->type() == QEvent::KeyPress) {
|
2024-05-20 23:25:55 -04:00
|
|
|
QKeyEvent *key = dynamic_cast<QKeyEvent *>(event);
|
|
|
|
if (key->key() == Qt::Key_Escape) {
|
|
|
|
// Don't set
|
|
|
|
buttonClicked(false);
|
|
|
|
} else if (key->key() == Qt::Key_Backspace) {
|
|
|
|
setKey(Qt::Key_unknown);
|
|
|
|
} else {
|
|
|
|
// Set whatever was pressed
|
|
|
|
setKey(static_cast<Qt::Key>(key->key()));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-11-14 21:49:18 -05:00
|
|
|
void InputConfigButtonBase::timerTimeout()
|
2024-05-20 23:25:55 -04:00
|
|
|
{
|
|
|
|
m_timerState--;
|
|
|
|
if (m_timerState == 0) {
|
|
|
|
buttonClicked(false);
|
|
|
|
} else {
|
|
|
|
m_button->setText(tr("Waiting for input (%1)\n<Backspace> to clear").arg(m_timerState));
|
|
|
|
}
|
2024-11-14 21:49:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
InputConfigControllerButton::InputConfigControllerButton(const QString &name, QWidget *parent) : InputConfigButtonBase(name, parent)
|
|
|
|
{
|
|
|
|
m_button = SDL_CONTROLLER_BUTTON_INVALID;
|
|
|
|
m_axis = SDL_CONTROLLER_AXIS_INVALID;
|
|
|
|
buttonClicked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString InputConfigControllerButton::text() const
|
|
|
|
{
|
|
|
|
if (m_button != SDL_CONTROLLER_BUTTON_INVALID) {
|
|
|
|
return SDL_GameControllerGetStringForButton(m_button);
|
|
|
|
} else if (m_axis != SDL_CONTROLLER_AXIS_INVALID) {
|
|
|
|
return SDL_GameControllerGetStringForAxis(m_axis);
|
|
|
|
}
|
|
|
|
return tr("<none>");
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigControllerButton::setButton(SDL_GameControllerButton button)
|
|
|
|
{
|
|
|
|
m_button = button;
|
|
|
|
m_axis = SDL_CONTROLLER_AXIS_INVALID;
|
|
|
|
buttonClicked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigControllerButton::setAxis(SDL_GameControllerAxis axis)
|
|
|
|
{
|
|
|
|
m_button = SDL_CONTROLLER_BUTTON_INVALID;
|
|
|
|
m_axis = axis;
|
|
|
|
buttonClicked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
InputConfigButtonBase *InputConfigDialog::findCheckedButton()
|
|
|
|
{
|
|
|
|
for (auto it = m_buttons.cbegin(); it != m_buttons.cend(); it++) {
|
|
|
|
InputConfigButtonBase *test = it->second;
|
|
|
|
if (test && test->isChecked()) {
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::setControllerAxis(SDL_GameControllerAxis axis)
|
|
|
|
{
|
|
|
|
if (InputConfigButtonBase *b = findCheckedButton()) {
|
|
|
|
InputConfigControllerButton *c = static_cast<InputConfigControllerButton *>(b);
|
|
|
|
c->setAxis(axis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::setControllerButton(SDL_GameControllerButton button)
|
|
|
|
{
|
|
|
|
if (InputConfigButtonBase *b = findCheckedButton()) {
|
|
|
|
InputConfigControllerButton *c = static_cast<InputConfigControllerButton *>(b);
|
|
|
|
c->setButton(button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::connectSoloSignals()
|
|
|
|
{
|
|
|
|
for (auto it = m_buttons.cbegin(); it != m_buttons.cend(); it++) {
|
|
|
|
InputConfigButtonBase *btn = it->second;
|
|
|
|
if (btn)
|
|
|
|
connect(btn, &InputConfigButtonBase::checked, this, &InputConfigDialog::buttonChecked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::uncheckAllExcept(InputConfigButtonBase *except)
|
|
|
|
{
|
|
|
|
for (auto it = m_buttons.cbegin(); it != m_buttons.cend(); it++) {
|
|
|
|
InputConfigButtonBase *b = it->second;
|
|
|
|
if (b && b != except) {
|
|
|
|
b->setChecked(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputConfigDialog::buttonChecked(bool e)
|
|
|
|
{
|
|
|
|
if (e) {
|
|
|
|
uncheckAllExcept(static_cast<InputConfigButtonBase *>(sender()));
|
|
|
|
}
|
2024-05-20 23:25:55 -04:00
|
|
|
}
|