github.com/Seikaijyu/gio@v0.0.1/app/os_ios.m (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 // +build darwin,ios 4 5 @import UIKit; 6 7 #include <stdint.h> 8 #include "_cgo_export.h" 9 #include "framework_ios.h" 10 11 __attribute__ ((visibility ("hidden"))) Class gio_layerClass(void); 12 13 @interface GioView: UIView <UIKeyInput> 14 @end 15 16 @implementation GioViewController 17 18 CGFloat _keyboardHeight; 19 20 - (void)loadView { 21 gio_runMain(); 22 23 CGRect zeroFrame = CGRectMake(0, 0, 0, 0); 24 self.view = [[UIView alloc] initWithFrame:zeroFrame]; 25 self.view.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 0); 26 UIView *drawView = [[GioView alloc] initWithFrame:zeroFrame]; 27 [self.view addSubview: drawView]; 28 #ifndef TARGET_OS_TV 29 drawView.multipleTouchEnabled = YES; 30 #endif 31 drawView.preservesSuperviewLayoutMargins = YES; 32 drawView.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 0); 33 onCreate((__bridge CFTypeRef)drawView, (__bridge CFTypeRef)self); 34 [[NSNotificationCenter defaultCenter] addObserver:self 35 selector:@selector(keyboardWillChange:) 36 name:UIKeyboardWillShowNotification 37 object:nil]; 38 [[NSNotificationCenter defaultCenter] addObserver:self 39 selector:@selector(keyboardWillChange:) 40 name:UIKeyboardWillChangeFrameNotification 41 object:nil]; 42 [[NSNotificationCenter defaultCenter] addObserver:self 43 selector:@selector(keyboardWillHide:) 44 name:UIKeyboardWillHideNotification 45 object:nil]; 46 [[NSNotificationCenter defaultCenter] addObserver: self 47 selector: @selector(applicationDidEnterBackground:) 48 name: UIApplicationDidEnterBackgroundNotification 49 object: nil]; 50 [[NSNotificationCenter defaultCenter] addObserver: self 51 selector: @selector(applicationWillEnterForeground:) 52 name: UIApplicationWillEnterForegroundNotification 53 object: nil]; 54 } 55 56 - (void)applicationWillEnterForeground:(UIApplication *)application { 57 UIView *drawView = self.view.subviews[0]; 58 if (drawView != nil) { 59 gio_onDraw((__bridge CFTypeRef)drawView); 60 } 61 } 62 63 - (void)applicationDidEnterBackground:(UIApplication *)application { 64 UIView *drawView = self.view.subviews[0]; 65 if (drawView != nil) { 66 onStop((__bridge CFTypeRef)drawView); 67 } 68 } 69 70 - (void)viewDidDisappear:(BOOL)animated { 71 [super viewDidDisappear:animated]; 72 CFTypeRef viewRef = (__bridge CFTypeRef)self.view.subviews[0]; 73 onDestroy(viewRef); 74 } 75 76 - (void)viewDidLayoutSubviews { 77 [super viewDidLayoutSubviews]; 78 UIView *view = self.view.subviews[0]; 79 CGRect frame = self.view.bounds; 80 // Adjust view bounds to make room for the keyboard. 81 frame.size.height -= _keyboardHeight; 82 view.frame = frame; 83 gio_onDraw((__bridge CFTypeRef)view); 84 } 85 86 - (void)didReceiveMemoryWarning { 87 onLowMemory(); 88 [super didReceiveMemoryWarning]; 89 } 90 91 - (void)keyboardWillChange:(NSNotification *)note { 92 NSDictionary *userInfo = note.userInfo; 93 CGRect f = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; 94 _keyboardHeight = f.size.height; 95 [self.view setNeedsLayout]; 96 } 97 98 - (void)keyboardWillHide:(NSNotification *)note { 99 _keyboardHeight = 0.0; 100 [self.view setNeedsLayout]; 101 } 102 @end 103 104 static void handleTouches(int last, UIView *view, NSSet<UITouch *> *touches, UIEvent *event) { 105 CGFloat scale = view.contentScaleFactor; 106 NSUInteger i = 0; 107 NSUInteger n = [touches count]; 108 CFTypeRef viewRef = (__bridge CFTypeRef)view; 109 for (UITouch *touch in touches) { 110 CFTypeRef touchRef = (__bridge CFTypeRef)touch; 111 i++; 112 NSArray<UITouch *> *coalescedTouches = [event coalescedTouchesForTouch:touch]; 113 NSUInteger j = 0; 114 NSUInteger m = [coalescedTouches count]; 115 for (UITouch *coalescedTouch in [event coalescedTouchesForTouch:touch]) { 116 CGPoint loc = [coalescedTouch locationInView:view]; 117 j++; 118 int lastTouch = last && i == n && j == m; 119 onTouch(lastTouch, viewRef, touchRef, touch.phase, loc.x*scale, loc.y*scale, [coalescedTouch timestamp]); 120 } 121 } 122 } 123 124 @implementation GioView 125 NSArray<UIKeyCommand *> *_keyCommands; 126 + (void)onFrameCallback:(CADisplayLink *)link { 127 gio_onFrameCallback((__bridge CFTypeRef)link); 128 } 129 + (Class)layerClass { 130 return gio_layerClass(); 131 } 132 - (void)willMoveToWindow:(UIWindow *)newWindow { 133 if (self.window != nil) { 134 [[NSNotificationCenter defaultCenter] removeObserver:self 135 name:UIWindowDidBecomeKeyNotification 136 object:self.window]; 137 [[NSNotificationCenter defaultCenter] removeObserver:self 138 name:UIWindowDidResignKeyNotification 139 object:self.window]; 140 } 141 self.contentScaleFactor = newWindow.screen.nativeScale; 142 [[NSNotificationCenter defaultCenter] addObserver:self 143 selector:@selector(onWindowDidBecomeKey:) 144 name:UIWindowDidBecomeKeyNotification 145 object:newWindow]; 146 [[NSNotificationCenter defaultCenter] addObserver:self 147 selector:@selector(onWindowDidResignKey:) 148 name:UIWindowDidResignKeyNotification 149 object:newWindow]; 150 } 151 152 - (void)onWindowDidBecomeKey:(NSNotification *)note { 153 if (self.isFirstResponder) { 154 onFocus((__bridge CFTypeRef)self, YES); 155 } 156 } 157 158 - (void)onWindowDidResignKey:(NSNotification *)note { 159 if (self.isFirstResponder) { 160 onFocus((__bridge CFTypeRef)self, NO); 161 } 162 } 163 164 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 165 handleTouches(0, self, touches, event); 166 } 167 168 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 169 handleTouches(0, self, touches, event); 170 } 171 172 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 173 handleTouches(1, self, touches, event); 174 } 175 176 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 177 handleTouches(1, self, touches, event); 178 } 179 180 - (void)insertText:(NSString *)text { 181 onText((__bridge CFTypeRef)self, (__bridge CFTypeRef)text); 182 } 183 184 - (BOOL)canBecomeFirstResponder { 185 return YES; 186 } 187 188 - (BOOL)hasText { 189 return YES; 190 } 191 192 - (void)deleteBackward { 193 onDeleteBackward((__bridge CFTypeRef)self); 194 } 195 196 - (void)onUpArrow { 197 onUpArrow((__bridge CFTypeRef)self); 198 } 199 200 - (void)onDownArrow { 201 onDownArrow((__bridge CFTypeRef)self); 202 } 203 204 - (void)onLeftArrow { 205 onLeftArrow((__bridge CFTypeRef)self); 206 } 207 208 - (void)onRightArrow { 209 onRightArrow((__bridge CFTypeRef)self); 210 } 211 212 - (NSArray<UIKeyCommand *> *)keyCommands { 213 if (_keyCommands == nil) { 214 _keyCommands = @[ 215 [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow 216 modifierFlags:0 217 action:@selector(onUpArrow)], 218 [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow 219 modifierFlags:0 220 action:@selector(onDownArrow)], 221 [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow 222 modifierFlags:0 223 action:@selector(onLeftArrow)], 224 [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow 225 modifierFlags:0 226 action:@selector(onRightArrow)] 227 ]; 228 } 229 return _keyCommands; 230 } 231 @end 232 233 CFTypeRef gio_createDisplayLink(void) { 234 CADisplayLink *dl = [CADisplayLink displayLinkWithTarget:[GioView class] selector:@selector(onFrameCallback:)]; 235 dl.paused = YES; 236 NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; 237 [dl addToRunLoop:runLoop forMode:[runLoop currentMode]]; 238 return (__bridge_retained CFTypeRef)dl; 239 } 240 241 int gio_startDisplayLink(CFTypeRef dlref) { 242 CADisplayLink *dl = (__bridge CADisplayLink *)dlref; 243 dl.paused = NO; 244 return 0; 245 } 246 247 int gio_stopDisplayLink(CFTypeRef dlref) { 248 CADisplayLink *dl = (__bridge CADisplayLink *)dlref; 249 dl.paused = YES; 250 return 0; 251 } 252 253 void gio_releaseDisplayLink(CFTypeRef dlref) { 254 CADisplayLink *dl = (__bridge CADisplayLink *)dlref; 255 [dl invalidate]; 256 CFRelease(dlref); 257 } 258 259 void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did) { 260 // Nothing to do on iOS. 261 } 262 263 void gio_hideCursor() { 264 // Not supported. 265 } 266 267 void gio_showCursor() { 268 // Not supported. 269 } 270 271 void gio_setCursor(NSUInteger curID) { 272 // Not supported. 273 }