summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/jni
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/app/src/main/jni')
-rw-r--r--src/android/app/src/main/jni/CMakeLists.txt4
-rw-r--r--src/android/app/src/main/jni/android_common/android_common.cpp35
-rw-r--r--src/android/app/src/main/jni/android_common/android_common.h12
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.cpp277
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.h78
-rw-r--r--src/android/app/src/main/jni/id_cache.cpp7
-rw-r--r--src/android/app/src/main/jni/native.cpp62
-rw-r--r--src/android/app/src/main/jni/native.h6
8 files changed, 462 insertions, 19 deletions
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt
index 21c27d4ee..3cf36b7d1 100644
--- a/src/android/app/src/main/jni/CMakeLists.txt
+++ b/src/android/app/src/main/jni/CMakeLists.txt
@@ -1,4 +1,8 @@
add_library(yuzu-android SHARED
+ android_common/android_common.cpp
+ android_common/android_common.h
+ applets/software_keyboard.cpp
+ applets/software_keyboard.h
config.cpp
config.h
default_ini.h
diff --git a/src/android/app/src/main/jni/android_common/android_common.cpp b/src/android/app/src/main/jni/android_common/android_common.cpp
new file mode 100644
index 000000000..52d8ecfeb
--- /dev/null
+++ b/src/android/app/src/main/jni/android_common/android_common.cpp
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "jni/android_common/android_common.h"
+
+#include <string>
+#include <string_view>
+
+#include <jni.h>
+
+#include "common/string_util.h"
+
+std::string GetJString(JNIEnv* env, jstring jstr) {
+ if (!jstr) {
+ return {};
+ }
+
+ const jchar* jchars = env->GetStringChars(jstr, nullptr);
+ const jsize length = env->GetStringLength(jstr);
+ const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length);
+ const std::string converted_string = Common::UTF16ToUTF8(string_view);
+ env->ReleaseStringChars(jstr, jchars);
+
+ return converted_string;
+}
+
+jstring ToJString(JNIEnv* env, std::string_view str) {
+ const std::u16string converted_string = Common::UTF8ToUTF16(str);
+ return env->NewString(reinterpret_cast<const jchar*>(converted_string.data()),
+ static_cast<jint>(converted_string.size()));
+}
+
+jstring ToJString(JNIEnv* env, std::u16string_view str) {
+ return ToJString(env, Common::UTF16ToUTF8(str));
+}
diff --git a/src/android/app/src/main/jni/android_common/android_common.h b/src/android/app/src/main/jni/android_common/android_common.h
new file mode 100644
index 000000000..ccb0c06f7
--- /dev/null
+++ b/src/android/app/src/main/jni/android_common/android_common.h
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <string>
+
+#include <jni.h>
+
+std::string GetJString(JNIEnv* env, jstring jstr);
+jstring ToJString(JNIEnv* env, std::string_view str);
+jstring ToJString(JNIEnv* env, std::u16string_view str);
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.cpp b/src/android/app/src/main/jni/applets/software_keyboard.cpp
new file mode 100644
index 000000000..278137b4c
--- /dev/null
+++ b/src/android/app/src/main/jni/applets/software_keyboard.cpp
@@ -0,0 +1,277 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <map>
+#include <thread>
+
+#include <jni.h>
+
+#include "common/logging/log.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "jni/android_common/android_common.h"
+#include "jni/applets/software_keyboard.h"
+#include "jni/id_cache.h"
+
+static jclass s_software_keyboard_class;
+static jclass s_keyboard_config_class;
+static jclass s_keyboard_data_class;
+static jmethodID s_swkbd_execute_normal;
+static jmethodID s_swkbd_execute_inline;
+
+namespace SoftwareKeyboard {
+
+static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParameters& config) {
+ JNIEnv* env = IDCache::GetEnvForThread();
+ jobject object = env->AllocObject(s_keyboard_config_class);
+
+ env->SetObjectField(object,
+ env->GetFieldID(s_keyboard_config_class, "ok_text", "Ljava/lang/String;"),
+ ToJString(env, config.ok_text));
+ env->SetObjectField(
+ object, env->GetFieldID(s_keyboard_config_class, "header_text", "Ljava/lang/String;"),
+ ToJString(env, config.header_text));
+ env->SetObjectField(object,
+ env->GetFieldID(s_keyboard_config_class, "sub_text", "Ljava/lang/String;"),
+ ToJString(env, config.sub_text));
+ env->SetObjectField(
+ object, env->GetFieldID(s_keyboard_config_class, "guide_text", "Ljava/lang/String;"),
+ ToJString(env, config.guide_text));
+ env->SetObjectField(
+ object, env->GetFieldID(s_keyboard_config_class, "initial_text", "Ljava/lang/String;"),
+ ToJString(env, config.initial_text));
+ env->SetShortField(object,
+ env->GetFieldID(s_keyboard_config_class, "left_optional_symbol_key", "S"),
+ static_cast<jshort>(config.left_optional_symbol_key));
+ env->SetShortField(object,
+ env->GetFieldID(s_keyboard_config_class, "right_optional_symbol_key", "S"),
+ static_cast<jshort>(config.right_optional_symbol_key));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "max_text_length", "I"),
+ static_cast<jint>(config.max_text_length));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "min_text_length", "I"),
+ static_cast<jint>(config.min_text_length));
+ env->SetIntField(object,
+ env->GetFieldID(s_keyboard_config_class, "initial_cursor_position", "I"),
+ static_cast<jint>(config.initial_cursor_position));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "type", "I"),
+ static_cast<jint>(config.type));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "password_mode", "I"),
+ static_cast<jint>(config.password_mode));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "text_draw_type", "I"),
+ static_cast<jint>(config.text_draw_type));
+ env->SetIntField(object, env->GetFieldID(s_keyboard_config_class, "key_disable_flags", "I"),
+ static_cast<jint>(config.key_disable_flags.raw));
+ env->SetBooleanField(object,
+ env->GetFieldID(s_keyboard_config_class, "use_blur_background", "Z"),
+ static_cast<jboolean>(config.use_blur_background));
+ env->SetBooleanField(object,
+ env->GetFieldID(s_keyboard_config_class, "enable_backspace_button", "Z"),
+ static_cast<jboolean>(config.enable_backspace_button));
+ env->SetBooleanField(object,
+ env->GetFieldID(s_keyboard_config_class, "enable_return_button", "Z"),
+ static_cast<jboolean>(config.enable_return_button));
+ env->SetBooleanField(object,
+ env->GetFieldID(s_keyboard_config_class, "disable_cancel_button", "Z"),
+ static_cast<jboolean>(config.disable_cancel_button));
+
+ return object;
+}
+
+AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobject object) {
+ JNIEnv* env = IDCache::GetEnvForThread();
+ const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
+ object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
+ return ResultData{GetJString(env, string),
+ static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField(
+ object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
+}
+
+AndroidKeyboard::~AndroidKeyboard() = default;
+
+void AndroidKeyboard::InitializeKeyboard(
+ bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
+ SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {
+ if (is_inline) {
+ LOG_WARNING(
+ Frontend,
+ "(STUBBED) called, backend requested to initialize the inline software keyboard.");
+
+ submit_inline_callback = std::move(submit_inline_callback_);
+ } else {
+ LOG_WARNING(
+ Frontend,
+ "(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(Frontend,
+ "\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 AndroidKeyboard::ShowNormalKeyboard() const {
+ LOG_DEBUG(Frontend, "called, backend requested to show the normal software keyboard.");
+
+ ResultData data{};
+
+ // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
+ std::thread([&] {
+ data = ResultData::CreateFromFrontend(IDCache::GetEnvForThread()->CallStaticObjectMethod(
+ s_software_keyboard_class, s_swkbd_execute_normal, ToJKeyboardParams(parameters)));
+ }).join();
+
+ SubmitNormalText(data);
+}
+
+void AndroidKeyboard::ShowTextCheckDialog(
+ Service::AM::Applets::SwkbdTextCheckResult text_check_result,
+ std::u16string text_check_message) const {
+ LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
+}
+
+void AndroidKeyboard::ShowInlineKeyboard(
+ Core::Frontend::InlineAppearParameters appear_parameters) const {
+ LOG_WARNING(Frontend,
+ "(STUBBED) called, backend requested to show the inline software keyboard.");
+
+ LOG_INFO(Frontend,
+ "\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);
+
+ // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
+ m_is_inline_active = true;
+ std::thread([&] {
+ IDCache::GetEnvForThread()->CallStaticVoidMethod(
+ s_software_keyboard_class, s_swkbd_execute_inline, ToJKeyboardParams(parameters));
+ }).join();
+}
+
+void AndroidKeyboard::HideInlineKeyboard() const {
+ LOG_WARNING(Frontend,
+ "(STUBBED) called, backend requested to hide the inline software keyboard.");
+}
+
+void AndroidKeyboard::InlineTextChanged(
+ Core::Frontend::InlineTextParameters text_parameters) const {
+ LOG_WARNING(Frontend,
+ "(STUBBED) called, backend requested to change the inline keyboard text.");
+
+ LOG_INFO(Frontend,
+ "\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 AndroidKeyboard::ExitKeyboard() const {
+ LOG_WARNING(Frontend, "(STUBBED) called, backend requested to exit the software keyboard.");
+}
+
+void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
+ if (!m_is_inline_active) {
+ return;
+ }
+
+ m_current_text += submitted_text;
+
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
+ m_current_text.size());
+}
+
+void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
+ static constexpr int KEYCODE_BACK = 4;
+ static constexpr int KEYCODE_ENTER = 66;
+ static constexpr int KEYCODE_DEL = 67;
+
+ if (!m_is_inline_active) {
+ return;
+ }
+
+ switch (key_code) {
+ case KEYCODE_BACK:
+ case KEYCODE_ENTER:
+ m_is_inline_active = false;
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text,
+ static_cast<s32>(m_current_text.size()));
+ break;
+ case KEYCODE_DEL:
+ m_current_text.pop_back();
+ submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text,
+ m_current_text.size());
+ break;
+ }
+}
+
+void AndroidKeyboard::SubmitNormalText(const ResultData& data) const {
+ submit_normal_callback(data.result, Common::UTF8ToUTF16(data.text), true);
+}
+
+void InitJNI(JNIEnv* env) {
+ s_software_keyboard_class = reinterpret_cast<jclass>(
+ env->NewGlobalRef(env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard")));
+ s_keyboard_config_class = reinterpret_cast<jclass>(env->NewGlobalRef(
+ env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig")));
+ s_keyboard_data_class = reinterpret_cast<jclass>(env->NewGlobalRef(
+ env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardData")));
+
+ s_swkbd_execute_normal = env->GetStaticMethodID(
+ s_software_keyboard_class, "ExecuteNormal",
+ "(Lorg/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig;)Lorg/yuzu/yuzu_emu/"
+ "applets/SoftwareKeyboard$KeyboardData;");
+ s_swkbd_execute_inline =
+ env->GetStaticMethodID(s_software_keyboard_class, "ExecuteInline",
+ "(Lorg/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig;)V");
+}
+
+void CleanupJNI(JNIEnv* env) {
+ env->DeleteGlobalRef(s_software_keyboard_class);
+ env->DeleteGlobalRef(s_keyboard_config_class);
+ env->DeleteGlobalRef(s_keyboard_data_class);
+}
+
+} // namespace SoftwareKeyboard
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.h b/src/android/app/src/main/jni/applets/software_keyboard.h
new file mode 100644
index 000000000..b2fb59b68
--- /dev/null
+++ b/src/android/app/src/main/jni/applets/software_keyboard.h
@@ -0,0 +1,78 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <jni.h>
+
+#include "core/frontend/applets/software_keyboard.h"
+
+namespace SoftwareKeyboard {
+
+class AndroidKeyboard final : public Core::Frontend::SoftwareKeyboardApplet {
+public:
+ ~AndroidKeyboard() override;
+
+ void Close() const override {
+ ExitKeyboard();
+ }
+
+ void InitializeKeyboard(bool is_inline,
+ Core::Frontend::KeyboardInitializeParameters initialize_parameters,
+ SubmitNormalCallback submit_normal_callback_,
+ SubmitInlineCallback 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(
+ Core::Frontend::InlineAppearParameters appear_parameters) const override;
+
+ void HideInlineKeyboard() const override;
+
+ void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
+
+ void ExitKeyboard() const override;
+
+ void SubmitInlineKeyboardText(std::u16string submitted_text);
+
+ void SubmitInlineKeyboardInput(int key_code);
+
+private:
+ struct ResultData {
+ static ResultData CreateFromFrontend(jobject object);
+
+ std::string text;
+ Service::AM::Applets::SwkbdResult result{};
+ };
+
+ void SubmitNormalText(const ResultData& result) const;
+
+ Core::Frontend::KeyboardInitializeParameters parameters{};
+
+ mutable SubmitNormalCallback submit_normal_callback;
+ mutable SubmitInlineCallback submit_inline_callback;
+
+private:
+ mutable bool m_is_inline_active{};
+ std::u16string m_current_text;
+};
+
+// Should be called in JNI_Load
+void InitJNI(JNIEnv* env);
+
+// Should be called in JNI_Unload
+void CleanupJNI(JNIEnv* env);
+
+} // namespace SoftwareKeyboard
+
+// Native function calls
+extern "C" {
+JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_applets_SoftwareKeyboard_ValidateFilters(
+ JNIEnv* env, jclass clazz, jstring text);
+
+JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_applets_SoftwareKeyboard_ValidateInput(
+ JNIEnv* env, jclass clazz, jstring text);
+}
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp
index 8f085798d..6291c8652 100644
--- a/src/android/app/src/main/jni/id_cache.cpp
+++ b/src/android/app/src/main/jni/id_cache.cpp
@@ -4,6 +4,7 @@
#include <jni.h>
#include "common/fs/fs_android.h"
+#include "jni/applets/software_keyboard.h"
#include "jni/id_cache.h"
static JavaVM* s_java_vm;
@@ -63,6 +64,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
+ // Initialize applets
+ SoftwareKeyboard::InitJNI(env);
+
return JNI_VERSION;
}
@@ -75,6 +79,9 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
// UnInitialize Android Storage
Common::FS::Android::UnRegisterCallbacks();
env->DeleteGlobalRef(s_native_library_class);
+
+ // UnInitialze applets
+ SoftwareKeyboard::CleanupJNI(env);
}
#ifdef __cplusplus
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 6e670e899..10603c8fa 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -23,15 +23,29 @@
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h"
+#include "common/string_util.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
+#include "core/frontend/applets/cabinet.h"
+#include "core/frontend/applets/controller.h"
+#include "core/frontend/applets/error.h"
+#include "core/frontend/applets/general_frontend.h"
+#include "core/frontend/applets/mii_edit.h"
+#include "core/frontend/applets/profile_select.h"
+#include "core/frontend/applets/software_keyboard.h"
+#include "core/frontend/applets/web_browser.h"
#include "core/hid/hid_core.h"
+#include "core/hle/service/am/applet_ae.h"
+#include "core/hle/service/am/applet_oe.h"
+#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
+#include "jni/android_common/android_common.h"
+#include "jni/applets/software_keyboard.h"
#include "jni/config.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h"
@@ -135,11 +149,24 @@ public:
m_vulkan_library);
// Initialize system.
+ auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
+ m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false);
m_system.ApplySettings();
m_system.HIDCore().ReloadInputDevices();
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
+ m_system.SetAppletFrontendSet({
+ nullptr, // Amiibo Settings
+ nullptr, // Controller Selector
+ nullptr, // Error Display
+ nullptr, // Mii Editor
+ nullptr, // Parental Controls
+ nullptr, // Photo Viewer
+ nullptr, // Profile Selector
+ std::move(android_keyboard), // Software Keyboard
+ nullptr, // Web Browser
+ });
m_system.GetFileSystemController().CreateFactories(*m_system.GetFilesystem());
// Load the ROM.
@@ -233,6 +260,10 @@ public:
m_rom_metadata_cache.clear();
}
+ SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
+ return m_software_keyboard;
+ }
+
private:
struct RomMetadata {
std::string title;
@@ -278,6 +309,7 @@ private:
std::shared_ptr<FileSys::RealVfsFilesystem> m_vfs;
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
bool m_is_running{};
+ SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
@@ -290,25 +322,6 @@ private:
/*static*/ EmulationSession EmulationSession::s_instance;
-std::string UTF16ToUTF8(std::u16string_view input) {
- std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
- return convert.to_bytes(input.data(), input.data() + input.size());
-}
-
-std::string GetJString(JNIEnv* env, jstring jstr) {
- if (!jstr) {
- return {};
- }
-
- const jchar* jchars = env->GetStringChars(jstr, nullptr);
- const jsize length = env->GetStringLength(jstr);
- const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length);
- const std::string converted_string = UTF16ToUTF8(string_view);
- env->ReleaseStringChars(jstr, jchars);
-
- return converted_string;
-}
-
} // Anonymous namespace
static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
@@ -605,4 +618,15 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
}
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText(JNIEnv* env, jclass clazz,
+ jstring j_text) {
+ const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
+ EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
+}
+
+void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput(JNIEnv* env, jclass clazz,
+ jint j_key_code) {
+ EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
+}
+
} // extern "C"
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
index 192c9261d..d30351c16 100644
--- a/src/android/app/src/main/jni/native.h
+++ b/src/android/app/src/main/jni/native.h
@@ -133,6 +133,12 @@ JNIEXPORT jdoubleArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStat
JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env,
jclass clazz);
+JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText(
+ JNIEnv* env, jclass clazz, jstring j_text);
+
+JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput(
+ JNIEnv* env, jclass clazz, jint j_key_code);
+
#ifdef __cplusplus
}
#endif