src/video/uikit/SDL_uikitview.m
author Edward Rudd <urkle@outoforder.cc>
Thu, 25 Apr 2013 18:05:08 -0400
changeset 7111 f4ae9f1233df
parent 7050 aa1f44908402
child 7191 75360622e65f
permissions -rw-r--r--
Allow disabling SDL_IPHONE_KEYBOARD in iOS builds
     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         SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
   106                       SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   107 #else
   108         int i;
   109         for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   110             if (finger[i] == NULL) {
   111                 finger[i] = touch;
   112                 SDL_SendTouch(touchId, i,
   113                               SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
   114                 break;
   115             }
   116         }
   117 #endif
   118         touch = (UITouch*)[enumerator nextObject];
   119     }
   120 }
   121 
   122 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
   123 {
   124     NSEnumerator *enumerator = [touches objectEnumerator];
   125     UITouch *touch = (UITouch*)[enumerator nextObject];
   126 
   127     while(touch) {
   128         if (touch == leftFingerDown) {
   129             /* send mouse up */
   130             SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   131             leftFingerDown = nil;
   132         }
   133 
   134         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   135 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   136         SDL_SendTouch(touchId, (long)touch,
   137                       SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   138 #else
   139         int i;
   140         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   141             if (finger[i] == touch) {
   142                 SDL_SendTouch(touchId, i,
   143                               SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
   144                 finger[i] = NULL;
   145                 break;
   146             }
   147         }
   148 #endif
   149         touch = (UITouch*)[enumerator nextObject];
   150     }
   151 }
   152 
   153 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
   154 {
   155     /*
   156         this can happen if the user puts more than 5 touches on the screen
   157         at once, or perhaps in other circumstances.  Usually (it seems)
   158         all active touches are canceled.
   159     */
   160     [self touchesEnded: touches withEvent: event];
   161 }
   162 
   163 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
   164 {
   165     NSEnumerator *enumerator = [touches objectEnumerator];
   166     UITouch *touch = (UITouch*)[enumerator nextObject];
   167 
   168     while (touch) {
   169         if (touch == leftFingerDown) {
   170             CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
   171 
   172             /* send moved event */
   173             SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
   174         }
   175 
   176         CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
   177 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   178         SDL_SendTouchMotion(touchId, (long)touch,
   179                             locationInView.x, locationInView.y, 1.0f);
   180 #else
   181         int i;
   182         for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) {
   183             if (finger[i] == touch) {
   184                 SDL_SendTouchMotion(touchId, i,
   185                                     locationInView.x, locationInView.y, 1.0f);
   186                 break;
   187             }
   188         }
   189 #endif
   190         touch = (UITouch*)[enumerator nextObject];
   191     }
   192 }
   193 
   194 /*
   195     ---- Keyboard related functionality below this line ----
   196 */
   197 #if SDL_IPHONE_KEYBOARD
   198 
   199 /* Is the iPhone virtual keyboard visible onscreen? */
   200 - (BOOL)keyboardVisible
   201 {
   202     return keyboardVisible;
   203 }
   204 
   205 /* Set ourselves up as a UITextFieldDelegate */
   206 - (void)initializeKeyboard
   207 {
   208     textField = [[UITextField alloc] initWithFrame: CGRectZero];
   209     textField.delegate = self;
   210     /* placeholder so there is something to delete! */
   211     textField.text = @" ";
   212 
   213     /* set UITextInputTrait properties, mostly to defaults */
   214     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   215     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   216     textField.enablesReturnKeyAutomatically = NO;
   217     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   218     textField.keyboardType = UIKeyboardTypeDefault;
   219     textField.returnKeyType = UIReturnKeyDefault;
   220     textField.secureTextEntry = NO;
   221 
   222     textField.hidden = YES;
   223     keyboardVisible = NO;
   224     /* add the UITextField (hidden) to our view */
   225     [self addSubview: textField];
   226     [textField release];
   227 }
   228 
   229 /* reveal onscreen virtual keyboard */
   230 - (void)showKeyboard
   231 {
   232     keyboardVisible = YES;
   233     [textField becomeFirstResponder];
   234 }
   235 
   236 /* hide onscreen virtual keyboard */
   237 - (void)hideKeyboard
   238 {
   239     keyboardVisible = NO;
   240     [textField resignFirstResponder];
   241 }
   242 
   243 /* UITextFieldDelegate method.  Invoked when user types something. */
   244 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
   245 {
   246     if ([string length] == 0) {
   247         /* it wants to replace text with nothing, ie a delete */
   248         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DELETE);
   249         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DELETE);
   250     }
   251     else {
   252         /* go through all the characters in the string we've been sent
   253            and convert them to key presses */
   254         int i;
   255         for (i = 0; i < [string length]; i++) {
   256 
   257             unichar c = [string characterAtIndex: i];
   258 
   259             Uint16 mod = 0;
   260             SDL_Scancode code;
   261 
   262             if (c < 127) {
   263                 /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   264                 code = unicharToUIKeyInfoTable[c].code;
   265                 mod  = unicharToUIKeyInfoTable[c].mod;
   266             }
   267             else {
   268                 /* we only deal with ASCII right now */
   269                 code = SDL_SCANCODE_UNKNOWN;
   270                 mod = 0;
   271             }
   272 
   273             if (mod & KMOD_SHIFT) {
   274                 /* If character uses shift, press shift down */
   275                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   276             }
   277             /* send a keydown and keyup even for the character */
   278             SDL_SendKeyboardKey(SDL_PRESSED, code);
   279             SDL_SendKeyboardKey(SDL_RELEASED, code);
   280             if (mod & KMOD_SHIFT) {
   281                 /* If character uses shift, press shift back up */
   282                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   283             }
   284         }
   285         SDL_SendKeyboardText([string UTF8String]);
   286     }
   287     return NO; /* don't allow the edit! (keep placeholder text there) */
   288 }
   289 
   290 /* Terminates the editing session */
   291 - (BOOL)textFieldShouldReturn:(UITextField*)_textField
   292 {
   293     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   294     SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN);
   295     SDL_StopTextInput();
   296     return YES;
   297 }
   298 
   299 #endif
   300 
   301 @end
   302 
   303 /* iPhone keyboard addition functions */
   304 #if SDL_IPHONE_KEYBOARD
   305 
   306 static SDL_uikitview * getWindowView(SDL_Window * window)
   307 {
   308     if (window == NULL) {
   309         SDL_SetError("Window does not exist");
   310         return nil;
   311     }
   312 
   313     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   314     SDL_uikitview *view = data != NULL ? data->view : nil;
   315 
   316     if (view == nil) {
   317         SDL_SetError("Window has no view");
   318     }
   319 
   320     return view;
   321 }
   322 
   323 SDL_bool UIKit_HasScreenKeyboardSupport(_THIS)
   324 {
   325     return SDL_TRUE;
   326 }
   327 
   328 void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window)
   329 {
   330     SDL_uikitview *view = getWindowView(window);
   331     if (view != nil) {
   332         [view showKeyboard];
   333     }
   334 }
   335 
   336 void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window)
   337 {
   338     SDL_uikitview *view = getWindowView(window);
   339     if (view != nil) {
   340         [view hideKeyboard];
   341     }
   342 }
   343 
   344 SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window)
   345 {
   346     SDL_uikitview *view = getWindowView(window);
   347     if (view == nil) {
   348         return 0;
   349     }
   350 
   351     return view.keyboardVisible;
   352 }
   353 
   354 #endif /* SDL_IPHONE_KEYBOARD */
   355 
   356 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   357 
   358 /* vi: set ts=4 sw=4 expandtab: */