diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index 41d81c2934..05e2dc6b78 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -18,4 +18,10 @@ bool DefaultSoftwareKeyboardApplet::GetText(SoftwareKeyboardParameters parameter
     return true;
 }
 
+void DefaultSoftwareKeyboardApplet::SendTextCheckDialog(std::u16string error_message) const {
+    LOG_WARNING(Service_AM,
+                "(STUBBED) called - Default fallback software keyboard does not support text "
+                "check! (error_message={})",
+                Common::UTF16ToUTF8(error_message));
+}
 } // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index 2ea9db889b..0a82aac0d1 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -36,11 +36,13 @@ public:
     virtual ~SoftwareKeyboardApplet();
 
     virtual bool GetText(SoftwareKeyboardParameters parameters, std::u16string& text) const = 0;
+    virtual void SendTextCheckDialog(std::u16string error_message) const = 0;
 };
 
 class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
 public:
     bool GetText(SoftwareKeyboardParameters parameters, std::u16string& text) const override;
+    void SendTextCheckDialog(std::u16string error_message) const override;
 };
 
 } // namespace Core::Frontend
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index fc464270e8..ea00c5c720 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -544,7 +544,7 @@ public:
             {102, nullptr, "PushExtraStorage"},
             {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
             {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
-            {105, nullptr, "GetPopOutDataEvent"},
+            {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
             {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
             {110, nullptr, "NeedsToExitProcess"},
             {120, nullptr, "GetLibraryAppletInfo"},
@@ -558,6 +558,8 @@ public:
         auto& kernel = Core::System::GetInstance().Kernel();
         state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
                                                     "ILibraryAppletAccessor:StateChangedEvent");
+        pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
+                                                   "ILibraryAppletAccessor:PopDataOutEvent");
         pop_interactive_out_data_event =
             Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
                                   "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
@@ -585,9 +587,16 @@ private:
         ASSERT(applet != nullptr);
 
         applet->Initialize(storage_stack);
-        interactive_storage_stack.push_back(std::make_shared<IStorage>(applet->Execute()));
+        const auto data = std::make_shared<IStorage>(applet->Execute());
         state_changed_event->Signal();
-        pop_interactive_out_data_event->Signal();
+
+        if (applet->TransactionComplete()) {
+            storage_stack.push_back(data);
+            pop_out_data_event->Signal();
+        } else {
+            interactive_storage_stack.push_back(data);
+            pop_interactive_out_data_event->Signal();
+        }
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
@@ -617,6 +626,19 @@ private:
         IPC::RequestParser rp{ctx};
         interactive_storage_stack.push_back(rp.PopIpcInterface<IStorage>());
 
+        ASSERT(applet->IsInitialized());
+        applet->ReceiveInteractiveData(interactive_storage_stack.back());
+        const auto data = std::make_shared<IStorage>(applet->Execute());
+        state_changed_event->Signal();
+
+        if (applet->TransactionComplete()) {
+            storage_stack.push_back(data);
+            pop_out_data_event->Signal();
+        } else {
+            interactive_storage_stack.push_back(data);
+            pop_interactive_out_data_event->Signal();
+        }
+
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(RESULT_SUCCESS);
 
@@ -633,9 +655,13 @@ private:
         LOG_DEBUG(Service_AM, "called");
     }
 
-    void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
-        pop_interactive_out_data_event->Signal();
+    void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
+        IPC::ResponseBuilder rb{ctx, 2, 1};
+        rb.Push(RESULT_SUCCESS);
+        rb.PushCopyObjects(pop_out_data_event);
+    }
 
+    void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
         IPC::ResponseBuilder rb{ctx, 2, 1};
         rb.Push(RESULT_SUCCESS);
         rb.PushCopyObjects(pop_interactive_out_data_event);
@@ -647,6 +673,7 @@ private:
     std::vector<std::shared_ptr<IStorage>> storage_stack;
     std::vector<std::shared_ptr<IStorage>> interactive_storage_stack;
     Kernel::SharedPtr<Kernel::Event> state_changed_event;
