660 lines
24 KiB
Objective-C
660 lines
24 KiB
Objective-C
#import "SurfaceViewController.h"
|
|
#import "egl_bridge_ios.h"
|
|
#import "ios_uikit_bridge.h"
|
|
|
|
#import "customcontrols/ControlButton.h"
|
|
|
|
#include "glfw_keycodes.h"
|
|
#include "utils.h"
|
|
|
|
#include "EGL/egl.h"
|
|
|
|
#include "GLES2/gl2.h"
|
|
#include "GLES2/gl2ext.h"
|
|
|
|
#define SPECIALBTN_KEYBOARD -1
|
|
#define SPECIALBTN_TOGGLECTRL -2
|
|
#define SPECIALBTN_MOUSEPRI -3
|
|
#define SPECIALBTN_MOUSESEC -4
|
|
#define SPECIALBTN_VIRTUALMOUSE -5
|
|
#define SPECIALBTN_MOUSEMID -6
|
|
#define SPECIALBTN_SCROLLUP -7
|
|
#define SPECIALBTN_SCROLLDOWN -8
|
|
|
|
|
|
// Debugging purposes
|
|
// #define DEBUG_VISIBLE_TEXT_FIELD
|
|
|
|
#define ADD_BUTTON(NAME, KEY, RECT, VISIBLE) \
|
|
ControlButton *button_##KEY = [ControlButton initWithName:NAME keycode:KEY rect:CGRectOffset(RECT, notchOffset, 0) transparency:0.0f]; \
|
|
[button_##KEY addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown]; \
|
|
[button_##KEY addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside]; \
|
|
[button_##KEY addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpOutside]; \
|
|
[self.view addSubview:button_##KEY]; \
|
|
if (VISIBLE == YES) { \
|
|
togglableVisibleButtons[++togglableVisibleButtonIndex] = button_##KEY; \
|
|
}
|
|
|
|
#define BTN_RECT 80.0, 30.0
|
|
#define BTN_SQUARE 50.0, 50.0
|
|
#define INPUT_SPACE_CHAR @" "
|
|
#define INPUT_SPACE_LENGTH 20
|
|
|
|
int togglableVisibleButtonIndex = -1;
|
|
ControlButton* togglableVisibleButtons[100];
|
|
|
|
UIView *touchView;
|
|
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
|
UILabel *inputLengthView;
|
|
#endif
|
|
UITextField *inputView;
|
|
int inputTextLength;
|
|
|
|
BOOL shouldTriggerClick = NO;
|
|
int notchOffset;
|
|
|
|
// TODO: key modifiers impl
|
|
|
|
@interface SurfaceViewController ()<UITextFieldDelegate> {
|
|
}
|
|
|
|
@property (strong, nonatomic) MGLContext *context;
|
|
|
|
- (void)setupGL;
|
|
|
|
@end
|
|
|
|
@implementation SurfaceViewController
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
if(@available(iOS 12.0, *)) {
|
|
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
|
|
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
|
}
|
|
|
|
CGRect screenBounds = [[UIScreen mainScreen] bounds];
|
|
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
|
|
|
UIEdgeInsets insets = [[[UIApplication sharedApplication] keyWindow] safeAreaInsets];
|
|
|
|
int width = (int) roundf(screenBounds.size.width);
|
|
int height = (int) roundf(screenBounds.size.height);
|
|
|
|
savedWidth = roundf(width * screenScale);
|
|
savedHeight = roundf(height * screenScale);
|
|
|
|
width = width - insets.left - insets.right;
|
|
notchOffset = insets.left;
|
|
|
|
touchView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
|
|
|
|
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnClick:)];
|
|
tapGesture.numberOfTapsRequired = 1;
|
|
tapGesture.numberOfTouchesRequired = 1;
|
|
tapGesture.cancelsTouchesInView = NO;
|
|
[touchView addGestureRecognizer:tapGesture];
|
|
|
|
UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnLongpress:)];
|
|
longpressGesture.minimumPressDuration = 0.4;
|
|
[touchView addGestureRecognizer:longpressGesture];
|
|
|
|
[self.view addSubview:touchView];
|
|
|
|
if (NSClassFromString(@"UIPointerInteraction") != nil) {
|
|
[touchView addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]];
|
|
}
|
|
|
|
if (@available(iOS 13.4, *)) {
|
|
UIPanGestureRecognizer *mouseWheelGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnMouseScroll:)];
|
|
mouseWheelGesture.allowedScrollTypesMask = UIScrollTypeMaskDiscrete;
|
|
mouseWheelGesture.allowedTouchTypes = @[ @(UITouchTypeIndirectPointer) ];
|
|
mouseWheelGesture.cancelsTouchesInView = NO;
|
|
mouseWheelGesture.delaysTouchesBegan = NO;
|
|
mouseWheelGesture.delaysTouchesEnded = NO;
|
|
[touchView addGestureRecognizer:mouseWheelGesture];
|
|
}
|
|
|
|
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputView = [[UITextField alloc] initWithFrame:CGRectMake(5 * 3 + 80 * 2, 5, BTN_RECT)];
|
|
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
|
|
#else
|
|
inputView = [[UITextField alloc] initWithFrame:CGRectMake(5 * 3 + 80 * 2, 5 * 2 + 30, 200, 30)];
|
|
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
|
|
|
|
inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + 80, 5 * 2 + 30, BTN_RECT)];
|
|
inputLengthView.text = @"length=?";
|
|
inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f];
|
|
[self.view addSubview:inputLengthView];
|
|
#endif
|
|
inputView.delegate = self;
|
|
[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));
|
|
|
|
// Temporary fallback controls
|
|
BOOL cc_fallback = YES;
|
|
|
|
FILE *cc_file = fopen("/var/mobile/Documents/.pojavlauncher/controlmap/default.json", "r");
|
|
|
|
// 100kb (might not safe)
|
|
char cc_data[102400];
|
|
long cc_size;
|
|
if (cc_file) {
|
|
fseek(cc_file, 0L, SEEK_END);
|
|
cc_size = ftell(cc_file);
|
|
rewind(cc_file);
|
|
}
|
|
|
|
NSError *cc_error;
|
|
if (cc_size > 102400) {
|
|
NSLog(@"Error: control data is too big (over 100kb).");
|
|
fclose(cc_file);
|
|
} else if (!cc_file || !fread(cc_data, cc_size, 1, cc_file)) {
|
|
NSLog(@"Error: could not read \"default.json\", falling back to default control, error: %s", strerror(errno));
|
|
fclose(cc_file);
|
|
} else {
|
|
fclose(cc_file);
|
|
NSData* cc_objc_data = [@(cc_data) dataUsingEncoding:NSUTF8StringEncoding];
|
|
NSDictionary *cc_dictionary = [NSJSONSerialization JSONObjectWithData:cc_objc_data options:kNilOptions error:&cc_error];
|
|
if (cc_error != nil) {
|
|
showDialog(self, @"Error parsing JSON", cc_error.localizedDescription);
|
|
} else {
|
|
NSArray *cc_controlDataList = (NSArray *) [cc_dictionary valueForKey:@"mControlDataList"];
|
|
for (int i = 0; i < (int) cc_controlDataList.count; i++) {
|
|
ControlButton *button = [ControlButton initWithProperties:(NSMutableDictionary *)cc_controlDataList[i]];
|
|
[button addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown];
|
|
[button addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside];
|
|
[button addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpOutside];
|
|
[self.view addSubview:button];
|
|
if ([(NSNumber *) [button.properties valueForKey:@"keycode"] intValue] != SPECIALBTN_TOGGLECTRL) {
|
|
togglableVisibleButtons[++togglableVisibleButtonIndex] = button;
|
|
}
|
|
}
|
|
cc_fallback = NO;
|
|
}
|
|
}
|
|
|
|
if (cc_fallback == YES) {
|
|
ADD_BUTTON(@"GUI", SPECIALBTN_TOGGLECTRL, CGRectMake(5, height - 5 - 50, BTN_SQUARE), NO);
|
|
ADD_BUTTON(@"Keyboard", SPECIALBTN_KEYBOARD, CGRectMake(5 * 3 + 80 * 2, 5, BTN_RECT), YES);
|
|
|
|
ADD_BUTTON(@"Pri", SPECIALBTN_MOUSEPRI, CGRectMake(5, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"Sec", SPECIALBTN_MOUSESEC, CGRectMake(5 * 3 + 50 * 2, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
|
|
|
ADD_BUTTON(@"Debug", GLFW_KEY_F3, CGRectMake(5, 5, BTN_RECT), YES);
|
|
ADD_BUTTON(@"Chat", GLFW_KEY_T, CGRectMake(5 * 2 + 80, 5, BTN_RECT), YES);
|
|
ADD_BUTTON(@"Tab", GLFW_KEY_TAB, CGRectMake(5 * 4 + 80 * 3, 5, BTN_RECT), YES);
|
|
ADD_BUTTON(@"Opti-Zoom", GLFW_KEY_C, CGRectMake(5 * 5 + 80 * 4, 5, BTN_RECT), YES);
|
|
ADD_BUTTON(@"Offhand", GLFW_KEY_F, CGRectMake(5 * 6 + 80 * 5, 5, BTN_RECT), YES);
|
|
ADD_BUTTON(@"3rd", GLFW_KEY_F5, CGRectMake(5, 5 * 2 + 30.0, BTN_RECT), YES);
|
|
|
|
ADD_BUTTON(@"▲", GLFW_KEY_W, CGRectMake(5 * 2 + 50, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"◀", GLFW_KEY_A, CGRectMake(5, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"▼", GLFW_KEY_S, CGRectMake(5 * 2 + 50, height - 5 - 50, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"▶", GLFW_KEY_D, CGRectMake(5 * 3 + 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"◇", GLFW_KEY_LEFT_SHIFT, CGRectMake(5 * 2 + 50, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
|
ADD_BUTTON(@"Inv", GLFW_KEY_E, CGRectMake(5 * 3 + 50 * 2, height - 5 - 50, BTN_SQUARE), YES);
|
|
|
|
ADD_BUTTON(@"⬛", GLFW_KEY_SPACE, CGRectMake(width - 5 * 2 - 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
|
|
|
ADD_BUTTON(@"Esc", GLFW_KEY_ESCAPE, CGRectMake(width - 5 - 80, height - 5 - 30, BTN_RECT), YES);
|
|
|
|
// ADD_BUTTON(@"Fullscreen", f11, CGRectMake(width - 5 - 80, 5, BTN_RECT), YES);
|
|
}
|
|
|
|
[self.view addSubview:inputView];
|
|
|
|
[self executebtn_special_togglebtn:0];
|
|
|
|
viewController = self;
|
|
|
|
MGLKView *view = glView = (MGLKView *) self.view;
|
|
view.drawableDepthFormat = MGLDrawableDepthFormat24;
|
|
view.enableSetNeedsDisplay = YES;
|
|
// [self setPreferredFramesPerSecond:1000];
|
|
|
|
// Init GLES
|
|
self.context = [[MGLContext alloc] initWithAPI:kMGLRenderingAPIOpenGLES3];
|
|
|
|
if (!self.context) {
|
|
self.context = [[MGLContext alloc] initWithAPI:kMGLRenderingAPIOpenGLES2];
|
|
}
|
|
|
|
if (!self.context) {
|
|
NSLog(@"Failed to create ES context");
|
|
}
|
|
|
|
view.context = self.context;
|
|
#ifndef USE_EGL
|
|
glContext = self.context;
|
|
#endif
|
|
|
|
[MGLContext setCurrentContext:self.context];
|
|
|
|
[self setupGL];
|
|
}
|
|
|
|
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures
|
|
{
|
|
return UIRectEdgeAll;
|
|
}
|
|
|
|
- (BOOL)prefersHomeIndicatorAutoHidden
|
|
{
|
|
return NO;
|
|
}
|
|
#pragma mark - MetalANGLE stuff
|
|
|
|
- (void)dealloc
|
|
{
|
|
if ([MGLContext currentContext] == self.context) {
|
|
[MGLContext setCurrentContext:nil];
|
|
}
|
|
}
|
|
|
|
- (void)setupGL
|
|
{
|
|
[MGLContext setCurrentContext:self.context];
|
|
|
|
CGRect screenBounds = [[UIScreen mainScreen] bounds];
|
|
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
|
|
|
int width = (int) roundf(screenBounds.size.width * screenScale);
|
|
int height = (int) roundf(screenBounds.size.height * screenScale);
|
|
callback_SurfaceViewController_launchMinecraft(width, height);
|
|
}
|
|
|
|
BOOL isNotifRemoved;
|
|
- (void)mglkView:(MGLKView *)view drawInRect:(CGRect)rect
|
|
{
|
|
// glClearColor(0.6f, 0.6f, 0.6f, 1.0f);
|
|
// glClear(GL_COLOR_BUFFER_BIT);
|
|
// [self setNeedsDisplay]
|
|
// NSLog(@"swapbuffer");
|
|
|
|
// Remove notifications, so rendering will be manually controlled!
|
|
if (isNotifRemoved == NO) {
|
|
isNotifRemoved = YES;
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
|
name:MGLKApplicationWillResignActiveNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
|
name:MGLKApplicationDidBecomeActiveNotification
|
|
object:nil];
|
|
}
|
|
|
|
[super pause];
|
|
|
|
// Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(NULL, NULL, location.x * screenScale, location.y * screenScale);
|
|
}
|
|
|
|
#pragma mark - Input: send touch utilities
|
|
|
|
- (void)sendTouchPoint:(CGPoint)location withEvent:(int)event
|
|
{
|
|
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
|
if (callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale) == -1) {
|
|
callback_SurfaceViewController_onTouch(event, location.x * screenScale, location.y * screenScale);
|
|
}
|
|
}
|
|
|
|
- (void)sendTouchEvent:(NSSet *)touches withUIEvent:(UIEvent *)uievent withEvent:(int)event
|
|
{
|
|
UITouch* touchEvent = [touches anyObject];
|
|
|
|
BOOL isTouchTypeIndirect = NO;
|
|
if (@available(iOS 13.4, *)) {
|
|
if (touchEvent.type == UITouchTypeIndirectPointer) {
|
|
isTouchTypeIndirect = YES;
|
|
}
|
|
}
|
|
|
|
if ([touchEvent view] == touchView) {
|
|
CGPoint locationInView = [touchEvent locationInView:touchView];
|
|
[self sendTouchPoint:locationInView withEvent:event];
|
|
}
|
|
|
|
if (!isTouchTypeIndirect) {
|
|
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 fix 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - Input: on-surface gestures
|
|
|
|
- (void)surfaceOnClick:(UITapGestureRecognizer *)sender {
|
|
if (sender.state == UIGestureRecognizerStateRecognized &&
|
|
shouldTriggerClick == YES) {
|
|
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
|
CGPoint location = [sender locationInView:[sender.view superview]];
|
|
int hotbarItem = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale);
|
|
|
|
if (hotbarItem == -1) {
|
|
inputView.text = INPUT_SPACE_CHAR;
|
|
inputTextLength = 0;
|
|
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL,
|
|
isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 1, 0);
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL,
|
|
isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 0, 0);
|
|
} else {
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, hotbarItem, 0, 1, 0);
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, hotbarItem, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)surfaceOnHover:(UIHoverGestureRecognizer *)sender API_AVAILABLE(ios(13.0)) {
|
|
if (@available(iOS 13.0, *)) {
|
|
CGPoint point = [sender locationInView:touchView];
|
|
// NSLog(@"Mouse move!!");
|
|
// NSLog(@"Mouse pos = %d, %d", point.x, point.y);
|
|
switch (sender.state) {
|
|
case UIGestureRecognizerStateBegan:
|
|
[self sendTouchPoint:point withEvent:ACTION_DOWN];
|
|
break;
|
|
case UIGestureRecognizerStateChanged:
|
|
[self sendTouchPoint:point withEvent:ACTION_MOVE];
|
|
break;
|
|
case UIGestureRecognizerStateEnded:
|
|
case UIGestureRecognizerStateCancelled:
|
|
[self sendTouchPoint:point withEvent:ACTION_UP];
|
|
break;
|
|
default:
|
|
// point = CGPointMake(-1, -1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void)surfaceOnLongpress:(UILongPressGestureRecognizer *)sender
|
|
{
|
|
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
|
CGPoint location = [sender locationInView:[sender.view superview]];
|
|
int hotbarItem = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale);
|
|
if (sender.state == UIGestureRecognizerStateBegan) {
|
|
if (hotbarItem == -1) {
|
|
inputView.text = INPUT_SPACE_CHAR;
|
|
inputTextLength = 0;
|
|
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 1, 0);
|
|
} else {
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 1, 0);
|
|
}
|
|
} else if (sender.state == UIGestureRecognizerStateChanged) {
|
|
if (hotbarItem == -1) {
|
|
[self sendTouchPoint:location withEvent:ACTION_MOVE];
|
|
}
|
|
} else {
|
|
if (sender.state == UIGestureRecognizerStateCancelled
|
|
|| sender.state == UIGestureRecognizerStateFailed
|
|
|| sender.state == UIGestureRecognizerStateEnded)
|
|
{
|
|
if (hotbarItem == -1) {
|
|
inputView.text = INPUT_SPACE_CHAR;
|
|
inputTextLength = 0;
|
|
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 0, 0);
|
|
} else {
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, 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];
|
|
|
|
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, (jdouble) velocity.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (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 = touchView.bounds.origin;
|
|
CGPoint point = request.location;
|
|
|
|
point.x -= origin.x;
|
|
point.y -= origin.y;
|
|
|
|
NSLog(@"UIPointerInteraction pos changed: x=%d, y=%d", point.x, point.y);
|
|
|
|
// TODO FIXME
|
|
callback_SurfaceViewController_onTouch(ACTION_DOWN, (int)point.x, (int)point.y);
|
|
}
|
|
return [UIPointerRegion regionWithRect:touchView.bounds identifier:nil];
|
|
}
|
|
|
|
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)){
|
|
if (isGrabbing == JNI_FALSE) {
|
|
return nil;
|
|
} else {
|
|
return [UIPointerStyle hiddenPointerStyle];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Input view stuff
|
|
|
|
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);
|
|
inputView.text = [@" " stringByAppendingString:inputView.text];
|
|
|
|
if (inputTextLength > 0) {
|
|
--inputTextLength;
|
|
}
|
|
|
|
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
|
|
inputTextLength];
|
|
#endif
|
|
} else if ([inputView.text length] > INPUT_SPACE_LENGTH) {
|
|
NSString *newText = [inputView.text substringFromIndex:INPUT_SPACE_LENGTH];
|
|
int charLength = [newText length];
|
|
for (int i = 0; i < charLength; i++) {
|
|
// Directly convert unichar to jchar which both are in UTF-16 encoding.
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [newText characterAtIndex:i] /* charText[i] */, /* mods */ 0);
|
|
inputView.text = [inputView.text substringFromIndex:1];
|
|
if (inputTextLength < INPUT_SPACE_LENGTH) {
|
|
++inputTextLength;
|
|
}
|
|
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
|
|
inputTextLength];
|
|
#endif
|
|
}
|
|
inputStringBefore = inputView.text;
|
|
// [inputView.text substringFromIndex:inputTextLength - 1];
|
|
} else {
|
|
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
|
NSLog(@"Compare \"%@\" vs \"%@\"", inputView.text, inputStringBefore);
|
|
#endif
|
|
for (int i = 0; i < INPUT_SPACE_LENGTH; i++) {
|
|
if ([inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) {
|
|
NSString *inputStringNow = [inputView.text substringFromIndex:i];
|
|
/*
|
|
inputView.text = [inputView.text substringToIndex:i];
|
|
// self notify
|
|
[self inputViewDidChange];
|
|
|
|
inputView.text = [inputView.text stringByAppendingString:inputStringNow];
|
|
// self notify
|
|
[self inputViewDidChange];
|
|
*/
|
|
|
|
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);
|
|
}
|
|
|
|
for (int i2 = 0; i2 < [inputStringNow length]; i2++) {
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputLengthView.text = @"length =";
|
|
#endif
|
|
inputStringBefore = inputView.text;
|
|
// [inputView.text substringFromIndex:inputTextLength - 1];
|
|
}
|
|
|
|
// Reset to default value
|
|
// inputView.text = INPUT_SPACE_CHAR;
|
|
}
|
|
|
|
-(void)inputViewDidClick {
|
|
// Zero the input field so user will no longer able to select text inside.
|
|
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputView.alpha = 0.0f;
|
|
#endif
|
|
inputView.text = INPUT_SPACE_CHAR;
|
|
inputTextLength = 0;
|
|
}
|
|
|
|
-(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);
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - On-screen button functions
|
|
|
|
int currentVisibility = 1;
|
|
- (void) executebtn:(UIButton *)sender withAction:(int)action {
|
|
ControlButton *button = (ControlButton *)sender;
|
|
int held = action == ACTION_DOWN;
|
|
int keycode = [(NSNumber *) [button.properties valueForKey:@"keycode"] intValue];
|
|
if (keycode < 0) {
|
|
switch (keycode) {
|
|
case SPECIALBTN_KEYBOARD:
|
|
if (held == 0) {
|
|
[inputView resignFirstResponder];
|
|
inputView.alpha = 1.0f;
|
|
inputView.text = @"";
|
|
}
|
|
break;
|
|
|
|
case SPECIALBTN_MOUSEPRI:
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, held, 0);
|
|
break;
|
|
|
|
case SPECIALBTN_MOUSESEC:
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_RIGHT, held, 0);
|
|
break;
|
|
|
|
case SPECIALBTN_MOUSEMID:
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_MIDDLE, held, 0);
|
|
break;
|
|
|
|
case SPECIALBTN_TOGGLECTRL:
|
|
[self executebtn_special_togglebtn:held];
|
|
break;
|
|
}
|
|
} else {
|
|
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, keycode, 0, held, 0);
|
|
}
|
|
}
|
|
|
|
- (void) executebtn_down:(UIButton *)sender {
|
|
[self executebtn:sender withAction:ACTION_DOWN];
|
|
}
|
|
|
|
- (void) executebtn_up:(UIButton *)sender {
|
|
[self executebtn:sender withAction:ACTION_UP];
|
|
}
|
|
|
|
- (void) executebtn_special_togglebtn:(int)held {
|
|
if (held == 0) {
|
|
currentVisibility = !currentVisibility;
|
|
for (int i = 0; i < togglableVisibleButtonIndex + 1; i++) {
|
|
togglableVisibleButtons[i].hidden = currentVisibility;
|
|
}
|
|
|
|
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
|
inputView.hidden = currentVisibility;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#pragma mark - Input: On-screen touch events
|
|
|
|
int touchesMovedCount;
|
|
// Equals to Android ACTION_DOWN
|
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[super touchesBegan: touches withEvent: event];
|
|
[self sendTouchEvent: touches withUIEvent: event withEvent: ACTION_DOWN];
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
|
|
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[super touchesCancelled: touches withEvent: event];
|
|
[self sendTouchEvent: touches withUIEvent: event withEvent: ACTION_UP];
|
|
}
|
|
|
|
@end
|