diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java index 965a849f..ed36a7c3 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -104,7 +104,7 @@ public class UIKit { PLaunchApp.launchMinecraft(); } - public static void callback_SurfaceViewController_onTouch(int event, int x, int y) { + public static void callback_SurfaceViewController_onTouch(int event, float x, float y) { switch (event) { case ACTION_DOWN: case ACTION_UP: diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java index fc85edb3..933cbbbc 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -25,7 +25,7 @@ public class CallbackBridge { public static final int ANDROID_TYPE_GRAB_STATE = 0; // Should pending events be limited? - volatile public static List PENDING_EVENT_LIST = new ArrayList<>(); + volatile public static List PENDING_EVENT_LIST = new ArrayList<>(); volatile public static boolean PENDING_EVENT_READY = false; public static final boolean INPUT_DEBUG_ENABLED; @@ -41,15 +41,15 @@ public class CallbackBridge { } // BEGIN launcher side - public static int mouseX, mouseY, mouseLastX, mouseLastY; + public static float mouseX, mouseY, mouseLastX, mouseLastY; public static boolean mouseLeft; - public static StringBuilder DEBUG_STRING = new StringBuilder(); - + //public static StringBuilder DEBUG_STRING = new StringBuilder(); + public static boolean nativeIsGrabbing() { return GLFW.mGLFWIsGrabbing; } - private static void nativeSendCursorPos(int x, int y) { + private static void nativeSendCursorPos(float x, float y) { if (!inputReady) return; GLFW.mGLFWCursorX = x + GLFW.internalGetWindow(GLFW.mainContext).x; GLFW.mGLFWCursorY = y + GLFW.internalGetWindow(GLFW.mainContext).y; @@ -61,26 +61,26 @@ public class CallbackBridge { } private static void nativeSendMouseButton(int button, int action, int mods) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_MOUSE_BUTTON, button, action, mods, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_MOUSE_BUTTON, button, action, mods, 0}); } private static void nativeSendScroll(double xoffset, double yoffset) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_SCROLL, (int) xoffset, (int) yoffset, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_SCROLL, (int) xoffset, (int) yoffset, 0, 0}); } private static void nativeSendScreenSize(int width, int height) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_FRAMEBUFFER_SIZE, width, height, 0, 0}); - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_FRAMEBUFFER_SIZE, width, height, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0}); } private static void nativeSendWindowPos(int x, int y) { if (!inputReady) return; - PENDING_EVENT_LIST.add(new Integer[]{EVENT_TYPE_WINDOW_POS, x, y, 0, 0}); + PENDING_EVENT_LIST.add(new Object[]{EVENT_TYPE_WINDOW_POS, x, y, 0, 0}); } // volatile private static boolean isGrabbing = false; public static class PusherRunnable implements Runnable { - int button; int x; int y; - public PusherRunnable(int button, int x, int y) { + int button; float x; float y; + public PusherRunnable(int button, float x, float y) { this.button = button; this.x = x; this.y = y; @@ -92,29 +92,29 @@ public class CallbackBridge { putMouseEventWithCoords(button, 0, x, y); } } - public static void putMouseEventWithCoords(int button, int x, int y /* , int dz, long nanos */) { + public static void putMouseEventWithCoords(int button, float x, float y /* , int dz, long nanos */) { new Thread(new PusherRunnable(button,x,y)).run(); } - public static void putMouseEventWithCoords(int button, int state, int x, int y /* , int dz, long nanos */) { + public static void putMouseEventWithCoords(int button, int state, float x, float y /* , int dz, long nanos */) { sendCursorPos(x, y); sendMouseKeycode(button, CallbackBridge.getCurrentMods(), state == 1); } private static boolean threadAttached; - public static void sendCursorPos(int x, int y) { + public static void sendCursorPos(float x, float y) { if (!threadAttached) { threadAttached = true; // CallbackBridge.nativeAttachThreadToOther(true, true /* TODO BaseMainActivity.isInputStackCall */); } - DEBUG_STRING.append("CursorPos=" + x + ", " + y + "\n"); + //DEBUG_STRING.append("CursorPos=" + x + ", " + y + "\n"); mouseX = x; mouseY = y; nativeSendCursorPos(x, y); } public static void sendKeycode(int keycode, char keychar, int scancode, int modifiers, boolean isDown) { - DEBUG_STRING.append("KeyCode=" + keycode + ", Char=" + keychar); + //DEBUG_STRING.append("KeyCode=" + keycode + ", Char=" + keychar); // TODO CHECK: This may cause input issue, not receive input! /* if (!nativeSendCharMods((int) keychar, modifiers) || !nativeSendChar(keychar)) { @@ -128,7 +128,7 @@ public class CallbackBridge { } public static void sendMouseKeycode(int button, int modifiers, boolean isDown) { - DEBUG_STRING.append("MouseKey=" + button + ", down=" + isDown + "\n"); + //DEBUG_STRING.append("MouseKey=" + button + ", down=" + isDown + "\n"); // if (isGrabbing()) DEBUG_STRING.append("MouseGrabStrace: " + android.util.Log.getStackTraceString(new Throwable()) + "\n"); nativeSendMouseButton(button, isDown ? 1 : 0, modifiers); } @@ -139,7 +139,7 @@ public class CallbackBridge { } public static void sendScroll(double xoffset, double yoffset) { - DEBUG_STRING.append("ScrollX=" + xoffset + ",ScrollY=" + yoffset); + //DEBUG_STRING.append("ScrollX=" + xoffset + ",ScrollY=" + yoffset); nativeSendScroll(xoffset, yoffset); } @@ -150,13 +150,7 @@ public class CallbackBridge { public static boolean isGrabbing() { return nativeIsGrabbing(); } - - public static void sendPrepareGrabInitialPos() { - DEBUG_STRING.append("Prepare set grab initial posititon"); - // TODO grab mode - // nativeSendMouseKeycode(-1, CallbackBridge.getCurrentMods(), false); - } - + public static boolean holdingAlt, holdingCapslock, holdingCtrl, holdingNumlock, holdingShift; public static int getCurrentMods() { @@ -176,7 +170,7 @@ public class CallbackBridge { } // END launcher side - public static void sendGrabbing(boolean grab, int xset, int yset) { + public static void sendGrabbing(boolean grab, float xset, float yset) { // sendData(ANDROID_TYPE_GRAB_STATE, Boolean.toString(grab)); if (grab) { @@ -190,8 +184,8 @@ public class CallbackBridge { nativeSetGrabbing(grab, xset, yset); } - // Called from Android side - public static void receiveCallback(int type, int i1, int i2, int i3, int i4) { + // Called from native code + public static void receiveCallback(int type, float i1, float i2, int i3, int i4) { /* if (INPUT_DEBUG_ENABLED) { System.out.println("LWJGL GLFW Callback received type=" + Integer.toString(type) + ", data=" + i1 + ", " + i2 + ", " + i3 + ", " + i4); @@ -199,10 +193,12 @@ public class CallbackBridge { */ if (PENDING_EVENT_READY) { if (type == EVENT_TYPE_CURSOR_POS) { - GLFW.mGLFWCursorX = i1; - GLFW.mGLFWCursorY = i2; + GLFW.mGLFWCursorX = (double) i1; + GLFW.mGLFWCursorY = (double) i2; + } else if (type == EVENT_TYPE_SCROLL) { + PENDING_EVENT_LIST.add(new Object[]{type, i1, i2, i3, i4}); } else { - PENDING_EVENT_LIST.add(new Integer[]{type, i1, i2, i3, i4}); + PENDING_EVENT_LIST.add(new Object[]{type, (int)i1, (int)i2, i3, i4}); } } // else System.out.println("Event input is not ready yet!"); } @@ -214,6 +210,6 @@ public class CallbackBridge { } public static native String nativeClipboard(int action, String copy); - private static native void nativeSetGrabbing(boolean grab, int xset, int yset); + private static native void nativeSetGrabbing(boolean grab, float xset, float yset); } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java index 56917714..b0a8b00b 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java @@ -1105,7 +1105,7 @@ public class GLFW // Indirect event while (CallbackBridge.PENDING_EVENT_LIST.size() > 0) { - Integer[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0); + Object[] dataArr = CallbackBridge.PENDING_EVENT_LIST.remove(0); if (dataArr == null) { // It should not be null, but still should be catched // System.out.println("GLFW: popped callback is null, skipping"); @@ -1113,53 +1113,53 @@ public class GLFW } for (Long ptr : mGLFWWindowMap.keySet()) { - switch (dataArr[0]) { + switch ((int)dataArr[0]) { case CallbackBridge.EVENT_TYPE_CHAR: if (mGLFWCharCallback != null) { - mGLFWCharCallback.invoke(ptr, dataArr[1]); + mGLFWCharCallback.invoke(ptr, (int)dataArr[1]); } break; case CallbackBridge.EVENT_TYPE_CHAR_MODS: if (mGLFWCharModsCallback != null) { - mGLFWCharModsCallback.invoke(ptr, dataArr[1], dataArr[2]); + mGLFWCharModsCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2]); } break; case CallbackBridge.EVENT_TYPE_CURSOR_ENTER: if (mGLFWCursorEnterCallback != null) { - mGLFWCursorEnterCallback.invoke(ptr, dataArr[1] == 1); + mGLFWCursorEnterCallback.invoke(ptr, (int)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]); + keyDownBuffer[Math.max(0, (int)dataArr[1]-31)]=(byte)(int)dataArr[3]; + mGLFWKeyCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2], (int)dataArr[3], (int)dataArr[4]); } break; case CallbackBridge.EVENT_TYPE_MOUSE_BUTTON: if (mGLFWMouseButtonCallback != null) { - mGLFWMouseButtonCallback.invoke(ptr, dataArr[1], dataArr[2], dataArr[3]); + mGLFWMouseButtonCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2], (int)dataArr[3]); } break; case CallbackBridge.EVENT_TYPE_SCROLL: if (mGLFWScrollCallback != null) { - mGLFWScrollCallback.invoke(ptr, dataArr[1], dataArr[2]); + mGLFWScrollCallback.invoke(ptr, (int)dataArr[1], (int)dataArr[2]); } break; case CallbackBridge.EVENT_TYPE_WINDOW_POS: - glfwSetWindowPos(ptr, dataArr[1], dataArr[2]); + glfwSetWindowPos(ptr, (int)dataArr[1], (int)dataArr[2]); break; case CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE: case CallbackBridge.EVENT_TYPE_WINDOW_SIZE: - internalChangeMonitorSize(dataArr[1], dataArr[2]); + internalChangeMonitorSize((int)dataArr[1], (int)dataArr[2]); glfwSetWindowSize(ptr, mGLFWWindowWidth, mGLFWWindowHeight); - if (dataArr[0] == CallbackBridge.EVENT_TYPE_FRAMEBUFFER_SIZE && mGLFWFramebufferSizeCallback != null) { + if ((int)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) { + } else if ((int)dataArr[0] == CallbackBridge.EVENT_TYPE_WINDOW_SIZE && mGLFWWindowSizeCallback != null) { mGLFWWindowSizeCallback.invoke(ptr, mGLFWWindowWidth, mGLFWWindowHeight); } break; default: - System.err.println("GLFWEvent: unknown callback type " + dataArr[0]); + System.err.println("GLFWEvent: unknown callback type " + (int)dataArr[0]); break; } } @@ -1171,7 +1171,7 @@ public class GLFW for (Long ptr : mGLFWWindowMap.keySet()) { mGLFWCursorPosCallback.invoke(ptr, mGLFWCursorX, mGLFWCursorY); } - // System.out.println("CursorPos updated to x=" + mGLFWCursorX + ",y=" + mGLFWCursorY); + //System.out.println("CursorPos updated to x=" + mGLFWCursorX + ",y=" + mGLFWCursorY); } } diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java index 30ec8cd4..b7f42df8 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWWindowProperties.java @@ -5,7 +5,7 @@ import java.util.*; public class GLFWWindowProperties { public int width = GLFW.mGLFWWindowWidth; public int height = GLFW.mGLFWWindowHeight; - public int x, y; + public float x, y; public CharSequence title; public boolean shouldClose, isInitialSizeCalled, isCursorEntered; public long monitor; diff --git a/Natives/SurfaceViewController.h b/Natives/SurfaceViewController.h index 10d09917..edc8856f 100644 --- a/Natives/SurfaceViewController.h +++ b/Natives/SurfaceViewController.h @@ -19,5 +19,6 @@ CGPoint lastVirtualMousePoint; @property(nonatomic, strong) GameSurfaceView* surfaceView; @property UIImageView* mousePointerView; +@property UIPanGestureRecognizer* scrollPanGesture; @end diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index 040619e6..9ac8e2ce 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -18,6 +18,7 @@ // Debugging only // #define DEBUG_VISIBLE_TEXT_FIELD +// #define DEBUG_VISIBLE_TOUCH #define INPUT_SPACE_CHAR @" " #define INPUT_SPACE_LENGTH 20 @@ -85,6 +86,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { @property(nonatomic, strong) NSMutableArray* swipeableButtons; @property(nonatomic, strong) NSMutableArray* togglableVisibleButtons; @property ControlButton* swipingButton; +@property UITouch *primaryTouch, *hotbarTouch; - (void)setupGL; @@ -116,9 +118,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { savedWidth = roundf(width * screenScale); savedHeight = roundf(height * screenScale); - NSLog(@"Debug: Creating surfaceView"); self.surfaceView = [[GameSurfaceView alloc] initWithFrame:self.view.frame]; - NSLog(@"Debug: surfaceView=%@", self.surfaceView); + self.surfaceView.multipleTouchEnabled = YES; self.surfaceView.layer.contentsScale = screenScale * resolutionScale; self.surfaceView.layer.magnificationFilter = self.surfaceView.layer.minificationFilter = kCAFilterNearest; [self.view addSubview:self.surfaceView]; @@ -150,17 +151,17 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnLongpress:)]; + longpressGesture.cancelsTouchesInView = NO; longpressGesture.delegate = self; longpressGesture.minimumPressDuration = [getPreference(@"time_longPressTrigger") floatValue] / 1000; [self.surfaceView addGestureRecognizer:longpressGesture]; - UIPanGestureRecognizer *scrollPanGesture = [[UIPanGestureRecognizer alloc] + self.scrollPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnTouchesScroll:)]; - scrollPanGesture.delegate = self; - scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; - scrollPanGesture.minimumNumberOfTouches = 2; - scrollPanGesture.maximumNumberOfTouches = 2; - [self.surfaceView addGestureRecognizer:scrollPanGesture]; + self.scrollPanGesture.delegate = self; + self.scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; + self.scrollPanGesture.minimumNumberOfTouches = 2; + self.scrollPanGesture.maximumNumberOfTouches = 2; if (@available(iOS 13.4, *)) { [self.surfaceView addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]]; @@ -190,7 +191,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { inputView = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 1, 1)]; inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f]; - inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + rectBtnWidth, 5 * 2 + rectBtnHeight, rectBtnWidth, rectBtnHeight)]; + inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + 80.0, 5 * 2 + 30.0, 80.0, 30.0)]; inputLengthView.text = @"length=?"; inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f]; [self.view addSubview:inputLengthView]; @@ -199,8 +200,6 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { [inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged]; [inputView addTarget:self action:@selector(inputViewDidClick) forControlEvents:UIControlEventTouchDown]; - // Custom button - // ADD_BUTTON(@"F1", f1, CGRectMake(5, 5, width, height)); NSString *controlFilePath = [NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), (NSString *)getPreference(@"default_ctrl")]; @@ -275,6 +274,12 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { #pragma mark - Input: send touch utilities + +- (BOOL)isTouchInactive:(UITouch *)touch { + return touch == nil || touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled; +} + + - (void)sendTouchPoint:(CGPoint)location withEvent:(int)event { CGFloat screenScale = [[UIScreen mainScreen] scale]; @@ -309,9 +314,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return YES; } -- (void)sendTouchEvent:(NSSet *)touches withUIEvent:(UIEvent *)uievent withEvent:(int)event +- (void)sendTouchEvent:(UITouch *)touchEvent withUIEvent:(UIEvent *)uievent withEvent:(int)event { - UITouch* touchEvent = [touches anyObject]; CGPoint locationInView = [touchEvent locationInView:self.view]; BOOL isTouchTypeIndirect = NO; @@ -322,7 +326,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { } if (touchEvent.view == self.surfaceView) { - if (slideableHotbar && !isTouchTypeIndirect) { + if (touchEvent == self.hotbarTouch && slideableHotbar && !isTouchTypeIndirect && ![self isTouchInactive:self.hotbarTouch]) { CGFloat screenScale = [[UIScreen mainScreen] scale]; int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); @@ -338,13 +342,18 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (event == ACTION_DOWN && slot == -1) { currentHotbarSlot = -1; } - + /* if (currentHotbarSlot != -1) { return; } + */ + return; + } + + if (touchEvent == self.primaryTouch) { + if ([self isTouchInactive:self.primaryTouch]) return; // FIXME: should be? + [self sendTouchPoint:locationInView withEvent:event]; } - - [self sendTouchPoint:locationInView withEvent:event]; if (!isTouchTypeIndirect) { switch (event) { @@ -452,9 +461,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 1, 0); } } else if (sender.state == UIGestureRecognizerStateChanged) { - if (currentHotbarSlot == -1) { - [self sendTouchPoint:location withEvent:ACTION_MOVE]; - } + // Nothing to do here, already handled in touchesMoved } else { if (sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateFailed @@ -507,6 +514,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { } } +// FIXME: incomplete - (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) API_AVAILABLE(ios(13.4)) API_AVAILABLE(ios(13.4)){ if (request != nil) { CGPoint origin = self.surfaceView.bounds.origin; @@ -517,7 +525,6 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { NSLog(@"UIPointerInteraction pos changed: x=%d, y=%d", (int) point.x, (int) point.y); - // TODO FIXME callback_SurfaceViewController_onTouch(ACTION_DOWN, (int)point.x, (int)point.y); } return [UIPointerRegion regionWithRect:self.surfaceView.bounds identifier:nil]; @@ -554,12 +561,6 @@ NSString* inputStringBefore; for (int i = 0; i < charLength; i++) { // Directly convert unichar to jchar since both are in UTF-16 encoding. -/* - jchar theChar = (jchar) - (isUseStackQueueCall ? - [newText UTF8String][i] : [newText characterAtIndex:i]); -*/ - jchar theChar = (jchar) [newText characterAtIndex:i]; if (isUseStackQueueCall) { Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, theChar, /* mods */ 0); @@ -640,7 +641,6 @@ int currentVisibility = 1; - (void)executebtn:(UIButton *)sender withAction:(int)action { ControlButton *button = (ControlButton *)sender; int held = action == ACTION_DOWN; - // TODO v2: mulitple keys support for (int i = 0; i < 4; i++) { int keycode = ((NSNumber *)button.properties[@"keycodes"][i]).intValue; if (keycode < 0) { @@ -762,27 +762,57 @@ int touchesMovedCount; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_DOWN]; + int i = 0; + for (UITouch *touch in touches) { + CGPoint locationInView = [touch locationInView:self.view]; + CGFloat screenScale = [[UIScreen mainScreen] scale]; + int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); + if ([self isTouchInactive:self.hotbarTouch] && slot != -1) { + self.hotbarTouch = touch; + } + if ([self isTouchInactive:self.primaryTouch] && slot == -1) { + self.primaryTouch = touch; + } + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_DOWN]; + break; + } } // Equals to Android ACTION_MOVE - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_MOVE]; + + for (UITouch *touch in touches) { + if (self.hotbarTouch != touch && [self isTouchInactive:self.primaryTouch]) { + // Replace the inactive touch with the current active touch + self.primaryTouch = touch; + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_DOWN]; + } + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_MOVE]; + } +} + +// For ACTION_UP and ACTION_CANCEL +- (void)touchesEndedGlobal:(NSSet *)touches withEvent:(UIEvent *)event +{ + for (UITouch *touch in touches) { + [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_UP]; + } } // Equals to Android ACTION_UP - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_UP]; + [self touchesEndedGlobal:touches withEvent:event]; } +// Equals to Android ACTION_CANCEL - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; - [self sendTouchEvent:touches withUIEvent:event withEvent:ACTION_UP]; + [self touchesEndedGlobal:touches withEvent:event]; } @end diff --git a/Natives/input_bridge_v3.m b/Natives/input_bridge_v3.m index 14fe5b4b..6bffc26b 100644 --- a/Natives/input_bridge_v3.m +++ b/Natives/input_bridge_v3.m @@ -36,7 +36,7 @@ typedef void GLFW_invoke_Scroll_func(void* window, double xoffset, double yoffse typedef void GLFW_invoke_WindowSize_func(void* window, int width, int height); typedef void GLFW_invoke_WindowPos_func(void* window, int x, int y); -int grabCursorX, grabCursorY, lastCursorX, lastCursorY; +CGFloat grabCursorX, grabCursorY, lastCursorX, lastCursorY; jclass inputBridgeClass_ANDROID, inputBridgeClass_JRE; jmethodID inputBridgeMethod_ANDROID, inputBridgeMethod_JRE; @@ -87,12 +87,12 @@ void getJavaInputBridge(jclass* clazz, jmethodID* method) { if (*method == NULL && runtimeJNIEnvPtr_ANDROID != NULL) { *clazz = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID, "org/lwjgl/glfw/CallbackBridge"); assert(*clazz != NULL); - *method = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, *clazz, "receiveCallback", "(IIIII)V"); + *method = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, *clazz, "receiveCallback", "(IFFII)V"); assert(*method != NULL); } } -void sendData(int type, int i1, int i2, int i3, int i4) { +void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4) { if (runtimeJNIEnvPtr_ANDROID == NULL) { (*runtimeJavaVMPtr)->GetEnv(runtimeJavaVMPtr, (void**) &runtimeJNIEnvPtr_ANDROID, JNI_VERSION_1_4); getJavaInputBridge(&inputBridgeClass_ANDROID, &inputBridgeMethod_ANDROID); @@ -105,12 +105,13 @@ void sendData(int type, int i1, int i2, int i3, int i4) { debug("BUG: Input is ready but thread is not attached yet."); return; } + // FIXME: should we send double instead of float? (*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod( runtimeJNIEnvPtr_ANDROID, inputBridgeClass_ANDROID, inputBridgeMethod_ANDROID, type, - i1, i2, i3, i4 + (jfloat)i1, (jfloat)i2, i3, i4 ); } @@ -176,21 +177,21 @@ void callback_SurfaceViewController_launchMinecraft(int width, int height) { ); } -void callback_SurfaceViewController_onTouch(int event, int x, int y) { +void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y) { if (!uikitBridgeClass) { uikitBridgeClass = (*runtimeJNIEnvPtr_JRE)->FindClass(runtimeJNIEnvPtr_JRE, "net/kdt/pojavlaunch/uikit/UIKit"); assert(uikitBridgeClass != NULL); } if (!uikitBridgeTouchMethod) { - uikitBridgeTouchMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(III)V"); + uikitBridgeTouchMethod = (*runtimeJNIEnvPtr_JRE)->GetStaticMethodID(runtimeJNIEnvPtr_JRE, uikitBridgeClass, "callback_SurfaceViewController_onTouch", "(IFF)V"); assert(uikitBridgeTouchMethod != NULL); } (*runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod( runtimeJNIEnvPtr_JRE, uikitBridgeClass, uikitBridgeTouchMethod, - event, x, y + event, (jfloat)x, (jfloat)y ); } @@ -199,11 +200,11 @@ const int hotbarKeys[9] = { GLFW_KEY_4, GLFW_KEY_5, GLFW_KEY_6, GLFW_KEY_7, GLFW_KEY_8, GLFW_KEY_9 }; -int guiScale = 1; -int mcscale(int input) { +int guiScale = 1.0; +int mcscale(CGFloat input) { return (int)((guiScale * input)/resolutionScale); } -int callback_SurfaceViewController_touchHotbar(int x, int y) { +int callback_SurfaceViewController_touchHotbar(CGFloat x, CGFloat y) { if (isGrabbing == JNI_FALSE) { return -1; } @@ -215,7 +216,7 @@ int callback_SurfaceViewController_touchHotbar(int x, int y) { if (x < barX || x >= barX + barWidth || y < barY || y >= barY + barHeight) { return -1; } - return hotbarKeys[((x - barX) / mcscale(180 / 9)) % 9]; + return hotbarKeys[(int) MathUtils_map(x, barX, barX + barWidth, 0, 9)]; } JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_updateMCGuiScale(JNIEnv* env, jclass clazz, jint scale) { @@ -256,7 +257,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetInputRead return isUseStackQueueCall; } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing, jint xset, jint yset) { +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIEnv* env, jclass clazz, jboolean grabbing, jfloat xset, jfloat yset) { isGrabbing = grabbing; if (isGrabbing == JNI_TRUE) { grabCursorX = xset; // savedWidth / 2; @@ -269,10 +270,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIE } dispatch_async(dispatch_get_main_queue(), ^{ + UIView *surfaceView = ((SurfaceViewController *)viewController).surfaceView; if (isGrabbing == JNI_TRUE) { CGFloat screenScale = [[UIScreen mainScreen] scale] * resolutionScale; callback_SurfaceViewController_onTouch(ACTION_DOWN, lastVirtualMousePoint.x * screenScale, lastVirtualMousePoint.y * screenScale); ((SurfaceViewController *)viewController).mousePointerView.frame = virtualMouseFrame; + [surfaceView removeGestureRecognizer:((SurfaceViewController *)viewController).scrollPanGesture]; + } else { + [surfaceView addGestureRecognizer:((SurfaceViewController *)viewController).scrollPanGesture]; } ((SurfaceViewController *)viewController).mousePointerView.hidden = isGrabbing || !virtualMouseEnabled; }); @@ -313,7 +318,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter( } } */ -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jint x, jint y) { +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jfloat x, jfloat y) { if (GLFW_invoke_CursorPos && isInputReady) { if (!isCursorEntered) { if (GLFW_invoke_CursorEnter) { diff --git a/Natives/utils.h b/Natives/utils.h index 31125583..21b8d89c 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -57,6 +57,7 @@ int savedWidth, savedHeight; BOOL virtualMouseEnabled; CGFloat MathUtils_dist(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2); +CGFloat MathUtils_map(CGFloat x, CGFloat in_min, CGFloat in_max, CGFloat out_min, CGFloat out_max); CGFloat dpToPx(CGFloat dp); CGFloat pxToDp(CGFloat px); void _CGDataProviderReleaseBytePointerCallback(void *info,const void *pointer); @@ -67,17 +68,17 @@ jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows void free_char_array(JNIEnv *env, jobjectArray jstringArray, char **charArray); jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr); -void sendData(int type, int i1, int i2, int i3, int i4); +void sendData(int type, CGFloat i1, CGFloat i2, int i3, int i4); void closeGLFWWindow(); void callback_LauncherViewController_installMinecraft(); void callback_SurfaceViewController_launchMinecraft(int width, int height); -void callback_SurfaceViewController_onTouch(int event, int x, int y); -int callback_SurfaceViewController_touchHotbar(int x, int y); +void callback_SurfaceViewController_onTouch(int event, CGFloat x, CGFloat y); +int callback_SurfaceViewController_touchHotbar(CGFloat x, CGFloat y); JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNIEnv* env, jclass clazz, jchar codepoint /* jint codepoint */); JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(JNIEnv* env, jclass clazz, jchar codepoint, jint mods); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jint x, jint y); +JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jfloat x, jfloat y); JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* env, jclass clazz, jint key, jint scancode, jint action, jint mods); JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKeycode(JNIEnv* env, jclass clazz, jint keycode, jchar keychar, jint scancode, jint action, jint mods); JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(JNIEnv* env, jclass clazz, jint button, jint action, jint mods); diff --git a/Natives/utils.m b/Natives/utils.m index 24e45c0b..2500982a 100644 --- a/Natives/utils.m +++ b/Natives/utils.m @@ -12,7 +12,13 @@ CGFloat MathUtils_dist(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) { const CGFloat x = (x2 - x1); const CGFloat y = (y2 - y1); return (CGFloat) hypot(x, y); - } +} + +//Ported from https://www.arduino.cc/reference/en/language/functions/math/map/ +CGFloat MathUtils_map(CGFloat x, CGFloat in_min, CGFloat in_max, CGFloat out_min, CGFloat out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + void _CGDataProviderReleaseBytePointerCallback(void *info,const void *pointer) { }