InputManager: Default to using global sources in profiles/games

Fixes controllers disconnecting and reconnecting on game start if any
settings were not copied from global (e.g. new settings).

Also fixes raw input not being hidden on non-Windows.

This is a breaking change if you were relying on input profiles/game
configuration having different sources selected.

In those cases, you will need to enable the new "Use Profile Input
Sources" checkbox to revert to the old behaviour for new profiles.
This commit is contained in:
Stenzek
2026-01-15 18:32:51 +10:00
parent 0c29d4e1db
commit 56fc9afbcf
9 changed files with 268 additions and 161 deletions

View File

@@ -3029,7 +3029,7 @@ void FullscreenUI::CopyGlobalControllerSettingsToGame()
SettingsInterface* dsi = GetEditingSettingsInterface(true);
SettingsInterface* ssi = GetEditingSettingsInterface(false);
InputManager::CopyConfiguration(dsi, *ssi, true, true, false);
InputManager::CopyConfiguration(dsi, *ssi, true, false, true, false);
SetSettingsChanged(dsi);
ShowToast(OSDMessageType::Quick, {}, FSUI_STR("Per-game controller configuration initialized with global settings."));
@@ -3040,7 +3040,7 @@ void FullscreenUI::DoLoadInputProfile()
std::vector<std::string> profiles = InputManager::GetInputProfileNames();
if (profiles.empty())
{
ShowToast(OSDMessageType::Quick, {}, FSUI_STR("No input profiles available."));
ShowToast(OSDMessageType::Quick, {}, FSUI_STR("No controller presets available."));
return;
}
@@ -3048,25 +3048,27 @@ void FullscreenUI::DoLoadInputProfile()
coptions.reserve(profiles.size());
for (std::string& name : profiles)
coptions.emplace_back(std::move(name), false);
OpenChoiceDialog(FSUI_ICONVSTR(ICON_FA_FOLDER_OPEN, "Load Preset"), false, std::move(coptions),
[](s32 index, const std::string& title, bool checked) {
if (index < 0)
return;
OpenChoiceDialog(
FSUI_ICONVSTR(ICON_FA_FOLDER_OPEN, "Load Preset"), false, std::move(coptions),
[](s32 index, const std::string& title, bool checked) {
if (index < 0)
return;
INISettingsInterface ssi(System::GetInputProfilePath(title));
if (!ssi.Load())
{
ShowToast(OSDMessageType::Info, {}, fmt::format(FSUI_FSTR("Failed to load '{}'."), title));
return;
}
INISettingsInterface ssi(System::GetInputProfilePath(title));
if (!ssi.Load())
{
ShowToast(OSDMessageType::Info, {}, fmt::format(FSUI_FSTR("Failed to load '{}'."), title));
return;
}
const auto lock = Core::GetSettingsLock();
SettingsInterface* dsi = GetEditingSettingsInterface();
InputManager::CopyConfiguration(dsi, ssi, true, true, true, IsEditingGameSettings(dsi));
SetSettingsChanged(dsi);
ShowToast(OSDMessageType::Quick, {},
fmt::format(FSUI_FSTR("Controller preset '{}' loaded."), title));
});
const auto lock = Core::GetSettingsLock();
SettingsInterface* dsi = GetEditingSettingsInterface();
const bool copy_hotkey_bindings = ssi.GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
const bool copy_sources = ssi.GetBoolValue("ControllerPorts", "UseProfileInputSources", false);
InputManager::CopyConfiguration(dsi, ssi, true, copy_sources, true, copy_hotkey_bindings);
SetSettingsChanged(dsi);
ShowToast(OSDMessageType::Quick, {}, fmt::format(FSUI_FSTR("Controller preset '{}' loaded."), title));
});
}
void FullscreenUI::DoSaveInputProfile(const std::string& name)
@@ -3075,7 +3077,7 @@ void FullscreenUI::DoSaveInputProfile(const std::string& name)
const auto lock = Core::GetSettingsLock();
SettingsInterface* ssi = GetEditingSettingsInterface();
InputManager::CopyConfiguration(&dsi, *ssi, true, true, true, IsEditingGameSettings(ssi));
InputManager::CopyConfiguration(&dsi, *ssi, true, false, true, false);
if (dsi.Save())
ShowToast(OSDMessageType::Quick, {}, fmt::format(FSUI_FSTR("Controller preset '{}' saved."), name));
else
@@ -3138,6 +3140,11 @@ void FullscreenUI::DrawControllerSettingsPage()
const bool game_settings = IsEditingGameSettings(bsi);
const bool empty_game_settings =
(game_settings && !bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false));
const bool show_input_sources =
(!game_settings || (!empty_game_settings && bsi->GetBoolValue("ControllerPorts", "UseProfileInputSources", false)));
const bool show_hotkeys =
(!game_settings ||
(!empty_game_settings && bsi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false)));
BeginInnerSplitWindow();
@@ -3189,7 +3196,6 @@ void FullscreenUI::DrawControllerSettingsPage()
}
}
const bool show_hotkeys = !IsEditingGameSettings(bsi);
if (show_hotkeys && SplitWindowSidebarItem(FSUI_ICONVSTR(ICON_PF_KEYBOARD_ALT, "Hotkeys"),
(s_settings_locals.selected_controller_port == -2)))
{
@@ -3216,11 +3222,11 @@ void FullscreenUI::DrawControllerSettingsPage()
MenuHeading(FSUI_VSTR("Configuration"));
ResetSplitWindowContentFocusHere();
if (IsEditingGameSettings(bsi))
if (game_settings)
{
if (DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_GEARS, "Per-Game Configuration"),
FSUI_VSTR("Uses game-specific settings for controllers for this game."), "ControllerPorts",
"UseGameSettingsForController", false, IsEditingGameSettings(bsi), false))
"UseGameSettingsForController", false, true, false))
{
// did we just enable per-game for the first time?
if (bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false) &&
@@ -3230,17 +3236,24 @@ void FullscreenUI::DrawControllerSettingsPage()
CopyGlobalControllerSettingsToGame();
}
}
}
if (empty_game_settings)
{
// nothing to edit..
content_done();
return;
}
if (empty_game_settings)
{
// nothing to edit..
content_done();
return;
}
DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_KEY, "Use Per-Game Input Sources"),
FSUI_VSTR(
"Uses game-specific configuration for input sources. If disabled, the global configuration will be used."),
"ControllerPorts", "UseProfileInputSources", false, true, false);
DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_KEY, "Use Per-Game Hotkeys"),
FSUI_VSTR("Uses game-specific configuration for hotkeys. If disabled, global hotkeys will be used."),
"ControllerPorts", "UseProfileHotkeyBindings", false, true, false);
if (IsEditingGameSettings(bsi))
{
if (MenuButton(FSUI_ICONVSTR(ICON_FA_COPY, "Copy Global Settings"),
FSUI_VSTR("Copies the global controller configuration to this game.")))
{
@@ -3267,24 +3280,27 @@ void FullscreenUI::DrawControllerSettingsPage()
DoSaveInputProfile();
}
MenuHeading(FSUI_VSTR("Input Sources"));
if (show_input_sources)
{
MenuHeading(FSUI_VSTR("Input Sources"));
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_GEAR, "Enable SDL Input Source"),
FSUI_VSTR("The SDL input source supports most controllers."), "InputSources", "SDL", true, true,
false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_WIFI, "SDL DualShock 4 / DualSense Enhanced Mode"),
FSUI_VSTR("Provides vibration and LED control support over Bluetooth."), "InputSources",
"SDLControllerEnhancedMode", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_LIGHTBULB, "SDL DualSense Player LED"),
FSUI_VSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources",
"SDLPS5PlayerLED", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_GEAR, "Enable SDL Input Source"),
FSUI_VSTR("The SDL input source supports most controllers."), "InputSources", "SDL", true, true,
false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_WIFI, "SDL DualShock 4 / DualSense Enhanced Mode"),
FSUI_VSTR("Provides vibration and LED control support over Bluetooth."), "InputSources",
"SDLControllerEnhancedMode", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_LIGHTBULB, "SDL DualSense Player LED"),
FSUI_VSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources",
"SDLPS5PlayerLED", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
#ifdef _WIN32
DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_GEAR, "Enable XInput Input Source"),
FSUI_VSTR("Support for controllers that use the XInput protocol. XInput should only be used if you "
"are using a XInput wrapper library."),
"InputSources", "XInput", false);
DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_GEAR, "Enable XInput Input Source"),
FSUI_VSTR("Support for controllers that use the XInput protocol. XInput should only be used if you "
"are using a XInput wrapper library."),
"InputSources", "XInput", false);
#endif
}
MenuHeading(FSUI_VSTR("Multitap"));
DrawEnumSetting(bsi, FSUI_ICONVSTR(ICON_FA_SITEMAP, "Multitap Mode"),

View File

@@ -500,8 +500,8 @@ TRANSLATE_NOOP("FullscreenUI", "No Game Selected");
TRANSLATE_NOOP("FullscreenUI", "No LED");
TRANSLATE_NOOP("FullscreenUI", "No Vibration");
TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "No controller presets available.");
TRANSLATE_NOOP("FullscreenUI", "No devices with vibration motors were detected.");
TRANSLATE_NOOP("FullscreenUI", "No input profiles available.");
TRANSLATE_NOOP("FullscreenUI", "No patches are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "No resume save state found.");
TRANSLATE_NOOP("FullscreenUI", "No save present in this slot.");
@@ -810,6 +810,8 @@ TRANSLATE_NOOP("FullscreenUI", "Use Debug GPU Device");
TRANSLATE_NOOP("FullscreenUI", "Use DualShock/DualSense Button Icons");
TRANSLATE_NOOP("FullscreenUI", "Use Global Setting");
TRANSLATE_NOOP("FullscreenUI", "Use Old MDEC Routines");
TRANSLATE_NOOP("FullscreenUI", "Use Per-Game Hotkeys");
TRANSLATE_NOOP("FullscreenUI", "Use Per-Game Input Sources");
TRANSLATE_NOOP("FullscreenUI", "Use Separate Disc Settings");
TRANSLATE_NOOP("FullscreenUI", "Use Single Card For Multi-Disc Games");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer (Low VRAM Mode)");
@@ -819,6 +821,8 @@ TRANSLATE_NOOP("FullscreenUI", "Uses OpenGL ES even when desktop OpenGL is suppo
TRANSLATE_NOOP("FullscreenUI", "Uses PGXP for all instructions, not just memory operations.");
TRANSLATE_NOOP("FullscreenUI", "Uses a blit presentation model instead of flipping. This may be needed on some systems.");
TRANSLATE_NOOP("FullscreenUI", "Uses a second thread for drawing graphics. Provides a significant speed improvement particularly with the software renderer, and is safe to use.");
TRANSLATE_NOOP("FullscreenUI", "Uses game-specific configuration for hotkeys. If disabled, global hotkeys will be used.");
TRANSLATE_NOOP("FullscreenUI", "Uses game-specific configuration for input sources. If disabled, the global configuration will be used.");
TRANSLATE_NOOP("FullscreenUI", "Uses game-specific settings for controllers for this game.");
TRANSLATE_NOOP("FullscreenUI", "Uses localized (native language) titles in the game list.");
TRANSLATE_NOOP("FullscreenUI", "Uses native resolution coordinates for 2D polygons, instead of precise coordinates. Can fix misaligned UI in some games, but otherwise should be left disabled.");

View File

@@ -151,6 +151,7 @@ struct UndoSaveStateBuffer : public SaveStateBuffer
static void CheckCacheLineSize();
static void LogStartupInformation();
static const SettingsInterface& GetInputSourceSettingsLayer(std::unique_lock<std::mutex>& lock);
static const SettingsInterface& GetControllerSettingsLayer(std::unique_lock<std::mutex>& lock);
static const SettingsInterface& GetHotkeySettingsLayer(std::unique_lock<std::mutex>& lock);
@@ -1248,7 +1249,6 @@ void System::LoadSettings(bool display_osd_messages)
auto lock = Core::GetSettingsLock();
const SettingsInterface& si = *Core::GetSettingsInterface();
const SettingsInterface& controller_si = GetControllerSettingsLayer(lock);
const SettingsInterface& hotkey_si = GetHotkeySettingsLayer(lock);
const bool previous_safe_mode = g_settings.disable_all_enhancements;
g_settings.Load(si, controller_si);
@@ -1270,7 +1270,8 @@ void System::LoadSettings(bool display_osd_messages)
Settings::UpdateLogConfig(si);
Host::LoadSettings(si, lock);
InputManager::ReloadSourcesAndBindings(controller_si, hotkey_si, lock);
InputManager::ReloadSourcesAndBindings(GetInputSourceSettingsLayer(lock), controller_si, GetHotkeySettingsLayer(lock),
lock);
// apply compatibility settings
if (g_settings.apply_compatibility_settings && s_state.running_game_entry)
@@ -1285,9 +1286,8 @@ void System::LoadSettings(bool display_osd_messages)
void System::ReloadInputSources()
{
auto lock = Core::GetSettingsLock();
const SettingsInterface& controller_si = GetControllerSettingsLayer(lock);
const SettingsInterface& hotkey_si = GetHotkeySettingsLayer(lock);
InputManager::ReloadSourcesAndBindings(controller_si, hotkey_si, lock);
InputManager::ReloadSourcesAndBindings(GetInputSourceSettingsLayer(lock), GetControllerSettingsLayer(lock),
GetHotkeySettingsLayer(lock), lock);
}
void System::ReloadInputBindings()
@@ -1297,9 +1297,27 @@ void System::ReloadInputBindings()
return;
auto lock = Core::GetSettingsLock();
const SettingsInterface& controller_si = GetControllerSettingsLayer(lock);
const SettingsInterface& hotkey_si = GetHotkeySettingsLayer(lock);
InputManager::ReloadBindings(controller_si, hotkey_si);
InputManager::ReloadBindings(GetControllerSettingsLayer(lock), GetHotkeySettingsLayer(lock));
}
const SettingsInterface& System::GetInputSourceSettingsLayer(std::unique_lock<std::mutex>& lock)
{
// Select input profile _or_ game settings, not both.
if (const SettingsInterface* isi = Core::GetInputSettingsLayer();
isi && isi->GetBoolValue("ControllerPorts", "UseProfileInputSources", false))
{
return *isi;
}
else if (const SettingsInterface* gsi = Core::GetGameSettingsLayer();
gsi && gsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false) &&
gsi->GetBoolValue("ControllerPorts", "UseProfileInputSources", false))
{
return *gsi;
}
else
{
return *Core::GetBaseSettingsLayer();
}
}
const SettingsInterface& System::GetControllerSettingsLayer(std::unique_lock<std::mutex>& lock)
@@ -1328,6 +1346,12 @@ const SettingsInterface& System::GetHotkeySettingsLayer(std::unique_lock<std::mu
{
return *isi;
}
else if (const SettingsInterface* gsi = Core::GetGameSettingsLayer();
gsi && gsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false) &&
gsi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
{
return *gsi;
}
else
{
return *Core::GetBaseSettingsLayer();

View File

@@ -28,75 +28,132 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingsInterface* sif = dialog->getEditingSettingsInterface();
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources",
"SDLControllerEnhancedMode", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableTouchPadAsPointer, "InputSources",
"SDLTouchpadAsPointer", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources",
"SDLPS5PlayerLED", false);
connect(m_ui.enableSDLSource, &QCheckBox::checkStateChanged, this,
&ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
connect(m_ui.SDLHelpText, &QLabel::linkActivated, this, &ControllerGlobalSettingsWidget::sdlHelpTextLinkClicked);
#ifdef _WIN32
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableDInputSource, "InputSources", "DInput",
false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableXInputSource, "InputSources", "XInput",
false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableRawInput, "InputSources", "RawInput",
false);
#else
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
delete m_ui.xinputGroup;
m_ui.xinputGroup = nullptr;
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
delete m_ui.dinputGroup;
m_ui.dinputGroup = nullptr;
#endif
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping",
false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileEnumSetting(
sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode", &Settings::ParseMultitapModeName,
&Settings::GetMultitapModeName, &Settings::GetMultitapModeDisplayName, Settings::DEFAULT_MULTITAP_MODE,
MultitapMode::Count);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "ControllerPorts",
"PointerXScale", 8.0f);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "ControllerPorts",
"PointerYScale", 8.0f);
if (dialog->isEditingProfile())
// editing game profile or input profile
bool remove_sources = false;
if (sif)
{
m_ui.useProfileHotkeyBindings->setChecked(
m_dialog->getBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false));
m_ui.useProfileHotkeyBindings->setChecked(sif->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false));
connect(m_ui.useProfileHotkeyBindings, &QCheckBox::checkStateChanged, this, [this](int new_state) {
m_dialog->setBoolValue("ControllerPorts", "UseProfileHotkeyBindings", (new_state == Qt::Checked));
emit bindingSetupChanged();
});
m_ui.useProfileInputSources->setChecked(sif->GetBoolValue("ControllerPorts", "UseProfileInputSources", false));
connect(m_ui.useProfileInputSources, &QCheckBox::checkStateChanged, this, [this](int new_state) {
m_dialog->setBoolValue("ControllerPorts", "UseProfileInputSources", (new_state == Qt::Checked));
emit bindingSetupChanged();
});
remove_sources = !m_ui.useProfileInputSources->isChecked();
}
else
{
// remove profile options from the UI.
m_ui.mainLayout->removeWidget(m_ui.profileSettings);
delete m_ui.profileSettings;
m_ui.profileSettings = nullptr;
QtUtils::SafeDeleteWidget(m_ui.profileSettings);
m_ui.profileSettingsLayout = nullptr;
m_ui.profileSettingsDescription = nullptr;
m_ui.useProfileHotkeyBindings = nullptr;
m_ui.useProfileInputSources = nullptr;
}
if (!remove_sources)
{
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources",
"SDLControllerEnhancedMode", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableTouchPadAsPointer, "InputSources",
"SDLTouchpadAsPointer", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources",
"SDLPS5PlayerLED", false);
connect(m_ui.enableSDLSource, &QCheckBox::checkStateChanged, this,
&ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
connect(m_ui.sdlHelpText, &QLabel::linkActivated, this, &ControllerGlobalSettingsWidget::sdlHelpTextLinkClicked);
#ifdef _WIN32
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableDInputSource, "InputSources", "DInput",
false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableXInputSource, "InputSources", "XInput",
false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableRawInput, "InputSources", "RawInput",
false);
#else
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
QtUtils::SafeDeleteWidget(m_ui.xinputGroup);
m_ui.xinputLayout = nullptr;
m_ui.enableXInputSource = nullptr;
m_ui.xinputDescription = nullptr;
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
QtUtils::SafeDeleteWidget(m_ui.dinputGroup);
m_ui.dinputLayout = nullptr;
m_ui.enableDInputSource = nullptr;
m_ui.dinputDescription = nullptr;
m_ui.pointerOptionsLayout->removeWidget(m_ui.enableRawInput);
QtUtils::SafeDeleteWidget(m_ui.enableRawInput);
#endif
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableMouseMapping, "UI",
"EnableMouseMapping", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "ControllerPorts",
"PointerXScale", 8.0f);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "ControllerPorts",
"PointerYScale", 8.0f);
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
connect(m_ui.pointerYScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerXScale->value()));
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
updateSDLOptionsEnabled();
}
else
{
m_ui.mainLayout->removeWidget(m_ui.sdlGroup);
QtUtils::SafeDeleteWidget(m_ui.sdlGroup);
m_ui.sdlGridLayout = nullptr;
m_ui.sdlLEDLayout = nullptr;
m_ui.enableSDLPS5PlayerLED = nullptr;
m_ui.ledSettings = nullptr;
m_ui.enableSDLSource = nullptr;
m_ui.enableSDLEnhancedMode = nullptr;
m_ui.sdlHelpText = nullptr;
m_ui.enableTouchPadAsPointer = nullptr;
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
QtUtils::SafeDeleteWidget(m_ui.xinputGroup);
m_ui.xinputLayout = nullptr;
m_ui.enableXInputSource = nullptr;
m_ui.xinputDescription = nullptr;
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
QtUtils::SafeDeleteWidget(m_ui.dinputGroup);
m_ui.dinputLayout = nullptr;
m_ui.enableDInputSource = nullptr;
m_ui.dinputDescription = nullptr;
m_ui.mainLayout->removeWidget(m_ui.pointerGroup);
QtUtils::SafeDeleteWidget(m_ui.pointerGroup);
m_ui.pointerLayout = nullptr;
m_ui.pointerDescription = nullptr;
m_ui.pointerXScaleDescription = nullptr;
m_ui.pointerXScaleLayout = nullptr;
m_ui.pointerXScale = nullptr;
m_ui.pointerXScaleLabel = nullptr;
m_ui.pointerYScaleDescription = nullptr;
m_ui.pointerYScaleLayout = nullptr;
m_ui.pointerYScale = nullptr;
m_ui.pointerYScaleLabel = nullptr;
m_ui.pointerOptionsLayout = nullptr;
m_ui.enableMouseMapping = nullptr;
m_ui.enableRawInput = nullptr;
}
m_ui.deviceList->setModel(g_core_thread->getInputDeviceListModel());
ControllerSettingWidgetBinder::BindWidgetToInputProfileEnumSetting(
sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode", &Settings::ParseMultitapModeName,
&Settings::GetMultitapModeName, &Settings::GetMultitapModeDisplayName, Settings::DEFAULT_MULTITAP_MODE,
MultitapMode::Count);
connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
connect(m_ui.pointerYScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerXScale->value()));
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
updateSDLOptionsEnabled();
QtUtils::RemoveEmptyRowsAndColumns(m_ui.mainLayout);
}

