Compare commits

...

15 Commits

Author SHA1 Message Date
Rosalie Wanders 541724b63c Package: v0.3.4 2023-02-11 19:48:49 +01:00
Rosalie Wanders 304afbb50d RMG-Input: add Input_FilterEventsFor{Buttons,Axis} settings 2023-02-11 19:47:12 +01:00
Rosalie Wanders 1ba88f48bb RMG-Core: add Input_FilterEventsFor{Buttons,Axis} settings 2023-02-11 19:46:00 +01:00
Rosalie Wanders 8f8c9c35f1 3rdParty: update GLideN64 2023-02-11 15:28:54 +01:00
Rosalie Wanders 1c07d032ef RMG-Input: account for added profiles in RevertSettings() 2023-02-11 15:18:44 +01:00
Rosalie Wanders c500a17b1a RMG-Input: implement reverting settings & improve saving 2023-02-11 14:33:30 +01:00
Rosalie Wanders 6d0347b48a RMG-Core: introduce CoreSettingsRevertSection() 2023-02-11 14:32:43 +01:00
Rosalie Wanders 83af0ff4af RMG-Input: improve per game profile handling 2023-02-11 13:41:26 +01:00
Rosalie Wanders 32c13eee1d RMG-Core: add Input_UseGameProfile setting 2023-02-11 13:40:50 +01:00
Rosalie Wanders 42597a76f0 RMG-Input: handle automatic input device in CheckInputDeviceSettings() 2023-02-11 13:09:32 +01:00
Rosalie Wanders 7c59a520aa RMG: improve updater script for windows 2023-02-10 21:23:25 +01:00
Rosalie Wanders 3c124d8519 RMG-Input: change size policy for top UI elements 2023-02-10 15:01:31 +01:00
Rosalie Wanders 76282a11da RMG-Input: use const wherever possible in main.cpp 2023-02-10 14:35:51 +01:00
Rosalie Wanders 5249bf6a56 RMG-Input: fix button mapping when having multiple mappings in get_axis_state() 2023-02-10 14:23:32 +01:00
Rosalie Wanders 12e0dac777 RMG-Input: store & use initial size in MappingButton 2023-02-10 13:45:31 +01:00
17 changed files with 397 additions and 93 deletions
@@ -33,6 +33,24 @@
</screenshots>
<description/>
<releases>
<release version="v0.3.4" date="2023-02-11" type="stable">
<description>
<p>Changes:</p>
<ul>
<li>Fix mapping button size increasing when reloading settings in RMG-Input</li>
<li>Fix analog stick mapping in-game when having buttons and axis bound in RMG-Input</li>
<li>Fix height mismatch of "Profile" and "Input Device" UI elements in RMG-Input</li>
<li>Fix updater script not using the correct path seperators on Windows</li>
<li>Fix GLideN64's per game settings being overwritten by the updater on windows (or not being updated on linux)</li>
<li>Fix "Automatic" input device not opening controller device when clicking on 'Refresh' in RMG-Input</li>
<li>Fix game specific profile having unexpected UI behavior in RMG-Input</li>
<li>Fix cancel and close button not working correctly in RMG-Input</li>
<li>Fix profile saving not working correctly when having the same profile selected for multiple players in RMG-Input</li>
<li>Add "Filter Events Based On Joystick Type For Buttons" setting to RMG-Input</li>
<li>Add "Filter Events Based On Joystick Type For Axis" setting to RMG-Input</li>
</ul>
</description>
</release>
<release version="v0.3.3" date="2023-02-09" type="stable">
<description>
<p>Changes:</p>
+2 -2
View File
@@ -57,8 +57,8 @@ if(NOT NO_GIT_CLONE)
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "158e74d4ec1c818289cd19c3a05e498c3ceff758")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "263a7bd2ca81759ece98209bd282a6c1173a129f")
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/Rosalie241/GLideN64")
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "698f5580249e2edf86fb89cd75d921535171074c")
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
set(MUPEN64PLUS_GFX_PARALLEL_TAG "48abaa5e082add7848e6f98648111c69c4a71632")
+30
View File
@@ -553,6 +553,9 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_UseProfile:
setting = {"", "UseProfile"};
break;
case SettingsID::Input_UseGameProfile:
setting = {"", "UseGameProfile"};
break;
case SettingsID::Input_PluggedIn:
setting = {"", "PluggedIn"};
break;
@@ -580,6 +583,12 @@ static l_Setting get_setting(SettingsID settingId)
case SettingsID::Input_RemoveDuplicateMappings:
setting = {"", "RemoveDuplicateMappings"};
break;
case SettingsID::Input_FilterEventsForButtons:
setting = {"", "FilterEventsForButtons"};
break;
case SettingsID::Input_FilterEventsForAxis:
setting = {"", "FilterEventsForAxis"};
break;
case SettingsID::Input_A_InputType:
setting = {"", "A_InputType"};
break;
@@ -1227,6 +1236,27 @@ bool CoreSettingsSectionExists(std::string section)
return config_section_exists(section);
}
bool CoreSettingsRevertSection(std::string section)
{
std::string error;
m64p_error ret;
if (!m64p::Config.IsHooked())
{
return false;
}
ret = m64p::Config.RevertChanges(section.c_str());
if (ret != M64ERR_SUCCESS)
{
error = "CoreSettingsRevertSection m64p::Config.RevertChanges() Failed: ";
error = m64p::Core.ErrorMessage(ret);
CoreSetError(error);
}
return ret == M64ERR_SUCCESS;
}
bool CoreSettingsDeleteSection(std::string section)
{
std::string error;
+3
View File
@@ -27,6 +27,9 @@ bool CoreSettingsSetupDefaults(void);
// returns whether a section exists
bool CoreSettingsSectionExists(std::string section);
// reverts section to the one from the settings
bool CoreSettingsRevertSection(std::string section);
// deletes given section
bool CoreSettingsDeleteSection(std::string section);
+4 -1
View File
@@ -25,7 +25,7 @@ enum class SettingsID
GUI_CheckForUpdates,
GUI_DiscordRpc,
GUI_Version,
// Core Plugin Settings
Core_GFX_Plugin,
Core_AUDIO_Plugin,
@@ -160,6 +160,7 @@ enum class SettingsID
// Input Plugin Settings
Input_Profiles,
Input_UseProfile,
Input_UseGameProfile,
Input_PluggedIn,
Input_DeviceType,
Input_DeviceName,
@@ -169,6 +170,8 @@ enum class SettingsID
Input_GameboyRom,
Input_GameboySave,
Input_RemoveDuplicateMappings,
Input_FilterEventsForButtons,
Input_FilterEventsForAxis,
Input_A_InputType,
Input_A_Name,
Input_A_Data,
+25 -7
View File
@@ -370,19 +370,37 @@ void MainDialog::on_EventFilter_KeyReleased(QKeyEvent *event)
SDL_PeepEvents(&sdlEvent, 1, SDL_ADDEVENT, 0, 0);
}
void MainDialog::on_buttonBox_clicked(QAbstractButton *button)
void MainDialog::accept(void)
{
QPushButton *pushButton = (QPushButton *)button;
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
Widget::ControllerWidget* controllerWidget;
int currentIndex = this->tabWidget->currentIndex();
if (pushButton == okButton)
for (int i = 0; i < this->controllerWidgets.count(); i++)
{
for (auto& controllerWidget : this->controllerWidgets)
if (i != currentIndex)
{
controllerWidget = this->controllerWidgets.at(currentIndex);
controllerWidget->SaveSettings();
}
CoreSettingsSave();
}
// the widget which has focus should be saved last
controllerWidget = this->controllerWidgets.at(currentIndex);
controllerWidget->SaveSettings();
CoreSettingsSave();
QDialog::accept();
}
void MainDialog::reject(void)
{
for (auto& controllerWidget : this->controllerWidgets)
{
controllerWidget->RevertSettings();
}
CoreSettingsSave();
QDialog::reject();
}
@@ -80,7 +80,8 @@ private slots:
void on_EventFilter_KeyPressed(QKeyEvent *);
void on_EventFilter_KeyReleased(QKeyEvent *);
void on_buttonBox_clicked(QAbstractButton *);
void accept(void) Q_DECL_OVERRIDE;
void reject(void) Q_DECL_OVERRIDE;
};
}
@@ -24,6 +24,8 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
this->gameboyRomLineEdit->setText(QString::fromStdString(settings.GameboyRom));
this->gameboySaveLineEdit->setText(QString::fromStdString(settings.GameboySave));
this->removeDuplicateMappingsCheckbox->setChecked(settings.RemoveDuplicateMappings);
this->filterEventsForButtonsCheckBox->setChecked(settings.FilterEventsForButtons);
this->filterEventsForAxisCheckBox->setChecked(settings.FilterEventsForAxis);
if (!CoreIsEmulationRunning() && !CoreIsEmulationPaused())
{
@@ -83,6 +85,8 @@ void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
this->settings.FilterEventsForButtons = this->filterEventsForButtonsCheckBox->isChecked();
this->settings.FilterEventsForAxis = this->filterEventsForAxisCheckBox->isChecked();
}
this->accept();
@@ -24,6 +24,8 @@ struct OptionsDialogSettings
// UI settings
bool RemoveDuplicateMappings = false;
bool FilterEventsForButtons = true;
bool FilterEventsForAxis = true;
};
namespace UserInterface
@@ -202,6 +202,20 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="filterEventsForButtonsCheckBox">
<property name="text">
<string>Filter Events Based On Joystick Type For Buttons</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="filterEventsForAxisCheckBox">
<property name="text">
<string>Filter Events Based On Joystick Type For Axis</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -302,6 +302,11 @@ bool ControllerWidget::isSectionUserProfile(QString section)
return section.contains("User Profile");
}
bool ControllerWidget::isSectionGameProfile(QString section)
{
return !this->isSectionUserProfile(section) && section.contains("Game");
}
void ControllerWidget::setPluggedIn(bool value)
{
QWidget* widgetList[] =
@@ -446,6 +451,12 @@ void ControllerWidget::CheckInputDeviceSettings()
(this->inputDeviceComboBox->itemText(deviceNumIndex).startsWith(QString::fromStdString(deviceName))))
{ // full match
this->inputDeviceComboBox->setCurrentIndex(deviceNumIndex);
// force-refresh automatic input device
if (deviceNum == (int)InputDeviceType::Automatic)
{
this->on_inputDeviceComboBox_currentIndexChanged(deviceNumIndex);
}
}
else if (deviceNameIndex != -1)
{ // name only match
@@ -507,11 +518,7 @@ void ControllerWidget::on_profileComboBox_currentIndexChanged(int value)
if (this->previousProfileComboBoxIndex < this->profileComboBox->count())
{
QString section = this->profileComboBox->itemData(this->previousProfileComboBoxIndex).toString();
// TODO: how to handle game specific profiles here?
if (!section.startsWith(this->settingsSection + " Game"))
{
this->SaveSettings(section);
}
this->SaveSettings(section);
}
}
@@ -558,6 +565,7 @@ void ControllerWidget::on_addProfileButton_clicked()
{
std::vector<std::string> profiles;
std::vector<std::string>::iterator profilesIter;
QString section;
// retrieve profiles from settings
profiles = CoreSettingsGetStringListValue(SettingsID::Input_Profiles);
@@ -590,16 +598,24 @@ void ControllerWidget::on_addProfileButton_clicked()
return;
}
section = this->getUserProfileSectionName(newProfile);
// add profile to UI
this->profileComboBox->addItem(newProfile, this->getUserProfileSectionName(newProfile));
this->profileComboBox->addItem(newProfile, section);
this->profileComboBox->setCurrentText(newProfile);
// add profile to settings
profiles.push_back(newProfile.toStdString());
CoreSettingsSetValue(SettingsID::Input_Profiles, profiles);
// update added profiles
if (!this->addedProfiles.contains(section))
{
this->addedProfiles.push_back(section);
}
// emit signal
emit this->UserProfileAdded(newProfile, this->getUserProfileSectionName(newProfile));
emit this->UserProfileAdded(newProfile, section);
}
void ControllerWidget::on_removeProfileButton_clicked()
@@ -623,12 +639,12 @@ void ControllerWidget::on_removeProfileButton_clicked()
QString currentSection = this->getCurrentSettingsSection();
// try to remove profile settings section when it exists
if (CoreSettingsSectionExists(currentSection.toStdString()) &&
!CoreSettingsDeleteSection(currentSection.toStdString()))
{ // show error when failed
this->showErrorMessage("CoreSettingsDeleteSection() Failed!", QString::fromStdString(CoreGetError()));
// add to removed profiles list (will be deleted later)
if (!this->removedProfiles.contains(currentSection))
{
this->removedProfiles.push_back(currentSection);
}
this->addedProfiles.removeAll(currentSection);
// if section is a user profile,
// also remove it from the profiles list
@@ -653,8 +669,15 @@ void ControllerWidget::on_removeProfileButton_clicked()
emit this->UserProfileRemoved(this->profileComboBox->currentText(), currentSection);
}
// change current index
this->profileComboBox->setCurrentIndex(0);
// switch back to main profile when deleting
// a per game profile
if (this->isSectionGameProfile(currentSection))
{
// ensure we don't save the game specific profile
// upon switching to the main profile
this->previousProfileComboBoxIndex = -1;
this->profileComboBox->setCurrentIndex(0);
}
}
void ControllerWidget::on_resetButton_clicked()
@@ -739,7 +762,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
if ((event->type == SDL_CONTROLLERBUTTONDOWN) ||
(event->type == SDL_CONTROLLERBUTTONUP))
{ // gamepad button
if (!this->isCurrentJoystickGameController)
if (!this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForButtons)
{
return;
}
@@ -752,7 +776,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
else
{ // joystick button
if (this->isCurrentJoystickGameController)
if (this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForButtons)
{
return;
}
@@ -853,7 +878,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
if (event->type == SDL_CONTROLLERAXISMOTION)
{ // gamepad axis
if (!this->isCurrentJoystickGameController)
if (!this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForAxis)
{
return;
}
@@ -867,7 +893,8 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
}
else
{ // joystick axis
if (this->isCurrentJoystickGameController)
if (this->isCurrentJoystickGameController &&
this->optionsDialogSettings.FilterEventsForAxis)
{
return;
}
@@ -1077,7 +1104,6 @@ void ControllerWidget::LoadSettings()
}
QString section = this->settingsSection;
QString gameSection;
std::vector<std::string> userProfiles;
// if the main profile section doesn't exist,
@@ -1095,26 +1121,33 @@ void ControllerWidget::LoadSettings()
if (CoreGetCurrentRomSettings(romSettings) &&
CoreGetCurrentRomHeader(romHeader))
{
gameSection = section + " Game " + QString::fromStdString(romSettings.MD5);
this->gameSection = section + " Game " + QString::fromStdString(romSettings.MD5);
// use internal rom name
QString internalName = QString::fromStdString(romHeader.Name);
// add game specific profile when
// it doesn't exist yet
int index = this->profileComboBox->findData(gameSection);
int index = this->profileComboBox->findData(this->gameSection);
if (index == -1)
{
this->profileComboBox->addItem(internalName, gameSection);
this->profileComboBox->addItem(internalName, this->gameSection);
}
// if a game specific section exists,
// select it in the profile combobox
// and use it to load the settings
if (CoreSettingsSectionExists(gameSection.toStdString()))
if (CoreSettingsSectionExists(this->gameSection.toStdString()))
{
this->profileComboBox->setCurrentText(internalName);
section = gameSection;
// check if the key 'UseGameProfile' exists,
// if it doesn't then use the profile,
// else check if it's true and use it
if (!CoreSettingsKeyExists(this->gameSection.toStdString(), "UseGameProfile") ||
CoreSettingsGetBoolValue(SettingsID::Input_UseGameProfile, this->gameSection.toStdString()))
{
this->profileComboBox->setCurrentText(internalName);
section = this->gameSection;
}
}
}
@@ -1145,10 +1178,27 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
std::string section = sectionQString.toStdString();
std::string useProfile;
// if the removed profiles contain
// the section, don't load it
if (this->removedProfiles.contains(sectionQString) &&
!this->addedProfiles.contains(sectionQString))
{
return;
}
// do nothing if the section doesn't exist
if (!CoreSettingsSectionExists(section))
{
return;
// fallback to main section for per game profiles
if (this->isSectionGameProfile(sectionQString))
{
sectionQString = this->settingsSection;
section = this->settingsSection.toStdString();
}
else
{
return;
}
}
// see if the profile contains the UseProfile setting,
@@ -1174,6 +1224,19 @@ void ControllerWidget::LoadSettings(QString sectionQString, bool loadUserProfile
this->optionsDialogSettings.GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
this->optionsDialogSettings.GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
// keep backwards compatibility with old profiles
if (CoreSettingsKeyExists(section, "FilterEventsForButtons") &&
CoreSettingsKeyExists(section, "FilterEventsForAxis"))
{
this->optionsDialogSettings.FilterEventsForButtons = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForButtons, section);
this->optionsDialogSettings.FilterEventsForAxis = CoreSettingsGetBoolValue(SettingsID::Input_FilterEventsForAxis, section);
}
else
{
this->optionsDialogSettings.FilterEventsForButtons = true;
this->optionsDialogSettings.FilterEventsForAxis = true;
}
for (auto& buttonSetting : this->buttonSettingMappings)
{
buttonSetting.button->Clear();
@@ -1234,6 +1297,8 @@ void ControllerWidget::SaveDefaultSettings()
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9);
CoreSettingsSetValue(SettingsID::Input_Pak, section, 0);
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, true);
CoreSettingsSetValue(SettingsID::Input_FilterEventsForButtons, section, true);
CoreSettingsSetValue(SettingsID::Input_FilterEventsForAxis, section, true);
for (auto& buttonSetting : this->buttonSettingMappings)
{
@@ -1242,8 +1307,6 @@ void ControllerWidget::SaveDefaultSettings()
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, std::vector<int>({ 0 }));
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, std::vector<int>({ 0 }));
}
CoreSettingsSave();
}
void ControllerWidget::SaveSettings()
@@ -1252,8 +1315,17 @@ void ControllerWidget::SaveSettings()
{
return;
}
this->SaveSettings(this->getCurrentSettingsSection());
// delete all removed profile sections
for (QString section : this->removedProfiles)
{
if (!this->addedProfiles.contains(section))
{
CoreSettingsDeleteSection(section.toStdString());
}
}
}
void ControllerWidget::SaveUserProfileSettings()
@@ -1289,6 +1361,18 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(SettingsID::Input_UseProfile, mainSettingsSection, std::string(""));
}
// when section is a game specific profile,
// make sure we tell it whether or not to use it
if (this->isSectionGameProfile(section))
{
CoreSettingsSetValue(SettingsID::Input_UseGameProfile, sectionStr, true);
}
else if (!this->gameSection.isEmpty() &&
CoreSettingsSectionExists(this->gameSection.toStdString()))
{
CoreSettingsSetValue(SettingsID::Input_UseGameProfile, this->gameSection.toStdString(), false);
}
this->GetCurrentInputDevice(deviceName, deviceNum, true);
CoreSettingsSetValue(SettingsID::Input_PluggedIn, sectionStr, this->IsPluggedIn());
@@ -1299,6 +1383,8 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(SettingsID::Input_GameboyRom, sectionStr, this->optionsDialogSettings.GameboyRom);
CoreSettingsSetValue(SettingsID::Input_GameboySave, sectionStr, this->optionsDialogSettings.GameboySave);
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, sectionStr, this->optionsDialogSettings.RemoveDuplicateMappings);
CoreSettingsSetValue(SettingsID::Input_FilterEventsForButtons, sectionStr, this->optionsDialogSettings.FilterEventsForButtons);
CoreSettingsSetValue(SettingsID::Input_FilterEventsForAxis, sectionStr, this->optionsDialogSettings.FilterEventsForAxis);
for (auto& buttonSetting : this->buttonSettingMappings)
{
@@ -1307,8 +1393,47 @@ void ControllerWidget::SaveSettings(QString section)
CoreSettingsSetValue(buttonSetting.dataSettingsId, sectionStr, buttonSetting.button->GetInputData());
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, sectionStr, buttonSetting.button->GetExtraInputData());
}
}
CoreSettingsSave();
void ControllerWidget::RevertSettings()
{
QList<QString> sections;
// add all sections from profile combobox
for (int i = 0; i < this->profileComboBox->count(); i++)
{
sections.push_back(this->profileComboBox->itemData(i).toString());
}
// add section with profiles list
sections.push_back("Rosalie's Mupen GUI - Input Plugin");
// add removed profile sections
for (QString section : this->removedProfiles)
{
// ensure it's unique
if (!this->addedProfiles.contains(section) &&
!sections.contains(section))
{
sections.push_back(section);
}
}
// revert each section
for (QString section : sections)
{
CoreSettingsRevertSection(section.toStdString());
}
// delete all sections for added profiles,
// which weren't deleted
for (QString section : this->addedProfiles)
{
if (!this->removedProfiles.contains(section))
{
CoreSettingsDeleteSection(section.toStdString());
}
}
}
void ControllerWidget::SetCurrentJoystickID(SDL_JoystickID joystickId)
@@ -36,13 +36,17 @@ class ControllerWidget : public QWidget, Ui::ControllerWidget
private:
bool initialized = false;
QString settingsSection;
QString gameSection;
OptionsDialogSettings optionsDialogSettings;
QList<QString> inputDeviceNameList;
MappingButton* currentButton = nullptr;
bool addMappingToButton = false;
QList<QString> removedProfiles;
QList<QString> addedProfiles;
struct buttonWidgetMapping
{
enum N64ControllerButton button;
@@ -82,9 +86,11 @@ private:
void removeDuplicates(MappingButton* button);
QString getCurrentSettingsSection();
QString getUserProfileSectionName(QString profile);
bool isSectionUserProfile(QString section);
bool isSectionGameProfile(QString section);
void setPluggedIn(bool value);
@@ -115,12 +121,14 @@ public:
void LoadSettings();
void LoadSettings(QString section, bool loadUserProfile = false);
void LoadUserProfileSettings();
void SaveDefaultSettings();
void SaveSettings();
void SaveUserProfileSettings();
void SaveSettings(QString section);
void RevertSettings();
void SetCurrentJoystickID(SDL_JoystickID joystickId);
void SetIsCurrentJoystickGameController(bool isGameController);
@@ -30,6 +30,12 @@
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QComboBox" name="profileComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@@ -37,6 +43,12 @@
</item>
<item>
<widget class="QPushButton" name="addProfileButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Add</string>
</property>
@@ -44,6 +56,12 @@
</item>
<item>
<widget class="QPushButton" name="removeProfileButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Remove</string>
</property>
@@ -80,7 +98,7 @@
<item>
<widget class="QComboBox" name="inputDeviceComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -93,7 +111,7 @@
<item>
<widget class="QPushButton" name="inputDeviceRefreshButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -128,7 +146,7 @@
<item>
<widget class="QSlider" name="deadZoneSlider">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -14,8 +14,10 @@ using namespace UserInterface::Widget;
MappingButton::MappingButton(QWidget* parent) : QPushButton(parent)
{
this->countDownTimer = new QTimer(this);
this->countDownTimer = new QTimer(this);
connect(this->countDownTimer, &QTimer::timeout, this, &MappingButton::on_countDownTimer_triggered);
this->initialSize = this->size();
}
MappingButton::~MappingButton()
@@ -223,7 +225,7 @@ void MappingButton::reloadText()
}
}
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->width());
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->initialSize.width());
// needed for spacing
if (elidedText.isEmpty())
@@ -36,6 +36,7 @@ struct MappingButtonInputDataType
class MappingButton : public QPushButton
{
private:
QSize initialSize;
QTimer* countDownTimer = nullptr;
ControllerWidget* controllerWidget = nullptr;
int currentCountDownNum = 0;
+55 -34
View File
@@ -183,13 +183,19 @@ static void load_settings(void)
}
// if game ID was retrieved,
// check if game section exists, if it does
// use that section instead of the main section
// check if game section exists,
// if it does, check if the 'UseGameProfile' key exists,
// if it doesn't then use the profile, else
// check if the value is true
if (!gameId.empty())
{
if (CoreSettingsSectionExists(gameSection))
{
section = gameSection;
if (!CoreSettingsKeyExists(gameSection, "UseGameProfile") ||
CoreSettingsGetBoolValue(SettingsID::Input_UseGameProfile, gameSection))
{
section = gameSection;
}
}
}
@@ -397,7 +403,7 @@ static void close_controllers(void)
}
}
static int get_button_state(InputProfile* profile, InputMapping* inputMapping)
static int get_button_state(InputProfile* profile, const InputMapping* inputMapping)
{
int state = 0;
@@ -439,9 +445,10 @@ static int get_button_state(InputProfile* profile, InputMapping* inputMapping)
}
// returns axis input scaled to the range [-1, 1]
static double get_axis_state(InputProfile* profile, InputMapping* inputMapping, int direction, double value)
static double get_axis_state(InputProfile* profile, const InputMapping* inputMapping, const int direction, const double value, bool& useButtonMapping)
{
int state = 0;
double axis_state = value;
bool button_state = false;
for (int i = 0; i < inputMapping->Count; i++)
{
@@ -452,8 +459,7 @@ static double get_axis_state(InputProfile* profile, InputMapping* inputMapping,
{
case InputType::GamepadButton:
{
int buttonState = SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
state |= buttonState;
button_state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);;
} break;
case InputType::GamepadAxis:
{
@@ -462,13 +468,12 @@ static double get_axis_state(InputProfile* profile, InputMapping* inputMapping,
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
axis_state = axis_value;
}
} break;
case InputType::JoystickButton:
{
int buttonState = SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
state |= buttonState;
button_state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);;
} break;
case InputType::JoystickAxis:
{
@@ -477,22 +482,37 @@ static double get_axis_state(InputProfile* profile, InputMapping* inputMapping,
{
axis_value = (axis_value / SDL_AXIS_PEAK);
axis_value = abs(axis_value) * direction;
return axis_value;
axis_state = axis_value;
}
} break;
case InputType::Keyboard:
{
state |= l_KeyboardState[data];
button_state |= l_KeyboardState[data];
} break;
default:
break;
}
}
}
return state ? direction : value;
// when a button has been mapped
// to an axis, we should prioritize
// the button when it's been pressed
if (button_state)
{
useButtonMapping = true;
return direction;
}
else if (!useButtonMapping)
{
return axis_state;
}
else
{
return value;
}
}
static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzone, double axisRange)
static double simulate_deadzone(const double n64InputAxis, const double maxAxis, const int deadzone, const double axisRange)
{
double axisAbsolute = std::abs(n64InputAxis);
@@ -510,12 +530,12 @@ static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzon
}
// Credit: MerryMage
static void simulate_octagon(double inputX, double inputY, double deadzoneFactor, int& outputX, int& outputY)
static void simulate_octagon(const double inputX, const double inputY, const double deadzoneFactor, int& outputX, int& outputY)
{
double maxAxis = N64_AXIS_PEAK;
double maxDiagonal = MAX_DIAGONAL_VALUE;
int deadzone = static_cast<int>(deadzoneFactor * N64_AXIS_PEAK);
double axisRange = maxAxis - deadzone;
const double maxAxis = N64_AXIS_PEAK;
const double maxDiagonal = MAX_DIAGONAL_VALUE;
const int deadzone = (int)(deadzoneFactor * N64_AXIS_PEAK);
const double axisRange = maxAxis - deadzone;
// scale to [-maxAxis, maxAxis]
double ax = inputX * maxAxis;
double ay = inputY * maxAxis;
@@ -539,18 +559,18 @@ static void simulate_octagon(double inputX, double inputY, double deadzoneFactor
// bound diagonals to an octagonal range [-69, 69]
if (ax != 0.0 && ay != 0.0)
{
double slope = ay / ax;
double edgex = copysign(maxAxis / (std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal), ax);
double edgey = copysign(std::min(std::abs(edgex * slope), maxAxis / (1.0 / std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal)), ay);
const double slope = ay / ax;
double edgex = std::copysign(maxAxis / (std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal), ax);
const double edgey = std::copysign(std::min(std::abs(edgex * slope), maxAxis / (1.0 / std::abs(slope) + (maxAxis - maxDiagonal) / maxDiagonal)), ay);
edgex = edgey / slope;
double scale = std::sqrt(edgex*edgex + edgey*edgey) / maxAxis;
const double scale = std::sqrt(edgex*edgex + edgey*edgey) / maxAxis;
ax *= scale;
ay *= scale;
}
outputX = static_cast<int>(ax);
outputY = static_cast<int>(ay);
outputX = (int)ax;
outputY = (int)ay;
}
static unsigned char data_crc(unsigned char *data, int length)
@@ -581,7 +601,7 @@ void sdl_init()
{
std::filesystem::path gameControllerDbPath;
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
{
if (!SDL_WasInit(subsystem))
{
@@ -598,7 +618,7 @@ void sdl_init()
void sdl_quit()
{
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
for (const int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_HAPTIC})
{
if (SDL_WasInit(subsystem))
{
@@ -804,7 +824,7 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
// check if device has been disconnected,
// if it has, try to open it again,
// only do this every 2 seconds to prevent lag
const auto currentTime = std::chrono::high_resolution_clock::now();
const auto currentTime = std::chrono::high_resolution_clock::now();
const int secondsPassed = std::chrono::duration_cast<std::chrono::seconds>(currentTime - profile->LastDeviceCheckTime).count();
if (secondsPassed >= 2)
{
@@ -840,10 +860,11 @@ EXPORT void CALL GetKeys(int Control, BUTTONS* Keys)
Keys->Z_TRIG = get_button_state(profile, &profile->Button_ZTrigger);
double inputX = 0, inputY = 0;
inputY = get_axis_state(profile, &profile->AnalogStick_Up, 1, inputY);
inputY = get_axis_state(profile, &profile->AnalogStick_Down, -1, inputY);
inputX = get_axis_state(profile, &profile->AnalogStick_Left, -1, inputX);
inputX = get_axis_state(profile, &profile->AnalogStick_Right, 1, inputX);
bool useButtonMapping = false;
inputY = get_axis_state(profile, &profile->AnalogStick_Up, 1, inputY, useButtonMapping);
inputY = get_axis_state(profile, &profile->AnalogStick_Down, -1, inputY, useButtonMapping);
inputX = get_axis_state(profile, &profile->AnalogStick_Left, -1, inputX, useButtonMapping);
inputX = get_axis_state(profile, &profile->AnalogStick_Right, 1, inputX, useButtonMapping);
int octagonX = 0, octagonY = 0;
simulate_octagon(
@@ -39,16 +39,40 @@ void InstallUpdateDialog::install(void)
QString appPath = QCoreApplication::applicationDirPath();
QString appPid = QString::number(QCoreApplication::applicationPid());
QString logPath = appPath + "/Cache/updater.log";
#ifdef _WIN32
// convert paths to use the right path seperator
this->temporaryDirectory = QDir::toNativeSeparators(this->temporaryDirectory);
fullFilePath = QDir::toNativeSeparators(fullFilePath);
appPath = QDir::toNativeSeparators(appPath);
logPath = QDir::toNativeSeparators(logPath);
// remove log file when it exists
QFile qLogFile(logPath);
if (qLogFile.exists())
{
qLogFile.remove();
}
QString outputToLogLine = " >> \"" + logPath + "\" 2>&1";
if (this->filename.endsWith(".exe"))
{
this->label->setText("Executing " + this->filename + "...");
QStringList scriptLines =
QStringList scriptLines =
{
"@echo off",
"taskkill /F /PID:" + appPid,
"\"" + fullFilePath + "\" /CLOSEAPPLICATIONS /SILENT /DIR=\"" + appPath + "\"",
"(",
" echo == Attemping to kill PID " + appPid + outputToLogLine,
" taskkill /F /PID:" + appPid + outputToLogLine,
" echo == Attemping to start \'" + fullFilePath + "\'" + outputToLogLine,
" \"" + fullFilePath + "\" /CLOSEAPPLICATIONS /NOCANCEL /SILENT /DIR=\"" + appPath + "\"" + outputToLogLine,
")",
"IF NOT ERRORLEVEL 0 (",
" start \"\" cmd /c \"echo Rosalie's Mupen GUI failed to update, check the updater.log file in the Cache directory for more information && pause\"",
")",
// remove temporary directory at last
"rmdir /S /Q \"" + this->temporaryDirectory + "\"",
};
this->writeAndRunScript(scriptLines);
@@ -77,20 +101,32 @@ void InstallUpdateDialog::install(void)
this->showErrorMessage("CoreUnzip() Failed!", QString::fromStdString(CoreGetError()));
this->reject();
return;
}
}
this->label->setText("Executing update script...");
this->progressBar->setValue(100);
#ifdef _WIN32
extractDirectory = QDir::toNativeSeparators(extractDirectory);
QStringList scriptLines =
{
"@echo off",
"del /F /Q \"" + fullFilePath + "\"",
"taskkill /F /PID:" + appPid,
"xcopy /S /Y /I \"" + extractDirectory + "\\*\" \"" + appPath + "/\"",
"start \"\" \"" + appPath + "\\RMG.exe\"",
"rmdir /S /Q \"" + this->temporaryDirectory + "\"",
"(",
" echo == Attempting to remove \'" + fullFilePath + "\'" + outputToLogLine,
" del /F /Q \"" + fullFilePath + "\"" + outputToLogLine,
" echo == Attemping to kill PID " + appPid + outputToLogLine,
" taskkill /F /PID:" + appPid + outputToLogLine,
" echo == Attemping to copy \'" + extractDirectory + "\' to \'" + appPath + "\'" + outputToLogLine,
" xcopy /S /Y /I \"" + extractDirectory + "\\*\" \"" + appPath + "\"" + outputToLogLine,
" echo == Attemping to start \'" + appPath + "\\RMG.exe\'" + outputToLogLine,
" start \"\" \"" + appPath + "\\RMG.exe\"" + outputToLogLine,
")",
"IF NOT ERRORLEVEL 0 (",
" start \"\" cmd /c \"echo Rosalie's Mupen GUI failed to update, check the updater.log file in the Cache directory for more information && pause\"",
")",
// remove temporary directory at last
"rmdir /S /Q \"" + this->temporaryDirectory + "\"",
};
this->writeAndRunScript(scriptLines);
#else // Linux