src/video/uikit/SDL_uikitview.m
branchiOS-improvements
changeset 9532 318042c16b76
parent 9529 4bf9830d8153
child 9551 950a1a7b4c3c
     1.1 --- a/src/video/uikit/SDL_uikitview.m	Tue Dec 02 02:52:45 2014 -0400
     1.2 +++ b/src/video/uikit/SDL_uikitview.m	Thu Jan 15 01:06:14 2015 -0400
     1.3 @@ -24,36 +24,26 @@
     1.4  
     1.5  #include "SDL_uikitview.h"
     1.6  
     1.7 -#include "../../events/SDL_keyboard_c.h"
     1.8  #include "../../events/SDL_mouse_c.h"
     1.9  #include "../../events/SDL_touch_c.h"
    1.10 +#include "../../events/SDL_events_c.h"
    1.11  
    1.12 -#if SDL_IPHONE_KEYBOARD
    1.13 -#include "keyinfotable.h"
    1.14 -#endif
    1.15 -#include "SDL_uikitappdelegate.h"
    1.16 -#include "SDL_uikitmodes.h"
    1.17 -#include "SDL_uikitwindow.h"
    1.18 +#import "SDL_uikitappdelegate.h"
    1.19 +#import "SDL_uikitmodes.h"
    1.20 +#import "SDL_uikitwindow.h"
    1.21  
    1.22  @implementation SDL_uikitview {
    1.23 +    SDL_Window *sdlwindow;
    1.24  
    1.25      SDL_TouchID touchId;
    1.26 -    UITouch *leftFingerDown;
    1.27 -
    1.28 -#if SDL_IPHONE_KEYBOARD
    1.29 -    UITextField *textField;
    1.30 -#endif
    1.31 -
    1.32 +    UITouch * __weak firstFingerDown;
    1.33  }
    1.34  
    1.35 -@synthesize sdlwindow;
    1.36 -
    1.37 -- (id)initWithFrame:(CGRect)frame
    1.38 +- (instancetype)initWithFrame:(CGRect)frame
    1.39  {
    1.40 -    if (self = [super initWithFrame:frame]) {
    1.41 -#if SDL_IPHONE_KEYBOARD
    1.42 -        [self initKeyboard];
    1.43 -#endif
    1.44 +    if ((self = [super initWithFrame:frame])) {
    1.45 +        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    1.46 +        self.autoresizesSubviews = YES;
    1.47  
    1.48          self.multipleTouchEnabled = YES;
    1.49  
    1.50 @@ -62,14 +52,65 @@
    1.51      }
    1.52  
    1.53      return self;
    1.54 -
    1.55  }
    1.56  
    1.57 -- (void)dealloc
    1.58 +- (void)setSDLWindow:(SDL_Window *)window
    1.59  {
    1.60 -#if SDL_IPHONE_KEYBOARD
    1.61 -    [self deinitKeyboard];
    1.62 -#endif
    1.63 +    SDL_WindowData *data = nil;
    1.64 +
    1.65 +    if (window == sdlwindow) {
    1.66 +        return;
    1.67 +    }
    1.68 +
    1.69 +    if (sdlwindow) {
    1.70 +        SDL_uikitview *view = nil;
    1.71 +        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
    1.72 +
    1.73 +        [data.views removeObject:self];
    1.74 +
    1.75 +        [self removeFromSuperview];
    1.76 +
    1.77 +        /* Restore the next-oldest view in the old window. */
    1.78 +        if (data.views.count > 0) {
    1.79 +            view = data.views[data.views.count - 1];
    1.80 +        }
    1.81 +
    1.82 +        data.viewcontroller.view = view;
    1.83 +
    1.84 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
    1.85 +            data.uiwindow.rootViewController = data.viewcontroller;
    1.86 +        } else if (view) {
    1.87 +            [data.uiwindow addSubview:view];
    1.88 +        }
    1.89 +
    1.90 +        [data.uiwindow layoutIfNeeded];
    1.91 +    }
    1.92 +
    1.93 +    if (window) {
    1.94 +        data = (__bridge SDL_WindowData *) window->driverdata;
    1.95 +
    1.96 +        /* Make sure the SDL window has a strong reference to this view. */
    1.97 +        [data.views addObject:self];
    1.98 +
    1.99 +        /* Replace the view controller's old view with this one. */
   1.100 +        [data.viewcontroller.view removeFromSuperview];
   1.101 +        data.viewcontroller.view = self;
   1.102 +
   1.103 +        if (data.uiwindow.rootViewController != data.viewcontroller) {
   1.104 +            /* The root view controller handles rotation and the status bar.
   1.105 +             * Assigning it also adds the controller's view to the window. */
   1.106 +            data.uiwindow.rootViewController = data.viewcontroller;
   1.107 +        } else {
   1.108 +            [data.uiwindow addSubview:self];
   1.109 +        }
   1.110 +
   1.111 +        /* The view's bounds may not be correct until the next event cycle. That
   1.112 +         * might happen after the current dimensions are queried, so we force a
   1.113 +         * layout now to immediately update the bounds. */
   1.114 +        [data.uiwindow layoutIfNeeded];
   1.115 +    }
   1.116 +
   1.117 +    sdlwindow = window;
   1.118  }
   1.119  
   1.120  - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
   1.121 @@ -88,16 +129,16 @@
   1.122  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
   1.123  {
   1.124      for (UITouch *touch in touches) {
   1.125 -        if (!leftFingerDown) {
   1.126 +        if (!firstFingerDown) {
   1.127              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   1.128  
   1.129 -            /* send moved event */
   1.130 +            /* send mouse moved event */
   1.131              SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
   1.132  
   1.133              /* send mouse down event */
   1.134              SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
   1.135  
   1.136 -            leftFingerDown = touch;
   1.137 +            firstFingerDown = touch;
   1.138          }
   1.139  
   1.140          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   1.141 @@ -109,10 +150,10 @@
   1.142  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   1.143  {
   1.144      for (UITouch *touch in touches) {
   1.145 -        if (touch == leftFingerDown) {
   1.146 +        if (touch == firstFingerDown) {
   1.147              /* send mouse up */
   1.148              SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   1.149 -            leftFingerDown = nil;
   1.150 +            firstFingerDown = nil;
   1.151          }
   1.152  
   1.153          CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   1.154 @@ -123,18 +164,13 @@
   1.155  
   1.156  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
   1.157  {
   1.158 -    /*
   1.159 -        this can happen if the user puts more than 5 touches on the screen
   1.160 -        at once, or perhaps in other circumstances.  Usually (it seems)
   1.161 -        all active touches are canceled.
   1.162 -    */
   1.163      [self touchesEnded:touches withEvent:event];
   1.164  }
   1.165  
   1.166  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
   1.167  {
   1.168      for (UITouch *touch in touches) {
   1.169 -        if (touch == leftFingerDown) {
   1.170 +        if (touch == firstFingerDown) {
   1.171              CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   1.172  
   1.173              /* send moved event */
   1.174 @@ -147,274 +183,8 @@
   1.175      }
   1.176  }
   1.177  
   1.178 -/*
   1.179 -    ---- Keyboard related functionality below this line ----
   1.180 -*/
   1.181 -#if SDL_IPHONE_KEYBOARD
   1.182 -
   1.183 -@synthesize textInputRect;
   1.184 -@synthesize keyboardHeight;
   1.185 -@synthesize keyboardVisible;
   1.186 -
   1.187 -/* Set ourselves up as a UITextFieldDelegate */
   1.188 -- (void)initKeyboard
   1.189 -{
   1.190 -    textField = [[UITextField alloc] initWithFrame:CGRectZero];
   1.191 -    textField.delegate = self;
   1.192 -    /* placeholder so there is something to delete! */
   1.193 -    textField.text = @" ";
   1.194 -
   1.195 -    /* set UITextInputTrait properties, mostly to defaults */
   1.196 -    textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   1.197 -    textField.autocorrectionType = UITextAutocorrectionTypeNo;
   1.198 -    textField.enablesReturnKeyAutomatically = NO;
   1.199 -    textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   1.200 -    textField.keyboardType = UIKeyboardTypeDefault;
   1.201 -    textField.returnKeyType = UIReturnKeyDefault;
   1.202 -    textField.secureTextEntry = NO;
   1.203 -
   1.204 -    textField.hidden = YES;
   1.205 -    keyboardVisible = NO;
   1.206 -    /* add the UITextField (hidden) to our view */
   1.207 -    [self addSubview:textField];
   1.208 -
   1.209 -    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
   1.210 -    [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
   1.211 -    [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
   1.212 -}
   1.213 -
   1.214 -- (void)deinitKeyboard
   1.215 -{
   1.216 -    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
   1.217 -    [center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
   1.218 -    [center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
   1.219 -}
   1.220 -
   1.221 -/* reveal onscreen virtual keyboard */
   1.222 -- (void)showKeyboard
   1.223 -{
   1.224 -    keyboardVisible = YES;
   1.225 -    [textField becomeFirstResponder];
   1.226 -}
   1.227 -
   1.228 -/* hide onscreen virtual keyboard */
   1.229 -- (void)hideKeyboard
   1.230 -{
   1.231 -    keyboardVisible = NO;
   1.232 -    [textField resignFirstResponder];
   1.233 -}
   1.234 -
   1.235 -- (void)keyboardWillShow:(NSNotification *)notification
   1.236 -{
   1.237 -    CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
   1.238 -    int height;
   1.239 -
   1.240 -    /* The keyboard rect is in the coordinate space of the screen, but we want
   1.241 -     * its height in the view's coordinate space.
   1.242 -     */
   1.243 -#ifdef __IPHONE_8_0
   1.244 -    if ([self respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) {
   1.245 -        UIScreen *screen = self.window.screen;
   1.246 -        kbrect = [self convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace];
   1.247 -        height = kbrect.size.height;
   1.248 -    } else
   1.249 -#endif
   1.250 -    {
   1.251 -        /* In iOS 7 and below, the screen's coordinate space is never rotated. */
   1.252 -        if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
   1.253 -            height = kbrect.size.width;
   1.254 -        } else {
   1.255 -            height = kbrect.size.height;
   1.256 -        }
   1.257 -    }
   1.258 -
   1.259 -    [self setKeyboardHeight:height];
   1.260 -}
   1.261 -
   1.262 - - (void)keyboardWillHide:(NSNotification *)notification
   1.263 -{
   1.264 -    [self setKeyboardHeight:0];
   1.265 -}
   1.266 -
   1.267 -- (void)updateKeyboard
   1.268 -{
   1.269 -    SDL_Rect textrect = self.textInputRect;
   1.270 -    CGAffineTransform t = self.transform;
   1.271 -    CGPoint offset = CGPointMake(0.0, 0.0);
   1.272 -
   1.273 -    if (self.keyboardHeight) {
   1.274 -        int rectbottom = textrect.y + textrect.h;
   1.275 -        int kbottom = self.bounds.size.height - self.keyboardHeight;
   1.276 -        if (kbottom < rectbottom) {
   1.277 -            offset.y = kbottom - rectbottom;
   1.278 -        }
   1.279 -    }
   1.280 -
   1.281 -    /* Put the offset into the this view transform's coordinate space. */
   1.282 -    t.tx = 0.0;
   1.283 -    t.ty = 0.0;
   1.284 -    offset = CGPointApplyAffineTransform(offset, t);
   1.285 -
   1.286 -    t.tx = offset.x;
   1.287 -    t.ty = offset.y;
   1.288 -
   1.289 -    /* Move the view by applying the updated transform. */
   1.290 -    self.transform = t;
   1.291 -}
   1.292 -
   1.293 -- (void)setKeyboardHeight:(int)height
   1.294 -{
   1.295 -    keyboardVisible = height > 0;
   1.296 -    keyboardHeight = height;
   1.297 -    [self updateKeyboard];
   1.298 -}
   1.299 -
   1.300 -/* UITextFieldDelegate method.  Invoked when user types something. */
   1.301 -- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
   1.302 -{
   1.303 -    NSUInteger len = string.length;
   1.304 -
   1.305 -    if (len == 0) {
   1.306 -        /* it wants to replace text with nothing, ie a delete */
   1.307 -        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
   1.308 -        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
   1.309 -    } else {
   1.310 -        /* go through all the characters in the string we've been sent
   1.311 -           and convert them to key presses */
   1.312 -        for (int i = 0; i < len; i++) {
   1.313 -            unichar c = [string characterAtIndex:i];
   1.314 -            Uint16 mod = 0;
   1.315 -            SDL_Scancode code;
   1.316 -
   1.317 -            if (c < 127) {
   1.318 -                /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   1.319 -                code = unicharToUIKeyInfoTable[c].code;
   1.320 -                mod  = unicharToUIKeyInfoTable[c].mod;
   1.321 -            }
   1.322 -            else {
   1.323 -                /* we only deal with ASCII right now */
   1.324 -                code = SDL_SCANCODE_UNKNOWN;
   1.325 -                mod = 0;
   1.326 -            }
   1.327 -
   1.328 -            if (mod & KMOD_SHIFT) {
   1.329 -                /* If character uses shift, press shift down */
   1.330 -                SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   1.331 -            }
   1.332 -
   1.333 -            /* send a keydown and keyup even for the character */
   1.334 -            SDL_SendKeyboardKey(SDL_PRESSED, code);
   1.335 -            SDL_SendKeyboardKey(SDL_RELEASED, code);
   1.336 -
   1.337 -            if (mod & KMOD_SHIFT) {
   1.338 -                /* If character uses shift, press shift back up */
   1.339 -                SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   1.340 -            }
   1.341 -        }
   1.342 -
   1.343 -        SDL_SendKeyboardText([string UTF8String]);
   1.344 -    }
   1.345 -
   1.346 -    return NO; /* don't allow the edit! (keep placeholder text there) */
   1.347 -}
   1.348 -
   1.349 -/* Terminates the editing session */
   1.350 -- (BOOL)textFieldShouldReturn:(UITextField*)_textField
   1.351 -{
   1.352 -    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   1.353 -    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
   1.354 -    SDL_StopTextInput();
   1.355 -    return YES;
   1.356 -}
   1.357 -
   1.358 -#endif
   1.359 -
   1.360  @end
   1.361  
   1.362 -/* iPhone keyboard addition functions */
   1.363 -#if SDL_IPHONE_KEYBOARD
   1.364 -
   1.365 -static SDL_uikitview *
   1.366 -GetWindowView(SDL_Window * window)
   1.367 -{
   1.368 -    if (window == NULL) {
   1.369 -        SDL_SetError("Window does not exist");
   1.370 -        return nil;
   1.371 -    }
   1.372 -
   1.373 -    SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
   1.374 -    SDL_uikitview *view = data != nil ? data.view : nil;
   1.375 -
   1.376 -    if (view == nil) {
   1.377 -        SDL_SetError("Window has no view");
   1.378 -    }
   1.379 -
   1.380 -    return view;
   1.381 -}
   1.382 -
   1.383 -SDL_bool
   1.384 -UIKit_HasScreenKeyboardSupport(_THIS)
   1.385 -{
   1.386 -    return SDL_TRUE;
   1.387 -}
   1.388 -
   1.389 -void
   1.390 -UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
   1.391 -{
   1.392 -    @autoreleasepool {
   1.393 -        SDL_uikitview *view = GetWindowView(window);
   1.394 -        if (view != nil) {
   1.395 -            [view showKeyboard];
   1.396 -        }
   1.397 -    }
   1.398 -}
   1.399 -
   1.400 -void
   1.401 -UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
   1.402 -{
   1.403 -    @autoreleasepool {
   1.404 -        SDL_uikitview *view = GetWindowView(window);
   1.405 -        if (view != nil) {
   1.406 -            [view hideKeyboard];
   1.407 -        }
   1.408 -    }
   1.409 -}
   1.410 -
   1.411 -SDL_bool
   1.412 -UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
   1.413 -{
   1.414 -    @autoreleasepool {
   1.415 -        SDL_uikitview *view = GetWindowView(window);
   1.416 -        if (view != nil) {
   1.417 -            return view.isKeyboardVisible;
   1.418 -        }
   1.419 -        return 0;
   1.420 -    }
   1.421 -}
   1.422 -
   1.423 -void
   1.424 -UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
   1.425 -{
   1.426 -    if (!rect) {
   1.427 -        SDL_InvalidParamError("rect");
   1.428 -        return;
   1.429 -    }
   1.430 -
   1.431 -    @autoreleasepool {
   1.432 -        SDL_uikitview *view = GetWindowView(SDL_GetFocusWindow());
   1.433 -        if (view != nil) {
   1.434 -            view.textInputRect = *rect;
   1.435 -
   1.436 -            if (view.keyboardVisible) {
   1.437 -                [view updateKeyboard];
   1.438 -            }
   1.439 -        }
   1.440 -    }
   1.441 -}
   1.442 -
   1.443 -
   1.444 -#endif /* SDL_IPHONE_KEYBOARD */
   1.445 -
   1.446  #endif /* SDL_VIDEO_DRIVER_UIKIT */
   1.447  
   1.448  /* vi: set ts=4 sw=4 expandtab: */