From e696ed1f4d20f28f8b26c637498962938df7d96f Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Sun, 11 Nov 2018 16:39:25 -0500
Subject: [PATCH] am: Deglobalize software keyboard applet

---
 src/common/string_util.cpp                    |  4 +-
 src/common/string_util.h                      |  4 +-
 src/core/core.cpp                             | 17 ++++++
 src/core/core.h                               |  5 ++
 .../frontend/applets/software_keyboard.cpp    | 13 ++--
 src/core/frontend/applets/software_keyboard.h | 54 +++++++++--------
 src/core/hle/kernel/svc.cpp                   |  8 +--
 src/core/hle/service/am/am.cpp                | 14 +++--
 src/core/hle/service/am/am.h                  | 10 ++--
 src/core/hle/service/am/applets/applets.cpp   | 16 +----
 src/core/hle/service/am/applets/applets.h     | 10 +++-
 .../service/am/applets/software_keyboard.cpp  | 12 +++-
 .../service/am/applets/software_keyboard.h    |  9 +++
 src/yuzu/applets/software_keyboard.cpp        | 59 ++++++++++++-------
 src/yuzu/applets/software_keyboard.h          | 33 ++++++-----
 src/yuzu/main.cpp                             |  7 ++-
 src/yuzu/main.h                               |  9 +++
 17 files changed, 182 insertions(+), 102 deletions(-)

diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index a1360dd268..959f278aaf 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -214,13 +214,13 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t
     return std::string(buffer, len);
 }
 
