android: fix directory listing, keyboard show/hide and read chars
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user