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