+    Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
     Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
 };
 
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 47db22fb4d..6d90eb608f 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -8,6 +8,8 @@
 #include <vector>
 #include "common/swap.h"
 
+union ResultCode;
+
 namespace Frontend {
 class SoftwareKeyboardApplet;
 }
@@ -25,6 +27,9 @@ public:
 
     virtual void Initialize(std::vector<std::shared_ptr<IStorage>> storage);
 
+    virtual bool TransactionComplete() const = 0;
+    virtual ResultCode GetStatus() const = 0;
+    virtual void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) = 0;
     virtual IStorage Execute() = 0;
 
     bool IsInitialized() const {
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 556dea3e46..044a162648 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -50,28 +50,77 @@ void SoftwareKeyboard::Initialize(std::vector<std::shared_ptr<IStorage>> storage
     ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
     std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
 
-    ASSERT_MSG(config.text_check == 0, "Text check software keyboard mode is not implemented!");
-
     const auto& work_buffer = storage_stack[2]->GetData();
-    std::memcpy(initial_text.data(), work_buffer.data() + config.initial_string_offset,
-                config.initial_string_size);
+
+    if (config.initial_string_size == 0)
+        return;
+
+    std::vector<char16_t> string(config.initial_string_size);
+    std::memcpy(string.data(), work_buffer.data() + 4, string.size() * 2);
+    initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
+}
+
+bool SoftwareKeyboard::TransactionComplete() const {
+    return complete;
+}
+
+ResultCode SoftwareKeyboard::GetStatus() const {
+    return RESULT_SUCCESS;
+}
+
+void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) {
+    if (complete)
+        return;
+
+    const auto data = storage->GetData();
+    const auto status = static_cast<bool>(data[0]);
+
+    if (status == INTERACTIVE_STATUS_OK) {
+        complete = true;
+    } else {
+        const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
+
+        std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
+        std::memcpy(string.data(), data.data() + 4, string.size() * 2);
+        frontend.SendTextCheckDialog(
+            Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()));
+    }
 }
 
 IStorage SoftwareKeyboard::Execute() {
-    const auto frontend{GetSoftwareKeyboard()};
-    ASSERT(frontend != nullptr);
+    if (complete)
+        return IStorage{final_data};
+
+    const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
 
     const auto parameters = ConvertToFrontendParameters(config, initial_text);
 
     std::u16string text;
-    const auto success = frontend->GetText(parameters, text);
+    const auto success = frontend.GetText(parameters, text);
 
     std::vector<u8> output(SWKBD_OUTPUT_BUFFER_SIZE);
 
     if (success) {
-        output[0] = 1;
+        if (config.text_check) {
+            const auto size = static_cast<u32>(text.size() * 2 + 4);
+            std::memcpy(output.data(), &size, sizeof(u32));
+        } else {
+            output[0] = 1;
+        }
+
         std::memcpy(output.data() + 4, text.data(),
-                    std::min<std::size_t>(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
+                    std::min(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
+    } else {
+        complete = true;
+        final_data = std::move(output);
+        return IStorage{final_data};
+    }
+
+    complete = !config.text_check;
+
+    if (complete) {
+        final_data = std::move(output);
+        return IStorage{final_data};
     }
 
     return IStorage{output};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9b2c09f324..447d9dece8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -61,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"
@@ -206,6 +207,22 @@ GMainWindow::~GMainWindow() {
         delete render_window;
 }
 
+bool GMainWindow::SoftwareKeyboardGetText(
+    const Core::Frontend::SoftwareKeyboardParameters& parameters, std::u16string& text) {
+    QtSoftwareKeyboardDialog dialog(this, parameters);
+    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+                          Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
+    dialog.setWindowModality(Qt::WindowModal);
+    dialog.exec();
+
+    text = dialog.GetText();
+    return dialog.GetStatus();
+}
+
+void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) {
+    QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message));
+}
+
 void GMainWindow::InitializeWidgets() {
 #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
     ui.action_Report_Compatibility->setVisible(true);