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