View File

@@ -30,7 +30,7 @@
</property>
<layout class="QGridLayout" name="sdlGridLayout">
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<layout class="QHBoxLayout" name="sdlLEDLayout">
<item>
<widget class="QCheckBox" name="enableSDLPS5PlayerLED">
<property name="sizePolicy">
@@ -86,7 +86,7 @@
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="SDLHelpText">
<widget class="QLabel" name="sdlHelpText">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The SDL input source supports most controllers, and is the preferred option. Enhanced mode may be required for the Vibration/LED functionality of DualShock 4 / DualSense pads in Bluetooth mode. You can also edit &lt;a href=&quot;ADVANCED_SDL_OPTIONS&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#99ebff;&quot;&gt;advanced options&lt;/span&gt;&lt;/a&gt; which control device-specific behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@@ -113,9 +113,9 @@
<property name="title">
<string>XInput Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="xinputLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="xinputDescription">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The XInput source provides support for controllers that use the XInput protocol. This source should &lt;span style=&quot; font-weight:700;&quot;&gt;only&lt;/span&gt; be used if you are using a XInput wrapper library.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@@ -139,9 +139,9 @@
<property name="title">
<string>DirectInput Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<layout class="QGridLayout" name="dinputLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<widget class="QLabel" name="dinputDescription">
<property name="text">
<string>The DirectInput source provides support for legacy controllers which do not support XInput. Accessing these controllers via SDL is recommended instead.</string>
</property>
@@ -161,13 +161,13 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBox_5">
<widget class="QGroupBox" name="pointerGroup">
<property name="title">
<string>Mouse/Pointer Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_6" columnstretch="0,1">
<layout class="QGridLayout" name="pointerLayout" columnstretch="0,1">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_7">
<widget class="QLabel" name="pointerDescription">
<property name="text">
<string>Using raw input improves precision when you bind controller sticks to the mouse pointer. Also enables multiple mice to be used.</string>
</property>
@@ -177,14 +177,14 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<widget class="QLabel" name="pointerXScaleDescription">
<property name="text">
<string>Horizontal Sensitivity:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="pointerXScaleLayout">
<item>
<widget class="QSlider" name="pointerXScale">
<property name="sizePolicy">
@@ -232,14 +232,14 @@
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<widget class="QLabel" name="pointerYScaleDescription">
<property name="text">
<string>Vertical Sensitivity:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="pointerYScaleLayout">
<item>
<widget class="QSlider" name="pointerYScale">
<property name="sizePolicy">
@@ -287,7 +287,7 @@
</layout>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<layout class="QHBoxLayout" name="pointerOptionsLayout">
<item>
<widget class="QCheckBox" name="enableMouseMapping">
<property name="toolTip">
@@ -314,13 +314,13 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="groupBox_4">
<widget class="QGroupBox" name="multitapGroup">
<property name="title">
<string>Controller Multitap</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
<layout class="QGridLayout" name="multitapLayout" columnstretch="0,1">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<widget class="QLabel" name="multitapDescription">
<property name="text">
<string>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.</string>
</property>
@@ -330,7 +330,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<widget class="QLabel" name="multitapModeLabel">
<property name="text">
<string>Multitap Mode:</string>
</property>
@@ -342,16 +342,16 @@
</layout>
</widget>
</item>
<item row="5" column="0">
<item row="0" column="0">
<widget class="QGroupBox" name="profileSettings">
<property name="title">
<string>Profile Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<layout class="QGridLayout" name="profileSettingsLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="profileSettingsDescription">
<property name="text">
<string>When this option is enabled, hotkeys can be set in this input profile, and will be used instead of the global hotkeys. By default, hotkeys are always shared between all profiles.</string>
<string>When these options are enabled, input sources and hotkeys can be set in this input profile, and will be used instead of the global source/hotkey configuration. By default, sources and hotkeys are always shared between all profiles.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -359,9 +359,16 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="useProfileInputSources">
<property name="text">
<string>Use Profile Input Sources</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="useProfileHotkeyBindings">
<property name="text">
<string>Use Per-Profile Hotkeys</string>
<string>Use Profile Hotkeys</string>
</property>
</widget>
</item>
@@ -375,8 +382,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
@@ -386,7 +393,7 @@
<property name="title">
<string>Detected Devices</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QGridLayout" name="deviceListLayout">
<item row="0" column="0" colspan="2">
<widget class="QListView" name="deviceList">
<property name="minimumSize">

