123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /**************************************************************************/
- /* view_controller.mm */
- /**************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /**************************************************************************/
- /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
- /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /**************************************************************************/
- #import "view_controller.h"
- #import "display_server_ios.h"
- #import "godot_view.h"
- #import "godot_view_renderer.h"
- #import "key_mapping_ios.h"
- #import "keyboard_input_view.h"
- #import "os_ios.h"
- #include "core/config/project_settings.h"
- #import <AVFoundation/AVFoundation.h>
- #import <GameController/GameController.h>
- @interface ViewController () <GodotViewDelegate>
- @property(strong, nonatomic) GodotViewRenderer *renderer;
- @property(strong, nonatomic) GodotKeyboardInputView *keyboardView;
- @property(strong, nonatomic) UIView *godotLoadingOverlay;
- @end
- @implementation ViewController
- - (GodotView *)godotView {
- return (GodotView *)self.view;
- }
- - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
- [super pressesBegan:presses withEvent:event];
- if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
- return;
- }
- if (@available(iOS 13.4, *)) {
- for (UIPress *press in presses) {
- String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
- String u32text = String::utf8([press.key.characters UTF8String]);
- Key key = KeyMappingIOS::remap_key(press.key.keyCode);
- if (press.key.keyCode == 0 && u32text.is_empty() && u32lbl.is_empty()) {
- continue;
- }
- char32_t us = 0;
- if (!u32lbl.is_empty() && !u32lbl.begins_with("UIKey")) {
- us = u32lbl[0];
- }
- if (!u32text.is_empty() && !u32text.begins_with("UIKey")) {
- for (int i = 0; i < u32text.length(); i++) {
- const char32_t c = u32text[i];
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true);
- }
- } else {
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true);
- }
- }
- }
- }
- - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
- [super pressesEnded:presses withEvent:event];
- if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
- return;
- }
- if (@available(iOS 13.4, *)) {
- for (UIPress *press in presses) {
- String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
- Key key = KeyMappingIOS::remap_key(press.key.keyCode);
- if (press.key.keyCode == 0 && u32lbl.is_empty()) {
- continue;
- }
- char32_t us = 0;
- if (!u32lbl.is_empty() && !u32lbl.begins_with("UIKey")) {
- us = u32lbl[0];
- }
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false);
- }
- }
- }
- - (void)loadView {
- GodotView *view = [[GodotView alloc] init];
- GodotViewRenderer *renderer = [[GodotViewRenderer alloc] init];
- self.renderer = renderer;
- self.view = view;
- view.renderer = self.renderer;
- view.delegate = self;
- }
- - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- [self godot_commonInit];
- }
- return self;
- }
- - (instancetype)initWithCoder:(NSCoder *)coder {
- self = [super initWithCoder:coder];
- if (self) {
- [self godot_commonInit];
- }
- return self;
- }
- - (void)godot_commonInit {
- // Initialize view controller values.
- }
- - (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- print_verbose("Did receive memory warning!");
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self observeKeyboard];
- [self displayLoadingOverlay];
- [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
- }
- - (void)observeKeyboard {
- print_verbose("Setting up keyboard input view.");
- self.keyboardView = [GodotKeyboardInputView new];
- [self.view addSubview:self.keyboardView];
- print_verbose("Adding observer for keyboard show/hide.");
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(keyboardOnScreen:)
- name:UIKeyboardDidShowNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(keyboardHidden:)
- name:UIKeyboardDidHideNotification
- object:nil];
- }
- - (void)displayLoadingOverlay {
- NSBundle *bundle = [NSBundle mainBundle];
- NSString *storyboardName = @"Launch Screen";
- if ([bundle pathForResource:storyboardName ofType:@"storyboardc"] == nil) {
- return;
- }
- UIStoryboard *launchStoryboard = [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
- UIViewController *controller = [launchStoryboard instantiateInitialViewController];
- self.godotLoadingOverlay = controller.view;
- self.godotLoadingOverlay.frame = self.view.bounds;
- self.godotLoadingOverlay.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
- [self.view addSubview:self.godotLoadingOverlay];
- }
- - (BOOL)godotViewFinishedSetup:(GodotView *)view {
- [self.godotLoadingOverlay removeFromSuperview];
- self.godotLoadingOverlay = nil;
- return YES;
- }
- - (void)dealloc {
- self.keyboardView = nil;
- self.renderer = nil;
- if (self.godotLoadingOverlay) {
- [self.godotLoadingOverlay removeFromSuperview];
- self.godotLoadingOverlay = nil;
- }
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- // MARK: Orientation
- - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
- if (GLOBAL_GET("display/window/ios/suppress_ui_gesture")) {
- return UIRectEdgeAll;
- } else {
- return UIRectEdgeNone;
- }
- }
- - (BOOL)shouldAutorotate {
- if (!DisplayServerIOS::get_singleton()) {
- return NO;
- }
- switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
- case DisplayServer::SCREEN_SENSOR:
- case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
- case DisplayServer::SCREEN_SENSOR_PORTRAIT:
- return YES;
- default:
- return NO;
- }
- }
- - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
- if (!DisplayServerIOS::get_singleton()) {
- return UIInterfaceOrientationMaskAll;
- }
- switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
- case DisplayServer::SCREEN_PORTRAIT:
- return UIInterfaceOrientationMaskPortrait;
- case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
- return UIInterfaceOrientationMaskLandscapeRight;
- case DisplayServer::SCREEN_REVERSE_PORTRAIT:
- return UIInterfaceOrientationMaskPortraitUpsideDown;
- case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
- return UIInterfaceOrientationMaskLandscape;
- case DisplayServer::SCREEN_SENSOR_PORTRAIT:
- return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
- case DisplayServer::SCREEN_SENSOR:
- return UIInterfaceOrientationMaskAll;
- case DisplayServer::SCREEN_LANDSCAPE:
- return UIInterfaceOrientationMaskLandscapeLeft;
- }
- }
- - (BOOL)prefersStatusBarHidden {
- if (GLOBAL_GET("display/window/ios/hide_status_bar")) {
- return YES;
- } else {
- return NO;
- }
- }
- - (BOOL)prefersHomeIndicatorAutoHidden {
- if (GLOBAL_GET("display/window/ios/hide_home_indicator")) {
- return YES;
- } else {
- return NO;
- }
- }
- // MARK: Keyboard
- - (void)keyboardOnScreen:(NSNotification *)notification {
- NSDictionary *info = notification.userInfo;
- NSValue *value = info[UIKeyboardFrameEndUserInfoKey];
- CGRect rawFrame = [value CGRectValue];
- CGRect keyboardFrame = [self.view convertRect:rawFrame fromView:nil];
- if (DisplayServerIOS::get_singleton()) {
- DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height);
- }
- }
- - (void)keyboardHidden:(NSNotification *)notification {
- if (DisplayServerIOS::get_singleton()) {
- DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(0);
- }
- }
- @end
|