From 578e6c5a57bc29aed27e604ac0ede34f87bae86d Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Tue, 16 Mar 2021 13:01:03 -0400
Subject: [PATCH] applets/swkbd: Implement the Default Software Keyboard
 frontend

---
 .../frontend/applets/software_keyboard.cpp    | 140 +++++++++++++++++-
 src/core/frontend/applets/software_keyboard.h |  98 +++++++++++-
 2 files changed, 236 insertions(+), 2 deletions(-)

diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index 73e7a89b9..12c76c9ee 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -1,11 +1,149 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <thread>
+
+#include "common/logging/log.h"
+#include "common/string_util.h"
 #include "core/frontend/applets/software_keyboard.h"
 
 namespace Core::Frontend {
 
 SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
 
+DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
+
+void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
+    bool is_inline, KeyboardInitializeParameters initialize_parameters,
+    std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
+    std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+        submit_inline_callback_) {
+    if (is_inline) {
+        LOG_WARNING(
+            Service_AM,
+            "(STUBBED) called, backend requested to initialize the inline software keyboard.");
+
+        submit_inline_callback = std::move(submit_inline_callback_);
+    } else {
+        LOG_WARNING(
+            Service_AM,
+            "(STUBBED) called, backend requested to initialize the normal software keyboard.");
+
+        submit_normal_callback = std::move(submit_normal_callback_);
+    }
+
+    parameters = std::move(initialize_parameters);
+
+    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(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
+             Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
+             Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
+             parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
+             parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
+             parameters.use_blur_background, parameters.enable_backspace_button,
+             parameters.enable_return_button, parameters.disable_cancel_button);
+}
+
+void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
+    LOG_WARNING(Service_AM,
+                "(STUBBED) called, backend requested to show the normal software keyboard.");
+
+    SubmitNormalText(u"yuzu");
+}
+
+void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
+    Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+    std::u16string text_check_message) const {
+    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
+}
+
+void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
+    InlineAppearParameters appear_parameters) const {
+    LOG_WARNING(Service_AM,
+                "(STUBBED) called, backend requested to show the inline software keyboard.");
+
+    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);
+
+    std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
+}
+
+void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
+    LOG_WARNING(Service_AM,
+                "(STUBBED) called, backend requested to hide the inline software keyboard.");
+}
+
+void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
+    LOG_WARNING(Service_AM,
+                "(STUBBED) called, backend requested to change the inline keyboard text.");
+
+    LOG_INFO(Service_AM,
+             "\nInlineTextParameters:"
+             "\ninput_text={}"
+             "\ncursor_position={}",
+             Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
+
+    submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
+                           text_parameters.input_text, text_parameters.cursor_position);
+}
+
+void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
+    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
+}
+
+void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
+    submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
+}
+
+void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+    for (std::size_t index = 0; index < text.size(); ++index) {
+        submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
+                               std::u16string(text.data(), text.data() + index + 1),
+                               static_cast<s32>(index) + 1);
+
+        std::this_thread::sleep_for(std::chrono::milliseconds(250));
+    }
+
+    submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
+                           static_cast<s32>(text.size()));
+}
+
 } // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index 54528837e..506eb35bb 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -1,20 +1,116 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
 #pragma once
 
+#include <functional>
+#include <thread>
+
 #include "common/common_types.h"
 
+#include "core/hle/service/am/applets/software_keyboard_types.h"
+
 namespace Core::Frontend {
 
+struct KeyboardInitializeParameters {
+    std::u16string ok_text;
+    std::u16string header_text;
+    std::u16string sub_text;
+    std::u16string guide_text;
+    std::u16string initial_text;
+    u32 max_text_length;
+    u32 min_text_length;
+    s32 initial_cursor_position;
+    Service::AM::Applets::SwkbdType type;
+    Service::AM::Applets::SwkbdPasswordMode password_mode;
+    Service::AM::Applets::SwkbdTextDrawType text_draw_type;
+    Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
+    bool use_blur_background;
+    bool enable_backspace_button;
+    bool enable_return_button;
+    bool disable_cancel_button;
+};
+
+struct InlineAppearParameters {
+    u32 max_text_length;
+    u32 min_text_length;
+    f32 key_top_scale_x;
+    f32 key_top_scale_y;
+    f32 key_top_translate_x;
+    f32 key_top_translate_y;
+    Service::AM::Applets::SwkbdType type;
+    Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
+    bool key_top_as_floating;
+    bool enable_backspace_button;
+    bool enable_return_button;
+    bool disable_cancel_button;
+};
+
+struct InlineTextParameters {
+    std::u16string input_text;
+    s32 cursor_position;
+};
+
 class SoftwareKeyboardApplet {
 public:
     virtual ~SoftwareKeyboardApplet();
+
+    virtual void InitializeKeyboard(
+        bool is_inline, KeyboardInitializeParameters initialize_parameters,
+        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+            submit_normal_callback_,
+        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+            submit_inline_callback_) = 0;
+
+    virtual void ShowNormalKeyboard() const = 0;
+
+    virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+                                     std::u16string text_check_message) const = 0;
+
+    virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
+
+    virtual void HideInlineKeyboard() const = 0;
+
+    virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0;
+
+    virtual void ExitKeyboard() const = 0;
 };
 
 class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
 public:
+    ~DefaultSoftwareKeyboardApplet() override;
+
+    void InitializeKeyboard(
+        bool is_inline, KeyboardInitializeParameters initialize_parameters,
+        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+            submit_normal_callback_,
+        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+            submit_inline_callback_) override;
+
+    void ShowNormalKeyboard() const override;
+
+    void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+                             std::u16string text_check_message) const override;
+
+    void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
+
+    void HideInlineKeyboard() const override;
+
+    void InlineTextChanged(InlineTextParameters text_parameters) const override;
+
+    void ExitKeyboard() const override;
+
+private:
+    void SubmitNormalText(std::u16string text) const;
+    void SubmitInlineText(std::u16string_view text) const;
+
+    KeyboardInitializeParameters parameters;
+
+    mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
+        submit_normal_callback;
+    mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
+        submit_inline_callback;
 };
 
 } // namespace Core::Frontend