diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/yuzu/applets/software_keyboard.cpp | 152 | ||||
| -rw-r--r-- | src/yuzu/applets/software_keyboard.h | 80 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 31 | ||||
| -rw-r--r-- | src/yuzu/main.h | 11 |
5 files changed, 276 insertions, 0 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 34f36f06b..cfca8f4a8 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable(yuzu Info.plist about_dialog.cpp about_dialog.h + applets/software_keyboard.cpp + applets/software_keyboard.h bootmanager.cpp bootmanager.h compatibility_list.cpp diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp new file mode 100644 index 000000000..efefb1f99 --- /dev/null +++ b/src/yuzu/applets/software_keyboard.cpp @@ -0,0 +1,152 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <mutex> +#include <QDialogButtonBox> +#include <QFont> +#include <QLabel> +#include <QLineEdit> +#include <QVBoxLayout> +#include "core/hle/lock.h" +#include "yuzu/applets/software_keyboard.h" +#include "yuzu/main.h" + +QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator( + Core::Frontend::SoftwareKeyboardParameters parameters) + : parameters(std::move(parameters)) {} + +QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const { + if (input.size() > parameters.max_length) + return Invalid; + if (parameters.disable_space && input.contains(' ')) + return Invalid; + if (parameters.disable_address && input.contains('@')) + return Invalid; + if (parameters.disable_percent && input.contains('%')) + return Invalid; + if (parameters.disable_slash && (input.contains('/') || input.contains('\\'))) + return Invalid; + if (parameters.disable_number && + std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) { + return Invalid; + } + + if (parameters.disable_download_code && + std::any_of(input.begin(), input.end(), [](QChar c) { return c == 'O' || c == 'I'; })) { + return Invalid; + } + + return Acceptable; +} + +QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( + QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_) + : QDialog(parent), parameters(std::move(parameters_)) { + layout = new QVBoxLayout; + + header_label = new QLabel(QString::fromStdU16String(parameters.header_text)); + header_label->setFont({header_label->font().family(), 11, QFont::Bold}); + if (header_label->text().isEmpty()) + header_label->setText(tr("Enter text:")); + + sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text)); + sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(), + sub_label->font().weight(), true}); + sub_label->setHidden(parameters.sub_text.empty()); + + guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text)); + guide_label->setHidden(parameters.guide_text.empty()); + + length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length)); + length_label->setAlignment(Qt::AlignRight); + length_label->setFont({length_label->font().family(), 8}); + + line_edit = new QLineEdit; + line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters)); + line_edit->setMaxLength(static_cast<int>(parameters.max_length)); + line_edit->setText(QString::fromStdU16String(parameters.initial_text)); + line_edit->setCursorPosition( + parameters.cursor_at_beginning ? 0 : static_cast<int>(parameters.initial_text.size())); + line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal); + + connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { + length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length)); + }); + + buttons = new QDialogButtonBox; + buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); + buttons->addButton(parameters.submit_text.empty() + ? tr("OK") + : QString::fromStdU16String(parameters.submit_text), + QDialogButtonBox::AcceptRole); + + connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::Submit); + connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::Reject); + layout->addWidget(header_label); + layout->addWidget(sub_label); + layout->addWidget(guide_label); + layout->addWidget(length_label); + layout->addWidget(line_edit); + layout->addWidget(buttons); + setLayout(layout); + setWindowTitle(tr("Software Keyboard")); +} + +QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; + +void QtSoftwareKeyboardDialog::Submit() { + ok = true; + text = line_edit->text().toStdU16String(); + accept(); +} + +void QtSoftwareKeyboardDialog::Reject() { + ok = false; + text.clear(); + accept(); +} + +std::u16string QtSoftwareKeyboardDialog::GetText() const { + return text; +} + +bool QtSoftwareKeyboardDialog::GetStatus() const { + return ok; +} + +QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { + connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window, + &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection); + connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window, + &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection); + connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this, + &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection); +} + +QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; + +void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, + Core::Frontend::SoftwareKeyboardParameters parameters) const { + text_output = out; + emit MainWindowGetText(parameters); +} + +void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, + std::function<void()> finished_check) const { + this->finished_check = finished_check; + emit MainWindowTextCheckDialog(error_message); +} + +void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) { + // Acquire the HLE mutex + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + text_output(text); +} + +void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { + // Acquire the HLE mutex + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + finished_check(); +} diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h new file mode 100644 index 000000000..73f56714f --- /dev/null +++ b/src/yuzu/applets/software_keyboard.h @@ -0,0 +1,80 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QDialog> +#include <QValidator> +#include "common/assert.h" +#include "core/frontend/applets/software_keyboard.h" + +class GMainWindow; +class QDialogButtonBox; +class QLabel; +class QLineEdit; +class QVBoxLayout; +class QtSoftwareKeyboard; + +class QtSoftwareKeyboardValidator final : public QValidator { +public: + explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters); + State validate(QString& input, int& pos) const override; + +private: + Core::Frontend::SoftwareKeyboardParameters parameters; +}; + +class QtSoftwareKeyboardDialog final : public QDialog { + Q_OBJECT + +public: + QtSoftwareKeyboardDialog(QWidget* parent, + Core::Frontend::SoftwareKeyboardParameters parameters); + ~QtSoftwareKeyboardDialog() override; + + void Submit(); + void Reject(); + + std::u16string GetText() const; + bool GetStatus() const; + +private: + bool ok = false; + std::u16string text; + + QDialogButtonBox* buttons; + QLabel* header_label; + QLabel* sub_label; + QLabel* guide_label; + QLabel* length_label; + QLineEdit* line_edit; + QVBoxLayout* layout; + + Core::Frontend::SoftwareKeyboardParameters parameters; +}; + +class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { + Q_OBJECT + +public: + explicit QtSoftwareKeyboard(GMainWindow& parent); + ~QtSoftwareKeyboard() override; + + void RequestText(std::function<void(std::optional<std::u16string>)> out, + Core::Frontend::SoftwareKeyboardParameters parameters) const override; + void SendTextCheckDialog(std::u16string error_message, + std::function<void()> finished_check) const override; + +signals: + void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; + void MainWindowTextCheckDialog(std::u16string error_message) const; + +public slots: + void MainWindowFinishedText(std::optional<std::u16string> text); + void MainWindowFinishedCheckDialog(); + +private: + mutable std::function<void(std::optional<std::u16string>)> text_output; + mutable std::function<void()> finished_check; +}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4b969119c..9e13bbf7c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,9 +8,11 @@ #include <thread> // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. +#include "applets/software_keyboard.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" #include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applets/applets.h" // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. @@ -59,6 +61,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/romfs.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/submission_package.h" +#include "core/frontend/applets/software_keyboard.h" #include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_ldr.h" @@ -204,6 +207,27 @@ GMainWindow::~GMainWindow() { delete render_window; } +void GMainWindow::SoftwareKeyboardGetText( + const Core::Frontend::SoftwareKeyboardParameters& parameters) { + QtSoftwareKeyboardDialog dialog(this, parameters); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + dialog.exec(); + + if (!dialog.GetStatus()) { + emit SoftwareKeyboardFinishedText(std::nullopt); + return; + } + + emit SoftwareKeyboardFinishedText(dialog.GetText()); +} + +void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) { + QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message)); + emit SoftwareKeyboardFinishedCheckDialog(); +} + void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING ui.action_Report_Compatibility->setVisible(true); @@ -559,6 +583,8 @@ bool GMainWindow::LoadROM(const QString& filename) { system.SetGPUDebugContext(debug_context); + system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); + const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; const auto drd_callout = @@ -1228,8 +1254,13 @@ void GMainWindow::OnMenuRecentFile() { void GMainWindow::OnStartGame() { emu_thread->SetRunning(true); + + qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>( + "Core::Frontend::SoftwareKeyboardParameters"); qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); qRegisterMetaType<std::string>("std::string"); + qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); + connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); ui.action_Start->setEnabled(false); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 929250e8c..674e73412 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -29,6 +29,10 @@ class ProfilerWidget; class WaitTreeWidget; enum class GameListOpenTarget; +namespace Core::Frontend { +struct SoftwareKeyboardParameters; +} // namespace Core::Frontend + namespace FileSys { class RegisteredCacheUnion; class VfsFilesystem; @@ -95,6 +99,13 @@ signals: // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); + void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); + void SoftwareKeyboardFinishedCheckDialog(); + +public slots: + void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); + void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); + private: void InitializeWidgets(); void InitializeDebugWidgets(); |
