Skip to content

Commit

Permalink
Qt: Implement per-game controller configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Aug 24, 2024
1 parent 9e3507e commit bda6869
Show file tree
Hide file tree
Showing 24 changed files with 429 additions and 181 deletions.
3 changes: 1 addition & 2 deletions src/common/layered_settings_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class LayeredSettingsInterface final : public SettingsInterface
public:
enum Layer : u32
{
LAYER_CMDLINE,
LAYER_GAME,
LAYER_INPUT,
LAYER_BASE,
Expand Down Expand Up @@ -66,7 +65,7 @@ class LayeredSettingsInterface final : public SettingsInterface
using SettingsInterface::GetUIntValue;

private:
static constexpr Layer FIRST_LAYER = LAYER_CMDLINE;
static constexpr Layer FIRST_LAYER = LAYER_GAME;
static constexpr Layer LAST_LAYER = LAYER_BASE;

std::array<SettingsInterface*, NUM_LAYERS> m_layers{};
Expand Down
2 changes: 1 addition & 1 deletion src/common/memory_settings_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class MemorySettingsInterface final : public SettingsInterface
{
public:
MemorySettingsInterface();
~MemorySettingsInterface();
~MemorySettingsInterface() override;

bool Save(Error* error = nullptr) override;

Expand Down
12 changes: 6 additions & 6 deletions src/core/fullscreen_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2798,7 +2798,7 @@ void FullscreenUI::DoCopyGameSettings()
return;

Settings temp_settings;
temp_settings.Load(*GetEditingSettingsInterface(false));
temp_settings.Load(*GetEditingSettingsInterface(false), *GetEditingSettingsInterface(false));
temp_settings.Save(*s_game_settings_interface, true);
SetSettingsChanged(s_game_settings_interface.get());

Expand Down Expand Up @@ -3652,20 +3652,20 @@ void FullscreenUI::DrawControllerSettingsPage()
if (IsEditingGameSettings(bsi))
{
if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "Per-Game Configuration"),
FSUI_CSTR("Uses game-specific settings for controllers for this game."), "Pad",
FSUI_CSTR("Uses game-specific settings for controllers for this game."), "ControllerPorts",
"UseGameSettingsForController", false, IsEditingGameSettings(bsi), false))
{
// did we just enable per-game for the first time?
if (bsi->GetBoolValue("Pad", "UseGameSettingsForController", false) &&
!bsi->GetBoolValue("Pad", "GameSettingsInitialized", false))
if (bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false) &&
!bsi->GetBoolValue("ControllerPorts", "GameSettingsInitialized", false))
{
bsi->SetBoolValue("Pad", "GameSettingsInitialized", true);
bsi->SetBoolValue("ControllerPorts", "GameSettingsInitialized", true);
CopyGlobalControllerSettingsToGame();
}
}
}

if (IsEditingGameSettings(bsi) && !bsi->GetBoolValue("Pad", "UseGameSettingsForController", false))
if (IsEditingGameSettings(bsi) && !bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false))
{
// nothing to edit..
EndMenuButtons();
Expand Down
7 changes: 4 additions & 3 deletions src/core/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void Settings::UpdateOverclockActive()
cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1));
}

void Settings::Load(SettingsInterface& si)
void Settings::Load(SettingsInterface& si, SettingsInterface& controller_si)
{
region =
ParseConsoleRegionName(
Expand Down Expand Up @@ -364,7 +364,8 @@ void Settings::Load(SettingsInterface& si)

multitap_mode =
ParseMultitapModeName(
si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE)).c_str())
controller_si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE))
.c_str())
.value_or(DEFAULT_MULTITAP_MODE);

const std::array<bool, 2> mtap_enabled = {{IsPort1MultitapEnabled(), IsPort2MultitapEnabled()}};
Expand All @@ -379,7 +380,7 @@ void Settings::Load(SettingsInterface& si)
}

