diff options
Diffstat (limited to 'src/yuzu')
-rw-r--r-- | src/yuzu/applets/controller.cpp | 123 | ||||
-rw-r--r-- | src/yuzu/applets/controller.h | 17 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 8 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 9 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 138 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input_player.h | 13 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 24 | ||||
-rw-r--r-- | src/yuzu/main.h | 8 |
8 files changed, 232 insertions, 108 deletions
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index 8ecfec770..6944478f3 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp @@ -72,40 +72,6 @@ bool IsControllerCompatible(Settings::ControllerType controller_type, } } -/// Maps the controller type combobox index to Controller Type enum -constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { - switch (index) { - case 0: - default: - return Settings::ControllerType::ProController; - case 1: - return Settings::ControllerType::DualJoyconDetached; - case 2: - return Settings::ControllerType::LeftJoycon; - case 3: - return Settings::ControllerType::RightJoycon; - case 4: - return Settings::ControllerType::Handheld; - } -} - -/// Maps the Controller Type enum to controller type combobox index -constexpr int GetIndexFromControllerType(Settings::ControllerType type) { - switch (type) { - case Settings::ControllerType::ProController: - default: - return 0; - case Settings::ControllerType::DualJoyconDetached: - return 1; - case Settings::ControllerType::LeftJoycon: - return 2; - case Settings::ControllerType::RightJoycon: - return 3; - case Settings::ControllerType::Handheld: - return 4; - } -} - } // namespace QtControllerSelectorDialog::QtControllerSelectorDialog( @@ -184,6 +150,11 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( // This avoids unintentionally changing the states of elements while loading them in. SetSupportedControllers(); DisableUnsupportedPlayers(); + + for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { + SetEmulatedControllers(player_index); + } + LoadConfiguration(); for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { @@ -223,8 +194,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( if (i == 0) { connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), - [this](int index) { - UpdateDockedState(GetControllerTypeFromIndex(index) == + [this, i](int index) { + UpdateDockedState(GetControllerTypeFromIndex(index, i) == Settings::ControllerType::Handheld); }); } @@ -281,8 +252,8 @@ void QtControllerSelectorDialog::LoadConfiguration() { (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); - emulated_controllers[index]->setCurrentIndex( - GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type)); + emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( + Settings::values.players.GetValue()[index].controller_type, index)); } UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); @@ -338,7 +309,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { } const auto compatible = IsControllerCompatible( - GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()), + GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index), parameters); // If any controller is found to be incompatible, return false early. @@ -422,6 +393,63 @@ void QtControllerSelectorDialog::SetSupportedControllers() { } } +void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { + auto& pairs = index_controller_type_pairs[player_index]; + + pairs.clear(); + emulated_controllers[player_index]->clear(); + + pairs.emplace_back(emulated_controllers[player_index]->count(), + Settings::ControllerType::ProController); + emulated_controllers[player_index]->addItem(tr("Pro Controller")); + + pairs.emplace_back(emulated_controllers[player_index]->count(), + Settings::ControllerType::DualJoyconDetached); + emulated_controllers[player_index]->addItem(tr("Dual Joycons")); + + pairs.emplace_back(emulated_controllers[player_index]->count(), + Settings::ControllerType::LeftJoycon); + emulated_controllers[player_index]->addItem(tr("Left Joycon")); + + pairs.emplace_back(emulated_controllers[player_index]->count(), + Settings::ControllerType::RightJoycon); + emulated_controllers[player_index]->addItem(tr("Right Joycon")); + + if (player_index == 0) { + pairs.emplace_back(emulated_controllers[player_index]->count(), + Settings::ControllerType::Handheld); + emulated_controllers[player_index]->addItem(tr("Handheld")); + } +} + +Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( + int index, std::size_t player_index) const { + const auto& pairs = index_controller_type_pairs[player_index]; + + const auto it = std::find_if(pairs.begin(), pairs.end(), + [index](const auto& pair) { return pair.first == index; }); + + if (it == pairs.end()) { + return Settings::ControllerType::ProController; + } + + return it->second; +} + +int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, + std::size_t player_index) const { + const auto& pairs = index_controller_type_pairs[player_index]; + + const auto it = std::find_if(pairs.begin(), pairs.end(), + [type](const auto& pair) { return pair.second == type; }); + + if (it == pairs.end()) { + return 0; + } + + return it->first; +} + void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) { if (!player_groupboxes[player_index]->isChecked()) { connected_controller_icons[player_index]->setStyleSheet(QString{}); @@ -430,7 +458,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) } const QString stylesheet = [this, player_index] { - switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) { + switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), + player_index)) { case Settings::ControllerType::ProController: return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); case Settings::ControllerType::DualJoyconDetached: @@ -446,6 +475,12 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) } }(); + if (stylesheet.isEmpty()) { + connected_controller_icons[player_index]->setStyleSheet(QString{}); + player_labels[player_index]->show(); + return; + } + const QString theme = [] { if (QIcon::themeName().contains(QStringLiteral("dark"))) { return QStringLiteral("_dark"); @@ -463,8 +498,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { auto& player = Settings::values.players.GetValue()[player_index]; - const auto controller_type = - GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()); + const auto controller_type = GetControllerTypeFromIndex( + emulated_controllers[player_index]->currentIndex(), player_index); const auto player_connected = player_groupboxes[player_index]->isChecked() && controller_type != Settings::ControllerType::Handheld; @@ -507,8 +542,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { if (!player_groupboxes[player_index]->isChecked() || - GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) == - Settings::ControllerType::Handheld) { + GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), + player_index) == Settings::ControllerType::Handheld) { led_patterns_boxes[player_index][0]->setChecked(false); led_patterns_boxes[player_index][1]->setChecked(false); led_patterns_boxes[player_index][2]->setChecked(false); diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h index 4344e1dd0..7a421d856 100644 --- a/src/yuzu/applets/controller.h +++ b/src/yuzu/applets/controller.h @@ -22,6 +22,10 @@ namespace InputCommon { class InputSubsystem; } +namespace Settings { +enum class ControllerType; +} + namespace Ui { class QtControllerSelectorDialog; } @@ -57,6 +61,15 @@ private: // Sets the controller icons for "Supported Controller Types". void SetSupportedControllers(); + // Sets the emulated controllers per player. + void SetEmulatedControllers(std::size_t player_index); + + // Gets the Controller Type for a given controller combobox index per player. + Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; + + // Gets the controller combobox index for a given Controller Type per player. + int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; + // Updates the controller icons per player. void UpdateControllerIcon(std::size_t player_index); @@ -114,6 +127,10 @@ private: // Comboboxes with a list of emulated controllers per player. std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; + /// Pairs of emulated controller index and Controller Type enum per player. + std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS> + index_controller_type_pairs; + // Labels representing the number of connected controllers // above the "Connected Controllers" checkboxes. std::array<QLabel*, NUM_PLAYERS> connected_controller_labels; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d62b0efc2..ea8f0d7b1 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -302,13 +302,19 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, this->setMouseTracking(true); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); + connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, + Qt::QueuedConnection); +} + +void GRenderWindow::ExecuteProgram(std::size_t program_index) { + emit ExecuteProgramSignal(program_index); } GRenderWindow::~GRenderWindow() { input_subsystem->Shutdown(); } -void GRenderWindow::PollEvents() { +void GRenderWindow::OnFrameDisplayed() { if (!first_frame) { first_frame = true; emit FirstFrameDisplayed(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index ca35cf831..a6d788d40 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -131,7 +131,7 @@ public: ~GRenderWindow() override; // EmuWindow implementation. - void PollEvents() override; + void OnFrameDisplayed() override; bool IsShown() const override; std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; @@ -166,6 +166,12 @@ public: std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; + /** + * Instructs the window to re-launch the application using the specified program_index. + * @param program_index Specifies the index within the application of the program to launch. + */ + void ExecuteProgram(std::size_t program_index); + public slots: void OnEmulationStarting(EmuThread* emu_thread); void OnEmulationStopping(); @@ -175,6 +181,7 @@ signals: /// Emitted when the window is closed void Closed(); void FirstFrameDisplayed(); + void ExecuteProgramSignal(std::size_t program_index); private: void TouchBeginEvent(const QTouchEvent* event); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 56ab32a35..918bfb56b 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -27,6 +27,8 @@ #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" +using namespace Service::HID; + const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> ConfigureInputPlayer::analog_sub_buttons{{ "up", @@ -47,48 +49,12 @@ void UpdateController(Settings::ControllerType controller_type, std::size_t npad } Service::SM::ServiceManager& sm = system.ServiceManager(); - auto& npad = - sm.GetService<Service::HID::Hid>("hid") - ->GetAppletResource() - ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); + auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( + HidController::NPad); npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); } -/// Maps the controller type combobox index to Controller Type enum -constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { - switch (index) { - case 0: - default: - return Settings::ControllerType::ProController; - case 1: - return Settings::ControllerType::DualJoyconDetached; - case 2: - return Settings::ControllerType::LeftJoycon; - case 3: - return Settings::ControllerType::RightJoycon; - case 4: - return Settings::ControllerType::Handheld; - } -} - -/// Maps the Controller Type enum to controller type combobox index -constexpr int GetIndexFromControllerType(Settings::ControllerType type) { - switch (type) { - case Settings::ControllerType::ProController: - default: - return 0; - case Settings::ControllerType::DualJoyconDetached: - return 1; - case Settings::ControllerType::LeftJoycon: - return 2; - case Settings::ControllerType::RightJoycon: - return 3; - case Settings::ControllerType::Handheld: - return 4; - } -} - QString GetKeyName(int key_code) { switch (key_code) { case Qt::LeftButton: @@ -453,18 +419,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { emit Connected(checked); }); - // Set up controller type. Only Player 1 can choose Handheld. - ui->comboControllerType->clear(); - - QStringList controller_types = { - tr("Pro Controller"), - tr("Dual Joycons"), - tr("Left Joycon"), - tr("Right Joycon"), - }; - if (player_index == 0) { - controller_types.append(tr("Handheld")); connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) { emit HandheldStateChanged(GetControllerTypeFromIndex(index) == @@ -480,12 +435,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (debug) { ui->buttonScreenshot->setEnabled(false); ui->buttonHome->setEnabled(false); - QStringList debug_controller_types = { - tr("Pro Controller"), - }; - ui->comboControllerType->addItems(debug_controller_types); + ui->comboControllerType->addItem(tr("Pro Controller")); } else { - ui->comboControllerType->addItems(controller_types); + SetConnectableControllers(); } UpdateControllerIcon(); @@ -667,7 +619,7 @@ void ConfigureInputPlayer::LoadConfiguration() { return; } - ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type)); + ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type)); ui->groupConnectedController->setChecked( player.connected || (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); @@ -841,6 +793,82 @@ void ConfigureInputPlayer::UpdateUI() { } } +void ConfigureInputPlayer::SetConnectableControllers() { + const auto add_controllers = [this](bool enable_all, + Controller_NPad::NpadStyleSet npad_style_set = {}) { + index_controller_type_pairs.clear(); + ui->comboControllerType->clear(); + + if (enable_all || npad_style_set.pro_controller == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Settings::ControllerType::ProController); + ui->comboControllerType->addItem(tr("Pro Controller")); + } + + if (enable_all || npad_style_set.joycon_dual == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Settings::ControllerType::DualJoyconDetached); + ui->comboControllerType->addItem(tr("Dual Joycons")); + } + + if (enable_all || npad_style_set.joycon_left == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Settings::ControllerType::LeftJoycon); + ui->comboControllerType->addItem(tr("Left Joycon")); + } + + if (enable_all || npad_style_set.joycon_right == 1) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Settings::ControllerType::RightJoycon); + ui->comboControllerType->addItem(tr("Right Joycon")); + } + + if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { + index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), + Settings::ControllerType::Handheld); + ui->comboControllerType->addItem(tr("Handheld")); + } + }; + + Core::System& system{Core::System::GetInstance()}; + + if (!system.IsPoweredOn()) { + add_controllers(true); + return; + } + + Service::SM::ServiceManager& sm = system.ServiceManager(); + + auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( + HidController::NPad); + + add_controllers(false, npad.GetSupportedStyleSet()); +} + +Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { + const auto it = + std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), + [index](const auto& pair) { return pair.first == index; }); + + if (it == index_controller_type_pairs.end()) { + return Settings::ControllerType::ProController; + } + + return it->second; +} + +int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const { + const auto it = + std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), + [type](const auto& pair) { return pair.second == type; }); + + if (it == index_controller_type_pairs.end()) { + return -1; + } + + return it->first; +} + void ConfigureInputPlayer::UpdateInputDevices() { input_devices = input_subsystem->GetInputDevices(); ui->comboDevices->clear(); diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 23cf6f958..9c30879a2 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -9,6 +9,7 @@ #include <memory> #include <optional> #include <string> +#include <vector> #include <QWidget> @@ -112,6 +113,15 @@ private: /// Update UI to reflect current configuration. void UpdateUI(); + /// Sets the available controllers. + void SetConnectableControllers(); + + /// Gets the Controller Type for a given controller combobox index. + Settings::ControllerType GetControllerTypeFromIndex(int index) const; + + /// Gets the controller combobox index for a given Controller Type. + int GetIndexFromControllerType(Settings::ControllerType type) const; + /// Update the available input devices. void UpdateInputDevices(); @@ -151,6 +161,9 @@ private: std::unique_ptr<QTimer> timeout_timer; std::unique_ptr<QTimer> poll_timer; + /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. + std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs; + static constexpr int PLAYER_COUNT = 8; std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e704cc656..805619ccf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -978,7 +978,7 @@ void GMainWindow::AllowOSSleep() { #endif } -bool GMainWindow::LoadROM(const QString& filename) { +bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { // Shutdown previous session if the emu thread is still active... if (emu_thread != nullptr) ShutdownGame(); @@ -1003,7 +1003,8 @@ bool GMainWindow::LoadROM(const QString& filename) { system.RegisterHostThread(); - const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; + const Core::System::ResultStatus result{ + system.Load(*render_window, filename.toStdString(), program_index)}; const auto drd_callout = (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; @@ -1085,14 +1086,18 @@ void GMainWindow::SelectAndSetCurrentUser() { Settings::values.current_user = dialog.GetIndex(); } -void GMainWindow::BootGame(const QString& filename) { +void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { LOG_INFO(Frontend, "yuzu starting..."); StoreRecentFile(filename); // Put the filename on top of the list u64 title_id{0}; + + last_filename_booted = filename; + auto& system = Core::System::GetInstance(); const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(system, v_file); + const auto loader = Loader::GetLoader(system, v_file, program_index); + if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { // Load per game settings Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); @@ -1106,7 +1111,7 @@ void GMainWindow::BootGame(const QString& filename) { SelectAndSetCurrentUser(); } - if (!LoadROM(filename)) + if (!LoadROM(filename, program_index)) return; // Create and start the emulation thread @@ -1114,6 +1119,10 @@ void GMainWindow::BootGame(const QString& filename) { emit EmulationStarting(emu_thread.get()); emu_thread->start(); + // Register an ExecuteProgram callback such that Core can execute a sub-program + system.RegisterExecuteProgramCallback( + [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); + connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views // before the CPU continues @@ -2136,6 +2145,11 @@ void GMainWindow::OnLoadComplete() { loading_screen->OnLoadComplete(); } +void GMainWindow::OnExecuteProgram(std::size_t program_index) { + ShutdownGame(); + BootGame(last_filename_booted, program_index); +} + void GMainWindow::ErrorDisplayDisplayError(QString body) { QMessageBox::critical(this, tr("Error Display"), body); emit ErrorDisplayFinished(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b380a66f3..6242341d1 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -131,6 +131,7 @@ signals: public slots: void OnLoadComplete(); + void OnExecuteProgram(std::size_t program_index); void ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters); void ErrorDisplayDisplayError(QString body); @@ -154,8 +155,8 @@ private: void PreventOSSleep(); void AllowOSSleep(); - bool LoadROM(const QString& filename); - void BootGame(const QString& filename); + bool LoadROM(const QString& filename, std::size_t program_index); + void BootGame(const QString& filename, std::size_t program_index = 0); void ShutdownGame(); void ShowTelemetryCallout(); @@ -317,6 +318,9 @@ private: // Install progress dialog QProgressDialog* install_progress; + // Last game booted, used for multi-process apps + QString last_filename_booted; + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; |