From 9427e27e24a7135880ee2881c3c44988e174b41a Mon Sep 17 00:00:00 2001 From: Zephyron Date: Tue, 31 Dec 2024 16:19:25 +1000 Subject: chore: update project branding to citron --- src/yuzu/applets/qt_amiibo_settings.cpp | 274 --- src/yuzu/applets/qt_amiibo_settings.h | 85 - src/yuzu/applets/qt_amiibo_settings.ui | 494 ---- src/yuzu/applets/qt_controller.cpp | 778 ------- src/yuzu/applets/qt_controller.h | 183 -- src/yuzu/applets/qt_controller.ui | 2699 ---------------------- src/yuzu/applets/qt_error.cpp | 68 - src/yuzu/applets/qt_error.h | 34 - src/yuzu/applets/qt_profile_select.cpp | 260 --- src/yuzu/applets/qt_profile_select.h | 87 - src/yuzu/applets/qt_software_keyboard.cpp | 1674 -------------- src/yuzu/applets/qt_software_keyboard.h | 287 --- src/yuzu/applets/qt_software_keyboard.ui | 3541 ----------------------------- src/yuzu/applets/qt_web_browser.cpp | 449 ---- src/yuzu/applets/qt_web_browser.h | 220 -- src/yuzu/applets/qt_web_browser_scripts.h | 198 -- 16 files changed, 11331 deletions(-) delete mode 100644 src/yuzu/applets/qt_amiibo_settings.cpp delete mode 100644 src/yuzu/applets/qt_amiibo_settings.h delete mode 100644 src/yuzu/applets/qt_amiibo_settings.ui delete mode 100644 src/yuzu/applets/qt_controller.cpp delete mode 100644 src/yuzu/applets/qt_controller.h delete mode 100644 src/yuzu/applets/qt_controller.ui delete mode 100644 src/yuzu/applets/qt_error.cpp delete mode 100644 src/yuzu/applets/qt_error.h delete mode 100644 src/yuzu/applets/qt_profile_select.cpp delete mode 100644 src/yuzu/applets/qt_profile_select.h delete mode 100644 src/yuzu/applets/qt_software_keyboard.cpp delete mode 100644 src/yuzu/applets/qt_software_keyboard.h delete mode 100644 src/yuzu/applets/qt_software_keyboard.ui delete mode 100644 src/yuzu/applets/qt_web_browser.cpp delete mode 100644 src/yuzu/applets/qt_web_browser.h delete mode 100644 src/yuzu/applets/qt_web_browser_scripts.h (limited to 'src/yuzu/applets') diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp deleted file mode 100644 index b91796dde..000000000 --- a/src/yuzu/applets/qt_amiibo_settings.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include -#include - -#include "common/assert.h" -#include "common/string_util.h" -#include "core/hle/service/nfc/common/device.h" -#include "core/hle/service/nfp/nfp_result.h" -#include "input_common/drivers/virtual_amiibo.h" -#include "input_common/main.h" -#include "ui_qt_amiibo_settings.h" -#ifdef ENABLE_WEB_SERVICE -#include "web_service/web_backend.h" -#endif -#include "yuzu/applets/qt_amiibo_settings.h" -#include "yuzu/main.h" - -QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, - Core::Frontend::CabinetParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, - std::shared_ptr nfp_device_) - : QDialog(parent), ui(std::make_unique()), - input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)}, - parameters(std::move(parameters_)) { - ui->setupUi(this); - - LoadInfo(); - - resize(0, 0); -} - -QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default; - -int QtAmiiboSettingsDialog::exec() { - if (!is_initialized) { - return QDialog::Rejected; - } - return QDialog::exec(); -} - -std::string QtAmiiboSettingsDialog::GetName() const { - return ui->amiiboCustomNameValue->text().toStdString(); -} - -void QtAmiiboSettingsDialog::LoadInfo() { - if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() != - InputCommon::VirtualAmiibo::Info::Success) { - return; - } - - if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound && - nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) { - return; - } - nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All); - - LoadAmiiboInfo(); - LoadAmiiboData(); - LoadAmiiboGameInfo(); - - ui->amiiboDirectoryValue->setText( - QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); - - SetSettingsDescription(); - is_initialized = true; -} - -void QtAmiiboSettingsDialog::LoadAmiiboInfo() { - Service::NFP::ModelInfo model_info{}; - const auto model_result = nfp_device->GetModelInfo(model_info); - - if (model_result.IsFailure()) { - ui->amiiboImageLabel->setVisible(false); - ui->amiiboInfoGroup->setVisible(false); - return; - } - - const auto amiibo_id = - fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id), - model_info.character_variant, model_info.amiibo_type, model_info.model_number, - model_info.series); - - LOG_DEBUG(Frontend, "Loading amiibo id {}", amiibo_id); - // Note: This function is not being used until we host the images on our server - // LoadAmiiboApiInfo(amiibo_id); - ui->amiiboImageLabel->setVisible(false); - ui->amiiboInfoGroup->setVisible(false); -} - -void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) { -#ifdef ENABLE_WEB_SERVICE - // TODO: Host this data on our website - WebService::Client client{"https://amiiboapi.com", {}, {}}; - WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; - const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); - - const auto amiibo_json = client.GetJson(url_path, true).returned_data; - if (amiibo_json.empty()) { - ui->amiiboImageLabel->setVisible(false); - ui->amiiboInfoGroup->setVisible(false); - return; - } - - std::string amiibo_series{}; - std::string amiibo_name{}; - std::string amiibo_image_url{}; - std::string amiibo_type{}; - - const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); - parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); - parsed_amiibo_json_json.at("name").get_to(amiibo_name); - parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); - parsed_amiibo_json_json.at("type").get_to(amiibo_type); - - ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); - ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); - ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); - - if (amiibo_image_url.size() < 34) { - ui->amiiboImageLabel->setVisible(false); - } - - const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); - const auto image_data = image_client.GetImage(image_url_path, true).returned_data; - - if (image_data.empty()) { - ui->amiiboImageLabel->setVisible(false); - } - - QPixmap pixmap; - pixmap.loadFromData(reinterpret_cast(image_data.data()), - static_cast(image_data.size())); - pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, - Qt::TransformationMode::SmoothTransformation); - ui->amiiboImageLabel->setPixmap(pixmap); -#endif -} - -void QtAmiiboSettingsDialog::LoadAmiiboData() { - Service::NFP::RegisterInfo register_info{}; - Service::NFP::CommonInfo common_info{}; - const auto register_result = nfp_device->GetRegisterInfo(register_info); - const auto common_result = nfp_device->GetCommonInfo(common_info); - - if (register_result.IsFailure()) { - ui->creationDateValue->setDisabled(true); - ui->modificationDateValue->setDisabled(true); - ui->amiiboCustomNameValue->setReadOnly(false); - ui->amiiboOwnerValue->setReadOnly(false); - return; - } - - if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) { - ui->creationDateValue->setDisabled(true); - ui->modificationDateValue->setDisabled(true); - } - - const auto amiibo_name = std::string(register_info.amiibo_name.data()); - const auto owner_name = - Common::UTF16ToUTF8(register_info.mii_char_info.GetNickname().data.data()); - const auto creation_date = - QDate(register_info.creation_date.year, register_info.creation_date.month, - register_info.creation_date.day); - - ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name)); - ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name)); - ui->amiiboCustomNameValue->setReadOnly(true); - ui->amiiboOwnerValue->setReadOnly(true); - ui->creationDateValue->setDate(creation_date); - - if (common_result.IsFailure()) { - ui->modificationDateValue->setDisabled(true); - return; - } - - const auto modification_date = - QDate(common_info.last_write_date.year, common_info.last_write_date.month, - common_info.last_write_date.day); - ui->modificationDateValue->setDate(modification_date); -} - -void QtAmiiboSettingsDialog::LoadAmiiboGameInfo() { - u32 application_area_id{}; - const auto application_result = nfp_device->GetApplicationAreaId(application_area_id); - - if (application_result.IsFailure()) { - ui->gameIdValue->setVisible(false); - ui->gameIdLabel->setText(tr("No game data present")); - return; - } - - SetGameDataName(application_area_id); -} - -void QtAmiiboSettingsDialog::SetGameDataName(u32 application_area_id) { - static constexpr std::array, 12> game_name_list = { - // 3ds, wii u - std::pair{0x10110E00, "Super Smash Bros (3DS/WiiU)"}, - {0x00132600, "Mario & Luigi: Paper Jam"}, - {0x0014F000, "Animal Crossing: Happy Home Designer"}, - {0x00152600, "Chibi-Robo!: Zip Lash"}, - {0x10161f00, "Mario Party 10"}, - {0x1019C800, "The Legend of Zelda: Twilight Princess HD"}, - // switch - {0x10162B00, "Splatoon 2"}, - {0x1016e100, "Shovel Knight: Treasure Trove"}, - {0x1019C800, "The Legend of Zelda: Breath of the Wild"}, - {0x34F80200, "Super Smash Bros. Ultimate"}, - {0x38600500, "Splatoon 3"}, - {0x3B440400, "The Legend of Zelda: Link's Awakening"}, - }; - - for (const auto& [game_id, game_name] : game_name_list) { - if (application_area_id == game_id) { - ui->gameIdValue->setText(QString::fromStdString(game_name)); - return; - } - } - - const auto application_area_string = fmt::format("{:016x}", application_area_id); - ui->gameIdValue->setText(QString::fromStdString(application_area_string)); -} - -void QtAmiiboSettingsDialog::SetSettingsDescription() { - switch (parameters.mode) { - case Service::NFP::CabinetMode::StartFormatter: - ui->cabinetActionDescriptionLabel->setText( - tr("The following amiibo data will be formatted:")); - break; - case Service::NFP::CabinetMode::StartGameDataEraser: - ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:")); - break; - case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: - ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:")); - break; - case Service::NFP::CabinetMode::StartRestorer: - ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo?")); - break; - } -} - -QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) { - connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent, - &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection); - connect(this, &QtAmiiboSettings::MainWindowRequestExit, &parent, - &GMainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection); - connect(&parent, &GMainWindow::AmiiboSettingsFinished, this, - &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection); -} - -QtAmiiboSettings::~QtAmiiboSettings() = default; - -void QtAmiiboSettings::Close() const { - callback = {}; - emit MainWindowRequestExit(); -} - -void QtAmiiboSettings::ShowCabinetApplet( - const Core::Frontend::CabinetCallback& callback_, - const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const { - callback = std::move(callback_); - emit MainWindowShowAmiiboSettings(parameters, nfp_device); -} - -void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) { - if (callback) { - callback(is_success, name); - } -} diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h deleted file mode 100644 index 3833cf6f2..000000000 --- a/src/yuzu/applets/qt_amiibo_settings.h +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include "core/frontend/applets/cabinet.h" - -class GMainWindow; -class QCheckBox; -class QComboBox; -class QDialogButtonBox; -class QGroupBox; -class QLabel; - -namespace InputCommon { -class InputSubsystem; -} - -namespace Ui { -class QtAmiiboSettingsDialog; -} - -namespace Service::NFC { -class NfcDevice; -} // namespace Service::NFC - -class QtAmiiboSettingsDialog final : public QDialog { - Q_OBJECT - -public: - explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, - std::shared_ptr nfp_device_); - ~QtAmiiboSettingsDialog() override; - - int exec() override; - - std::string GetName() const; - -private: - void LoadInfo(); - void LoadAmiiboInfo(); - void LoadAmiiboApiInfo(std::string_view amiibo_id); - void LoadAmiiboData(); - void LoadAmiiboGameInfo(); - void SetGameDataName(u32 application_area_id); - void SetSettingsDescription(); - - std::unique_ptr ui; - - InputCommon::InputSubsystem* input_subsystem; - std::shared_ptr nfp_device; - - // Parameters sent in from the backend HLE applet. - Core::Frontend::CabinetParameters parameters; - - // If false amiibo settings failed to load - bool is_initialized{}; -}; - -class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet { - Q_OBJECT - -public: - explicit QtAmiiboSettings(GMainWindow& parent); - ~QtAmiiboSettings() override; - - void Close() const override; - void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, - const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const override; - -signals: - void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const; - void MainWindowRequestExit() const; - -private: - void MainWindowFinished(bool is_success, const std::string& name); - - mutable Core::Frontend::CabinetCallback callback; -}; diff --git a/src/yuzu/applets/qt_amiibo_settings.ui b/src/yuzu/applets/qt_amiibo_settings.ui deleted file mode 100644 index f377a6e61..000000000 --- a/src/yuzu/applets/qt_amiibo_settings.ui +++ /dev/null @@ -1,494 +0,0 @@ - - - QtAmiiboSettingsDialog - - - - 0 - 0 - 839 - 500 - - - - Amiibo Settings - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 10 - - - 20 - - - 15 - - - 0 - - - 15 - - - - - - 12 - 75 - true - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - 15 - - - 15 - - - - - - 250 - 350 - - - - - 236 - 350 - - - - - - - Qt::AlignCenter - - - - - - - 0 - - - 8 - - - 15 - - - - - Amiibo Info - - - - - - - - Series - - - - - - - - 0 - 0 - - - - true - - - - - - - Type - - - - - - - - 0 - 0 - - - - true - - - - - - - Name - - - - - - - - 0 - 0 - - - - true - - - - - - - - - - - - Amiibo Data - - - - - - - - Custom Name - - - - - - - - 0 - 0 - - - - 10 - - - - - - - Owner - - - - - - - - 0 - 0 - - - - 10 - - - - - - - Creation Date - - - - - - - true - - - - 1970 - 1 - 1 - - - - dd/MM/yyyy - - - - - - - Modification Date - - - - - - - true - - - - 1970 - 1 - 1 - - - - dd/MM/yyyy - - - - - - - - - - - - - 500 - 0 - - - - Game Data - - - - - - Game Id - - - - - - - - 0 - 0 - - - - true - - - - - - - - - - - 500 - 0 - - - - Mount Amiibo - - - - - - ... - - - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 60 - 20 - - - - - - - - File Path - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - 15 - - - 15 - - - 8 - - - 20 - - - 8 - - - - - true - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - - - - - buttonBox - accepted() - QtAmiiboSettingsDialog - accept() - - - buttonBox - rejected() - QtAmiiboSettingsDialog - reject() - - - diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp deleted file mode 100644 index 48ce860ad..000000000 --- a/src/yuzu/applets/qt_controller.cpp +++ /dev/null @@ -1,778 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include - -#include "common/assert.h" -#include "common/settings.h" -#include "common/settings_enums.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/hle/service/sm/sm.h" -#include "hid_core/frontend/emulated_controller.h" -#include "hid_core/hid_core.h" -#include "hid_core/hid_types.h" -#include "hid_core/resources/npad/npad.h" -#include "ui_qt_controller.h" -#include "yuzu/applets/qt_controller.h" -#include "yuzu/configuration/configure_input.h" -#include "yuzu/configuration/configure_input_profile_dialog.h" -#include "yuzu/configuration/configure_motion_touch.h" -#include "yuzu/configuration/configure_vibration.h" -#include "yuzu/configuration/input_profiles.h" -#include "yuzu/main.h" -#include "yuzu/util/controller_navigation.h" - -namespace { - -void UpdateController(Core::HID::EmulatedController* controller, - Core::HID::NpadStyleIndex controller_type, bool connected) { - if (controller->IsConnected(true)) { - controller->Disconnect(); - } - controller->SetNpadStyleIndex(controller_type); - if (connected) { - controller->Connect(true); - } -} - -// Returns true if the given controller type is compatible with the given parameters. -bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, - Core::Frontend::ControllerParameters parameters) { - switch (controller_type) { - case Core::HID::NpadStyleIndex::Fullkey: - return parameters.allow_pro_controller; - case Core::HID::NpadStyleIndex::JoyconDual: - return parameters.allow_dual_joycons; - case Core::HID::NpadStyleIndex::JoyconLeft: - return parameters.allow_left_joycon; - case Core::HID::NpadStyleIndex::JoyconRight: - return parameters.allow_right_joycon; - case Core::HID::NpadStyleIndex::Handheld: - return parameters.enable_single_mode && parameters.allow_handheld; - case Core::HID::NpadStyleIndex::GameCube: - return parameters.allow_gamecube_controller; - default: - return false; - } -} - -} // namespace - -QtControllerSelectorDialog::QtControllerSelectorDialog( - QWidget* parent, Core::Frontend::ControllerParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, Core::System& system_) - : QDialog(parent), ui(std::make_unique()), - parameters(std::move(parameters_)), input_subsystem{input_subsystem_}, - input_profiles(std::make_unique()), system{system_} { - ui->setupUi(this); - - player_widgets = { - ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4, - ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8, - }; - - player_groupboxes = { - ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected, - ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected, - ui->groupPlayer7Connected, ui->groupPlayer8Connected, - }; - - connected_controller_icons = { - ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4, - ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8, - }; - - led_patterns_boxes = {{ - {ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3, - ui->checkboxPlayer1LED4}, - {ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3, - ui->checkboxPlayer2LED4}, - {ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3, - ui->checkboxPlayer3LED4}, - {ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3, - ui->checkboxPlayer4LED4}, - {ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3, - ui->checkboxPlayer5LED4}, - {ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3, - ui->checkboxPlayer6LED4}, - {ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3, - ui->checkboxPlayer7LED4}, - {ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3, - ui->checkboxPlayer8LED4}, - }}; - - explain_text_labels = { - ui->labelPlayer1Explain, ui->labelPlayer2Explain, ui->labelPlayer3Explain, - ui->labelPlayer4Explain, ui->labelPlayer5Explain, ui->labelPlayer6Explain, - ui->labelPlayer7Explain, ui->labelPlayer8Explain, - }; - - emulated_controllers = { - ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated, - ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated, - ui->comboPlayer7Emulated, ui->comboPlayer8Emulated, - }; - - player_labels = { - ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4, - ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8, - }; - - connected_controller_labels = { - ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3, - ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6, - ui->labelConnectedPlayer7, ui->labelConnectedPlayer8, - }; - - connected_controller_checkboxes = { - ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected, - ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected, - ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected, - }; - - ui->labelError->setVisible(false); - - // Setup/load everything prior to setting up connections. - // 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(); - - controller_navigation = new ControllerNavigation(system.HIDCore(), this); - - for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { - SetExplainText(i); - UpdateControllerIcon(i); - UpdateLEDPattern(i); - UpdateBorderColor(i); - - connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) { - // Reconnect current controller if it was the last one checked - // (player number was reduced by more than one) - const bool reconnect_first = !checked && i < player_groupboxes.size() - 1 && - player_groupboxes[i + 1]->isChecked(); - - // Ensures that connecting a controller changes the number of players - if (connected_controller_checkboxes[i]->isChecked() != checked) { - // Ensures that the players are always connected in sequential order - PropagatePlayerNumberChanged(i, checked, reconnect_first); - } - }); - connect(connected_controller_checkboxes[i], &QCheckBox::clicked, [this, i](bool checked) { - // Reconnect current controller if it was the last one checked - // (player number was reduced by more than one) - const bool reconnect_first = !checked && - i < connected_controller_checkboxes.size() - 1 && - connected_controller_checkboxes[i + 1]->isChecked(); - - // Ensures that the players are always connected in sequential order - PropagatePlayerNumberChanged(i, checked, reconnect_first); - }); - - connect(emulated_controllers[i], qOverload(&QComboBox::currentIndexChanged), - [this, i](int) { - UpdateControllerIcon(i); - UpdateControllerState(i); - UpdateLEDPattern(i); - CheckIfParametersMet(); - }); - - connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) { - player_groupboxes[i]->setChecked(state == Qt::Checked); - UpdateControllerIcon(i); - UpdateControllerState(i); - UpdateLEDPattern(i); - UpdateBorderColor(i); - CheckIfParametersMet(); - }); - - if (i == 0) { - connect(emulated_controllers[i], qOverload(&QComboBox::currentIndexChanged), - [this, i](int index) { - UpdateDockedState(GetControllerTypeFromIndex(index, i) == - Core::HID::NpadStyleIndex::Handheld); - }); - } - } - - connect(ui->vibrationButton, &QPushButton::clicked, this, - &QtControllerSelectorDialog::CallConfigureVibrationDialog); - - connect(ui->motionButton, &QPushButton::clicked, this, - &QtControllerSelectorDialog::CallConfigureMotionTouchDialog); - - connect(ui->inputConfigButton, &QPushButton::clicked, this, - &QtControllerSelectorDialog::CallConfigureInputProfileDialog); - - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, - &QtControllerSelectorDialog::ApplyConfiguration); - - connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, - [this](Qt::Key key) { - QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); - QCoreApplication::postEvent(this, event); - }); - - // Enhancement: Check if the parameters have already been met before disconnecting controllers. - // If all the parameters are met AND only allows a single player, - // stop the constructor here as we do not need to continue. - if (CheckIfParametersMet() && parameters.enable_single_mode) { - return; - } - - // If keep_controllers_connected is false, forcefully disconnect all controllers - if (!parameters.keep_controllers_connected) { - for (auto player : player_groupboxes) { - player->setChecked(false); - } - } - - resize(0, 0); -} - -QtControllerSelectorDialog::~QtControllerSelectorDialog() { - controller_navigation->UnloadController(); - system.HIDCore().DisableAllControllerConfiguration(); -} - -int QtControllerSelectorDialog::exec() { - if (parameters_met && parameters.enable_single_mode) { - return QDialog::Accepted; - } - return QDialog::exec(); -} - -void QtControllerSelectorDialog::ApplyConfiguration() { - const bool pre_docked_mode = Settings::IsDockedMode(); - const bool docked_mode_selected = ui->radioDocked->isChecked(); - Settings::values.use_docked_mode.SetValue( - docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld); - OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system); - - Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); - Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); -} - -void QtControllerSelectorDialog::LoadConfiguration() { - system.HIDCore().EnableAllControllerConfiguration(); - - const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); - const auto connected = - controller->IsConnected(true) || (index == 0 && handheld->IsConnected(true)); - player_groupboxes[index]->setChecked(connected); - connected_controller_checkboxes[index]->setChecked(connected); - emulated_controllers[index]->setCurrentIndex( - GetIndexFromControllerType(controller->GetNpadStyleIndex(true), index)); - } - - UpdateDockedState(handheld->IsConnected(true)); - - ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); - ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); -} - -void QtControllerSelectorDialog::CallConfigureVibrationDialog() { - ConfigureVibration dialog(this, system.HIDCore()); - - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint); - dialog.setWindowModality(Qt::WindowModal); - - if (dialog.exec() == QDialog::Accepted) { - dialog.ApplyConfiguration(); - } -} - -void QtControllerSelectorDialog::CallConfigureMotionTouchDialog() { - ConfigureMotionTouch dialog(this, input_subsystem); - - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint); - dialog.setWindowModality(Qt::WindowModal); - - if (dialog.exec() == QDialog::Accepted) { - dialog.ApplyConfiguration(); - } -} - -void QtControllerSelectorDialog::CallConfigureInputProfileDialog() { - ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get(), system); - - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint); - dialog.setWindowModality(Qt::WindowModal); - dialog.exec(); -} - -void QtControllerSelectorDialog::keyPressEvent(QKeyEvent* evt) { - const auto num_connected_players = static_cast( - std::count_if(player_groupboxes.begin(), player_groupboxes.end(), - [](const QGroupBox* player) { return player->isChecked(); })); - - const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players; - const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players; - - if ((evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) && !parameters_met) { - // Display error message when trying to validate using "Enter" and "OK" button is disabled - ui->labelError->setVisible(true); - return; - } else if (evt->key() == Qt::Key_Left && num_connected_players > min_supported_players) { - // Remove a player if possible - connected_controller_checkboxes[num_connected_players - 1]->setChecked(false); - return; - } else if (evt->key() == Qt::Key_Right && num_connected_players < max_supported_players) { - // Add a player, if possible - ui->labelError->setVisible(false); - connected_controller_checkboxes[num_connected_players]->setChecked(true); - return; - } - QDialog::keyPressEvent(evt); -} - -bool QtControllerSelectorDialog::CheckIfParametersMet() { - // Here, we check and validate the current configuration against all applicable parameters. - const auto num_connected_players = static_cast( - std::count_if(player_groupboxes.begin(), player_groupboxes.end(), - [](const QGroupBox* player) { return player->isChecked(); })); - - const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players; - const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players; - - // First, check against the number of connected players. - if (num_connected_players < min_supported_players || - num_connected_players > max_supported_players) { - parameters_met = false; - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); - return parameters_met; - } - - // Next, check against all connected controllers. - const auto all_controllers_compatible = [this] { - for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - // Skip controllers that are not used, we only care about the currently connected ones. - if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) { - continue; - } - - const auto compatible = IsControllerCompatible( - GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index), - parameters); - - // If any controller is found to be incompatible, return false early. - if (!compatible) { - return false; - } - } - - // Reaching here means all currently connected controllers are compatible. - return true; - }(); - - parameters_met = all_controllers_compatible; - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); - return parameters_met; -} - -void QtControllerSelectorDialog::SetSupportedControllers() { - const QString theme = [] { - if (QIcon::themeName().contains(QStringLiteral("dark"))) { - return QStringLiteral("_dark"); - } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { - return QStringLiteral("_midnight"); - } else { - return QString{}; - } - }(); - - if (parameters.enable_single_mode && parameters.allow_handheld) { - ui->controllerSupported1->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme)); - } else { - ui->controllerSupported1->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme)); - } - - if (parameters.allow_dual_joycons) { - ui->controllerSupported2->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme)); - } else { - ui->controllerSupported2->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme)); - } - - if (parameters.allow_left_joycon) { - ui->controllerSupported3->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme)); - } else { - ui->controllerSupported3->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme)); - } - - if (parameters.allow_right_joycon) { - ui->controllerSupported4->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme)); - } else { - ui->controllerSupported4->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme)); - } - - if (parameters.allow_pro_controller || parameters.allow_gamecube_controller) { - ui->controllerSupported5->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme)); - } else { - ui->controllerSupported5->setStyleSheet( - QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ") - .arg(theme)); - } - - // enable_single_mode overrides min_players and max_players. - if (parameters.enable_single_mode) { - ui->numberSupportedLabel->setText(QStringLiteral("1")); - return; - } - - if (parameters.min_players == parameters.max_players) { - ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players)); - } else { - ui->numberSupportedLabel->setText( - QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players)); - } -} - -void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { - const auto npad_style_set = system.HIDCore().GetSupportedStyleTag(); - auto& pairs = index_controller_type_pairs[player_index]; - - pairs.clear(); - emulated_controllers[player_index]->clear(); - - const auto add_item = [&](Core::HID::NpadStyleIndex controller_type, - const QString& controller_name) { - pairs.emplace_back(emulated_controllers[player_index]->count(), controller_type); - emulated_controllers[player_index]->addItem(controller_name); - }; - - if (npad_style_set.fullkey == 1) { - add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller")); - } - - if (npad_style_set.joycon_dual == 1) { - add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons")); - } - - if (npad_style_set.joycon_left == 1) { - add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon")); - } - - if (npad_style_set.joycon_right == 1) { - add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon")); - } - - if (player_index == 0 && npad_style_set.handheld == 1) { - add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld")); - } - - if (npad_style_set.gamecube == 1) { - add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller")); - } - - // Disable all unsupported controllers - if (!Settings::values.enable_all_controllers) { - return; - } - - if (npad_style_set.palma == 1) { - add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus")); - } - - if (npad_style_set.lark == 1) { - add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller")); - } - - if (npad_style_set.lucia == 1) { - add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller")); - } - - if (npad_style_set.lagoon == 1) { - add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller")); - } - - if (npad_style_set.lager == 1) { - add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis")); - } -} - -Core::HID::NpadStyleIndex 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 Core::HID::NpadStyleIndex::Fullkey; - } - - return it->second; -} - -int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex 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{}); - player_labels[player_index]->show(); - return; - } - - const QString stylesheet = [this, player_index] { - switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), - player_index)) { - case Core::HID::NpadStyleIndex::Fullkey: - case Core::HID::NpadStyleIndex::GameCube: - return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); - case Core::HID::NpadStyleIndex::JoyconDual: - return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); - case Core::HID::NpadStyleIndex::JoyconLeft: - return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); - case Core::HID::NpadStyleIndex::JoyconRight: - return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); - case Core::HID::NpadStyleIndex::Handheld: - return QStringLiteral("image: url(:/controller/applet_handheld%0); "); - default: - return QString{}; - } - }(); - - 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"); - } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { - return QStringLiteral("_midnight"); - } else { - return QString{}; - } - }(); - - connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme)); - player_labels[player_index]->hide(); -} - -void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { - auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); - - const auto controller_type = GetControllerTypeFromIndex( - emulated_controllers[player_index]->currentIndex(), player_index); - const auto player_connected = player_groupboxes[player_index]->isChecked() && - controller_type != Core::HID::NpadStyleIndex::Handheld; - - if (controller->GetNpadStyleIndex(true) == controller_type && - controller->IsConnected(true) == player_connected) { - return; - } - - // Disconnect the controller first. - UpdateController(controller, controller_type, false); - - // Handheld - if (player_index == 0) { - if (controller_type == Core::HID::NpadStyleIndex::Handheld) { - auto* handheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - UpdateController(handheld, Core::HID::NpadStyleIndex::Handheld, - player_groupboxes[player_index]->isChecked()); - } - } - - UpdateController(controller, controller_type, player_connected); -} - -void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { - if (!player_groupboxes[player_index]->isChecked() || - GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), - player_index) == Core::HID::NpadStyleIndex::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); - led_patterns_boxes[player_index][3]->setChecked(false); - return; - } - - const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); - const auto led_pattern = controller->GetLedPattern(); - led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1); - led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2); - led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3); - led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4); -} - -void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) { - if (!parameters.enable_border_color || - player_index >= static_cast(parameters.max_players) || - player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) { - return; - } - - player_groupboxes[player_index]->setStyleSheet( - player_groupboxes[player_index]->styleSheet().append( - QStringLiteral("QGroupBox#groupPlayer%1Connected:checked " - "{ border: 1px solid rgba(%2, %3, %4, %5); }") - .arg(player_index + 1) - .arg(parameters.border_colors[player_index][0]) - .arg(parameters.border_colors[player_index][1]) - .arg(parameters.border_colors[player_index][2]) - .arg(parameters.border_colors[player_index][3]))); -} - -void QtControllerSelectorDialog::SetExplainText(std::size_t player_index) { - if (!parameters.enable_explain_text || - player_index >= static_cast(parameters.max_players)) { - return; - } - - explain_text_labels[player_index]->setText(QString::fromStdString( - Common::StringFromFixedZeroTerminatedBuffer(parameters.explain_text[player_index].data(), - parameters.explain_text[player_index].size()))); -} - -void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) { - // Disallow changing the console mode if the controller type is handheld. - ui->radioDocked->setEnabled(!is_handheld); - ui->radioUndocked->setEnabled(!is_handheld); - - ui->radioDocked->setChecked(Settings::IsDockedMode()); - ui->radioUndocked->setChecked(!Settings::IsDockedMode()); - - // Also force into undocked mode if the controller type is handheld. - if (is_handheld) { - ui->radioUndocked->setChecked(true); - } -} - -void QtControllerSelectorDialog::PropagatePlayerNumberChanged(size_t player_index, bool checked, - bool reconnect_current) { - connected_controller_checkboxes[player_index]->setChecked(checked); - // Hide eventual error message about number of controllers - ui->labelError->setVisible(false); - - if (checked) { - // Check all previous buttons when checked - if (player_index > 0) { - PropagatePlayerNumberChanged(player_index - 1, checked); - } - } else { - // Unchecked all following buttons when unchecked - if (player_index < connected_controller_checkboxes.size() - 1) { - PropagatePlayerNumberChanged(player_index + 1, checked); - } - } - - if (reconnect_current) { - connected_controller_checkboxes[player_index]->setCheckState(Qt::Checked); - } -} - -void QtControllerSelectorDialog::DisableUnsupportedPlayers() { - const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players; - - switch (max_supported_players) { - case 0: - default: - ASSERT(false); - return; - case 1: - ui->widgetSpacer->hide(); - ui->widgetSpacer2->hide(); - ui->widgetSpacer3->hide(); - ui->widgetSpacer4->hide(); - break; - case 2: - ui->widgetSpacer->hide(); - ui->widgetSpacer2->hide(); - ui->widgetSpacer3->hide(); - break; - case 3: - ui->widgetSpacer->hide(); - ui->widgetSpacer2->hide(); - break; - case 4: - ui->widgetSpacer->hide(); - break; - case 5: - case 6: - case 7: - case 8: - break; - } - - for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { - auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); - // Disconnect any unsupported players here and disable or hide them if applicable. - UpdateController(controller, controller->GetNpadStyleIndex(true), false); - // Hide the player widgets when max_supported_controllers is less than or equal to 4. - if (max_supported_players <= 4) { - player_widgets[index]->hide(); - } - - // Disable and hide the following to prevent these from interaction. - player_widgets[index]->setDisabled(true); - connected_controller_checkboxes[index]->setDisabled(true); - connected_controller_labels[index]->hide(); - connected_controller_checkboxes[index]->hide(); - } -} - -QtControllerSelector::QtControllerSelector(GMainWindow& parent) { - connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent, - &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection); - connect(this, &QtControllerSelector::MainWindowRequestExit, &parent, - &GMainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection); - connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this, - &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection); -} - -QtControllerSelector::~QtControllerSelector() = default; - -void QtControllerSelector::Close() const { - callback = {}; - emit MainWindowRequestExit(); -} - -void QtControllerSelector::ReconfigureControllers( - ReconfigureCallback callback_, const Core::Frontend::ControllerParameters& parameters) const { - callback = std::move(callback_); - emit MainWindowReconfigureControllers(parameters); -} - -void QtControllerSelector::MainWindowReconfigureFinished(bool is_success) { - if (callback) { - callback(is_success); - } -} diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h deleted file mode 100644 index e5372495d..000000000 --- a/src/yuzu/applets/qt_controller.h +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include "core/frontend/applets/controller.h" - -class GMainWindow; -class QCheckBox; -class QComboBox; -class QDialogButtonBox; -class QGroupBox; -class QLabel; - -class InputProfiles; - -namespace InputCommon { -class InputSubsystem; -} - -namespace Ui { -class QtControllerSelectorDialog; -} - -namespace Core { -class System; -} - -namespace Core::HID { -class HIDCore; -enum class NpadStyleIndex : u8; -} // namespace Core::HID - -class ControllerNavigation; - -class QtControllerSelectorDialog final : public QDialog { - Q_OBJECT - -public: - explicit QtControllerSelectorDialog(QWidget* parent, - Core::Frontend::ControllerParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, - Core::System& system_); - ~QtControllerSelectorDialog() override; - - int exec() override; - - void keyPressEvent(QKeyEvent* evt) override; - -private: - // Applies the current configuration. - void ApplyConfiguration(); - - // Loads the current input configuration into the frontend applet. - void LoadConfiguration(); - - // Initializes the "Configure Vibration" Dialog. - void CallConfigureVibrationDialog(); - - // Initializes the "Configure Motion / Touch" Dialog. - void CallConfigureMotionTouchDialog(); - - // Initializes the "Create Input Profile" Dialog. - void CallConfigureInputProfileDialog(); - - // Checks the current configuration against the given parameters. - // This sets and returns the value of parameters_met. - bool CheckIfParametersMet(); - - // 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. - Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const; - - // Gets the controller combobox index for a given Controller Type per player. - int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const; - - // Updates the controller icons per player. - void UpdateControllerIcon(std::size_t player_index); - - // Updates the controller state (type and connection status) per player. - void UpdateControllerState(std::size_t player_index); - - // Updates the LED pattern per player. - void UpdateLEDPattern(std::size_t player_index); - - // Updates the border color per player. - void UpdateBorderColor(std::size_t player_index); - - // Sets the "Explain Text" per player. - void SetExplainText(std::size_t player_index); - - // Updates the console mode. - void UpdateDockedState(bool is_handheld); - - // Enable preceding controllers or disable following ones - void PropagatePlayerNumberChanged(size_t player_index, bool checked, - bool reconnect_current = false); - - // Disables and disconnects unsupported players based on the given parameters. - void DisableUnsupportedPlayers(); - - std::unique_ptr ui; - - // Parameters sent in from the backend HLE applet. - Core::Frontend::ControllerParameters parameters; - - InputCommon::InputSubsystem* input_subsystem; - - std::unique_ptr input_profiles; - - Core::System& system; - - ControllerNavigation* controller_navigation = nullptr; - - // This is true if and only if all parameters are met. Otherwise, this is false. - // This determines whether the "OK" button can be clicked to exit the applet. - bool parameters_met{false}; - - static constexpr std::size_t NUM_PLAYERS = 8; - - // Widgets encapsulating the groupboxes and comboboxes per player. - std::array player_widgets; - - // Groupboxes encapsulating the controller icons and LED patterns per player. - std::array player_groupboxes; - - // Icons for currently connected controllers/players. - std::array connected_controller_icons; - - // Labels that represent the player numbers in place of the controller icons. - std::array player_labels; - - // LED patterns for currently connected controllers/players. - std::array, NUM_PLAYERS> led_patterns_boxes; - - // Labels representing additional information known as "Explain Text" per player. - std::array explain_text_labels; - - // Comboboxes with a list of emulated controllers per player. - std::array emulated_controllers; - - /// Pairs of emulated controller index and Controller Type enum per player. - std::array>, NUM_PLAYERS> - index_controller_type_pairs; - - // Labels representing the number of connected controllers - // above the "Connected Controllers" checkboxes. - std::array connected_controller_labels; - - // Checkboxes representing the "Connected Controllers". - std::array connected_controller_checkboxes; -}; - -class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet { - Q_OBJECT - -public: - explicit QtControllerSelector(GMainWindow& parent); - ~QtControllerSelector() override; - - void Close() const override; - void ReconfigureControllers( - ReconfigureCallback callback_, - const Core::Frontend::ControllerParameters& parameters) const override; - -signals: - void MainWindowReconfigureControllers( - const Core::Frontend::ControllerParameters& parameters) const; - void MainWindowRequestExit() const; - -private: - void MainWindowReconfigureFinished(bool is_success); - - mutable ReconfigureCallback callback; -}; diff --git a/src/yuzu/applets/qt_controller.ui b/src/yuzu/applets/qt_controller.ui deleted file mode 100644 index 6f7cb3c13..000000000 --- a/src/yuzu/applets/qt_controller.ui +++ /dev/null @@ -1,2699 +0,0 @@ - - - QtControllerSelectorDialog - - - - 0 - 0 - 839 - 630 - - - - Controller Applet - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 10 - - - 0 - - - 10 - - - 0 - - - 10 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - 75 - true - - - - Supported Controller Types: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - - - - - - - - - 0 - 0 - - - - - 70 - 70 - - - - - 70 - 70 - - - - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - - - - - - - - 70 - 70 - - - - - 70 - 70 - - - - - 0 - - - 0 - - - 16 - - - 14 - - - 16 - - - - - - 75 - true - - - - Players: - - - Qt::AlignCenter - - - false - - - - - - - - 14 - - - - 1 - 8 - - - Qt::AlignCenter - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 5 - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P4 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P2 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P1 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::LeftToRight - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - Handheld - - - - - - - - - Use Current Config - - - - - - - - - - - - 25 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 25 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P3 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 0 - 25 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 25 - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P7 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P8 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P5 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::LeftToRight - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 100 - 100 - - - - - 100 - 100 - - - - - - - true - - - false - - - - 7 - - - 14 - - - 7 - - - 14 - - - 4 - - - - - - - - - 16 - - - - - P6 - - - - - - - - - - false - - - - 0 - 10 - - - - - 4 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - 0 - 10 - - - - - 150 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::AlignCenter - - - - - - - - - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - - - - - Use Current Config - - - - - - - - - - - - 0 - 25 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 25 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 25 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 25 - 20 - - - - - - - - - - - - 0 - 25 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 25 - - - - - - - - - - - - - - - - - 15 - - - 15 - - - 8 - - - 15 - - - 15 - - - - - - 16777215 - 16777215 - - - - Console Mode - - - - 6 - - - 8 - - - 6 - - - 3 - - - 6 - - - - - Docked - - - true - - - - - - - Handheld - - - - - - - - - - Vibration - - - true - - - - 3 - - - 3 - - - 3 - - - 3 - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - min-width: 68px; - - - Configure - - - - - - - - - - Motion - - - true - - - - 3 - - - 3 - - - 3 - - - 3 - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - min-width: 68px; - - - Configure - - - - - - - - - - Profiles - - - - 3 - - - 3 - - - 3 - - - 3 - - - - - - 68 - 16777215 - - - - min-width: 68px; - - - Create - - - - - - - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 3 - - - - - - - - - - - - Controllers - - - - - - - - - - - - - - 1 - - - Qt::AlignCenter - - - - - - - - - - - - - - Qt::LeftToRight - - - false - - - - - - - 2 - - - Qt::AlignCenter - - - - - - - 4 - - - Qt::AlignCenter - - - - - - - 3 - - - Qt::AlignCenter - - - - - - - Connected - - - - - - - - - - - - - - 5 - - - Qt::AlignCenter - - - - - - - - - - - - - - 7 - - - Qt::AlignCenter - - - - - - - - - - - - - - 6 - - - Qt::AlignCenter - - - - - - - 8 - - - Qt::AlignCenter - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 7 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - QLabel { color : red; } - - - Not enough controllers - - - Qt::AlignCenter - - - 0 - - - - - - - true - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - - - - - - - - buttonBox - accepted() - QtControllerSelectorDialog - accept() - - - buttonBox - rejected() - QtControllerSelectorDialog - reject() - - - diff --git a/src/yuzu/applets/qt_error.cpp b/src/yuzu/applets/qt_error.cpp deleted file mode 100644 index ad35f4126..000000000 --- a/src/yuzu/applets/qt_error.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include "yuzu/applets/qt_error.h" -#include "yuzu/main.h" - -QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { - connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent, - &GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection); - connect(this, &QtErrorDisplay::MainWindowRequestExit, &parent, - &GMainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection); - connect(&parent, &GMainWindow::ErrorDisplayFinished, this, - &QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection); -} - -QtErrorDisplay::~QtErrorDisplay() = default; - -void QtErrorDisplay::Close() const { - callback = {}; - emit MainWindowRequestExit(); -} - -void QtErrorDisplay::ShowError(Result error, FinishedCallback finished) const { - callback = std::move(finished); - emit MainWindowDisplayError( - tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) - .arg(error.raw, 8, 16, QChar::fromLatin1('0')), - tr("An error has occurred.\nPlease try again or contact the developer of the software.")); -} - -void QtErrorDisplay::ShowErrorWithTimestamp(Result error, std::chrono::seconds time, - FinishedCallback finished) const { - callback = std::move(finished); - - const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); - emit MainWindowDisplayError( - tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) - .arg(error.raw, 8, 16, QChar::fromLatin1('0')), - tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the " - "software.") - .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy"))) - .arg(date_time.toString(QStringLiteral("h:mm:ss A")))); -} - -void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text, - std::string fullscreen_text, - FinishedCallback finished) const { - callback = std::move(finished); - emit MainWindowDisplayError( - tr("Error Code: %1-%2 (0x%3)") - .arg(static_cast(error.GetModule()) + 2000, 4, 10, QChar::fromLatin1('0')) - .arg(error.GetDescription(), 4, 10, QChar::fromLatin1('0')) - .arg(error.raw, 8, 16, QChar::fromLatin1('0')), - tr("An error has occurred.\n\n%1\n\n%2") - .arg(QString::fromStdString(dialog_text)) - .arg(QString::fromStdString(fullscreen_text))); -} - -void QtErrorDisplay::MainWindowFinishedError() { - if (callback) { - callback(); - } -} diff --git a/src/yuzu/applets/qt_error.h b/src/yuzu/applets/qt_error.h deleted file mode 100644 index 957f170ad..000000000 --- a/src/yuzu/applets/qt_error.h +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "core/frontend/applets/error.h" - -class GMainWindow; - -class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet { - Q_OBJECT - -public: - explicit QtErrorDisplay(GMainWindow& parent); - ~QtErrorDisplay() override; - - void Close() const override; - void ShowError(Result error, FinishedCallback finished) const override; - void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, - FinishedCallback finished) const override; - void ShowCustomErrorText(Result error, std::string dialog_text, std::string fullscreen_text, - FinishedCallback finished) const override; - -signals: - void MainWindowDisplayError(QString error_code, QString error_text) const; - void MainWindowRequestExit() const; - -private: - void MainWindowFinishedError(); - - mutable FinishedCallback callback; -}; diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp deleted file mode 100644 index 66edd6acd..000000000 --- a/src/yuzu/applets/qt_profile_select.cpp +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common/fs/path_util.h" -#include "common/string_util.h" -#include "core/constants.h" -#include "core/core.h" -#include "core/hle/service/acc/profile_manager.h" -#include "yuzu/applets/qt_profile_select.h" -#include "yuzu/main.h" -#include "yuzu/util/controller_navigation.h" - -namespace { -QString FormatUserEntryText(const QString& username, Common::UUID uuid) { - return QtProfileSelectionDialog::tr( - "%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. " - "00112233-4455-6677-8899-AABBCCDDEEFF))") - .arg(username, QString::fromStdString(uuid.FormattedString())); -} - -QString GetImagePath(Common::UUID uuid) { - const auto path = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / - fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString()); - return QString::fromStdString(Common::FS::PathToUTF8String(path)); -} - -QPixmap GetIcon(Common::UUID uuid) { - QPixmap icon{GetImagePath(uuid)}; - - if (!icon) { - icon.fill(Qt::black); - icon.loadFromData(Core::Constants::ACCOUNT_BACKUP_JPEG.data(), - static_cast(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); - } - - return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); -} -} // Anonymous namespace - -QtProfileSelectionDialog::QtProfileSelectionDialog( - Core::System& system, QWidget* parent, - const Core::Frontend::ProfileSelectParameters& parameters) - : QDialog(parent), profile_manager{system.GetProfileManager()} { - outer_layout = new QVBoxLayout; - - instruction_label = new QLabel(); - - scroll_area = new QScrollArea; - - buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); - connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept); - connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject); - - outer_layout->addWidget(instruction_label); - outer_layout->addWidget(scroll_area); - outer_layout->addWidget(buttons); - - layout = new QVBoxLayout; - tree_view = new QTreeView; - item_model = new QStandardItemModel(tree_view); - tree_view->setModel(item_model); - controller_navigation = new ControllerNavigation(system.HIDCore(), this); - - tree_view->setAlternatingRowColors(true); - tree_view->setSelectionMode(QHeaderView::SingleSelection); - tree_view->setSelectionBehavior(QHeaderView::SelectRows); - tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel); - tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel); - tree_view->setSortingEnabled(true); - tree_view->setEditTriggers(QHeaderView::NoEditTriggers); - tree_view->setUniformRowHeights(true); - tree_view->setIconSize({64, 64}); - tree_view->setContextMenuPolicy(Qt::NoContextMenu); - - item_model->insertColumns(0, 1); - item_model->setHeaderData(0, Qt::Horizontal, tr("Users")); - - // We must register all custom types with the Qt Automoc system so that we are able to use it - // with signals/slots. In this case, QList falls under the umbrella of custom types. - qRegisterMetaType>("QList"); - - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(tree_view); - - scroll_area->setLayout(layout); - - connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); - connect(tree_view, &QTreeView::doubleClicked, this, &QtProfileSelectionDialog::accept); - connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, - [this](Qt::Key key) { - if (!this->isActiveWindow()) { - return; - } - QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); - QCoreApplication::postEvent(tree_view, event); - SelectUser(tree_view->currentIndex()); - }); - - const auto& profiles = profile_manager.GetAllUsers(); - for (const auto& user : profiles) { - Service::Account::ProfileBase profile{}; - if (!profile_manager.GetProfileBase(user, profile)) - continue; - - const auto username = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast(profile.username.data()), profile.username.size()); - - list_items.push_back(QList{new QStandardItem{ - GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}}); - } - - for (const auto& item : list_items) - item_model->appendRow(item); - - setLayout(outer_layout); - SetWindowTitle(parameters); - SetDialogPurpose(parameters); - resize(550, 400); -} - -QtProfileSelectionDialog::~QtProfileSelectionDialog() { - controller_navigation->UnloadController(); -}; - -int QtProfileSelectionDialog::exec() { - // Skip profile selection when there's only one. - if (profile_manager.GetUserCount() == 1) { - user_index = 0; - return QDialog::Accepted; - } - return QDialog::exec(); -} - -void QtProfileSelectionDialog::accept() { - QDialog::accept(); -} - -void QtProfileSelectionDialog::reject() { - user_index = 0; - QDialog::reject(); -} - -int QtProfileSelectionDialog::GetIndex() const { - return user_index; -} - -void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { - user_index = index.row(); -} - -void QtProfileSelectionDialog::SetWindowTitle( - const Core::Frontend::ProfileSelectParameters& parameters) { - using Service::AM::Frontend::UiMode; - switch (parameters.mode) { - case UiMode::UserCreator: - case UiMode::UserCreatorForStarter: - setWindowTitle(tr("Profile Creator")); - return; - case UiMode::EnsureNetworkServiceAccountAvailable: - setWindowTitle(tr("Profile Selector")); - return; - case UiMode::UserIconEditor: - setWindowTitle(tr("Profile Icon Editor")); - return; - case UiMode::UserNicknameEditor: - setWindowTitle(tr("Profile Nickname Editor")); - return; - case UiMode::NintendoAccountAuthorizationRequestContext: - case UiMode::IntroduceExternalNetworkServiceAccount: - case UiMode::IntroduceExternalNetworkServiceAccountForRegistration: - case UiMode::NintendoAccountNnidLinker: - case UiMode::LicenseRequirementsForNetworkService: - case UiMode::LicenseRequirementsForNetworkServiceWithUserContextImpl: - case UiMode::UserCreatorForImmediateNaLoginTest: - case UiMode::UserQualificationPromoter: - case UiMode::UserSelector: - default: - setWindowTitle(tr("Profile Selector")); - } -} - -void QtProfileSelectionDialog::SetDialogPurpose( - const Core::Frontend::ProfileSelectParameters& parameters) { - using Service::AM::Frontend::UserSelectionPurpose; - - switch (parameters.purpose) { - case UserSelectionPurpose::GameCardRegistration: - instruction_label->setText(tr("Who will receive the points?")); - return; - case UserSelectionPurpose::EShopLaunch: - instruction_label->setText(tr("Who is using Nintendo eShop?")); - return; - case UserSelectionPurpose::EShopItemShow: - instruction_label->setText(tr("Who is making this purchase?")); - return; - case UserSelectionPurpose::PicturePost: - instruction_label->setText(tr("Who is posting?")); - return; - case UserSelectionPurpose::NintendoAccountLinkage: - instruction_label->setText(tr("Select a user to link to a Nintendo Account.")); - return; - case UserSelectionPurpose::SettingsUpdate: - instruction_label->setText(tr("Change settings for which user?")); - return; - case UserSelectionPurpose::SaveDataDeletion: - instruction_label->setText(tr("Format data for which user?")); - return; - case UserSelectionPurpose::UserMigration: - instruction_label->setText(tr("Which user will be transferred to another console?")); - return; - case UserSelectionPurpose::SaveDataTransfer: - instruction_label->setText(tr("Send save data for which user?")); - return; - case UserSelectionPurpose::General: - default: - instruction_label->setText(tr("Select a user:")); - return; - } -} - -QtProfileSelector::QtProfileSelector(GMainWindow& parent) { - connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, - &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); - connect(this, &QtProfileSelector::MainWindowRequestExit, &parent, - &GMainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection); - connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this, - &QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection); -} - -QtProfileSelector::~QtProfileSelector() = default; - -void QtProfileSelector::Close() const { - callback = {}; - emit MainWindowRequestExit(); -} - -void QtProfileSelector::SelectProfile( - SelectProfileCallback callback_, - const Core::Frontend::ProfileSelectParameters& parameters) const { - callback = std::move(callback_); - emit MainWindowSelectProfile(parameters); -} - -void QtProfileSelector::MainWindowFinishedSelection(std::optional uuid) { - if (callback) { - callback(uuid); - } -} diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h deleted file mode 100644 index 607f1777c..000000000 --- a/src/yuzu/applets/qt_profile_select.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include "core/frontend/applets/profile_select.h" - -class ControllerNavigation; -class GMainWindow; -class QDialogButtonBox; -class QGraphicsScene; -class QLabel; -class QScrollArea; -class QStandardItem; -class QStandardItemModel; -class QTreeView; -class QVBoxLayout; - -namespace Core { -class System; -} - -namespace Service::Account { -class ProfileManager; -} - -class QtProfileSelectionDialog final : public QDialog { - Q_OBJECT - -public: - explicit QtProfileSelectionDialog(Core::System& system, QWidget* parent, - const Core::Frontend::ProfileSelectParameters& parameters); - ~QtProfileSelectionDialog() override; - - int exec() override; - void accept() override; - void reject() override; - - int GetIndex() const; - -private: - void SelectUser(const QModelIndex& index); - - void SetWindowTitle(const Core::Frontend::ProfileSelectParameters& parameters); - void SetDialogPurpose(const Core::Frontend::ProfileSelectParameters& parameters); - - int user_index = 0; - - QVBoxLayout* layout; - QTreeView* tree_view; - QStandardItemModel* item_model; - QGraphicsScene* scene; - - std::vector> list_items; - - QVBoxLayout* outer_layout; - QLabel* instruction_label; - QScrollArea* scroll_area; - QDialogButtonBox* buttons; - - Service::Account::ProfileManager& profile_manager; - ControllerNavigation* controller_navigation = nullptr; -}; - -class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet { - Q_OBJECT - -public: - explicit QtProfileSelector(GMainWindow& parent); - ~QtProfileSelector() override; - - void Close() const override; - void SelectProfile(SelectProfileCallback callback_, - const Core::Frontend::ProfileSelectParameters& parameters) const override; - -signals: - void MainWindowSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters) const; - void MainWindowRequestExit() const; - -private: - void MainWindowFinishedSelection(std::optional uuid); - - mutable SelectProfileCallback callback; -}; diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp deleted file mode 100644 index 2749e6ed3..000000000 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ /dev/null @@ -1,1674 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include - -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/string_util.h" -#include "core/core.h" -#include "hid_core/frontend/emulated_controller.h" -#include "hid_core/frontend/input_interpreter.h" -#include "hid_core/hid_core.h" -#include "hid_core/hid_types.h" -#include "ui_qt_software_keyboard.h" -#include "yuzu/applets/qt_software_keyboard.h" -#include "yuzu/main.h" -#include "yuzu/util/overlay_dialog.h" - -namespace { - -using namespace Service::AM::Frontend; - -constexpr float BASE_HEADER_FONT_SIZE = 23.0f; -constexpr float BASE_SUB_FONT_SIZE = 17.0f; -constexpr float BASE_EDITOR_FONT_SIZE = 26.0f; -constexpr float BASE_CHAR_BUTTON_FONT_SIZE = 28.0f; -constexpr float BASE_LABEL_BUTTON_FONT_SIZE = 18.0f; -constexpr float BASE_ICON_BUTTON_SIZE = 36.0f; -[[maybe_unused]] constexpr float BASE_WIDTH = 1280.0f; -constexpr float BASE_HEIGHT = 720.0f; - -} // Anonymous namespace - -QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( - QWidget* parent, Core::System& system_, bool is_inline_, - Core::Frontend::KeyboardInitializeParameters initialize_parameters_) - : QDialog(parent), ui{std::make_unique()}, system{system_}, - is_inline{is_inline_}, initialize_parameters{std::move(initialize_parameters_)} { - ui->setupUi(this); - - setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint); - setWindowModality(Qt::WindowModal); - setAttribute(Qt::WA_DeleteOnClose); - setAttribute(Qt::WA_TranslucentBackground); - - keyboard_buttons = {{ - {{ - { - ui->button_1, - ui->button_2, - ui->button_3, - ui->button_4, - ui->button_5, - ui->button_6, - ui->button_7, - ui->button_8, - ui->button_9, - ui->button_0, - ui->button_minus, - ui->button_backspace, - }, - { - ui->button_q, - ui->button_w, - ui->button_e, - ui->button_r, - ui->button_t, - ui->button_y, - ui->button_u, - ui->button_i, - ui->button_o, - ui->button_p, - ui->button_slash, - ui->button_return, - }, - { - ui->button_a, - ui->button_s, - ui->button_d, - ui->button_f, - ui->button_g, - ui->button_h, - ui->button_j, - ui->button_k, - ui->button_l, - ui->button_colon, - ui->button_apostrophe, - ui->button_return, - }, - { - ui->button_z, - ui->button_x, - ui->button_c, - ui->button_v, - ui->button_b, - ui->button_n, - ui->button_m, - ui->button_comma, - ui->button_dot, - ui->button_question, - ui->button_exclamation, - ui->button_ok, - }, - { - ui->button_shift, - ui->button_shift, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_space, - ui->button_ok, - }, - }}, - {{ - { - ui->button_hash, - ui->button_left_bracket, - ui->button_right_bracket, - ui->button_dollar, - ui->button_percent, - ui->button_circumflex, - ui->button_ampersand, - ui->button_asterisk, - ui->button_left_parenthesis, - ui->button_right_parenthesis, - ui->button_underscore, - ui->button_backspace_shift, - }, - { - ui->button_q_shift, - ui->button_w_shift, - ui->button_e_shift, - ui->button_r_shift, - ui->button_t_shift, - ui->button_y_shift, - ui->button_u_shift, - ui->button_i_shift, - ui->button_o_shift, - ui->button_p_shift, - ui->button_at, - ui->button_return_shift, - }, - { - ui->button_a_shift, - ui->button_s_shift, - ui->button_d_shift, - ui->button_f_shift, - ui->button_g_shift, - ui->button_h_shift, - ui->button_j_shift, - ui->button_k_shift, - ui->button_l_shift, - ui->button_semicolon, - ui->button_quotation, - ui->button_return_shift, - }, - { - ui->button_z_shift, - ui->button_x_shift, - ui->button_c_shift, - ui->button_v_shift, - ui->button_b_shift, - ui->button_n_shift, - ui->button_m_shift, - ui->button_less_than, - ui->button_greater_than, - ui->button_plus, - ui->button_equal, - ui->button_ok_shift, - }, - { - ui->button_shift_shift, - ui->button_shift_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_space_shift, - ui->button_ok_shift, - }, - }}, - }}; - - numberpad_buttons = {{ - { - ui->button_1_num, - ui->button_2_num, - ui->button_3_num, - ui->button_backspace_num, - }, - { - ui->button_4_num, - ui->button_5_num, - ui->button_6_num, - ui->button_ok_num, - }, - { - ui->button_7_num, - ui->button_8_num, - ui->button_9_num, - ui->button_ok_num, - }, - { - ui->button_left_optional_num, - ui->button_0_num, - ui->button_right_optional_num, - ui->button_ok_num, - }, - }}; - - all_buttons = { - ui->button_1, - ui->button_2, - ui->button_3, - ui->button_4, - ui->button_5, - ui->button_6, - ui->button_7, - ui->button_8, - ui->button_9, - ui->button_0, - ui->button_minus, - ui->button_backspace, - ui->button_q, - ui->button_w, - ui->button_e, - ui->button_r, - ui->button_t, - ui->button_y, - ui->button_u, - ui->button_i, - ui->button_o, - ui->button_p, - ui->button_slash, - ui->button_return, - ui->button_a, - ui->button_s, - ui->button_d, - ui->button_f, - ui->button_g, - ui->button_h, - ui->button_j, - ui->button_k, - ui->button_l, - ui->button_colon, - ui->button_apostrophe, - ui->button_z, - ui->button_x, - ui->button_c, - ui->button_v, - ui->button_b, - ui->button_n, - ui->button_m, - ui->button_comma, - ui->button_dot, - ui->button_question, - ui->button_exclamation, - ui->button_ok, - ui->button_shift, - ui->button_space, - ui->button_hash, - ui->button_left_bracket, - ui->button_right_bracket, - ui->button_dollar, - ui->button_percent, - ui->button_circumflex, - ui->button_ampersand, - ui->button_asterisk, - ui->button_left_parenthesis, - ui->button_right_parenthesis, - ui->button_underscore, - ui->button_backspace_shift, - ui->button_q_shift, - ui->button_w_shift, - ui->button_e_shift, - ui->button_r_shift, - ui->button_t_shift, - ui->button_y_shift, - ui->button_u_shift, - ui->button_i_shift, - ui->button_o_shift, - ui->button_p_shift, - ui->button_at, - ui->button_return_shift, - ui->button_a_shift, - ui->button_s_shift, - ui->button_d_shift, - ui->button_f_shift, - ui->button_g_shift, - ui->button_h_shift, - ui->button_j_shift, - ui->button_k_shift, - ui->button_l_shift, - ui->button_semicolon, - ui->button_quotation, - ui->button_z_shift, - ui->button_x_shift, - ui->button_c_shift, - ui->button_v_shift, - ui->button_b_shift, - ui->button_n_shift, - ui->button_m_shift, - ui->button_less_than, - ui->button_greater_than, - ui->button_plus, - ui->button_equal, - ui->button_ok_shift, - ui->button_shift_shift, - ui->button_space_shift, - ui->button_1_num, - ui->button_2_num, - ui->button_3_num, - ui->button_backspace_num, - ui->button_4_num, - ui->button_5_num, - ui->button_6_num, - ui->button_ok_num, - ui->button_7_num, - ui->button_8_num, - ui->button_9_num, - ui->button_left_optional_num, - ui->button_0_num, - ui->button_right_optional_num, - }; - - SetupMouseHover(); - - if (!initialize_parameters.ok_text.empty()) { - ui->button_ok->setText(QString::fromStdU16String(initialize_parameters.ok_text)); - } - - ui->label_header->setText(QString::fromStdU16String(initialize_parameters.header_text)); - ui->label_sub->setText(QString::fromStdU16String(initialize_parameters.sub_text)); - - ui->button_left_optional_num->setText(QChar{initialize_parameters.left_optional_symbol_key}); - ui->button_right_optional_num->setText(QChar{initialize_parameters.right_optional_symbol_key}); - - current_text = initialize_parameters.initial_text; - cursor_position = initialize_parameters.initial_cursor_position; - - SetTextDrawType(); - - for (auto* button : all_buttons) { - connect(button, &QPushButton::clicked, this, [this, button](bool) { - if (is_inline) { - InlineKeyboardButtonClicked(button); - } else { - NormalKeyboardButtonClicked(button); - } - }); - } - - // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend - if (system.IsPoweredOn()) { - input_interpreter = std::make_unique(system); - } -} - -QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() { - StopInputThread(); -} - -void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) { - if (isVisible()) { - return; - } - - MoveAndResizeWindow(pos, size); - - SetKeyboardType(); - SetPasswordMode(); - SetControllerImage(); - DisableKeyboardButtons(); - SetBackspaceOkEnabled(); - - open(); -} - -void QtSoftwareKeyboardDialog::ShowTextCheckDialog( - Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) { - switch (text_check_result) { - case SwkbdTextCheckResult::Success: - case SwkbdTextCheckResult::Silent: - default: - break; - case SwkbdTextCheckResult::Failure: { - StopInputThread(); - - OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), - QString{}, tr("OK"), Qt::AlignCenter); - dialog.exec(); - - StartInputThread(); - break; - } - case SwkbdTextCheckResult::Confirm: { - StopInputThread(); - - OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), - tr("Cancel"), tr("OK"), Qt::AlignCenter); - if (dialog.exec() != QDialog::Accepted) { - StartInputThread(); - break; - } - - const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() - : ui->line_edit_osk->text(); - auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); - - emit SubmitNormalText(SwkbdResult::Ok, std::move(text_str), true); - break; - } - } -} - -void QtSoftwareKeyboardDialog::ShowInlineKeyboard( - Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, QSize size) { - MoveAndResizeWindow(pos, size); - - ui->topOSK->setStyleSheet(QStringLiteral("background: rgba(0, 0, 0, 0);")); - - ui->headerOSK->hide(); - ui->subOSK->hide(); - ui->inputOSK->hide(); - ui->charactersOSK->hide(); - ui->inputBoxOSK->hide(); - ui->charactersBoxOSK->hide(); - - initialize_parameters.max_text_length = appear_parameters.max_text_length; - initialize_parameters.min_text_length = appear_parameters.min_text_length; - initialize_parameters.type = appear_parameters.type; - initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags; - initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button; - initialize_parameters.enable_return_button = appear_parameters.enable_return_button; - initialize_parameters.disable_cancel_button = appear_parameters.disable_cancel_button; - - SetKeyboardType(); - SetControllerImage(); - DisableKeyboardButtons(); - SetBackspaceOkEnabled(); - - open(); -} - -void QtSoftwareKeyboardDialog::HideInlineKeyboard() { - StopInputThread(); - QDialog::hide(); -} - -void QtSoftwareKeyboardDialog::InlineTextChanged( - Core::Frontend::InlineTextParameters text_parameters) { - current_text = text_parameters.input_text; - cursor_position = text_parameters.cursor_position; - - SetBackspaceOkEnabled(); -} - -void QtSoftwareKeyboardDialog::ExitKeyboard() { - StopInputThread(); - QDialog::done(QDialog::Accepted); -} - -void QtSoftwareKeyboardDialog::open() { - QDialog::open(); - - row = 0; - column = 0; - - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - case BottomOSKIndex::UpperCase: { - const auto* const curr_button = - keyboard_buttons[static_cast(bottom_osk_index)][row][column]; - - // This is a workaround for setFocus() randomly not showing focus in the UI - QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); - break; - } - case BottomOSKIndex::NumberPad: { - const auto* const curr_button = numberpad_buttons[row][column]; - - // This is a workaround for setFocus() randomly not showing focus in the UI - QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); - break; - } - default: - break; - } - - StartInputThread(); -} - -void QtSoftwareKeyboardDialog::reject() { - // Pressing the ESC key in a dialog calls QDialog::reject(). - // We will override this behavior to the "Cancel" action on the software keyboard. - TranslateButtonPress(Core::HID::NpadButton::X); -} - -void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { - if (!is_inline) { - QDialog::keyPressEvent(event); - return; - } - - const auto entered_key = event->key(); - - switch (entered_key) { - case Qt::Key_Escape: - QDialog::keyPressEvent(event); - return; - case Qt::Key_Backspace: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_backspace->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_backspace_shift->click(); - break; - case BottomOSKIndex::NumberPad: - ui->button_backspace_num->click(); - break; - default: - break; - } - return; - case Qt::Key_Return: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_ok->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_ok_shift->click(); - break; - case BottomOSKIndex::NumberPad: - ui->button_ok_num->click(); - break; - default: - break; - } - return; - case Qt::Key_Left: - MoveTextCursorDirection(Direction::Left); - return; - case Qt::Key_Right: - MoveTextCursorDirection(Direction::Right); - return; - default: - break; - } - - const auto entered_text = event->text(); - - if (entered_text.isEmpty()) { - return; - } - - InlineTextInsertString(Common::U16StringFromBuffer(entered_text.utf16(), entered_text.size())); -} - -void QtSoftwareKeyboardDialog::MoveAndResizeWindow(QPoint pos, QSize size) { - QDialog::move(pos); - QDialog::resize(size); - - // High DPI - const float dpi_scale = screen()->logicalDotsPerInch() / 96.0f; - - RescaleKeyboardElements(size.width(), size.height(), dpi_scale); -} - -void QtSoftwareKeyboardDialog::RescaleKeyboardElements(float width, float height, float dpi_scale) { - const auto header_font_size = BASE_HEADER_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; - const auto sub_font_size = BASE_SUB_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; - const auto editor_font_size = BASE_EDITOR_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; - const auto char_button_font_size = - BASE_CHAR_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; - const auto label_button_font_size = - BASE_LABEL_BUTTON_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale; - - QFont header_font(QStringLiteral("MS Shell Dlg 2"), header_font_size, QFont::Normal); - QFont sub_font(QStringLiteral("MS Shell Dlg 2"), sub_font_size, QFont::Normal); - QFont editor_font(QStringLiteral("MS Shell Dlg 2"), editor_font_size, QFont::Normal); - QFont char_button_font(QStringLiteral("MS Shell Dlg 2"), char_button_font_size, QFont::Normal); - QFont label_button_font(QStringLiteral("MS Shell Dlg 2"), label_button_font_size, - QFont::Normal); - - ui->label_header->setFont(header_font); - ui->label_sub->setFont(sub_font); - ui->line_edit_osk->setFont(editor_font); - ui->text_edit_osk->setFont(editor_font); - ui->label_characters->setFont(sub_font); - ui->label_characters_box->setFont(sub_font); - - ui->label_shift->setFont(label_button_font); - ui->label_shift_shift->setFont(label_button_font); - ui->label_cancel->setFont(label_button_font); - ui->label_cancel_shift->setFont(label_button_font); - ui->label_cancel_num->setFont(label_button_font); - ui->label_enter->setFont(label_button_font); - ui->label_enter_shift->setFont(label_button_font); - ui->label_enter_num->setFont(label_button_font); - - for (auto* button : all_buttons) { - if (button == ui->button_return || button == ui->button_return_shift) { - button->setFont(label_button_font); - continue; - } - - if (button == ui->button_space || button == ui->button_space_shift) { - button->setFont(label_button_font); - continue; - } - - if (button == ui->button_shift || button == ui->button_shift_shift) { - button->setFont(label_button_font); - button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) * - (height / BASE_HEIGHT)); - continue; - } - - if (button == ui->button_backspace || button == ui->button_backspace_shift || - button == ui->button_backspace_num) { - button->setFont(label_button_font); - button->setIconSize(QSize(BASE_ICON_BUTTON_SIZE, BASE_ICON_BUTTON_SIZE) * - (height / BASE_HEIGHT)); - continue; - } - - if (button == ui->button_ok || button == ui->button_ok_shift || - button == ui->button_ok_num) { - button->setFont(label_button_font); - continue; - } - - button->setFont(char_button_font); - } -} - -void QtSoftwareKeyboardDialog::SetKeyboardType() { - switch (initialize_parameters.type) { - case SwkbdType::Normal: - case SwkbdType::Qwerty: - case SwkbdType::Unknown3: - case SwkbdType::Latin: - case SwkbdType::SimplifiedChinese: - case SwkbdType::TraditionalChinese: - case SwkbdType::Korean: - default: { - bottom_osk_index = BottomOSKIndex::LowerCase; - ui->bottomOSK->setCurrentIndex(static_cast(bottom_osk_index)); - - ui->verticalLayout_2->setStretch(0, 320); - ui->verticalLayout_2->setStretch(1, 400); - - ui->gridLineOSK->setRowStretch(5, 94); - ui->gridBoxOSK->setRowStretch(2, 81); - break; - } - case SwkbdType::NumberPad: { - bottom_osk_index = BottomOSKIndex::NumberPad; - ui->bottomOSK->setCurrentIndex(static_cast(bottom_osk_index)); - - ui->verticalLayout_2->setStretch(0, 370); - ui->verticalLayout_2->setStretch(1, 350); - - ui->gridLineOSK->setRowStretch(5, 144); - ui->gridBoxOSK->setRowStretch(2, 131); - break; - } - } -} - -void QtSoftwareKeyboardDialog::SetPasswordMode() { - switch (initialize_parameters.password_mode) { - case SwkbdPasswordMode::Disabled: - default: - ui->line_edit_osk->setEchoMode(QLineEdit::Normal); - break; - case SwkbdPasswordMode::Enabled: - ui->line_edit_osk->setEchoMode(QLineEdit::Password); - break; - } -} - -void QtSoftwareKeyboardDialog::SetTextDrawType() { - switch (initialize_parameters.text_draw_type) { - case SwkbdTextDrawType::Line: - case SwkbdTextDrawType::DownloadCode: { - ui->topOSK->setCurrentIndex(0); - - if (initialize_parameters.max_text_length <= 10) { - ui->gridLineOSK->setColumnStretch(0, 390); - ui->gridLineOSK->setColumnStretch(1, 500); - ui->gridLineOSK->setColumnStretch(2, 390); - } else { - ui->gridLineOSK->setColumnStretch(0, 130); - ui->gridLineOSK->setColumnStretch(1, 1020); - ui->gridLineOSK->setColumnStretch(2, 130); - } - - if (is_inline) { - return; - } - - connect(ui->line_edit_osk, &QLineEdit::textChanged, [this](const QString& changed_string) { - const auto is_valid = ValidateInputText(changed_string); - - const auto text_length = static_cast(changed_string.length()); - - ui->label_characters->setText(QStringLiteral("%1/%2") - .arg(text_length) - .arg(initialize_parameters.max_text_length)); - - ui->button_ok->setEnabled(is_valid); - ui->button_ok_shift->setEnabled(is_valid); - ui->button_ok_num->setEnabled(is_valid); - - ui->line_edit_osk->setFocus(); - }); - - connect(ui->line_edit_osk, &QLineEdit::cursorPositionChanged, - [this](int old_cursor_position, int new_cursor_position) { - ui->button_backspace->setEnabled( - initialize_parameters.enable_backspace_button && new_cursor_position > 0); - ui->button_backspace_shift->setEnabled( - initialize_parameters.enable_backspace_button && new_cursor_position > 0); - ui->button_backspace_num->setEnabled( - initialize_parameters.enable_backspace_button && new_cursor_position > 0); - - ui->line_edit_osk->setFocus(); - }); - - connect( - ui->line_edit_osk, &QLineEdit::returnPressed, this, - [this] { TranslateButtonPress(Core::HID::NpadButton::Plus); }, Qt::QueuedConnection); - - ui->line_edit_osk->setPlaceholderText( - QString::fromStdU16String(initialize_parameters.guide_text)); - ui->line_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text)); - ui->line_edit_osk->setMaxLength(initialize_parameters.max_text_length); - ui->line_edit_osk->setCursorPosition(initialize_parameters.initial_cursor_position); - - ui->label_characters->setText(QStringLiteral("%1/%2") - .arg(initialize_parameters.initial_text.size()) - .arg(initialize_parameters.max_text_length)); - break; - } - case SwkbdTextDrawType::Box: - default: { - ui->topOSK->setCurrentIndex(1); - - if (is_inline) { - return; - } - - connect(ui->text_edit_osk, &QTextEdit::textChanged, [this] { - if (static_cast(ui->text_edit_osk->toPlainText().length()) > - initialize_parameters.max_text_length) { - auto text_cursor = ui->text_edit_osk->textCursor(); - ui->text_edit_osk->setTextCursor(text_cursor); - text_cursor.deletePreviousChar(); - } - - const auto is_valid = ValidateInputText(ui->text_edit_osk->toPlainText()); - - const auto text_length = static_cast(ui->text_edit_osk->toPlainText().length()); - - ui->label_characters_box->setText(QStringLiteral("%1/%2") - .arg(text_length) - .arg(initialize_parameters.max_text_length)); - - ui->button_ok->setEnabled(is_valid); - ui->button_ok_shift->setEnabled(is_valid); - ui->button_ok_num->setEnabled(is_valid); - - ui->text_edit_osk->setFocus(); - }); - - connect(ui->text_edit_osk, &QTextEdit::cursorPositionChanged, [this] { - const auto new_cursor_position = ui->text_edit_osk->textCursor().position(); - - ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && - new_cursor_position > 0); - ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && - new_cursor_position > 0); - ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && - new_cursor_position > 0); - - ui->text_edit_osk->setFocus(); - }); - - ui->text_edit_osk->setPlaceholderText( - QString::fromStdU16String(initialize_parameters.guide_text)); - ui->text_edit_osk->setText(QString::fromStdU16String(initialize_parameters.initial_text)); - ui->text_edit_osk->moveCursor(initialize_parameters.initial_cursor_position == 0 - ? QTextCursor::Start - : QTextCursor::End); - - ui->label_characters_box->setText(QStringLiteral("%1/%2") - .arg(initialize_parameters.initial_text.size()) - .arg(initialize_parameters.max_text_length)); - break; - } - } -} - -void QtSoftwareKeyboardDialog::SetControllerImage() { - const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - const auto controller_type = - handheld->IsConnected() ? handheld->GetNpadStyleIndex() : player_1->GetNpadStyleIndex(); - - const QString theme = [] { - if (QIcon::themeName().contains(QStringLiteral("dark")) || - QIcon::themeName().contains(QStringLiteral("midnight"))) { - return QStringLiteral("_dark"); - } else { - return QString{}; - } - }(); - - switch (controller_type) { - case Core::HID::NpadStyleIndex::Fullkey: - case Core::HID::NpadStyleIndex::GameCube: - ui->icon_controller->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); - ui->icon_controller_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); - ui->icon_controller_num->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - ui->icon_controller->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); - ui->icon_controller_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); - ui->icon_controller_num->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - ui->icon_controller->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") - .arg(theme)); - ui->icon_controller_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") - .arg(theme)); - ui->icon_controller_num->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") - .arg(theme)); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - ui->icon_controller->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") - .arg(theme)); - ui->icon_controller_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") - .arg(theme)); - ui->icon_controller_num->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") - .arg(theme)); - break; - case Core::HID::NpadStyleIndex::Handheld: - ui->icon_controller->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); - ui->icon_controller_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); - ui->icon_controller_num->setStyleSheet( - QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); - break; - default: - break; - } -} - -void QtSoftwareKeyboardDialog::DisableKeyboardButtons() { - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - case BottomOSKIndex::UpperCase: - default: { - for (const auto& keys : keyboard_buttons) { - for (const auto& rows : keys) { - for (auto* button : rows) { - if (!button) { - continue; - } - - button->setEnabled(true); - } - } - } - - const auto& key_disable_flags = initialize_parameters.key_disable_flags; - - ui->button_space->setDisabled(key_disable_flags.space); - ui->button_space_shift->setDisabled(key_disable_flags.space); - - ui->button_at->setDisabled(key_disable_flags.at || key_disable_flags.username); - - ui->button_percent->setDisabled(key_disable_flags.percent || key_disable_flags.username); - - ui->button_slash->setDisabled(key_disable_flags.slash); - - ui->button_1->setDisabled(key_disable_flags.numbers); - ui->button_2->setDisabled(key_disable_flags.numbers); - ui->button_3->setDisabled(key_disable_flags.numbers); - ui->button_4->setDisabled(key_disable_flags.numbers); - ui->button_5->setDisabled(key_disable_flags.numbers); - ui->button_6->setDisabled(key_disable_flags.numbers); - ui->button_7->setDisabled(key_disable_flags.numbers); - ui->button_8->setDisabled(key_disable_flags.numbers); - ui->button_9->setDisabled(key_disable_flags.numbers); - ui->button_0->setDisabled(key_disable_flags.numbers); - - ui->button_return->setEnabled(initialize_parameters.enable_return_button); - ui->button_return_shift->setEnabled(initialize_parameters.enable_return_button); - break; - } - case BottomOSKIndex::NumberPad: { - for (const auto& rows : numberpad_buttons) { - for (auto* button : rows) { - if (!button) { - continue; - } - - button->setEnabled(true); - } - } - - const auto enable_left_optional = initialize_parameters.left_optional_symbol_key != '\0'; - const auto enable_right_optional = initialize_parameters.right_optional_symbol_key != '\0'; - - ui->button_left_optional_num->setEnabled(enable_left_optional); - ui->button_left_optional_num->setVisible(enable_left_optional); - - ui->button_right_optional_num->setEnabled(enable_right_optional); - ui->button_right_optional_num->setVisible(enable_right_optional); - break; - } - } -} - -void QtSoftwareKeyboardDialog::SetBackspaceOkEnabled() { - if (is_inline) { - ui->button_ok->setEnabled(current_text.size() >= initialize_parameters.min_text_length); - ui->button_ok_shift->setEnabled(current_text.size() >= - initialize_parameters.min_text_length); - ui->button_ok_num->setEnabled(current_text.size() >= initialize_parameters.min_text_length); - - ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && - cursor_position > 0); - ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && - cursor_position > 0); - ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && - cursor_position > 0); - } else { - const auto text_length = [this] { - if (ui->topOSK->currentIndex() == 1) { - return static_cast(ui->text_edit_osk->toPlainText().length()); - } else { - return static_cast(ui->line_edit_osk->text().length()); - } - }(); - - const auto normal_cursor_position = [this] { - if (ui->topOSK->currentIndex() == 1) { - return ui->text_edit_osk->textCursor().position(); - } else { - return ui->line_edit_osk->cursorPosition(); - } - }(); - - ui->button_ok->setEnabled(text_length >= initialize_parameters.min_text_length); - ui->button_ok_shift->setEnabled(text_length >= initialize_parameters.min_text_length); - ui->button_ok_num->setEnabled(text_length >= initialize_parameters.min_text_length); - - ui->button_backspace->setEnabled(initialize_parameters.enable_backspace_button && - normal_cursor_position > 0); - ui->button_backspace_shift->setEnabled(initialize_parameters.enable_backspace_button && - normal_cursor_position > 0); - ui->button_backspace_num->setEnabled(initialize_parameters.enable_backspace_button && - normal_cursor_position > 0); - } -} - -bool QtSoftwareKeyboardDialog::ValidateInputText(const QString& input_text) { - const auto& key_disable_flags = initialize_parameters.key_disable_flags; - - const auto input_text_length = static_cast(input_text.length()); - - if (input_text_length < initialize_parameters.min_text_length || - input_text_length > initialize_parameters.max_text_length) { - return false; - } - - if (key_disable_flags.space && input_text.contains(QLatin1Char{' '})) { - return false; - } - - if ((key_disable_flags.at || key_disable_flags.username) && - input_text.contains(QLatin1Char{'@'})) { - return false; - } - - if ((key_disable_flags.percent || key_disable_flags.username) && - input_text.contains(QLatin1Char{'%'})) { - return false; - } - - if (key_disable_flags.slash && input_text.contains(QLatin1Char{'/'})) { - return false; - } - - if ((key_disable_flags.backslash || key_disable_flags.username) && - input_text.contains(QLatin1Char('\\'))) { - return false; - } - - if (key_disable_flags.numbers && - std::any_of(input_text.begin(), input_text.end(), [](QChar c) { return c.isDigit(); })) { - return false; - } - - if (bottom_osk_index == BottomOSKIndex::NumberPad && - std::any_of(input_text.begin(), input_text.end(), [this](QChar c) { - return !c.isDigit() && c != QChar{initialize_parameters.left_optional_symbol_key} && - c != QChar{initialize_parameters.right_optional_symbol_key}; - })) { - return false; - } - - return true; -} - -void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() { - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - bottom_osk_index = BottomOSKIndex::UpperCase; - ui->bottomOSK->setCurrentIndex(static_cast(bottom_osk_index)); - - ui->button_shift_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);" - "\nimage-position: left;")); - - ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); - ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); - break; - case BottomOSKIndex::UpperCase: - if (caps_lock_enabled) { - caps_lock_enabled = false; - - ui->button_shift_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);" - "\nimage-position: left;")); - - ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); - ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); - - ui->label_shift_shift->setText(QStringLiteral("Caps Lock")); - - bottom_osk_index = BottomOSKIndex::LowerCase; - ui->bottomOSK->setCurrentIndex(static_cast(bottom_osk_index)); - } else { - caps_lock_enabled = true; - - ui->button_shift_shift->setStyleSheet( - QStringLiteral("image: url(:/overlay/osk_button_shift_lock_on.png);" - "\nimage-position: left;")); - - ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); - ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); - - ui->label_shift_shift->setText(QStringLiteral("Caps Lock Off")); - } - break; - case BottomOSKIndex::NumberPad: - default: - break; - } -} - -void QtSoftwareKeyboardDialog::NormalKeyboardButtonClicked(QPushButton* button) { - if (button == ui->button_ampersand) { - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->insertPlainText(QStringLiteral("&")); - } else { - ui->line_edit_osk->insert(QStringLiteral("&")); - } - return; - } - - if (button == ui->button_return || button == ui->button_return_shift) { - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->insertPlainText(QStringLiteral("\n")); - } else { - ui->line_edit_osk->insert(QStringLiteral("\n")); - } - return; - } - - if (button == ui->button_space || button == ui->button_space_shift) { - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->insertPlainText(QStringLiteral(" ")); - } else { - ui->line_edit_osk->insert(QStringLiteral(" ")); - } - return; - } - - if (button == ui->button_shift || button == ui->button_shift_shift) { - ChangeBottomOSKIndex(); - return; - } - - if (button == ui->button_backspace || button == ui->button_backspace_shift || - button == ui->button_backspace_num) { - if (ui->topOSK->currentIndex() == 1) { - auto text_cursor = ui->text_edit_osk->textCursor(); - ui->text_edit_osk->setTextCursor(text_cursor); - text_cursor.deletePreviousChar(); - } else { - ui->line_edit_osk->backspace(); - } - return; - } - - if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { - const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() - : ui->line_edit_osk->text(); - auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); - - emit SubmitNormalText(SwkbdResult::Ok, std::move(text_str)); - return; - } - - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->insertPlainText(button->text()); - } else { - ui->line_edit_osk->insert(button->text()); - } - - // Revert the keyboard to lowercase if the shift key is active. - if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { - // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase - // if bottom_osk_index is UpperCase and caps_lock_enabled is true. - caps_lock_enabled = true; - ChangeBottomOSKIndex(); - } -} - -void QtSoftwareKeyboardDialog::InlineKeyboardButtonClicked(QPushButton* button) { - if (!button->isEnabled()) { - return; - } - - if (button == ui->button_ampersand) { - InlineTextInsertString(u"&"); - return; - } - - if (button == ui->button_return || button == ui->button_return_shift) { - InlineTextInsertString(u"\n"); - return; - } - - if (button == ui->button_space || button == ui->button_space_shift) { - InlineTextInsertString(u" "); - return; - } - - if (button == ui->button_shift || button == ui->button_shift_shift) { - ChangeBottomOSKIndex(); - return; - } - - if (button == ui->button_backspace || button == ui->button_backspace_shift || - button == ui->button_backspace_num) { - if (cursor_position <= 0 || current_text.empty()) { - cursor_position = 0; - return; - } - - --cursor_position; - - current_text.erase(cursor_position, 1); - - SetBackspaceOkEnabled(); - - emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position); - return; - } - - if (button == ui->button_ok || button == ui->button_ok_shift || button == ui->button_ok_num) { - emit SubmitInlineText(SwkbdReplyType::DecidedEnter, current_text, cursor_position); - return; - } - - const auto button_text = button->text(); - InlineTextInsertString(Common::U16StringFromBuffer(button_text.utf16(), button_text.size())); - - // Revert the keyboard to lowercase if the shift key is active. - if (bottom_osk_index == BottomOSKIndex::UpperCase && !caps_lock_enabled) { - // This is set to true since ChangeBottomOSKIndex will change bottom_osk_index to LowerCase - // if bottom_osk_index is UpperCase and caps_lock_enabled is true. - caps_lock_enabled = true; - ChangeBottomOSKIndex(); - } -} - -void QtSoftwareKeyboardDialog::InlineTextInsertString(std::u16string_view string) { - if ((current_text.size() + string.size()) > initialize_parameters.max_text_length) { - return; - } - - current_text.insert(cursor_position, string); - - cursor_position += static_cast(string.size()); - - SetBackspaceOkEnabled(); - - emit SubmitInlineText(SwkbdReplyType::ChangedString, current_text, cursor_position); -} - -void QtSoftwareKeyboardDialog::SetupMouseHover() { - // setFocus() has a bug where continuously changing focus will cause the focus UI to - // mysteriously disappear. A workaround we have found is using the mouse to hover over - // the buttons to act in place of the button focus. As a result, we will have to set - // a blank cursor when hovering over all the buttons and set a no focus policy so the - // buttons do not stay in focus in addition to the mouse hover. - for (auto* button : all_buttons) { - button->setCursor(QCursor(Qt::BlankCursor)); - button->setFocusPolicy(Qt::NoFocus); - } -} - -template -void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { - if (input_interpreter->IsButtonPressedOnce(button)) { - TranslateButtonPress(button); - } - }; - - (f(T), ...); -} - -template -void QtSoftwareKeyboardDialog::HandleButtonHold() { - const auto f = [this](Core::HID::NpadButton button) { - if (input_interpreter->IsButtonHeld(button)) { - TranslateButtonPress(button); - } - }; - - (f(T), ...); -} - -void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button) { - switch (button) { - case Core::HID::NpadButton::A: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - case BottomOSKIndex::UpperCase: - keyboard_buttons[static_cast(bottom_osk_index)][row][column]->click(); - break; - case BottomOSKIndex::NumberPad: - numberpad_buttons[row][column]->click(); - break; - default: - break; - } - break; - case Core::HID::NpadButton::B: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_backspace->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_backspace_shift->click(); - break; - case BottomOSKIndex::NumberPad: - ui->button_backspace_num->click(); - break; - default: - break; - } - break; - case Core::HID::NpadButton::X: - if (is_inline) { - emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); - } else { - const auto text = ui->topOSK->currentIndex() == 1 ? ui->text_edit_osk->toPlainText() - : ui->line_edit_osk->text(); - auto text_str = Common::U16StringFromBuffer(text.utf16(), text.size()); - - emit SubmitNormalText(SwkbdResult::Cancel, std::move(text_str)); - } - break; - case Core::HID::NpadButton::Y: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_space->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_space_shift->click(); - break; - case BottomOSKIndex::NumberPad: - default: - break; - } - break; - case Core::HID::NpadButton::StickL: - case Core::HID::NpadButton::StickR: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_shift->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_shift_shift->click(); - break; - case BottomOSKIndex::NumberPad: - default: - break; - } - break; - case Core::HID::NpadButton::L: - MoveTextCursorDirection(Direction::Left); - break; - case Core::HID::NpadButton::R: - MoveTextCursorDirection(Direction::Right); - break; - case Core::HID::NpadButton::Plus: - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - ui->button_ok->click(); - break; - case BottomOSKIndex::UpperCase: - ui->button_ok_shift->click(); - break; - case BottomOSKIndex::NumberPad: - ui->button_ok_num->click(); - break; - default: - break; - } - break; - case Core::HID::NpadButton::Left: - case Core::HID::NpadButton::StickLLeft: - case Core::HID::NpadButton::StickRLeft: - MoveButtonDirection(Direction::Left); - break; - case Core::HID::NpadButton::Up: - case Core::HID::NpadButton::StickLUp: - case Core::HID::NpadButton::StickRUp: - MoveButtonDirection(Direction::Up); - break; - case Core::HID::NpadButton::Right: - case Core::HID::NpadButton::StickLRight: - case Core::HID::NpadButton::StickRRight: - MoveButtonDirection(Direction::Right); - break; - case Core::HID::NpadButton::Down: - case Core::HID::NpadButton::StickLDown: - case Core::HID::NpadButton::StickRDown: - MoveButtonDirection(Direction::Down); - break; - default: - break; - } -} - -void QtSoftwareKeyboardDialog::MoveButtonDirection(Direction direction) { - // Changes the row or column index depending on the direction. - auto move_direction = [this, direction](std::size_t max_rows, std::size_t max_columns) { - switch (direction) { - case Direction::Left: - column = (column + max_columns - 1) % max_columns; - break; - case Direction::Up: - row = (row + max_rows - 1) % max_rows; - break; - case Direction::Right: - column = (column + 1) % max_columns; - break; - case Direction::Down: - row = (row + 1) % max_rows; - break; - default: - break; - } - }; - - // Store the initial row and column. - const auto initial_row = row; - const auto initial_column = column; - - switch (bottom_osk_index) { - case BottomOSKIndex::LowerCase: - case BottomOSKIndex::UpperCase: { - const auto index = static_cast(bottom_osk_index); - - const auto* const prev_button = keyboard_buttons[index][row][column]; - move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL); - auto* curr_button = keyboard_buttons[index][row][column]; - - while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) { - // If we returned back to where we started from, break the loop. - if (row == initial_row && column == initial_column) { - break; - } - - move_direction(NUM_ROWS_NORMAL, NUM_COLUMNS_NORMAL); - curr_button = keyboard_buttons[index][row][column]; - } - - // This is a workaround for setFocus() randomly not showing focus in the UI - QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); - break; - } - case BottomOSKIndex::NumberPad: { - const auto* const prev_button = numberpad_buttons[row][column]; - move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD); - auto* curr_button = numberpad_buttons[row][column]; - - while (!curr_button || !curr_button->isEnabled() || curr_button == prev_button) { - // If we returned back to where we started from, break the loop. - if (row == initial_row && column == initial_column) { - break; - } - - move_direction(NUM_ROWS_NUMPAD, NUM_COLUMNS_NUMPAD); - curr_button = numberpad_buttons[row][column]; - } - - // This is a workaround for setFocus() randomly not showing focus in the UI - QCursor::setPos(curr_button->mapToGlobal(curr_button->rect().center())); - break; - } - default: - break; - } -} - -void QtSoftwareKeyboardDialog::MoveTextCursorDirection(Direction direction) { - switch (direction) { - case Direction::Left: - if (is_inline) { - if (cursor_position <= 0) { - cursor_position = 0; - } else { - --cursor_position; - emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position); - } - } else { - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->moveCursor(QTextCursor::Left); - } else { - ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() - 1); - } - } - break; - case Direction::Right: - if (is_inline) { - if (cursor_position >= static_cast(current_text.size())) { - cursor_position = static_cast(current_text.size()); - } else { - ++cursor_position; - emit SubmitInlineText(SwkbdReplyType::MovedCursor, current_text, cursor_position); - } - } else { - if (ui->topOSK->currentIndex() == 1) { - ui->text_edit_osk->moveCursor(QTextCursor::Right); - } else { - ui->line_edit_osk->setCursorPosition(ui->line_edit_osk->cursorPosition() + 1); - } - } - break; - default: - break; - } -} - -void QtSoftwareKeyboardDialog::StartInputThread() { - if (input_thread_running) { - return; - } - - input_thread_running = true; - - input_thread = std::thread(&QtSoftwareKeyboardDialog::InputThread, this); -} - -void QtSoftwareKeyboardDialog::StopInputThread() { - input_thread_running = false; - - if (input_thread.joinable()) { - input_thread.join(); - } - - if (input_interpreter) { - input_interpreter->ResetButtonStates(); - } -} - -void QtSoftwareKeyboardDialog::InputThread() { - while (input_thread_running) { - input_interpreter->PollInput(); - - HandleButtonPressedOnce< - Core::HID::NpadButton::A, Core::HID::NpadButton::B, Core::HID::NpadButton::X, - Core::HID::NpadButton::Y, Core::HID::NpadButton::StickL, Core::HID::NpadButton::StickR, - Core::HID::NpadButton::L, Core::HID::NpadButton::R, Core::HID::NpadButton::Plus, - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft, - Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight, - Core::HID::NpadButton::StickRDown>(); - - HandleButtonHold(); - - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } -} - -QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { - connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window, - &GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window, - &GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window, - &GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window, - &GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window, - &GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window, - &GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection); - connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window, - &GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection); - connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this, - &QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection); - connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this, - &QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection); -} - -QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; - -void QtSoftwareKeyboard::InitializeKeyboard( - bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, - SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) { - if (is_inline) { - submit_inline_callback = std::move(submit_inline_callback_); - } else { - submit_normal_callback = std::move(submit_normal_callback_); - } - - LOG_INFO(Service_AM, - "\nKeyboardInitializeParameters:" - "\nok_text={}" - "\nheader_text={}" - "\nsub_text={}" - "\nguide_text={}" - "\ninitial_text={}" - "\nmax_text_length={}" - "\nmin_text_length={}" - "\ninitial_cursor_position={}" - "\ntype={}" - "\npassword_mode={}" - "\ntext_draw_type={}" - "\nkey_disable_flags={}" - "\nuse_blur_background={}" - "\nenable_backspace_button={}" - "\nenable_return_button={}" - "\ndisable_cancel_button={}", - Common::UTF16ToUTF8(initialize_parameters.ok_text), - Common::UTF16ToUTF8(initialize_parameters.header_text), - Common::UTF16ToUTF8(initialize_parameters.sub_text), - Common::UTF16ToUTF8(initialize_parameters.guide_text), - Common::UTF16ToUTF8(initialize_parameters.initial_text), - initialize_parameters.max_text_length, initialize_parameters.min_text_length, - initialize_parameters.initial_cursor_position, initialize_parameters.type, - initialize_parameters.password_mode, initialize_parameters.text_draw_type, - initialize_parameters.key_disable_flags.raw, initialize_parameters.use_blur_background, - initialize_parameters.enable_backspace_button, - initialize_parameters.enable_return_button, - initialize_parameters.disable_cancel_button); - - emit MainWindowInitializeKeyboard(is_inline, std::move(initialize_parameters)); -} - -void QtSoftwareKeyboard::ShowNormalKeyboard() const { - emit MainWindowShowNormalKeyboard(); -} - -void QtSoftwareKeyboard::ShowTextCheckDialog( - Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) const { - emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message)); -} - -void QtSoftwareKeyboard::ShowInlineKeyboard( - Core::Frontend::InlineAppearParameters appear_parameters) const { - LOG_INFO(Service_AM, - "\nInlineAppearParameters:" - "\nmax_text_length={}" - "\nmin_text_length={}" - "\nkey_top_scale_x={}" - "\nkey_top_scale_y={}" - "\nkey_top_translate_x={}" - "\nkey_top_translate_y={}" - "\ntype={}" - "\nkey_disable_flags={}" - "\nkey_top_as_floating={}" - "\nenable_backspace_button={}" - "\nenable_return_button={}" - "\ndisable_cancel_button={}", - appear_parameters.max_text_length, appear_parameters.min_text_length, - appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y, - appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y, - appear_parameters.type, appear_parameters.key_disable_flags.raw, - appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button, - appear_parameters.enable_return_button, appear_parameters.disable_cancel_button); - - emit MainWindowShowInlineKeyboard(std::move(appear_parameters)); -} - -void QtSoftwareKeyboard::HideInlineKeyboard() const { - emit MainWindowHideInlineKeyboard(); -} - -void QtSoftwareKeyboard::InlineTextChanged( - Core::Frontend::InlineTextParameters text_parameters) const { - LOG_INFO(Service_AM, - "\nInlineTextParameters:" - "\ninput_text={}" - "\ncursor_position={}", - Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); - - emit MainWindowInlineTextChanged(std::move(text_parameters)); -} - -void QtSoftwareKeyboard::ExitKeyboard() const { - emit MainWindowExitKeyboard(); -} - -void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Frontend::SwkbdResult result, - std::u16string submitted_text, bool confirmed) const { - submit_normal_callback(result, submitted_text, confirmed); -} - -void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, - std::u16string submitted_text, - s32 cursor_position) const { - submit_inline_callback(reply_type, submitted_text, cursor_position); -} diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h deleted file mode 100644 index 7e2fdf09e..000000000 --- a/src/yuzu/applets/qt_software_keyboard.h +++ /dev/null @@ -1,287 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include "core/frontend/applets/software_keyboard.h" - -class InputInterpreter; - -namespace Core { -class System; -} - -namespace Core::HID { -enum class NpadButton : u64; -} - -namespace Ui { -class QtSoftwareKeyboardDialog; -} - -class GMainWindow; - -class QtSoftwareKeyboardDialog final : public QDialog { - Q_OBJECT - -public: - QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_, - Core::Frontend::KeyboardInitializeParameters initialize_parameters_); - ~QtSoftwareKeyboardDialog() override; - - void ShowNormalKeyboard(QPoint pos, QSize size); - - void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message); - - void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, - QSize size); - - void HideInlineKeyboard(); - - void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); - - void ExitKeyboard(); - -signals: - void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, - bool confirmed = false) const; - - void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, - std::u16string submitted_text, s32 cursor_position) const; - -public slots: - void open() override; - void reject() override; - -protected: - /// We override the keyPressEvent for inputting text into the inline software keyboard. - void keyPressEvent(QKeyEvent* event) override; - -private: - enum class Direction { - Left, - Up, - Right, - Down, - }; - - enum class BottomOSKIndex { - LowerCase, - UpperCase, - NumberPad, - }; - - /** - * Moves and resizes the window to a specified position and size. - * - * @param pos Top-left window position - * @param size Window size - */ - void MoveAndResizeWindow(QPoint pos, QSize size); - - /** - * Rescales all keyboard elements to account for High DPI displays. - * - * @param width Window width - * @param height Window height - * @param dpi_scale Display scaling factor - */ - void RescaleKeyboardElements(float width, float height, float dpi_scale); - - /// Sets the keyboard type based on initialize_parameters. - void SetKeyboardType(); - - /// Sets the password mode based on initialize_parameters. - void SetPasswordMode(); - - /// Sets the text draw type based on initialize_parameters. - void SetTextDrawType(); - - /// Sets the controller image at the bottom left of the software keyboard. - void SetControllerImage(); - - /// Disables buttons based on initialize_parameters. - void DisableKeyboardButtons(); - - /// Changes whether the backspace or/and ok buttons should be enabled or disabled. - void SetBackspaceOkEnabled(); - - /** - * Validates the input text sent in based on the parameters in initialize_parameters. - * - * @param input_text Input text - * - * @returns True if the input text is valid, false otherwise. - */ - bool ValidateInputText(const QString& input_text); - - /// Switches between LowerCase and UpperCase (Shift and Caps Lock) - void ChangeBottomOSKIndex(); - - /// Processes a keyboard button click from the UI as normal keyboard input. - void NormalKeyboardButtonClicked(QPushButton* button); - - /// Processes a keyboard button click from the UI as inline keyboard input. - void InlineKeyboardButtonClicked(QPushButton* button); - - /** - * Inserts a string of arbitrary length into the current_text at the current cursor position. - * This is only used for the inline software keyboard. - */ - void InlineTextInsertString(std::u16string_view string); - - /// Setup the mouse hover workaround for "focusing" buttons. This should only be called once. - void SetupMouseHover(); - - /** - * Handles button presses and converts them into keyboard input. - * - * @tparam HIDButton The list of buttons that can be converted into keyboard input. - */ - template - void HandleButtonPressedOnce(); - - /** - * Handles button holds and converts them into keyboard input. - * - * @tparam HIDButton The list of buttons that can be converted into keyboard input. - */ - template - void HandleButtonHold(); - - /** - * Translates a button press to focus or click a keyboard button. - * - * @param button The button press to process. - */ - void TranslateButtonPress(Core::HID::NpadButton button); - - /** - * Moves the focus of a button in a certain direction. - * - * @param direction The direction to move. - */ - void MoveButtonDirection(Direction direction); - - /** - * Moves the text cursor in a certain direction. - * - * @param direction The direction to move. - */ - void MoveTextCursorDirection(Direction direction); - - void StartInputThread(); - void StopInputThread(); - - /// The thread where input is being polled and processed. - void InputThread(); - - std::unique_ptr ui; - - Core::System& system; - - // True if it is the inline software keyboard. - bool is_inline; - - // Common software keyboard initialize parameters. - Core::Frontend::KeyboardInitializeParameters initialize_parameters; - - // Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden. - std::u16string current_text; - s32 cursor_position{0}; - - static constexpr std::size_t NUM_ROWS_NORMAL = 5; - static constexpr std::size_t NUM_COLUMNS_NORMAL = 12; - static constexpr std::size_t NUM_ROWS_NUMPAD = 4; - static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4; - - // Stores the normal keyboard layout. - std::array, NUM_ROWS_NORMAL>, 2> - keyboard_buttons; - // Stores the numberpad keyboard layout. - std::array, NUM_ROWS_NUMPAD> numberpad_buttons; - - // Contains a set of all buttons used in keyboard_buttons and numberpad_buttons. - std::array all_buttons; - - std::size_t row{0}; - std::size_t column{0}; - - BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase}; - std::atomic caps_lock_enabled{false}; - - std::unique_ptr input_interpreter; - - std::thread input_thread; - - std::atomic input_thread_running{}; -}; - -class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { - Q_OBJECT - -public: - explicit QtSoftwareKeyboard(GMainWindow& parent); - ~QtSoftwareKeyboard() override; - - void Close() const override { - ExitKeyboard(); - } - - void InitializeKeyboard(bool is_inline, - Core::Frontend::KeyboardInitializeParameters initialize_parameters, - SubmitNormalCallback submit_normal_callback_, - SubmitInlineCallback submit_inline_callback_) override; - - void ShowNormalKeyboard() const override; - - void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) const override; - - void ShowInlineKeyboard( - Core::Frontend::InlineAppearParameters appear_parameters) const override; - - void HideInlineKeyboard() const override; - - void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override; - - void ExitKeyboard() const override; - -signals: - void MainWindowInitializeKeyboard( - bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const; - - void MainWindowShowNormalKeyboard() const; - - void MainWindowShowTextCheckDialog( - Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message) const; - - void MainWindowShowInlineKeyboard( - Core::Frontend::InlineAppearParameters appear_parameters) const; - - void MainWindowHideInlineKeyboard() const; - - void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const; - - void MainWindowExitKeyboard() const; - -private: - void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, - bool confirmed) const; - - void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, - std::u16string submitted_text, s32 cursor_position) const; - - mutable SubmitNormalCallback submit_normal_callback; - mutable SubmitInlineCallback submit_inline_callback; -}; diff --git a/src/yuzu/applets/qt_software_keyboard.ui b/src/yuzu/applets/qt_software_keyboard.ui deleted file mode 100644 index 9661cb260..000000000 --- a/src/yuzu/applets/qt_software_keyboard.ui +++ /dev/null @@ -1,3541 +0,0 @@ - - - QtSoftwareKeyboardDialog - - - - 0 - 0 - 1280 - 720 - - - - Software Keyboard - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - 0 - 100 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 17 - - - - 0/32 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - 26 - 50 - false - - - - Qt::StrongFocus - - - - - - 32 - - - Enter Text - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 127 - 20 - - - - - - - - - 23 - - - - - - - - - - - Qt::Horizontal - - - - 127 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 127 - 20 - - - - - - - - - 17 - - - - - - - - - - - Qt::Horizontal - - - - 127 - 20 - - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - - 17 - - - - 0/500 - - - - - - - - - - - 0 - - - 14 - - - 9 - - - 14 - - - 9 - - - - - - 26 - - - - Qt::StrongFocus - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - - - - - - - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - - 0 - - - 2 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Shift - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Cancel - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Enter - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - ' - - - - - - - - 1 - 1 - - - - - 28 - - - - / - - - - - - - - 1 - 1 - - - - - 28 - - - - ! - - - - - - - - 1 - 1 - - - - - 28 - - - - 7 - - - - - - - - 1 - 1 - - - - - 28 - - - - 8 - - - - - - - - 1 - 1 - - - - - 28 - - - - 0 - - - - - - - - 1 - 1 - - - - - 28 - - - - 9 - - - - - - - - 1 - 1 - - - - - 28 - - - - w - - - - - - - - 1 - 1 - - - - - 28 - - - - r - - - - - - - - 1 - 1 - - - - - 28 - - - - e - - - - - - - - 1 - 1 - - - - - 28 - - - - q - - - - - - - - 1 - 1 - - - - - 28 - - - - u - - - - - - - - 1 - 1 - - - - - 28 - - - - y - - - - - - - - 1 - 1 - - - - - 28 - - - - t - - - - - - - - 1 - 1 - - - - - 28 - - - - o - - - - - - - - 1 - 1 - - - - - 28 - - - - p - - - - - - - - 1 - 1 - - - - - 28 - - - - i - - - - - - - - 1 - 1 - - - - - 28 - - - - a - - - - - - - - 1 - 1 - - - - - 28 - - - - s - - - - - - - - 1 - 1 - - - - - 28 - - - - d - - - - - - - - 1 - 1 - - - - - 28 - - - - f - - - - - - - - 1 - 1 - - - - - 28 - - - - h - - - - - - - - 1 - 1 - - - - - 28 - - - - j - - - - - - - - 1 - 1 - - - - - 28 - - - - g - - - - - - - - 1 - 1 - - - - - 28 - - - - k - - - - - - - - 1 - 1 - - - - - 28 - - - - l - - - - - - - - 1 - 1 - - - - - 28 - - - - : - - - - - - - - 1 - 1 - - - - - 18 - - - - Return - - - - - - - - 1 - 1 - - - - - 18 - - - - OK - - - - - - - - 1 - 1 - - - - - 28 - - - - z - - - - - - - - 1 - 1 - - - - - 28 - - - - c - - - - - - - - 1 - 1 - - - - - 28 - - - - x - - - - - - - - 1 - 1 - - - - - 28 - - - - v - - - - - - - - 1 - 1 - - - - - 28 - - - - m - - - - - - - - 1 - 1 - - - - - 28 - - - - , - - - - - - - - 1 - 1 - - - - - 28 - - - - n - - - - - - - - 1 - 1 - - - - - 28 - - - - b - - - - - - - - 1 - 1 - - - - - 18 - - - - - - - true - - - false - - - - - - - - 1 - 1 - - - - - 28 - - - - ? - - - - - - - - 1 - 1 - - - - - 28 - - - - . - - - - - - - - 1 - 1 - - - - - 28 - - - - 1 - - - - - - - - 1 - 1 - - - - - 28 - - - - 3 - - - - - - - - 1 - 1 - - - - - 28 - - - - 4 - - - - - - - - 1 - 1 - - - - - 28 - - - - 2 - - - - - - - - 1 - 1 - - - - - 28 - - - - 6 - - - - - - - - 1 - 1 - - - - - 28 - - - - 5 - - - - - - - - 1 - 1 - - - - - 18 - - - - Space - - - - - - - - 1 - 1 - - - - - 18 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - - 0 - - - 2 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Caps Lock - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Cancel - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Enter - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - _ - - - - - - - - 1 - 1 - - - - - 28 - - - - " - - - - - - - - 1 - 1 - - - - - 28 - - - - @ - - - - - - - - 1 - 1 - - - - - 28 - - - - = - - - - - - - - 1 - 1 - - - - - 28 - - - - && - - - - - - - - 1 - 1 - - - - - 28 - - - - * - - - - - - - - 1 - 1 - - - - - 28 - - - - ) - - - - - - - - 1 - 1 - - - - - 28 - - - - ( - - - - - - - - 1 - 1 - - - - - 28 - - - - W - - - - - - - - 1 - 1 - - - - - 28 - - - - R - - - - - - - - 1 - 1 - - - - - 28 - - - - E - - - - - - - - 1 - 1 - - - - - 28 - - - - Q - - - - - - - - 1 - 1 - - - - - 28 - - - - U - - - - - - - - 1 - 1 - - - - - 28 - - - - Y - - - - - - - - 1 - 1 - - - - - 28 - - - - T - - - - - - - - 1 - 1 - - - - - 28 - - - - O - - - - - - - - 1 - 1 - - - - - 28 - - - - P - - - - - - - - 1 - 1 - - - - - 28 - - - - I - - - - - - - - 1 - 1 - - - - - 28 - - - - A - - - - - - - - 1 - 1 - - - - - 28 - - - - S - - - - - - - - 1 - 1 - - - - - 28 - - - - D - - - - - - - - 1 - 1 - - - - - 28 - - - - F - - - - - - - - 1 - 1 - - - - - 28 - - - - H - - - - - - - - 1 - 1 - - - - - 28 - - - - J - - - - - - - - 1 - 1 - - - - - 28 - - - - G - - - - - - - - 1 - 1 - - - - - 28 - - - - K - - - - - - - - 1 - 1 - - - - - 28 - - - - L - - - - - - - - 1 - 1 - - - - - 28 - - - - ; - - - - - - - - 1 - 1 - - - - - 18 - - - - Return - - - - - - - - 1 - 1 - - - - - 18 - - - - OK - - - - - - - - 1 - 1 - - - - - 28 - - - - Z - - - - - - - - 1 - 1 - - - - - 28 - - - - C - - - - - - - - 1 - 1 - - - - - 28 - - - - X - - - - - - - - 1 - 1 - - - - - 28 - - - - V - - - - - - - - 1 - 1 - - - - - 28 - - - - M - - - - - - - - 1 - 1 - - - - - 28 - - - - < - - - - - - - - 1 - 1 - - - - - 28 - - - - N - - - - - - - - 1 - 1 - - - - - 28 - - - - B - - - - - - - - 1 - 1 - - - - - 18 - - - - - - - true - - - false - - - - - - - - 1 - 1 - - - - - 28 - - - - + - - - - - - - - 1 - 1 - - - - - 28 - - - - > - - - - - - - - 1 - 1 - - - - - 28 - - - - # - - - - - - - - 1 - 1 - - - - - 28 - - - - ] - - - - - - - - 1 - 1 - - - - - 28 - - - - $ - - - - - - - - 1 - 1 - - - - - 28 - - - - [ - - - - - - - - 1 - 1 - - - - - 28 - - - - ^ - - - - - - - - 1 - 1 - - - - - 28 - - - - % - - - - - - - - 1 - 1 - - - - - 18 - - - - Space - - - - - - - - 1 - 1 - - - - - 18 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - 0 - - - - - - 1 - 1 - - - - - 18 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Cancel - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - 18 - - - - Enter - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - 6 - - - - - - - - 1 - 1 - - - - - 28 - - - - 4 - - - - - - - - 1 - 1 - - - - - 28 - - - - 9 - - - - - - - - 1 - 1 - - - - - 28 - - - - 5 - - - - - - - - 1 - 1 - - - - - 18 - - - - OK - - - - - - - - 1 - 1 - - - - - 28 - - - - 7 - - - - - - - - 1 - 1 - - - - - 28 - - - - 8 - - - - - - - - 1 - 1 - - - - - 28 - - - - 2 - - - - - - - - 1 - 1 - - - - - 28 - - - - 1 - - - - - - - - 1 - 1 - - - - - 28 - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - 0 - - - - - - - - 1 - 1 - - - - - 28 - - - - - - - - - - - - 1 - 1 - - - - - 28 - - - - 3 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - - - - - - - - button_1 - button_2 - button_3 - button_4 - button_5 - button_6 - button_7 - button_8 - button_9 - button_0 - button_minus - button_backspace - button_q - button_w - button_e - button_r - button_t - button_y - button_u - button_i - button_o - button_p - button_slash - button_return - button_a - button_s - button_d - button_f - button_g - button_h - button_j - button_k - button_l - button_colon - button_apostrophe - button_z - button_x - button_c - button_v - button_b - button_n - button_m - button_comma - button_dot - button_question - button_exclamation - button_ok - button_shift - button_space - button_hash - button_left_bracket - button_right_bracket - button_dollar - button_percent - button_circumflex - button_ampersand - button_asterisk - button_left_parenthesis - button_right_parenthesis - button_underscore - button_backspace_shift - button_q_shift - button_w_shift - button_e_shift - button_r_shift - button_t_shift - button_y_shift - button_u_shift - button_i_shift - button_o_shift - button_p_shift - button_at - button_return_shift - button_a_shift - button_s_shift - button_d_shift - button_f_shift - button_g_shift - button_h_shift - button_j_shift - button_k_shift - button_l_shift - button_semicolon - button_quotation - button_z_shift - button_x_shift - button_c_shift - button_v_shift - button_b_shift - button_n_shift - button_m_shift - button_less_than - button_greater_than - button_plus - button_equal - button_ok_shift - button_shift_shift - button_space_shift - button_1_num - button_2_num - button_3_num - button_backspace_num - button_4_num - button_5_num - button_6_num - button_ok_num - button_7_num - button_8_num - button_9_num - button_left_optional_num - button_0_num - button_right_optional_num - - - - - - diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp deleted file mode 100644 index cce9b2efb..000000000 --- a/src/yuzu/applets/qt_web_browser.cpp +++ /dev/null @@ -1,449 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#ifdef YUZU_USE_QT_WEB_ENGINE -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "hid_core/frontend/input_interpreter.h" -#include "yuzu/applets/qt_web_browser_scripts.h" -#endif - -#include "common/fs/path_util.h" -#include "core/core.h" -#include "input_common/drivers/keyboard.h" -#include "yuzu/applets/qt_web_browser.h" -#include "yuzu/main.h" -#include "yuzu/util/url_request_interceptor.h" - -#ifdef YUZU_USE_QT_WEB_ENGINE - -namespace { - -constexpr int HIDButtonToKey(Core::HID::NpadButton button) { - switch (button) { - case Core::HID::NpadButton::Left: - case Core::HID::NpadButton::StickLLeft: - return Qt::Key_Left; - case Core::HID::NpadButton::Up: - case Core::HID::NpadButton::StickLUp: - return Qt::Key_Up; - case Core::HID::NpadButton::Right: - case Core::HID::NpadButton::StickLRight: - return Qt::Key_Right; - case Core::HID::NpadButton::Down: - case Core::HID::NpadButton::StickLDown: - return Qt::Key_Down; - default: - return 0; - } -} - -} // Anonymous namespace - -QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system, - InputCommon::InputSubsystem* input_subsystem_) - : QWebEngineView(parent), input_subsystem{input_subsystem_}, - url_interceptor(std::make_unique()), - input_interpreter(std::make_unique(system)), - default_profile{QWebEngineProfile::defaultProfile()}, global_settings{ - default_profile->settings()} { - default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine"))); - - QWebEngineScript gamepad; - QWebEngineScript window_nx; - - gamepad.setName(QStringLiteral("gamepad_script.js")); - window_nx.setName(QStringLiteral("window_nx_script.js")); - - gamepad.setSourceCode(QString::fromStdString(GAMEPAD_SCRIPT)); - window_nx.setSourceCode(QString::fromStdString(WINDOW_NX_SCRIPT)); - - gamepad.setInjectionPoint(QWebEngineScript::DocumentCreation); - window_nx.setInjectionPoint(QWebEngineScript::DocumentCreation); - - gamepad.setWorldId(QWebEngineScript::MainWorld); - window_nx.setWorldId(QWebEngineScript::MainWorld); - - gamepad.setRunsOnSubFrames(true); - window_nx.setRunsOnSubFrames(true); - - default_profile->scripts()->insert(gamepad); - default_profile->scripts()->insert(window_nx); - - default_profile->setUrlRequestInterceptor(url_interceptor.get()); - - global_settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); - global_settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); - global_settings->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); - global_settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); - global_settings->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, true); - global_settings->setAttribute(QWebEngineSettings::ShowScrollBars, false); - - global_settings->setFontFamily(QWebEngineSettings::StandardFont, QStringLiteral("Roboto")); - - connect( - page(), &QWebEnginePage::windowCloseRequested, page(), - [this] { - if (page()->url() == url_interceptor->GetRequestedURL()) { - SetFinished(true); - SetExitReason(Service::AM::Frontend::WebExitReason::WindowClosed); - } - }, - Qt::QueuedConnection); -} - -QtNXWebEngineView::~QtNXWebEngineView() { - SetFinished(true); - StopInputThread(); -} - -void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url, - const std::string& additional_args) { - is_local = true; - - LoadExtractedFonts(); - FocusFirstLinkElement(); - SetUserAgent(UserAgent::WebApplet); - SetFinished(false); - SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed); - SetLastURL("http://localhost/"); - StartInputThread(); - - load(QUrl(QUrl::fromLocalFile(QString::fromStdString(main_url)).toString() + - QString::fromStdString(additional_args))); -} - -void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url, - const std::string& additional_args) { - is_local = false; - - FocusFirstLinkElement(); - SetUserAgent(UserAgent::WebApplet); - SetFinished(false); - SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed); - SetLastURL("http://localhost/"); - StartInputThread(); - - load(QUrl(QString::fromStdString(main_url) + QString::fromStdString(additional_args))); -} - -void QtNXWebEngineView::SetUserAgent(UserAgent user_agent) { - const QString user_agent_str = [user_agent] { - switch (user_agent) { - case UserAgent::WebApplet: - default: - return QStringLiteral("WebApplet"); - case UserAgent::ShopN: - return QStringLiteral("ShopN"); - case UserAgent::LoginApplet: - return QStringLiteral("LoginApplet"); - case UserAgent::ShareApplet: - return QStringLiteral("ShareApplet"); - case UserAgent::LobbyApplet: - return QStringLiteral("LobbyApplet"); - case UserAgent::WifiWebAuthApplet: - return QStringLiteral("WifiWebAuthApplet"); - } - }(); - - QWebEngineProfile::defaultProfile()->setHttpUserAgent( - QStringLiteral("Mozilla/5.0 (Nintendo Switch; %1) AppleWebKit/606.4 " - "(KHTML, like Gecko) NF/6.0.1.15.4 NintendoBrowser/5.1.0.20389") - .arg(user_agent_str)); -} - -bool QtNXWebEngineView::IsFinished() const { - return finished; -} - -void QtNXWebEngineView::SetFinished(bool finished_) { - finished = finished_; -} - -Service::AM::Frontend::WebExitReason QtNXWebEngineView::GetExitReason() const { - return exit_reason; -} - -void QtNXWebEngineView::SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_) { - exit_reason = exit_reason_; -} - -const std::string& QtNXWebEngineView::GetLastURL() const { - return last_url; -} - -void QtNXWebEngineView::SetLastURL(std::string last_url_) { - last_url = std::move(last_url_); -} - -QString QtNXWebEngineView::GetCurrentURL() const { - return url_interceptor->GetRequestedURL().toString(); -} - -void QtNXWebEngineView::hide() { - SetFinished(true); - StopInputThread(); - - QWidget::hide(); -} - -void QtNXWebEngineView::keyPressEvent(QKeyEvent* event) { - if (is_local) { - input_subsystem->GetKeyboard()->PressKey(event->key()); - } -} - -void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) { - if (is_local) { - input_subsystem->GetKeyboard()->ReleaseKey(event->key()); - } -} - -template -void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { - if (input_interpreter->IsButtonPressedOnce(button)) { - const auto button_index = std::countr_zero(static_cast(button)); - - page()->runJavaScript( - QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(button_index), - [this, button](const QVariant& variant) { - if (variant.toBool()) { - switch (button) { - case Core::HID::NpadButton::A: - SendMultipleKeyPressEvents(); - break; - case Core::HID::NpadButton::B: - SendKeyPressEvent(Qt::Key_B); - break; - case Core::HID::NpadButton::X: - SendKeyPressEvent(Qt::Key_X); - break; - case Core::HID::NpadButton::Y: - SendKeyPressEvent(Qt::Key_Y); - break; - default: - break; - } - } - }); - - page()->runJavaScript( - QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }") - .arg(button_index)); - } - }; - - (f(T), ...); -} - -template -void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { - if (input_interpreter->IsButtonPressedOnce(button)) { - SendKeyPressEvent(HIDButtonToKey(button)); - } - }; - - (f(T), ...); -} - -template -void QtNXWebEngineView::HandleWindowKeyButtonHold() { - const auto f = [this](Core::HID::NpadButton button) { - if (input_interpreter->IsButtonHeld(button)) { - SendKeyPressEvent(HIDButtonToKey(button)); - } - }; - - (f(T), ...); -} - -void QtNXWebEngineView::SendKeyPressEvent(int key) { - if (key == 0) { - return; - } - - QCoreApplication::postEvent(focusProxy(), - new QKeyEvent(QKeyEvent::KeyPress, key, Qt::NoModifier)); - QCoreApplication::postEvent(focusProxy(), - new QKeyEvent(QKeyEvent::KeyRelease, key, Qt::NoModifier)); -} - -void QtNXWebEngineView::StartInputThread() { - if (input_thread_running) { - return; - } - - input_thread_running = true; - input_thread = std::thread(&QtNXWebEngineView::InputThread, this); -} - -void QtNXWebEngineView::StopInputThread() { - if (is_local) { - QWidget::releaseKeyboard(); - } - - input_thread_running = false; - if (input_thread.joinable()) { - input_thread.join(); - } -} - -void QtNXWebEngineView::InputThread() { - // Wait for 1 second before allowing any inputs to be processed. - std::this_thread::sleep_for(std::chrono::seconds(1)); - - if (is_local) { - QWidget::grabKeyboard(); - } - - while (input_thread_running) { - input_interpreter->PollInput(); - - HandleWindowFooterButtonPressedOnce(); - - HandleWindowKeyButtonPressedOnce< - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown>(); - - HandleWindowKeyButtonHold< - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown>(); - - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } -} - -void QtNXWebEngineView::LoadExtractedFonts() { - QWebEngineScript nx_font_css; - QWebEngineScript load_nx_font; - - auto fonts_dir_str = Common::FS::PathToUTF8String( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts/"); - - std::replace(fonts_dir_str.begin(), fonts_dir_str.end(), '\\', '/'); - - const auto fonts_dir = QString::fromStdString(fonts_dir_str); - - nx_font_css.setName(QStringLiteral("nx_font_css.js")); - load_nx_font.setName(QStringLiteral("load_nx_font.js")); - - nx_font_css.setSourceCode( - QString::fromStdString(NX_FONT_CSS) - .arg(fonts_dir + QStringLiteral("FontStandard.ttf")) - .arg(fonts_dir + QStringLiteral("FontChineseSimplified.ttf")) - .arg(fonts_dir + QStringLiteral("FontExtendedChineseSimplified.ttf")) - .arg(fonts_dir + QStringLiteral("FontChineseTraditional.ttf")) - .arg(fonts_dir + QStringLiteral("FontKorean.ttf")) - .arg(fonts_dir + QStringLiteral("FontNintendoExtended.ttf")) - .arg(fonts_dir + QStringLiteral("FontNintendoExtended2.ttf"))); - load_nx_font.setSourceCode(QString::fromStdString(LOAD_NX_FONT)); - - nx_font_css.setInjectionPoint(QWebEngineScript::DocumentReady); - load_nx_font.setInjectionPoint(QWebEngineScript::Deferred); - - nx_font_css.setWorldId(QWebEngineScript::MainWorld); - load_nx_font.setWorldId(QWebEngineScript::MainWorld); - - nx_font_css.setRunsOnSubFrames(true); - load_nx_font.setRunsOnSubFrames(true); - - default_profile->scripts()->insert(nx_font_css); - default_profile->scripts()->insert(load_nx_font); - - connect( - url_interceptor.get(), &UrlRequestInterceptor::FrameChanged, url_interceptor.get(), - [this] { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - page()->runJavaScript(QString::fromStdString(LOAD_NX_FONT)); - }, - Qt::QueuedConnection); -} - -void QtNXWebEngineView::FocusFirstLinkElement() { - QWebEngineScript focus_link_element; - - focus_link_element.setName(QStringLiteral("focus_link_element.js")); - focus_link_element.setSourceCode(QString::fromStdString(FOCUS_LINK_ELEMENT_SCRIPT)); - focus_link_element.setWorldId(QWebEngineScript::MainWorld); - focus_link_element.setInjectionPoint(QWebEngineScript::Deferred); - focus_link_element.setRunsOnSubFrames(true); - default_profile->scripts()->insert(focus_link_element); -} - -#endif - -QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { - connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window, - &GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection); - connect(this, &QtWebBrowser::MainWindowRequestExit, &main_window, - &GMainWindow::WebBrowserRequestExit, Qt::QueuedConnection); - connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this, - &QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection); - connect(&main_window, &GMainWindow::WebBrowserClosed, this, - &QtWebBrowser::MainWindowWebBrowserClosed, Qt::QueuedConnection); -} - -QtWebBrowser::~QtWebBrowser() = default; - -void QtWebBrowser::Close() const { - callback = {}; - emit MainWindowRequestExit(); -} - -void QtWebBrowser::OpenLocalWebPage(const std::string& local_url, - ExtractROMFSCallback extract_romfs_callback_, - OpenWebPageCallback callback_) const { - extract_romfs_callback = std::move(extract_romfs_callback_); - callback = std::move(callback_); - - const auto index = local_url.find('?'); - - if (index == std::string::npos) { - emit MainWindowOpenWebPage(local_url, "", true); - } else { - emit MainWindowOpenWebPage(local_url.substr(0, index), local_url.substr(index), true); - } -} - -void QtWebBrowser::OpenExternalWebPage(const std::string& external_url, - OpenWebPageCallback callback_) const { - callback = std::move(callback_); - - const auto index = external_url.find('?'); - - if (index == std::string::npos) { - emit MainWindowOpenWebPage(external_url, "", false); - } else { - emit MainWindowOpenWebPage(external_url.substr(0, index), external_url.substr(index), - false); - } -} - -void QtWebBrowser::MainWindowExtractOfflineRomFS() { - extract_romfs_callback(); -} - -void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, - std::string last_url) { - if (callback) { - callback(exit_reason, last_url); - } -} diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h deleted file mode 100644 index e8a0b6931..000000000 --- a/src/yuzu/applets/qt_web_browser.h +++ /dev/null @@ -1,220 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include - -#ifdef YUZU_USE_QT_WEB_ENGINE -#include -#endif - -#include "core/frontend/applets/web_browser.h" - -class GMainWindow; -class InputInterpreter; -class UrlRequestInterceptor; - -namespace Core { -class System; -} - -namespace Core::HID { -enum class NpadButton : u64; -} - -namespace InputCommon { -class InputSubsystem; -} - -#ifdef YUZU_USE_QT_WEB_ENGINE - -enum class UserAgent { - WebApplet, - ShopN, - LoginApplet, - ShareApplet, - LobbyApplet, - WifiWebAuthApplet, -}; - -class QWebEngineProfile; -class QWebEngineSettings; - -class QtNXWebEngineView : public QWebEngineView { - Q_OBJECT - -public: - explicit QtNXWebEngineView(QWidget* parent, Core::System& system, - InputCommon::InputSubsystem* input_subsystem_); - ~QtNXWebEngineView() override; - - /** - * Loads a HTML document that exists locally. Cannot be used to load external websites. - * - * @param main_url The url to the file. - * @param additional_args Additional arguments appended to the main url. - */ - void LoadLocalWebPage(const std::string& main_url, const std::string& additional_args); - - /** - * Loads an external website. Cannot be used to load local urls. - * - * @param main_url The url to the website. - * @param additional_args Additional arguments appended to the main url. - */ - void LoadExternalWebPage(const std::string& main_url, const std::string& additional_args); - - /** - * Sets the background color of the web page. - * - * @param color The color to set. - */ - void SetBackgroundColor(QColor color); - - /** - * Sets the user agent of the web browser. - * - * @param user_agent The user agent enum. - */ - void SetUserAgent(UserAgent user_agent); - - [[nodiscard]] bool IsFinished() const; - void SetFinished(bool finished_); - - [[nodiscard]] Service::AM::Frontend::WebExitReason GetExitReason() const; - void SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_); - - [[nodiscard]] const std::string& GetLastURL() const; - void SetLastURL(std::string last_url_); - - /** - * This gets the current URL that has been requested by the webpage. - * This only applies to the main frame. Sub frames and other resources are ignored. - * - * @return Currently requested URL - */ - [[nodiscard]] QString GetCurrentURL() const; - -public slots: - void hide(); - -protected: - void keyPressEvent(QKeyEvent* event) override; - void keyReleaseEvent(QKeyEvent* event) override; - -private: - /** - * Handles button presses to execute functions assigned in yuzu_key_callbacks. - * yuzu_key_callbacks contains specialized functions for the buttons in the window footer - * that can be overridden by games to achieve desired functionality. - * - * @tparam HIDButton The list of buttons contained in yuzu_key_callbacks - */ - template - void HandleWindowFooterButtonPressedOnce(); - - /** - * Handles button presses and converts them into keyboard input. - * This should only be used to convert D-Pad or Analog Stick input into arrow keys. - * - * @tparam HIDButton The list of buttons that can be converted into keyboard input. - */ - template - void HandleWindowKeyButtonPressedOnce(); - - /** - * Handles button holds and converts them into keyboard input. - * This should only be used to convert D-Pad or Analog Stick input into arrow keys. - * - * @tparam HIDButton The list of buttons that can be converted into keyboard input. - */ - template - void HandleWindowKeyButtonHold(); - - /** - * Sends a key press event to QWebEngineView. - * - * @param key Qt key code. - */ - void SendKeyPressEvent(int key); - - /** - * Sends multiple key press events to QWebEngineView. - * - * @tparam int Qt key code. - */ - template - void SendMultipleKeyPressEvents() { - (SendKeyPressEvent(T), ...); - } - - void StartInputThread(); - void StopInputThread(); - - /// The thread where input is being polled and processed. - void InputThread(); - - /// Loads the extracted fonts using JavaScript. - void LoadExtractedFonts(); - - /// Brings focus to the first available link element. - void FocusFirstLinkElement(); - - InputCommon::InputSubsystem* input_subsystem; - - std::unique_ptr url_interceptor; - - std::unique_ptr input_interpreter; - - std::thread input_thread; - - std::atomic input_thread_running{}; - - std::atomic finished{}; - - Service::AM::Frontend::WebExitReason exit_reason{ - Service::AM::Frontend::WebExitReason::EndButtonPressed}; - - std::string last_url{"http://localhost/"}; - - bool is_local{}; - - QWebEngineProfile* default_profile; - QWebEngineSettings* global_settings; -}; - -#endif - -class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet { - Q_OBJECT - -public: - explicit QtWebBrowser(GMainWindow& parent); - ~QtWebBrowser() override; - - void Close() const override; - void OpenLocalWebPage(const std::string& local_url, - ExtractROMFSCallback extract_romfs_callback_, - OpenWebPageCallback callback_) const override; - - void OpenExternalWebPage(const std::string& external_url, - OpenWebPageCallback callback_) const override; - -signals: - void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args, - bool is_local) const; - void MainWindowRequestExit() const; - -private: - void MainWindowExtractOfflineRomFS(); - - void MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, - std::string last_url); - - mutable ExtractROMFSCallback extract_romfs_callback; - mutable OpenWebPageCallback callback; -}; diff --git a/src/yuzu/applets/qt_web_browser_scripts.h b/src/yuzu/applets/qt_web_browser_scripts.h deleted file mode 100644 index f5530c38f..000000000 --- a/src/yuzu/applets/qt_web_browser_scripts.h +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -constexpr char NX_FONT_CSS[] = R"( -(function() { - css = document.createElement('style'); - css.type = 'text/css'; - css.id = 'nx_font'; - css.innerText = ` -/* FontStandard */ -@font-face { - font-family: 'FontStandard'; - src: url('%1') format('truetype'); -} - -/* FontChineseSimplified */ -@font-face { - font-family: 'FontChineseSimplified'; - src: url('%2') format('truetype'); -} - -/* FontExtendedChineseSimplified */ -@font-face { - font-family: 'FontExtendedChineseSimplified'; - src: url('%3') format('truetype'); -} - -/* FontChineseTraditional */ -@font-face { - font-family: 'FontChineseTraditional'; - src: url('%4') format('truetype'); -} - -/* FontKorean */ -@font-face { - font-family: 'FontKorean'; - src: url('%5') format('truetype'); -} - -/* FontNintendoExtended */ -@font-face { - font-family: 'NintendoExt003'; - src: url('%6') format('truetype'); -} - -/* FontNintendoExtended2 */ -@font-face { - font-family: 'NintendoExt003'; - src: url('%7') format('truetype'); -} -`; - - document.head.appendChild(css); -})(); -)"; - -constexpr char LOAD_NX_FONT[] = R"( -(function() { - var elements = document.querySelectorAll("*"); - - for (var i = 0; i < elements.length; i++) { - var style = window.getComputedStyle(elements[i], null); - if (style.fontFamily.includes("Arial") || style.fontFamily.includes("Calibri") || - style.fontFamily.includes("Century") || style.fontFamily.includes("Times New Roman")) { - elements[i].style.fontFamily = "FontStandard, FontChineseSimplified, FontExtendedChineseSimplified, FontChineseTraditional, FontKorean, NintendoExt003"; - } else { - elements[i].style.fontFamily = style.fontFamily + ", FontStandard, FontChineseSimplified, FontExtendedChineseSimplified, FontChineseTraditional, FontKorean, NintendoExt003"; - } - } -})(); -)"; - -constexpr char FOCUS_LINK_ELEMENT_SCRIPT[] = R"( -if (document.getElementsByTagName("a").length > 0) { - document.getElementsByTagName("a")[0].focus(); -} -)"; - -constexpr char GAMEPAD_SCRIPT[] = R"( -window.addEventListener("gamepadconnected", function(e) { - console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", - e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length); -}); - -window.addEventListener("gamepaddisconnected", function(e) { - console.log("Gamepad disconnected from index %d: %s", e.gamepad.index, e.gamepad.id); -}); -)"; - -constexpr char WINDOW_NX_SCRIPT[] = R"( -var end_applet = false; -var yuzu_key_callbacks = []; - -(function() { - class WindowNX { - constructor() { - yuzu_key_callbacks[1] = function() { window.history.back(); }; - yuzu_key_callbacks[2] = function() { window.nx.endApplet(); }; - } - - addEventListener(type, listener, options) { - console.log("nx.addEventListener called, type=%s", type); - - window.addEventListener(type, listener, options); - } - - endApplet() { - console.log("nx.endApplet called"); - - end_applet = true; - } - - playSystemSe(system_se) { - console.log("nx.playSystemSe is not implemented, system_se=%s", system_se); - } - - sendMessage(message) { - console.log("nx.sendMessage is not implemented, message=%s", message); - } - - setCursorScrollSpeed(scroll_speed) { - console.log("nx.setCursorScrollSpeed is not implemented, scroll_speed=%d", scroll_speed); - } - } - - class WindowNXFooter { - setAssign(key, label, func, option) { - console.log("nx.footer.setAssign called, key=%s", key); - - switch (key) { - case "A": - yuzu_key_callbacks[0] = func; - break; - case "B": - yuzu_key_callbacks[1] = func; - break; - case "X": - yuzu_key_callbacks[2] = func; - break; - case "Y": - yuzu_key_callbacks[3] = func; - break; - case "L": - yuzu_key_callbacks[6] = func; - break; - case "R": - yuzu_key_callbacks[7] = func; - break; - } - } - - setFixed(kind) { - console.log("nx.footer.setFixed is not implemented, kind=%s", kind); - } - - unsetAssign(key) { - console.log("nx.footer.unsetAssign called, key=%s", key); - - switch (key) { - case "A": - yuzu_key_callbacks[0] = function() {}; - break; - case "B": - yuzu_key_callbacks[1] = function() {}; - break; - case "X": - yuzu_key_callbacks[2] = function() {}; - break; - case "Y": - yuzu_key_callbacks[3] = function() {}; - break; - case "L": - yuzu_key_callbacks[6] = function() {}; - break; - case "R": - yuzu_key_callbacks[7] = function() {}; - break; - } - } - } - - class WindowNXPlayReport { - incrementCounter(counter_id) { - console.log("nx.playReport.incrementCounter is not implemented, counter_id=%d", counter_id); - } - - setCounterSetIdentifier(counter_id) { - console.log("nx.playReport.setCounterSetIdentifier is not implemented, counter_id=%d", counter_id); - } - } - - window.nx = new WindowNX(); - window.nx.footer = new WindowNXFooter(); - window.nx.playReport = new WindowNXPlayReport(); -})(); -)"; -- cgit v1.2.3