const ControllerType default_type = (i == 0) ? DEFAULT_CONTROLLER_1_TYPE : DEFAULT_CONTROLLER_2_TYPE;
const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(si.GetTinyStringValue(
const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(controller_si.GetTinyStringValue(
Controller::GetSettingsSection(i).c_str(), "Type", Controller::GetControllerInfo(default_type)->name));
controller_types[i] = cinfo ? cinfo->type : default_type;
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ struct Settings
DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD = 128,
};

void Load(SettingsInterface& si);
void Load(SettingsInterface& si, SettingsInterface& controller_si);
void Save(SettingsInterface& si, bool ignore_base) const;
static void Clear(SettingsInterface& si);

Expand Down
65 changes: 39 additions & 26 deletions src/core/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "common/dynamic_library.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/layered_settings_interface.h"
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
Expand Down Expand Up @@ -136,7 +137,8 @@ struct MemorySaveState
static void CheckCacheLineSize();
static void LogStartupInformation();

static void LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
static LayeredSettingsInterface GetControllerSettingsLayers(std::unique_lock<std::mutex>& lock);
static LayeredSettingsInterface GetHotkeySettingsLayer(std::unique_lock<std::mutex>& lock);

static std::string GetExecutableNameForImage(IsoReader& iso, bool strip_subdirectories);
static bool ReadExecutableFromImage(IsoReader& iso, std::string* out_executable_name,
Expand Down Expand Up @@ -1202,12 +1204,14 @@ void System::LoadSettings(bool display_osd_messages)
{
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface& si = *Host::GetSettingsInterface();
g_settings.Load(si);
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
g_settings.Load(si, controller_si);
g_settings.UpdateLogSettings();

Host::LoadSettings(si, lock);
InputManager::ReloadSources(si, lock);
LoadInputBindings(si, lock);
InputManager::ReloadSources(controller_si, lock);
InputManager::ReloadBindings(controller_si, hotkey_si);
WarnAboutUnsafeSettings();

// apply compatibility settings
Expand All @@ -1224,12 +1228,15 @@ void System::LoadSettings(bool display_osd_messages)
void System::ReloadInputSources()
{
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
InputManager::ReloadSources(*si, lock);
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
InputManager::ReloadSources(controller_si, lock);

// skip loading bindings if we're not running, since it'll get done on startup anyway
if (IsValid())
LoadInputBindings(*si, lock);
{
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
InputManager::ReloadBindings(controller_si, hotkey_si);
}
}

void System::ReloadInputBindings()
Expand All @@ -1239,37 +1246,43 @@ void System::ReloadInputBindings()
return;

std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
LoadInputBindings(*si, lock);
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
InputManager::ReloadBindings(controller_si, hotkey_si);
}

void System::LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
LayeredSettingsInterface System::GetControllerSettingsLayers(std::unique_lock<std::mutex>& lock)
{
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
LayeredSettingsInterface ret;
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_BASE, Host::Internal::GetBaseSettingsLayer());

// Select input profile _or_ game settings, not both.
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer())
{
const bool use_profile_hotkeys = isi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
if (use_profile_hotkeys)
{
InputManager::ReloadBindings(si, *isi, *isi);
}
else
{
// Temporarily disable the input profile layer, so it doesn't take precedence.
Host::Internal::SetInputSettingsLayer(nullptr, lock);
InputManager::ReloadBindings(si, *isi, si);
Host::Internal::SetInputSettingsLayer(s_input_settings_interface.get(), lock);
}
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_INPUT, Host::Internal::GetInputSettingsLayer());
}
else if (SettingsInterface* gsi = Host::Internal::GetGameSettingsLayer();
gsi && gsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false))
{
InputManager::ReloadBindings(si, *gsi, si);
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_GAME, gsi);
}
else

return ret;
}

LayeredSettingsInterface System::GetHotkeySettingsLayer(std::unique_lock<std::mutex>& lock)
{
LayeredSettingsInterface ret;
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_BASE, Host::Internal::GetBaseSettingsLayer());

// Only add input profile layer if the option is enabled.
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer();
isi && isi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
{
InputManager::ReloadBindings(si, si, si);
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_INPUT, Host::Internal::GetInputSettingsLayer());
}

return ret;
}

void System::SetDefaultSettings(SettingsInterface& si)
Expand Down
18 changes: 9 additions & 9 deletions src/duckstation-qt/controllerbindingwidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ void ControllerBindingWidget::onTypeChanged()
m_controller_info = Controller::GetControllerInfo(static_cast<ControllerType>(index));
DebugAssert(m_controller_info);

SettingsInterface* sif = m_dialog->getProfileSettingsInterface();
SettingsInterface* sif = m_dialog->getEditingSettingsInterface();
if (sif)
{
sif->SetStringValue(m_config_section.c_str(), "Type", m_controller_info->name);
Expand Down Expand Up @@ -307,7 +307,7 @@ void ControllerBindingWidget::onClearBindingsClicked()
}
else
{
InputManager::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
InputManager::ClearPortBindings(*m_dialog->getEditingSettingsInterface(), m_port_number);
}

saveAndRefresh();
Expand Down Expand Up @@ -358,8 +358,8 @@ void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
}
else
{
result = InputManager::MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
QtHost::SaveGameSettings(m_dialog->getProfileSettingsInterface(), false);
result = InputManager::MapController(*m_dialog->getEditingSettingsInterface(), m_port_number, mapping);
QtHost::SaveGameSettings(m_dialog->getEditingSettingsInterface(), false);
g_emu_thread->reloadInputBindings();
}

Expand All @@ -377,7 +377,7 @@ void ControllerBindingWidget::saveAndRefresh()

