New, combined native+Java input bridge

This commit is contained in:
artdeell 2022-11-20 12:29:40 +03:00
parent 641eae051b
commit 86eb81c00b
4 changed files with 100 additions and 76 deletions

View File

@ -1 +1 @@
1665886806915
1668936448354

View File

@ -49,9 +49,12 @@ jmethodID inputBridgeMethod_ANDROID, inputBridgeMethod_JRE;
jmethodID method_accessAndroidClipboard;
jmethodID method_onGrabStateChanged;
jmethodID method_glftSetWindowAttrib;
jmethodID method_internalWindowSizeChanged;
jmethodID method_fallbackWriteKey = NULL;
jclass bridgeClazz;
jclass vmGlfwClass;
jboolean isGrabbing;
jbyte* keyDownBuffer;
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
if (dalvikJavaVMPtr == NULL) {
@ -67,7 +70,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
(*vm)->GetEnv(vm, (void**) &runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4);
vmGlfwClass = (*runtimeJNIEnvPtr_JRE)->NewGlobalRef(runtimeJNIEnvPtr_JRE, (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW"));
method_glftSetWindowAttrib = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, vmGlfwClass, "glfwSetWindowAttrib", "(JII)V");
hookExec();
method_internalWindowSizeChanged = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, vmGlfwClass, "internalWindowSizeChanged", "(JII)V");
jfieldID field_keyDownBuffer = (*runtimeJNIEnvPtr_JRE)->GetStaticFieldID(runtimeJNIEnvPtr_JRE, vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;");
jobject keyDownBufferJ = (*runtimeJNIEnvPtr_JRE)->GetStaticObjectField(runtimeJNIEnvPtr_JRE, vmGlfwClass, field_keyDownBuffer);
keyDownBuffer = (*runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(runtimeJNIEnvPtr_JRE, keyDownBufferJ);
hookExec();
}
isGrabbing = JNI_FALSE;
@ -127,6 +134,56 @@ jboolean attachThread(bool isAndroid, JNIEnv** secondJNIEnvPtr) {
return JNI_FALSE;
}
typedef struct {
int type;
int i1;
int i2;
int i3;
int i4;
} GLFWInputEvent;
static size_t eventCounter = 0;
static GLFWInputEvent events[500];
void handleFramebufferSizeJava(long window, int w, int h) {
(*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(runtimeJNIEnvPtr_JRE, vmGlfwClass, method_internalWindowSizeChanged, (long)window, w, h);
}
void pojavPumpEvents(void* window) {
//__android_log_print(ANDROID_LOG_INFO, "input_bridge_v3", "pojavPumpEvents %d", eventCounter);
for(size_t i = 0; i < eventCounter; i++) {
GLFWInputEvent event = events[i];
switch(event.type) {
case EVENT_TYPE_CHAR:
if(GLFW_invoke_Char) GLFW_invoke_Char(window, event.i1);
break;
case EVENT_TYPE_CHAR_MODS:
if(GLFW_invoke_CharMods) GLFW_invoke_CharMods(window, event.i1, event.i2);
break;
case EVENT_TYPE_KEY:
if(GLFW_invoke_Key) GLFW_invoke_Key(window, event.i1, event.i2, event.i3, event.i4);
case EVENT_TYPE_MOUSE_BUTTON:
if(GLFW_invoke_MouseButton) GLFW_invoke_MouseButton(window, event.i1, event.i2, event.i3);
break;
case EVENT_TYPE_SCROLL:
if(GLFW_invoke_Scroll) GLFW_invoke_Scroll(window, event.i1, event.i2);
break;
case EVENT_TYPE_FRAMEBUFFER_SIZE:
handleFramebufferSizeJava(showingWindow, event.i1, event.i2);
if(GLFW_invoke_FramebufferSize) GLFW_invoke_FramebufferSize(window, event.i1, event.i2);
break;
case EVENT_TYPE_WINDOW_SIZE:
handleFramebufferSizeJava(showingWindow, event.i1, event.i2);
if(GLFW_invoke_WindowSize) GLFW_invoke_WindowSize(window, event.i1, event.i2);
break;
}
}
}
void pojavRewindEvents() {
eventCounter = 0;
}
void sendData(int type, int i1, int i2, int i3, int i4) {
#ifdef DEBUG
LOGD("Debug: Send data, jnienv.isNull=%d\n", runtimeJNIEnvPtr_ANDROID == NULL);
@ -136,13 +193,24 @@ void sendData(int type, int i1, int i2, int i3, int i4) {
return;
}
if(inputBridgeClass_ANDROID == NULL) return;
(*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod(
runtimeJNIEnvPtr_ANDROID,
inputBridgeClass_ANDROID,
inputBridgeMethod_ANDROID,
type,
i1, i2, i3, i4
);
if(type == EVENT_TYPE_CURSOR_POS) {
(*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod(
runtimeJNIEnvPtr_ANDROID,
inputBridgeClass_ANDROID,
inputBridgeMethod_ANDROID,
type,
i1, i2, i3, i4
);
}else {
if (eventCounter < 499) {
GLFWInputEvent *event = &events[eventCounter++];
event->type = type;
event->i1 = i1;
event->i2 = i2;
event->i3 = i3;
event->i4 = i4;
}
}
}
void closeGLFWWindow() {
@ -356,10 +424,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JN
lastCursorY = y;
}
}
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
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) {
keyDownBuffer[max(0, key-31)]=(jbyte)action;
sendData(EVENT_TYPE_KEY, key, scancode, action, mods);
} else {
GLFW_invoke_Key((void*) showingWindow, key, scancode, action, mods);

View File

@ -21,6 +21,8 @@ import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
import java.util.*;
import sun.misc.Unsafe;
public class GLFW
{
static FloatBuffer joystickData = (FloatBuffer)FloatBuffer.allocate(8).flip();
@ -496,7 +498,7 @@ public class GLFW
private static ArrayMap<Long, GLFWWindowProperties> mGLFWWindowMap;
public static boolean mGLFWIsGrabbing, mGLFWIsInputReady, mGLFWIsUseStackQueue = false;
public static final byte[] keyDownBuffer = new byte[317];
public static final ByteBuffer keyDownBuffer = ByteBuffer.allocateDirect(317);
private static final String PROP_WINDOW_WIDTH = "glfwstub.windowWidth";
private static final String PROP_WINDOW_HEIGHT= "glfwstub.windowHeight";
public static long mainContext = 0;
@ -612,7 +614,9 @@ public class GLFW
MakeContextCurrent = apiGetFunctionAddress(GLFW, "pojavMakeCurrent"),
Terminate = apiGetFunctionAddress(GLFW, "pojavTerminate"),
SwapBuffers = apiGetFunctionAddress(GLFW, "pojavSwapBuffers"),
SwapInterval = apiGetFunctionAddress(GLFW, "pojavSwapInterval");
SwapInterval = apiGetFunctionAddress(GLFW, "pojavSwapInterval"),
PumpEvents = apiGetFunctionAddress(GLFW, "pojavPumpEvents"),
RewindEvents = apiGetFunctionAddress(GLFW, "pojavRewindEvents");
}
public static SharedLibrary getLibrary() {
@ -1057,69 +1061,8 @@ public class GLFW
CallbackBridge.PENDING_EVENT_READY = true;
}
// Indirect event
while (CallbackBridge.PENDING_EVENT_LIST.size() > 0) {
Integer[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0);
for (Long ptr : mGLFWWindowMap.keySet()) {
try {
switch (dataArr[0]) {
case CallbackBridge.EVENT_TYPE_CHAR:
if (mGLFWCharCallback != null) {
mGLFWCharCallback.invoke(ptr, dataArr[1]);
}
break;
case CallbackBridge.EVENT_TYPE_CHAR_MODS:
if (mGLFWCharModsCallback != null) {
mGLFWCharModsCallback.invoke(ptr, dataArr[1], dataArr[2]);
}
break;
case CallbackBridge.EVENT_TYPE_CURSOR_ENTER:
if (mGLFWCursorEnterCallback != null) {
mGLFWCursorEnterCallback.invoke(ptr, dataArr[1] == 1);
}
break;
case CallbackBridge.EVENT_TYPE_KEY:
if (mGLFWKeyCallback != null) {
keyDownBuffer[Math.max(0, dataArr[1]-31)]=(byte)(int)dataArr[3];
mGLFWKeyCallback.invoke(ptr, dataArr[1], dataArr[2], dataArr[3], dataArr[4]);
}
break;
case CallbackBridge.EVENT_TYPE_MOUSE_BUTTON:
if (mGLFWMouseButtonCallback != null) {
mGLFWMouseButtonCallback.invoke(ptr, dataArr[1], dataArr[2], dataArr[3]);
}
break;
case CallbackBridge.EVENT_TYPE_SCROLL:
if (mGLFWScrollCallback != null) {
mGLFWScrollCallback.invoke(ptr, dataArr[1], dataArr[2]);
}
break;
case CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE:
case CallbackBridge.EVENT_TYPE_WINDOW_SIZE:
try {
internalChangeMonitorSize(dataArr[1], dataArr[2]);
glfwSetWindowSize(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
if (dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) {
mGLFWFramebufferSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
} else if (dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) {
mGLFWWindowSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight);
}
} catch (Throwable th) {
// Some Minecraft versions cause a NPE when setting size, so we will have to ignore them to make game alive
th.printStackTrace();
}
break;
default:
System.err.println("GLFWEvent: unknown callback type " + dataArr[0]);
break;
}
}catch (Throwable throwable){
throwable.printStackTrace();
}
}
}
for (Long ptr : mGLFWWindowMap.keySet()) callJV(ptr, Functions.PumpEvents);
callV(Functions.RewindEvents);
if ((mGLFWCursorX != mGLFWCursorLastX || mGLFWCursorY != mGLFWCursorLastY) && mGLFWCursorPosCallback != null) {
mGLFWCursorLastX = mGLFWCursorX;
mGLFWCursorLastY = mGLFWCursorY;
@ -1138,6 +1081,15 @@ public class GLFW
}
}
public static void internalWindowSizeChanged(long window, int w, int h) {
try {
internalChangeMonitorSize(w, h);
glfwSetWindowSize(window, mGLFWWindowWidth, mGLFWWindowHeight);
}catch (Exception e) {
e.printStackTrace();
}
}
public static void glfwWaitEvents() {}
public static void glfwWaitEventsTimeout(double timeout) {
@ -1181,7 +1133,7 @@ public class GLFW
}
public static int glfwGetKey(@NativeType("GLFWwindow *") long window, int key) {
return keyDownBuffer[Math.max(0, key-31)];
return keyDownBuffer.get(Math.max(0, key-31));
}
public static int glfwGetMouseButton(@NativeType("GLFWwindow *") long window, int button) {