src/video/uikit/SDL_uikitviewcontroller.m
author Alex Szpakowski
Sat, 02 Apr 2016 13:21:01 -0300
changeset 10141 fe9cf7c678f4
parent 9998 f67cf37e9cd4
child 10340 5724f5087acd
permissions -rw-r--r--
iOS: Also do the Dictation crash workaround before executing the animation callback.
kees@5640
     1
/*
slouken@6044
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
kees@6001
     4
slouken@6044
     5
  This software is provided 'as-is', without any express or implied
slouken@6044
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@6044
     7
  arising from the use of this software.
slouken@6044
     8
slouken@6044
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@6044
    10
  including commercial applications, and to alter it and redistribute it
slouken@6044
    11
  freely, subject to the following restrictions:
kees@6001
    12
slouken@6044
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@6044
    14
     claim that you wrote the original software. If you use this software
slouken@6044
    15
     in a product, an acknowledgment in the product documentation would be
slouken@6044
    16
     appreciated but is not required.
slouken@6044
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@6044
    18
     misrepresented as being the original software.
slouken@6044
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@6044
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
kees@6001
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_UIKIT
kees@5640
    24
kees@5640
    25
#include "SDL_video.h"
kees@5640
    26
#include "SDL_assert.h"
kees@5640
    27
#include "SDL_hints.h"
kees@5640
    28
#include "../SDL_sysvideo.h"
kees@5640
    29
#include "../../events/SDL_events_c.h"
kees@5640
    30
slime73@9532
    31
#import "SDL_uikitviewcontroller.h"
slime73@9532
    32
#import "SDL_uikitmessagebox.h"
icculus@6093
    33
#include "SDL_uikitvideo.h"
slouken@6518
    34
#include "SDL_uikitmodes.h"
slouken@6518
    35
#include "SDL_uikitwindow.h"
slime73@10141
    36
#include "SDL_uikitopengles.h"
slouken@6518
    37
slime73@9532
    38
#if SDL_IPHONE_KEYBOARD
slime73@9532
    39
#include "keyinfotable.h"
slime73@9532
    40
#endif
kees@5640
    41
slime73@9532
    42
@implementation SDL_uikitviewcontroller {
slime73@9532
    43
    CADisplayLink *displayLink;
slime73@9532
    44
    int animationInterval;
slime73@9532
    45
    void (*animationCallback)(void*);
slime73@9532
    46
    void *animationCallbackParam;
slime73@9532
    47
slime73@9532
    48
#if SDL_IPHONE_KEYBOARD
slime73@9532
    49
    UITextField *textField;
slime73@9532
    50
#endif
slime73@9532
    51
}
kees@5640
    52
kees@6011
    53
@synthesize window;
kees@6011
    54
slime73@9532
    55
- (instancetype)initWithSDLWindow:(SDL_Window *)_window
kees@6003
    56
{
slime73@9505
    57
    if (self = [super initWithNibName:nil bundle:nil]) {
slime73@9505
    58
        self.window = _window;
slime73@9532
    59
slime73@9532
    60
#if SDL_IPHONE_KEYBOARD
slime73@9532
    61
        [self initKeyboard];
slime73@9532
    62
#endif
kees@5640
    63
    }
kees@5640
    64
    return self;
kees@5640
    65
}
kees@5640
    66
slime73@9532
    67
- (void)dealloc
slime73@9532
    68
{
slime73@9532
    69
#if SDL_IPHONE_KEYBOARD
slime73@9532
    70
    [self deinitKeyboard];
slime73@9532
    71
#endif
slime73@9532
    72
}
slime73@9532
    73
slime73@9532
    74
- (void)setAnimationCallback:(int)interval
slime73@9532
    75
                    callback:(void (*)(void*))callback
slime73@9532
    76
               callbackParam:(void*)callbackParam
slime73@9532
    77
{
slime73@9532
    78
    [self stopAnimation];
slime73@9532
    79
slime73@9532
    80
    animationInterval = interval;
slime73@9532
    81
    animationCallback = callback;
slime73@9532
    82
    animationCallbackParam = callbackParam;
slime73@9532
    83
slime73@9532
    84
    if (animationCallback) {
slime73@9532
    85
        [self startAnimation];
slime73@9532
    86
    }
slime73@9532
    87
}
slime73@9532
    88
slime73@9532
    89
- (void)startAnimation
slime73@9532
    90
{
slime73@9532
    91
    displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
slime73@9532
    92
    [displayLink setFrameInterval:animationInterval];
slime73@9532
    93
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
slime73@9532
    94
}
slime73@9532
    95
slime73@9532
    96
- (void)stopAnimation
slime73@9532
    97
{
slime73@9532
    98
    [displayLink invalidate];
slime73@9532
    99
    displayLink = nil;
slime73@9532
   100
}
slime73@9532
   101
slime73@9532
   102
- (void)doLoop:(CADisplayLink*)sender
slime73@9532
   103
{
slime73@9532
   104
    /* Don't run the game loop while a messagebox is up */