void ControllerBindingWidget::createBindingWidgets(QWidget* parent)
{
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
SettingsInterface* sif = getDialog()->getEditingSettingsInterface();
DebugAssert(m_controller_info);

QGroupBox* axis_gbox = nullptr;
Expand Down Expand Up @@ -471,7 +471,7 @@ void ControllerBindingWidget::createBindingWidgets(QWidget* parent)

void ControllerBindingWidget::bindBindingWidgets(QWidget* parent)
{
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
SettingsInterface* sif = getDialog()->getEditingSettingsInterface();
DebugAssert(m_controller_info);

const std::string& config_section = getConfigSection();
Expand Down Expand Up @@ -601,12 +601,12 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
}

m_frequency = dialog->getIntValue(section.c_str(), TinyString::from_format("Macro{}Frequency", index + 1u), 0);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(dialog->getProfileSettingsInterface(), m_ui.triggerToggle,
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(dialog->getEditingSettingsInterface(), m_ui.triggerToggle,
section.c_str(), fmt::format("Macro{}Toggle", index + 1u),
false);
updateFrequencyText();

m_ui.trigger->initialize(dialog->getProfileSettingsInterface(), InputBindingInfo::Type::Macro, section,
m_ui.trigger->initialize(dialog->getEditingSettingsInterface(), InputBindingInfo::Type::Macro, section,
fmt::format("Macro{}", index + 1u));

connect(m_ui.increaseFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(1); });
Expand Down Expand Up @@ -747,7 +747,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
QGridLayout* layout, const Controller::ControllerInfo* cinfo)
{
const std::string& section = parent->getConfigSection();
SettingsInterface* sif = parent->getDialog()->getProfileSettingsInterface();
SettingsInterface* sif = parent->getDialog()->getEditingSettingsInterface();
int current_row = 0;

for (const SettingInfo& si : cinfo->settings)
Expand Down
20 changes: 12 additions & 8 deletions src/duckstation-qt/controllerglobalsettingswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
{
m_ui.setupUi(this);

SettingsInterface* sif = dialog->getProfileSettingsInterface();
SettingsInterface* sif = dialog->getEditingSettingsInterface();

SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources",
Expand All @@ -28,10 +28,10 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLMFIDriver, "InputSources", "SDLMFIDriver", true);
#else
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLIOKitDriver);
m_ui.enableSDLIOKitDriver->deleteLater();
delete m_ui.enableSDLIOKitDriver;
m_ui.enableSDLIOKitDriver = nullptr;
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLMFIDriver);
m_ui.enableSDLMFIDriver->deleteLater();
delete m_ui.enableSDLMFIDriver;
m_ui.enableSDLMFIDriver = nullptr;
#endif

Expand All @@ -41,10 +41,10 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableRawInput, "InputSources", "RawInput", false);
#else
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
m_ui.xinputGroup->deleteLater();
delete m_ui.xinputGroup;
m_ui.xinputGroup = nullptr;
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
m_ui.dinputGroup->deleteLater();
delete m_ui.dinputGroup;
m_ui.dinputGroup = nullptr;
#endif

Expand All @@ -71,10 +71,13 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
{
// remove profile options from the UI.
m_ui.mainLayout->removeWidget(m_ui.profileSettings);
m_ui.profileSettings->deleteLater();
delete m_ui.profileSettings;
m_ui.profileSettings = nullptr;
}

if (dialog->isEditingGameSettings())
m_ui.deviceListGroup->setEnabled(false);

connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });

connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
Expand Down Expand Up @@ -134,9 +137,10 @@ ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, Contro
linkButton(m_ui.SDL2LED, 2);
linkButton(m_ui.SDL3LED, 3);

SettingsInterface* sif = dialog->getProfileSettingsInterface();
SettingsInterface* sif = dialog->getEditingSettingsInterface();

ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources",
"SDLPS5PlayerLED", false);
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
}

Expand Down
11 changes: 5 additions & 6 deletions src/duckstation-qt/controllerglobalsettingswidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
</widget>
</item>
<item row="0" column="1" rowspan="7">
<widget class="QGroupBox" name="groupBox_3">
<widget class="QGroupBox" name="deviceListGroup">
<property name="title">
<string>Detected Devices</string>
</property>
Expand Down Expand Up @@ -162,8 +162,7 @@
<string>Controller LED Settings</string>
</property>
<property name="icon">
<iconset theme="lightbulb-line">
<normaloff>.</normaloff>.</iconset>
<iconset theme="lightbulb-line"/>
</property>
</widget>
</item>
Expand Down Expand Up @@ -284,7 +283,7 @@
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
Expand Down Expand Up @@ -339,7 +338,7 @@
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
Expand Down Expand Up @@ -388,7 +387,7 @@
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
Expand Down
Loading

0 comments on commit bda6869

Please sign in to comment.