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