slime73@9532
   105
    if (!UIKit_ShowingMessageBox()) {
slime73@10141
   106
        /* See the comment in the function definition. */
slime73@10141
   107
        UIKit_GL_RestoreCurrentContext();
slime73@10141
   108
slime73@9532
   109
        animationCallback(animationCallbackParam);
slime73@9532
   110
    }
slime73@9532
   111
}
slime73@9532
   112
slouken@6440
   113
- (void)loadView
slouken@6440
   114
{
slime73@9532
   115
    /* Do nothing. */
slouken@6440
   116
}
slouken@6440
   117
slouken@6451
   118
- (void)viewDidLayoutSubviews
slouken@6440
   119
{
slime73@9505
   120
    const CGSize size = self.view.bounds.size;
slime73@9494
   121
    int w = (int) size.width;
slime73@9494
   122
    int h = (int) size.height;
slouken@7191
   123
slime73@9494
   124
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
slouken@6440
   125
}
slouken@6440
   126
slouken@6451
   127
- (NSUInteger)supportedInterfaceOrientations
kees@6003
   128
{
slime73@9523
   129
    return UIKit_GetSupportedOrientations(window);
kees@5640
   130
}
kees@5640
   131
slouken@6451
   132
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient
kees@6003
   133
{
slime73@9532
   134
    return ([self supportedInterfaceOrientations] & (1 << orient)) != 0;
kees@5640
   135
}
kees@5640
   136
slouken@7862
   137
- (BOOL)prefersStatusBarHidden
slouken@7862
   138
{
slime73@9529
   139
    return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
slouken@7862
   140
}
slouken@7862
   141
slime73@9532
   142
/*
slime73@9532
   143
 ---- Keyboard related functionality below this line ----
slime73@9532
   144
 */
slime73@9532
   145
#if SDL_IPHONE_KEYBOARD
slime73@9532
   146
slime73@9532
   147
@synthesize textInputRect;
slime73@9532
   148
@synthesize keyboardHeight;
slime73@9532
   149
@synthesize keyboardVisible;
slime73@9532
   150
slime73@9532
   151
/* Set ourselves up as a UITextFieldDelegate */
slime73@9532
   152
- (void)initKeyboard
slime73@9532
   153
{
slime73@9532
   154
    textField = [[UITextField alloc] initWithFrame:CGRectZero];
slime73@9532
   155
    textField.delegate = self;
slime73@9532
   156
    /* placeholder so there is something to delete! */
slime73@9532
   157
    textField.text = @" ";
slime73@9532
   158
slime73@9532
   159
    /* set UITextInputTrait properties, mostly to defaults */
slime73@9532
   160
    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
slime73@9532
   161
    textField.autocorrectionType = UITextAutocorrectionTypeNo;
slime73@9532
   162
    textField.enablesReturnKeyAutomatically = NO;
slime73@9532
   163
    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
slime73@9532
   164
    textField.keyboardType = UIKeyboardTypeDefault;
slime73@9532
   165
    textField.returnKeyType = UIReturnKeyDefault;
slime73@9532
   166
    textField.secureTextEntry = NO;
slime73@9532
   167
slime73@9532
   168
    textField.hidden = YES;
slime73@9532
   169
    keyboardVisible = NO;
slime73@9532
   170
slime73@9532
   171
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
slime73@9532
   172
    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
slime73@9532
   173
    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
slime73@9532
   174
}
slime73@9532
   175
slime73@9532
   176
- (void)setView:(UIView *)view
slime73@9532
   177
{
slime73@9532
   178
    [super setView:view];
slime73@9532
   179
slime73@9532
   180
    [view addSubview:textField];
slime73@9532
   181
slime73@9532
   182
    if (keyboardVisible) {
slime73@9532
   183
        [self showKeyboard];
slime73@9532
   184
    }
slime73@9532
   185
}
slime73@9532
   186
slime73@9532
   187
- (void)deinitKeyboard
slime73@9532
   188
{
slime73@9532
   189
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
slime73@9532
   190
    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
slime73@9532
   191
    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
slime73@9532
   192
}
slime73@9532
   193
slime73@9532
   194
/* reveal onscreen virtual keyboard */
slime73@9532
   195
- (void)showKeyboard
slime73@9532
   196
{
slime73@9532
   197
    keyboardVisible = YES;
slime73@9532
   198
    if (textField.window) {
slime73@9532
   199
        [textField becomeFirstResponder];
slime73@9532
   200
    }
slime73@9532
   201
}
slime73@9532
   202
