From 18160a8e06051a6294df481601e1c817ff6e268e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 14 May 2024 15:52:43 +1000 Subject: [PATCH] Qt: Add option to pause when controller is disconnected --- src/core/fullscreen_ui.cpp | 14 ++-- src/core/settings.cpp | 4 +- src/core/settings.h | 1 + src/duckstation-qt/advancedsettingswidget.cpp | 10 ++- .../interfacesettingswidget.cpp | 16 ++-- src/duckstation-qt/interfacesettingswidget.ui | 78 +++++++++---------- src/duckstation-qt/mainwindow.cpp | 18 ++--- src/duckstation-qt/mainwindow.h | 3 +- src/duckstation-qt/qthost.cpp | 38 ++++++++- src/duckstation-qt/qthost.h | 3 +- src/duckstation-regtest/regtest_host.cpp | 2 +- src/util/dinput_source.cpp | 8 +- src/util/input_manager.cpp | 4 +- src/util/input_manager.h | 4 +- src/util/sdl_input_source.cpp | 4 +- src/util/xinput_source.cpp | 7 +- 16 files changed, 129 insertions(+), 85 deletions(-) diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 144dd0a8a..c289337fa 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -3082,6 +3082,9 @@ void FullscreenUI::DrawInterfaceSettingsPage() FSUI_CSTR("Pauses the emulator when you minimize the window or switch to another " "application, and unpauses when you switch back."), "Main", "PauseOnFocusLoss", false); + DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GAMEPAD, "Pause On Controller Disconnection"), + FSUI_CSTR("Pauses the emulator when a controller with bindings is disconnected."), "Main", + "PauseOnControllerDisconnection", false); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_POWER_OFF, "Confirm Power Off"), FSUI_CSTR("Determines whether a prompt will be displayed to confirm shutting down the emulator/game " @@ -3104,10 +3107,7 @@ void FullscreenUI::DrawInterfaceSettingsPage() bsi, FSUI_ICONSTR(ICON_FA_MAGIC, "Inhibit Screensaver"), FSUI_CSTR("Prevents the screen saver from activating and the host from sleeping while emulation is running."), "Main", "InhibitScreensaver", true); - DrawToggleSetting( - bsi, FSUI_ICONSTR(ICON_FA_COGS, "Apply Per-Game Settings"), - FSUI_CSTR("When enabled, per-game settings will be applied, and incompatible enhancements will be disabled."), - "Main", "ApplyGameSettings", true); + if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Use Light Theme"), FSUI_CSTR("Uses a light coloured theme instead of the default dark theme."), "Main", "UseLightFullscreenUITheme", false)) @@ -6984,6 +6984,7 @@ bool FullscreenUI::IsLeaderboardsWindowOpen() // TRANSLATION-STRING-AREA-BEGIN TRANSLATE_NOOP("FullscreenUI", "%.2f Seconds"); TRANSLATE_NOOP("FullscreenUI", "%d Frames"); +TRANSLATE_NOOP("FullscreenUI", "%d ms"); TRANSLATE_NOOP("FullscreenUI", "%d sectors"); TRANSLATE_NOOP("FullscreenUI", "-"); TRANSLATE_NOOP("FullscreenUI", "1 Frame"); @@ -7071,7 +7072,6 @@ TRANSLATE_NOOP("FullscreenUI", "An error occurred while deleting empty game sett TRANSLATE_NOOP("FullscreenUI", "An error occurred while saving game settings:\n{}"); TRANSLATE_NOOP("FullscreenUI", "Applies modern dithering techniques to further smooth out gradients when true color is enabled."); TRANSLATE_NOOP("FullscreenUI", "Apply Image Patches"); -TRANSLATE_NOOP("FullscreenUI", "Apply Per-Game Settings"); TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to clear the current post-processing chain? All configuration will be lost."); TRANSLATE_NOOP("FullscreenUI", "Aspect Ratio"); TRANSLATE_NOOP("FullscreenUI", "Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization behavior, filling in gaps introduced by upscaling."); @@ -7396,8 +7396,10 @@ TRANSLATE_NOOP("FullscreenUI", "Parent Directory"); TRANSLATE_NOOP("FullscreenUI", "Patches"); TRANSLATE_NOOP("FullscreenUI", "Patches the BIOS to skip the boot animation. Safe to enable."); TRANSLATE_NOOP("FullscreenUI", "Path"); +TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection"); TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss"); TRANSLATE_NOOP("FullscreenUI", "Pause On Start"); +TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back."); TRANSLATE_NOOP("FullscreenUI", "Per-Game Configuration"); @@ -7625,7 +7627,6 @@ TRANSLATE_NOOP("FullscreenUI", "When enabled, DuckStation will assume all achiev TRANSLATE_NOOP("FullscreenUI", "When enabled, DuckStation will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements."); TRANSLATE_NOOP("FullscreenUI", "When enabled, each session will behave as if no achievements have been unlocked."); TRANSLATE_NOOP("FullscreenUI", "When enabled, memory cards and controllers will be overwritten when save states are loaded."); -TRANSLATE_NOOP("FullscreenUI", "When enabled, per-game settings will be applied, and incompatible enhancements will be disabled."); TRANSLATE_NOOP("FullscreenUI", "When enabled, the minimum supported output latency will be used for the host API."); TRANSLATE_NOOP("FullscreenUI", "When playing a multi-disc game and using per-game (title) memory cards, use a single memory card for all discs."); TRANSLATE_NOOP("FullscreenUI", "When this option is chosen, the clock speed set below will be used."); @@ -7644,6 +7645,5 @@ TRANSLATE_NOOP("FullscreenUI", "{} Frames"); TRANSLATE_NOOP("FullscreenUI", "{} deleted."); TRANSLATE_NOOP("FullscreenUI", "{} does not exist."); TRANSLATE_NOOP("FullscreenUI", "{} is not a valid disc image."); -TRANSLATE_NOOP("FullscreenUI", "%d ms"); // TRANSLATION-STRING-AREA-END #endif diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 5398c5daa..5db63718d 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -144,6 +144,7 @@ void Settings::Load(SettingsInterface& si) start_paused = si.GetBoolValue("Main", "StartPaused", false); start_fullscreen = si.GetBoolValue("Main", "StartFullscreen", false); pause_on_focus_loss = si.GetBoolValue("Main", "PauseOnFocusLoss", false); + pause_on_controller_disconnection = si.GetBoolValue("Main", "PauseOnControllerDisconnection", false); save_state_on_exit = si.GetBoolValue("Main", "SaveStateOnExit", true); create_save_state_backups = si.GetBoolValue("Main", "CreateSaveStateBackups", DEFAULT_SAVE_STATE_BACKUPS); compress_save_states = si.GetBoolValue("Main", "CompressSaveStates", DEFAULT_SAVE_STATE_COMPRESSION); @@ -439,12 +440,11 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const si.SetBoolValue("Main", "StartPaused", start_paused); si.SetBoolValue("Main", "StartFullscreen", start_fullscreen); si.SetBoolValue("Main", "PauseOnFocusLoss", pause_on_focus_loss); + si.SetBoolValue("Main", "PauseOnControllerDisconnection", pause_on_controller_disconnection); si.SetBoolValue("Main", "SaveStateOnExit", save_state_on_exit); si.SetBoolValue("Main", "CreateSaveStateBackups", create_save_state_backups); si.SetBoolValue("Main", "CompressSaveStates", compress_save_states); si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off); - si.SetBoolValue("Main", "ApplyCompatibilitySettings", apply_compatibility_settings); - si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings); si.SetBoolValue("Main", "EnableDiscordPresence", enable_discord_presence); } diff --git a/src/core/settings.h b/src/core/settings.h index 744e9f6e9..5ab9c5458 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -81,6 +81,7 @@ struct Settings bool start_paused : 1 = false; bool start_fullscreen : 1 = false; bool pause_on_focus_loss : 1 = false; + bool pause_on_controller_disconnection : 1 = false; bool save_state_on_exit : 1 = true; bool create_save_state_backups : 1 = DEFAULT_SAVE_STATE_BACKUPS; bool compress_save_states : 1 = DEFAULT_SAVE_STATE_COMPRESSION; diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index b24927b0c..9d6b2f64f 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -178,7 +178,8 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* connect(m_ui.resetToDefaultButton, &QPushButton::clicked, this, &AdvancedSettingsWidget::onResetToDefaultClicked); connect(m_ui.showDebugMenu, &QCheckBox::checkStateChanged, g_main_window, &MainWindow::updateDebugMenuVisibility, Qt::QueuedConnection); - connect(m_ui.showDebugMenu, &QCheckBox::checkStateChanged, this, &AdvancedSettingsWidget::onShowDebugOptionsStateChanged); + connect(m_ui.showDebugMenu, &QCheckBox::checkStateChanged, this, + &AdvancedSettingsWidget::onShowDebugOptionsStateChanged); m_ui.tweakOptionTable->setColumnWidth(0, 380); m_ui.tweakOptionTable->setColumnWidth(1, 170); @@ -209,6 +210,12 @@ void AdvancedSettingsWidget::onShowDebugOptionsStateChanged() void AdvancedSettingsWidget::addTweakOptions() { + if (!m_dialog->isPerGameSettings()) + { + addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Apply Game Settings"), "Main", "ApplyGameSettings", + true); + } + addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Apply Compatibility Settings"), "Main", "ApplyCompatibilitySettings", true); addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Increase Timer Resolution"), "Main", @@ -267,6 +274,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() { int i = 0; + setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Apply Game Settings setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Apply compatibility settings setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Load Devices From Save States diff --git a/src/duckstation-qt/interfacesettingswidget.cpp b/src/duckstation-qt/interfacesettingswidget.cpp index 8bcdb6dae..23d4487da 100644 --- a/src/duckstation-qt/interfacesettingswidget.cpp +++ b/src/duckstation-qt/interfacesettingswidget.cpp @@ -50,10 +50,11 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.inhibitScreensaver, "Main", "InhibitScreensaver", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "Main", "PauseOnFocusLoss", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnControllerDisconnection, "Main", + "PauseOnControllerDisconnection", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnStart, "Main", "StartPaused", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnExit, "Main", "SaveStateOnExit", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmPowerOff, "Main", "ConfirmPowerOff", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.applyGameSettings, "Main", "ApplyGameSettings", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.startFullscreen, "Main", "StartFullscreen", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.doubleClickTogglesFullscreen, "Main", @@ -71,11 +72,6 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget onRenderToSeparateWindowChanged(); - if (m_dialog->isPerGameSettings()) - { - m_ui.applyGameSettings->setEnabled(false); - } - dialog->registerWidgetHelp( m_ui.confirmPowerOff, tr("Confirm Power Off"), tr("Checked"), tr("Determines whether a prompt will be displayed to confirm shutting down the emulator/game " @@ -99,10 +95,12 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget dialog->registerWidgetHelp(m_ui.pauseOnFocusLoss, tr("Pause On Focus Loss"), tr("Unchecked"), tr("Pauses the emulator when you minimize the window or switch to another application, " "and unpauses when you switch back.")); + dialog->registerWidgetHelp(m_ui.pauseOnControllerDisconnection, tr("Pause On Controller Disconnection"), + tr("Unchecked"), + tr("Pauses the emulator when a controller with bindings is disconnected.")); dialog->registerWidgetHelp( - m_ui.applyGameSettings, tr("Apply Per-Game Settings"), tr("Checked"), - tr("When enabled, per-game settings will be applied, and incompatible enhancements will be disabled. You should " - "leave this option enabled except when testing enhancements with incompatible games.")); + m_ui.createSaveStateBackups, tr("Create Save State Backups"), tr("Checked"), + tr("Backs up any previous save state when creating a new save state, with a .bak extension.")); dialog->registerWidgetHelp(m_ui.enableDiscordPresence, tr("Enable Discord Presence"), tr("Unchecked"), tr("Shows the game you are currently playing as part of your profile in Discord.")); diff --git a/src/duckstation-qt/interfacesettingswidget.ui b/src/duckstation-qt/interfacesettingswidget.ui index 3e4900dd5..ac1dc8882 100644 --- a/src/duckstation-qt/interfacesettingswidget.ui +++ b/src/duckstation-qt/interfacesettingswidget.ui @@ -29,59 +29,59 @@ Behaviour - - - - Save State On Shutdown - - - - - - - Pause On Focus Loss - - - - - - - Apply Per-Game Settings - - - - + Create Save State Backups + + + + Enable Discord Presence + + + + + + + Pause On Controller Disconnection + + + - - - Inhibit Screensaver - - - - - - - Pause On Start - - - - Confirm Power Off - - + + - Enable Discord Presence + Inhibit Screensaver + + + + + + + Save State On Shutdown + + + + + + + Pause On Start + + + + + + + Pause On Focus Loss diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index fcbf65cd2..9fdb2b9f3 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -194,6 +194,11 @@ bool MainWindow::confirmMessage(const QString& title, const QString& message) return (QMessageBox::question(this, title, message) == QMessageBox::Yes); } +void MainWindow::onStatusMessage(const QString& message) +{ + m_ui.statusBar->showMessage(message); +} + void MainWindow::registerForDeviceNotifications() { #ifdef _WIN32 @@ -2093,6 +2098,7 @@ void MainWindow::connectSignals() Qt::QueuedConnection); connect(g_emu_thread, &EmuThread::errorReported, this, &MainWindow::reportError, Qt::BlockingQueuedConnection); connect(g_emu_thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection); + connect(g_emu_thread, &EmuThread::statusMessage, this, &MainWindow::onStatusMessage); connect(g_emu_thread, &EmuThread::onAcquireRenderWindowRequested, this, &MainWindow::acquireRenderWindow, Qt::BlockingQueuedConnection); connect(g_emu_thread, &EmuThread::onReleaseRenderWindowRequested, this, &MainWindow::releaseRenderWindow); @@ -2108,7 +2114,6 @@ void MainWindow::connectSignals() connect(g_emu_thread, &EmuThread::mouseModeRequested, this, &MainWindow::onMouseModeRequested); connect(g_emu_thread, &EmuThread::fullscreenUIStateChange, this, &MainWindow::onFullscreenUIStateChange); connect(g_emu_thread, &EmuThread::achievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested); - connect(g_emu_thread, &EmuThread::achievementsLoginSucceeded, this, &MainWindow::onAchievementsLoginSucceeded); connect(g_emu_thread, &EmuThread::achievementsChallengeModeChanged, this, &MainWindow::onAchievementsChallengeModeChanged); connect(g_emu_thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered); @@ -2961,17 +2966,6 @@ void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason r dlg.exec(); } -void MainWindow::onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, - quint32 unread_messages) -{ - const QString message = tr("RA: Logged in as %1 (%2, %3 softcore). %4 unread messages.") - .arg(display_name) - .arg(points) - .arg(sc_points) - .arg(unread_messages); - m_ui.statusBar->showMessage(message); -} - void MainWindow::onAchievementsChallengeModeChanged(bool enabled) { if (enabled) diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 17c4ef16a..f81fad40e 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -123,6 +123,7 @@ public Q_SLOTS: private Q_SLOTS: void reportError(const QString& title, const QString& message); bool confirmMessage(const QString& title, const QString& message); + void onStatusMessage(const QString& message); std::optional acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless, bool use_main_window_pos); @@ -139,8 +140,6 @@ private Q_SLOTS: void onSystemResumed(); void onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title); void onAchievementsLoginRequested(Achievements::LoginRequestReason reason); - void onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, - quint32 unread_messages); void onAchievementsChallengeModeChanged(bool enabled); void onApplicationStateChanged(Qt::ApplicationState state); diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index a9d556f38..34ad8d1d5 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1529,7 +1529,13 @@ void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason) void Host::OnAchievementsLoginSuccess(const char* username, u32 points, u32 sc_points, u32 unread_messages) { - emit g_emu_thread->achievementsLoginSucceeded(QString::fromUtf8(username), points, sc_points, unread_messages); + const QString message = qApp->translate("QtHost", "RA: Logged in as %1 (%2, %3 softcore). %4 unread messages.") + .arg(QString::fromUtf8(username)) + .arg(points) + .arg(sc_points) + .arg(unread_messages); + + emit g_emu_thread->statusMessage(message); } void Host::OnAchievementsRefreshed() @@ -1844,12 +1850,40 @@ void Host::OnInputDeviceConnected(std::string_view identifier, std::string_view emit g_emu_thread->onInputDeviceConnected( identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size()), device_name.empty() ? QString() : QString::fromUtf8(device_name.data(), device_name.size())); + + if (System::IsValid() || g_emu_thread->isRunningFullscreenUI()) + { + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, + fmt::format(TRANSLATE_FS("QtHost", "Controller {} connected."), identifier), + Host::OSD_INFO_DURATION); + } } -void Host::OnInputDeviceDisconnected(std::string_view identifier) +void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier) { emit g_emu_thread->onInputDeviceDisconnected( identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size())); + + if (g_settings.pause_on_controller_disconnection && System::GetState() == System::State::Running && + InputManager::HasAnyBindingsForSource(key)) + { + std::string message = + fmt::format(TRANSLATE_FS("QtHost", "System paused because controller {} was disconnected."), identifier); + Host::RunOnCPUThread([message = QString::fromStdString(message)]() { + System::PauseSystem(true); + + // has to be done after pause, otherwise pause message takes precedence + emit g_emu_thread->statusMessage(message); + }); + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, std::move(message), + Host::OSD_WARNING_DURATION); + } + else if (System::IsValid() || g_emu_thread->isRunningFullscreenUI()) + { + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, + fmt::format(TRANSLATE_FS("QtHost", "Controller {} disconnected."), identifier), + Host::OSD_INFO_DURATION); + } } ALWAYS_INLINE std::string QtHost::GetResourcePath(std::string_view filename, bool allow_override) diff --git a/src/duckstation-qt/qthost.h b/src/duckstation-qt/qthost.h index 7a08b8071..9290747af 100644 --- a/src/duckstation-qt/qthost.h +++ b/src/duckstation-qt/qthost.h @@ -122,6 +122,7 @@ public: Q_SIGNALS: void errorReported(const QString& title, const QString& message); bool messageConfirmed(const QString& title, const QString& message); + void statusMessage(const QString& message); void debuggerMessageReported(const QString& message); void settingsResetToDefault(bool system, bool controller); void onInputDevicesEnumerated(const QList>& devices); @@ -144,8 +145,6 @@ Q_SIGNALS: void mouseModeRequested(bool relative, bool hide_cursor); void fullscreenUIStateChange(bool running); void achievementsLoginRequested(Achievements::LoginRequestReason reason); - void achievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, - quint32 unread_messages); void achievementsRefreshed(quint32 id, const QString& game_info_string); void achievementsChallengeModeChanged(bool enabled); void cheatEnabled(quint32 index, bool enabled); diff --git a/src/duckstation-regtest/regtest_host.cpp b/src/duckstation-regtest/regtest_host.cpp index ec9353c25..bcf6c2363 100644 --- a/src/duckstation-regtest/regtest_host.cpp +++ b/src/duckstation-regtest/regtest_host.cpp @@ -442,7 +442,7 @@ void Host::OnInputDeviceConnected(std::string_view identifier, std::string_view // noop } -void Host::OnInputDeviceDisconnected(std::string_view identifier) +void Host::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier) { // noop } diff --git a/src/util/dinput_source.cpp b/src/util/dinput_source.cpp index 413140270..c9cdf032c 100644 --- a/src/util/dinput_source.cpp +++ b/src/util/dinput_source.cpp @@ -162,7 +162,9 @@ void DInputSource::Shutdown() { while (!m_controllers.empty()) { - InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(m_controllers.size() - 1))); + const u32 index = static_cast(m_controllers.size() - 1); + InputManager::OnInputDeviceDisconnected({{.source_type = InputSourceType::DInput, .source_index = index}}, + GetDeviceIdentifier(static_cast(m_controllers.size() - 1))); m_controllers.pop_back(); } } @@ -265,7 +267,9 @@ void DInputSource::PollEvents() if (hr != DI_OK) { - InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(i))); + InputManager::OnInputDeviceDisconnected( + {{.source_type = InputSourceType::DInput, .source_index = static_cast(i)}}, + GetDeviceIdentifier(static_cast(i))); m_controllers.erase(m_controllers.begin() + i); continue; } diff --git a/src/util/input_manager.cpp b/src/util/input_manager.cpp index 11463db75..39aa528c8 100644 --- a/src/util/input_manager.cpp +++ b/src/util/input_manager.cpp @@ -1440,9 +1440,9 @@ void InputManager::OnInputDeviceConnected(std::string_view identifier, std::stri Host::OnInputDeviceConnected(identifier, device_name); } -void InputManager::OnInputDeviceDisconnected(std::string_view identifier) +void InputManager::OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier) { - Host::OnInputDeviceDisconnected(identifier); + Host::OnInputDeviceDisconnected(key, identifier); } // ------------------------------------------------------------------------ diff --git a/src/util/input_manager.h b/src/util/input_manager.h index 378328001..24bac4c64 100644 --- a/src/util/input_manager.h +++ b/src/util/input_manager.h @@ -351,7 +351,7 @@ std::vector GetInputProfileNames(); void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name); /// Called when an input device is disconnected. -void OnInputDeviceDisconnected(std::string_view identifier); +void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier); } // namespace InputManager namespace Host { @@ -362,7 +362,7 @@ void AddFixedInputBindings(SettingsInterface& si); void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name); /// Called when an input device is disconnected. -void OnInputDeviceDisconnected(std::string_view identifier); +void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier); /// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates. void SetMouseMode(bool relative, bool hide_cursor); diff --git a/src/util/sdl_input_source.cpp b/src/util/sdl_input_source.cpp index a34e24fc5..4928e7586 100644 --- a/src/util/sdl_input_source.cpp +++ b/src/util/sdl_input_source.cpp @@ -822,7 +822,9 @@ bool SDLInputSource::CloseDevice(int joystick_index) if (it == m_controllers.end()) return false; - InputManager::OnInputDeviceDisconnected(fmt::format("SDL-{}", it->player_id)); + InputManager::OnInputDeviceDisconnected( + {{.source_type = InputSourceType::SDL, .source_index = static_cast(it->player_id)}}, + fmt::format("SDL-{}", it->player_id)); if (it->haptic) SDL_HapticClose(it->haptic); diff --git a/src/util/xinput_source.cpp b/src/util/xinput_source.cpp index ff88ab870..7f8d07ab2 100644 --- a/src/util/xinput_source.cpp +++ b/src/util/xinput_source.cpp @@ -442,7 +442,12 @@ void XInputSource::HandleControllerConnection(u32 index) void XInputSource::HandleControllerDisconnection(u32 index) { Log_InfoPrintf("XInput controller %u disconnected.", index); - InputManager::OnInputDeviceDisconnected(fmt::format("XInput-{}", index)); + + InputManager::OnInputDeviceDisconnected({{ + .source_type = InputSourceType::XInput, + .source_index = index, + }}, + fmt::format("XInput-{}", index)); m_controllers[index] = {}; }