From 0123ae62d6fc5e13d557fdfcae1dbd412bf925b6 Mon Sep 17 00:00:00 2001 From: khanhduytran0 Date: Mon, 2 Nov 2020 19:48:41 +0700 Subject: [PATCH] - Rewrite to input bridge v3 - Language switcher: fix crash on select the final item. --- .../kdt/pojavlaunch/PojavLoginActivity.java | 7 +- app/src/main/jni/Android.mk | 2 +- app/src/main/jni/input_bridge_v1.c | 107 ++++++++ .../jni/{input_bridge.c => input_bridge_v2.c} | 0 app/src/main/jni/input_bridge_v3.c | 229 ++++++------------ 5 files changed, 183 insertions(+), 162 deletions(-) create mode 100644 app/src/main/jni/input_bridge_v1.c rename app/src/main/jni/{input_bridge.c => input_bridge_v2.c} (100%) diff --git a/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java b/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java index 89bdef12d..3a9a1c10a 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java +++ b/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java @@ -234,12 +234,13 @@ public class PojavLoginActivity extends AppCompatActivity if (position == 0) { locale = Locale.getDefault(); } else { - locale = Locale.getAvailableLocales()[position + 1]; + locale = Locale.getAvailableLocales()[position - 1]; } Locale.setDefault(locale); Configuration config = new Configuration(); - config.locale = locale; - getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); + config.setLocale(locale); + // TODO replace deprecated + getResources().updateConfiguration(config, getResources().getDisplayMetrics()); } @Override diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk index 53eb458f0..fe6b6b11e 100644 --- a/app/src/main/jni/Android.mk +++ b/app/src/main/jni/Android.mk @@ -9,7 +9,7 @@ LOCAL_MODULE := pojavexec # LOCAL_CFLAGS += -DGLES_TEST LOCAL_SRC_FILES := \ egl_bridge.c \ - input_bridge.c \ + input_bridge_v3.c \ jre_launcher.c \ utils.c include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/input_bridge_v1.c b/app/src/main/jni/input_bridge_v1.c new file mode 100644 index 000000000..b50c41168 --- /dev/null +++ b/app/src/main/jni/input_bridge_v1.c @@ -0,0 +1,107 @@ +#include +#include + +#include "utils.h" + +jclass inputBridgeClass_ANDROID; +jmethodID inputBridgeMethod_ANDROID; + +jclass inputBridgeClass_JRE; +jmethodID inputBridgeMethod_JRE; + +jboolean isGrabbing; + +JavaVM* firstJavaVM; +JNIEnv* firstJNIEnv; + +JavaVM* secondJavaVM; +JNIEnv* secondJNIEnv; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + if (dalvikJavaVMPtr == NULL) { + //Save dalvik global JavaVM pointer + dalvikJavaVMPtr = vm; + (*vm)->GetEnv(vm, (void**) &dalvikJNIEnvPtr_ANDROID, JNI_VERSION_1_4); + } else if (dalvikJavaVMPtr != vm) { + runtimeJavaVMPtr = vm; + (*vm)->GetEnv(vm, (void**) &runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4); + } + + isGrabbing = JNI_FALSE; + + return JNI_VERSION_1_4; +} + +// Should be? +/* +void JNI_OnUnload(JavaVM* vm, void* reserved) { + if (dalvikJavaVMPtr == vm) { + } else { + } + + DetachCurrentThread(vm); + + return JNI_VERSION_1_4; +} +*/ + +void attachThreadIfNeed(bool* isAttached, JNIEnv** secondJNIEnvPtr) { + if (!*isAttached && secondJavaVM) { + (*secondJavaVM)->AttachCurrentThread(secondJavaVM, secondJNIEnvPtr, NULL); + *isAttached = true; + } + secondJNIEnv = *secondJNIEnvPtr; +} + +void getJavaInputBridge(jclass* clazz, jmethodID* method) { + if (*method == NULL && secondJNIEnv != NULL) { + *clazz = (*secondJNIEnv)->FindClass(secondJNIEnv, "org/lwjgl/glfw/CallbackBridge"); + assert(*clazz != NULL); + *method = (*secondJNIEnv)->GetStaticMethodID(secondJNIEnv, *clazz, "receiveCallback", "(ILjava/lang/String;)V"); + assert(*method != NULL); + } +} + +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendData(JNIEnv* env, jclass clazz, jboolean isAndroid, jint type, jstring data) { + if (isAndroid == JNI_TRUE) { + firstJavaVM = dalvikJavaVMPtr; + firstJNIEnv = dalvikJNIEnvPtr_ANDROID; + secondJavaVM = runtimeJavaVMPtr; + + attachThreadIfNeed(&isAndroidThreadAttached, &runtimeJNIEnvPtr_ANDROID); + getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); + } else { + firstJavaVM = runtimeJavaVMPtr; + firstJNIEnv = runtimeJNIEnvPtr_JRE; + secondJavaVM = dalvikJavaVMPtr; + + attachThreadIfNeed(&isRuntimeThreadAttached, &dalvikJNIEnvPtr_JRE); + getJavaInputBridge(&inputBridgeClass_JRE, &inputBridgeMethod_JRE); + } + + // printf("isAndroid=%p, isSecondJVMNull=%p\n", isAndroid, secondJavaVM == NULL); + + if (secondJavaVM != NULL) { + char *data_c = (char*)(*env)->GetStringUTFChars(env, data, 0); + // printf("data=%s\n", data_c); + jstring data_jre = (*secondJNIEnv)->NewStringUTF(secondJNIEnv, data_c); + (*env)->ReleaseStringUTFChars(env, data, data_c); + (*secondJNIEnv)->CallStaticVoidMethod( + secondJNIEnv, + isAndroid == JNI_TRUE ? inputBridgeClass_ANDROID : inputBridgeClass_JRE, + isAndroid == JNI_TRUE ? inputBridgeMethod_ANDROID : inputBridgeMethod_JRE, + type, + data_jre + ); + } + // else: too early! +} + +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing) { + isGrabbing = grabbing; +} + +JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeIsGrabbing(JNIEnv* env, jclass clazz) { + return isGrabbing; +} + diff --git a/app/src/main/jni/input_bridge.c b/app/src/main/jni/input_bridge_v2.c similarity index 100% rename from app/src/main/jni/input_bridge.c rename to app/src/main/jni/input_bridge_v2.c diff --git a/app/src/main/jni/input_bridge_v3.c b/app/src/main/jni/input_bridge_v3.c index 5d19b2d1c..fbd937b4e 100644 --- a/app/src/main/jni/input_bridge_v3.c +++ b/app/src/main/jni/input_bridge_v3.c @@ -4,6 +4,26 @@ #include "log.h" #include "utils.h" +#define EVENT_TYPE_CHAR 1000 +#define EVENT_TYPE_CHAR_MODS 1001 +#define EVENT_TYPE_CURSOR_ENTER 1002 +#define EVENT_TYPE_CURSOR_POS 1003 +#define EVENT_TYPE_FRAMEBUFFER_SIZE 1004 +#define EVENT_TYPE_KEY 1005 +#define EVENT_TYPE_MOUSE_BUTTON 1006 +#define EVENT_TYPE_SCROLL 1007 +#define EVENT_TYPE_WINDOW_SIZE 1008 + +typedef void GLFW_invoke_Char_func(void* window, unsigned int codepoint); +typedef void GLFW_invoke_CharMods_func(void* window, unsigned int codepoint, int mods); +typedef void GLFW_invoke_CursorEnter_func(void* window, int entered); +typedef void GLFW_invoke_CursorPos_func(void* window, double xpos, double ypos); +typedef void GLFW_invoke_FramebufferSize_func(void* window, int width, int height); +typedef void GLFW_invoke_Key_func(void* window, int key, int scancode, int action, int mods); +typedef void GLFW_invoke_MouseButton_func(void* window, int button, int action, int mods); +typedef void GLFW_invoke_Scroll_func(void* window, double xoffset, double yoffset); +typedef void GLFW_invoke_WindowSize_func(void* window, int width, int height); + int grabCursorX, grabCursorY, lastCursorX, lastCursorY; JavaVM* firstJavaVM; @@ -77,41 +97,22 @@ void getJavaInputBridge(jclass* clazz, jmethodID* method) { if (*method == NULL && secondJNIEnv != NULL) { *clazz = (*secondJNIEnv)->FindClass(secondJNIEnv, "org/lwjgl/glfw/CallbackBridge"); assert(*clazz != NULL); - *method = (*secondJNIEnv)->GetStaticMethodID(secondJNIEnv, *clazz, "receiveCallback", "(ILjava/lang/String;)V"); + *method = (*secondJNIEnv)->GetStaticMethodID(secondJNIEnv, *clazz, "receiveCallback", "(IIIII)V"); assert(*method != NULL); } } -void invokeCursorPos(int x, int y) { - if (isGrabbing) { - if (!isPrepareGrabPos) { - grabCursorX += x - lastCursorX; - grabCursorY += y - lastCursorY; - } else { - isPrepareGrabPos = false; - lastCursorX = x; - lastCursorY = y; - return; - } - } - if (!isUseStackQueueCall && GLFW_invoke_CursorPos) { - GLFW_invoke_CursorPos(showingWindow, (double) (isGrabbing ? grabCursorX : x), (double) (isGrabbing ? grabCursorY : y)); - } - lastCursorX = x; - lastCursorY = y; -} - -void addInputToQueue(GLFWInputEvent event) { - if (glfwInputEventIndex++ >= 100) { - // player type too fast? or fps lower than player tps? - glfwInputEventIndex = 0; - } - glfwInputEventArr[glfwInputEventIndex] = &event; +void sendData(int type, int i1, int i2, int i3, int i4) { + (*secondJNIEnv)->CallStaticVoidMethod( + secondJNIEnv, + inputBridgeClass_ANDROID, + inputBridgeMethod_ANDROID, + type, + i1, i2, i3, i4 + ); } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeAttachThreadToOther(JNIEnv* env, jclass clazz, jboolean isAndroid, jboolean isUseStackQueue) { - glfwInputEventIndex = -1; - // isUseStackQueueCall = 1; isUseStackQueueCall = (int) isUseStackQueue; if (isUseStackQueue) { isPrepareGrabPos = true; @@ -124,14 +125,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeAttachThreadToOt getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); isPrepareGrabPos = true; - } else { + } /* else { firstJavaVM = runtimeJavaVMPtr; firstJNIEnv = runtimeJNIEnvPtr_JRE; secondJavaVM = dalvikJavaVMPtr; attachThreadIfNeed(&isRuntimeThreadAttached, &dalvikJNIEnvPtr_JRE); getJavaInputBridge(&inputBridgeClass_JRE, &inputBridgeMethod_JRE); - } + } */ } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing) { @@ -142,93 +143,10 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeIsGrabbing(J return isGrabbing; } -int diffX, diffY, diffGrabX, diffGrabY, debugTimes; -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwPollEvents(JNIEnv* env, jclass clazz) { - if (!isInputReady) isInputReady = true; -/* - if (debugTimes < 1000) { - debugTimes++; - LOGI("INPUT: IsUseStackQueue=%d, CurrentInputLength=%d, CursorX=%d, CursorY=%d", isUseStackQueueCall, glfwInputEventIndex, lastCursorX, lastCursorY); - } -*/ - if (isUseStackQueueCall) { - if (diffX != lastCursorX || diffY != lastCursorY) { - diffX = lastCursorX; - diffY = lastCursorY; - - if (GLFW_invoke_CursorPos) { - GLFW_invoke_CursorPos(showingWindow, - isGrabbing ? grabCursorX : lastCursorX, - isGrabbing ? grabCursorY : lastCursorY); - } - } - - for (int i = 0; i <= glfwInputEventIndex; i++) { - GLFWInputEvent curr = *glfwInputEventArr[i]; - ((GLFW_invoke_callback*) curr.trigger)(curr); - -// if (debugTimes < 1000) { -// LOGI("INPUT: Got input event %d", curr.type); -// } -/* - switch (curr.type) { - case EVENT_TYPE_CHAR: - if (GLFW_invoke_Char) { - GLFW_invoke_Char(showingWindow, curr.ui1); - } - break; - case EVENT_TYPE_CHAR_MODS: - if (GLFW_invoke_CharMods) { - GLFW_invoke_CharMods(showingWindow, curr.ui1, curr.i2); - } - break; - case EVENT_TYPE_CURSOR_ENTER: - if (GLFW_invoke_CursorEnter) { - GLFW_invoke_CursorEnter(showingWindow, curr.i1); - } - break; - case EVENT_TYPE_FRAMEBUFFER_SIZE: - if (GLFW_invoke_FramebufferSize) { - GLFW_invoke_FramebufferSize(showingWindow, curr.i1, curr.i2); - } - break; - case EVENT_TYPE_KEY: - if (GLFW_invoke_Key) { - GLFW_invoke_Key(showingWindow, curr.i1, curr.i2, curr.i3, curr.i4); - } - break; - case EVENT_TYPE_MOUSE_BUTTON: - if (GLFW_invoke_MouseButton) { - GLFW_invoke_MouseButton(showingWindow, curr.i1, curr.i2, curr.i3); - } - break; - case EVENT_TYPE_SCROLL: - if (GLFW_invoke_Scroll) { - GLFW_invoke_Scroll(showingWindow, curr.d1, curr.d2); - } - break; - case EVENT_TYPE_WINDOW_SIZE: - if (GLFW_invoke_WindowSize) { - GLFW_invoke_WindowSize(showingWindow, curr.i1, curr.i2); - } - break; - default: - LOGW("Unknown GLFW input event: %d", curr.type); - break; - } -*/ - } - glfwInputEventIndex = -1; - } -} - JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNIEnv* env, jclass clazz, jint codepoint) { if (GLFW_invoke_Char && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerChar; - curr.ui1 = (unsigned int) codepoint; - addInputToQueue(curr); + sendData(EVENT_TYPE_CHAR, codepoint, 0, 0, 0); } else GLFW_invoke_Char(showingWindow, codepoint); return JNI_TRUE; @@ -239,11 +157,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNI JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(JNIEnv* env, jclass clazz, jint codepoint, jint mods) { if (GLFW_invoke_CharMods && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerCharMods; - curr.ui1 = (unsigned int) codepoint; - curr.i2 = mods; - addInputToQueue(curr); + sendData(EVENT_TYPE_CHAR_MODS, codepoint, mods, 0, 0); } else GLFW_invoke_CharMods(showingWindow, codepoint, mods); return JNI_TRUE; @@ -263,12 +177,10 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JN if (GLFW_invoke_CursorEnter) { isCursorEntered = true; if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerCursorEnter; - curr.i1 = 1; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_CURSOR_ENTER, 1, 0, 0, 0); + } else { GLFW_invoke_CursorEnter(showingWindow, 1); + } } else if (isGrabbing) { // Some Minecraft versions does not use GLFWCursorEnterCallback // This is a smart check, as Minecraft will not in grab mode if already not. @@ -276,35 +188,46 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JN } } - invokeCursorPos(x, y); + if (isGrabbing) { + if (!isPrepareGrabPos) { + grabCursorX += x - lastCursorX; + grabCursorY += y - lastCursorY; + } else { + isPrepareGrabPos = false; + lastCursorX = x; + lastCursorY = y; + return; + } + } + + if (!isUseStackQueueCall) { + GLFW_invoke_CursorPos(showingWindow, (double) (isGrabbing ? grabCursorX : x), (double) (isGrabbing ? grabCursorY : y)); + } else { + sendData(EVENT_TYPE_CURSOR_POS, (isGrabbing ? grabCursorX : x), (isGrabbing ? grabCursorY : y), 0, 0); + } + + lastCursorX = x; + lastCursorY = y; } } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendFramebufferSize(JNIEnv* env, jclass clazz, jint width, jint height) { if (GLFW_invoke_FramebufferSize && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerFramebufferSize; - curr.i1 = width; - curr.i2 = height; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_FRAMEBUFFER_SIZE, width, height, 0, 0); + } else { GLFW_invoke_FramebufferSize(showingWindow, width, height); + } } } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* env, jclass clazz, jint key, jint scancode, jint action, jint mods) { if (GLFW_invoke_Key && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerKey; - curr.i1 = key; - curr.i2 = scancode; - curr.i3 = action; - curr.i4 = mods; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_KEY, key, scancode, action, mods); + } else { GLFW_invoke_Key(showingWindow, key, scancode, action, mods); + } } } @@ -315,14 +238,10 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton( isPrepareGrabPos = true; } else if (GLFW_invoke_MouseButton) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerMouseButton; - curr.i1 = button; - curr.i2 = action; - curr.i3 = mods; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_MOUSE_BUTTON, button, action, mods, 0); + } else { GLFW_invoke_MouseButton(showingWindow, button, action, mods); + } } } } @@ -330,26 +249,20 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton( JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEnv* env, jclass clazz, jdouble xoffset, jdouble yoffset) { if (GLFW_invoke_Scroll && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerScroll; - curr.d1 = (double) xoffset; - curr.d2 = (double) yoffset; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_SCROLL, xoffset, yoffset, 0, 0); + } else { GLFW_invoke_Scroll(showingWindow, (double) xoffset, (double) yoffset); + } } } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendWindowSize(JNIEnv* env, jclass clazz, jint width, jint height) { if (GLFW_invoke_WindowSize && isInputReady) { if (isUseStackQueueCall) { - GLFWInputEvent curr; - curr.trigger = triggerWindowSize; - curr.i1 = width; - curr.i2 = height; - addInputToQueue(curr); - } else + sendData(EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0); + } else { GLFW_invoke_WindowSize(showingWindow, width, height); + } } }