src/video/uikit/SDL_uikitview.m
author Sam Lantinga <slouken@libsdl.org>
Tue, 01 Feb 2011 09:04:43 -0800
changeset 5134 c63b901d97ab
parent 5132 5f09cb749d75
child 5218 572a73d71b5f
permissions -rw-r--r--
Fixed bug #1025 (iphone keyboard doesn't send 'return' and 'backspace' events)

Vittorio Giovara 2011-02-01 02:25:48 PST

i have attached an updated patch that fixes this behaviour
     1 /*
     2  SDL - Simple DirectMedia Layer
     3  Copyright (C) 1997-2009 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     SDL_Touch touch;
    51     touch.id = 0; //TODO: Should be -1?
    52 
    53     //touch.driverdata = SDL_malloc(sizeof(EventTouchData));
    54     //EventTouchData* data = (EventTouchData*)(touch.driverdata);
    55     
    56     touch.x_min = 0;
    57     touch.x_max = frame.size.width;
    58     touch.native_xres = touch.x_max - touch.x_min;
    59     touch.y_min = 0;
    60     touch.y_max = frame.size.height;
    61     touch.native_yres = touch.y_max - touch.y_min;
    62     touch.pressure_min = 0;
    63     touch.pressure_max = 1;
    64     touch.native_pressureres = touch.pressure_max - touch.pressure_min;
    65 
    66 
    67     touchId = SDL_AddTouch(&touch, "IPHONE SCREEN");
    68 #endif
    69 
    70     return self;
    71 
    72 }
    73 
    74 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    75 
    76     NSEnumerator *enumerator = [touches objectEnumerator];
    77     UITouch *touch = (UITouch*)[enumerator nextObject];
    78     
    79     //NSLog("Click");
    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 
   117       
   118 
   119       touch = (UITouch*)[enumerator nextObject]; 
   120     }
   121 #endif
   122 }
   123 
   124 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
   125     
   126     NSEnumerator *enumerator = [touches objectEnumerator];
   127     UITouch *touch = (UITouch*)[enumerator nextObject];
   128     
   129     if (touch) {
   130         /* send mouse up */
   131         SDL_SendMouseButton(NULL, SDL_RELEASED, SDL_BUTTON_LEFT);
   132     }
   133 
   134 #ifdef FIXED_MULTITOUCH
   135     while(touch) {
   136       CGPoint locationInView = [touch locationInView: self];
   137       
   138 
   139 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   140       SDL_SendFingerDown(touchId,(long)touch,
   141                  SDL_FALSE,locationInView.x,locationInView.y,
   142                  1);
   143 #else
   144       int i;
   145       for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
   146         if(finger[i] == touch) {
   147           SDL_SendFingerDown(touchId,i,
   148                  SDL_FALSE,locationInView.x,locationInView.y,
   149                  1);
   150           break;
   151         }
   152       }
   153 #endif
   154 
   155       touch = (UITouch*)[enumerator nextObject]; 
   156     }
   157 #endif
   158 }
   159 
   160 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
   161     /*
   162         this can happen if the user puts more than 5 touches on the screen
   163         at once, or perhaps in other circumstances.  Usually (it seems)
   164         all active touches are canceled.
   165     */
   166     [self touchesEnded: touches withEvent: event];
   167 }
   168 
   169 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
   170     
   171     NSEnumerator *enumerator = [touches objectEnumerator];
   172     UITouch *touch = (UITouch*)[enumerator nextObject];
   173     
   174     if (touch) {
   175         CGPoint locationInView = [touch locationInView: self];
   176 
   177         /* send moved event */
   178         SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
   179     }
   180 
   181 #ifdef FIXED_MULTITOUCH
   182     while(touch) {
   183       CGPoint locationInView = [touch locationInView: self];
   184       
   185 
   186 #ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
   187       SDL_SendTouchMotion(touchId,(long)touch,
   188                   SDL_FALSE,locationInView.x,locationInView.y,
   189                   1);
   190 #else
   191       int i;
   192       for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
   193         if(finger[i] == touch) {
   194           SDL_SendTouchMotion(touchId,i,
   195                   SDL_FALSE,locationInView.x,locationInView.y,
   196                   1);
   197           break;
   198         }
   199       }
   200 #endif
   201 
   202       touch = (UITouch*)[enumerator nextObject]; 
   203     }
   204 #endif
   205 }
   206 
   207 /*
   208     ---- Keyboard related functionality below this line ----
   209 */
   210 #if SDL_IPHONE_KEYBOARD
   211 
   212 /* Is the iPhone virtual keyboard visible onscreen? */
   213 - (BOOL)keyboardVisible {
   214     return keyboardVisible;
   215 }
   216 
   217 /* Set ourselves up as a UITextFieldDelegate */
   218 - (void)initializeKeyboard {
   219         
   220     textField = [[UITextField alloc] initWithFrame: CGRectZero];
   221     textField.delegate = self;
   222     /* placeholder so there is something to delete! */
   223     textField.text = @" ";    
   224     
   225     /* set UITextInputTrait properties, mostly to defaults */
   226     textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   227     textField.autocorrectionType = UITextAutocorrectionTypeNo;
   228     textField.enablesReturnKeyAutomatically = NO;
   229     textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   230     textField.keyboardType = UIKeyboardTypeDefault;
   231     textField.returnKeyType = UIReturnKeyDefault;
   232     textField.secureTextEntry = NO;    
   233     
   234     textField.hidden = YES;
   235     keyboardVisible = NO;
   236     /* add the UITextField (hidden) to our view */
   237     [self addSubview: textField];
   238     [textField release];
   239 }
   240 
   241 /* reveal onscreen virtual keyboard */
   242 - (void)showKeyboard {
   243     keyboardVisible = YES;
   244     [textField becomeFirstResponder];
   245 }
   246 
   247 /* hide onscreen virtual keyboard */
   248 - (void)hideKeyboard {
   249     keyboardVisible = NO;
   250     [textField resignFirstResponder];
   251 }
   252 
   253 /* UITextFieldDelegate method.  Invoked when user types something. */
   254 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
   255     
   256     if ([string length] == 0) {
   257         /* it wants to replace text with nothing, ie a delete */
   258         SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DELETE);
   259         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DELETE);
   260     }
   261     else {
   262         /* go through all the characters in the string we've been sent
   263            and convert them to key presses */
   264         int i;
   265         for (i=0; i<[string length]; i++) {
   266             
   267             unichar c = [string characterAtIndex: i];
   268             
   269             Uint16 mod = 0;
   270             SDL_ScanCode code;
   271             
   272             if (c < 127) {
   273                 /* figure out the SDL_ScanCode and SDL_keymod for this unichar */
   274                 code = unicharToUIKeyInfoTable[c].code;
   275                 mod  = unicharToUIKeyInfoTable[c].mod;
   276             }
   277             else {
   278                 /* we only deal with ASCII right now */
   279                 code = SDL_SCANCODE_UNKNOWN;
   280                 mod = 0;
   281             }
   282             
   283             if (mod & KMOD_SHIFT) {
   284                 /* If character uses shift, press shift down */
   285                 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   286             }
   287             /* send a keydown and keyup even for the character */
   288             SDL_SendKeyboardKey(SDL_PRESSED, code);
   289             SDL_SendKeyboardKey(SDL_RELEASED, code);
   290             if (mod & KMOD_SHIFT) {
   291                 /* If character uses shift, press shift back up */
   292                 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   293             }            
   294         }
   295     }
   296     return NO; /* don't allow the edit! (keep placeholder text there) */
   297 }
   298 
   299 /* Terminates the editing session */
   300 - (BOOL)textFieldShouldReturn:(UITextField*)_textField {
   301     SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN);
   302     [self hideKeyboard];
   303     return YES;
   304 }
   305 
   306 #endif
   307 
   308 @end
   309 
   310 /* iPhone keyboard addition functions */
   311 #if SDL_IPHONE_KEYBOARD
   312 
   313 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   314     
   315     SDL_WindowData *data;
   316     SDL_uikitview *view;
   317     
   318     if (NULL == window) {
   319         SDL_SetError("Window does not exist");
   320         return -1;
   321     }
   322     
   323     data = (SDL_WindowData *)window->driverdata;
   324     view = data->view;
   325     
   326     if (nil == view) {
   327         SDL_SetError("Window has no view");
   328         return -1;
   329     }
   330     else {
   331         [view showKeyboard];
   332         return 0;
   333     }
   334 }
   335 
   336 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   337     
   338     SDL_WindowData *data;
   339     SDL_uikitview *view;
   340     
   341     if (NULL == window) {
   342         SDL_SetError("Window does not exist");
   343         return -1;
   344     }    
   345     
   346     data = (SDL_WindowData *)window->driverdata;
   347     view = data->view;
   348     
   349     if (NULL == view) {
   350         SDL_SetError("Window has no view");
   351         return -1;
   352     }
   353     else {
   354         [view hideKeyboard];
   355         return 0;
   356     }
   357 }
   358 
   359 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   360     
   361     SDL_WindowData *data;
   362     SDL_uikitview *view;
   363     
   364     if (NULL == window) {
   365         SDL_SetError("Window does not exist");
   366         return -1;
   367     }    
   368     
   369     data = (SDL_WindowData *)window->driverdata;
   370     view = data->view;
   371     
   372     if (NULL == view) {
   373         SDL_SetError("Window has no view");
   374         return 0;
   375     }
   376     else {
   377         return view.keyboardVisible;
   378     }
   379 }
   380 
   381 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   382     
   383     SDL_WindowData *data;
   384     SDL_uikitview *view;
   385     
   386     if (NULL == window) {
   387         SDL_SetError("Window does not exist");
   388         return -1;
   389     }    
   390     
   391     data = (SDL_WindowData *)window->driverdata;
   392     view = data->view;
   393     
   394     if (NULL == view) {
   395         SDL_SetError("Window has no view");
   396         return -1;
   397     }
   398     else {
   399         if (SDL_iPhoneKeyboardIsShown(window)) {
   400             SDL_iPhoneKeyboardHide(window);
   401         }
   402         else {
   403             SDL_iPhoneKeyboardShow(window);
   404         }
   405         return 0;
   406     }
   407 }
   408 
   409 #else
   410 
   411 /* stubs, used if compiled without keyboard support */
   412 
   413 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   414     SDL_SetError("Not compiled with keyboard support");
   415     return -1;
   416 }
   417 
   418 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   419     SDL_SetError("Not compiled with keyboard support");
   420     return -1;
   421 }
   422 
   423 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   424     return 0;
   425 }
   426 
   427 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   428     SDL_SetError("Not compiled with keyboard support");
   429     return -1;
   430 }
   431 
   432 #endif /* SDL_IPHONE_KEYBOARD */
   433 
   434 /* vi: set ts=4 sw=4 expandtab: */