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 "stuck on" 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 "stuck on" 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