src/video/uikit/SDL_uikitview.m
author Ryan C. Gordon <icculus@icculus.org>
Wed, 02 Oct 2013 22:18:04 -0400
changeset 7774 c5d6c8c001be
parent 7191 75360622e65f
child 7962 e4d2f3375868
child 8535 e8ee0708ef5c
permissions -rw-r--r--
SDLK_DELETE should probably be SDLK_BACKSPACE on iOS.

The key on the software keyboard works like backspace, at least. Not sure
what happens with a bluetooth keyboard here.
     1  /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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 @implementation SDL_uikitview
    39 
    40 - (void)dealloc
    41 {
    42     [super dealloc];
    43 }
    44 
    45 - (id)initWithFrame:(CGRect)frame
    46 {
    47     self = [super initWithFrame: frame];
    48 
    49 #if SDL_IPHONE_KEYBOARD
    50     [self initializeKeyboard];
    51 #endif
    52 
    53     self.multipleTouchEnabled = YES;
    54 
    55     touchId = 1;
    56     SDL_AddTouch(touchId, "");
    57 
    58     return self;
    59 
    60 }
    61 
    62 - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
    63 {
    64     CGPoint point = [touch locationInView: self];
    65 
    66     /* Get the display scale and apply that to the input coordinates */
    67     SDL_Window *window = self->viewcontroller.window;
    68     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    69     SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
    70 
    71     if (normalize) {
    72         CGRect bounds = [self bounds];
    73         point.x /= bounds.size.width;
    74         point.y /= bounds.size.height;
    75     } else {
    76         point.x *= displaymodedata->scale;
    77         point.y *= displaymodedata->scale;
    78     }
    79     return point;
    80 }
    81 
    82 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    83 {
    84     NSEnumerator *enumerator = [touches objectEnumerator];
    85     UITouch *touch = (UITouch*)[enumerator nextObject];
    86 
    87     while (touch) {
    88         if (!leftFingerDown) {
    89             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
    90 
    91             /* send moved event */
    92             SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
    93 
    94             /* send mouse down event */
    95             SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    96 
    97             leftFingerDown = touch;
    98         }
    99 
   100         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   101 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   102         /* FIXME: TODO: Using touch as the fingerId is potentially dangerous
   103          * It is also much more efficient than storing the UITouch pointer
   104          * and comparing it to the incoming event.
   105          */
   106         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
   107                       SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   108 #else
   109         int i;
   110         for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   111             if (finger[i] == NULL) {
   112                 finger[i] = touch;
   113                 SDL_SendTouch(touchId, i,
   114                               SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   115                 break;
   116             }
   117         }
   118 #endif
   119         touch = (UITouch*)[enumerator nextObject];
   120     }
   121 }
   122 
   123 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   124 {
   125     NSEnumerator *enumerator = [touches objectEnumerator];
   126     UITouch *touch = (UITouch*)[enumerator nextObject];
   127 
   128     while(touch) {
   129         if (touch == leftFingerDown) {
   130             /* send mouse up */
   131             SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   132             leftFingerDown = nil;
   133         }
   134 
   135         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   136 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   137         SDL_SendTouch(touchId, (long)touch,
   138                       SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   139 #else
   140         int i;
   141         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   142             if (finger[i] == touch) {
   143                 SDL_SendTouch(touchId, i,
   144                               SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   145                 finger[i] = NULL;
   146                 break;
   147             }
   148         }
   149 #endif
   150         touch = (UITouch*)[enumerator nextObject];
   151     }
   152 }
   153 
   154 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
   155 {
   156     /*
   157         this can happen if the user puts more than 5 touches on the screen
   158         at once, or perhaps in other circumstances.  Usually (it seems)
   159         all active touches are canceled.
   160     */
   161     [self touchesEnded: touches withEvent: event];
   162 }
   163 
   164 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
   165 {
   166     NSEnumerator *enumerator = [touches objectEnumerator];
   167     UITouch *touch = (UITouch*)[enumerator nextObject];
   168 
   169     while (touch) {
   170         if (touch == leftFingerDown) {
   171             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   172 
   173             /* send moved event */
   174             SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
   175         }
   176 
   177         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   178 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   179         SDL_SendTouchMotion(touchId, (long)touch,
   180                             locationInView.x, locationInView.y, 1.0f);
   181 #else
   182         int i;
   183         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   184             if (finger[i] == touch) {
   185                 SDL_SendTouchMotion(touchId, i,
   186                                     locationInView.x, locationInView.y, 1.0f);
   187                 break;
   188             }
   189         }
   190 #endif
   191         touch = (UITouch*)[enumerator nextObject];
   192     }
   193 }
   194 
   195 /*
   196     ---- Keyboard related functionality below this line ----
   197 */
   198 #if SDL_IPHONE_KEYBOARD
   199 
   200 /* Is the iPhone virtual keyboard visible onscreen? */
   201 - (BOOL)keyboardVisible
   202 {
   203     return keyboardVisible;
   204 }
   205 
   206 /* Set ourselves up as a UITextFieldDelegate */
   207 - (void)initializeKeyboard
   208 {
   209     textField = [[UITextField alloc] initWithFrame: CGRectZero];
   210     textField.delegate = self;
   211     /* placeholder so there is something to delete! */
   212     textField.text = @" ";
   213 
   214     /* set UITextInputTrait properties, mostly to defaults */
   215     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   216     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   217     textField.enablesReturnKeyAutomatically = NO;
   218     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   219     textField.keyboardType = UIKeyboardTypeDefault;
   220     textField.returnKeyType = UIReturnKeyDefault;
   221     textField.secureTextEntry = NO;
   222 
   223     textField.hidden = YES;
   224     keyboardVisible = NO;
   225     /* add the UITextField (hidden) to our view */
   226     [self addSubview: textField];
   227     [textField release];
   228 }
   229 
   230 /* reveal onscreen virtual keyboard */
   231 - (void)showKeyboard
   232 {
   233     keyboardVisible = YES;
   234     [textField becomeFirstResponder];
   235 }
   236 
   237 /* hide onscreen virtual keyboard */
   238 - (void)hideKeyboard
   239 {
   240     keyboardVisible = NO;
   241     [textField resignFirstResponder];
   242 }
   243 
   244 /* UITextFieldDelegate method.  Invoked when user types something. */
   245 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
   246 {
   247     if ([string length] == 0) {
   248         /* it wants to replace text with nothing, ie a delete */
   249         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
   250         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
   251     }
   252     else {
   253         /* go through all the characters in the string we've been sent
   254            and convert them to key presses */
   255         int i;
   256         for (i = 0; i < [string length]; i++) {
   257 
   258             unichar c = [string characterAtIndex: i];
   259 
   260             Uint16 mod = 0;
   261             SDL_Scancode code;
   262 
   263             if (c < 127) {
   264                 /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   265                 code = unicharToUIKeyInfoTable[c].code;
   266                 mod  = unicharToUIKeyInfoTable[c].mod;
   267             }
   268             else {
   269                 /* we only deal with ASCII right now */
   270                 code = SDL_SCANCODE_UNKNOWN;
   271                 mod = 0;
   272             }
   273 
   274             if (mod & KMOD_SHIFT) {
   275                 /* If character uses shift, press shift down */
   276                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   277             }
   278             /* send a keydown and keyup even for the character */
   279             SDL_SendKeyboardKey(SDL_PRESSED, code);
   280             SDL_SendKeyboardKey(SDL_RELEASED, code);
   281             if (mod & KMOD_SHIFT) {
   282                 /* If character uses shift, press shift back up */
   283                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   284             }
   285         }
   286         SDL_SendKeyboardText([string UTF8String]);
   287     }
   288     return NO; /* don't allow the edit! (keep placeholder text there) */
   289 }
   290 
   291 /* Terminates the editing session */
   292 - (BOOL)textFieldShouldReturn:(UITextField*)_textField
   293 {
   294     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   295     SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
   296     SDL_StopTextInput();
   297     return YES;
   298 }
   299 
   300 #endif
   301 
   302 @end
   303 
   304 /* iPhone keyboard addition functions */
   305 #if SDL_IPHONE_KEYBOARD
   306 
   307 static SDL_uikitview * getWindowView(SDL_Window * window)
   308 {
   309     if (window == NULL) {
   310         SDL_SetError("Window does not exist");
   311         return nil;
   312     }
   313 
   314     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   315     SDL_uikitview *view = data != NULL ? data->view : nil;
   316 
   317     if (view == nil) {
   318         SDL_SetError("Window has no view");
   319     }
   320 
   321     return view;
   322 }
   323 
   324 SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
   325 {
   326     return SDL_TRUE;
   327 }
   328 
   329 void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
   330 {
   331     SDL_uikitview *view = getWindowView(window);
   332     if (view != nil) {
   333         [view showKeyboard];
   334     }
   335 }
   336 
   337 void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
   338 {
   339     SDL_uikitview *view = getWindowView(window);
   340     if (view != nil) {
   341         [view hideKeyboard];
   342     }
   343 }
   344 
   345 SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
   346 {
   347     SDL_uikitview *view = getWindowView(window);
   348     if (view == nil) {
   349         return 0;
   350     }
   351 
   352     return view.keyboardVisible;
   353 }
   354 
   355 #endif /* SDL_IPHONE_KEYBOARD */
   356 
   357 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   358 
   359 /* vi: set ts=4 sw=4 expandtab: */