src/video/uikit/SDL_uikitview.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 11:00:25 -0700
changeset 8983 21f5923cfd15
parent 8891 7b6472f1b7ba
child 9487 f9fbc2d1edb0
permissions -rw-r--r--
Fixed compiler warnings on iOS
     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 - (void)dealloc
    43 {
    44     [super dealloc];
    45 }
    46 
    47 - (id)initWithFrame:(CGRect)frame
    48 {
    49     self = [super initWithFrame: frame];
    50 
    51 #if SDL_IPHONE_KEYBOARD
    52     [self initializeKeyboard];
    53 #endif
    54 
    55     self.multipleTouchEnabled = YES;
    56 
    57     touchId = 1;
    58     SDL_AddTouch(touchId, "");
    59 
    60     return self;
    61 
    62 }
    63 
    64 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
    65 {
    66     CGPoint point = [touch locationInView: self];
    67 
    68     /* Get the display scale and apply that to the input coordinates */
    69     SDL_Window *window = self->viewcontroller.window;
    70     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    71     SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
    72 
    73     if (normalize) {
    74         CGRect bounds = [self bounds];
    75         point.x /= bounds.size.width;
    76         point.y /= bounds.size.height;
    77     } else {
    78         point.x *= displaymodedata->scale;
    79         point.y *= displaymodedata->scale;
    80     }
    81     return point;
    82 }
    83 
    84 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    85 {
    86     NSEnumerator *enumerator = [touches objectEnumerator];
    87     UITouch *touch = (UITouch*)[enumerator nextObject];
    88 
    89     while (touch) {
    90         if (!leftFingerDown) {
    91             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
    92 
    93             /* send moved event */
    94             SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
    95 
    96             /* send mouse down event */
    97             SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    98 
    99             leftFingerDown = touch;
   100         }
   101 
   102         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   103 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   104         /* FIXME: TODO: Using touch as the fingerId is potentially dangerous
   105          * It is also much more efficient than storing the UITouch pointer
   106          * and comparing it to the incoming event.
   107          */
   108         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
   109                       SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   110 #else
   111         int i;
   112         for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   113             if (finger[i] == NULL) {
   114                 finger[i] = touch;
   115                 SDL_SendTouch(touchId, i,
   116                               SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   117                 break;
   118             }
   119         }
   120 #endif
   121         touch = (UITouch*)[enumerator nextObject];
   122     }
   123 }
   124 
   125 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   126 {
   127     NSEnumerator *enumerator = [touches objectEnumerator];
   128     UITouch *touch = (UITouch*)[enumerator nextObject];
   129 
   130     while(touch) {
   131         if (touch == leftFingerDown) {
   132             /* send mouse up */
   133             SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   134             leftFingerDown = nil;
   135         }
   136 
   137         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   138 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   139         SDL_SendTouch(touchId, (long)touch,
   140                       SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   141 #else
   142         int i;
   143         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   144             if (finger[i] == touch) {
   145                 SDL_SendTouch(touchId, i,
   146                               SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   147                 finger[i] = NULL;
   148                 break;
   149             }
   150         }
   151 #endif
   152         touch = (UITouch*)[enumerator nextObject];
   153     }
   154 }
   155 
   156 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
   157 {
   158     /*
   159         this can happen if the user puts more than 5 touches on the screen
   160         at once, or perhaps in other circumstances.  Usually (it seems)
   161         all active touches are canceled.
   162     */
   163     [self touchesEnded: touches withEvent: event];
   164 }
   165 
   166 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
   167 {
   168     NSEnumerator *enumerator = [touches objectEnumerator];
   169     UITouch *touch = (UITouch*)[enumerator nextObject];
   170 
   171     while (touch) {
   172         if (touch == leftFingerDown) {
   173             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   174 
   175             /* send moved event */
   176             SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
   177         }
   178 
   179         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   180 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   181         SDL_SendTouchMotion(touchId, (long)touch,
   182                             locationInView.x, locationInView.y, 1.0f);
   183 #else
   184         int i;
   185         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   186             if (finger[i] == touch) {
   187                 SDL_SendTouchMotion(touchId, i,
   188                                     locationInView.x, locationInView.y, 1.0f);
   189                 break;
   190             }
   191         }
   192 #endif
   193         touch = (UITouch*)[enumerator nextObject];
   194     }
   195 }
   196 
   197 /*
   198     ---- Keyboard related functionality below this line ----
   199 */
   200 #if SDL_IPHONE_KEYBOARD
   201 
   202 @synthesize textInputRect = textInputRect;
   203 @synthesize keyboardHeight = keyboardHeight;
   204 
   205 /* Is the iPhone virtual keyboard visible onscreen? */
   206 - (BOOL)keyboardVisible
   207 {
   208     return keyboardVisible;
   209 }
   210 
   211 /* Set ourselves up as a UITextFieldDelegate */
   212 - (void)initializeKeyboard
   213 {
   214     textField = [[UITextField alloc] initWithFrame: CGRectZero];
   215     textField.delegate = self;
   216     /* placeholder so there is something to delete! */
   217     textField.text = @" ";
   218 
   219     /* set UITextInputTrait properties, mostly to defaults */
   220     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   221     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   222     textField.enablesReturnKeyAutomatically = NO;
   223     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   224     textField.keyboardType = UIKeyboardTypeDefault;
   225     textField.returnKeyType = UIReturnKeyDefault;
   226     textField.secureTextEntry = NO;
   227 
   228     textField.hidden = YES;
   229     keyboardVisible = NO;
   230     /* add the UITextField (hidden) to our view */
   231     [self addSubview: textField];
   232     [textField release];
   233     
   234     _uikit_keyboard_init();
   235 }
   236 
   237 /* reveal onscreen virtual keyboard */
   238 - (void)showKeyboard
   239 {
   240     keyboardVisible = YES;
   241     [textField becomeFirstResponder];
   242 }
   243 
   244 /* hide onscreen virtual keyboard */
   245 - (void)hideKeyboard
   246 {
   247     keyboardVisible = NO;
   248     [textField resignFirstResponder];
   249 }
   250 
   251 /* UITextFieldDelegate method.  Invoked when user types something. */
   252 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
   253 {
   254     if ([string length] == 0) {
   255         /* it wants to replace text with nothing, ie a delete */
   256         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
   257         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
   258     }
   259     else {
   260         /* go through all the characters in the string we've been sent
   261            and convert them to key presses */
   262         int i;
   263         for (i = 0; i < [string length]; i++) {
   264 
   265             unichar c = [string characterAtIndex: i];
   266 
   267             Uint16 mod = 0;
   268             SDL_Scancode code;
   269 
   270             if (c < 127) {
   271                 /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   272                 code = unicharToUIKeyInfoTable[c].code;
   273                 mod  = unicharToUIKeyInfoTable[c].mod;
   274             }
   275             else {
   276                 /* we only deal with ASCII right now */
   277                 code = SDL_SCANCODE_UNKNOWN;
   278                 mod = 0;
   279             }
   280 
   281             if (mod & KMOD_SHIFT) {
   282                 /* If character uses shift, press shift down */
   283                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   284             }
   285             /* send a keydown and keyup even for the character */
   286             SDL_SendKeyboardKey(SDL_PRESSED, code);
   287             SDL_SendKeyboardKey(SDL_RELEASED, code);
   288             if (mod & KMOD_SHIFT) {
   289                 /* If character uses shift, press shift back up */
   290                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   291             }
   292         }
   293         SDL_SendKeyboardText([string UTF8String]);
   294     }
   295     return NO; /* don't allow the edit! (keep placeholder text there) */
   296 }
   297 
   298 /* Terminates the editing session */
   299 - (BOOL)textFieldShouldReturn:(UITextField*)_textField
   300 {
   301     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   302     SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
   303     SDL_StopTextInput();
   304     return YES;
   305 }
   306 
   307 #endif
   308 
   309 @end
   310 
   311 /* iPhone keyboard addition functions */
   312 #if SDL_IPHONE_KEYBOARD
   313 
   314 static SDL_uikitview * getWindowView(SDL_Window * window)
   315 {
   316     if (window == NULL) {
   317         SDL_SetError("Window does not exist");
   318         return nil;
   319     }
   320 
   321     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   322     SDL_uikitview *view = data != NULL ? data->view : nil;
   323 
   324     if (view == nil) {
   325         SDL_SetError("Window has no view");
   326     }
   327 
   328     return view;
   329 }
   330 
   331 SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
   332 {
   333     return SDL_TRUE;
   334 }
   335 
   336 void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
   337 {
   338     SDL_uikitview *view = getWindowView(window);
   339     if (view != nil) {
   340         [view showKeyboard];
   341     }
   342 }
   343 
   344 void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
   345 {
   346     SDL_uikitview *view = getWindowView(window);
   347     if (view != nil) {
   348         [view hideKeyboard];
   349     }
   350 }
   351 
   352 SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
   353 {
   354     SDL_uikitview *view = getWindowView(window);
   355     if (view == nil) {
   356         return 0;
   357     }
   358 
   359     return view.keyboardVisible;
   360 }
   361 
   362 
   363 void _uikit_keyboard_update() {
   364     SDL_Window *window = SDL_GetFocusWindow();
   365     if (!window) { return; }
   366     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   367     if (!data) { return; }
   368     SDL_uikitview *view = data->view;
   369     if (!view) { return; }
   370     
   371     SDL_Rect r = view.textInputRect;
   372     int height = view.keyboardHeight;
   373     int offsetx = 0;
   374     int offsety = 0;
   375     float scale = [UIScreen mainScreen].scale;
   376     if (height) {
   377         int sw,sh;
   378         SDL_GetWindowSize(window,&sw,&sh);
   379         int bottom = (r.y + r.h);
   380         int kbottom = sh - height;
   381         if (kbottom < bottom) {
   382             offsety = kbottom-bottom;
   383         }
   384     }
   385     UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
   386     if (ui_orient == UIInterfaceOrientationLandscapeLeft) {
   387         int tmp = offsetx; offsetx = offsety; offsety = tmp;
   388     }
   389     if (ui_orient == UIInterfaceOrientationLandscapeRight) {
   390         offsety = -offsety;
   391         int tmp = offsetx; offsetx = offsety; offsety = tmp;
   392     }
   393     if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) {
   394         offsety = -offsety;
   395     }
   396 
   397     offsetx /= scale;
   398     offsety /= scale;
   399 
   400     view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height);
   401 }
   402 
   403 void _uikit_keyboard_set_height(int height) {
   404     SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
   405     if (view == nil) {
   406         return ;
   407     }
   408     
   409     view.keyboardHeight = height;
   410     _uikit_keyboard_update();
   411 }
   412 
   413 void _uikit_keyboard_init() {
   414     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
   415     NSOperationQueue *queue = [NSOperationQueue mainQueue];
   416     [center addObserverForName:UIKeyboardWillShowNotification
   417                         object:nil
   418                          queue:queue
   419                     usingBlock:^(NSNotification *notification) {
   420                         int height = 0;
   421                         CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
   422                         height = keyboardSize.height;
   423                         UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation];
   424                         if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) {
   425                             height = keyboardSize.width;
   426                         }
   427                         height *= [UIScreen mainScreen].scale;
   428                         _uikit_keyboard_set_height(height);
   429                     }
   430      ];
   431     [center addObserverForName:UIKeyboardDidHideNotification
   432                         object:nil
   433                          queue:queue
   434                     usingBlock:^(NSNotification *notification) {
   435                         _uikit_keyboard_set_height(0);
   436                     }
   437      ];
   438 }
   439 
   440 void
   441 UIKit_SetTextInputRect(_THIS, SDL_Rect *rect)
   442 {
   443     if (!rect) {
   444         SDL_InvalidParamError("rect");
   445         return;
   446     }
   447     
   448     SDL_uikitview *view = getWindowView(SDL_GetFocusWindow());
   449     if (view == nil) {
   450         return ;
   451     }
   452 
   453     view.textInputRect = *rect;
   454 }
   455 
   456 
   457 #endif /* SDL_IPHONE_KEYBOARD */
   458 
   459 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   460 
   461 /* vi: set ts=4 sw=4 expandtab: */