slime73@9532
   203
/* hide onscreen virtual keyboard */
slime73@9532
   204
- (void)hideKeyboard
slime73@9532
   205
{
slime73@9532
   206
    keyboardVisible = NO;
slime73@9532
   207
    [textField resignFirstResponder];
slime73@9532
   208
}
slime73@9532
   209
slime73@9532
   210
- (void)keyboardWillShow:(NSNotification *)notification
slime73@9532
   211
{
slime73@9532
   212
    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
slime73@9532
   213
slime73@9585
   214
    /* The keyboard rect is in the coordinate space of the screen/window, but we
slime73@9585
   215
     * want its height in the coordinate space of the view. */
slime73@9585
   216
    kbrect = [self.view convertRect:kbrect fromView:nil];
slime73@9532
   217
slime73@9585
   218
    [self setKeyboardHeight:(int)kbrect.size.height];
slime73@9532
   219
}
slime73@9532
   220
slime73@9532
   221
- (void)keyboardWillHide:(NSNotification *)notification
slime73@9532
   222
{
slime73@9532
   223
    [self setKeyboardHeight:0];
slime73@9532
   224
}
slime73@9532
   225
slime73@9532
   226
- (void)updateKeyboard
slime73@9532
   227
{
slime73@9532
   228
    CGAffineTransform t = self.view.transform;
slime73@9532
   229
    CGPoint offset = CGPointMake(0.0, 0.0);
slime73@9585
   230
    CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen);
slime73@9532
   231
slime73@9532
   232
    if (self.keyboardHeight) {
slime73@9585
   233
        int rectbottom = self.textInputRect.y + self.textInputRect.h;
slime73@9585
   234
        int keybottom = self.view.bounds.size.height - self.keyboardHeight;
slime73@9585
   235
        if (keybottom < rectbottom) {
slime73@9585
   236
            offset.y = keybottom - rectbottom;
slime73@9532
   237
        }
slime73@9532
   238
    }
slime73@9532
   239
slime73@9585
   240
    /* Apply this view's transform (except any translation) to the offset, in
slime73@9585
   241
     * order to orient it correctly relative to the frame's coordinate space. */
slime73@9532
   242
    t.tx = 0.0;
slime73@9532
   243
    t.ty = 0.0;
slime73@9532
   244
    offset = CGPointApplyAffineTransform(offset, t);
slime73@9532
   245
slime73@9585
   246
    /* Apply the updated offset to the view's frame. */
slime73@9585
   247
    frame.origin.x += offset.x;
slime73@9585
   248
    frame.origin.y += offset.y;
slime73@9532
   249
slime73@9585
   250
    self.view.frame = frame;
slime73@9532
   251
}
slime73@9532
   252
slime73@9532
   253
- (void)setKeyboardHeight:(int)height
slime73@9532
   254
{
slime73@9532
   255
    keyboardVisible = height > 0;
slime73@9532
   256
    keyboardHeight = height;
slime73@9532
   257
    [self updateKeyboard];
slime73@9532
   258
}
slime73@9532
   259
slime73@9532
   260
/* UITextFieldDelegate method.  Invoked when user types something. */
slime73@9532
   261
- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
slime73@9532
   262
{
slime73@9532
   263
    NSUInteger len = string.length;
slime73@9532
   264
slime73@9532
   265
    if (len == 0) {
slime73@9532
   266
        /* it wants to replace text with nothing, ie a delete */
slime73@9532
   267
        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
slime73@9532
   268
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
slime73@9532
   269
    } else {
slime73@9532
   270
        /* go through all the characters in the string we've been sent and
slime73@9532
   271
         * convert them to key presses */
slime73@9532
   272
        int i;
slime73@9532
   273
        for (i = 0; i < len; i++) {
slime73@9532
   274
            unichar c = [string characterAtIndex:i];
slime73@9532
   275
            Uint16 mod = 0;
slime73@9532
   276
            SDL_Scancode code;
slime73@9532
   277
slime73@9532
   278
            if (c < 127) {
slime73@9532
   279
                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
slime73@9532
   280
                code = unicharToUIKeyInfoTable[c].code;
slime73@9532
   281
                mod  = unicharToUIKeyInfoTable[c].mod;
slime73@9532
   282
            } else {
slime73@9532
   283
                /* we only deal with ASCII right now */
slime73@9532
   284
                code = SDL_SCANCODE_UNKNOWN;
slime73@9532
   285
                mod = 0;
slime73@9532
   286
            }
slime73@9532
   287
slime73@9532
   288
            if (mod & KMOD_SHIFT) {
slime73@9532
   289
                /* If character uses shift, press shift down */
slime73@9532
   290
                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
slime73@9532
   291
            }
slime73@9532
   292
slime73@9532
   293
            /* send a keydown and keyup even for the character */
slime73@9532
   294
            SDL_SendKeyboardKey(SDL_PRESSED, code);
slime73@9532
   295
            SDL_SendKeyboardKey(SDL_RELEASED, code);
slime73@9532
   296
slime73@9532
   297
            if (mod & KMOD_SHIFT) {
slime73@9532
   298
                /* If character uses shift, press shift back up */
slime73@9532
   299
                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
slime73@9532
   300
            }
slime73@9532
   301
        }
slime73@9532
   302
slime73@9532
   303
        SDL_SendKeyboardText([string UTF8String]);
slime73@9532
   304
    }
slime73@9532
   305
slime73@9532
   306
    return NO; /* don't allow the edit! (keep placeholder text there) */
slime73@9532
   307
}
slime73@9532
   308
