mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-25 08:04:01 +02:00
989 lines
34 KiB
C++
989 lines
34 KiB
C++
/*
|
|
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
|
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3.
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "ControllerWidget.hpp"
|
|
#include "UserInterface/OptionsDialog.hpp"
|
|
|
|
#include "common.hpp"
|
|
|
|
#include <RMG-Core/Core.hpp>
|
|
|
|
#include <QPixmap>
|
|
#include <QPainter>
|
|
#include <QResizeEvent>
|
|
#include <QSvgRenderer>
|
|
#include <QMessageBox>
|
|
#include <SDL.h>
|
|
#include <iostream>
|
|
|
|
using namespace UserInterface::Widget;
|
|
|
|
ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) : QWidget(parent)
|
|
{
|
|
this->setupUi(this);
|
|
|
|
// install eventFilter to all children and parents
|
|
this->installEventFilter(eventFilter);
|
|
for (auto& widget : this->children())
|
|
{
|
|
widget->installEventFilter(eventFilter);
|
|
}
|
|
QObject* parentObject = this->parent();
|
|
while (parentObject != nullptr)
|
|
{
|
|
parentObject->installEventFilter(eventFilter);
|
|
parentObject = parentObject->parent();
|
|
}
|
|
|
|
this->DrawControllerImage();
|
|
|
|
this->buttonWidgetMappings.append(
|
|
{
|
|
{ N64ControllerButton::A, this->aButton, },
|
|
{ N64ControllerButton::B, this->bButton, },
|
|
{ N64ControllerButton::Start, this->startButton },
|
|
{ N64ControllerButton::DpadUp, this->dpadUpButton },
|
|
{ N64ControllerButton::DpadDown, this->dpadDownButton },
|
|
{ N64ControllerButton::DpadLeft, this->dpadLeftButton },
|
|
{ N64ControllerButton::DpadRight, this->dpadRightButton },
|
|
{ N64ControllerButton::CButtonUp, this->cbuttonUpButton },
|
|
{ N64ControllerButton::CButtonDown, this->cbuttonDownButton },
|
|
{ N64ControllerButton::CButtonLeft, this->cbuttonLeftButton },
|
|
{ N64ControllerButton::CButtonRight, this->cbuttonRightButton },
|
|
{ N64ControllerButton::LeftTrigger, this->leftTriggerButton },
|
|
{ N64ControllerButton::RightTrigger, this->rightTriggerButton },
|
|
});
|
|
|
|
this->joystickWidgetMappings.append(
|
|
{
|
|
{ InputAxisDirection::Up, this->analogStickUpButton },
|
|
{ InputAxisDirection::Down, this->analogStickDownButton },
|
|
{ InputAxisDirection::Left, this->analogStickLeftButton },
|
|
{ InputAxisDirection::Right, this->analogStickRightButton },
|
|
});
|
|
|
|
this->buttonSettingMappings.append(
|
|
{
|
|
{ this->aButton, SettingsID::Input_A_InputType, SettingsID::Input_A_Name, SettingsID::Input_A_Data, SettingsID::Input_A_ExtraData },
|
|
{ this->bButton, SettingsID::Input_B_InputType, SettingsID::Input_B_Name, SettingsID::Input_B_Data, SettingsID::Input_B_ExtraData },
|
|
{ this->startButton, SettingsID::Input_Start_InputType, SettingsID::Input_Start_Name, SettingsID::Input_Start_Data, SettingsID::Input_Start_ExtraData },
|
|
{ this->dpadUpButton, SettingsID::Input_DpadUp_InputType, SettingsID::Input_DpadUp_Name, SettingsID::Input_DpadUp_Data, SettingsID::Input_DpadUp_ExtraData },
|
|
{ this->dpadDownButton, SettingsID::Input_DpadDown_InputType, SettingsID::Input_DpadDown_Name, SettingsID::Input_DpadDown_Data, SettingsID::Input_DpadDown_ExtraData },
|
|
{ this->dpadLeftButton, SettingsID::Input_DpadLeft_InputType, SettingsID::Input_DpadLeft_Name, SettingsID::Input_DpadLeft_Data, SettingsID::Input_DpadLeft_ExtraData },
|
|
{ this->dpadRightButton, SettingsID::Input_DpadRight_InputType, SettingsID::Input_DpadRight_Name, SettingsID::Input_DpadRight_Data, SettingsID::Input_DpadRight_ExtraData },
|
|
{ this->cbuttonUpButton, SettingsID::Input_CButtonUp_InputType, SettingsID::Input_CButtonUp_Name, SettingsID::Input_CButtonUp_Data, SettingsID::Input_CButtonUp_ExtraData },
|
|
{ this->cbuttonDownButton, SettingsID::Input_CButtonDown_InputType, SettingsID::Input_CButtonDown_Name, SettingsID::Input_CButtonDown_Data, SettingsID::Input_CButtonDown_ExtraData },
|
|
{ this->cbuttonLeftButton, SettingsID::Input_CButtonLeft_InputType, SettingsID::Input_CButtonLeft_Name, SettingsID::Input_CButtonLeft_Data, SettingsID::Input_CButtonLeft_ExtraData },
|
|
{ this->cbuttonRightButton, SettingsID::Input_CButtonRight_InputType, SettingsID::Input_CButtonRight_Name, SettingsID::Input_CButtonRight_Data, SettingsID::Input_CButtonRight_ExtraData },
|
|
{ this->leftTriggerButton, SettingsID::Input_LeftTrigger_InputType, SettingsID::Input_LeftTrigger_Name, SettingsID::Input_LeftTrigger_Data, SettingsID::Input_LeftTrigger_ExtraData },
|
|
{ this->rightTriggerButton, SettingsID::Input_RightTrigger_InputType, SettingsID::Input_RightTrigger_Name, SettingsID::Input_RightTrigger_Data, SettingsID::Input_RightTrigger_ExtraData },
|
|
{ this->zTriggerButton, SettingsID::Input_ZTrigger_InputType, SettingsID::Input_ZTrigger_Name, SettingsID::Input_ZTrigger_Data, SettingsID::Input_ZTrigger_ExtraData },
|
|
{ this->analogStickUpButton, SettingsID::Input_AnalogStickUp_InputType, SettingsID::Input_AnalogStickUp_Name, SettingsID::Input_AnalogStickUp_Data, SettingsID::Input_AnalogStickUp_ExtraData },
|
|
{ this->analogStickDownButton, SettingsID::Input_AnalogStickDown_InputType, SettingsID::Input_AnalogStickDown_Name, SettingsID::Input_AnalogStickDown_Data, SettingsID::Input_AnalogStickDown_ExtraData },
|
|
{ this->analogStickLeftButton, SettingsID::Input_AnalogStickLeft_InputType, SettingsID::Input_AnalogStickLeft_Name, SettingsID::Input_AnalogStickLeft_Data, SettingsID::Input_AnalogStickLeft_ExtraData },
|
|
{ this->analogStickRightButton, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData },
|
|
});
|
|
|
|
CustomButton* buttonList[] =
|
|
{
|
|
// dpad
|
|
this->dpadUpButton,
|
|
this->dpadDownButton,
|
|
this->dpadLeftButton,
|
|
this->dpadRightButton,
|
|
// analog stick
|
|
this->analogStickUpButton,
|
|
this->analogStickDownButton,
|
|
this->analogStickLeftButton,
|
|
this->analogStickRightButton,
|
|
// cbuttons
|
|
this->cbuttonUpButton,
|
|
this->cbuttonDownButton,
|
|
this->cbuttonLeftButton,
|
|
this->cbuttonRightButton,
|
|
// triggers
|
|
this->leftTriggerButton,
|
|
this->rightTriggerButton,
|
|
this->zTriggerButton,
|
|
// buttons
|
|
this->aButton,
|
|
this->bButton,
|
|
this->startButton,
|
|
};
|
|
for (auto& button : buttonList)
|
|
{
|
|
this->setupButtonWidgets.append(button);
|
|
}
|
|
|
|
|
|
this->initializeButtons();
|
|
}
|
|
|
|
ControllerWidget::~ControllerWidget()
|
|
{
|
|
|
|
}
|
|
|
|
void ControllerWidget::initializeButtons()
|
|
{
|
|
CustomButton* buttonList[] =
|
|
{
|
|
// dpad
|
|
this->dpadUpButton,
|
|
this->dpadDownButton,
|
|
this->dpadLeftButton,
|
|
this->dpadRightButton,
|
|
// analog stick
|
|
this->analogStickUpButton,
|
|
this->analogStickDownButton,
|
|
this->analogStickLeftButton,
|
|
this->analogStickRightButton,
|
|
// cbuttons
|
|
this->cbuttonUpButton,
|
|
this->cbuttonDownButton,
|
|
this->cbuttonLeftButton,
|
|
this->cbuttonRightButton,
|
|
// triggers
|
|
this->leftTriggerButton,
|
|
this->rightTriggerButton,
|
|
this->zTriggerButton,
|
|
// buttons
|
|
this->aButton,
|
|
this->bButton,
|
|
this->startButton,
|
|
};
|
|
|
|
for (auto& button : buttonList)
|
|
{
|
|
button->Initialize(this);
|
|
button->setText(" ");
|
|
}
|
|
}
|
|
|
|
bool ControllerWidget::isCurrentDeviceKeyboard()
|
|
{
|
|
return this->inputDeviceComboBox->currentIndex() == 0;
|
|
}
|
|
|
|
bool ControllerWidget::isCurrentDeviceNotFound()
|
|
{
|
|
QString title = this->inputDeviceComboBox->currentText();
|
|
return title.endsWith("(not found)");
|
|
}
|
|
|
|
void ControllerWidget::disableAllChildren()
|
|
{
|
|
for (auto& object : this->children())
|
|
{
|
|
if (!object->inherits("QWidget"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
QWidget* widget = (QWidget*)object;
|
|
if (widget->isEnabled())
|
|
{
|
|
widget->setEnabled(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::enableAllChildren()
|
|
{
|
|
for (auto& object : this->children())
|
|
{
|
|
if (!object->inherits("QWidget"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
QWidget* widget = (QWidget*)object;
|
|
if (!widget->isEnabled())
|
|
{
|
|
widget->setEnabled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::removeDuplicates(CustomButton* button)
|
|
{
|
|
std::string section = this->getCurrentSettingsSection().toStdString();
|
|
|
|
if (!CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, section))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (auto& buttonWidget : this->setupButtonWidgets)
|
|
{
|
|
// skip ourselfes
|
|
if (buttonWidget == button)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((buttonWidget->GetInputType() == button->GetInputType()) &&
|
|
(buttonWidget->GetInputData() == button->GetInputData()) &&
|
|
(buttonWidget->GetExtraInputData() == button->GetExtraInputData()))
|
|
{
|
|
buttonWidget->Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
QString ControllerWidget::getCurrentSettingsSection()
|
|
{
|
|
QString section;
|
|
|
|
if (this->profileComboBox->currentIndex() == 0)
|
|
{
|
|
section = this->settingsSection;
|
|
}
|
|
else
|
|
{
|
|
section = this->gameSettingsSection;
|
|
}
|
|
|
|
return section;
|
|
}
|
|
|
|
void ControllerWidget::AddInputDevice(QString deviceName, int deviceNum)
|
|
{
|
|
QString name = deviceName;
|
|
|
|
if (deviceNum != -1)
|
|
{
|
|
name += " (";
|
|
name += QString::number(deviceNum);
|
|
name += ")";
|
|
}
|
|
|
|
this->inputDeviceNameList.append(deviceName);
|
|
this->inputDeviceComboBox->addItem(name, deviceNum);
|
|
}
|
|
|
|
void ControllerWidget::RemoveInputDevice(QString deviceName, int deviceNum)
|
|
{
|
|
inputDeviceNameList.removeOne(deviceName);
|
|
|
|
for (int i = 0; i < this->inputDeviceComboBox->count(); i++)
|
|
{
|
|
int tmpNum = this->inputDeviceComboBox->itemData(i).toInt();
|
|
QString tmpName = this->inputDeviceComboBox->itemText(i);
|
|
|
|
if (tmpName.contains(deviceName) && deviceNum == tmpNum)
|
|
{
|
|
this->inputDeviceComboBox->removeItem(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::CheckInputDeviceSettings()
|
|
{
|
|
std::string section = this->settingsSection.toStdString();
|
|
|
|
if (!CoreSettingsSectionExists(section))
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::string deviceName = CoreSettingsGetStringValue(SettingsID::Input_DeviceName, section);
|
|
int deviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section);
|
|
|
|
// clear (not found) devices first
|
|
int notFoundIndex = this->inputDeviceComboBox->findText("(not found)", Qt::MatchFlag::MatchEndsWith);
|
|
if (notFoundIndex != -1)
|
|
{
|
|
this->inputDeviceNameList.removeAt(notFoundIndex);
|
|
this->inputDeviceComboBox->removeItem(notFoundIndex);
|
|
}
|
|
|
|
int deviceNameIndex = this->inputDeviceComboBox->findText(QString::fromStdString(deviceName), Qt::MatchFlag::MatchStartsWith);
|
|
int deviceNumIndex = this->inputDeviceComboBox->findData(deviceNum);
|
|
|
|
if ((deviceNameIndex == deviceNumIndex) &&
|
|
(deviceNameIndex != -1))
|
|
{ // full match
|
|
this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex);
|
|
}
|
|
else if (deviceNameIndex != -1)
|
|
{ // name only match
|
|
this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex);
|
|
}
|
|
else
|
|
{ // no match
|
|
QString title = QString::fromStdString(deviceName);
|
|
title += " (not found)";
|
|
this->inputDeviceNameList.append(QString::fromStdString(deviceName));
|
|
this->inputDeviceComboBox->addItem(title, deviceNum);
|
|
this->inputDeviceComboBox->setCurrentIndex(this->inputDeviceNameList.count() - 1);
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::DrawControllerImage()
|
|
{
|
|
this->controllerImageWidget->UpdateImage();
|
|
}
|
|
|
|
void ControllerWidget::ClearControllerImage()
|
|
{
|
|
this->controllerImageWidget->ClearControllerState();
|
|
}
|
|
|
|
void ControllerWidget::GetCurrentInputDevice(QString& deviceName, int& deviceNum, bool ignoreDeviceNotFound)
|
|
{
|
|
int currentIndex = this->inputDeviceComboBox->currentIndex();
|
|
|
|
if (this->isCurrentDeviceNotFound() && !ignoreDeviceNotFound)
|
|
{
|
|
deviceName = "";
|
|
deviceNum = -1;
|
|
}
|
|
else
|
|
{
|
|
deviceName = this->inputDeviceNameList.at(currentIndex);
|
|
deviceNum = this->inputDeviceComboBox->itemData(currentIndex).toInt();
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::on_deadZoneSlider_valueChanged(int value)
|
|
{
|
|
QString title = tr("Deadzone: ");
|
|
title += QString::number(value);
|
|
title += "%";
|
|
|
|
this->deadZoneGroupBox->setTitle(title);
|
|
this->controllerImageWidget->SetDeadzone(value);
|
|
}
|
|
|
|
void ControllerWidget::on_analogStickRangeSlider_valueChanged(int value)
|
|
{
|
|
QString text = QString::number(value);
|
|
text += "%";
|
|
this->analogStickRangeLabel->setText(text);
|
|
this->controllerImageWidget->SetRange(value);
|
|
}
|
|
|
|
void ControllerWidget::on_profileComboBox_currentIndexChanged(int value)
|
|
{
|
|
this->LoadSettings(this->getCurrentSettingsSection());
|
|
}
|
|
|
|
void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
|
|
{
|
|
QString deviceName = this->inputDeviceNameList.at(value);
|
|
int deviceNum = this->inputDeviceComboBox->itemData(value).toInt();
|
|
|
|
this->ClearControllerImage();
|
|
|
|
if (this->isCurrentDeviceNotFound())
|
|
{
|
|
deviceName = "";
|
|
deviceNum = -1;
|
|
}
|
|
|
|
emit this->CurrentInputDeviceChanged(this, deviceName, deviceNum);
|
|
}
|
|
|
|
void ControllerWidget::on_inputDeviceRefreshButton_clicked()
|
|
{
|
|
emit this->RefreshInputDevicesButtonClicked();
|
|
}
|
|
|
|
void ControllerWidget::on_controllerPluggedCheckBox_toggled(bool value)
|
|
{
|
|
QWidget* widgetList[] =
|
|
{
|
|
// dpad
|
|
this->dpadUpButton,
|
|
this->dpadDownButton,
|
|
this->dpadLeftButton,
|
|
this->dpadRightButton,
|
|
// analog stick
|
|
this->analogStickUpButton,
|
|
this->analogStickDownButton,
|
|
this->analogStickLeftButton,
|
|
this->analogStickRightButton,
|
|
this->analogStickRangeSlider,
|
|
// cbuttons
|
|
this->cbuttonUpButton,
|
|
this->cbuttonDownButton,
|
|
this->cbuttonLeftButton,
|
|
this->cbuttonRightButton,
|
|
// triggers
|
|
this->leftTriggerButton,
|
|
this->rightTriggerButton,
|
|
this->zTriggerButton,
|
|
// buttons
|
|
this->aButton,
|
|
this->bButton,
|
|
this->startButton,
|
|
// misc UI elements
|
|
this->deadZoneSlider,
|
|
this->optionsButton,
|
|
//this->setupButton,
|
|
this->resetButton,
|
|
this->inputDeviceComboBox,
|
|
this->inputDeviceRefreshButton
|
|
};
|
|
|
|
for (auto& widget : widgetList)
|
|
{
|
|
widget->setEnabled(value);
|
|
}
|
|
|
|
this->ClearControllerImage();
|
|
}
|
|
|
|
void ControllerWidget::on_removeProfileButton_clicked()
|
|
{
|
|
bool ret;
|
|
|
|
if (this->profileComboBox->currentIndex() == 0)
|
|
{
|
|
QMessageBox messageBox(this);
|
|
messageBox.setIcon(QMessageBox::Icon::Critical);
|
|
messageBox.setWindowTitle("Error");
|
|
messageBox.setText("Cannot remove main profile!");
|
|
messageBox.addButton(QMessageBox::Ok);
|
|
messageBox.exec();
|
|
return;
|
|
}
|
|
|
|
// reset profile to main profile
|
|
this->profileComboBox->setCurrentIndex(0);
|
|
// try to remove game settings section
|
|
ret = CoreSettingsDeleteSection(this->gameSettingsSection.toStdString());
|
|
if (!ret)
|
|
{ // show error when failed
|
|
QMessageBox messageBox(this);
|
|
messageBox.setIcon(QMessageBox::Icon::Critical);
|
|
messageBox.setWindowTitle("Error");
|
|
messageBox.setText("CoreSettingsDeleteSection() Failed!");
|
|
messageBox.setDetailedText(QString::fromStdString(CoreGetError()));
|
|
messageBox.addButton(QMessageBox::Ok);
|
|
messageBox.exec();
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::on_setupButton_clicked()
|
|
{
|
|
this->currentInSetup = true;
|
|
this->currentSetupButtonWidgetIndex = 0;
|
|
|
|
this->setupButtonWidgets.at(0)->setFocus(Qt::OtherFocusReason);
|
|
this->setupButtonWidgets.at(0)->click();
|
|
}
|
|
|
|
void ControllerWidget::on_resetButton_clicked()
|
|
{
|
|
this->LoadSettings();
|
|
}
|
|
|
|
void ControllerWidget::on_optionsButton_clicked()
|
|
{
|
|
OptionsDialog dialog(this, this->settingsSection, this->getCurrentSettingsSection());
|
|
dialog.exec();
|
|
}
|
|
|
|
void ControllerWidget::on_CustomButton_released(CustomButton* button)
|
|
{
|
|
if (this->currentButton != nullptr)
|
|
{
|
|
this->currentButton->StopTimer();
|
|
this->currentButton->RestoreState();
|
|
}
|
|
|
|
this->currentButton = button;
|
|
button->SaveState();
|
|
button->StartTimer();
|
|
|
|
this->disableAllChildren();
|
|
}
|
|
|
|
void ControllerWidget::on_CustomButton_TimerFinished(CustomButton* button)
|
|
{
|
|
if (this->currentButton == button)
|
|
{
|
|
this->currentButton = nullptr;
|
|
}
|
|
|
|
button->RestoreState();
|
|
|
|
this->enableAllChildren();
|
|
}
|
|
|
|
void ControllerWidget::on_CustomButton_DataSet(CustomButton* button)
|
|
{
|
|
this->enableAllChildren();
|
|
this->removeDuplicates(button);
|
|
this->currentButton = nullptr;
|
|
|
|
|
|
/*
|
|
if (this->currentInSetup)
|
|
{
|
|
if (this->currentSetupButtonWidgetIndex + 1 >= this->setupButtonWidgets.count())
|
|
{
|
|
this->currentInSetup = false;
|
|
return;
|
|
}
|
|
|
|
this->currentSetupButtonWidgetIndex++;
|
|
this->setupButtonWidgets.at(currentSetupButtonWidgetIndex)->setFocus(Qt::OtherFocusReason);
|
|
this->setupButtonWidgets.at(currentSetupButtonWidgetIndex)->click();
|
|
}*/
|
|
}
|
|
|
|
void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case SDL_CONTROLLERBUTTONDOWN:
|
|
case SDL_CONTROLLERBUTTONUP:
|
|
case SDL_JOYBUTTONDOWN:
|
|
case SDL_JOYBUTTONUP:
|
|
{ // gamepad & joystick button
|
|
SDL_JoystickID joystickId = -1;
|
|
InputType inputType = InputType::Invalid;
|
|
int sdlButton = 0;
|
|
bool sdlButtonPressed = false;
|
|
QString sdlButtonName;
|
|
|
|
if ((event->type == SDL_CONTROLLERBUTTONDOWN) ||
|
|
(event->type == SDL_CONTROLLERBUTTONUP))
|
|
{ // gamepad button
|
|
joystickId = event->cbutton.which;
|
|
inputType = InputType::GamepadButton;
|
|
sdlButton = event->cbutton.button;
|
|
sdlButtonPressed = (event->type == SDL_CONTROLLERBUTTONDOWN);
|
|
sdlButtonName = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)sdlButton);
|
|
}
|
|
else
|
|
{ // joystick button
|
|
joystickId = event->jbutton.which;
|
|
inputType = InputType::JoystickButton;
|
|
sdlButton = event->jbutton.button;
|
|
sdlButtonPressed = (event->type == SDL_JOYBUTTONDOWN);
|
|
sdlButtonName = "button " + QString::number(sdlButton);
|
|
}
|
|
|
|
// make sure we have the right joystick
|
|
if (joystickId != this->currentJoystickId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// handle button widget
|
|
if (this->currentButton != nullptr)
|
|
{
|
|
if (sdlButtonPressed)
|
|
{
|
|
this->currentButton->SetInputData(
|
|
inputType,
|
|
sdlButton,
|
|
0,
|
|
sdlButtonName
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// update controller button state
|
|
for (auto& button : this->buttonWidgetMappings)
|
|
{
|
|
if (button.buttonWidget->GetInputType() == inputType &&
|
|
button.buttonWidget->GetInputData() == sdlButton)
|
|
{
|
|
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
|
|
}
|
|
}
|
|
|
|
// update controller analog stick state
|
|
for (auto& joystick : this->joystickWidgetMappings)
|
|
{
|
|
if (joystick.buttonWidget->GetInputType() == inputType &&
|
|
joystick.buttonWidget->GetInputData() == sdlButton)
|
|
{
|
|
switch (joystick.direction)
|
|
{
|
|
case InputAxisDirection::Up:
|
|
case InputAxisDirection::Down:
|
|
{
|
|
const int value = (
|
|
joystick.direction == InputAxisDirection::Up ?
|
|
100 :
|
|
-100
|
|
);
|
|
this->controllerImageWidget->SetYAxisState(sdlButtonPressed ? value : 0);
|
|
} break;
|
|
|
|
case InputAxisDirection::Left:
|
|
case InputAxisDirection::Right:
|
|
{
|
|
const int value = (
|
|
joystick.direction == InputAxisDirection::Left ?
|
|
100 :
|
|
-100
|
|
);
|
|
this->controllerImageWidget->SetXAxisState(sdlButtonPressed ? value : 0);
|
|
} break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case SDL_CONTROLLERAXISMOTION:
|
|
case SDL_JOYAXISMOTION:
|
|
{ // gamepad & joystick axis
|
|
SDL_JoystickID joystickId = -1;
|
|
InputType inputType = InputType::Invalid;
|
|
int sdlAxis = 0;
|
|
int sdlAxisValue = 0;
|
|
QString sdlAxisName;
|
|
|
|
if (event->type == SDL_CONTROLLERAXISMOTION)
|
|
{ // gamepad axis
|
|
joystickId = event->caxis.which;
|
|
inputType = InputType::GamepadAxis;
|
|
sdlAxis = event->caxis.axis;
|
|
sdlAxisValue = event->caxis.value;
|
|
sdlAxisName = SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)sdlAxis);
|
|
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
|
|
}
|
|
else
|
|
{ // joystick axis
|
|
joystickId = event->jaxis.which;
|
|
inputType = InputType::JoystickAxis;
|
|
sdlAxis = event->jaxis.axis;
|
|
sdlAxisValue = event->jaxis.value;
|
|
sdlAxisName = "axis " + QString::number(sdlAxis);
|
|
sdlAxisName += sdlAxisValue > 0 ? "+" : "-";
|
|
}
|
|
|
|
// make sure the user presses the axis
|
|
// more than 50%, otherwise we might detect
|
|
// an accidental axis movement (due to i.e deadzone)
|
|
const bool sdlAxisButtonPressed = (abs(sdlAxisValue) >= (SDL_AXIS_PEAK / 2));
|
|
const int sdlAxisDirection = (sdlAxisValue > 0 ? 1 : 0);
|
|
|
|
// make sure we have the right joystick
|
|
if (joystickId != this->currentJoystickId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// handle button widget
|
|
if (this->currentButton != nullptr)
|
|
{
|
|
if (sdlAxisButtonPressed)
|
|
{
|
|
this->currentButton->SetInputData(
|
|
inputType,
|
|
sdlAxis,
|
|
sdlAxisDirection,
|
|
sdlAxisName
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// update controller button state
|
|
for (auto& button : this->buttonWidgetMappings)
|
|
{
|
|
if (button.buttonWidget->GetInputType() == inputType &&
|
|
button.buttonWidget->GetInputData() == sdlAxis &&
|
|
button.buttonWidget->GetExtraInputData() == sdlAxisDirection)
|
|
{
|
|
this->controllerImageWidget->SetButtonState(button.button, sdlAxisButtonPressed);
|
|
}
|
|
}
|
|
|
|
// update controller analog stick state
|
|
for (auto& joystick : this->joystickWidgetMappings)
|
|
{
|
|
if (joystick.buttonWidget->GetInputType() == inputType &&
|
|
joystick.buttonWidget->GetInputData() == sdlAxis &&
|
|
joystick.buttonWidget->GetExtraInputData() == sdlAxisDirection)
|
|
{
|
|
const int value = -(double)((double)sdlAxisValue / SDL_AXIS_PEAK * 100);
|
|
|
|
switch (joystick.direction)
|
|
{
|
|
case InputAxisDirection::Up:
|
|
case InputAxisDirection::Down:
|
|
{
|
|
this->controllerImageWidget->SetYAxisState(value);
|
|
} break;
|
|
|
|
case InputAxisDirection::Left:
|
|
case InputAxisDirection::Right:
|
|
{
|
|
this->controllerImageWidget->SetXAxisState(value);
|
|
} break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case SDL_KEYDOWN:
|
|
case SDL_KEYUP:
|
|
{ // keyboard button
|
|
|
|
// make sure a keyboard is selected
|
|
if (!this->isCurrentDeviceKeyboard())
|
|
{
|
|
break;
|
|
}
|
|
|
|
const SDL_Scancode sdlButton = (SDL_Scancode)event->key.keysym.scancode;
|
|
const bool sdlButtonPressed = (event->type == SDL_KEYDOWN);
|
|
|
|
// handle button widget
|
|
if (this->currentButton != nullptr)
|
|
{
|
|
if (sdlButtonPressed)
|
|
{
|
|
this->currentButton->SetInputData(
|
|
InputType::Keyboard,
|
|
sdlButton,
|
|
0,
|
|
SDL_GetScancodeName(sdlButton)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// update controller button state
|
|
for (auto& button : this->buttonWidgetMappings)
|
|
{
|
|
if (button.buttonWidget->GetInputType() == InputType::Keyboard &&
|
|
button.buttonWidget->GetInputData() == sdlButton)
|
|
{
|
|
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
|
|
}
|
|
}
|
|
|
|
// update controller analog stick state
|
|
for (auto& joystick : this->joystickWidgetMappings)
|
|
{
|
|
if (joystick.buttonWidget->GetInputType() == InputType::Keyboard &&
|
|
joystick.buttonWidget->GetInputData() == sdlButton)
|
|
{
|
|
switch (joystick.direction)
|
|
{
|
|
case InputAxisDirection::Up:
|
|
case InputAxisDirection::Down:
|
|
{
|
|
const int value = (
|
|
joystick.direction == InputAxisDirection::Up ?
|
|
100 :
|
|
-100
|
|
);
|
|
this->controllerImageWidget->SetYAxisState(sdlButtonPressed ? value : 0);
|
|
} break;
|
|
|
|
case InputAxisDirection::Left:
|
|
case InputAxisDirection::Right:
|
|
{
|
|
const int value = (
|
|
joystick.direction == InputAxisDirection::Left ?
|
|
100 :
|
|
-100
|
|
);
|
|
this->controllerImageWidget->SetXAxisState(sdlButtonPressed ? value : 0);
|
|
} break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::on_MainDialog_SdlEventPollFinished()
|
|
{
|
|
this->controllerImageWidget->UpdateImage();
|
|
}
|
|
|
|
bool ControllerWidget::IsPluggedIn()
|
|
{
|
|
return this->controllerPluggedCheckBox->isChecked();
|
|
}
|
|
|
|
void ControllerWidget::SetSettingsSection(QString section)
|
|
{
|
|
this->settingsSection = section;
|
|
}
|
|
|
|
void ControllerWidget::LoadSettings()
|
|
{
|
|
if (this->settingsSection.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
QString section = this->settingsSection;
|
|
QString gameSection;
|
|
|
|
// if the main profile section doesn't exist,
|
|
// save default settings
|
|
if (!CoreSettingsSectionExists(section.toStdString()))
|
|
{
|
|
this->SaveDefaultSettings();
|
|
}
|
|
|
|
// try to retrieve the current rom's settings,
|
|
// if that succeeds, we know we're ingame
|
|
// and then we'll add a game specific profile to the combobox
|
|
CoreRomSettings romSettings;
|
|
CoreRomHeader romHeader;
|
|
if (CoreGetCurrentRomSettings(romSettings))
|
|
{
|
|
gameSection = section + " Game " + QString::fromStdString(romSettings.MD5);
|
|
this->gameSettingsSection = gameSection;
|
|
|
|
QString goodName = QString::fromStdString(romSettings.GoodName);
|
|
if (goodName.contains("(unknown rom)"))
|
|
{
|
|
|
|
if (CoreGetCurrentRomHeader(romHeader))
|
|
{ // only set to internal rom name when retrieving header succeeds
|
|
goodName = QString::fromStdString(romHeader.Name);
|
|
}
|
|
}
|
|
|
|
// add game specific profile
|
|
this->profileComboBox->addItem(goodName);
|
|
|
|
// if a game specific section exists,
|
|
// select it in the profile combobox
|
|
// and use it to load the settings
|
|
if (CoreSettingsSectionExists(gameSection.toStdString()))
|
|
{
|
|
this->profileComboBox->setCurrentText(goodName);
|
|
section = gameSection;
|
|
}
|
|
}
|
|
|
|
this->LoadSettings(section);
|
|
}
|
|
|
|
void ControllerWidget::LoadSettings(QString sectionQString)
|
|
{
|
|
std::string section = sectionQString.toStdString();
|
|
|
|
// do nothing if the section doesn't exist
|
|
if (!CoreSettingsSectionExists(section))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->controllerPluggedCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section));
|
|
this->analogStickRangeSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Range, section));
|
|
this->deadZoneSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section));
|
|
|
|
for (auto& buttonSetting : this->buttonSettingMappings)
|
|
{
|
|
enum InputType type = (InputType)CoreSettingsGetIntValue(buttonSetting.inputTypeSettingsId, section);
|
|
std::string name = CoreSettingsGetStringValue(buttonSetting.nameSettingsId, section);
|
|
int data = CoreSettingsGetIntValue(buttonSetting.dataSettingsId, section);
|
|
int extraData = CoreSettingsGetIntValue(buttonSetting.extraDataSettingsId, section);
|
|
|
|
buttonSetting.button->SetInputData(type, data, extraData, QString::fromStdString(name));
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::SaveDefaultSettings()
|
|
{
|
|
if (this->settingsSection.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::string section = this->settingsSection.toStdString();
|
|
|
|
CoreSettingsSetValue(SettingsID::Input_PluggedIn, section, false);
|
|
CoreSettingsSetValue(SettingsID::Input_DeviceName, section, std::string("Keyboard"));
|
|
CoreSettingsSetValue(SettingsID::Input_DeviceNum, section, -1);
|
|
CoreSettingsSetValue(SettingsID::Input_Range, section, 100);
|
|
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 15);
|
|
CoreSettingsSetValue(SettingsID::Input_Pak, section, 0);
|
|
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, true);
|
|
|
|
for (auto& buttonSetting : this->buttonSettingMappings)
|
|
{
|
|
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)InputType::Invalid);
|
|
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, std::string(" "));
|
|
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, 0);
|
|
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, 0);
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::SaveSettings()
|
|
{
|
|
if (this->settingsSection.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
QString deviceName;
|
|
int deviceNum;
|
|
std::string section = this->getCurrentSettingsSection().toStdString();
|
|
|
|
// when a game specific profile has been selected,
|
|
// and the section doesn't exist yet,
|
|
// copy 2 missing settings from the main section
|
|
if (section == this->gameSettingsSection.toStdString() &&
|
|
!CoreSettingsSectionExists(section))
|
|
{
|
|
std::string mainSection = this->settingsSection.toStdString();
|
|
|
|
// copy settings from main profile section
|
|
CoreSettingsSetValue(SettingsID::Input_Pak, section, CoreSettingsGetIntValue(SettingsID::Input_Pak, mainSection));
|
|
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, mainSection));
|
|
}
|
|
|
|
this->GetCurrentInputDevice(deviceName, deviceNum, true);
|
|
|
|
CoreSettingsSetValue(SettingsID::Input_PluggedIn, section, this->IsPluggedIn());
|
|
CoreSettingsSetValue(SettingsID::Input_DeviceName, section, deviceName.toStdString());
|
|
CoreSettingsSetValue(SettingsID::Input_DeviceNum, section, deviceNum);
|
|
CoreSettingsSetValue(SettingsID::Input_Range, section, this->analogStickRangeSlider->value());
|
|
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, this->deadZoneSlider->value());
|
|
|
|
for (auto& buttonSetting : this->buttonSettingMappings)
|
|
{
|
|
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)buttonSetting.button->GetInputType());
|
|
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, buttonSetting.button->text().toStdString());
|
|
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, buttonSetting.button->GetInputData());
|
|
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, buttonSetting.button->GetExtraInputData());
|
|
}
|
|
}
|
|
|
|
void ControllerWidget::SetCurrentJoystickID(SDL_JoystickID joystickId)
|
|
{
|
|
this->currentJoystickId = joystickId;
|
|
}
|
|
|