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@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 */
57static void Mac_DoAppleMenu(_THIS, long item);
58
59/* The translation table from a macintosh key scancode to a SDL keysym */
60static SDLKey MAC_keymap[256];
61static 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 */
65static 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
89static 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 */
105static 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
448void Mac_PumpEvents(_THIS)
449{
450	/* Process pending MacOS events */
451	while ( Mac_HandleEvents(this, 0) ) {
452		/* Loop and check again */;
453	}
454}
455
456void 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
649static 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
674void 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
691void 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
702static 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 */
737struct QDGlobals *theQD = NULL;
738#endif
739
740/* Exported to the macmain code */
741void SDL_InitQuickDraw(struct QDGlobals *the_qd)
742{
743#if !TARGET_API_MAC_CARBON
744	theQD = the_qd;
745#endif
746}
747