android: fix directory listing, keyboard show/hide and read chars

This commit is contained in:
2017-08-20 00:51:59 +01:00
parent a2b888efd6
commit 81a5fb10e3
6 changed files with 218 additions and 14 deletions

View File

@@ -24,7 +24,9 @@ add_library(
../libs/yoga/yoga/YGNodeList.c
../libs/yoga/yoga/Yoga.c
../libs/tinyxml2/tinyxml2.cpp
src/main/cpp/main.cpp
../libs/jpeg/jpgd.cpp
../libs/jpeg/jpge.cpp
src/main/cpp/main.cpp
../engine/pch.cpp
../engine/util.cpp
../engine/rtt.cpp
@@ -36,6 +38,7 @@ add_library(
../engine/shader.cpp
../engine/shape.cpp
../engine/app.cpp
../engine/app_dialogs.cpp
../engine/app_events.cpp
../engine/app_layout.cpp
../engine/app_shaders.cpp
@@ -53,6 +56,7 @@ add_library(
../engine/node_checkbox.cpp
../engine/node_color_quad.cpp
../engine/node_dialog_open.cpp
../engine/node_dialog_layer_rename.cpp
../engine/node_icon.cpp
../engine/node_image.cpp
../engine/node_image_texture.cpp
@@ -78,6 +82,7 @@ target_include_directories(native-lib PRIVATE
../libs/tinyxml2
../libs/yoga
../libs/stb
../libs/jpeg
../libs/curl-android-ios/prebuilt-with-ssl/android/include
)

View File

@@ -75,6 +75,157 @@ struct engine {
struct saved_state state;
};
std::string utf8chr(int cp)
{
char c[5]={ 0x00,0x00,0x00,0x00,0x00 };
if (cp<=0x7F) { c[0] = cp; }
else if(cp<=0x7FF) { c[0] = (cp>>6)+192; c[1] = (cp&63)+128; }
else if(0xd800<=cp && cp<=0xdfff) {} //invalid block of utf8
else if(cp<=0xFFFF) { c[0] = (cp>>12)+224; c[1]= ((cp>>6)&63)+128; c[2]=(cp&63)+128; }
else if(cp<=0x10FFFF) { c[0] = (cp>>18)+240; c[1] = ((cp>>12)&63)+128; c[2] = ((cp>>6)&63)+128; c[3]=(cp&63)+128; }
return std::string(c);
}
// see https://stackoverflow.com/questions/21124051/receive-complete-android-unicode-input-in-c-c
// see http://www.zedwood.com/article/cpp-utf8-char-to-codepoint
int GetUnicodeChar(struct android_app* app, int eventType, int keyCode, int metaState)
{
#define COMBINING_ACCENT 0x80000000
#define COMBINING_ACCENT_MASK 0x7fffffff
JavaVM* javaVM = app->activity->vm;
JNIEnv* jniEnv = app->activity->env;
JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_6;
attachArgs.name = "NativeThread";
attachArgs.group = NULL;
jint result = javaVM->AttachCurrentThread(&jniEnv, &attachArgs);
if(result == JNI_ERR)
{
return 0;
}
jclass class_key_event = jniEnv->FindClass("android/view/KeyEvent");
int unicodeKey;
if(metaState == 0)
{
jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "()I");
jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);
unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char);
}
else
{
jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, "getUnicodeChar", "(I)I");
jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(II)V");
jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, eventType, keyCode);
unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char, metaState);
}
if ((unicodeKey & COMBINING_ACCENT) != 0)
{
unicodeKey = unicodeKey & COMBINING_ACCENT_MASK;
}
javaVM->DetachCurrentThread();
LOG("Unicode key is: %d", unicodeKey);
return unicodeKey;
}
// see https://groups.google.com/forum/#!topic/android-ndk/Tk3g00wLKhk
void displayKeyboard(android_app* mApplication, bool pShow)
{
// Attaches the current thread to the JVM.
jint lResult;
jint lFlags = 0;
JavaVM* lJavaVM = mApplication->activity->vm;
JNIEnv* lJNIEnv = mApplication->activity->env;
JavaVMAttachArgs lJavaVMAttachArgs;
lJavaVMAttachArgs.version = JNI_VERSION_1_6;
lJavaVMAttachArgs.name = "NativeThread";
lJavaVMAttachArgs.group = NULL;
lResult=lJavaVM->AttachCurrentThread(&lJNIEnv,
&lJavaVMAttachArgs);
if (lResult == JNI_ERR) {
return;
}
// Retrieves NativeActivity.
jobject lNativeActivity = mApplication->activity->clazz;
jclass ClassNativeActivity = lJNIEnv->GetObjectClass(lNativeActivity);
// Retrieves Context.INPUT_METHOD_SERVICE.
jclass ClassContext = lJNIEnv->FindClass("android/content/Context");
jfieldID FieldINPUT_METHOD_SERVICE =
lJNIEnv->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
jobject INPUT_METHOD_SERVICE =
lJNIEnv->GetStaticObjectField(ClassContext,
FieldINPUT_METHOD_SERVICE);
//jniCheck(INPUT_METHOD_SERVICE);
// Runs getSystemService(Context.INPUT_METHOD_SERVICE).
jclass ClassInputMethodManager = lJNIEnv->FindClass(
"android/view/inputmethod/InputMethodManager");
jmethodID MethodGetSystemService = lJNIEnv->GetMethodID(
ClassNativeActivity, "getSystemService",
"(Ljava/lang/String;)Ljava/lang/Object;");
jobject lInputMethodManager = lJNIEnv->CallObjectMethod(
lNativeActivity, MethodGetSystemService,
INPUT_METHOD_SERVICE);
// Runs getWindow().getDecorView().
jmethodID MethodGetWindow = lJNIEnv->GetMethodID(
ClassNativeActivity, "getWindow",
"()Landroid/view/Window;");
jobject lWindow = lJNIEnv->CallObjectMethod(lNativeActivity,
MethodGetWindow);
jclass ClassWindow = lJNIEnv->FindClass(
"android/view/Window");
jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(
ClassWindow, "getDecorView", "()Landroid/view/View;");
jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow,
MethodGetDecorView);
if (pShow) {
// Runs lInputMethodManager.showSoftInput(...).
jmethodID MethodShowSoftInput = lJNIEnv->GetMethodID(
ClassInputMethodManager, "showSoftInput",
"(Landroid/view/View;I)Z");
jboolean lResult = lJNIEnv->CallBooleanMethod(
lInputMethodManager, MethodShowSoftInput,
lDecorView, lFlags);
} else {
// Runs lWindow.getViewToken()
jclass ClassView = lJNIEnv->FindClass(
"android/view/View");
jmethodID MethodGetWindowToken = lJNIEnv->GetMethodID(
ClassView, "getWindowToken", "()Landroid/os/IBinder;");
jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
MethodGetWindowToken);
// lInputMethodManager.hideSoftInput(...).
jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(
ClassInputMethodManager, "hideSoftInputFromWindow",
"(Landroid/os/IBinder;I)Z");
jboolean lRes = lJNIEnv->CallBooleanMethod(
lInputMethodManager, MethodHideSoftInput,
lBinder, lFlags);
}
// Finished with the JVM.
lJavaVM->DetachCurrentThread();
}
/**
* Initialize an EGL context for the current display.
*/
@@ -313,14 +464,15 @@ static int engine_init_display(struct engine* engine) {
glDisable(GL_DEPTH_TEST);
//glEnableClientState(GL_VERTEX_ARRAY);
Asset::m_am = engine->app->activity->assetManager;
App::I.and_app = engine->app;
App::I.data_path = "/sdcard/PanoPainter";// engine->app->activity->externalDataPath;
App::I.width = w;
App::I.height = h;
App::I.redraw = true;
App::I.init();
LOG("All ready");
engine->animating = 1;
ANativeActivity_showSoftInput(engine->app->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED);
return 0;
}
@@ -329,13 +481,10 @@ static int engine_init_display(struct engine* engine) {
* Just the current frame in the display.
*/
static void engine_draw_frame(struct engine* engine) {
if (engine->display == NULL)
if (engine->display == NULL || !(App::I.redraw || App::I.animate))
return;
glClearColor(.1f, .1f, .1f, 1.f);
glViewport(0, 0, (GLsizei)engine->width, (GLsizei)engine->height);
glClear(GL_COLOR_BUFFER_BIT);
App::I.clear();
App::I.update(0);
eglSwapBuffers(engine->display, engine->surface);
@@ -367,6 +516,7 @@ static void engine_term_display(struct engine* engine) {
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
struct engine* engine = (struct engine*)app->userData;
int32_t eventType = AInputEvent_getType(event);
App::I.redraw = true;
//LOG("event type: %d", eventType);
switch (eventType) {
case AINPUT_EVENT_TYPE_MOTION:
@@ -411,7 +561,11 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
p0.id = AMotionEvent_getPointerId(event, 0);
p0.pos = {x, y};
p0.idx = index;
App::I.mouse_down(0, x, y);
int tool_type = AMotionEvent_getToolType(event, index);
float pressure = AMotionEvent_getPressure(event, 0);
kEventSource source = tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS ?
kEventSource::Stylus : kEventSource::Touch;
App::I.mouse_down(0, x, y, pressure, source);
tracked = 1;
//LOG("first down");
return 1;
@@ -442,8 +596,12 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
float x = AMotionEvent_getX(event, 0);
p0.id = -1;
p1.id = -1;
int tool_type = AMotionEvent_getToolType(event, index);
float pressure = AMotionEvent_getPressure(event, 0);
kEventSource source = tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS ?
kEventSource::Stylus : kEventSource::Touch;
if (tracked == 1)
App::I.mouse_up(0, x, y);
App::I.mouse_up(0, x, y, source);
tracked = 0;
//LOG("first up");
return 1;
@@ -460,7 +618,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
{
float y = AMotionEvent_getY(event, 0);
float x = AMotionEvent_getX(event, 0);
App::I.mouse_move(x, y);
App::I.mouse_move(x, y, 0, kEventSource::Stylus);
//LOG("single move");
return 1;
}
@@ -469,7 +627,11 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
{
float y = AMotionEvent_getY(event, 0);
float x = AMotionEvent_getX(event, 0);
App::I.mouse_move(x, y);
int tool_type = AMotionEvent_getToolType(event, index);
float pressure = AMotionEvent_getPressure(event, 0);
kEventSource source = tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS ?
kEventSource::Stylus : kEventSource::Touch;
App::I.mouse_move(x, y, pressure, source);
//LOG("single move");
}
else if (count == 2)
@@ -505,15 +667,25 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
{
int action = AKeyEvent_getAction(event);
int32_t key_val = AKeyEvent_getKeyCode(event);
int key = AKeyEvent_getKeyCode(event);
int metaState = AKeyEvent_getMetaState(event);
int uniValue = GetUnicodeChar(app, action, key, metaState);
switch (action)
{
case AKEY_EVENT_ACTION_MULTIPLE:
LOG("Received key multi event: %d\n", key_val);
if (uniValue > 32 && uniValue < 127) //printable ascii range
App::I.key_char(uniValue);
break;
case AKEY_EVENT_ACTION_DOWN:
LOG("Received key down event: %d\n", key_val);
LOG("Received key down event: %d\n", key_val);
App::I.key_down(convert_key(key_val));
break;
case AKEY_EVENT_ACTION_UP:
LOG("Received key up event: %d\n", key_val);
LOG("Received key up event: %d\n", key_val);
App::I.key_up(convert_key(key_val));
if (uniValue > 32 && uniValue < 127) //printable ascii range
App::I.key_char(uniValue);
break;
}
return 1;

View File

@@ -66,6 +66,9 @@ public:
#if defined(__IOS__) && defined(__OBJC__)
GameViewController* ios_view;
#endif
#ifdef __ANDROID__
struct android_app* and_app;
#endif
void showKeyboard();
void hideKeyboard();

View File

@@ -1,6 +1,11 @@
#include "pch.h"
#include "app.h"
#ifdef __ANDROID__
void displayKeyboard(android_app* mApplication, bool pShow);
#endif
using namespace ui;
void App::resize(float w, float h)
@@ -14,17 +19,23 @@ void App::resize(float w, float h)
void App::showKeyboard()
{
LOG("show keyboard");
redraw = true;
#ifdef __IOS__
[ios_view becomeFirstResponder];
#elif __ANDROID__
displayKeyboard(and_app, true);
#endif
}
void App::hideKeyboard()
{
LOG("hide keyboard");
redraw = true;
#ifdef __IOS__
[ios_view resignFirstResponder];
#elif __ANDROID__
displayKeyboard(and_app, false);
#endif
}

View File

@@ -7,6 +7,7 @@
#endif
#ifdef __ANDROID__
#include <dirent.h>
AAssetManager* Asset::m_am;
#endif
@@ -49,7 +50,19 @@ std::vector<std::string> Asset::list_files(std::string folder, bool is_asset, co
}
else
{
DIR *dp;
struct dirent *ep;
dp = opendir(folder.c_str());
if (dp != NULL)
{
while ((ep = readdir(dp)))
if (ep->d_type != DT_DIR)
names.push_back(ep->d_name);
closedir(dp);
}
else
LOG("Couldn't open the directory: %s", folder.c_str());
}
#else
std::string abs_path = folder;

View File

@@ -44,7 +44,7 @@ void NodePanelBrush::init()
{
init_template("tpl-panel-brushes");
//m_layers_container = find<NodeBorder>("layers-container");
static auto icons = Asset::list_files("data/Icons/", true, ".*\\.png$");
static auto icons = Asset::list_files("data/Icons", true, ".*\\.png$");
if ((m_container = find<NodeBorder>("brushes")))
{