View File

@@ -209,25 +209,21 @@ void ControllerSettingsWindow::onNewProfileClicked()
// from global
const auto lock = Core::GetSettingsLock();
InputManager::CopyConfiguration(&temp_si, *Core::GetBaseSettingsLayer(), true, true, true, copy_hotkey_bindings);
InputManager::CopyConfiguration(&temp_si, *Core::GetBaseSettingsLayer(), true, false, true, copy_hotkey_bindings);
}
else
{
// from profile
const bool copy_hotkey_bindings =
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
const bool copy_sources =
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileInputSources", false);
temp_si.SetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", copy_hotkey_bindings);
InputManager::CopyConfiguration(&temp_si, *m_editing_settings_interface, true, true, true, copy_hotkey_bindings);
temp_si.SetBoolValue("ControllerPorts", "UseProfileInputSources", copy_sources);
InputManager::CopyConfiguration(&temp_si, *m_editing_settings_interface, true, copy_sources, true,
copy_hotkey_bindings);
}
}
else
{
// still need to copy the source config
if (!m_editing_settings_interface)
InputManager::CopyConfiguration(&temp_si, *Core::GetBaseSettingsLayer(), false, true, false, false);
else
InputManager::CopyConfiguration(&temp_si, *m_editing_settings_interface, false, true, false, false);
}
if (!temp_si.Save())
{
@@ -255,9 +251,11 @@ void ControllerSettingsWindow::onApplyProfileClicked()
{
const bool copy_hotkey_bindings =
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
const bool copy_sources =
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileInputSources", false);
const auto lock = Core::GetSettingsLock();
InputManager::CopyConfiguration(Core::GetBaseSettingsLayer(), *m_editing_settings_interface, true, true, true,
copy_hotkey_bindings);
InputManager::CopyConfiguration(Core::GetBaseSettingsLayer(), *m_editing_settings_interface, true, copy_sources,
true, copy_hotkey_bindings);
QtHost::QueueSettingsSave();
}
g_core_thread->applySettings();
@@ -312,7 +310,7 @@ void ControllerSettingsWindow::onCopyGlobalSettingsClicked()
{
const auto lock = Core::GetSettingsLock();
InputManager::CopyConfiguration(m_editing_settings_interface, *Core::GetBaseSettingsLayer(), true, true, true,
InputManager::CopyConfiguration(m_editing_settings_interface, *Core::GetBaseSettingsLayer(), true, false, true,
false);
}

View File

@@ -462,7 +462,7 @@ void GameSummaryWidget::onInputProfileChanged(int index)
{
const auto lock = Core::GetSettingsLock();
SettingsInterface* base_sif = Core::GetBaseSettingsLayer();
InputManager::CopyConfiguration(sif, *base_sif, true, true, true, false);
InputManager::CopyConfiguration(sif, *base_sif, true, false, true, false);
QtUtils::AsyncMessageBox(this, QMessageBox::Information, QtUtils::GetRootWidget(this)->windowTitle(),
tr("Per-game controller configuration initialized with global settings."));

View File

@@ -59,7 +59,7 @@ enum : u32
};
/// Delay before showing any controller connected notifications after startup.
static constexpr float DEVICE_CONNECTED_NOTIFICATION_DELAY = 3.0f;
static constexpr float DEVICE_CONNECTED_NOTIFICATION_DELAY = 5.0f;
// ------------------------------------------------------------------------
// Binding Type
@@ -2522,15 +2522,16 @@ void InputManager::UpdateInputSourceState(const SettingsInterface& si, std::uniq
}
}
void InputManager::ReloadSourcesAndBindings(const SettingsInterface& si, const SettingsInterface& hotkey_binding_si,
void InputManager::ReloadSourcesAndBindings(const SettingsInterface& sources_si, const SettingsInterface& binding_si,
const SettingsInterface& hotkey_binding_si,
std::unique_lock<std::mutex>& settings_lock)
{
std::unique_lock lock(s_state.mutex);
#ifdef _WIN32
UpdateInputSourceState(si, settings_lock, InputSourceType::DInput, &InputSource::CreateDInputSource);
UpdateInputSourceState(si, settings_lock, InputSourceType::XInput, &InputSource::CreateXInputSource);
UpdateInputSourceState(si, settings_lock, InputSourceType::RawInput, &InputSource::CreateWin32RawInputSource);
UpdateInputSourceState(sources_si, settings_lock, InputSourceType::DInput, &InputSource::CreateDInputSource);
UpdateInputSourceState(sources_si, settings_lock, InputSourceType::XInput, &InputSource::CreateXInputSource);
UpdateInputSourceState(sources_si, settings_lock, InputSourceType::RawInput, &InputSource::CreateWin32RawInputSource);
// Request device notifications when using raw input/xinput/dinput, as we need to manually handle device changes
if (s_state.input_sources[static_cast<u32>(InputSourceType::DInput)] ||
@@ -2547,15 +2548,15 @@ void InputManager::ReloadSourcesAndBindings(const SettingsInterface& si, const S
}
#endif
#ifdef ENABLE_SDL
UpdateInputSourceState(si, settings_lock, InputSourceType::SDL, &InputSource::CreateSDLSource);
UpdateInputSourceState(sources_si, settings_lock, InputSourceType::SDL, &InputSource::CreateSDLSource);
#endif
#ifdef __ANDROID__
UpdateInputSourceState(si, settings_lock, InputSourceType::Android, &InputSource::CreateAndroidSource);
UpdateInputSourceState(sources_si, settings_lock, InputSourceType::Android, &InputSource::CreateAndroidSource);
#endif
UpdatePointerCount();
InternalReloadBindings(si, hotkey_binding_si);
InternalReloadBindings(binding_si, hotkey_binding_si);
UpdateRelativeMouseMode();
}

View File

@@ -279,11 +279,11 @@ bool IsInputSourceEnabled(const SettingsInterface& si, InputSourceType type);
void SynchronizeBindingHandlerState();
/// Re-parses the config and registers all hotkey and pad bindings.
void ReloadBindings(const SettingsInterface& si, const SettingsInterface& hotkey_binding_si);
void ReloadBindings(const SettingsInterface& binding_si, const SettingsInterface& hotkey_binding_si);
/// Re-parses the sources part of the config and initializes any backends.
void ReloadSourcesAndBindings(const SettingsInterface& si, const SettingsInterface& hotkey_binding_si,
std::unique_lock<std::mutex>& settings_lock);
void ReloadSourcesAndBindings(const SettingsInterface& sources_si, const SettingsInterface& binding_si,
const SettingsInterface& hotkey_binding_si, std::unique_lock<std::mutex>& settings_lock);
/// Shuts down any enabled input sources.
void CloseSources();