diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp
index 45956162ab..7accc907af 100644
--- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp
+++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.cpp
@@ -29,8 +29,13 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableSDLSource, "InputSources", "SDL", true);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableXInputSource, "InputSources", "XInput", false);
+ SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.multitapPort1, "EmuCore", "MultitapPort0_Enabled", false);
+ SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.multitapPort2, "EmuCore", "MultitapPort1_Enabled", false);
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
+ for (QCheckBox* cb : {m_ui.multitapPort1, m_ui.multitapPort2})
+ connect(cb, &QCheckBox::stateChanged, this, [this]() { emit multitapModeChanged(); });
+
updateSDLOptionsEnabled();
}
diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h
index e49e4ee50f..9e032ff9e8 100644
--- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h
+++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.h
@@ -35,6 +35,9 @@ public:
void addDeviceToList(const QString& identifier, const QString& name);
void removeDeviceFromList(const QString& identifier);
+Q_SIGNALS:
+ void multitapModeChanged();
+
private:
void updateSDLOptionsEnabled();
diff --git a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui
index 7c2088c426..e57ce21f50 100644
--- a/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui
+++ b/pcsx2-qt/Settings/ControllerGlobalSettingsWidget.ui
@@ -96,7 +96,7 @@
-
- The multitap enables up to 8 controllers to be connected to the console. Each multitap provides 4 ports. Multitap is not supported by all games. (NOT YET IMPLEMENTED)
+ The multitap enables up to 8 controllers to be connected to the console. Each multitap provides 4 ports. Multitap is not supported by all games.
true
@@ -105,9 +105,6 @@
-
-
- false
-
Multitap on Console Port 1
@@ -115,9 +112,6 @@
-
-
- false
-
Multitap on Console Port 2
diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.cpp b/pcsx2-qt/Settings/ControllerSettingsDialog.cpp
index 3634192fbf..7bfc738929 100644
--- a/pcsx2-qt/Settings/ControllerSettingsDialog.cpp
+++ b/pcsx2-qt/Settings/ControllerSettingsDialog.cpp
@@ -22,6 +22,11 @@
#include "Settings/ControllerBindingWidgets.h"
#include "Settings/HotkeySettingsWidget.h"
+#include "pcsx2/Sio.h"
+
+#include "common/Assertions.h"
+
+#include
#include
#include
@@ -32,17 +37,14 @@ ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ // These are preset in the ui file.
m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this);
- m_ui.settingsContainer->insertWidget(0, m_global_settings);
-
- for (u32 i = 0; i < MAX_PORTS; i++)
- {
- m_port_bindings[i] = new ControllerBindingWidget(m_ui.settingsContainer, this, i);
- m_ui.settingsContainer->insertWidget(i + 1, m_port_bindings[i]);
- }
-
+ m_ui.settingsContainer->addWidget(m_global_settings);
m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this);
- m_ui.settingsContainer->insertWidget(3, m_hotkey_settings);
+ m_ui.settingsContainer->addWidget(m_hotkey_settings);
+
+ // add remainder of ports
+ createPortWidgets();
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &ControllerSettingsDialog::onCategoryCurrentRowChanged);
@@ -53,6 +55,8 @@ ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &ControllerSettingsDialog::onInputDeviceDisconnected);
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this, &ControllerSettingsDialog::onVibrationMotorsEnumerated);
+ connect(m_global_settings, &ControllerGlobalSettingsWidget::multitapModeChanged, this, &ControllerSettingsDialog::createPortWidgets);
+
// trigger a device enumeration to populate the device list
g_emu_thread->enumerateInputDevices();
g_emu_thread->enumerateVibrationMotors();
@@ -128,3 +132,61 @@ void ControllerSettingsDialog::onVibrationMotorsEnumerated(const QListsetCurrentIndex(0);
+ m_ui.settingsCategory->setCurrentRow(0);
+ }
+
+ // remove all except global and hotkeys (i.e. first and last)
+ pxAssert(m_ui.settingsCategory->count() == m_ui.settingsContainer->count());
+ while (m_ui.settingsContainer->count() > 2)
+ {
+ delete m_ui.settingsCategory->takeItem(1);
+
+ QWidget* widget = m_ui.settingsContainer->widget(1);
+ m_ui.settingsContainer->removeWidget(widget);
+ delete widget;
+ }
+
+ // because we can't insert and shuffle everything forward, we need to temporarily remove hotkeys
+ QListWidgetItem* const hotkeys_row = m_ui.settingsCategory->takeItem(1);
+ QWidget* const hotkeys_widget = m_ui.settingsContainer->widget(1);
+ m_ui.settingsContainer->removeWidget(hotkeys_widget);
+
+ // load mtap settings
+ const std::array mtap_enabled = {{Host::GetBaseBoolSettingValue("EmuCore", "MultitapPort0_Enabled", false),
+ Host::GetBaseBoolSettingValue("EmuCore", "MultitapPort1_Enabled", false)}};
+
+ // we reorder things a little to make it look less silly for mtap
+ static constexpr const std::array mtap_slot_names = {{'A', 'B', 'C', 'D'}};
+ static constexpr const std::array mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}};
+
+ // create the ports
+ for (u32 global_slot : mtap_port_order)
+ {
+ const bool is_mtap_port = sioPadIsMultitapSlot(global_slot);
+ const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
+ if (is_mtap_port && !mtap_enabled[port])
+ continue;
+
+ QListWidgetItem* item = new QListWidgetItem();
+ item->setText(mtap_enabled[port] ?
+ (tr("Controller Port %1%2").arg(port + 1).arg(mtap_slot_names[slot])) :
+ tr("Controller Port %1").arg(port + 1));
+ item->setIcon(QIcon::fromTheme("gamepad-line"));
+ m_ui.settingsCategory->addItem(item);
+
+ m_port_bindings[global_slot] = new ControllerBindingWidget(m_ui.settingsContainer, this, global_slot);
+ m_ui.settingsContainer->addWidget(m_port_bindings[global_slot]);
+ }
+
+ // and re-insert hotkeys
+ m_ui.settingsCategory->addItem(hotkeys_row);
+ m_ui.settingsContainer->addWidget(hotkeys_widget);
+}
\ No newline at end of file
diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.h b/pcsx2-qt/Settings/ControllerSettingsDialog.h
index 768d71320d..f0d380adf3 100644
--- a/pcsx2-qt/Settings/ControllerSettingsDialog.h
+++ b/pcsx2-qt/Settings/ControllerSettingsDialog.h
@@ -42,7 +42,7 @@ public:
enum : u32
{
- MAX_PORTS = 2
+ MAX_PORTS = 8
};
ControllerSettingsDialog(QWidget* parent = nullptr);
@@ -64,6 +64,8 @@ private Q_SLOTS:
void onInputDeviceDisconnected(const QString& identifier);
void onVibrationMotorsEnumerated(const QList& motors);
+ void createPortWidgets();
+
private:
Ui::ControllerSettingsDialog m_ui;
diff --git a/pcsx2-qt/Settings/ControllerSettingsDialog.ui b/pcsx2-qt/Settings/ControllerSettingsDialog.ui
index 4c1287d2a1..11fc21d118 100644
--- a/pcsx2-qt/Settings/ControllerSettingsDialog.ui
+++ b/pcsx2-qt/Settings/ControllerSettingsDialog.ui
@@ -58,24 +58,6 @@
..
- -
-
- Controller 1
-
-
-
- ..
-
-
- -
-
- Controller 2
-
-
-
- ..
-
-
-
Hotkeys
@@ -95,15 +77,6 @@
620
-
- 4
-
-
-
-
-
-
-
-
diff --git a/pcsx2/Frontend/InputManager.cpp b/pcsx2/Frontend/InputManager.cpp
index 5f21990a01..b6b3a30a7a 100644
--- a/pcsx2/Frontend/InputManager.cpp
+++ b/pcsx2/Frontend/InputManager.cpp
@@ -808,12 +808,6 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
// Binding Updater
// ------------------------------------------------------------------------
-// TODO(Stenzek): Find a better place for this. Maybe in PAD?
-static constexpr std::array s_default_pad_types = {{
- "DualShock2", // Pad 1
- "None" // Pad 2
-}};
-
void InputManager::ReloadBindings(SettingsInterface& si)
{
PauseVibration();
@@ -825,8 +819,8 @@ void InputManager::ReloadBindings(SettingsInterface& si)
AddHotkeyBindings(si);
- for (u32 pad = 0; pad < MAX_PAD_NUMBER; pad++)
- AddPadBindings(si, pad, s_default_pad_types[pad]);
+ for (u32 pad = 0; pad < PAD::NUM_CONTROLLER_PORTS; pad++)
+ AddPadBindings(si, pad, PAD::GetDefaultPadType(pad));
}
// ------------------------------------------------------------------------
diff --git a/pcsx2/Frontend/InputManager.h b/pcsx2/Frontend/InputManager.h
index d178a3109f..cf2e6b3ba4 100644
--- a/pcsx2/Frontend/InputManager.h
+++ b/pcsx2/Frontend/InputManager.h
@@ -174,9 +174,6 @@ class InputSource;
namespace InputManager
{
- /// Number of emulated pads. TODO: Multitap support.
- static constexpr u32 MAX_PAD_NUMBER = 2;
-
/// Minimum interval between vibration updates when the effect is continuous.
static constexpr double VIBRATION_UPDATE_INTERVAL_SECONDS = 0.5; // 500ms
diff --git a/pcsx2/PAD/Host/Global.h b/pcsx2/PAD/Host/Global.h
index 58793cbc94..6b4518c12b 100644
--- a/pcsx2/PAD/Host/Global.h
+++ b/pcsx2/PAD/Host/Global.h
@@ -15,19 +15,8 @@
#pragma once
-#include
-#include
-#include
-#include
-#include