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