src/video/uikit/SDL_uikitview.m
author Sam Lantinga <slouken@libsdl.org>
Sat, 04 Oct 2008 06:46:59 +0000
changeset 2765 f55c87ae336b
child 2859 99210400e8b9
permissions -rw-r--r--
Final merge of Google Summer of Code 2008 work...

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