Merge pull request #11159 from flodavid/master_bis

Enable to use controller to close a game
This commit is contained in:
liamwhite 2023-10-14 09:58:03 -04:00 committed by GitHub
commit 18672e6a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 125 additions and 43 deletions

View File

@ -45,6 +45,7 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true); SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true); SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true); SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false); SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true); SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true); SWITCHABLE(RendererBackend, true);
@ -61,6 +62,10 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false); SWITCHABLE(u8, false);
SWITCHABLE(u8, true); SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.cpp
SWITCHABLE(ConfirmStop, true);
#undef SETTING #undef SETTING
#undef SWITCHABLE #undef SWITCHABLE
#endif #endif

View File

@ -67,6 +67,7 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true); SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true); SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true); SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false); SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true); SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true); SWITCHABLE(RendererBackend, true);
@ -83,6 +84,10 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false); SWITCHABLE(u8, false);
SWITCHABLE(u8, true); SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.h
SWITCHABLE(ConfirmStop, true);
#undef SETTING #undef SETTING
#undef SWITCHABLE #undef SWITCHABLE
#endif #endif

View File

@ -133,6 +133,8 @@ ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb); ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
ENUM(FullscreenMode, Borderless, Exclusive); ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu); ENUM(NvdecEmulation, Off, Cpu, Gpu);

View File

@ -128,8 +128,8 @@ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}},

View File

