Qt: Add option to pause when controller is disconnected

This commit is contained in:
Stenzek
2024-05-14 15:52:43 +10:00
parent 2b31c08083
commit 18160a8e06
16 changed files with 129 additions and 85 deletions

View File

@ -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

View File

@ -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."));

View File

@ -29,59 +29,59 @@
<string>Behaviour</string>
</property>
<layout class="QGridLayout" name="formLayout_4">
<item row="3" column="1">
<widget class="QCheckBox" name="saveStateOnExit">
<property name="text">
<string>Save State On Shutdown</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
<string>Pause On Focus Loss</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="applyGameSettings">
<property name="text">
<string>Apply Per-Game Settings</string>
</property>
</widget>
</item>
<item row="7" column="0">
<item row="3" column="0">
<widget class="QCheckBox" name="createSaveStateBackups">
<property name="text">
<string>Create Save State Backups</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="enableDiscordPresence">
<property name="text">
<string>Enable Discord Presence</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="pauseOnControllerDisconnection">
<property name="text">
<string>Pause On Controller Disconnection</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="pauseOnStart">
<property name="text">
<string>Pause On Start</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="confirmPowerOff">
<property name="text">
<string>Confirm Power Off</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="enableDiscordPresence">
<item row="1" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Enable Discord Presence</string>
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="saveStateOnExit">
<property name="text">
<string>Save State On Shutdown</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="pauseOnStart">
<property name="text">
<string>Pause On Start</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
<string>Pause On Focus Loss</string>
</property>
</widget>
</item>

View File

@ -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)

View File

@ -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<WindowInfo> 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);

View File

@ -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)

View File

@ -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<QPair<QString, QString>>& 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);