src/video/uikit/SDL_uikitview.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 21 Jul 2010 21:47:12 -0700
changeset 4565 e2d46c5c7483
parent 4560 95352c671a6e
child 4694 c24ba2cc9583
permissions -rw-r--r--
Fixed key repeat detection on X11, and simplified the code for everyone else.
     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 
    28 #if SDL_IPHONE_KEYBOARD
    29 #import "keyinfotable.h"
    30 #import "SDL_uikitappdelegate.h"
    31 #import "SDL_uikitwindow.h"
    32 #endif
    33 
    34 @implementation SDL_uikitview
    35 
    36 - (void)dealloc {
    37 #if SDL_IPHONE_KEYBOARD
    38 	[textField release];
    39 #endif
    40 	[super dealloc];
    41 }
    42 
    43 - (id)initWithFrame:(CGRect)frame {
    44 
    45 	self = [super initWithFrame: frame];
    46 	
    47 #if SDL_IPHONE_KEYBOARD
    48 	[self initializeKeyboard];
    49 #endif	
    50 
    51 #if FIXME_MULTITOUCH
    52 	int i;
    53 	for (i=0; i<MAX_SIMULTANEOUS_TOUCHES; i++) {
    54         mice[i].id = i;
    55 		mice[i].driverdata = NULL;
    56 		SDL_AddMouse(&mice[i], "Mouse", 0, 0, 1);
    57 	}
    58 	self.multipleTouchEnabled = YES;
    59 #endif
    60 			
    61 	return self;
    62 
    63 }
    64 
    65 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    66 
    67 	NSEnumerator *enumerator = [touches objectEnumerator];
    68 	UITouch *touch = (UITouch*)[enumerator nextObject];
    69 	
    70 #if FIXME_MULTITOUCH
    71 	/* associate touches with mice, so long as we have slots */
    72 	int i;
    73 	int found = 0;
    74 	for(i=0; touch && i < MAX_SIMULTANEOUS_TOUCHES; i++) {
    75 	
    76 		/* check if this mouse is already tracking a touch */
    77 		if (mice[i].driverdata != NULL) {
    78 			continue;
    79 		}
    80 		/*	
    81 			mouse not associated with anything right now,
    82 			associate the touch with this mouse
    83 		*/
    84 		found = 1;
    85 		
    86 		/* save old mouse so we can switch back */
    87 		int oldMouse = SDL_SelectMouse(-1);
    88 		
    89 		/* select this slot's mouse */
    90 		SDL_SelectMouse(i);
    91 		CGPoint locationInView = [touch locationInView: self];
    92 		
    93 		/* set driver data to touch object, we'll use touch object later */
    94 		mice[i].driverdata = [touch retain];
    95 		
    96 		/* send moved event */
    97 		SDL_SendMouseMotion(i, 0, locationInView.x, locationInView.y, 0);
    98 		
    99 		/* send mouse down event */
   100 		SDL_SendMouseButton(i, SDL_PRESSED, SDL_BUTTON_LEFT);
   101 		
   102 		/* re-calibrate relative mouse motion */
   103 		SDL_GetRelativeMouseState(i, NULL, NULL);
   104 		
   105 		/* switch back to our old mouse */
   106 		SDL_SelectMouse(oldMouse);
   107 		
   108 		/* grab next touch */
   109 		touch = (UITouch*)[enumerator nextObject]; 
   110 	}
   111 #else
   112 	if (touch) {
   113 		CGPoint locationInView = [touch locationInView: self];
   114 			
   115 		/* send moved event */
   116 		SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
   117 
   118 		/* send mouse down event */
   119 		SDL_SendMouseButton(NULL, SDL_PRESSED, SDL_BUTTON_LEFT);
   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 FIXME_MULTITOUCH
   130 	while(touch) {
   131 		/* search for the mouse slot associated with this touch */
   132 		int i, found = NO;
   133 		for (i=0; i<MAX_SIMULTANEOUS_TOUCHES && !found; i++) {
   134 			if (mice[i].driverdata == touch) {
   135 				/* found the mouse associate with the touch */
   136 				[(UITouch*)(mice[i].driverdata) release];
   137 				mice[i].driverdata = NULL;
   138 				/* send mouse up */
   139 				SDL_SendMouseButton(i, SDL_RELEASED, SDL_BUTTON_LEFT);
   140 				/* discontinue search for this touch */
   141 				found = YES;
   142 			}
   143 		}
   144 		
   145 		/* grab next touch */
   146 		touch = (UITouch*)[enumerator nextObject]; 
   147 	}
   148 #else
   149 	if (touch) {
   150 		/* send mouse up */
   151 		SDL_SendMouseButton(NULL, SDL_RELEASED, SDL_BUTTON_LEFT);
   152 	}
   153 #endif
   154 }
   155 
   156 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
   157 	/*
   158 		this can happen if the user puts more than 5 touches on the screen
   159 		at once, or perhaps in other circumstances.  Usually (it seems)
   160 		all active touches are canceled.
   161 	*/
   162 	[self touchesEnded: touches withEvent: event];
   163 }
   164 
   165 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
   166 	
   167 	NSEnumerator *enumerator = [touches objectEnumerator];
   168 	UITouch *touch = (UITouch*)[enumerator nextObject];
   169 	
   170 #if FIXME_MULTITOUCH
   171 	while(touch) {
   172 		/* try to find the mouse associated with this touch */
   173 		int i, found = NO;
   174 		for (i=0; i<MAX_SIMULTANEOUS_TOUCHES && !found; i++) {
   175 			if (mice[i].driverdata == touch) {
   176 				/* found proper mouse */
   177 				CGPoint locationInView = [touch locationInView: self];
   178 				/* send moved event */
   179 				SDL_SendMouseMotion(i, 0, locationInView.x, locationInView.y, 0);
   180 				/* discontinue search */
   181 				found = YES;
   182 			}
   183 		}
   184 		
   185 		/* grab next touch */
   186 		touch = (UITouch*)[enumerator nextObject]; 
   187 	}
   188 #else
   189 	if (touch) {
   190 		CGPoint locationInView = [touch locationInView: self];
   191 
   192 		/* send moved event */
   193 		SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
   194 	}
   195 #endif
   196 }
   197 
   198 /*
   199 	---- Keyboard related functionality below this line ----
   200 */
   201 #if SDL_IPHONE_KEYBOARD
   202 
   203 /* Is the iPhone virtual keyboard visible onscreen? */
   204 - (BOOL)keyboardVisible {
   205 	return keyboardVisible;
   206 }
   207 
   208 /* Set ourselves up as a UITextFieldDelegate */
   209 - (void)initializeKeyboard {
   210 		
   211 	textField = [[[UITextField alloc] initWithFrame: CGRectZero] autorelease];
   212 	textField.delegate = self;
   213 	/* placeholder so there is something to delete! */
   214 	textField.text = @" ";	
   215 	
   216 	/* set UITextInputTrait properties, mostly to defaults */
   217 	textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
   218 	textField.autocorrectionType = UITextAutocorrectionTypeNo;
   219 	textField.enablesReturnKeyAutomatically = NO;
   220 	textField.keyboardAppearance = UIKeyboardAppearanceDefault;
   221 	textField.keyboardType = UIKeyboardTypeDefault;
   222 	textField.returnKeyType = UIReturnKeyDefault;
   223 	textField.secureTextEntry = NO;	
   224 	
   225 	textField.hidden = YES;
   226 	keyboardVisible = NO;
   227 	/* add the UITextField (hidden) to our view */
   228 	[self addSubview: textField];
   229 }
   230 
   231 /* reveal onscreen virtual keyboard */
   232 - (void)showKeyboard {
   233 	keyboardVisible = YES;
   234 	[textField becomeFirstResponder];
   235 }
   236 
   237 /* hide onscreen virtual keyboard */
   238 - (void)hideKeyboard {
   239 	keyboardVisible = NO;
   240 	[textField resignFirstResponder];
   241 }
   242 
   243 /* UITextFieldDelegate method.  Invoked when user types something. */
   244 - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
   245 	
   246 	if ([string length] == 0) {
   247 		/* it wants to replace text with nothing, ie a delete */
   248 		SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DELETE);
   249 		SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DELETE);
   250 	}
   251 	else {
   252 		/* go through all the characters in the string we've been sent
   253 		   and convert them to key presses */
   254 		int i;
   255 		for (i=0; i<[string length]; i++) {
   256 			
   257 			unichar c = [string characterAtIndex: i];
   258 			
   259 			Uint16 mod = 0;
   260 			SDL_scancode code;
   261 			
   262 			if (c < 127) {
   263 				/* figure out the SDL_scancode and SDL_keymod for this unichar */
   264 				code = unicharToUIKeyInfoTable[c].code;
   265 				mod  = unicharToUIKeyInfoTable[c].mod;
   266 			}
   267 			else {
   268 				/* we only deal with ASCII right now */
   269 				code = SDL_SCANCODE_UNKNOWN;
   270 				mod = 0;
   271 			}
   272 			
   273 			if (mod & KMOD_SHIFT) {
   274 				/* If character uses shift, press shift down */
   275 				SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
   276 			}
   277 			/* send a keydown and keyup even for the character */
   278 			SDL_SendKeyboardKey(SDL_PRESSED, code);
   279 			SDL_SendKeyboardKey(SDL_RELEASED, code);
   280 			if (mod & KMOD_SHIFT) {
   281 				/* If character uses shift, press shift back up */
   282 				SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
   283 			}			
   284 		}
   285 	}
   286 	return NO; /* don't allow the edit! (keep placeholder text there) */
   287 }
   288 
   289 /* Terminates the editing session */
   290 - (BOOL)textFieldShouldReturn:(UITextField*)_textField {
   291 	[self hideKeyboard];
   292 	return YES;
   293 }
   294 
   295 #endif
   296 
   297 @end
   298 
   299 /* iPhone keyboard addition functions */
   300 #if SDL_IPHONE_KEYBOARD
   301 
   302 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   303 	
   304 	SDL_WindowData *data;
   305 	SDL_uikitview *view;
   306 	
   307 	if (NULL == window) {
   308 		SDL_SetError("Window does not exist");
   309 		return -1;
   310 	}
   311 	
   312 	data = (SDL_WindowData *)window->driverdata;
   313 	view = data->view;
   314 	
   315 	if (nil == view) {
   316 		SDL_SetError("Window has no view");
   317 		return -1;
   318 	}
   319 	else {
   320 		[view showKeyboard];
   321 		return 0;
   322 	}
   323 }
   324 
   325 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   326 	
   327 	SDL_WindowData *data;
   328 	SDL_uikitview *view;
   329 	
   330 	if (NULL == window) {
   331 		SDL_SetError("Window does not exist");
   332 		return -1;
   333 	}	
   334 	
   335 	data = (SDL_WindowData *)window->driverdata;
   336 	view = data->view;
   337 	
   338 	if (NULL == view) {
   339 		SDL_SetError("Window has no view");
   340 		return -1;
   341 	}
   342 	else {
   343 		[view hideKeyboard];
   344 		return 0;
   345 	}
   346 }
   347 
   348 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   349 	
   350 	SDL_WindowData *data;
   351 	SDL_uikitview *view;
   352 	
   353 	if (NULL == window) {
   354 		SDL_SetError("Window does not exist");
   355 		return -1;
   356 	}	
   357 	
   358 	data = (SDL_WindowData *)window->driverdata;
   359 	view = data->view;
   360 	
   361 	if (NULL == view) {
   362 		SDL_SetError("Window has no view");
   363 		return 0;
   364 	}
   365 	else {
   366 		return view.keyboardVisible;
   367 	}
   368 }
   369 
   370 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   371 	
   372 	SDL_WindowData *data;
   373 	SDL_uikitview *view;
   374 	
   375 	if (NULL == window) {
   376 		SDL_SetError("Window does not exist");
   377 		return -1;
   378 	}	
   379 	
   380 	data = (SDL_WindowData *)window->driverdata;
   381 	view = data->view;
   382 	
   383 	if (NULL == view) {
   384 		SDL_SetError("Window has no view");
   385 		return -1;
   386 	}
   387 	else {
   388 		if (SDL_iPhoneKeyboardIsShown(window)) {
   389 			SDL_iPhoneKeyboardHide(window);
   390 		}
   391 		else {
   392 			SDL_iPhoneKeyboardShow(window);
   393 		}
   394 		return 0;
   395 	}
   396 }
   397 
   398 #else
   399 
   400 /* stubs, used if compiled without keyboard support */
   401 
   402 int SDL_iPhoneKeyboardShow(SDL_Window * window) {
   403 	SDL_SetError("Not compiled with keyboard support");
   404 	return -1;
   405 }
   406 
   407 int SDL_iPhoneKeyboardHide(SDL_Window * window) {
   408 	SDL_SetError("Not compiled with keyboard support");
   409 	return -1;
   410 }
   411 
   412 SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window) {
   413 	return 0;
   414 }
   415 
   416 int SDL_iPhoneKeyboardToggle(SDL_Window * window) {
   417 	SDL_SetError("Not compiled with keyboard support");
   418 	return -1;
   419 }
   420 
   421 
   422 #endif /* SDL_IPHONE_KEYBOARD */