From b5ef0791c512b67a2826812cd9a3c974eab26383 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 5 Sep 2020 10:49:09 +0900 Subject: [PATCH] Android: Implement text input dialog --- .../github/kichikuou/system3/GameActivity.kt | 37 +++++++++++++- src/CMakeLists.txt | 2 +- src/android/jnihelper.h | 33 +++++++++++++ src/android/mako.cpp | 28 +---------- src/android/nact_android.cpp | 48 +++++++++++++++++++ 5 files changed, 119 insertions(+), 29 deletions(-) create mode 100644 src/android/jnihelper.h create mode 100644 src/android/nact_android.cpp diff --git a/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt b/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt index 362f4d4..74a215a 100644 --- a/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt +++ b/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt @@ -17,9 +17,12 @@ */ package io.github.kichikuou.system3 +import android.app.AlertDialog import android.media.MediaPlayer import android.os.Bundle +import android.text.InputType import android.util.Log +import android.widget.EditText import org.libsdl.app.SDLActivity import java.io.File import java.io.IOException @@ -74,13 +77,45 @@ class GameActivity : SDLActivity() { Launcher.updateGameList() } - // These functions are called in the SDL thread by JNI. + private fun textInputDialog(oldVal: String, result: Array) { + val input = EditText(this) + input.inputType = InputType.TYPE_CLASS_TEXT + input.setText(oldVal) + AlertDialog.Builder(this) + .setView(input) + .setPositiveButton(R.string.ok) {_, _ -> + result[0] = input.text.toString() + } + .setNegativeButton(R.string.cancel) {_, _ -> } + .setOnDismissListener { + synchronized(result) { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (result as Object).notify() + } + } + .show() + } + + // The functions below are called in the SDL thread by JNI. @Suppress("unused") fun cddaStart(track: Int, loop: Boolean) = cdda.start(track, loop) @Suppress("unused") fun cddaStop() = cdda.stop() @Suppress("unused") fun cddaCurrentPosition() = cdda.currentPosition() @Suppress("unused") fun midiStart(path: String, loop: Boolean) = midi.start(path, loop) @Suppress("unused") fun midiStop() = midi.stop() @Suppress("unused") fun midiCurrentPosition() = midi.currentPosition() + + @Suppress("unused") fun inputString(oldVal: String): String? { + val result = arrayOfNulls(1) + runOnUiThread { textInputDialog(oldVal, result) } + // Block the calling thread. + synchronized(result) { + try { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (result as Object).wait() + } catch (ex: InterruptedException) { + ex.printStackTrace() + } + } + return result[0] + } } private class CddaPlayer(private val playlistPath: File) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 172d625..d2f0771 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ if (ANDROID) add_library(system3 SHARED) target_sources(system3 PRIVATE - linux/nact_linux.cpp + android/nact_android.cpp android/mako.cpp ) target_link_libraries(system3 PRIVATE SDL2 SDL2_ttf) diff --git a/src/android/jnihelper.h b/src/android/jnihelper.h new file mode 100644 index 0000000..968015b --- /dev/null +++ b/src/android/jnihelper.h @@ -0,0 +1,33 @@ +#ifndef _JNIHELPER_H_ +#define _JNIHELPER_H_ + +#include +#include "common.h" + +class JNILocalFrame { +public: + JNILocalFrame(int n) : + env_((JNIEnv*)SDL_AndroidGetJNIEnv()), + context_((jobject)SDL_AndroidGetActivity()) + { + if (env_->PushLocalFrame(n) < 0) { + ERROR("Failed to allocate JVM local references"); + env_ = NULL; + } + } + ~JNILocalFrame() { + if (env_) + env_->PopLocalFrame(NULL); + } + JNIEnv* env() { return env_; } + jobject context() { return context_; } + jmethodID GetMethodID(const char* name, const char* sig) { + return env_->GetMethodID(env_->GetObjectClass(context_), name, sig); + } + +private: + JNIEnv* env_; + jobject context_; +}; + +#endif // _JNIHELPER_H_ diff --git a/src/android/mako.cpp b/src/android/mako.cpp index bb9e6da..55d0cae 100644 --- a/src/android/mako.cpp +++ b/src/android/mako.cpp @@ -1,36 +1,10 @@ #include #include #include -#include +#include "jnihelper.h" #include "mako.h" #include "mako_midi.h" -class JNILocalFrame { -public: - JNILocalFrame(int n) : - env_((JNIEnv*)SDL_AndroidGetJNIEnv()), - context_((jobject)SDL_AndroidGetActivity()) - { - if (env_->PushLocalFrame(n) < 0) { - ERROR("Failed to allocate JVM local references"); - env_ = NULL; - } - } - ~JNILocalFrame() { - if (env_) - env_->PopLocalFrame(NULL); - } - JNIEnv* env() { return env_; } - jobject context() { return context_; } - jmethodID GetMethodID(const char* name, const char* sig) { - return env_->GetMethodID(env_->GetObjectClass(context_), name, sig); - } - -private: - JNIEnv* env_; - jobject context_; -}; - MAKO::MAKO(NACT* parent, const char* playlist) : current_music(0), next_loop(0), diff --git a/src/android/nact_android.cpp b/src/android/nact_android.cpp new file mode 100644 index 0000000..13dd68b --- /dev/null +++ b/src/android/nact_android.cpp @@ -0,0 +1,48 @@ +#include +#include "nact.h" +#include "utfsjis.h" +#include "jnihelper.h" + +#define STRING "Ljava/lang/String;" + +void NACT::text_dialog() +{ + JNILocalFrame jni(16); + if (!jni.env()) + return; + + char *oldstr = sjis2utf(tvar[tvar_index - 1]); + jstring joldstr = jni.env()->NewStringUTF(oldstr); + if (!joldstr) { + WARNING("Failed to allocate a string"); + return; + } + jmethodID mid = jni.GetMethodID("inputString", "(" STRING ")" STRING); + jstring jnewstr = (jstring)jni.env()->CallObjectMethod(jni.context(), mid, joldstr); + if (!jnewstr) + return; + const char* newstr_utf8 = jni.env()->GetStringUTFChars(jnewstr, NULL); + char* newstr_sjis = utf2sjis((char*)newstr_utf8); + strcpy_s(tvar[tvar_index - 1], 22, newstr_sjis); + free(newstr_sjis); + jni.env()->ReleaseStringUTFChars(jnewstr, newstr_utf8); +} + +void NACT::initialize_console() +{ +} + +void NACT::release_console() +{ +} + +void NACT::output_console(const char *format, ...) +{ +#if defined(_DEBUG_CONSOLE) + va_list ap; + + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); +#endif +}