summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp152
-rw-r--r--src/yuzu/applets/software_keyboard.h80
-rw-r--r--src/yuzu/main.cpp31
-rw-r--r--src/yuzu/main.h11
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();