slime73@9532
   309
/* Terminates the editing session */
slime73@9532
   310
- (BOOL)textFieldShouldReturn:(UITextField*)_textField
slime73@9532
   311
{
slime73@9532
   312
    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
slime73@9532
   313
    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
slime73@9532
   314
    SDL_StopTextInput();
slime73@9532
   315
    return YES;
slime73@9532
   316
}
slime73@9532
   317
slime73@9532
   318
#endif
slime73@9532
   319
slouken@6451
   320
@end
slouken@6451
   321
slime73@9532
   322
/* iPhone keyboard addition functions */
slime73@9532
   323
#if SDL_IPHONE_KEYBOARD
slime73@9532
   324
slime73@9532
   325
static SDL_uikitviewcontroller *
slime73@9532
   326
GetWindowViewController(SDL_Window * window)
slime73@9532
   327
{
slime73@9532
   328
    if (!window || !window->driverdata) {
slime73@9532
   329
        SDL_SetError("Invalid window");
slime73@9532
   330
        return nil;
slime73@9532
   331
    }
slime73@9532
   332
slime73@9532
   333
    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
slime73@9532
   334
slime73@9532
   335
    return data.viewcontroller;
slime73@9532
   336
}
slime73@9532
   337
slime73@9532
   338
SDL_bool
slime73@9532
   339
UIKit_HasScreenKeyboardSupport(_THIS)
slime73@9532
   340
{
slime73@9532
   341
    return SDL_TRUE;
slime73@9532
   342
}
slime73@9532
   343
slime73@9532
   344
void
slime73@9532
   345
UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
slime73@9532
   346
{
slime73@9532
   347
    @autoreleasepool {
slime73@9532
   348
        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
slime73@9532
   349
        [vc showKeyboard];
slime73@9532
   350
    }
slime73@9532
   351
}
slime73@9532
   352
slime73@9532
   353
void
slime73@9532
   354
UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
slime73@9532
   355
{
slime73@9532
   356
    @autoreleasepool {
slime73@9532
   357
        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
slime73@9532
   358
        [vc hideKeyboard];
slime73@9532
   359
    }
slime73@9532
   360
}
slime73@9532
   361
slime73@9532
   362
SDL_bool
slime73@9532
   363
UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
slime73@9532
   364
{
slime73@9532
   365
    @autoreleasepool {
slime73@9532
   366
        SDL_uikitviewcontroller *vc = GetWindowViewController(window);
slime73@9532
   367
        if (vc != nil) {
slime73@9532
   368
            return vc.isKeyboardVisible;
slime73@9532
   369
        }
slime73@9532
   370
        return SDL_FALSE;
slime73@9532
   371
    }
slime73@9532
   372
}
slime73@9532
   373
slime73@9532
   374
void
slime73@9532
   375
UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
slime73@9532
   376
{
slime73@9532
   377
    if (!rect) {
slime73@9532
   378
        SDL_InvalidParamError("rect");
slime73@9532
   379
        return;
slime73@9532
   380
    }
slime73@9532
   381
slime73@9532
   382
    @autoreleasepool {
slime73@9532
   383
        SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
slime73@9532
   384
        if (vc != nil) {
slime73@9532
   385
            vc.textInputRect = *rect;
slime73@9532
   386
slime73@9532
   387
            if (vc.keyboardVisible) {
slime73@9532
   388
                [vc updateKeyboard];
slime73@9532
   389
            }
slime73@9532
   390
        }
slime73@9532
   391
    }
slime73@9532
   392
}
slime73@9532
   393
slime73@9532
   394
slime73@9532
   395
#endif /* SDL_IPHONE_KEYBOARD */
slime73@9532
   396
slouken@6044
   397
#endif /* SDL_VIDEO_DRIVER_UIKIT */
slouken@6044
   398
slouken@6440
   399
/* vi: set ts=4 sw=4 expandtab: */