From b6f552df85213ff3fd86686d66fcadbb8c2428ba Mon Sep 17 00:00:00 2001 From: khanhduytran0 Date: Tue, 4 Jan 2022 09:55:47 +0700 Subject: [PATCH] Keyboard + Mouse input handling; some cleanups * Keyboard input: KeyboardInput.m - Requires iOS 13.4. Used pressesBegan and pressesEnded. - Not all keys are handled, these will be handled later. * Mouse input - Requires iOS 13.0 for hovering. Used UIHoverGestureRecognizer. - Requires iOS 14.0 for L/R mouse buttons and scroll handling. Used GCMouse for now. We will use iOS 13.4(?)'s API later. - Pointer lock is not yet handled. These above apply to iPadOS aswell, not sure about tvOS. iPhone users need to disable "Perform Touch Gestures" in the AssistiveTouch Accessibility settings in order to get the pointer hovering to work. * Cleanups - Use asprintf instead of sprintf when possible - CallbackBridge functions: removed unnecessary JNI fields. - Condition cleanup (managing virtual mouse position). --- .../main/java/net/kdt/pojavlaunch/Tools.java | 4 +- .../java/net/kdt/pojavlaunch/uikit/UIKit.java | 7 +- Natives/CMakeLists.txt | 2 + Natives/CustomControlsViewController.m | 4 - Natives/JavaLauncher.m | 41 ++- Natives/KeyboardInput.h | 10 + Natives/KeyboardInput.m | 153 +++++++++ Natives/SurfaceViewController.m | 303 ++++++++++-------- Natives/input_bridge_v3.m | 39 ++- Natives/ios_uikit_bridge.m | 3 +- Natives/utils.h | 25 +- 11 files changed, 394 insertions(+), 197 deletions(-) create mode 100644 Natives/KeyboardInput.h create mode 100644 Natives/KeyboardInput.m diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java index 8613a50b..74758024 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -177,8 +177,6 @@ public final class Tools if (versionInfo.inheritsFrom != null) { versionName = versionInfo.inheritsFrom; } - - String userType = "mojang"; File gameDir = new File(Tools.DIR_GAME_NEW); gameDir.mkdirs(); @@ -194,7 +192,7 @@ public final class Tools varArgMap.put("game_assets", Tools.ASSETS_PATH); varArgMap.put("game_directory", gameDir.getAbsolutePath()); varArgMap.put("user_properties", "{}"); - varArgMap.put("user_type", userType); + varArgMap.put("user_type", /* profile.isMicrosoft ? "msa" : */ "mojang"); // FIXME: handle MS auth varArgMap.put("version_name", versionName); varArgMap.put("version_type", versionInfo.type); 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 ed36a7c3..c26e3ba9 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -12,7 +12,8 @@ public class UIKit { public static final int ACTION_DOWN = 0; public static final int ACTION_UP = 1; public static final int ACTION_MOVE = 2; - + public static final int ACTION_MOVE_MOTION = 3; + private static int guiScale; private static void patch_FlatLAF_setLinux() { @@ -123,6 +124,10 @@ public class UIKit { CallbackBridge.mouseY = y; } break; + + case ACTION_MOVE_MOTION: + CallbackBridge.mouseX += x; + CallbackBridge.mouseY += y; } CallbackBridge.mouseLastX = x; CallbackBridge.mouseLastY = y; diff --git a/Natives/CMakeLists.txt b/Natives/CMakeLists.txt index e6c0acd6..9dc11449 100644 --- a/Natives/CMakeLists.txt +++ b/Natives/CMakeLists.txt @@ -50,6 +50,7 @@ add_executable(PojavLauncher CustomControlsViewController.m FileListViewController.m JavaGUIViewController.m + KeyboardInput.m LauncherFAQViewController.m LauncherPreferences.m LauncherPreferencesViewController.m @@ -73,6 +74,7 @@ target_link_libraries(PojavLauncher "-F'${CMAKE_CURRENT_LIST_DIR}/build'" "-framework AuthenticationServices" "-framework CoreGraphics" + "-framework GameController" "-framework QuartzCore" "-framework UIKit" "-framework SafariServices" diff --git a/Natives/CustomControlsViewController.m b/Natives/CustomControlsViewController.m index ffc767cd..e19b309c 100644 --- a/Natives/CustomControlsViewController.m +++ b/Natives/CustomControlsViewController.m @@ -14,10 +14,6 @@ BOOL shouldDismissPopover = YES; int width; NSMutableArray *keyCodeMap, *keyValueMap; -CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { - return fmin(upper, fmax(x, lower)); -} - @interface ControlLayout () @end @implementation ControlLayout diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index 50022889..e8a590ad 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -194,14 +194,17 @@ void init_loadCustomEnv() { void init_loadCustomJvmFlags() { NSString *jvmargs = getPreference(@"java_args"); BOOL isFirstArg = YES; - for (NSString *jvmarg in [jvmargs componentsSeparatedByString:@" -"]) { + for (NSString *jvmarg in [jvmargs componentsSeparatedByString:@" "]) { if ([jvmarg length] == 0) continue; + margv[margc] = (char *) [jvmarg UTF8String]; +/* if (isFirstArg) { isFirstArg = NO; margv[margc] = (char *) [jvmarg UTF8String]; } else { margv[margc] = (char *) [[@"-" stringByAppendingString:jvmarg] UTF8String]; } +*/ NSLog(@"[Pre-init] Added custom JVM flag: %s", margv[margc]); ++margc; } @@ -284,8 +287,7 @@ void environmentFailsafes(char *argv[]) { javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding]; setPreference(@"java_home", javaHome_pre); } else { - javaHome = calloc(1, 2048); - sprintf((char *)javaHome, "%s/jre", homeDir); + asprintf((char **)&javaHome, "%s/jre", homeDir); } } @@ -507,8 +509,8 @@ int launchJVM(int argc, char *argv[]) { allocmem_pre = [getPreference(@"allocated_memory") stringValue]; allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding]; - char *controlPath = calloc(1, 2048); - sprintf(controlPath, "%s/controlmap", homeDir); + char *controlPath; + asprintf(&controlPath, "%s/controlmap", homeDir); mkdir(controlPath, S_IRWXU | S_IRWXG | S_IRWXO); setenv("POJAV_PATH_CONTROL", controlPath, 1); free(controlPath); @@ -543,10 +545,9 @@ int launchJVM(int argc, char *argv[]) { multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding]; debug("[Pre-init] Restored preference: MULTI_DIR is set to %s\n", multidir); } - char *multidir_char = calloc(1, 2048); - char *librarySym = calloc(1, 2048); - snprintf(multidir_char, 2048, "%s/instances/%s", getenv("POJAV_HOME"), multidir); - snprintf(librarySym, 2048, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME")); + char *multidir_char, *librarySym; + asprintf(&multidir_char, "%s/instances/%s", getenv("POJAV_HOME"), multidir); + asprintf(&librarySym, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME")); remove(librarySym); if (0 != access(multidir_char, F_OK)) { mkdir(multidir_char, 755); @@ -564,20 +565,14 @@ int launchJVM(int argc, char *argv[]) { } // Check if JVM restarts if (!started) { - char *frameworkPath = calloc(1, 2048); - char *javaPath = calloc(1, 2048); - char *jnaLibPath = calloc(1, 2048); - char *userDir = calloc(1, 2048); - char *userHome = calloc(1, 2048); - char *memMin = calloc(1, 2048); - char *memMax = calloc(1, 2048); - snprintf(frameworkPath, 2048, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); - snprintf(javaPath, 2048, "%s/bin/java", javaHome); - snprintf(jnaLibPath, 2048, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); - snprintf(userDir, 2048, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); - snprintf(userHome, 2048, "-Duser.home=%s", getenv("POJAV_HOME")); - snprintf(memMin, 2048, "-Xms%sM", allocmem); - snprintf(memMax, 2048, "-Xmx%sM", allocmem); + char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax; + asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); + asprintf(&javaPath, "%s/bin/java", javaHome); + asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); + asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); + asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME")); + asprintf(&memMin, "-Xms%sM", allocmem); + asprintf(&memMax, "-Xmx%sM", allocmem); NSLog(@"[Pre-init] Java executable path: %s", javaPath); setenv("JAVA_EXT_EXECNAME", javaPath, 1); diff --git a/Natives/KeyboardInput.h b/Natives/KeyboardInput.h new file mode 100644 index 00000000..3b3a8709 --- /dev/null +++ b/Natives/KeyboardInput.h @@ -0,0 +1,10 @@ +#import + +NSMutableDictionary* keycodeTable; + +@interface KeyboardInput : NSObject + ++ (void)initKeycodeTable; ++ (BOOL)sendKeyEvent:(UIKey *)key down:(BOOL)isDown API_AVAILABLE(ios(13.4)); + +@end diff --git a/Natives/KeyboardInput.m b/Natives/KeyboardInput.m new file mode 100644 index 00000000..24d26fd7 --- /dev/null +++ b/Natives/KeyboardInput.m @@ -0,0 +1,153 @@ +#import "KeyboardInput.h" +#import "utils.h" + +#include "glfw_keycodes.h" + +@implementation KeyboardInput + ++ (void)initKeycodeTable { + if (@available(iOS 13.4, *)) { + keycodeTable = [[NSMutableDictionary alloc] init]; + + // A-Z keys + for (int i = UIKeyboardHIDUsageKeyboardA; i <= UIKeyboardHIDUsageKeyboardZ; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboardA + GLFW_KEY_A); + } + + // 0-9 keys + keycodeTable[@(UIKeyboardHIDUsageKeyboard0)] = @(GLFW_KEY_0); + for (int i = UIKeyboardHIDUsageKeyboard1; i <= UIKeyboardHIDUsageKeyboard9; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboard1 + GLFW_KEY_1); + } + + // Arrow keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardUpArrow)] = @(GLFW_KEY_DPAD_UP); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDownArrow)] = @(GLFW_KEY_DPAD_DOWN); + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftArrow)] = @(GLFW_KEY_DPAD_LEFT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightArrow)] = @(GLFW_KEY_DPAD_RIGHT); + + keycodeTable[@(UIKeyboardHIDUsageKeyboardComma)] = @(GLFW_KEY_COMMA); + keycodeTable[@(UIKeyboardHIDUsageKeyboardPeriod)] = @(GLFW_KEY_PERIOD); + + // Alt keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftAlt)] = @(GLFW_KEY_LEFT_ALT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightAlt)] = @(GLFW_KEY_RIGHT_ALT); + + // Control keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftControl)] = @(GLFW_KEY_LEFT_CONTROL); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightControl)] = @(GLFW_KEY_RIGHT_CONTROL); + + // Shift keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardLeftShift)] = @(GLFW_KEY_LEFT_SHIFT); + keycodeTable[@(UIKeyboardHIDUsageKeyboardRightShift)] = @(GLFW_KEY_RIGHT_SHIFT); + + // Bracket keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardOpenBracket)] = @(GLFW_KEY_LEFT_BRACKET); + keycodeTable[@(UIKeyboardHIDUsageKeyboardCloseBracket)] = @(GLFW_KEY_RIGHT_BRACKET); + + // Slash keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardSlash)] = @(GLFW_KEY_SLASH); + keycodeTable[@(UIKeyboardHIDUsageKeyboardBackslash)] = @(GLFW_KEY_BACKSLASH); + + // Page keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardPageUp)] = @(GLFW_KEY_PAGE_UP); + keycodeTable[@(UIKeyboardHIDUsageKeyboardPageDown)] = @(GLFW_KEY_PAGE_DOWN); + + // Some other keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardHome)] = @(GLFW_KEY_HOME); + keycodeTable[@(UIKeyboardHIDUsageKeyboardEscape)] = @(GLFW_KEY_ESCAPE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardTab)] = @(GLFW_KEY_TAB); + keycodeTable[@(UIKeyboardHIDUsageKeyboardReturnOrEnter)] = @(GLFW_KEY_ENTER); + keycodeTable[@(UIKeyboardHIDUsageKeyboardSpacebar)] = @(GLFW_KEY_SPACE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDeleteOrBackspace)] = @(GLFW_KEY_BACKSPACE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardDeleteForward)] = @(GLFW_KEY_DELETE); + keycodeTable[@(UIKeyboardHIDUsageKeyboardGraveAccentAndTilde)] = @(GLFW_KEY_GRAVE_ACCENT); + + keycodeTable[@(UIKeyboardHIDUsageKeyboardHyphen)] = @(GLFW_KEY_MINUS); + keycodeTable[@(UIKeyboardHIDUsageKeyboardEqualSign)] = @(GLFW_KEY_EQUAL); + keycodeTable[@(UIKeyboardHIDUsageKeyboardSemicolon)] = @(GLFW_KEY_SEMICOLON); + + // Lock keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardCapsLock)] = @(GLFW_KEY_CAPS_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeypadNumLock)] = @(GLFW_KEY_NUM_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeyboardScrollLock)] = @(GLFW_KEY_SCROLL_LOCK); + + // Numpad keys + keycodeTable[@(UIKeyboardHIDUsageKeypadSlash)] = @(GLFW_KEY_NUMPAD_DIVIDE); + keycodeTable[@(UIKeyboardHIDUsageKeypadAsterisk)] = @(GLFW_KEY_NUMPAD_MULTIPLY); + keycodeTable[@(UIKeyboardHIDUsageKeypadHyphen)] = @(GLFW_KEY_NUMPAD_SUBTRACT); + keycodeTable[@(UIKeyboardHIDUsageKeypadPlus)] = @(GLFW_KEY_NUMPAD_ADD); + keycodeTable[@(UIKeyboardHIDUsageKeypadEnter)] = @(GLFW_KEY_NUMPAD_ENTER); + keycodeTable[@(UIKeyboardHIDUsageKeypadEqualSign)] = @(GLFW_KEY_NUMPAD_EQUAL); + keycodeTable[@(UIKeyboardHIDUsageKeypad0)] = @(GLFW_KEY_NUMPAD_0); + for (int i = UIKeyboardHIDUsageKeypad1; i <= UIKeyboardHIDUsageKeypad9; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeypad1 + GLFW_KEY_NUMPAD_1); + } + + // Function keys + for (int i = UIKeyboardHIDUsageKeyboardF1; i <= UIKeyboardHIDUsageKeyboardF12; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboardF1 + GLFW_KEY_F1); + } + + // Lock keys + keycodeTable[@(UIKeyboardHIDUsageKeyboardCapsLock)] = @(GLFW_KEY_CAPS_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeypadNumLock)] = @(GLFW_KEY_NUM_LOCK); + keycodeTable[@(UIKeyboardHIDUsageKeyboardScrollLock)] = @(GLFW_KEY_SCROLL_LOCK); + + // Numpad keys + keycodeTable[@(UIKeyboardHIDUsageKeypadSlash)] = @(GLFW_KEY_NUMPAD_DIVIDE); + keycodeTable[@(UIKeyboardHIDUsageKeypadAsterisk)] = @(GLFW_KEY_NUMPAD_MULTIPLY); + keycodeTable[@(UIKeyboardHIDUsageKeypadHyphen)] = @(GLFW_KEY_NUMPAD_SUBTRACT); + keycodeTable[@(UIKeyboardHIDUsageKeypadPlus)] = @(GLFW_KEY_NUMPAD_ADD); + keycodeTable[@(UIKeyboardHIDUsageKeypadEnter)] = @(GLFW_KEY_NUMPAD_ENTER); + keycodeTable[@(UIKeyboardHIDUsageKeypadEqualSign)] = @(GLFW_KEY_NUMPAD_EQUAL); + keycodeTable[@(UIKeyboardHIDUsageKeypad0)] = @(GLFW_KEY_NUMPAD_0); + for (int i = UIKeyboardHIDUsageKeypad1; i <= UIKeyboardHIDUsageKeypad9; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeypad1 + GLFW_KEY_NUMPAD_1); + } + + // Function keys + for (int i = UIKeyboardHIDUsageKeyboardF1; i <= UIKeyboardHIDUsageKeyboardF12; i++) { + keycodeTable[@(i)] = @(i - UIKeyboardHIDUsageKeyboardF1 + GLFW_KEY_F1); + } + } +} + ++ (BOOL)sendKeyEvent:(UIKey *)key down:(BOOL)isDown API_AVAILABLE(ios(13.4)) { + char modifiers = 0; + + // convert UIKey's modifiers to GLFW + if (key.modifierFlags & UIKeyModifierAlphaShift) { + modifiers |= GLFW_MOD_CAPS_LOCK; + } + if (key.modifierFlags & UIKeyModifierShift) { + modifiers |= GLFW_MOD_SHIFT; + } + if (key.modifierFlags & UIKeyModifierAlternate) { + modifiers |= GLFW_MOD_ALT; + } + if (key.modifierFlags & UIKeyModifierControl) { + modifiers |= GLFW_MOD_CONTROL; + } + + // send the keycode + int keycode = [keycodeTable[@(key.keyCode)] intValue]; + if (keycode != 0) { + CallbackBridge_nativeSendKey(keycode, 0 /* scancode */, isDown, modifiers); + } else { + NSLog(@"KeyboardInput: Unhandled key %lu", (unsigned long)key.keyCode); + } + + // key.characters.length < 11: skip sending characters if the string starts with UIKeyInput + if (isDown && key.characters.length < 11) { + for (int i = 0; i < key.characters.length; i++) { + int keychar = [key.characters characterAtIndex:i]; + CallbackBridge_nativeSendCharMods(keychar, modifiers); + CallbackBridge_nativeSendChar(keychar); + } + } + + return keycode != 0 || isDown; +} + +@end diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index a18a883f..5926cb85 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -1,3 +1,5 @@ +#import + #import "LauncherPreferences.h" #import "SurfaceViewController.h" #import "egl_bridge.h" @@ -8,6 +10,8 @@ #import "customcontrols/ControlSubButton.h" #import "customcontrols/CustomControlsUtils.h" +#import "KeyboardInput.h" + #include "glfw_keycodes.h" #include "utils.h" @@ -77,6 +81,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return CAMetalLayer.class; } } + @end @interface SurfaceViewController () { @@ -87,8 +92,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { @property(nonatomic, strong) NSMutableArray* togglableVisibleButtons; @property ControlButton* swipingButton; @property UITouch *primaryTouch, *hotbarTouch; - -- (void)setupGL; +@property id mouseConnectCallback, mouseDisconnectCallback; @end @@ -105,6 +109,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; [self setNeedsUpdateOfHomeIndicatorAutoHidden]; + [self.navigationItem setHidesBackButton:YES animated:YES]; + [self.navigationController setNavigationBarHidden:YES animated:YES]; CGRect screenBounds = [[UIScreen mainScreen] bounds]; CGFloat screenScale = [[UIScreen mainScreen] scale]; @@ -134,9 +140,10 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { notchOffset = insets.left; width = width - notchOffset * 2; CGFloat buttonScale = [getPreference(@"button_scale") floatValue] / 100.0; - + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnClick:)]; + tapGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; tapGesture.delegate = self; tapGesture.numberOfTapsRequired = 1; tapGesture.numberOfTouchesRequired = 1; @@ -145,14 +152,22 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnDoubleClick:)]; + doubleTapGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; doubleTapGesture.delegate = self; doubleTapGesture.numberOfTapsRequired = 2; doubleTapGesture.numberOfTouchesRequired = 1; doubleTapGesture.cancelsTouchesInView = NO; [self.surfaceView addGestureRecognizer:doubleTapGesture]; + if (@available(iOS 13.0, *)) { + UIHoverGestureRecognizer *hoverGesture = [[UIHoverGestureRecognizer alloc] + initWithTarget:self action:@selector(surfaceOnHover:)]; + [self.surfaceView addGestureRecognizer:hoverGesture]; + } + UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnLongpress:)]; + longpressGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; longpressGesture.cancelsTouchesInView = NO; longpressGesture.delegate = self; longpressGesture.minimumPressDuration = [getPreference(@"time_longPressTrigger") floatValue] / 1000; @@ -160,22 +175,13 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { self.scrollPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnTouchesScroll:)]; - self.scrollPanGesture.delegate = self; self.scrollPanGesture.allowedTouchTypes = @[@(UITouchTypeDirect)]; + self.scrollPanGesture.delegate = self; self.scrollPanGesture.minimumNumberOfTouches = 2; self.scrollPanGesture.maximumNumberOfTouches = 2; if (@available(iOS 13.4, *)) { [self.surfaceView addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]]; - - UIPanGestureRecognizer *mouseWheelGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnMouseScroll:)]; - mouseWheelGesture.delegate = self; - mouseWheelGesture.allowedScrollTypesMask = UIScrollTypeMaskDiscrete; - mouseWheelGesture.allowedTouchTypes = @[@(UITouchTypeIndirectPointer)]; - mouseWheelGesture.cancelsTouchesInView = NO; - mouseWheelGesture.delaysTouchesBegan = NO; - mouseWheelGesture.delaysTouchesEnded = NO; - [self.surfaceView addGestureRecognizer:mouseWheelGesture]; } // Virtual mouse @@ -253,13 +259,35 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { } } + [KeyboardInput initKeycodeTable]; + if (@available(iOS 14.0, tvOS 14.0, *)) { + self.mouseConnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Mouse connected!"); + GCMouse* mouse = note.object; + [self registerMouseCallbacks: mouse]; + [self setNeedsUpdateOfPrefersPointerLocked]; + }]; + self.mouseDisconnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Mouse disconnected!"); + GCMouse* mouse = note.object; + mouse.mouseInput.mouseMovedHandler = nil; + mouse.mouseInput.leftButton.pressedChangedHandler = nil; + mouse.mouseInput.middleButton.pressedChangedHandler = nil; + mouse.mouseInput.rightButton.pressedChangedHandler = nil; + [self setNeedsUpdateOfPrefersPointerLocked]; + }]; + if (GCMouse.current != nil) { + [self registerMouseCallbacks: GCMouse.current]; + } + } + [self.view addSubview:inputView]; [self executebtn_special_togglebtn:0]; // [self setPreferredFramesPerSecond:1000]; - [self setupGL]; + callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); } - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { @@ -270,10 +298,6 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { return NO; } -- (void)setupGL { - callback_SurfaceViewController_launchMinecraft(savedWidth * resolutionScale, savedHeight * resolutionScale); -} - #pragma mark - Input: send touch utilities @@ -291,17 +315,13 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (event == ACTION_MOVE) { virtualMouseFrame.origin.x += location.x - lastVirtualMousePoint.x; virtualMouseFrame.origin.y += location.y - lastVirtualMousePoint.y; - if (virtualMouseFrame.origin.x < 0) { - virtualMouseFrame.origin.x = 0; - } else if (virtualMouseFrame.origin.x > self.view.frame.size.width) { - virtualMouseFrame.origin.x = self.view.frame.size.width; - } - if (virtualMouseFrame.origin.y < 0) { - virtualMouseFrame.origin.y = 0; - } else if (virtualMouseFrame.origin.y > self.view.frame.size.height) { - virtualMouseFrame.origin.y = self.view.frame.size.height; - } + } else if (event == ACTION_MOVE_MOTION) { + event = ACTION_MOVE; + virtualMouseFrame.origin.x += location.x; + virtualMouseFrame.origin.y += location.y; } + virtualMouseFrame.origin.x = clamp(virtualMouseFrame.origin.x, 0, self.view.frame.size.width); + virtualMouseFrame.origin.y = clamp(virtualMouseFrame.origin.y, 0, self.view.frame.size.height); lastVirtualMousePoint = location; self.mousePointerView.frame = virtualMouseFrame; callback_SurfaceViewController_onTouch(event, virtualMouseFrame.origin.x * screenScale, virtualMouseFrame.origin.y * screenScale); @@ -312,6 +332,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { callback_SurfaceViewController_onTouch(event, location.x * screenScale, location.y * screenScale); } +#pragma mark - Input: on-surface functions + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } @@ -320,22 +342,15 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { { CGPoint locationInView = [touchEvent locationInView:self.view]; - BOOL isTouchTypeIndirect = NO; - if (@available(iOS 13.4, *)) { - if (touchEvent.type == UITouchTypeIndirectPointer) { - isTouchTypeIndirect = YES; - } - } - if (touchEvent.view == self.surfaceView) { - if (touchEvent == self.hotbarTouch && slideableHotbar && !isTouchTypeIndirect && ![self isTouchInactive:self.hotbarTouch]) { + if (touchEvent == self.hotbarTouch && slideableHotbar && ![self isTouchInactive:self.hotbarTouch]) { CGFloat screenScale = [[UIScreen mainScreen] scale]; int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); if (slot != -1 && currentHotbarSlot != slot && (event == ACTION_DOWN || currentHotbarSlot != -1)) { currentHotbarSlot = slot; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, slot, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, slot, 0, 0, 0); + CallbackBridge_nativeSendKey(slot, 0, 1, 0); + CallbackBridge_nativeSendKey(slot, 0, 0, 0); return; } /* else if ((event == ACTION_MOVE || event == ACTION_UP) && slot == -1 && currentHotbarSlot != -1) { return; @@ -357,56 +372,89 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { [self sendTouchPoint:locationInView withEvent:event]; } - if (!isTouchTypeIndirect) { - switch (event) { - case ACTION_DOWN: - touchesMovedCount = 0; - shouldTriggerClick = YES; - break; + switch (event) { + case ACTION_DOWN: + touchesMovedCount = 0; + shouldTriggerClick = YES; + break; - case ACTION_MOVE: - // TODO: better handling this - if (touchesMovedCount >= 1) { - shouldTriggerClick = NO; - } else ++touchesMovedCount; - break; - } - } else if (@available(iOS 13.4, *)) { - // Recheck @available for suppressing compile warnings - - // Mouse clicks are handled here - int held = event == ACTION_MOVE || event == ACTION_UP; - shouldTriggerClick = NO; - for (int i = 1; i <= 5; ++i) { - if ((uievent.buttonMask & (1 << ((i)-1))) != 0) { - // iOS button index = GLFW button index + 1; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, i - 1, held, 0); - } - } + case ACTION_MOVE: + // TODO: better handling this + if (touchesMovedCount >= 1) { + shouldTriggerClick = NO; + } else ++touchesMovedCount; + break; } } } -#pragma mark - Input: on-surface gestures +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event { + BOOL handled = NO; + + if (@available(iOS 13.4, *)) { + for (UIPress *press in presses) { + if (press.key != nil && [KeyboardInput sendKeyEvent:press.key down:YES]) { + handled = YES; + } + } + } + + if (!handled) { + [super pressesBegan:presses withEvent:event]; + } +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event { + BOOL handled = NO; + + if (@available(iOS 13.4, *)) { + for (UIPress *press in presses) { + if (press.key != nil && [KeyboardInput sendKeyEvent:press.key down:NO]) { + handled = YES; + } + } + } + + if (!handled) { + [super pressesEnded:presses withEvent:event]; + } +} + +- (void)registerMouseCallbacks:(GCMouse *)mouse API_AVAILABLE(ios(14.0)) { + NSLog(@"Input: Got mouse %@", mouse); + mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, pressed, 0); + }; + mouse.mouseInput.middleButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, pressed, 0); + }; + mouse.mouseInput.rightButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, pressed, 0); + }; + + mouse.mouseInput.scroll.xAxis.valueChangedHandler = ^(GCControllerAxisInput * _Nonnull axis, float value) { + CallbackBridge_nativeSendScroll(value, 0); + }; + mouse.mouseInput.scroll.yAxis.valueChangedHandler = ^(GCControllerAxisInput * _Nonnull axis, float value) { + CallbackBridge_nativeSendScroll(0, value); + }; + +} - (void)surfaceOnClick:(UITapGestureRecognizer *)sender { - if (sender.state == UIGestureRecognizerStateRecognized && - shouldTriggerClick == YES) { - CGFloat screenScale = [[UIScreen mainScreen] scale]; - CGPoint location = [sender locationInView:[sender.view superview]]; - currentHotbarSlot = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale); - + if (shouldTriggerClick == NO) return; + if (sender.state == UIGestureRecognizerStateRecognized) { if (currentHotbarSlot == -1) { inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, + CallbackBridge_nativeSendMouseButton( isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, + CallbackBridge_nativeSendMouseButton( isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 0, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, currentHotbarSlot, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, currentHotbarSlot, 0, 0, 0); + CallbackBridge_nativeSendKey(currentHotbarSlot, 0, 1, 0); + CallbackBridge_nativeSendKey(currentHotbarSlot, 0, 0, 0); } } } @@ -417,8 +465,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { CGPoint location = [sender locationInView:[sender.view superview]]; int hotbarSlot = callback_SurfaceViewController_touchHotbar(location.x * screenScale * resolutionScale, location.y * screenScale * resolutionScale); if (hotbarSlot != -1 && currentHotbarSlot == hotbarSlot) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_F, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_F, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_F, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_F, 0, 0, 0); } } } @@ -427,7 +475,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { if (@available(iOS 13.0, *)) { CGPoint point = [sender locationInView:self.surfaceView]; // NSLog(@"Mouse move!!"); - // NSLog(@"Mouse pos = %d, %d", point.x, point.y); + // NSLog(@"Mouse pos = %f, %f", point.x, point.y); switch (sender.state) { case UIGestureRecognizerStateBegan: [self sendTouchPoint:point withEvent:ACTION_DOWN]; @@ -458,9 +506,9 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 1, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 1, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_Q, 0, 1, 0); } } else if (sender.state == UIGestureRecognizerStateChanged) { // Nothing to do here, already handled in touchesMoved @@ -473,37 +521,15 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { inputView.text = INPUT_SPACE_CHAR; inputTextLength = 0; - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 0, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 0, 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 0, 0); + +CallbackBridge_nativeSendKey(GLFW_KEY_Q, 0, 0, 0); } } } } --(void)surfaceOnMouseScroll:(UIPanGestureRecognizer *)sender API_AVAILABLE(ios(13.4)) -{ - if (sender.state == UIGestureRecognizerStateBegan || - sender.state == UIGestureRecognizerStateChanged || - sender.state == UIGestureRecognizerStateEnded) { - CGPoint velocity = [sender velocityInView:self.view]; - - if (velocity.x > 0.0f) { - velocity.x = -1.0; - } else if (velocity.x < 0.0f) { - velocity.x = 1.0f; - } - if (velocity.y > 0.0f) { - velocity.y = -1.0; - } else if (velocity.y < 0.0f) { - velocity.y = 1.0f; - } - if (velocity.x != 0.0f || velocity.y != 0.0f) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, (jdouble) velocity.x * 4.0, (jdouble) velocity.y * 4.0); - } - } -} - - (void)surfaceOnTouchesScroll:(UIPanGestureRecognizer *)sender { if (isGrabbing) return; if (sender.state == UIGestureRecognizerStateBegan || @@ -511,33 +537,20 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { sender.state == UIGestureRecognizerStateEnded) { CGPoint velocity = [sender velocityInView:self.view]; if (velocity.x != 0.0f || velocity.y != 0.0f) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, (jdouble) (velocity.x/10.0), (jdouble) (velocity.y/10.0)); + CallbackBridge_nativeSendScroll((CGFloat) (velocity.x/10.0), (CGFloat) (velocity.y/10.0)); } } } // 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; - CGPoint point = request.location; - - point.x -= origin.x; - point.y -= origin.y; - - NSLog(@"UIPointerInteraction pos changed: x=%d, y=%d", (int) point.x, (int) point.y); - - callback_SurfaceViewController_onTouch(ACTION_DOWN, (int)point.x, (int)point.y); - } - return [UIPointerRegion regionWithRect:self.surfaceView.bounds identifier:nil]; + NSLog(@"regionForRequest called"); + return nil; } - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)){ - if (isGrabbing == JNI_FALSE) { - return nil; - } else { - return [UIPointerStyle hiddenPointerStyle]; - } + NSLog(@"styleForRegion called"); + return [UIPointerStyle hiddenPointerStyle]; } #pragma mark - Input view stuff @@ -545,8 +558,8 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { NSString* inputStringBefore; -(void)inputViewDidChange { if ([inputView.text length] < INPUT_SPACE_LENGTH) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0); inputView.text = [@" " stringByAppendingString:inputView.text]; if (inputTextLength > 0) { @@ -565,9 +578,9 @@ NSString* inputStringBefore; jchar theChar = (jchar) [newText characterAtIndex:i]; if (isUseStackQueueCall) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, theChar, /* mods */ 0); + CallbackBridge_nativeSendCharMods(theChar, /* mods */ 0); } else { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(NULL, NULL, theChar); + CallbackBridge_nativeSendChar(theChar); } inputView.text = [inputView.text substringFromIndex:1]; @@ -599,12 +612,12 @@ NSString* inputStringBefore; */ for (int i2 = 0; i2 < [inputStringNow length]; i2++) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0); } for (int i2 = 0; i2 < [inputStringNow length]; i2++) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0); + CallbackBridge_nativeSendCharMods((jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0); } break; @@ -632,8 +645,8 @@ NSString* inputStringBefore; } -(BOOL)textFieldShouldReturn:(UITextField *)textField { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_ENTER, 0, 1, 0); - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_ENTER, 0, 0, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_ENTER, 0, 1, 0); + CallbackBridge_nativeSendKey(GLFW_KEY_ENTER, 0, 0, 0); return YES; } @@ -656,15 +669,15 @@ int currentVisibility = 1; break; case SPECIALBTN_MOUSEPRI: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, held, 0); break; case SPECIALBTN_MOUSESEC: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_RIGHT, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, held, 0); break; case SPECIALBTN_MOUSEMID: - Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_MIDDLE, held, 0); + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, held, 0); break; case SPECIALBTN_TOGGLECTRL: @@ -673,13 +686,13 @@ int currentVisibility = 1; case SPECIALBTN_SCROLLDOWN: if (!held) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, 0.0, 1.0); + CallbackBridge_nativeSendScroll(0.0, 1.0); } break; case SPECIALBTN_SCROLLUP: if (!held) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(NULL, NULL, 0.0, -1.0); + CallbackBridge_nativeSendScroll(0.0, -1.0); } case SPECIALBTN_VIRTUALMOUSE: @@ -697,7 +710,8 @@ int currentVisibility = 1; // there's no key id 0, but we accidentally used -1 as a special key id, so we had to do that // if (keycode == 0) { keycode = -1; } // at the moment, send unknown keycode does nothing, may even cause performance issue, so ignore it - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, keycode, 0, held, 0); + +CallbackBridge_nativeSendKey(keycode, 0, held, 0); } } } @@ -766,6 +780,11 @@ int touchesMovedCount; [super touchesBegan:touches withEvent:event]; int i = 0; for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } CGPoint locationInView = [touch locationInView:self.view]; CGFloat screenScale = [[UIScreen mainScreen] scale]; int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale); @@ -786,6 +805,11 @@ int touchesMovedCount; [super touchesMoved:touches withEvent:event]; for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } if (self.hotbarTouch != touch && [self isTouchInactive:self.primaryTouch]) { // Replace the inactive touch with the current active touch self.primaryTouch = touch; @@ -799,6 +823,11 @@ int touchesMovedCount; - (void)touchesEndedGlobal:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { + if (@available(iOS 14.0, *)) { // 13.4 + if (touch.type == UITouchTypeIndirectPointer) { + continue; // handle this in a different place + } + } [self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_UP]; } } diff --git a/Natives/input_bridge_v3.m b/Natives/input_bridge_v3.m index 467242b9..72923977 100644 --- a/Natives/input_bridge_v3.m +++ b/Natives/input_bridge_v3.m @@ -287,7 +287,7 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeIsGrabbing(J return isGrabbing; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNIEnv* env, jclass clazz, jchar codepoint /* jint codepoint */) { +BOOL CallbackBridge_nativeSendChar(jchar codepoint /* jint codepoint */) { if (GLFW_invoke_Char && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR, codepoint, 0, 0, 0); @@ -295,21 +295,21 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(JNI GLFW_invoke_Char((void*) showingWindow, (unsigned int) codepoint); // return lwjgl2_triggerCharEvent(codepoint); } - return JNI_TRUE; + return YES; } - return JNI_FALSE; + return NO; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(JNIEnv* env, jclass clazz, jchar codepoint, jint mods) { +BOOL CallbackBridge_nativeSendCharMods(jchar codepoint, int mods) { if (GLFW_invoke_CharMods && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR_MODS, (unsigned int) codepoint, mods, 0, 0); } else { GLFW_invoke_CharMods((void*) showingWindow, codepoint, mods); } - return JNI_TRUE; + return YES; } - return JNI_FALSE; + return NO; } /* JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter(JNIEnv* env, jclass clazz, jint entered) { @@ -318,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, jfloat x, jfloat y) { +void CallbackBridge_nativeSendCursorPos(CGFloat x, CGFloat y) { if (GLFW_invoke_CursorPos && isInputReady) { if (!isCursorEntered) { if (GLFW_invoke_CursorEnter) { @@ -361,7 +361,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JN } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* env, jclass clazz, jint key, jint scancode, jint action, jint mods) { +void CallbackBridge_nativeSendKey(int key, int scancode, int action, int mods) { if (GLFW_invoke_Key && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_KEY, key, scancode, action, mods); @@ -371,16 +371,16 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(JNIEnv* } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKeycode(JNIEnv* env, jclass clazz, jint keycode, jchar keychar, jint scancode, jint action, jint mods) { +void CallbackBridge_nativeSendKeycode(int keycode, char keychar, int scancode, int action, int mods) { if (isInputReady) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(env, clazz, keycode, scancode, action, mods); - if (!Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(env, clazz, keychar, mods)) { - Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(env, clazz, keychar); + CallbackBridge_nativeSendKey(keycode, scancode, action, mods); + if (!CallbackBridge_nativeSendCharMods(keychar, mods)) { + CallbackBridge_nativeSendChar(keychar); } } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(JNIEnv* env, jclass clazz, jint button, jint action, jint mods) { +void CallbackBridge_nativeSendMouseButton(int button, int action, int mods) { if (isInputReady) { if (button == -1) { // Notify to prepare set new grab pos @@ -395,7 +395,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton( } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(JNIEnv* env, jclass clazz, jint width, jint height) { +void CallbackBridge_nativeSendScreenSize(int width, int height) { savedWidth = width; savedHeight = height; @@ -420,7 +420,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(J // return (isInputReady && (GLFW_invoke_FramebufferSize || GLFW_invoke_WindowSize)); } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEnv* env, jclass clazz, jdouble xoffset, jdouble yoffset) { +void CallbackBridge_nativeSendScroll(CGFloat xoffset, CGFloat yoffset) { if (GLFW_invoke_Scroll && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_SCROLL, xoffset, yoffset, 0, 0); @@ -430,7 +430,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEn } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendWindowPos(JNIEnv* env, jclass clazz, jint x, jint y) { +void CallbackBridge_nativeSendWindowPos(int x, int y) { if (GLFW_invoke_WindowPos && isInputReady) { if (isUseStackQueueCall) { sendData(EVENT_TYPE_WINDOW_POS, x, y, 0, 0); @@ -444,3 +444,10 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(JNIEnv* en showingWindow = (long) window; } +void CallbackBridge_sendKeycode(int keycode, jchar keychar, int scancode, int modifiers, BOOL isDown) { + if(keycode != 0) CallbackBridge_nativeSendKey(keycode,scancode,isDown ? 1 : 0, modifiers); + if(isDown && keychar != '\0') { + CallbackBridge_nativeSendCharMods(keychar, modifiers); + CallbackBridge_nativeSendChar(keychar); + } +} diff --git a/Natives/ios_uikit_bridge.m b/Natives/ios_uikit_bridge.m index 642c8601..1f406a3c 100644 --- a/Natives/ios_uikit_bridge.m +++ b/Natives/ios_uikit_bridge.m @@ -156,10 +156,9 @@ void UIKit_launchMinecraftSurfaceVC() { usleep(1000); exit(0); } else { - UIViewController *rootController = UIApplication.sharedApplication.windows.lastObject.rootViewController; SurfaceViewController *vc = [[SurfaceViewController alloc] init]; vc.modalPresentationStyle = UIModalPresentationFullScreen; - [rootController presentViewController:vc animated:YES completion:nil]; + [viewController.navigationController pushViewController:vc animated:YES]; } }); } diff --git a/Natives/utils.h b/Natives/utils.h index 21b8d89c..5d4db85d 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -7,6 +7,7 @@ #define ACTION_DOWN 0 #define ACTION_UP 1 #define ACTION_MOVE 2 +#define ACTION_MOVE_MOTION 3 #define BUTTON1_DOWN_MASK 1 << 10 // left btn #define BUTTON2_DOWN_MASK 1 << 11 // mid btn @@ -56,6 +57,9 @@ int savedWidth, savedHeight; BOOL virtualMouseEnabled; +static inline CGFloat clamp(CGFloat x, CGFloat lower, CGFloat upper) { + return fmin(upper, fmax(x, lower)); +} 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); @@ -76,14 +80,13 @@ void callback_SurfaceViewController_launchMinecraft(int width, int height); 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, 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); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(JNIEnv* env, jclass clazz, jint width, jint height); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEnv* env, jclass clazz, jdouble xoffset, jdouble yoffset); -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendWindowPos(JNIEnv* env, jclass clazz, jint x, jint y); - - +BOOL CallbackBridge_nativeSendChar(jchar codepoint /* jint codepoint */); +BOOL CallbackBridge_nativeSendCharMods(jchar codepoint, int mods); +void CallbackBridge_nativeSendCursorPos(CGFloat x, CGFloat y); +void CallbackBridge_nativeSendKey(int key, int scancode, int action, int mods); +void CallbackBridge_nativeSendKeycode(int keycode, char keychar, int scancode, int action, int mods); +void CallbackBridge_nativeSendMouseButton(int button, int action, int mods); +void CallbackBridge_nativeSendScreenSize(int width, int height); +void CallbackBridge_nativeSendScroll(CGFloat xoffset, CGFloat yoffset); +void CallbackBridge_nativeSendWindowPos(jint x, jint y); +void CallbackBridge_sendKeycode(int keycode, jchar keychar, int scancode, int modifiers, BOOL isDown);