|
|
|
|
@@ -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,8 +667,16 @@ 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);
|
|
|
|
|
App::I.key_down(convert_key(key_val));
|
|
|
|
|
@@ -514,6 +684,8 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
|
|
|
|
|
case AKEY_EVENT_ACTION_UP:
|
|
|
|
|
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;
|
|
|
|
|
|