Home | History | Annotate | Download | only in maccommon
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #include <stdio.h>
     25 
     26 #if defined(__APPLE__) && defined(__MACH__)
     27 #include <Carbon/Carbon.h>
     28 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
     29 #include <Carbon.h>
     30 #else
     31 #include <Script.h>
     32 #include <LowMem.h>
     33 #include <Devices.h>
     34 #include <DiskInit.h>
     35 #include <ToolUtils.h>
     36 #endif
     37 
     38 #include "SDL_events.h"
     39 #include "SDL_video.h"
     40 #include "SDL_syswm.h"
     41 #include "../../events/SDL_events_c.h"
     42 #include "../../events/SDL_sysevents.h"
     43 #include "../SDL_cursor_c.h"
     44 #include "SDL_macevents_c.h"
     45 #include "SDL_mackeys.h"
     46 #include "SDL_macmouse_c.h"
     47 
     48 /* Define this to be able to collapse SDL windows.
     49 #define USE_APPEARANCE_MANAGER
     50  */
     51 
     52 /* Macintosh resource constants */
     53 #define mApple	128			/* Apple menu resource */
     54 #define iAbout	1			/* About menu item */
     55 
     56 /* Functions to handle the About menu */
     57 static void Mac_DoAppleMenu(_THIS, long item);
     58 
     59 /* The translation table from a macintosh key scancode to a SDL keysym */
     60 static SDLKey MAC_keymap[256];
     61 static SDL_keysym *TranslateKey(int scancode, int modifiers,
     62                                 SDL_keysym *keysym, int pressed);
     63 
     64 /* Handle activation and deactivation  -- returns whether an event was posted */
     65 static int Mac_HandleActivate(int activate)
     66 {
     67 	if ( activate ) {
     68 		/* Show the current SDL application cursor */
     69 		SDL_SetCursor(NULL);
     70 
     71 		/* put our mask back case it changed during context switch */
     72 		SetEventMask(everyEvent & ~autoKeyMask);
     73 	} else {
     74 #if TARGET_API_MAC_CARBON
     75 		{ Cursor cursor;
     76 			SetCursor(GetQDGlobalsArrow(&cursor));
     77 		}
     78 #else
     79 		SetCursor(&theQD->arrow);
     80 #endif
     81 		if ( ! Mac_cursor_showing ) {
     82 			ShowCursor();
     83 			Mac_cursor_showing = 1;
     84 		}
     85 	}
     86 	return(SDL_PrivateAppActive(activate, SDL_APPINPUTFOCUS));
     87 }
     88 
     89 static void myGlobalToLocal(_THIS, Point *pt)
     90 {
     91 	if ( SDL_VideoSurface && !(SDL_VideoSurface->flags&SDL_FULLSCREEN) ) {
     92 		GrafPtr saveport;
     93 		GetPort(&saveport);
     94 #if TARGET_API_MAC_CARBON
     95 		SetPort(GetWindowPort(SDL_Window));
     96 #else
     97 		SetPort(SDL_Window);
     98 #endif
     99 		GlobalToLocal(pt);
    100 		SetPort(saveport);
    101 	}
    102 }
    103 
    104 /* The main MacOS event handler */
    105 static int Mac_HandleEvents(_THIS, int wait4it)
    106 {
    107 	static int mouse_button = 1;
    108 	int i;
    109 	EventRecord event;
    110 
    111 #if TARGET_API_MAC_CARBON
    112 	/* There's no GetOSEvent() in the Carbon API. *sigh* */
    113 #define cooperative_multitasking 1
    114 #else
    115 	int cooperative_multitasking;
    116 	/* If we're running fullscreen, we can hog the MacOS events,
    117 	   otherwise we had better play nicely with the other apps.
    118 	*/
    119 	if ( this->screen && (this->screen->flags & SDL_FULLSCREEN) ) {
    120 		cooperative_multitasking = 0;
    121 	} else {
    122 		cooperative_multitasking = 1;
    123 	}
    124 #endif
    125 
    126 	/* If we call WaitNextEvent(), MacOS will check other processes
    127 	 * and allow them to run, and perform other high-level processing.
    128 	 */
    129 	if ( cooperative_multitasking || wait4it ) {
    130 		UInt32 wait_time;
    131 
    132 		/* Are we polling or not? */
    133 		if ( wait4it ) {
    134 			wait_time = 2147483647;
    135 		} else {
    136 			wait_time = 0;
    137 		}
    138 		WaitNextEvent(everyEvent, &event, wait_time, nil);
    139 	} else {
    140 #if ! TARGET_API_MAC_CARBON
    141 		GetOSEvent(everyEvent, &event);
    142 #endif
    143 	}
    144 
    145 #if TARGET_API_MAC_CARBON
    146 	/* for some reason, event.where isn't set ? */
    147 	GetGlobalMouse ( &event.where );
    148 #endif
    149 
    150 	/* Check for mouse motion */
    151 	if ( (event.where.h != last_where.h) ||
    152 	     (event.where.v != last_where.v) ) {
    153 		Point pt;
    154 		pt = last_where = event.where;
    155 		myGlobalToLocal(this, &pt);
    156 		SDL_PrivateMouseMotion(0, 0, pt.h, pt.v);
    157 	}
    158 
    159 	/* Check the current state of the keyboard */
    160 	if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
    161 		KeyMap keys;
    162 		const Uint32 *keysptr = (Uint32 *) &keys;
    163 		const Uint32 *last_keysptr = (Uint32 *) &last_keys;
    164 
    165 		/* Check for special non-event keys */
    166 		if ( event.modifiers != last_mods ) {
    167 			static struct {
    168 				EventModifiers mask;
    169 				SDLKey key;
    170 			} mods[] = {
    171 				{ alphaLock,		SDLK_CAPSLOCK },
    172 #if 0 /* These are handled below in the GetKeys() code */
    173 				{ cmdKey,		SDLK_LMETA },
    174 				{ shiftKey,		SDLK_LSHIFT },
    175 				{ rightShiftKey,	SDLK_RSHIFT },
    176 				{ optionKey,		SDLK_LALT },
    177 				{ rightOptionKey,	SDLK_RALT },
    178 				{ controlKey,		SDLK_LCTRL },
    179 				{ rightControlKey,	SDLK_RCTRL },
    180 #endif /* 0 */
    181 				{ 0,			0 }
    182 			};
    183 			SDL_keysym keysym;
    184 			Uint8 mode;
    185 			EventModifiers mod, mask;
    186 
    187 
    188 			/* Set up the keyboard event */
    189 			keysym.scancode = 0;
    190 			keysym.sym = SDLK_UNKNOWN;
    191 			keysym.mod = KMOD_NONE;
    192 			keysym.unicode = 0;
    193 
    194 			/* See what has changed, and generate events */
    195 			mod = event.modifiers;
    196 			for ( i=0; mods[i].mask; ++i ) {
    197 				mask = mods[i].mask;
    198 				if ( (mod&mask) != (last_mods&mask) ) {
    199 					keysym.sym = mods[i].key;
    200 					if ( (mod&mask) ||
    201 					     (mods[i].key == SDLK_CAPSLOCK) ) {
    202 						mode = SDL_PRESSED;
    203 					} else {
    204 						mode = SDL_RELEASED;
    205 					}
    206 					SDL_PrivateKeyboard(mode, &keysym);
    207 				}
    208 			}
    209 
    210 			/* Save state for next time */
    211 			last_mods = mod;
    212 		}
    213 
    214 		/* Check for normal event keys, but we have to scan the
    215 		   actual keyboard state because on Mac OS X a keydown event
    216 		   is immediately followed by a keyup event.
    217 		*/
    218 		GetKeys(keys);
    219 		if ( (keysptr[0] != last_keysptr[0]) ||
    220 		     (keysptr[1] != last_keysptr[1]) ||
    221 		     (keysptr[2] != last_keysptr[2]) ||
    222 		     (keysptr[3] != last_keysptr[3]) ) {
    223 			SDL_keysym keysym;
    224 			int old_bit, new_bit;
    225 
    226 #ifdef DEBUG_KEYBOARD
    227 			fprintf(sterr, "New keys: 0x%x 0x%x 0x%x 0x%x\n",
    228 				new_keys[0], new_keys[1],
    229 				new_keys[2], new_keys[3]);
    230 #endif
    231 			for ( i=0; i<128; ++i ) {
    232 				old_bit = (((Uint8 *)last_keys)[i/8]>>(i%8)) & 0x01;
    233 				new_bit = (((Uint8 *)keys)[i/8]>>(i%8)) & 0x01;
    234 				if ( old_bit != new_bit ) {
    235 					/* Post the keyboard event */
    236 #ifdef DEBUG_KEYBOARD
    237 					fprintf(stderr,"Scancode: 0x%2.2X\n",i);
    238 #endif
    239 					SDL_PrivateKeyboard(new_bit,
    240 				            TranslateKey(i, event.modifiers,
    241 				                         &keysym, new_bit));
    242 				}
    243 			}
    244 
    245 			/* Save state for next time */
    246 			last_keys[0] = keys[0];
    247 			last_keys[1] = keys[1];
    248 			last_keys[2] = keys[2];
    249 			last_keys[3] = keys[3];
    250 		}
    251 	}
    252 
    253 	/* Handle normal events */
    254 	switch (event.what) {
    255 	  case mouseDown: {
    256 		WindowRef win;
    257 		short area;
    258 
    259 		area = FindWindow(event.where, &win);
    260 		/* Support switching between the SIOUX console
    261 		   and SDL_Window by clicking in the window.
    262 		 */
    263 		if ( win && (win != FrontWindow()) ) {
    264 			SelectWindow(win);
    265 		}
    266 		switch (area) {
    267 		  case inMenuBar: /* Only the apple menu exists */
    268 			Mac_DoAppleMenu(this, MenuSelect(event.where));
    269 			HiliteMenu(0);
    270 			break;
    271 		  case inDrag:
    272 #if TARGET_API_MAC_CARBON
    273 			DragWindow(win, event.where, NULL);
    274 #else
    275 			DragWindow(win, event.where, &theQD->screenBits.bounds);
    276 #endif
    277 			break;
    278 		  case inGoAway:
    279 			if ( TrackGoAway(win, event.where) ) {
    280 				SDL_PrivateQuit();
    281 			}
    282 			break;
    283 		  case inContent:
    284 			myGlobalToLocal(this, &event.where);
    285 			/* Treat command-click as right mouse button */
    286 			if ( event.modifiers & optionKey ) {
    287 				mouse_button = 2;
    288 			} else if ( event.modifiers & cmdKey ) {
    289 				mouse_button = 3;
    290 			} else {
    291 				mouse_button = 1;
    292 			}
    293 			SDL_PrivateMouseButton(SDL_PRESSED,
    294 				mouse_button, event.where.h, event.where.v);
    295 			break;
    296 		  case inGrow: {
    297 			int newSize;
    298 
    299 			/* Don't allow resize if video mode isn't resizable */
    300 			if ( ! SDL_PublicSurface ||
    301 			     ! (SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
    302 				break;
    303 			}
    304 #if TARGET_API_MAC_CARBON
    305 			newSize = GrowWindow(win, event.where, NULL);
    306 #else
    307 			newSize = GrowWindow(win, event.where, &theQD->screenBits.bounds);
    308 #endif
    309 			if ( newSize ) {
    310 #if !TARGET_API_MAC_CARBON
    311 				EraseRect ( &theQD->screenBits.bounds );
    312 #endif
    313 				SizeWindow ( win, LoWord (newSize), HiWord (newSize), 1 );
    314 				SDL_PrivateResize ( LoWord (newSize), HiWord (newSize) );
    315 			}
    316 		  	} break;
    317 		  case inZoomIn:
    318 		  case inZoomOut:
    319 			if ( TrackBox (win, event.where, area )) {
    320 				Rect rect;
    321 #if !TARGET_API_MAC_CARBON
    322 				EraseRect ( &theQD->screenBits.bounds );
    323 #endif
    324 				ZoomWindow ( win, area, 0);
    325 				if ( area == inZoomIn ) {
    326 					GetWindowUserState(SDL_Window, &rect);
    327 				} else {
    328 					GetWindowStandardState(SDL_Window, &rect);
    329 				}
    330 				SDL_PrivateResize (rect.right-rect.left,
    331 				                   rect.bottom-rect.top);
    332 			}
    333 			break;
    334 #if TARGET_API_MAC_CARBON
    335 		  case inCollapseBox:
    336 			if ( TrackBox (win, event.where, area )) {
    337 				if ( IsWindowCollapsable(win) ) {
    338 					CollapseWindow (win, !IsWindowCollapsed(win));
    339 					/* There should be something done like in inGrow case, but... */
    340 				}
    341 			}
    342 			break;
    343 #endif /* TARGET_API_MAC_CARBON */
    344 		  case inSysWindow:
    345 #if TARGET_API_MAC_CARBON
    346 			/* Never happens in Carbon? */
    347 #else
    348 			SystemClick(&event, win);
    349 #endif
    350 			break;
    351 		  default:
    352 			break;
    353 		}
    354 	  }
    355 	  break;
    356 	  case mouseUp: {
    357 		myGlobalToLocal(this, &event.where);
    358 		/* Release the mouse button we simulated in the last press.
    359 		   The drawback of this methos is we cannot press more than
    360 		   one button. However, this doesn't matter, since there is
    361 		   only a single logical mouse button, even if you have a
    362 		   multi-button mouse, this doesn't matter at all.
    363 		 */
    364 		SDL_PrivateMouseButton(SDL_RELEASED,
    365 			mouse_button, event.where.h, event.where.v);
    366 	  }
    367 	  break;
    368 #if 0 /* Handled above the switch statement */
    369 	  case keyDown: {
    370 		SDL_keysym keysym;
    371 
    372 		SDL_PrivateKeyboard(SDL_PRESSED,
    373 			TranslateKey((event.message&keyCodeMask)>>8
    374 		                     event.modifiers, &keysym, 1));
    375 	  }
    376 	  break;
    377 	  case keyUp: {
    378 		SDL_keysym keysym;
    379 
    380 		SDL_PrivateKeyboard(SDL_RELEASED,
    381 			TranslateKey((event.message&keyCodeMask)>>8
    382 		                     event.modifiers, &keysym, 0));
    383 	  }
    384 	  break;
    385 #endif
    386 	  case updateEvt: {
    387 		BeginUpdate(SDL_Window);
    388 	#if SDL_VIDEO_OPENGL
    389 		if (SDL_VideoSurface->flags & SDL_OPENGL)
    390 			SDL_GL_SwapBuffers();
    391 		else
    392 	#endif
    393 		if ( (SDL_VideoSurface->flags & SDL_HWSURFACE) ==
    394 						SDL_SWSURFACE ) {
    395 			SDL_UpdateRect(SDL_VideoSurface, 0, 0, 0, 0);
    396 		}
    397 		EndUpdate(SDL_Window);
    398 	  }
    399 	  /* If this was an update event for the SIOUX console, we return 0
    400              in order to stop an endless series of updates being triggered.
    401 	  */
    402 	  if ( (WindowRef) event.message != SDL_Window ) {
    403 		return 0;
    404 	  }
    405 	  break;
    406 	  case activateEvt: {
    407 		Mac_HandleActivate(!!(event.modifiers & activeFlag));
    408 	  }
    409 	  break;
    410 	  case diskEvt: {
    411 #if TARGET_API_MAC_CARBON
    412 		/* What are we supposed to do? */;
    413 #else
    414 		if ( ((event.message>>16)&0xFFFF) != noErr ) {
    415 			Point spot;
    416 			SetPt(&spot, 0x0070, 0x0050);
    417 			DIBadMount(spot, event.message);
    418 		}
    419 #endif
    420 	  }
    421 	  break;
    422 	  case osEvt: {
    423 		switch ((event.message>>24) & 0xFF) {
    424 #if 0 /* Handled above the switch statement */
    425 		  case mouseMovedMessage: {
    426 			myGlobalToLocal(this, &event.where);
    427 			SDL_PrivateMouseMotion(0, 0,
    428 					event.where.h, event.where.v);
    429 		  }
    430 		  break;
    431 #endif /* 0 */
    432 		  case suspendResumeMessage: {
    433 			Mac_HandleActivate(!!(event.message & resumeFlag));
    434 		  }
    435 		  break;
    436 		}
    437 	  }
    438 	  break;
    439 	  default: {
    440 		;
    441 	  }
    442 	  break;
    443 	}
    444 	return (event.what != nullEvent);
    445 }
    446 
    447 
    448 void Mac_PumpEvents(_THIS)
    449 {
    450 	/* Process pending MacOS events */
    451 	while ( Mac_HandleEvents(this, 0) ) {
    452 		/* Loop and check again */;
    453 	}
    454 }
    455 
    456 void Mac_InitOSKeymap(_THIS)
    457 {
    458 	const void *KCHRPtr;
    459 	UInt32 state;
    460 	UInt32 value;
    461 	int i;
    462 	int world = SDLK_WORLD_0;
    463 
    464 	/* Map the MAC keysyms */
    465 	for ( i=0; i<SDL_arraysize(MAC_keymap); ++i )
    466 		MAC_keymap[i] = SDLK_UNKNOWN;
    467 
    468 	/* Defined MAC_* constants */
    469 	MAC_keymap[MK_ESCAPE] = SDLK_ESCAPE;
    470 	MAC_keymap[MK_F1] = SDLK_F1;
    471 	MAC_keymap[MK_F2] = SDLK_F2;
    472 	MAC_keymap[MK_F3] = SDLK_F3;
    473 	MAC_keymap[MK_F4] = SDLK_F4;
    474 	MAC_keymap[MK_F5] = SDLK_F5;
    475 	MAC_keymap[MK_F6] = SDLK_F6;
    476 	MAC_keymap[MK_F7] = SDLK_F7;
    477 	MAC_keymap[MK_F8] = SDLK_F8;
    478 	MAC_keymap[MK_F9] = SDLK_F9;
    479 	MAC_keymap[MK_F10] = SDLK_F10;
    480 	MAC_keymap[MK_F11] = SDLK_F11;
    481 	MAC_keymap[MK_F12] = SDLK_F12;
    482 	MAC_keymap[MK_PRINT] = SDLK_PRINT;
    483 	MAC_keymap[MK_SCROLLOCK] = SDLK_SCROLLOCK;
    484 	MAC_keymap[MK_PAUSE] = SDLK_PAUSE;
    485 	MAC_keymap[MK_POWER] = SDLK_POWER;
    486 	MAC_keymap[MK_BACKQUOTE] = SDLK_BACKQUOTE;
    487 	MAC_keymap[MK_1] = SDLK_1;
    488 	MAC_keymap[MK_2] = SDLK_2;
    489 	MAC_keymap[MK_3] = SDLK_3;
    490 	MAC_keymap[MK_4] = SDLK_4;
    491 	MAC_keymap[MK_5] = SDLK_5;
    492 	MAC_keymap[MK_6] = SDLK_6;
    493 	MAC_keymap[MK_7] = SDLK_7;
    494 	MAC_keymap[MK_8] = SDLK_8;
    495 	MAC_keymap[MK_9] = SDLK_9;
    496 	MAC_keymap[MK_0] = SDLK_0;
    497 	MAC_keymap[MK_MINUS] = SDLK_MINUS;
    498 	MAC_keymap[MK_EQUALS] = SDLK_EQUALS;
    499 	MAC_keymap[MK_BACKSPACE] = SDLK_BACKSPACE;
    500 	MAC_keymap[MK_INSERT] = SDLK_INSERT;
    501 	MAC_keymap[MK_HOME] = SDLK_HOME;
    502 	MAC_keymap[MK_PAGEUP] = SDLK_PAGEUP;
    503 	MAC_keymap[MK_NUMLOCK] = SDLK_NUMLOCK;
    504 	MAC_keymap[MK_KP_EQUALS] = SDLK_KP_EQUALS;
    505 	MAC_keymap[MK_KP_DIVIDE] = SDLK_KP_DIVIDE;
    506 	MAC_keymap[MK_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
    507 	MAC_keymap[MK_TAB] = SDLK_TAB;
    508 	MAC_keymap[MK_q] = SDLK_q;
    509 	MAC_keymap[MK_w] = SDLK_w;
    510 	MAC_keymap[MK_e] = SDLK_e;
    511 	MAC_keymap[MK_r] = SDLK_r;
    512 	MAC_keymap[MK_t] = SDLK_t;
    513 	MAC_keymap[MK_y] = SDLK_y;
    514 	MAC_keymap[MK_u] = SDLK_u;
    515 	MAC_keymap[MK_i] = SDLK_i;
    516 	MAC_keymap[MK_o] = SDLK_o;
    517 	MAC_keymap[MK_p] = SDLK_p;
    518 	MAC_keymap[MK_LEFTBRACKET] = SDLK_LEFTBRACKET;
    519 	MAC_keymap[MK_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
    520 	MAC_keymap[MK_BACKSLASH] = SDLK_BACKSLASH;
    521 	MAC_keymap[MK_DELETE] = SDLK_DELETE;
    522 	MAC_keymap[MK_END] = SDLK_END;
    523 	MAC_keymap[MK_PAGEDOWN] = SDLK_PAGEDOWN;
    524 	MAC_keymap[MK_KP7] = SDLK_KP7;
    525 	MAC_keymap[MK_KP8] = SDLK_KP8;
    526 	MAC_keymap[MK_KP9] = SDLK_KP9;
    527 	MAC_keymap[MK_KP_MINUS] = SDLK_KP_MINUS;
    528 	MAC_keymap[MK_CAPSLOCK] = SDLK_CAPSLOCK;
    529 	MAC_keymap[MK_a] = SDLK_a;
    530 	MAC_keymap[MK_s] = SDLK_s;
    531 	MAC_keymap[MK_d] = SDLK_d;
    532 	MAC_keymap[MK_f] = SDLK_f;
    533 	MAC_keymap[MK_g] = SDLK_g;
    534 	MAC_keymap[MK_h] = SDLK_h;
    535 	MAC_keymap[MK_j] = SDLK_j;
    536 	MAC_keymap[MK_k] = SDLK_k;
    537 	MAC_keymap[MK_l] = SDLK_l;
    538 	MAC_keymap[MK_SEMICOLON] = SDLK_SEMICOLON;
    539 	MAC_keymap[MK_QUOTE] = SDLK_QUOTE;
    540 	MAC_keymap[MK_RETURN] = SDLK_RETURN;
    541 	MAC_keymap[MK_KP4] = SDLK_KP4;
    542 	MAC_keymap[MK_KP5] = SDLK_KP5;
    543 	MAC_keymap[MK_KP6] = SDLK_KP6;
    544 	MAC_keymap[MK_KP_PLUS] = SDLK_KP_PLUS;
    545 	MAC_keymap[MK_LSHIFT] = SDLK_LSHIFT;
    546 	MAC_keymap[MK_z] = SDLK_z;
    547 	MAC_keymap[MK_x] = SDLK_x;
    548 	MAC_keymap[MK_c] = SDLK_c;
    549 	MAC_keymap[MK_v] = SDLK_v;
    550 	MAC_keymap[MK_b] = SDLK_b;
    551 	MAC_keymap[MK_n] = SDLK_n;
    552 	MAC_keymap[MK_m] = SDLK_m;
    553 	MAC_keymap[MK_COMMA] = SDLK_COMMA;
    554 	MAC_keymap[MK_PERIOD] = SDLK_PERIOD;
    555 	MAC_keymap[MK_SLASH] = SDLK_SLASH;
    556 #if 0	/* These are the same as the left versions - use left by default */
    557 	MAC_keymap[MK_RSHIFT] = SDLK_RSHIFT;
    558 #endif
    559 	MAC_keymap[MK_UP] = SDLK_UP;
    560 	MAC_keymap[MK_KP1] = SDLK_KP1;
    561 	MAC_keymap[MK_KP2] = SDLK_KP2;
    562 	MAC_keymap[MK_KP3] = SDLK_KP3;
    563 	MAC_keymap[MK_KP_ENTER] = SDLK_KP_ENTER;
    564 	MAC_keymap[MK_LCTRL] = SDLK_LCTRL;
    565 	MAC_keymap[MK_LALT] = SDLK_LALT;
    566 	MAC_keymap[MK_LMETA] = SDLK_LMETA;
    567 	MAC_keymap[MK_SPACE] = SDLK_SPACE;
    568 #if 0	/* These are the same as the left versions - use left by default */
    569 	MAC_keymap[MK_RMETA] = SDLK_RMETA;
    570 	MAC_keymap[MK_RALT] = SDLK_RALT;
    571 	MAC_keymap[MK_RCTRL] = SDLK_RCTRL;
    572 #endif
    573 	MAC_keymap[MK_LEFT] = SDLK_LEFT;
    574 	MAC_keymap[MK_DOWN] = SDLK_DOWN;
    575 	MAC_keymap[MK_RIGHT] = SDLK_RIGHT;
    576 	MAC_keymap[MK_KP0] = SDLK_KP0;
    577 	MAC_keymap[MK_KP_PERIOD] = SDLK_KP_PERIOD;
    578 
    579 #if defined(__APPLE__) && defined(__MACH__)
    580 	/* Wierd, these keys are on my iBook under Mac OS X
    581 	   Note that the left arrow keysym is the same as left ctrl!?
    582 	 */
    583 	MAC_keymap[MK_IBOOK_ENTER] = SDLK_KP_ENTER;
    584 	MAC_keymap[MK_IBOOK_RIGHT] = SDLK_RIGHT;
    585 	MAC_keymap[MK_IBOOK_DOWN] = SDLK_DOWN;
    586 	MAC_keymap[MK_IBOOK_UP] = SDLK_UP;
    587 	MAC_keymap[MK_IBOOK_LEFT] = SDLK_LEFT;
    588 #endif /* Mac OS X */
    589 
    590 	/* Up there we setup a static scancode->keysym map. However, it will not
    591 	 * work very well on international keyboard. Hence we now query MacOS
    592 	 * for its own keymap to adjust our own mapping table. However, this is
    593 	 * bascially only useful for ascii char keys. This is also the reason
    594 	 * why we keep the static table, too.
    595 	 */
    596 
    597 	/* Get a pointer to the systems cached KCHR */
    598 	KCHRPtr = (void *)GetScriptManagerVariable(smKCHRCache);
    599 	if (KCHRPtr)
    600 	{
    601 		/* Loop over all 127 possible scan codes */
    602 		for (i = 0; i < 0x7F; i++)
    603 		{
    604 			/* We pretend a clean start to begin with (i.e. no dead keys active */
    605 			state = 0;
    606 
    607 			/* Now translate the key code to a key value */
    608 			value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
    609 
    610 			/* If the state become 0, it was a dead key. We need to translate again,
    611 			passing in the new state, to get the actual key value */
    612 			if (state != 0)
    613 				value = KeyTranslate(KCHRPtr, i, &state) & 0xff;
    614 
    615 			/* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
    616 			if (value >= 128)	 /* Some non-ASCII char, map it to SDLK_WORLD_* */
    617 				MAC_keymap[i] = world++;
    618 			else if (value >= 32)	 /* non-control ASCII char */
    619 				MAC_keymap[i] = value;
    620 		}
    621 	}
    622 
    623 	/* The keypad codes are re-setup here, because the loop above cannot
    624 	 * distinguish between a key on the keypad and a regular key. We maybe
    625 	 * could get around this problem in another fashion: NSEvent's flags
    626 	 * include a "NSNumericPadKeyMask" bit; we could check that and modify
    627 	 * the symbol we return on the fly. However, this flag seems to exhibit
    628 	 * some weird behaviour related to the num lock key
    629 	 */
    630 	MAC_keymap[MK_KP0] = SDLK_KP0;
    631 	MAC_keymap[MK_KP1] = SDLK_KP1;
    632 	MAC_keymap[MK_KP2] = SDLK_KP2;
    633 	MAC_keymap[MK_KP3] = SDLK_KP3;
    634 	MAC_keymap[MK_KP4] = SDLK_KP4;
    635 	MAC_keymap[MK_KP5] = SDLK_KP5;
    636 	MAC_keymap[MK_KP6] = SDLK_KP6;
    637 	MAC_keymap[MK_KP7] = SDLK_KP7;
    638 	MAC_keymap[MK_KP8] = SDLK_KP8;
    639 	MAC_keymap[MK_KP9] = SDLK_KP9;
    640 	MAC_keymap[MK_KP_MINUS] = SDLK_KP_MINUS;
    641 	MAC_keymap[MK_KP_PLUS] = SDLK_KP_PLUS;
    642 	MAC_keymap[MK_KP_PERIOD] = SDLK_KP_PERIOD;
    643 	MAC_keymap[MK_KP_EQUALS] = SDLK_KP_EQUALS;
    644 	MAC_keymap[MK_KP_DIVIDE] = SDLK_KP_DIVIDE;
    645 	MAC_keymap[MK_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
    646 	MAC_keymap[MK_KP_ENTER] = SDLK_KP_ENTER;
    647 }
    648 
    649 static SDL_keysym *TranslateKey(int scancode, int modifiers,
    650                                 SDL_keysym *keysym, int pressed)
    651 {
    652 	/* Set the keysym information */
    653 	keysym->scancode = scancode;
    654 	keysym->sym = MAC_keymap[keysym->scancode];
    655 	keysym->mod = KMOD_NONE;
    656 	keysym->unicode = 0;
    657 	if ( pressed && SDL_TranslateUNICODE ) {
    658 		static unsigned long state = 0;
    659 		static Ptr keymap = nil;
    660 		Ptr new_keymap;
    661 
    662 		/* Get the current keyboard map resource */
    663 		new_keymap = (Ptr)GetScriptManagerVariable(smKCHRCache);
    664 		if ( new_keymap != keymap ) {
    665 			keymap = new_keymap;
    666 			state = 0;
    667 		}
    668 		keysym->unicode = KeyTranslate(keymap,
    669 			keysym->scancode|modifiers, &state) & 0xFFFF;
    670 	}
    671 	return(keysym);
    672 }
    673 
    674 void Mac_InitEvents(_THIS)
    675 {
    676 	/* Create apple menu bar */
    677 	apple_menu = GetMenu(mApple);
    678 	if ( apple_menu != nil ) {
    679 		AppendResMenu(apple_menu, 'DRVR');
    680 		InsertMenu(apple_menu, 0);
    681 	}
    682 	DrawMenuBar();
    683 
    684 	/* Get rid of spurious events at startup */
    685 	FlushEvents(everyEvent, 0);
    686 
    687 	/* Allow every event but keyrepeat */
    688 	SetEventMask(everyEvent & ~autoKeyMask);
    689 }
    690 
    691 void Mac_QuitEvents(_THIS)
    692 {
    693 	ClearMenuBar();
    694 	if ( apple_menu != nil ) {
    695 		ReleaseResource((char **)apple_menu);
    696 	}
    697 
    698 	/* Clean up pending events */
    699 	FlushEvents(everyEvent, 0);
    700 }
    701 
    702 static void Mac_DoAppleMenu(_THIS, long choice)
    703 {
    704 #if !TARGET_API_MAC_CARBON  /* No Apple menu in OS X */
    705 	short menu, item;
    706 
    707 	item = (choice&0xFFFF);
    708 	choice >>= 16;
    709 	menu = (choice&0xFFFF);
    710 
    711 	switch (menu) {
    712 		case mApple: {
    713 			switch (item) {
    714 				case iAbout: {
    715 					/* Run the about box */;
    716 				}
    717 				break;
    718 				default: {
    719 					Str255 name;
    720 
    721 					GetMenuItemText(apple_menu, item, name);
    722 					OpenDeskAcc(name);
    723 				}
    724 				break;
    725 			}
    726 		}
    727 		break;
    728 		default: {
    729 			/* Ignore other menus */;
    730 		}
    731 	}
    732 #endif /* !TARGET_API_MAC_CARBON */
    733 }
    734 
    735 #if !TARGET_API_MAC_CARBON
    736 /* Since we don't initialize QuickDraw, we need to get a pointer to qd */
    737 struct QDGlobals *theQD = NULL;
    738 #endif
    739 
    740 /* Exported to the macmain code */
    741 void SDL_InitQuickDraw(struct QDGlobals *the_qd)
    742 {
    743 #if !TARGET_API_MAC_CARBON
    744 	theQD = the_qd;
    745 #endif
    746 }
    747