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 beb1da2cb..9a3f74a59 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 f476a7b5a..f24b1ea4c 100644 --- a/app_pojavlauncher/src/main/assets/components/lwjgl3/version +++ b/app_pojavlauncher/src/main/assets/components/lwjgl3/version @@ -1 +1 @@ -1735293224932 \ No newline at end of file +1735328970475 \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java index 415d13f26..b63ffcd4f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java @@ -30,6 +30,7 @@ import net.kdt.pojavlaunch.customcontrols.ControlLayout; import net.kdt.pojavlaunch.customcontrols.gamepad.DefaultDataProvider; import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad; import net.kdt.pojavlaunch.customcontrols.gamepad.direct.DirectGamepad; +import net.kdt.pojavlaunch.customcontrols.gamepad.direct.DirectGamepadEnableHandler; import net.kdt.pojavlaunch.customcontrols.mouse.AbstractTouchpad; import net.kdt.pojavlaunch.customcontrols.mouse.AndroidPointerCapture; import net.kdt.pojavlaunch.customcontrols.mouse.InGUIEventProcessor; @@ -48,7 +49,7 @@ import fr.spse.gamepad_remapper.RemapperView; /** * Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft */ -public class MinecraftGLSurface extends View implements GrabListener { +public class MinecraftGLSurface extends View implements GrabListener, DirectGamepadEnableHandler { /* Gamepad object for gamepad inputs, instantiated on need */ private GamepadHandler mGamepadHandler; /* The RemapperView.Builder object allows you to set which buttons to remap */ @@ -90,6 +91,7 @@ public class MinecraftGLSurface extends View implements GrabListener { public MinecraftGLSurface(Context context, AttributeSet attributeSet) { super(context, attributeSet); setFocusable(true); + CallbackBridge.setDirectGamepadEnableHandler(this); } @RequiresApi(api = Build.VERSION_CODES.O) @@ -205,7 +207,7 @@ public class MinecraftGLSurface extends View implements GrabListener { } private void createGamepad(View contextView, InputDevice inputDevice) { - if(LauncherPreferences.PREF_DIRECT_CONTROLLER) { + if(CallbackBridge.sGamepadDirectInput) { mGamepadHandler = new DirectGamepad(); }else { mGamepadHandler = new Gamepad(contextView, inputDevice, DefaultDataProvider.INSTANCE, true); @@ -411,6 +413,17 @@ public class MinecraftGLSurface extends View implements GrabListener { } } + @Override + public void onDirectGamepadEnabled() { + post(()->{ + if(mGamepadHandler != null && mGamepadHandler instanceof Gamepad) { + ((Gamepad)mGamepadHandler).removeSelf(); + } + // Force gamepad recreation on next event + mGamepadHandler = null; + }); + } + /** A small interface called when the listener is ready for the first time */ public interface SurfaceReadyListener { void isReady(); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/DefaultDataProvider.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/DefaultDataProvider.java index f16c97115..50fcb4a60 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/DefaultDataProvider.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/DefaultDataProvider.java @@ -30,4 +30,9 @@ public class DefaultDataProvider implements GamepadDataProvider { public void attachGrabListener(GrabListener grabListener) { CallbackBridge.addGrabListener(grabListener); } + + @Override + public void detachGrabListener(GrabListener grabListener) { + CallbackBridge.removeGrabListener(grabListener); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java index 03466a3e7..f84cef74b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java @@ -87,6 +87,8 @@ public class Gamepad implements GrabListener, GamepadHandler { private final GamepadDataProvider mMapProvider; + private boolean mRemoved = false; + public Gamepad(View contextView, InputDevice inputDevice, GamepadDataProvider mapProvider, boolean showCursor){ Settings.setDeadzoneScale(PREF_DEADZONE_SCALE); @@ -95,7 +97,7 @@ public class Gamepad implements GrabListener, GamepadHandler { @Override public void doFrame(long frameTimeNanos) { tick(frameTimeNanos); - mScreenChoreographer.postFrameCallback(this); + if(!mRemoved) mScreenChoreographer.postFrameCallback(this); } }; mScreenChoreographer.postFrameCallback(frameCallback); @@ -452,4 +454,10 @@ public class Gamepad implements GrabListener, GamepadHandler { break; } } + public void removeSelf() { + mRemoved = true; + mMapProvider.detachGrabListener(this); + ViewGroup viewGroup = (ViewGroup) mPointerImageView.getParent(); + if(viewGroup != null) viewGroup.removeView(mPointerImageView); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDataProvider.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDataProvider.java index 37dcbaab5..0b79db086 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDataProvider.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDataProvider.java @@ -7,4 +7,5 @@ public interface GamepadDataProvider { GamepadMap getGameMap(); boolean isGrabbing(); void attachGrabListener(GrabListener grabListener); + void detachGrabListener(GrabListener grabListener); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMapperAdapter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMapperAdapter.java index 487440ffc..bdcd4741b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMapperAdapter.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadMapperAdapter.java @@ -325,6 +325,11 @@ public class GamepadMapperAdapter extends RecyclerView.Adapter grabListeners = new ArrayList<>(); + private static WeakReference sDirectGamepadEnableHandler; public static final int CLIPBOARD_COPY = 2000; public static final int CLIPBOARD_PASTE = 2001; @@ -32,6 +36,7 @@ public class CallbackBridge { public static final ByteBuffer sGamepadButtonBuffer; public static final FloatBuffer sGamepadAxisBuffer; + public static boolean sGamepadDirectInput = false; public static void putMouseEventWithCoords(int button, float x, float y) { putMouseEventWithCoords(button, true, x, y); @@ -171,6 +176,16 @@ public class CallbackBridge { } } + //Called from JRE side + @SuppressWarnings("unused") + @Keep + private static void onDirectInputEnable() { + Log.i("CallbackBridge", "onDirectInputEnable()"); + DirectGamepadEnableHandler enableHandler = Tools.getWeakReference(sDirectGamepadEnableHandler); + if(enableHandler != null) enableHandler.onDirectGamepadEnabled(); + sGamepadDirectInput = true; + } + //Called from JRE side @SuppressWarnings("unused") @Keep @@ -199,12 +214,17 @@ public class CallbackBridge { grabListeners.remove(listener); } } + public static FloatBuffer createGamepadAxisBuffer() { ByteBuffer axisByteBuffer = nativeCreateGamepadAxisBuffer(); // NOTE: hardcoded order (also in jre_lwjgl3glfw CallbackBridge) return axisByteBuffer.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer(); } + public static void setDirectGamepadEnableHandler(DirectGamepadEnableHandler h) { + sDirectGamepadEnableHandler = new WeakReference<>(h); + } + @Keep @CriticalNative public static native void nativeSetUseInputStackQueue(boolean useInputStackQueue); @Keep @CriticalNative private static native boolean nativeSendChar(char codepoint); diff --git a/app_pojavlauncher/src/main/jni/environ/environ.h b/app_pojavlauncher/src/main/jni/environ/environ.h index 62ec4a45d..11c4e4333 100644 --- a/app_pojavlauncher/src/main/jni/environ/environ.h +++ b/app_pojavlauncher/src/main/jni/environ/environ.h @@ -47,6 +47,7 @@ struct pojav_environ_s { double cursorX, cursorY, cLastX, cLastY; jmethodID method_accessAndroidClipboard; jmethodID method_onGrabStateChanged; + jmethodID method_onDirectInputEnable; jmethodID method_glftSetWindowAttrib; jmethodID method_internalWindowSizeChanged; jmethodID method_internalChangeMonitorSize; diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 3bfac1f07..ddabcfc34 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -9,7 +9,7 @@ * * - Implements glfwSetCursorPos() to handle grab camera pos correctly. */ - + #include #include #include @@ -30,6 +30,29 @@ #define EVENT_TYPE_MOUSE_BUTTON 1006 #define EVENT_TYPE_SCROLL 1007 +static jint attach_env(JNIEnv ** pEnv, JavaVM *jvm) { + JNIEnv *jvm_env = NULL; + jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); + if(env_result == JNI_EDETACHED) { + env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); + } + if(env_result != JNI_OK) { + return env_result; + } + *pEnv = jvm_env; + return JNI_OK; +} + +#define TRY_ATTACH_ENV(env_name, vm, error_message, then) JNIEnv* env_name;\ +do { \ + jint result = attach_env(&env_name, vm); \ + if(result != JNI_OK) { \ + printf(error_message, result); \ + then\ + } \ +} while(0) + + 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); static void registerFunctions(JNIEnv *env); @@ -44,6 +67,7 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { pojav_environ->bridgeClazz = (*env)->NewGlobalRef(env,(*env) ->FindClass(env,"org/lwjgl/glfw/CallbackBridge")); pojav_environ->method_accessAndroidClipboard = (*env)->GetStaticMethodID(env, pojav_environ->bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); pojav_environ->method_onGrabStateChanged = (*env)->GetStaticMethodID(env, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V"); + pojav_environ->method_onDirectInputEnable = (*env)->GetStaticMethodID(env, pojav_environ->bridgeClazz, "onDirectInputEnable", "()V"); pojav_environ->isUseStackQueueCall = JNI_FALSE; } else if (pojav_environ->dalvikJavaVMPtr != vm) { __android_log_print(ANDROID_LOG_INFO, "Native", "Saving JVM environ..."); @@ -71,7 +95,7 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { registerFunctions(env); } pojav_environ->isGrabbing = JNI_FALSE; - + return JNI_VERSION_1_4; } @@ -361,7 +385,7 @@ JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNI (*pojav_environ->dalvikJavaVMPtr)->AttachCurrentThread(pojav_environ->dalvikJavaVMPtr, &dalvikEnv, NULL); assert(dalvikEnv != NULL); assert(pojav_environ->bridgeClazz != NULL); - + LOGD("Clipboard: Converting string\n"); char *copySrcC; jstring copyDst = NULL; @@ -374,7 +398,7 @@ JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNI jstring pasteDst = convertStringJVM(dalvikEnv, env, (jstring) (*dalvikEnv)->CallStaticObjectMethod(dalvikEnv, pojav_environ->bridgeClazz, pojav_environ->method_accessAndroidClipboard, action, copyDst)); if (copySrc) { - (*dalvikEnv)->DeleteLocalRef(dalvikEnv, copyDst); + (*dalvikEnv)->DeleteLocalRef(dalvikEnv, copyDst); (*env)->ReleaseByteArrayElements(env, copySrc, (jbyte *)copySrcC, 0); } (*pojav_environ->dalvikJavaVMPtr)->DetachCurrentThread(pojav_environ->dalvikJavaVMPtr); @@ -395,13 +419,18 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetInputRead } JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jboolean grabbing) { - JNIEnv *dalvikEnv; - (*pojav_environ->dalvikJavaVMPtr)->AttachCurrentThread(pojav_environ->dalvikJavaVMPtr, &dalvikEnv, NULL); - (*dalvikEnv)->CallStaticVoidMethod(dalvikEnv, pojav_environ->bridgeClazz, pojav_environ->method_onGrabStateChanged, grabbing); - (*pojav_environ->dalvikJavaVMPtr)->DetachCurrentThread(pojav_environ->dalvikJavaVMPtr); + TRY_ATTACH_ENV(dvm_env, pojav_environ->dalvikJavaVMPtr, "nativeSetGrabbing failed: %i", return;); + (*dvm_env)->CallStaticVoidMethod(dvm_env, pojav_environ->bridgeClazz, pojav_environ->method_onGrabStateChanged, grabbing); pojav_environ->isGrabbing = grabbing; } +JNIEXPORT jboolean JNICALL +Java_org_lwjgl_glfw_CallbackBridge_nativeEnableGamepadDirectInput(__attribute__((unused)) JNIEnv *env, __attribute__((unused)) jclass clazz) { + TRY_ATTACH_ENV(dvm_env, pojav_environ->dalvikJavaVMPtr, "nativeEnableGamepadDirectInput failed: %i", return JNI_FALSE;); + (*dvm_env)->CallStaticVoidMethod(dvm_env, pojav_environ->bridgeClazz, pojav_environ->method_onDirectInputEnable); + return JNI_TRUE; +} + jboolean critical_send_char(jchar codepoint) { if (pojav_environ->GLFW_invoke_Char && pojav_environ->isInputReady) { if (pojav_environ->isUseStackQueueCall) { @@ -561,16 +590,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib( // in environ for the Android UI thread but this is the only place that uses it // (very rarely, only in lifecycle callbacks) so i dont care - JavaVM* jvm = pojav_environ->runtimeJavaVMPtr; - JNIEnv *jvm_env = NULL; - jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); - if(env_result == JNI_EDETACHED) { - env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); - } - if(env_result != JNI_OK) { - printf("input_bridge nativeSetWindowAttrib() JNI call failed: %i\n", env_result); - return; - } + TRY_ATTACH_ENV(jvm_env, pojav_environ->runtimeJavaVMPtr, "nativeSetWindowAttrib failed: %i", return;); (*jvm_env)->CallStaticVoidMethod( jvm_env, pojav_environ->vmGlfwClass, diff --git a/app_pojavlauncher/src/main/res/xml/pref_control.xml b/app_pojavlauncher/src/main/res/xml/pref_control.xml index cd0093bce..0d2778e17 100644 --- a/app_pojavlauncher/src/main/res/xml/pref_control.xml +++ b/app_pojavlauncher/src/main/res/xml/pref_control.xml @@ -144,13 +144,7 @@ - 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 17d25e203..88263d02c 100644 --- a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -19,6 +19,8 @@ public class CallbackBridge { public static final int ANDROID_TYPE_GRAB_STATE = 0; public static final boolean INPUT_DEBUG_ENABLED; + + public static boolean sGamepadDirectEnabled; // TODO send grab state event to Android @@ -41,6 +43,11 @@ public class CallbackBridge { } + public static void enableGamepadDirectInput() { + if(sGamepadDirectEnabled) return; + sGamepadDirectEnabled = nativeEnableGamepadDirectInput(); + } + public static void sendData(int type, String data) { nativeSendData(false, type, data); } @@ -50,5 +57,6 @@ public class CallbackBridge { public static native void nativeSetGrabbing(boolean grab); public static native ByteBuffer nativeCreateGamepadButtonBuffer(); public static native ByteBuffer nativeCreateGamepadAxisBuffer(); + private static native boolean nativeEnableGamepadDirectInput(); } 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 b878cb149..46646b804 100644 --- a/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/jre_lwjgl3glfw/src/main/java/org/lwjgl/glfw/GLFW.java @@ -1211,6 +1211,7 @@ public class GLFW public static boolean glfwJoystickPresent(int jid) { if(jid == GLFW_JOYSTICK_1) { + CallbackBridge.enableGamepadDirectInput(); return true; }else return false; }