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