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  }