Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher_iOS
Path: blob/main/Natives/JavaGUIViewController.m
589 views
1
#import "customcontrols/ControlLayout.h"
2
#import "customcontrols/CustomControlsUtils.h"
3
#import "JavaGUIViewController.h"
4
#import "JavaLauncher.h"
5
#import "LauncherPreferences.h"
6
#import "PLLogOutputView.h"
7
#import "TrackedTextField.h"
8
#import "UnzipKit.h"
9
#import "ios_uikit_bridge.h"
10
#include "glfw_keycodes.h"
11
#include "utils.h"
12
13
#define SPECIALBTN_LOGOUTPUT -100
14
15
static BOOL shouldHitEnterAfterWindowShown;
16
static SurfaceView* surfaceView;
17
18
static jclass class_CTCAndroidInput;
19
static jmethodID method_ReceiveInput;
20
21
void AWTInputBridge_nativeSendData(int type, int i1, int i2, int i3, int i4) {
22
if (!runtimeJNIEnvPtr) {
23
return;
24
}
25
26
if (!method_ReceiveInput) {
27
class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/java/openjdk/cacio/ctc/CTCAndroidInput");
28
if ((*runtimeJNIEnvPtr)->ExceptionCheck(runtimeJNIEnvPtr) == JNI_TRUE) {
29
(*runtimeJNIEnvPtr)->ExceptionClear(runtimeJNIEnvPtr);
30
class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "com/github/caciocavallosilano/cacio/ctc/CTCAndroidInput");
31
}
32
assert(class_CTCAndroidInput != NULL);
33
method_ReceiveInput = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, class_CTCAndroidInput, "receiveData", "(IIIII)V");
34
assert(method_ReceiveInput != NULL);
35
}
36
37
(*runtimeJNIEnvPtr)->CallStaticVoidMethod(
38
runtimeJNIEnvPtr,
39
class_CTCAndroidInput,
40
method_ReceiveInput,
41
type, i1, i2, i3, i4
42
);
43
}
44
45
void AWTInputBridge_sendChar(jchar keychar) {
46
AWTInputBridge_nativeSendData(EVENT_TYPE_CHAR, (unsigned int)keychar, 0, 0, 0);
47
}
48
49
void AWTInputBridge_sendKey(int keycode) {
50
// TODO: iOS -> AWT keycode mapping
51
AWTInputBridge_nativeSendData(EVENT_TYPE_KEY, ' ', keycode, 1, 0);
52
AWTInputBridge_nativeSendData(EVENT_TYPE_KEY, ' ', keycode, 0, 0);
53
}
54
55
@interface SurfaceView() {
56
JNIEnv *surfaceJNIEnv;
57
jclass class_CTCScreen;
58
jmethodID method_GetRGB;
59
int *rgbArray;
60
}
61
@property(nonatomic) CGColorSpaceRef colorSpace;
62
@end
63
64
@implementation SurfaceView
65
- (void)refreshBuffer {
66
if (!runtimeJavaVMPtr) {
67
// JVM is not ready yet
68
return;
69
} else if (!surfaceJNIEnv) {
70
// Obtain JNIEnvs
71
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &surfaceJNIEnv, NULL);
72
assert(surfaceJNIEnv);
73
dispatch_async(dispatch_get_main_queue(), ^{
74
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL);
75
assert(runtimeJNIEnvPtr);
76
});
77
78
// Obtain CTCScreen.getCurrentScreenRGB()
79
class_CTCScreen = (*surfaceJNIEnv)->FindClass(surfaceJNIEnv, "net/java/openjdk/cacio/ctc/CTCScreen");
80
if ((*surfaceJNIEnv)->ExceptionCheck(surfaceJNIEnv) == JNI_TRUE) {
81
(*surfaceJNIEnv)->ExceptionClear(surfaceJNIEnv);
82
class_CTCScreen = (*surfaceJNIEnv)->FindClass(surfaceJNIEnv, "com/github/caciocavallosilano/cacio/ctc/CTCScreen");
83
}
84
assert(class_CTCScreen != NULL);
85
method_GetRGB = (*surfaceJNIEnv)->GetStaticMethodID(surfaceJNIEnv, class_CTCScreen, "getCurrentScreenRGB", "()[I");
86
assert(method_GetRGB != NULL);
87
rgbArray = calloc(4, (size_t) (windowWidth * windowHeight));
88
}
89
90
jintArray jreRgbArray = (jintArray) (*surfaceJNIEnv)->CallStaticObjectMethod(
91
surfaceJNIEnv,
92
class_CTCScreen,
93
method_GetRGB
94
);
95
if (!jreRgbArray) {
96
return;
97
}
98
int *tmpArray = (*surfaceJNIEnv)->GetIntArrayElements(surfaceJNIEnv, jreRgbArray, 0);
99
memcpy(rgbArray, tmpArray, windowWidth * windowHeight * 4);
100
(*surfaceJNIEnv)->ReleaseIntArrayElements(surfaceJNIEnv, jreRgbArray, tmpArray, JNI_ABORT);
101
dispatch_async(dispatch_get_main_queue(), ^{
102
[surfaceView displayLayer];
103
});
104
105
// Wait until something renders at the middle
106
if (shouldHitEnterAfterWindowShown && rgbArray[windowWidth/2 + windowWidth*windowHeight/2] != 0) {
107
shouldHitEnterAfterWindowShown = NO;
108
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^(void){
109
// Auto hit Enter to install immediately
110
AWTInputBridge_sendKey('\n');
111
});
112
}
113
}
114
115
- (void)displayLayer {
116
CGDataProviderRef bitmapProvider = CGDataProviderCreateWithData(NULL, rgbArray, windowWidth * windowHeight * 4, NULL);
117
CGImageRef bitmap = CGImageCreate(windowWidth, windowHeight, 8, 32, 4 * windowWidth, _colorSpace, kCGImageAlphaFirst | kCGBitmapByteOrder32Little, bitmapProvider, NULL, FALSE, kCGRenderingIntentDefault);
118
119
self.layer.contents = (__bridge id) bitmap;
120
CGImageRelease(bitmap);
121
CGDataProviderRelease(bitmapProvider);
122
// CGColorSpaceRelease(colorSpace);
123
}
124
125
- (id)initWithFrame:(CGRect)frame {
126
self = [super initWithFrame:frame];
127
self.layer.opaque = YES;
128
self.colorSpace = CGColorSpaceCreateDeviceRGB();
129
return self;
130
}
131
@end
132
133
@interface ScrollableSurfaceView<UIScrollViewDelegate> : UIScrollView
134
@property CGRect clickRange, virtualMouseFrame;
135
@property(nonatomic) UIImageView* mousePointerView;
136
@property BOOL shouldTriggerClick;
137
@end
138
139
@implementation ScrollableSurfaceView
140
141
- (instancetype)initWithFrame:(CGRect)frame {
142
surfaceView = [[SurfaceView alloc] initWithFrame:frame];
143
self = [super initWithFrame:frame];
144
[self addSubview:surfaceView];
145
self.delegate = (id)self;
146
147
self.virtualMouseFrame = CGRectMake(frame.size.width / 2, frame.size.height / 2, 18, 27);
148
self.mousePointerView = [[UIImageView alloc] initWithFrame:self.virtualMouseFrame];
149
self.mousePointerView.hidden = !virtualMouseEnabled;
150
self.mousePointerView.image = [UIImage imageNamed:@"MousePointer"];
151
[surfaceView addSubview:self.mousePointerView];
152
153
return self;
154
}
155
156
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
157
[super touchesBegan:touches withEvent:event];
158
CGPoint location = [touches.anyObject locationInView:self];
159
self.clickRange = CGRectMake(location.x - 2, location.y - 2, 5, 5);
160
self.shouldTriggerClick = YES;
161
}
162
163
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
164
[super touchesMoved:touches withEvent:event];
165
UITouch *touchEvent = touches.anyObject;
166
CGPoint location = [touchEvent locationInView:self];
167
if (self.shouldTriggerClick && !CGRectContainsPoint(self.clickRange, location)) {
168
self.shouldTriggerClick = NO;
169
}
170
171
if (virtualMouseEnabled) {
172
CGPoint prevLocation = [touchEvent previousLocationInView:self];
173
// Calculate delta
174
location.x = (location.x - prevLocation.x) / self.zoomScale;
175
location.y = (location.y - prevLocation.y) / self.zoomScale;
176
// Update cursor's origin
177
_virtualMouseFrame.origin.x = clamp(self.virtualMouseFrame.origin.x + location.x, 0, self.frame.size.width * self.zoomScale);
178
_virtualMouseFrame.origin.y = clamp(self.virtualMouseFrame.origin.y + location.y, 0, self.frame.size.height * self.zoomScale);
179
self.mousePointerView.frame = self.virtualMouseFrame;
180
location = self.virtualMouseFrame.origin;
181
182
CGPoint minimumContentOffset = CGPointMake(-self.contentInset.left, -self.contentInset.top);
183
CGPoint maximumContentOffset = CGPointMake(
184
MAX(minimumContentOffset.x, self.contentSize.width + self.contentInset.right - self.frame.size.width),
185
MAX(minimumContentOffset.y, self.contentSize.height + self.contentInset.bottom - self.frame.size.height));
186
// Focus scroll view's content area on virtual mouse
187
self.contentOffset = CGPointMake(
188
clamp(self.virtualMouseFrame.origin.x * self.zoomScale - self.center.x, minimumContentOffset.x, maximumContentOffset.x),
189
clamp(self.virtualMouseFrame.origin.y * self.zoomScale - self.center.y, minimumContentOffset.y, maximumContentOffset.y));
190
}
191
192
// Send cursor position to AWT
193
CGFloat screenScale = UIScreen.mainScreen.scale * getPrefFloat(@"video.resolution") / 100.0;
194
AWTInputBridge_nativeSendData(EVENT_TYPE_CURSOR_POS, (int)(location.x * screenScale), (int)(location.y * screenScale), 0, 0);
195
}
196
197
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
198
if (virtualMouseEnabled) {
199
// Keep virtual mouse in the middle of screen while zooming
200
_virtualMouseFrame.origin.x = (self.contentOffset.x + self.center.x) / self.zoomScale;
201
_virtualMouseFrame.origin.y = (self.contentOffset.y + self.center.y) / self.zoomScale;
202
self.mousePointerView.frame = self.virtualMouseFrame;
203
// Send cursor position to AWT
204
CGFloat screenScale = UIScreen.mainScreen.scale * getPrefFloat(@"video.resolution") / 100.0;
205
AWTInputBridge_nativeSendData(EVENT_TYPE_CURSOR_POS, (int)(_virtualMouseFrame.origin.x * screenScale), (int)(_virtualMouseFrame.origin.y * screenScale), 0, 0);
206
}
207
}
208
209
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)view {
210
return surfaceView;
211
}
212
213
@end
214
215
@interface JavaGUIViewController ()<UIGestureRecognizerDelegate, UITextFieldDelegate>
216
217
@property(nonatomic) TrackedTextField* inputTextField;
218
@property(nonatomic) ControlLayout* ctrlView;
219
@property(nonatomic) PLLogOutputView* logOutputView;
220
@property(nonatomic) ScrollableSurfaceView* surfaceScrollView;
221
222
@end
223
224
@implementation JavaGUIViewController
225
226
- (void)viewDidLoad {
227
[super viewDidLoad];
228
self.view.backgroundColor = UIColor.blackColor;
229
[self.navigationController setNavigationBarHidden:YES animated:NO];
230
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
231
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
232
virtualMouseEnabled = getPrefBool(@"control.virtmouse_enable");
233
234
CGRect screenBounds = self.view.bounds;
235
CGFloat screenScale = UIScreen.mainScreen.scale * getPrefFloat(@"video.resolution") / 100.0;
236
windowWidth = roundf(screenBounds.size.width * screenScale);
237
windowHeight = roundf(screenBounds.size.height * screenScale);
238
// Resolution should not be odd
239
if ((windowWidth % 2) != 0) {
240
--windowWidth;
241
}
242
if ((windowHeight % 2) != 0) {
243
--windowHeight;
244
}
245
246
self.surfaceScrollView = [[ScrollableSurfaceView alloc] initWithFrame:self.view.frame];
247
self.surfaceScrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
248
self.surfaceScrollView.minimumZoomScale = 1;
249
self.surfaceScrollView.maximumZoomScale = 5;
250
self.surfaceScrollView.scrollEnabled = NO;
251
[self.view addSubview:self.surfaceScrollView];
252
253
self.inputTextField = [[TrackedTextField alloc] initWithFrame:CGRectMake(0, -32.0, self.view.frame.size.width, 30.0)];
254
self.inputTextField.backgroundColor = UIColor.secondarySystemBackgroundColor;
255
self.inputTextField.delegate = self;
256
self.inputTextField.font = [UIFont fontWithName:@"Menlo-Regular" size:20];
257
self.inputTextField.clearsOnBeginEditing = YES;
258
self.inputTextField.textAlignment = NSTextAlignmentCenter;
259
self.inputTextField.sendChar = ^(jchar keychar){
260
AWTInputBridge_sendChar(keychar);
261
};
262
self.inputTextField.sendKey = ^(int key, int scancode, int action, int mods) {
263
if (action == 0) return;
264
switch (key) {
265
case GLFW_KEY_BACKSPACE:
266
AWTInputBridge_sendKey('\b'); // VK_BACK_SPACE
267
break;
268
case GLFW_KEY_ENTER:
269
AWTInputBridge_sendKey('\n'); // VK_ENTER;
270
break;
271
case GLFW_KEY_DPAD_LEFT:
272
AWTInputBridge_sendKey(0xE2); // VK_KP_LEFT;
273
break;
274
case GLFW_KEY_DPAD_RIGHT:
275
AWTInputBridge_sendKey(0xE3); // VK_KP_RIGHT;
276
break;
277
}
278
};
279
[self.view addSubview:self.inputTextField];
280
281
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
282
initWithTarget:self action:@selector(surfaceOnClick:)];
283
tapGesture.delegate = self;
284
tapGesture.numberOfTapsRequired = 1;
285
tapGesture.numberOfTouchesRequired = 1;
286
tapGesture.cancelsTouchesInView = NO;
287
[surfaceView addGestureRecognizer:tapGesture];
288
289
// Borrowing custom controls, might be useful later (full-blown jar launcher with control support?)
290
self.ctrlView = [[ControlLayout alloc] initWithFrame:UIEdgeInsetsInsetRect(self.view.frame, self.view.safeAreaInsets)];
291
[self.view addSubview:self.ctrlView];
292
[self loadCustomControls];
293
294
self.logOutputView = [[PLLogOutputView alloc] initWithFrame:self.view.frame];
295
self.logOutputView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
296
[self.view addSubview:self.logOutputView];
297
298
setenv("POJAV_SKIP_JNI_GLFW", "1", 1);
299
300
// Register the display loop
301
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
302
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:surfaceView selector:@selector(refreshBuffer)];
303
if (@available(iOS 15.0, tvOS 15.0, *)) {
304
if(getPrefBool(@"video.max_framerate")) {
305
displayLink.preferredFrameRateRange = CAFrameRateRangeMake(30, 120, 120);
306
} else {
307
displayLink.preferredFrameRateRange = CAFrameRateRangeMake(30, 60, 60);
308
}
309
}
310
[displayLink addToRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
311
[NSRunLoop.currentRunLoop run];
312
});
313
314
315
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
316
launchJVM(nil, self.filepath, windowWidth, windowHeight, _requiredJavaVersion);
317
_requiredJavaVersion = 0;
318
});
319
}
320
321
- (void)loadCustomControls {
322
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
323
dict[@"version"] = @(4);
324
dict[@"scaledAt"] = @(100);
325
dict[@"mControlDataList"] = [[NSMutableArray alloc] init];
326
//dict[@"mDrawerDataList"] = [[NSMutableArray alloc] init];
327
[dict[@"mControlDataList"] addObject:createButton(@"Keyboard",
328
(int[]){SPECIALBTN_KEYBOARD,0,0,0},
329
@"${margin}", @"${margin}",
330
BTN_RECT
331
)];
332
[dict[@"mControlDataList"] addObject:createButton(localize(@"game.menu.log_output", nil),
333
(int[]){SPECIALBTN_LOGOUTPUT,0,0,0},
334
@"${right} - ${margin}", @"${margin}",
335
BTN_RECT
336
)];
337
[dict[@"mControlDataList"] addObject:createButton(@"Mouse",
338
(int[]){SPECIALBTN_VIRTUALMOUSE,0,0,0},
339
@"${right} - ${margin}", @"${margin} * 2 + ${height}",
340
BTN_RECT
341
)];
342
[dict[@"mControlDataList"] addObject:createButton(@"PRI",
343
(int[]){SPECIALBTN_MOUSEPRI,0,0,0},
344
@"${margin}", @"${bottom} - ${margin}",
345
BTN_RECT
346
)];
347
[dict[@"mControlDataList"] addObject:createButton(@"SEC",
348
(int[]){SPECIALBTN_MOUSESEC,0,0,0},
349
@"${margin} * 2 + ${width}", @"${bottom} - ${margin}",
350
BTN_RECT
351
)];
352
[self.ctrlView loadControlLayout:dict];
353
354
// Implement a subset of custom controls functionalites enough for few buttons
355
for (ControlButton *button in self.ctrlView.subviews) {
356
[button addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown];
357
[button addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
358
}
359
}
360
361
@synthesize requiredJavaVersion = _requiredJavaVersion;
362
- (int)requiredJavaVersion {
363
if (_requiredJavaVersion) {
364
return _requiredJavaVersion;
365
}
366
367
NSError *error;
368
UZKArchive *archive = [[UZKArchive alloc] initWithPath:self.filepath error:&error];
369
if (error) {
370
[self showErrorMessage:error.localizedDescription];
371
return _requiredJavaVersion = 0;
372
}
373
374
NSData *manifestData = [archive extractDataFromFile:@"META-INF/MANIFEST.MF" error:&error];
375
if (error) {
376
[self showErrorMessage:error.localizedDescription];
377
return _requiredJavaVersion = 0;
378
}
379
380
NSString *manifestStr = [[NSString alloc] initWithData:manifestData encoding:NSUTF8StringEncoding];
381
NSArray *manifestLines = [manifestStr componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet];
382
NSString *mainClass;
383
for (NSString *line in manifestLines) {
384
if ([line hasPrefix:@"Main-Class: "]) {
385
mainClass = [line substringFromIndex:12];
386
break;
387
}
388
}
389
if (!mainClass) {
390
[self showErrorMessage:[NSString stringWithFormat:
391
localize(@"java.error.missing_main_class", nil), self.filepath.lastPathComponent]];
392
return _requiredJavaVersion = 0;
393
}
394
mainClass = [NSString stringWithFormat:@"%@.class",
395
[mainClass stringByReplacingOccurrencesOfString:@"." withString:@"/"]];
396
397
NSData *mainClassData = [archive extractDataFromFile:mainClass error:&error];
398
if (error) {
399
[self showErrorMessage:error.localizedDescription];
400
return _requiredJavaVersion = 0;
401
}
402
403
uint32_t magic = OSSwapConstInt32(*(uint32_t*)mainClassData.bytes);
404
if (magic != 0xCAFEBABE) {
405
[self showErrorMessage:[NSString stringWithFormat:@"Invalid magic number: 0x%x", magic]];
406
return _requiredJavaVersion = 0;
407
}
408
409
uint16_t *version = (uint16_t *)(mainClassData.bytes+sizeof(magic));
410
uint16_t minorVer = OSSwapConstInt16(version[0]);
411
uint16_t majorVer = OSSwapConstInt16(version[1]);
412
NSLog(@"[ModInstaller] Main class version: %u.%u", majorVer, minorVer);
413
414
return _requiredJavaVersion = MAX(2, majorVer - 44);
415
}
416
417
- (void)showErrorMessage:(NSString *)message {
418
surfaceView = nil;
419
showDialog(localize(@"Error", nil), message);
420
}
421
422
- (void)setHitEnterAfterWindowShown:(BOOL)hitEnter {
423
shouldHitEnterAfterWindowShown = hitEnter;
424
}
425
426
- (void)executebtn:(ControlButton *)sender withAction:(int)action {
427
int held = action == ACTION_DOWN;
428
for (int i = 0; i < 4; i++) {
429
int keycode = ((NSNumber *)sender.properties[@"keycodes"][i]).intValue;
430
if (keycode < 0) {
431
switch (keycode) {
432
case SPECIALBTN_KEYBOARD:
433
if (held) return;
434
[self toggleSoftKeyboard];
435
break;
436
437
case SPECIALBTN_MOUSEPRI:
438
AWTInputBridge_nativeSendData(EVENT_TYPE_MOUSE_BUTTON, BUTTON1_DOWN_MASK, held, 0, 0);
439
break;
440
441
case SPECIALBTN_MOUSEMID:
442
AWTInputBridge_nativeSendData(EVENT_TYPE_MOUSE_BUTTON, BUTTON2_DOWN_MASK, held, 0, 0);
443
break;
444
445
case SPECIALBTN_MOUSESEC:
446
AWTInputBridge_nativeSendData(EVENT_TYPE_MOUSE_BUTTON, BUTTON3_DOWN_MASK, held, 0, 0);
447
break;
448
449
case SPECIALBTN_VIRTUALMOUSE:
450
if (held) break;
451
virtualMouseEnabled = !virtualMouseEnabled;
452
self.surfaceScrollView.mousePointerView.hidden = !virtualMouseEnabled;
453
setPrefBool(@"control.virtmouse_enable", virtualMouseEnabled);
454
break;
455
456
case SPECIALBTN_LOGOUTPUT:
457
if (held) break;
458
[self.logOutputView actionToggleLogOutput];
459
break;
460
461
default:
462
NSLog(@"Warning: button %@ sent unknown special keycode: %d", sender.titleLabel.text, keycode);
463
break;
464
}
465
} else if (keycode > 0) {
466
// unimplemented
467
}
468
}
469
}
470
471
- (void)executebtn_down:(ControlButton *)button {
472
[self executebtn:button withAction:ACTION_DOWN];
473
}
474
475
- (void)executebtn_up:(ControlButton *)button {
476
[self executebtn:button withAction:ACTION_UP];
477
}
478
479
- (void)surfaceOnClick:(UITapGestureRecognizer *)sender {
480
if (!self.surfaceScrollView.shouldTriggerClick) return;
481
if (sender.state == UIGestureRecognizerStateRecognized) {
482
CGFloat screenScale = UIScreen.mainScreen.scale * getPrefFloat(@"video.resolution") / 100.0;
483
CGPoint location = virtualMouseEnabled ?
484
self.surfaceScrollView.virtualMouseFrame.origin:
485
[sender locationInView:sender.view];
486
CGFloat x = location.x * screenScale;
487
CGFloat y = location.y * screenScale;
488
AWTInputBridge_nativeSendData(EVENT_TYPE_CURSOR_POS, (int)x, (int)y, 0, 0);
489
AWTInputBridge_nativeSendData(EVENT_TYPE_MOUSE_BUTTON, BUTTON1_DOWN_MASK, 1, 0, 0);
490
AWTInputBridge_nativeSendData(EVENT_TYPE_MOUSE_BUTTON, BUTTON1_DOWN_MASK, 0, 0, 0);
491
}
492
}
493
494
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
495
self.inputTextField.sendKey(GLFW_KEY_ENTER, 0, 1, 0);
496
//self.inputTextField.sendKey(GLFW_KEY_ENTER, 0, 0, 0);
497
textField.text = @"";
498
return YES;
499
}
500
501
502
- (void)toggleSoftKeyboard {
503
if (self.inputTextField.isFirstResponder) {
504
[self.inputTextField resignFirstResponder];
505
} else {
506
[self.inputTextField becomeFirstResponder];
507
}
508
}
509
510
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
511
{
512
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
513
self.ctrlView.frame = UIEdgeInsetsInsetRect(self.view.frame, self.view.safeAreaInsets);
514
[self.ctrlView.subviews makeObjectsPerformSelector:@selector(update)];
515
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
516
self.surfaceScrollView.virtualMouseFrame = self.surfaceScrollView.mousePointerView.frame;
517
}];
518
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
519
}
520
521
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
522
return UIRectEdgeBottom;
523
}
524
525
- (BOOL)prefersHomeIndicatorAutoHidden {
526
return NO;
527
}
528
529
- (BOOL)prefersStatusBarHidden {
530
return YES;
531
}
532
533
@end
534
535