@ -157,6 +157,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
@ -383,6 +384,13 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
translations->insert( translations->insert(
{Settings::EnumMetadata<Settings::ConsoleMode>::Index(), {Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
{PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
translations->insert(
{Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
{
PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"),
PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"),
PAIR(ConfirmStop, Ask_Never, "Never ask"),
}});
#undef PAIR #undef PAIR
#undef CTX_PAIR #undef CTX_PAIR

View File

@ -211,7 +211,7 @@ void GMainWindow::ShowTelemetryCallout() {
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous " tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
"data is collected</a> to help improve yuzu. " "data is collected</a> to help improve yuzu. "
"<br/><br/>Would you like to share your usage data with us?"); "<br/><br/>Would you like to share your usage data with us?");
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { if (!question(this, tr("Telemetry"), telemetry_message)) {
Settings::values.enable_telemetry = false; Settings::values.enable_telemetry = false;
system->ApplySettings(); system->ApplySettings();
} }
@ -2420,9 +2420,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
} }
}(); }();
if (QMessageBox::question(this, tr("Remove Entry"), entry_question, if (!question(this, tr("Remove Entry"), entry_question, QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
QMessageBox::No) != QMessageBox::Yes) {
return; return;
} }
@ -2521,8 +2520,8 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
} }
}(); }();
if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No, if (!GMainWindow::question(this, tr("Remove File"), question,
QMessageBox::No) != QMessageBox::Yes) { QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
return; return;
} }
@ -3409,10 +3408,13 @@ void GMainWindow::OnRestartGame() {
if (!system->IsPoweredOn()) { if (!system->IsPoweredOn()) {
return; return;
} }
if (ConfirmShutdownGame()) {
// Make a copy since ShutdownGame edits game_path // Make a copy since ShutdownGame edits game_path
const auto current_game = QString(current_game_path); const auto current_game = QString(current_game_path);
ShutdownGame(); ShutdownGame();
BootGame(current_game); BootGame(current_game);
}
} }
void GMainWindow::OnPauseGame() { void GMainWindow::OnPauseGame() {
@ -3434,10 +3436,7 @@ void GMainWindow::OnPauseContinueGame() {
} }
void GMainWindow::OnStopGame() { void GMainWindow::OnStopGame() {
if (system->GetExitLocked() && !ConfirmForceLockedExit()) { if (ConfirmShutdownGame()) {
return;
}
play_time_manager->Stop(); play_time_manager->Stop();
// Update game list to show new play time // Update game list to show new play time
game_list->PopulateAsync(UISettings::values.game_dirs); game_list->PopulateAsync(UISettings::values.game_dirs);
@ -3446,6 +3445,30 @@ void GMainWindow::OnStopGame() {
} else { } else {
OnEmulationStopped(); OnEmulationStopped();
} }
}
}
bool GMainWindow::ConfirmShutdownGame() {
if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) {
if (system->GetExitLocked()) {
if (!ConfirmForceLockedExit()) {
return false;
}
} else {
if (!ConfirmChangeGame()) {
return false;
}
}
} else {
if (UISettings::values.confirm_before_stopping.GetValue() ==
ConfirmStop::Ask_Based_On_Game &&
system->GetExitLocked()) {
if (!ConfirmForceLockedExit()) {
return false;
}
}
}
return true;
} }
void GMainWindow::OnLoadComplete() { void GMainWindow::OnLoadComplete() {
@ -3825,22 +3848,11 @@ void GMainWindow::OnTasRecord() {
const bool is_recording = input_subsystem->GetTas()->Record(); const bool is_recording = input_subsystem->GetTas()->Record();
if (!is_recording) { if (!is_recording) {
is_tas_recording_dialog_active = true; is_tas_recording_dialog_active = true;
ControllerNavigation* controller_navigation =
new ControllerNavigation(system->HIDCore(), this); bool answer = question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
// Use QMessageBox instead of question so we can link controller navigation QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
QMessageBox* box_dialog = new QMessageBox();
box_dialog->setWindowTitle(tr("TAS Recording")); input_subsystem->GetTas()->SaveRecording(answer);
box_dialog->setText(tr("Overwrite file of player 1?"));
box_dialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
box_dialog->setDefaultButton(QMessageBox::Yes);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
[box_dialog](Qt::Key key) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(box_dialog, event);
});
int res = box_dialog->exec();
controller_navigation->UnloadController();
input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
is_tas_recording_dialog_active = false; is_tas_recording_dialog_active = false;
} }
OnTasStateChanged(); OnTasStateChanged();
@ -4081,6 +4093,29 @@ void GMainWindow::OnLoadAmiibo() {
LoadAmiibo(filename); LoadAmiibo(filename);
} }
bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) {
QMessageBox* box_dialog = new QMessageBox(parent);
box_dialog->setWindowTitle(title);
box_dialog->setText(text);
box_dialog->setStandardButtons(buttons);
box_dialog->setDefaultButton(defaultButton);
ControllerNavigation* controller_navigation =
new ControllerNavigation(system->HIDCore(), box_dialog);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
[box_dialog](Qt::Key key) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(box_dialog, event);
});
int res = box_dialog->exec();
controller_navigation->UnloadController();
return res == QMessageBox::Yes;
}
void GMainWindow::LoadAmiibo(const QString& filename) { void GMainWindow::LoadAmiibo(const QString& filename) {
auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo();
const QString title = tr("Error loading Amiibo data"); const QString title = tr("Error loading Amiibo data");
@ -4814,8 +4849,7 @@ bool GMainWindow::ConfirmClose() {
return true; return true;
} }
const auto text = tr("Are you sure you want to close yuzu?"); const auto text = tr("Are you sure you want to close yuzu?");
const auto answer = QMessageBox::question(this, tr("yuzu"), text); return question(this, tr("yuzu"), text);
return answer != QMessageBox::No;
} }
void GMainWindow::closeEvent(QCloseEvent* event) { void GMainWindow::closeEvent(QCloseEvent* event) {
@ -4908,11 +4942,11 @@ bool GMainWindow::ConfirmChangeGame() {
if (emu_thread == nullptr) if (emu_thread == nullptr)
return true; return true;
const auto answer = QMessageBox::question( // Use custom question to link controller navigation
return question(
this, tr("yuzu"), this, tr("yuzu"),
tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."), tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No); QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return answer != QMessageBox::No;
} }
bool GMainWindow::ConfirmForceLockedExit() { bool GMainWindow::ConfirmForceLockedExit() {
@ -4922,8 +4956,7 @@ bool GMainWindow::ConfirmForceLockedExit() {
const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"
"Would you like to bypass this and exit anyway?"); "Would you like to bypass this and exit anyway?");
const auto answer = QMessageBox::question(this, tr("yuzu"), text); return question(this, tr("yuzu"), text);
return answer != QMessageBox::No;
} }
void GMainWindow::RequestGameExit() { void GMainWindow::RequestGameExit() {

View File

@ -7,6 +7,7 @@
#include <optional> #include <optional>
#include <QMainWindow> #include <QMainWindow>
#include <QMessageBox>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
@ -15,6 +16,7 @@
#include "input_common/drivers/tas_input.h" #include "input_common/drivers/tas_input.h"
#include "yuzu/compatibility_list.h" #include "yuzu/compatibility_list.h"
#include "yuzu/hotkeys.h" #include "yuzu/hotkeys.h"
#include "yuzu/util/controller_navigation.h"
#ifdef __unix__ #ifdef __unix__
#include <QVariant> #include <QVariant>
@ -424,6 +426,11 @@ private:
bool CheckSystemArchiveDecryption(); bool CheckSystemArchiveDecryption();
bool CheckFirmwarePresence(); bool CheckFirmwarePresence();
void ConfigureFilesystemProvider(const std::string& filepath); void ConfigureFilesystemProvider(const std::string& filepath);
/**
* Open (or not) the right confirm dialog based on current setting and game exit lock
* @returns true if the player confirmed or the settings do no require it
*/
bool ConfirmShutdownGame();
QString GetTasStateDescription() const; QString GetTasStateDescription() const;
bool CreateShortcut(const std::string& shortcut_path, const std::string& title, bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
@ -431,6 +438,17 @@ private:
const std::string& command, const std::string& arguments, const std::string& command, const std::string& arguments,
const std::string& categories, const std::string& keywords); const std::string& categories, const std::string& keywords);
/**
* Mimic the behavior of QMessageBox::question but link controller navigation to the dialog
* The only difference is that it returns a boolean.
*
* @returns true if buttons contains QMessageBox::Yes and the user clicks on the "Yes" button.
*/
bool question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
std::unique_ptr<Ui::MainWindow> ui; std::unique_ptr<Ui::MainWindow> ui;
std::unique_ptr<Core::System> system; std::unique_ptr<Core::System> system;

View File

@ -16,7 +16,9 @@
#include "common/settings_enums.h" #include "common/settings_enums.h"
using Settings::Category; using Settings::Category;
using Settings::ConfirmStop;
using Settings::Setting; using Settings::Setting;
using Settings::SwitchableSetting;
#ifndef CANNOT_EXPLICITLY_INSTANTIATE #ifndef CANNOT_EXPLICITLY_INSTANTIATE
namespace Settings { namespace Settings {
@ -94,6 +96,15 @@ struct Values {
Setting<bool> confirm_before_closing{ Setting<bool> confirm_before_closing{
linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default, linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
true, true}; true, true};
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
ConfirmStop::Ask_Always,
"confirmStop",
Category::UiGeneral,
Settings::Specialization::Default,
true,
true};
Setting<bool> first_start{linkage, true, "firstStart", Category::Ui}; Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};
Setting<bool> pause_when_in_background{linkage, Setting<bool> pause_when_in_background{linkage,
false, false,