diff --git a/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar b/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar index 3c0e31737..d58a61139 100644 Binary files a/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar and b/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar differ diff --git a/app_pojavlauncher/src/main/assets/components/lwjgl3/version b/app_pojavlauncher/src/main/assets/components/lwjgl3/version index 0f2502ae2..6bee63ec8 100644 --- a/app_pojavlauncher/src/main/assets/components/lwjgl3/version +++ b/app_pojavlauncher/src/main/assets/components/lwjgl3/version @@ -1 +1 @@ -1652206097040 \ No newline at end of file +1654610266310 \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java index d3b9cc876..8395cb970 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/BaseMainActivity.java @@ -37,6 +37,7 @@ import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles; import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile; import org.lwjgl.glfw.*; +import android.net.*; public class BaseMainActivity extends BaseActivity { public static volatile ClipboardManager GLOBAL_CLIPBOARD; @@ -418,4 +419,17 @@ public class BaseMainActivity extends BaseActivity { }); b.show(); } + + public static void openLink(String link) { + Context ctx = touchpad.getContext(); // no more better way to obtain a context statically + ((Activity)ctx).runOnUiThread(() -> { + try { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.parse(link.replace("file://", "content://")), "*/*"); + ctx.startActivity(intent); + } catch (Throwable th) { + Tools.showError(ctx, th); + } + }); + } } diff --git a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java index c9f5a928b..2df40f007 100644 --- a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -11,6 +11,7 @@ public class CallbackBridge { public static final int CLIPBOARD_COPY = 2000; public static final int CLIPBOARD_PASTE = 2001; + public static final int CLIPBOARD_OPEN = 2002; public static volatile int windowWidth, windowHeight; public static volatile int physicalWidth, physicalHeight; @@ -128,14 +129,17 @@ public class CallbackBridge { case CLIPBOARD_COPY: BaseMainActivity.GLOBAL_CLIPBOARD.setPrimaryClip(ClipData.newPlainText("Copy", copy)); return null; - + case CLIPBOARD_PASTE: if (BaseMainActivity.GLOBAL_CLIPBOARD.hasPrimaryClip() && BaseMainActivity.GLOBAL_CLIPBOARD.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { return BaseMainActivity.GLOBAL_CLIPBOARD.getPrimaryClip().getItemAt(0).getText().toString(); } else { return ""; } - + + case CLIPBOARD_OPEN: + BaseMainActivity.openLink(copy); + return null; default: return null; } } diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 94ac62724..d10cb9195 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -10,9 +10,12 @@ * - Implements glfwSetCursorPos() to handle grab camera pos correctly. */ -#include -#include #include +#include +#include +#include +#include +#include #include "log.h" #include "utils.h" @@ -27,6 +30,8 @@ #define EVENT_TYPE_SCROLL 1007 #define EVENT_TYPE_WINDOW_SIZE 1008 +jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream); + 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); @@ -55,6 +60,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { } else if (dalvikJavaVMPtr != vm) { runtimeJavaVMPtr = vm; (*vm)->GetEnv(vm, (void**) &runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4); + hookExec(); } isGrabbing = JNI_FALSE; @@ -72,7 +78,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { DetachCurrentThread(vm); */ - dalvikJNIEnvPtr_JRE = NULL; + //dalvikJNIEnvPtr_JRE = NULL; runtimeJNIEnvPtr_ANDROID = NULL; } @@ -148,6 +154,41 @@ void closeGLFWWindow() { exit(-1); } +/** + * Hooked version of java.lang.UNIXProcess.forkAndExec() + * which is used to handle the "open" command. + */ +jint +hooked_ProcessImpl_forkAndExec(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream) { + char *pProg = (char *)((*env)->GetByteArrayElements(env, prog, NULL)); + + // Here we only handle the "xdg-open" command + if (strcmp(basename(pProg), "xdg-open")) { + (*env)->ReleaseByteArrayElements(env, prog, (jbyte *)pProg, 0); + return orig_ProcessImpl_forkAndExec(env, process, mode, helperpath, prog, argBlock, argc, envBlock, envc, dir, std_fds, redirectErrorStream); + } + (*env)->ReleaseByteArrayElements(env, prog, (jbyte *)pProg, 0); + + Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(env, NULL, /* CLIPBOARD_OPEN */ 2002, argBlock); + return 0; +} + +void hookExec() { + jclass cls; + orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_UNIXProcess_forkAndExec"); + if (!orig_ProcessImpl_forkAndExec) { + orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_ProcessImpl_forkAndExec"); + cls = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "java/lang/ProcessImpl"); + } else { + cls = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "java/lang/UNIXProcess"); + } + JNINativeMethod methods[] = { + {"forkAndExec", "(I[B[B[BI[BI[B[IZ)I", (void *)&hooked_ProcessImpl_forkAndExec} + }; + (*runtimeJNIEnvPtr_JRE)->RegisterNatives(runtimeJNIEnvPtr_JRE, cls, methods, 1); + printf("Registered forkAndExec\n"); +} + JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetUseInputStackQueue(JNIEnv *env, jclass clazz, jboolean use_input_stack_queue) { @@ -164,10 +205,10 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeAttachThread //isUseStackQueueCall = (int) isUseStackQueueBool; if (isAndroid) { result = attachThread(true, &runtimeJNIEnvPtr_ANDROID); - } else { + } /* else { result = attachThread(false, &dalvikJNIEnvPtr_JRE); // getJavaInputBridge(&inputBridgeClass_JRE, &inputBridgeMethod_JRE); - } + } */ if (isUseStackQueueCall && isAndroid && result) { isPrepareGrabPos = true; @@ -175,7 +216,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeAttachThread return result; } -JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jstring copySrc) { +JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc) { #ifdef DEBUG LOGD("Debug: Clipboard access is going on\n", isUseStackQueueCall); #endif @@ -185,13 +226,24 @@ JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNI assert(dalvikEnv != NULL); assert(bridgeClazz != NULL); LOGD("Clipboard: Obtaining method\n"); - jmethodID bridgeMethod = (* dalvikEnv)->GetStaticMethodID(dalvikEnv, bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); + jmethodID bridgeMethod = (*dalvikEnv)->GetStaticMethodID(dalvikEnv, bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); assert(bridgeMethod != NULL); LOGD("Clipboard: Converting string\n"); - jstring copyDst = convertStringJVM(env, dalvikEnv, copySrc); + char *copySrcC = NULL; + jstring copyDst = NULL; + if (copySrc) { + copySrcC = (char *)((*env)->GetByteArrayElements(env, copySrc, NULL)); + copyDst = (*dalvikEnv)->NewStringUTF(dalvikEnv, copySrcC); + } + LOGD("Clipboard: Calling 2nd\n"); jstring pasteDst = convertStringJVM(dalvikEnv, env, (jstring) (*dalvikEnv)->CallStaticObjectMethod(dalvikEnv, bridgeClazz, bridgeMethod, action, copyDst)); + + if (copySrc) { + (*dalvikEnv)->DeleteLocalRef(dalvikEnv, copyDst); + (*env)->ReleaseByteArrayElements(env, copySrc, (jbyte *)copySrcC, 0); + } (*dalvikJavaVMPtr)->DetachCurrentThread(dalvikJavaVMPtr); return pasteDst; } @@ -368,13 +420,13 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib( return; // nothing to do yet } - jclass glfwClazz = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW"); + jclass glfwClazz = (*env)->FindClass(env, "org/lwjgl/glfw/GLFW"); assert(glfwClazz != NULL); - jmethodID glfwMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, glfwClazz, "glfwSetWindowAttrib", "(JII)V"); + jmethodID glfwMethod = (*env)->GetStaticMethodID(env, glfwClazz, "glfwSetWindowAttrib", "(JII)V"); assert(glfwMethod != NULL); - (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( - runtimeJNIEnvPtr_JRE, + (*env)->CallStaticVoidMethod( + env, glfwClazz, glfwMethod, (jlong) showingWindow, attrib, value ); @@ -384,4 +436,4 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_setClass(JNIEnv *env, jclass clazz) { inputBridgeMethod_ANDROID = (*env)->GetStaticMethodID(env, clazz, "receiveCallback", "(IIIII)V"); inputBridgeClass_ANDROID = (*env)->NewGlobalRef(env, clazz); -} \ No newline at end of file +} diff --git a/app_pojavlauncher/src/main/jni/utils.h b/app_pojavlauncher/src/main/jni/utils.h index 1bdb6c92e..5db4123b0 100644 --- a/app_pojavlauncher/src/main/jni/utils.h +++ b/app_pojavlauncher/src/main/jni/utils.h @@ -8,7 +8,7 @@ static JNIEnv* runtimeJNIEnvPtr_JRE; static JavaVM* dalvikJavaVMPtr; static JNIEnv* dalvikJNIEnvPtr_ANDROID; -static JNIEnv* dalvikJNIEnvPtr_JRE; +//static JNIEnv* dalvikJNIEnvPtr_JRE; static long showingWindow; @@ -23,4 +23,6 @@ void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charAr jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr); void closeGLFWWindow(); +void hookExec(); +JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc); diff --git a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java index a72fee84b..61a3eebb3 100644 --- a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -71,7 +71,7 @@ public class CallbackBridge { } public static native void nativeSendData(boolean isAndroid, int type, String data); public static native boolean nativeSetInputReady(boolean ready); - public static native String nativeClipboard(int action, String copy); + public static native String nativeClipboard(int action, byte[] copy); public static native void nativeAttachThreadToOther(boolean isAndroid, boolean isUseStackQueueBool); private static native void nativeSetGrabbing(boolean grab, int xset, int yset); public static native void setClass(); diff --git a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java index e751afe0b..9ef855c36 100644 --- a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java @@ -810,7 +810,7 @@ public class GLFW static boolean isGLFWReady; public static boolean glfwInit() { if (!isGLFWReady) { - CallbackBridge.nativeAttachThreadToOther(false, false); + //CallbackBridge.nativeAttachThreadToOther(false, false); mGLFWInitialTime = (double) System.nanoTime(); long __functionAddress = Functions.Init; isGLFWReady = invokeI(__functionAddress) != 0; @@ -1233,11 +1233,13 @@ public class GLFW } public static void glfwSetClipboardString(@NativeType("GLFWwindow *") long window, @NativeType("char const *") ByteBuffer string) { - glfwSetClipboardString(window, memUTF8Safe(string)); + byte[] arr = new byte[string.remaining()]; + string.get(arr); + CallbackBridge.nativeClipboard(CallbackBridge.CLIPBOARD_COPY, arr); } public static void glfwSetClipboardString(@NativeType("GLFWwindow *") long window, @NativeType("char const *") CharSequence string) { - CallbackBridge.nativeClipboard(CallbackBridge.CLIPBOARD_COPY, string.toString()); + glfwSetClipboardString(window, memUTF8Safe(string)); } public static String glfwGetClipboardString(@NativeType("GLFWwindow *") long window) {