src/video/uikit/SDL_uikitview.m
author Alex Szpakowski <slime73@gmail.com>
Thu, 20 Nov 2014 18:45:04 -0400
branchiOS-improvements
changeset 9524 9de159f9cefd
parent 9519 37ade10d4570
child 9525 64e3f446d6d7
permissions -rw-r--r--
Minor objective-c code style improvements
     1  /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_UIKIT
    24 
    25 #include "SDL_uikitview.h"
    26 
    27 #include "../../events/SDL_keyboard_c.h"
    28 #include "../../events/SDL_mouse_c.h"
    29 #include "../../events/SDL_touch_c.h"
    30 
    31 #if SDL_IPHONE_KEYBOARD
    32 #include "keyinfotable.h"
    33 #endif
    34 #include "SDL_uikitappdelegate.h"
    35 #include "SDL_uikitmodes.h"
    36 #include "SDL_uikitwindow.h"
    37 
    38 void _uikit_keyboard_init();
    39 
    40 @implementation SDL_uikitview {
    41 
    42     SDL_TouchID touchId;
    43     UITouch *leftFingerDown;
    44 
    45 #if SDL_IPHONE_KEYBOARD
    46     UITextField *textField;
    47 #endif
    48 
    49 }
    50 
    51 @synthesize viewcontroller;
    52 
    53 - (id)initWithFrame:(CGRect)frame
    54 {
    55     if (self = [super initWithFrame:frame]) {
    56 #if SDL_IPHONE_KEYBOARD
    57         [self initializeKeyboard];
    58 #endif
    59 
    60         self.multipleTouchEnabled = YES;
    61 
    62         touchId = 1;
    63         SDL_AddTouch(touchId, "");
    64     }
    65 
    66     return self;
    67 
    68 }
    69 
    70 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
    71 {
    72     CGPoint point = [touch locationInView:self];
    73 
    74     if (normalize) {
    75         CGRect bounds = self.bounds;
    76         point.x /= bounds.size.width;
    77         point.y /= bounds.size.height;
    78     }
    79 
    80     return point;
    81 }
    82 
    83 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    84 {
    85     for (UITouch *touch in touches) {
    86         if (!leftFingerDown) {
    87             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
    88 
    89             /* send moved event */
    90             SDL_SendMouseMotion(self.viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
    91 
    92             /* send mouse down event */
    93             SDL_SendMouseButton(self.viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    94 
    95             leftFingerDown = touch;
    96         }
    97 
    98         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
    99         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
   100                       SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   101     }
   102 }
   103 
   104 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   105 {
   106     for (UITouch *touch in touches) {
   107         if (touch == leftFingerDown) {
   108             /* send mouse up */
   109             SDL_SendMouseButton(self.viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   110             leftFingerDown = nil;
   111         }
   112 
   113         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   114         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
   115                       SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   116     }
   117 }
   118 
   119 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
   120 {
   121     /*
   122         this can happen if the user puts more than 5 touches on the screen
   123         at once, or perhaps in other circumstances.  Usually (it seems)
   124         all active touches are canceled.
   125     */
   126     [self touchesEnded:touches withEvent:event];
   127 }
   128 
   129 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
   130 {
   131     for (UITouch *touch in touches) {
   132         if (touch == leftFingerDown) {
   133             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   134 
   135             /* send moved event */
   136             SDL_SendMouseMotion(self.viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
   137         }
   138 
   139         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   140         SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
   141                             locationInView.x, locationInView.y, 1.0f);
   142     }
   143 }
   144 
   145 /*
   146     ---- Keyboard related functionality below this line ----
   147 */
   148 #if SDL_IPHONE_KEYBOARD
   149 
   150 @synthesize textInputRect;
   151 @synthesize keyboardHeight;
   152 @synthesize keyboardVisible;
   153 
   154 /* Set ourselves up as a UITextFieldDelegate */
   155 - (void)initializeKeyboard
   156 {
   157     textField = [[UITextField alloc] initWithFrame:CGRectZero];
   158     textField.delegate = self;
   159     /* placeholder so there is something to delete! */
   160     textField.text = @" ";
   161 
   162     /* set UITextInputTrait properties, mostly to defaults */
   163     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   164     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   165     textField.enablesReturnKeyAutomatically = NO;
   166     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   167     textField.keyboardType = UIKeyboardTypeDefault;
   168     textField.returnKeyType = UIReturnKeyDefault;
   169     textField.secureTextEntry = NO;
   170 
   171     textField.hidden = YES;
   172     keyboardVisible = NO;
   173     /* add the UITextField (hidden) to our view */
   174     [self addSubview:textField];
   175     
   176     _uikit_keyboard_init();
   177 }
   178 
   179 /* reveal onscreen virtual keyboard */
   180 - (void)showKeyboard
   181 {
   182     keyboardVisible = YES;
   183     [textField becomeFirstResponder];
   184 }
   185 
   186 /* hide onscreen virtual keyboard */
   187 - (void)hideKeyboard
   188 {
   189     keyboardVisible = NO;
   190     [textField resignFirstResponder];
   191 }
   192 
   193 /* UITextFieldDelegate method.  Invoked when user types something. */
   194 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
   195 {
   196     if ([string length] == 0) {
   197         /* it wants to replace text with nothing, ie a delete */
   198         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
   199         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
   200     }
   201     else {
   202         /* go through all the characters in the string we've been sent
   203            and convert them to key presses */
   204         int i;
   205         for (i = 0; i < [string length]; i++) {
   206 
   207             unichar c = [string characterAtIndex:i];
   208 
   209             Uint16 mod = 0;
   210             SDL_Scancode code;
   211 
   212             if (c < 127) {
   213                 /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   214                 code = unicharToUIKeyInfoTable[c].code;
   215                 mod  = unicharToUIKeyInfoTable[c].mod;
   216             }
   217             else {
   218                 /* we only deal with ASCII right now */
   219                 code = SDL_SCANCODE_UNKNOWN;
   220                 mod = 0;
   221             }
   222 
   223             if (mod & KMOD_SHIFT) {
   224                 /* If character uses shift, press shift down */
   225                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   226             }
   227             /* send a keydown and keyup even for the character */
   228             SDL_SendKeyboardKey(SDL_PRESSED, code);
   229             SDL_SendKeyboardKey(SDL_RELEASED, code);
   230             if (mod & KMOD_SHIFT) {
   231                 /* If character uses shift, press shift back up */
   232                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   233             }
   234         }
   235         SDL_SendKeyboardText([string UTF8String]);
   236     }
   237     return NO; /* don't allow the edit! (keep placeholder text there) */
   238 }
   239 
   240 /* Terminates the editing session */
   241 - (BOOL)textFieldShouldReturn:(UITextField*)_textField
   242 {
   243     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   244     SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
   245     SDL_StopTextInput();
   246     return YES;
   247 }
   248 
   249 #endif
   250 
   251 @end
   252 
   253 /* iPhone keyboard addition functions */
   254 #if SDL_IPHONE_KEYBOARD
   255 
   256 static SDL_uikitview * getWindowView(SDL_Window * window)
   257 {
   258     if (window == NULL) {
   259         SDL_SetError("Window does not exist");
   260         return nil;
   261     }
   262 
   263     SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
   264     SDL_uikitview *view = data != nil ? data.view : nil;
   265 
   266     if (view == nil) {
   267         SDL_SetError("Window has no view");
   268     }
   269 
   270     return view;
   271 }
   272 
   273 SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
   274 {
   275     return SDL_TRUE;
   276 }
   277 
   278 void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
   279 {
   280     @autoreleasepool {
   281         SDL_uikitview *view = getWindowView(window);
   282         if (view != nil) {
   283             [view showKeyboard];
   284         }
   285     }
   286 }
   287 
   288 void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
   289 {
   290     @autoreleasepool {
   291         SDL_uikitview *view = getWindowView(window);
   292         if (view != nil) {
   293             [view hideKeyboard];
   294         }
   295     }
   296 }
   297 
   298 SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
   299 {
   300     @autoreleasepool {
   301         SDL_uikitview *view = getWindowView(window);
   302         if (view == nil) {
   303             return 0;
   304         }
   305 
   306         return view.isKeyboardVisible;
   307     }
   308 }
   309 
   310 
   311 void _uikit_keyboard_update() {
   312     SDL_Window *window = SDL_GetFocusWindow();
   313     if (!window) { return; }
   314     SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
   315     if (!data) { return; }
   316     SDL_uikitview *view = data.view;
   317     if (!view) { return; }
   318 
   319     SDL_Rect r = view.textInputRect;
   320     int height = view.keyboardHeight;
   321     int offsetx = 0;
   322     int offsety = 0;
   323     if (height) {
   324         int sw,sh;
   325         SDL_GetWindowSize(window,&sw,&sh);
   326         int bottom = (r.y + r.h);
   327         int kbottom = sh - height;
   328         if (kbottom < bottom) {
   329             offsety = kbottom-bottom;
   330         }
   331     }
   332     UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
   333     if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
   334         int tmp = offsetx; offsetx = offsety; offsety = tmp;
   335     }
   336     if (ui_orient == UIInterfaceOrientationLandscapeRight) {
   337         offsety = -offsety;
   338         int tmp = offsetx; offsetx = offsety; offsety = tmp;
   339     }
   340     if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
   341         offsety = -offsety;
   342     }
   343 
   344     view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
   345 }
   346 
   347 void _uikit_keyboard_set_height(int height) {
   348     SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
   349     if (view == nil) {
   350         return;
   351     }
   352 
   353     view.keyboardVisible = height > 0;
   354     view.keyboardHeight = height;
   355     _uikit_keyboard_update();
   356 }
   357 
   358 void _uikit_keyboard_init() {
   359     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
   360     NSOperationQueue *queue = [NSOperationQueue mainQueue];
   361     [center addObserverForName:UIKeyboardWillShowNotification
   362                         object:nil
   363                          queue:queue
   364                     usingBlock:^(NSNotification *notification) {
   365                         int height = 0;
   366                         CGSize keyboardSize = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
   367                         height = keyboardSize.height;
   368                         UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
   369                         if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
   370                             height = keyboardSize.width;
   371                         }
   372                         _uikit_keyboard_set_height(height);
   373                     }
   374      ];
   375     [center addObserverForName:UIKeyboardDidHideNotification
   376                         object:nil
   377                          queue:queue
   378                     usingBlock:^(NSNotification *notification) {
   379                         _uikit_keyboard_set_height(0);
   380                     }
   381      ];
   382 }
   383 
   384 void
   385 UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
   386 {
   387     if (!rect) {
   388         SDL_InvalidParamError("rect");
   389         return;
   390     }
   391 
   392     @autoreleasepool {
   393         SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
   394         if (view == nil) {
   395             return;
   396         }
   397 
   398         view.textInputRect = *rect;
   399     }
   400 }
   401 
   402 
   403 #endif /* SDL_IPHONE_KEYBOARD */
   404 
   405 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   406 
   407 /* vi: set ts=4 sw=4 expandtab: */