-std::u16string UTF16StringFromFixedZeroTerminatedBuffer(const char16_t* buffer,
+std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
                                                         std::size_t max_len) {
     std::size_t len = 0;
     while (len < max_len && buffer[len] != '\0')
         ++len;
 
-    return std::u16string(buffer, len);
+    return std::u16string(buffer.begin(), buffer.begin() + len);
 }
 
 const char* TrimSourcePath(const char* path, const char* root) {
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 95b7badaf3..583fd05e68 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -68,10 +68,10 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t
 
 /**
  * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
- * NUL-terminated, then the string ends at the greatest multiple of two less then or equal to
+ * null-terminated, then the string ends at the greatest multiple of two less then or equal to
  * max_len_bytes.
  */
-std::u16string UTF16StringFromFixedZeroTerminatedBuffer(const char16_t* buffer,
+std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
                                                         std::size_t max_len);
 
 /**
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 6d5b5a2d01..6c72fdf4a0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -23,12 +23,14 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/service/am/applets/software_keyboard.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/loader/loader.h"
 #include "core/perf_stats.h"
 #include "core/settings.h"
 #include "core/telemetry_session.h"
+#include "frontend/applets/software_keyboard.h"
 #include "video_core/debug_utils/debug_utils.h"
 #include "video_core/gpu.h"
 #include "video_core/renderer_base.h"
@@ -136,6 +138,10 @@ struct System::Impl {
         if (virtual_filesystem == nullptr)
             virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
 
+        /// Create default implementations of applets if one is not provided.
+        if (software_keyboard == nullptr)
+            software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
+
         auto main_process = Kernel::Process::Create(kernel, "main");
         kernel.MakeCurrentProcess(main_process.get());
 
@@ -289,6 +295,9 @@ struct System::Impl {
     std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
     std::size_t active_core{}; ///< Active core, only used in single thread mode
 
+    /// Frontend applets
+    std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
+
     /// Service manager
     std::shared_ptr<Service::SM::ServiceManager> service_manager;
 
@@ -488,6 +497,14 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
     return impl->virtual_filesystem;
 }
 
+void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
+    impl->software_keyboard = std::move(applet);
+}
+
+const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
+    return *impl->software_keyboard;
+}
+
 System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
     return impl->Init(emu_window);
 }
diff --git a/src/core/core.h b/src/core/core.h
index cfacceb81c..be71bd4378 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -13,6 +13,7 @@
 
 namespace Core::Frontend {
 class EmuWindow;
+class SoftwareKeyboardApplet;
 } // namespace Core::Frontend
 
 namespace FileSys {
@@ -236,6 +237,10 @@ public:
 
     std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
 
+    void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
+
+    const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
+
 private:
     System();
 
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index c1bacefef3..41d81c2934 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -3,16 +3,19 @@
 // Refer to the license.txt file included.
 
 #include "common/logging/backend.h"
-#include "common/string_util.h"
 #include "core/frontend/applets/software_keyboard.h"
 
-namespace Frontend {
-bool DefaultSoftwareKeyboardApplet::GetText(Parameters parameters, std::u16string& text) {
+namespace Core::Frontend {
+SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
+
+bool DefaultSoftwareKeyboardApplet::GetText(SoftwareKeyboardParameters parameters,
+                                            std::u16string& text) const {
     if (parameters.initial_text.empty())
-        text = Common::UTF8ToUTF16("yuzu");
+        text = u"yuzu";
     else
         text = parameters.initial_text;
 
     return true;
 }
-} // namespace Frontend
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index d368385d24..2ea9db889b 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -8,37 +8,39 @@
 #include "common/bit_field.h"
 #include "common/common_types.h"
 
-namespace Frontend {
+namespace Core::Frontend {
+struct SoftwareKeyboardParameters {
+    std::u16string submit_text;
+    std::u16string header_text;
+    std::u16string sub_text;
+    std::u16string guide_text;
+    std::u16string initial_text;
+    std::size_t max_length;
+    bool password;
+    bool cursor_at_beginning;
+
+    union {
+        u8 value;
+
+        BitField<1, 1, u8> disable_space;
+        BitField<2, 1, u8> disable_address;
+        BitField<3, 1, u8> disable_percent;
+        BitField<4, 1, u8> disable_slash;
+        BitField<6, 1, u8> disable_number;
+        BitField<7, 1, u8> disable_download_code;
+    };
+};
+
 class SoftwareKeyboardApplet {
 public:
-    struct Parameters {
-        std::u16string submit_text;
-        std::u16string header_text;
-        std::u16string sub_text;
-        std::u16string guide_text;
-        std::u16string initial_text;
-        std::size_t max_length;
-        bool password;
-        bool cursor_at_beginning;
+    virtual ~SoftwareKeyboardApplet();
 
-        union {
-            u8 value;
-
-            BitField<1, 1, u8> disable_space;
-            BitField<2, 1, u8> disable_address;
-            BitField<3, 1, u8> disable_percent;
-            BitField<4, 1, u8> disable_slash;
-            BitField<6, 1, u8> disable_number;
-            BitField<7, 1, u8> disable_download_code;
-        };
-    };
-
-    virtual bool GetText(Parameters parameters, std::u16string& text) = 0;
-    virtual ~SoftwareKeyboardApplet() = default;
+    virtual bool GetText(SoftwareKeyboardParameters parameters, std::u16string& text) const = 0;
 };
 
 class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
-    bool GetText(Parameters parameters, std::u16string& text) override;
+public:
+    bool GetText(SoftwareKeyboardParameters parameters, std::u16string& text) const override;
 };
 
-} // namespace Frontend
+} // namespace Core::Frontend
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 20af65ee79..f84b00a009 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1207,14 +1207,15 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
         return ERR_INVALID_ADDRESS;
     }
 
-    if (addr + size <= addr) {
+    if (!IsValidAddressRange(addr, size)) {
         LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})",
                   addr, size);
         return ERR_INVALID_ADDRESS_STATE;
     }
 
-    if (permissions > static_cast<u32>(MemoryPermission::ReadWrite) ||
-        permissions == static_cast<u32>(MemoryPermission::Write)) {
+    const auto perms = static_cast<MemoryPermission>(permissions);
+    if (perms != MemoryPermission::None && perms != MemoryPermission::Read &&
+        perms != MemoryPermission::ReadWrite) {
         LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})",
                   permissions);
         return ERR_INVALID_MEMORY_PERMISSIONS;
@@ -1222,7 +1223,6 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
 
     auto& kernel = Core::System::GetInstance().Kernel();
     auto& handle_table = Core::CurrentProcess()->GetHandleTable();
-    const auto perms = static_cast<MemoryPermission>(permissions);
     const auto shared_mem_handle = SharedMemory::Create(
         kernel, handle_table.Get<Process>(CurrentProcess), size, perms, perms, addr);
 
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 53580d673a..fc464270e8 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -501,6 +501,8 @@ IStorage::IStorage(std::vector<u8> buffer)
     RegisterHandlers(functions);
 }
 
+IStorage::~IStorage() = default;
+
 const std::vector<u8>& IStorage::GetData() const {
     return buffer;
 }
@@ -670,6 +672,8 @@ IStorageAccessor::IStorageAccessor(IStorage& storage)
     RegisterHandlers(functions);
 }
 
+IStorageAccessor::~IStorageAccessor() = default;
+
 void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
     IPC::ResponseBuilder rb{ctx, 4};
 
@@ -685,7 +689,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
     const u64 offset{rp.Pop<u64>()};
     const std::vector<u8> data{ctx.ReadBuffer()};
 
-    const auto size = std::min<std::size_t>(data.size(), backing.buffer.size() - offset);
+    const auto size = std::min(data.size(), backing.buffer.size() - offset);
 
     std::memcpy(&backing.buffer[offset], data.data(), size);
 
@@ -701,7 +705,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
     const u64 offset{rp.Pop<u64>()};
     std::size_t size{ctx.GetWriteBufferSize()};
 
-    size = std::min<std::size_t>(size, backing.buffer.size() - offset);
+    size = std::min(size, backing.buffer.size() - offset);
 
     ctx.WriteBuffer(backing.buffer.data() + offset, size);
 
@@ -787,9 +791,9 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
         return;
     }
 
-    std::vector<u8> memory(shared_mem->size);
-    std::memcpy(memory.data(), shared_mem->backing_block->data() + shared_mem->backing_block_offset,
-                memory.size());
+    const auto mem_begin = shared_mem->backing_block->begin() + shared_mem->backing_block_offset;
+    const auto mem_end = mem_begin + shared_mem->size;
+    std::vector<u8> memory{mem_begin, mem_end};
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 640901e4af..44c1bcde5d 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -158,27 +158,29 @@ private:
 class IStorage final : public ServiceFramework<IStorage> {
 public:
     explicit IStorage(std::vector<u8> buffer);
+    ~IStorage() override;
 
     const std::vector<u8>& GetData() const;
 
 private:
-    std::vector<u8> buffer;
-
     void Open(Kernel::HLERequestContext& ctx);
 
+    std::vector<u8> buffer;
+
     friend class IStorageAccessor;
 };
 
 class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
 public:
     explicit IStorageAccessor(IStorage& backing);
+    ~IStorageAccessor() override;
 
 private:
-    IStorage& backing;
-
     void GetSize(Kernel::HLERequestContext& ctx);
     void Write(Kernel::HLERequestContext& ctx);
     void Read(Kernel::HLERequestContext& ctx);
+
+    IStorage& backing;
 };
 
 class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 8cc4b0f1ae..03b9d83e75 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -7,23 +7,13 @@
 
 namespace Service::AM::Applets {
 
-std::shared_ptr<Frontend::SoftwareKeyboardApplet> software_keyboard =
-    std::make_shared<Frontend::DefaultSoftwareKeyboardApplet>();
+Applet::Applet() = default;
+
+Applet::~Applet() = default;
 
 void Applet::Initialize(std::vector<std::shared_ptr<IStorage>> storage) {
     storage_stack = std::move(storage);
     initialized = true;
 }
 
-void RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboardApplet> applet) {
-    if (applet == nullptr)
-        return;
-
-    software_keyboard = std::move(applet);
-}
-
-std::shared_ptr<Frontend::SoftwareKeyboardApplet> GetSoftwareKeyboard() {
-    return software_keyboard;
-}
-
 } // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 1f91392b47..47db22fb4d 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -20,10 +20,17 @@ namespace Applets {
 
 class Applet {
 public:
+    Applet();
+    virtual ~Applet();
+
     virtual void Initialize(std::vector<std::shared_ptr<IStorage>> storage);
 
     virtual IStorage Execute() = 0;
 
+    bool IsInitialized() const {
+        return initialized;
+    }
+
 protected:
     struct CommonArguments {
         u32_le arguments_version;
@@ -39,8 +46,5 @@ protected:
     bool initialized = false;
 };
 
-void RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboardApplet> applet);
-std::shared_ptr<Frontend::SoftwareKeyboardApplet> GetSoftwareKeyboard();
-
 } // namespace Applets
 } // namespace Service::AM
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index ad1797ef18..556dea3e46 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -2,8 +2,10 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <cstring>
 #include "common/assert.h"
 #include "common/string_util.h"
+#include "core/core.h"
 #include "core/frontend/applets/software_keyboard.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/software_keyboard.h"
@@ -11,11 +13,13 @@
 namespace Service::AM::Applets {
 
 constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
+constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
 constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
+constexpr bool INTERACTIVE_STATUS_OK = false;
 
-static Frontend::SoftwareKeyboardApplet::Parameters ConvertToFrontendParameters(
+static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
     KeyboardConfig config, std::u16string initial_text) {
-    Frontend::SoftwareKeyboardApplet::Parameters params{};
+    Core::Frontend::SoftwareKeyboardParameters params{};
 
     params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
         config.submit_text.data(), config.submit_text.size());
@@ -34,6 +38,10 @@ static Frontend::SoftwareKeyboardApplet::Parameters ConvertToFrontendParameters(
     return params;
 }
 
+SoftwareKeyboard::SoftwareKeyboard() = default;
+
+SoftwareKeyboard::~SoftwareKeyboard() = default;
+
 void SoftwareKeyboard::Initialize(std::vector<std::shared_ptr<IStorage>> storage_) {
     Applet::Initialize(std::move(storage_));
 
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 9a37ba45fd..9d77f5802b 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include "common/common_funcs.h"
+#include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/applets.h"
 
 namespace Service::AM::Applets {
@@ -45,13 +46,21 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz
 
 class SoftwareKeyboard final : public Applet {
 public:
+    SoftwareKeyboard();
+    ~SoftwareKeyboard() override;
+
     void Initialize(std::vector<std::shared_ptr<IStorage>> storage) override;
 
+    bool TransactionComplete() const override;
+    ResultCode GetStatus() const override;
+    void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) override;
     IStorage Execute() override;
 
 private:
     KeyboardConfig config;
     std::u16string initial_text;
+    bool complete = false;
+    std::vector<u8> final_data;
 };
 
 } // namespace Service::AM::Applets
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
index bd8bd0dd01..fad150ec18 100644
--- a/src/yuzu/applets/software_keyboard.cpp
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -2,21 +2,20 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include <locale>
+#include <algorithm>
 #include <QDialogButtonBox>
 #include <QFont>
 #include <QLabel>
 #include <QLineEdit>
 #include <QVBoxLayout>
-#include "common/logging/backend.h"
-#include "common/string_util.h"
 #include "yuzu/applets/software_keyboard.h"
+#include "yuzu/main.h"
 
 QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator(
-    Frontend::SoftwareKeyboardApplet::Parameters parameters)
+    Core::Frontend::SoftwareKeyboardParameters parameters)
     : parameters(std::move(parameters)) {}
 
-QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int&) const {
+QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const {
     if (input.size() > parameters.max_length)
         return Invalid;
     if (parameters.disable_space && input.contains(' '))
@@ -28,18 +27,20 @@ QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int&) co
     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(); }))
+        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'; }))
+        std::any_of(input.begin(), input.end(), [](QChar c) { return c == 'O' || c == 'I'; })) {
         return Invalid;
+    }
 
     return Acceptable;
 }
 
 QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
-    QWidget* parent, Frontend::SoftwareKeyboardApplet::Parameters parameters_)
+    QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_)
     : QDialog(parent), parameters(std::move(parameters_)) {
     layout = new QVBoxLayout;
 
@@ -79,9 +80,11 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
     layout->addWidget(line_edit);
     layout->addWidget(buttons);
     setLayout(layout);
-    setWindowTitle("Software Keyboard");
+    setWindowTitle(tr("Software Keyboard"));
 }
 
+QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
+
 void QtSoftwareKeyboardDialog::Submit() {
     ok = true;
     text = line_edit->text().toStdU16String();
@@ -90,19 +93,33 @@ void QtSoftwareKeyboardDialog::Submit() {
 
 void QtSoftwareKeyboardDialog::Reject() {
     ok = false;
-    text = Common::UTF8ToUTF16("");
+    text.clear();
     accept();
 }
 
-QtSoftwareKeyboard::QtSoftwareKeyboard(QWidget& parent) : parent(parent) {}
-
-bool QtSoftwareKeyboard::GetText(Parameters parameters, std::u16string& text) {
-    QtSoftwareKeyboardDialog dialog(&parent, parameters);
-    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
-                          Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
-    dialog.setWindowModality(Qt::WindowModal);
-    dialog.exec();
-
-    text = dialog.text;
-    return dialog.ok;
+std::u16string QtSoftwareKeyboardDialog::GetText() {
+    return text;
+}
+
+bool QtSoftwareKeyboardDialog::GetStatus() {
+    return ok;
+}
+
+QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& parent) : main_window(parent) {}
+
+QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
+
+bool QtSoftwareKeyboard::GetText(Core::Frontend::SoftwareKeyboardParameters parameters,
+                                 std::u16string& text) const {
+    bool success;
+    QMetaObject::invokeMethod(&main_window, "SoftwareKeyboardGetText", Qt::BlockingQueuedConnection,
+                              Q_RETURN_ARG(bool, success),
+                              Q_ARG(Core::Frontend::SoftwareKeyboardParameters, parameters),
+                              Q_ARG(std::u16string&, text));
+    return success;
+}
+
+void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message) const {
+    QMetaObject::invokeMethod(&main_window, "SoftwareKeyboardInvokeCheckDialog",
+                              Qt::BlockingQueuedConnection, Q_ARG(std::u16string, error_message));
 }
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h
index 2a18419db4..1069c10ec8 100644
--- a/src/yuzu/applets/software_keyboard.h
+++ b/src/yuzu/applets/software_keyboard.h
@@ -3,11 +3,13 @@
 // 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;
@@ -16,11 +18,11 @@ class QtSoftwareKeyboard;
 
 class QtSoftwareKeyboardValidator final : public QValidator {
 public:
-    explicit QtSoftwareKeyboardValidator(Frontend::SoftwareKeyboardApplet::Parameters parameters);
-    State validate(QString&, int&) const override;
+    explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
+    State validate(QString& input, int& pos) const override;
 
 private:
-    Frontend::SoftwareKeyboardApplet::Parameters parameters;
+    Core::Frontend::SoftwareKeyboardParameters parameters;
 };
 
 class QtSoftwareKeyboardDialog final : public QDialog {
@@ -28,10 +30,15 @@ class QtSoftwareKeyboardDialog final : public QDialog {
 
 public:
     QtSoftwareKeyboardDialog(QWidget* parent,
-                             Frontend::SoftwareKeyboardApplet::Parameters parameters);
+                             Core::Frontend::SoftwareKeyboardParameters parameters);
+    ~QtSoftwareKeyboardDialog() override;
+
     void Submit();
     void Reject();
 
+    std::u16string GetText();
+    bool GetStatus();
+
 private:
     bool ok = false;
     std::u16string text;
@@ -43,20 +50,18 @@ private:
     QLineEdit* line_edit;
     QVBoxLayout* layout;
 
-    Frontend::SoftwareKeyboardApplet::Parameters parameters;
-
-    friend class QtSoftwareKeyboard;
+    Core::Frontend::SoftwareKeyboardParameters parameters;
 };
 
-class QtSoftwareKeyboard final : public QObject, public Frontend::SoftwareKeyboardApplet {
+class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
 public:
-    explicit QtSoftwareKeyboard(QWidget& parent);
-    bool GetText(Parameters parameters, std::u16string& text) override;
+    explicit QtSoftwareKeyboard(GMainWindow& parent);
+    ~QtSoftwareKeyboard() override;
 
-    ~QtSoftwareKeyboard() {
-        UNREACHABLE();
-    }
+    bool GetText(Core::Frontend::SoftwareKeyboardParameters parameters,
+                 std::u16string& text) const override;
+    void SendTextCheckDialog(std::u16string error_message) const override;
 
 private:
-    QWidget& parent;
+    GMainWindow& main_window;
 };
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 7b2a01169d..9b2c09f324 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -561,7 +561,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
 
     system.SetGPUDebugContext(debug_context);
 
-    Service::AM::Applets::RegisterSoftwareKeyboard(std::make_shared<QtSoftwareKeyboard>(*this));
+    system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
 
     const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
 
@@ -1232,8 +1232,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::u16string>("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 929250e8cd..38074e3f0e 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,11 @@ signals:
     // Signal that tells widgets to update icons to use the current theme
     void UpdateThemedIcons();
 
+public slots:
+    bool SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters,
+                                 std::u16string& text);
+    void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
+
 private:
     void InitializeWidgets();
     void InitializeDebugWidgets();