src/video/uikit/SDL_uikitview.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 09 Mar 2011 17:38:12 -0800
changeset 5461 94f742ce580a
parent 5459 881d1e03e381
child 5535 96594ac5fd1a
permissions -rw-r--r--
Fixed bug 1163 (SDL_TEXTINPUT not being received on iPhoneOS)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #import "SDL_uikitview.h"
    24 
    25 #include "../../events/SDL_keyboard_c.h"
    26 #include "../../events/SDL_mouse_c.h"
    27 #include "../../events/SDL_touch_c.h"
    28 
    29 #if SDL_IPHONE_KEYBOARD
    30 #import "keyinfotable.h"
    31 #import "SDL_uikitappdelegate.h"
    32 #import "SDL_uikitwindow.h"
    33 #endif
    34 
    35 @implementation SDL_uikitview
    36 
    37 - (void)dealloc {
    38     [super dealloc];
    39 }
    40 
    41 - (id)initWithFrame:(CGRect)frame {
    42 
    43     self = [super initWithFrame: frame];
    44     
    45 #if SDL_IPHONE_KEYBOARD
    46     [self initializeKeyboard];
    47 #endif    
    48 
    49 #ifdef FIXED_MULTITOUCH
    50     self.multipleTouchEnabled = YES;
    51 
    52     SDL_Touch touch;
    53     touch.id = 0; //TODO: Should be -1?
    54 
    55     //touch.driverdata = SDL_malloc(sizeof(EventTouchData));
    56     //EventTouchData* data = (EventTouchData*)(touch.driverdata);
    57     
    58     touch.x_min = 0;
    59     touch.x_max = frame.size.width;
    60     touch.native_xres = touch.x_max - touch.x_min;
    61     touch.y_min = 0;
    62     touch.y_max = frame.size.height;
    63     touch.native_yres = touch.y_max - touch.y_min;
    64     touch.pressure_min = 0;
    65     touch.pressure_max = 1;
    66     touch.native_pressureres = touch.pressure_max - touch.pressure_min;
    67 
    68 
    69     touchId = SDL_AddTouch(&touch, "IPHONE SCREEN");
    70 #endif
    71 
    72     return self;
    73 
    74 }
    75 
    76 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    77 
    78     NSEnumerator *enumerator = [touches objectEnumerator];
    79     UITouch *touch = (UITouch*)[enumerator nextObject];
    80 
    81     if (touch) {
    82         CGPoint locationInView = [touch locationInView: self];
    83             
    84         /* send moved event */
    85         SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
    86 
    87         /* send mouse down event */
    88         SDL_SendMouseButton(NULL, SDL_PRESSED, SDL_BUTTON_LEFT);
    89     }
    90 
    91 #ifdef FIXED_MULTITOUCH
    92     while(touch) {
    93       CGPoint locationInView = [touch locationInView: self];
    94 
    95 
    96 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
    97       //FIXME: TODO: Using touch as the fingerId is potentially dangerous
    98       //It is also much more efficient than storing the UITouch pointer
    99       //and comparing it to the incoming event.
   100       SDL_SendFingerDown(touchId,(long)touch,
   101                  SDL_TRUE,locationInView.x,locationInView.y,
   102                  1);
   103 #else
   104       int i;
   105       for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
   106         if(finger[i] == NULL) {
   107           finger[i] = touch;
   108           SDL_SendFingerDown(touchId,i,
   109                  SDL_TRUE,locationInView.x,locationInView.y,
   110                  1);
   111           break;
   112         }
   113       }
   114 #endif
   115 
   116       touch = (UITouch*)[enumerator nextObject]; 
   117     }
   118 #endif
   119 }
   120 
   121 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
   122     
   123     NSEnumerator *enumerator = [touches objectEnumerator];
   124     UITouch *touch = (UITouch*)[enumerator nextObject];
   125     
   126     if (touch) {
   127         /* send mouse up */
   128         SDL_SendMouseButton(NULL, SDL_RELEASED, SDL_BUTTON_LEFT);
   129     }
   130 
   131 #ifdef FIXED_MULTITOUCH
   132     while(touch) {
   133       CGPoint locationInView = [touch locationInView: self];
   134       
   135 
   136 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   137       SDL_SendFingerDown(touchId,(long)touch,
   138                  SDL_FALSE,locationInView.x,locationInView.y,
   139                  1);
   140 #else
   141       int i;
   142       for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
   143         if(finger[i] == touch) {
   144           SDL_SendFingerDown(touchId,i,
   145                  SDL_FALSE,locationInView.x,locationInView.y,
   146                  1);
   147           finger[i] = NULL;
   148           break;
   149         }
   150       }
   151 #endif
   152 
   153       touch = (UITouch*)[enumerator nextObject]; 
   154     }
   155 #endif
   156 }
   157 
   158 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
   159     /*
   160         this can happen if the user puts more than 5 touches on the screen
   161         at once, or perhaps in other circumstances.  Usually (it seems)
   162         all active touches are canceled.
   163     */
   164     [self touchesEnded: touches withEvent: event];
   165 }
   166 
   167 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
   168     
   169     NSEnumerator *enumerator = [touches objectEnumerator];
   170     UITouch *touch = (UITouch*)[enumerator nextObject];
   171     
   172     if (touch) {
   173         CGPoint locationInView = [touch locationInView: self];
   174 
   175         /* send moved event */
   176         SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
   177     }
   178 
   179 #ifdef FIXED_MULTITOUCH
   180     while(touch) {
   181       CGPoint locationInView = [touch locationInView: self];
   182       
   183 
   184 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   185       SDL_SendTouchMotion(touchId,(long)touch,
   186                   SDL_FALSE,locationInView.x,locationInView.y,
   187                   1);
   188 #else
   189       int i;
   190       for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
   191         if(finger[i] == touch) {
   192           SDL_SendTouchMotion(touchId,i,
   193                   SDL_FALSE,locationInView.x,locationInView.y,
   194                   1);
   195           break;
   196         }
   197       }
   198 #endif
   199 
   200       touch = (UITouch*)[enumerator nextObject]; 
   201     }
   202 #endif
   203 }
   204 
   205 /*
   206     ---- Keyboard related functionality below this line ----
   207 */
   208 #if SDL_IPHONE_KEYBOARD
   209 
   210 /* Is the iPhone virtual keyboard visible onscreen? */
   211 - (BOOL)keyboardVisible {
   212     return keyboardVisible;
   213 }
   214 
   215 /* Set ourselves up as a UITextFieldDelegate */
   216 - (void)initializeKeyboard {
   217         
   218     textField = [[UITextField alloc] initWithFrame: CGRectZero];
   219     textField.delegate = self;
   220     /* placeholder so there is something to delete! */
   221     textField.text = @" ";    
   222     
   223     /* set UITextInputTrait properties, mostly to defaults */
   224     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   225     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   226     textField.enablesReturnKeyAutomatically = NO;
   227     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   228     textField.keyboardType = UIKeyboardTypeDefault;
   229     textField.returnKeyType = UIReturnKeyDefault;
   230     textField.secureTextEntry = NO;    
   231     
   232     textField.hidden = YES;
   233     keyboardVisible = NO;
   234     /* add the UITextField (hidden) to our view */
   235     [self addSubview: textField];
   236     [textField release];
   237 }
   238 
   239 /* reveal onscreen virtual keyboard */
   240 - (void)showKeyboard {
   241     keyboardVisible = YES;
   242     [textField becomeFirstResponder];
   243 }
   244 
   245 /* hide onscreen virtual keyboard */
   246 - (void)hideKeyboard {
   247     keyboardVisible = NO;
   248     [textField resignFirstResponder];
   249 }
   250 
   251 /* UITextFieldDelegate method.  Invoked when user types something. */
   252 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
   253     
   254     if ([string length] == 0) {
   255         /* it wants to replace text with nothing, ie a delete */
   256         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DELETE);
   257         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DELETE);
   258     }
   259     else {
   260         /* go through all the characters in the string we've been sent
   261            and convert them to key presses */
   262         int i;
   263         for (i=0; i<[string length]; i++) {
   264             
   265             unichar c = [string characterAtIndex: i];
   266             
   267             Uint16 mod = 0;
   268             SDL_Scancode code;
   269             
   270             if (c < 127) {
   271                 /* figure out the SDL_Scancode and SDL_keymod for this unichar */
   272                 code = unicharToUIKeyInfoTable[c].code;
   273                 mod  = unicharToUIKeyInfoTable[c].mod;
   274             }
   275             else {
   276                 /* we only deal with ASCII right now */
   277                 code = SDL_SCANCODE_UNKNOWN;
   278                 mod = 0;
   279             }
   280             
   281             if (mod & KMOD_SHIFT) {
   282                 /* If character uses shift, press shift down */
   283                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   284             }
   285             /* send a keydown and keyup even for the character */
   286             SDL_SendKeyboardKey(SDL_PRESSED, code);
   287             SDL_SendKeyboardKey(SDL_RELEASED, code);
   288             if (mod & KMOD_SHIFT) {
   289                 /* If character uses shift, press shift back up */
   290                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   291             }            
   292         }
   293         SDL_SendKeyboardText([string UTF8String]);
   294     }
   295     return NO; /* don't allow the edit! (keep placeholder text there) */
   296 }
   297 
   298 /* Terminates the editing session */
   299 - (BOOL)textFieldShouldReturn:(UITextField*)_textField {
   300     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   301     [self hideKeyboard];
   302     return YES;
   303 }
   304 
   305 #endif
   306 
   307 @end
   308 
   309 /* iPhone keyboard addition functions */
   310 #if SDL_IPHONE_KEYBOARD
   311 
   312 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   313     
   314     SDL_WindowData *data;
   315     SDL_uikitview *view;
   316     
   317     if (NULL == window) {
   318         SDL_SetError("Window does not exist");
   319         return -1;
   320     }
   321     
   322     data = (SDL_WindowData *)window->driverdata;
   323     view = data->view;
   324     
   325     if (nil == view) {
   326         SDL_SetError("Window has no view");
   327         return -1;
   328     }
   329     else {
   330         [view showKeyboard];
   331         return 0;
   332     }
   333 }
   334 
   335 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   336     
   337     SDL_WindowData *data;
   338     SDL_uikitview *view;
   339     
   340     if (NULL == window) {
   341         SDL_SetError("Window does not exist");
   342         return -1;
   343     }    
   344     
   345     data = (SDL_WindowData *)window->driverdata;
   346     view = data->view;
   347     
   348     if (NULL == view) {
   349         SDL_SetError("Window has no view");
   350         return -1;
   351     }
   352     else {
   353         [view hideKeyboard];
   354         return 0;
   355     }
   356 }
   357 
   358 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   359     
   360     SDL_WindowData *data;
   361     SDL_uikitview *view;
   362     
   363     if (NULL == window) {
   364         SDL_SetError("Window does not exist");
   365         return -1;
   366     }    
   367     
   368     data = (SDL_WindowData *)window->driverdata;
   369     view = data->view;
   370     
   371     if (NULL == view) {
   372         SDL_SetError("Window has no view");
   373         return 0;
   374     }
   375     else {
   376         return view.keyboardVisible;
   377     }
   378 }
   379 
   380 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   381     
   382     SDL_WindowData *data;
   383     SDL_uikitview *view;
   384     
   385     if (NULL == window) {
   386         SDL_SetError("Window does not exist");
   387         return -1;
   388     }    
   389     
   390     data = (SDL_WindowData *)window->driverdata;
   391     view = data->view;
   392     
   393     if (NULL == view) {
   394         SDL_SetError("Window has no view");
   395         return -1;
   396     }
   397     else {
   398         if (SDL_iPhoneKeyboardIsShown(window)) {
   399             SDL_iPhoneKeyboardHide(window);
   400         }
   401         else {
   402             SDL_iPhoneKeyboardShow(window);
   403         }
   404         return 0;
   405     }
   406 }
   407 
   408 #else
   409 
   410 /* stubs, used if compiled without keyboard support */
   411 
   412 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   413     SDL_SetError("Not compiled with keyboard support");
   414     return -1;
   415 }
   416 
   417 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   418     SDL_SetError("Not compiled with keyboard support");
   419     return -1;
   420 }
   421 
   422 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   423     return 0;
   424 }
   425 
   426 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   427     SDL_SetError("Not compiled with keyboard support");
   428     return -1;
   429 }
   430 
   431 #endif /* SDL_IPHONE_KEYBOARD */
   432 
   433 /* vi: set ts=4 sw=4 expandtab: */