diff --git a/pcsx2-qt/CMakeLists.txt b/pcsx2-qt/CMakeLists.txt index c63d80bd30a8b..758d1024e3531 100644 --- a/pcsx2-qt/CMakeLists.txt +++ b/pcsx2-qt/CMakeLists.txt @@ -75,6 +75,7 @@ target_sources(pcsx2-qt PRIVATE Settings/ControllerGlobalSettingsWidget.ui Settings/ControllerMacroEditWidget.ui Settings/ControllerMacroWidget.ui + Settings/ControllerMappingSettingsDialog.ui Settings/ControllerMouseSettingsDialog.ui Settings/ControllerSettingsWindow.cpp Settings/ControllerSettingsWindow.h diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp index 85b2d1a89d8d7..1537a5db838da 100644 --- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp +++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #include "Settings/ControllerGlobalSettingsWidget.h" @@ -40,7 +40,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent, #ifdef _WIN32 SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableXInputSource, "InputSources", "XInput", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableDInputSource, "InputSources", "DInput", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreDInputInversion, "InputSources", "IgnoreDInputInversion", false); #else m_ui.mainLayout->removeWidget(m_ui.xinputGroup); m_ui.xinputGroup->deleteLater(); @@ -176,3 +175,19 @@ ControllerMouseSettingsDialog::ControllerMouseSettingsDialog(QWidget* parent, Co } ControllerMouseSettingsDialog::~ControllerMouseSettingsDialog() = default; + +ControllerMappingSettingsDialog::ControllerMappingSettingsDialog(ControllerSettingsWindow* parent) + : QDialog(parent) +{ + m_ui.setupUi(this); + + SettingsInterface* sif = parent->getProfileSettingsInterface(); + + m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("settings-3-line")).pixmap(32, 32)); + + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreInversion, "InputSources", "IgnoreInversion", false); + + connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept); +} + +ControllerMappingSettingsDialog::~ControllerMappingSettingsDialog() = default; diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h index b40a05aa44635..2ad191c166c5f 100644 --- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h +++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #pragma once @@ -12,6 +12,7 @@ #include "ui_ControllerGlobalSettingsWidget.h" #include "ui_ControllerLEDSettingsDialog.h" +#include "ui_ControllerMappingSettingsDialog.h" #include "ui_ControllerMouseSettingsDialog.h" class ControllerSettingsWindow; @@ -66,3 +67,15 @@ class ControllerMouseSettingsDialog : public QDialog private: Ui::ControllerMouseSettingsDialog m_ui; }; + +class ControllerMappingSettingsDialog : public QDialog +{ + Q_OBJECT + +public: + ControllerMappingSettingsDialog(ControllerSettingsWindow* parent); + ~ControllerMappingSettingsDialog(); + +private: + Ui::ControllerMappingSettingsDialog m_ui; +}; diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui index 36c4856d91896..9a3f7dc4ae0b0 100644 --- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui +++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui @@ -82,16 +82,6 @@ - - - - <html><head/><body><p>Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.</p><p>As a result, the analog stick will be &quot;stuck on&quot; even while resting at neutral position. </p><p>Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.</p></body></html> - - - Ignore Inversion - - - diff --git a/pcsx2-qt/Settings/ControllerMappingSettingsDialog.ui b/pcsx2-qt/Settings/ControllerMappingSettingsDialog.ui new file mode 100644 index 0000000000000..24dde602fff99 --- /dev/null +++ b/pcsx2-qt/Settings/ControllerMappingSettingsDialog.ui @@ -0,0 +1,105 @@ + + + ControllerMappingSettingsDialog + + + + 0 + 0 + 654 + 275 + + + + Controller Mapping Settings + + + + + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + <html><head/><body><p><span style=" font-weight:700;">Controller Mapping Settings</span><br/>These settings fine-tune the behavior when mapping physical controllers to the emulated controllers.</p></body></html> + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + + + + + Ignore Inversion + + + + + + + <html><head/><body><p>Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.</p><p>As a result, the analog stick will be &quot;stuck on&quot; even while resting at neutral position. </p><p>Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.</p></body></html> + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 28 + + + + + + + + QDialogButtonBox::Close + + + + + + + + + + diff --git a/pcsx2-qt/Settings/ControllerSettingsWindow.cpp b/pcsx2-qt/Settings/ControllerSettingsWindow.cpp index 97921494257bd..9416a9eca2f72 100644 --- a/pcsx2-qt/Settings/ControllerSettingsWindow.cpp +++ b/pcsx2-qt/Settings/ControllerSettingsWindow.cpp @@ -39,6 +39,7 @@ ControllerSettingsWindow::ControllerSettingsWindow() connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked); connect(m_ui.loadProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onLoadProfileClicked); connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked); + connect(m_ui.mappingSettings, &QPushButton::clicked, this, &ControllerSettingsWindow::onMappingSettingsClicked); connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked); connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &ControllerSettingsWindow::onInputDevicesEnumerated); @@ -186,6 +187,12 @@ void ControllerSettingsWindow::onDeleteProfileClicked() switchProfile({}); } +void ControllerSettingsWindow::onMappingSettingsClicked() +{ + ControllerMappingSettingsDialog dialog(this); + dialog.exec(); +} + void ControllerSettingsWindow::onRestoreDefaultsClicked() { if (QMessageBox::question(this, tr("Restore Defaults"), diff --git a/pcsx2-qt/Settings/ControllerSettingsWindow.h b/pcsx2-qt/Settings/ControllerSettingsWindow.h index c199cdbcfde9c..6c36060b87efb 100644 --- a/pcsx2-qt/Settings/ControllerSettingsWindow.h +++ b/pcsx2-qt/Settings/ControllerSettingsWindow.h @@ -76,6 +76,7 @@ private Q_SLOTS: void onNewProfileClicked(); void onLoadProfileClicked(); void onDeleteProfileClicked(); + void onMappingSettingsClicked(); void onRestoreDefaultsClicked(); void onInputDevicesEnumerated(const QList>& devices); diff --git a/pcsx2-qt/Settings/ControllerSettingsWindow.ui b/pcsx2-qt/Settings/ControllerSettingsWindow.ui index f13ea8c1db858..d9292f2e11caa 100644 --- a/pcsx2-qt/Settings/ControllerSettingsWindow.ui +++ b/pcsx2-qt/Settings/ControllerSettingsWindow.ui @@ -123,6 +123,16 @@ + + + + Mapping Settings + + + + + + diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj index 6266df4ce6633..4c3983e8fbd0e 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj +++ b/pcsx2-qt/pcsx2-qt.vcxproj @@ -428,6 +428,7 @@ Document + diff --git a/pcsx2-qt/pcsx2-qt.vcxproj.filters b/pcsx2-qt/pcsx2-qt.vcxproj.filters index 3d7d58b695bd9..793128e558946 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj.filters +++ b/pcsx2-qt/pcsx2-qt.vcxproj.filters @@ -661,6 +661,9 @@ Settings + + Settings + diff --git a/pcsx2/Input/DInputSource.cpp b/pcsx2/Input/DInputSource.cpp index c45f5c17a111f..66641a04ddcc3 100644 --- a/pcsx2/Input/DInputSource.cpp +++ b/pcsx2/Input/DInputSource.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #define INITGUID @@ -49,8 +49,6 @@ static constexpr std::array s_hat bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock& settings_lock) { - LoadSettings(si); - m_dinput_module.reset(LoadLibraryW(L"dinput8")); if (!m_dinput_module) { @@ -91,12 +89,6 @@ bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock& settings_lock) { - LoadSettings(si); -} - -void DInputSource::LoadSettings(SettingsInterface& si) -{ - m_ignore_inversion = si.GetBoolValue("InputSources", "IgnoreDInputInversion", false); } static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef) @@ -392,7 +384,7 @@ TinyString DInputSource::ConvertKeyToString(InputBindingKey key) if (key.source_subtype == InputSubclass::ControllerAxis) { const char* modifier = (key.modifier == InputModifier::FullAxis ? "Full" : (key.modifier == InputModifier::Negate ? "-" : "+")); - ret.fmt("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && !m_ignore_inversion) ? "~" : ""); + ret.fmt("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && !ShouldIgnoreInversion()) ? "~" : ""); } else if (key.source_subtype == InputSubclass::ControllerButton && key.data >= MAX_NUM_BUTTONS) { diff --git a/pcsx2/Input/DInputSource.h b/pcsx2/Input/DInputSource.h index 89f57cf68eb36..7700c0a1f3e37 100644 --- a/pcsx2/Input/DInputSource.h +++ b/pcsx2/Input/DInputSource.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #pragma once @@ -36,7 +36,6 @@ class DInputSource final : public InputSource bool Initialize(SettingsInterface& si, std::unique_lock& settings_lock) override; void UpdateSettings(SettingsInterface& si, std::unique_lock& settings_lock) override; - void LoadSettings(SettingsInterface& si); bool ReloadDevices() override; void Shutdown() override; @@ -81,5 +80,4 @@ class DInputSource final : public InputSource HWND m_toplevel_window = nullptr; ControllerDataArray m_controllers; - bool m_ignore_inversion = false; }; diff --git a/pcsx2/Input/InputSource.cpp b/pcsx2/Input/InputSource.cpp index 4865b0d8bf1db..f19db3d928423 100644 --- a/pcsx2/Input/InputSource.cpp +++ b/pcsx2/Input/InputSource.cpp @@ -1,7 +1,9 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #include "Input/InputSource.h" +#include "Host.h" + #include "common/StringUtil.h" InputSource::InputSource() = default; @@ -144,3 +146,9 @@ std::string InputSource::ConvertGenericControllerKeyToString(InputBindingKey key return {}; } } + +bool InputSource::ShouldIgnoreInversion() +{ + // This is only called when binding controllers, so the lookup is fine. + return Host::GetBaseBoolSettingValue("InputSources", "IgnoreInversion", false); +} diff --git a/pcsx2/Input/InputSource.h b/pcsx2/Input/InputSource.h index a861482121432..639239d21abc6 100644 --- a/pcsx2/Input/InputSource.h +++ b/pcsx2/Input/InputSource.h @@ -66,4 +66,7 @@ class InputSource /// Converts a generic controller key to a string. static std::string ConvertGenericControllerKeyToString(InputBindingKey key); + + /// Returns true if inversion/negation should be ignored when binding axes. + static bool ShouldIgnoreInversion(); }; diff --git a/pcsx2/Input/SDLInputSource.cpp b/pcsx2/Input/SDLInputSource.cpp index 5f9a814db45c0..774c32dcdd215 100644 --- a/pcsx2/Input/SDLInputSource.cpp +++ b/pcsx2/Input/SDLInputSource.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #include "Config.h" @@ -452,7 +452,7 @@ TinyString SDLInputSource::ConvertKeyToString(InputBindingKey key) if (key.data < std::size(s_sdl_axis_names)) ret.fmt("SDL-{}/{}{}", static_cast(key.source_index), modifier, s_sdl_axis_names[key.data]); else - ret.fmt("SDL-{}/{}Axis{}{}", static_cast(key.source_index), modifier, key.data, key.invert ? "~" : ""); + ret.fmt("SDL-{}/{}Axis{}{}", static_cast(key.source_index), modifier, key.data, (key.invert && !ShouldIgnoreInversion()) ? "~" : ""); } else if (key.source_subtype == InputSubclass::ControllerButton) { diff --git a/pcsx2/Input/SDLInputSource.h b/pcsx2/Input/SDLInputSource.h index 4b86936d0e307..34552ebd076c8 100644 --- a/pcsx2/Input/SDLInputSource.h +++ b/pcsx2/Input/SDLInputSource.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ #pragma once