1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 /***********************************************************************************
8   SNES9X for Mac OS (c) Copyright John Stiles
9 
10   Snes9x for Mac OS X
11 
12   (c) Copyright 2001 - 2011  zones
13   (c) Copyright 2002 - 2005  107
14   (c) Copyright 2002         PB1400c
15   (c) Copyright 2004         Alexander and Sander
16   (c) Copyright 2004 - 2005  Steven Seeger
17   (c) Copyright 2005         Ryan Vogt
18  ***********************************************************************************/
19 
20 
21 #include "port.h"
22 
23 #include "mac-prefix.h"
24 #include "mac-dialog.h"
25 #include "mac-gworld.h"
26 #include "mac-os.h"
27 #include "mac-keyboard.h"
28 
29 #define kmUpArrowKey	0x7E
30 #define kmDownArrowKey	0x7D
31 #define kmRightArrowKey	0x7C
32 #define kmLeftArrowKey	0x7B
33 #define kmReturnKey		0x24
34 #define kmTabKey		0x30
35 #define kmShiftKey		0x38
36 #define kmControlKey	0x3B
37 #define kmOptionKey		0x3A
38 #define kmCommandKey	0x37
39 #define kmXKey			0x07
40 #define kmZKey			0x06
41 #define kmKP2Key		0x54
42 #define kmKP4Key		0x56
43 #define kmKP5Key		0x57
44 #define kmKP6Key		0x58
45 #define kmKP8Key		0x5B
46 #define kmKPEnterKey	0x4C
47 #define kmKPPlusKey		0x45
48 #define kmKP0Key		0x52
49 #define kmKPPeriodKey	0x41
50 #define kmHomeKey		0x73
51 #define kmPageUpKey		0x74
52 #define kmEndKey		0x77
53 #define kmPageDownKey	0x79
54 #define kmBackslashKey	0x2A
55 #define km1Key			0x12
56 #define km0Key			0x1D
57 #define kmIKey			0x22
58 #define kmJKey			0x26
59 #define kmKKey			0x28
60 #define kmLKey			0x25
61 #define kmTildeKey		0x32
62 #define	kmRKey			0x0F
63 #define	kmBKey			0x0B
64 #define	kmNKey			0x2D
65 #define	kmMKey			0x2E
66 #define	kmSpaceKey		0x31
67 #define kmSlashKey		0x2C
68 #define	kmPeriodKey		0x2F
69 #define	kmQKey			0x0C
70 #define	kmWKey			0x0D
71 #define	kmEscKey		0x35
72 #define	kmCommaKey		0x2B
73 
74 #define kIconSize		16
75 #define kKeySize		24
76 #define KS				kKeySize
77 
78 uint8	keyCode[kKeys] =
79 {
80 	kmUpArrowKey,
81 	kmDownArrowKey,
82 	kmLeftArrowKey,
83 	kmRightArrowKey,
84 	kmShiftKey,
85 	kmOptionKey,
86 	kmControlKey,
87 	kmCommandKey,
88 	kmZKey,
89 	kmXKey,
90 	kmReturnKey,
91 	kmTabKey,
92 
93 	kmKP8Key,
94 	kmKP2Key,
95 	kmKP4Key,
96 	kmKP6Key,
97 	kmPageDownKey,
98 	kmPageUpKey,
99 	kmEndKey,
100 	kmHomeKey,
101 	kmKP0Key,
102 	kmKPPeriodKey,
103 	kmKPEnterKey,
104 	kmKPPlusKey,
105 
106 	kmBackslashKey,
107 	km1Key,
108 	km0Key,
109 	kmTildeKey,
110 	kmRKey,
111 	kmBKey,
112 	kmNKey,
113 	kmMKey,
114 	kmSpaceKey,
115 	kmSlashKey,
116 	kmPeriodKey,
117 	kmQKey,
118 	kmWKey,
119 	kmEscKey,
120 	kmCommaKey
121 };
122 
123 typedef struct
124 {
125 	int			keyWidth, keyHeight;
126 	uint8		scancode;
127   	const char	*keyLabel;
128 }	KeyboardLayout;
129 
130 typedef struct
131 {
132 	HIViewRef	view;
133 }	CustomViewData;
134 
135 static CGImageRef		iconTableImage;
136 static CGImageRef		keyLayoutImage;
137 static CGImageRef		iconPlaceImage;
138 static Ptr				iconTableCGWld;
139 static Ptr				keyLayoutWorld;
140 static Ptr				iconPlaceWorld;
141 
142 static CGRect			keyRect[0x80][2];
143 static uint8			defaultKeys[kKeys];
144 
145 static HIObjectClassRef	theClass;
146 static HIViewRef		customView;
147 static HIPoint			mousePos;
148 static float			ofsx, ofsy;
149 static int				dragKey;
150 static CGPoint			dragKeyOfs;
151 static CGRect			dragKeyRect;
152 static volatile Boolean	keyInDrag;
153 
154 static const int		kKeyLayoutWidth  = kKeySize * 23 + 1,
155 						kKeyLayoutHeight = kKeySize *  7 + 1;
156 
157 static KeyboardLayout	keys[] =
158 {
159 	{ KS,         KS,     0x35, "esc"    },
160 	{ KS,         KS,     0x00, NULL     },
161 	{ KS,         KS,     0x7a, "F1"     },
162 	{ KS,         KS,     0x78, "F2"     },
163 	{ KS,         KS,     0x63, "F3"     },
164 	{ KS,         KS,     0x76, "F4"     },
165 	{ KS / 2,     KS,     0x00, NULL     },
166 	{ KS,         KS,     0x60, "F5"     },
167 	{ KS,         KS,     0x61, "F6"     },
168 	{ KS,         KS,     0x62, "F7"     },
169 	{ KS,         KS,     0x64, "F8"     },
170 	{ KS / 2,     KS,     0x00, NULL     },
171 	{ KS,         KS,     0x65, "F9"     },
172 	{ KS,         KS,     0x6d, "F10"    },
173 	{ KS,         KS,     0x67, "F11"    },
174 	{ KS,         KS,     0x6f, "F12"    },
175 	{ KS / 2,     KS,     0x00, NULL     },
176 	{ KS,         KS,     0x69, "F13"    },
177 	{ KS,         KS,     0x6b, "F14"    },
178 	{ KS,         KS,     0x71, "F15"    },
179 	{ 0,          0,      0x00, NULL     },
180 
181 	{ 0,          0,      0x00, NULL     },
182 
183 	{ KS,         KS,     0x32, "`"      },
184 	{ KS,         KS,     0x12, "1"      },
185 	{ KS,         KS,     0x13, "2"      },
186 	{ KS,         KS,     0x14, "3"      },
187 	{ KS,         KS,     0x15, "4"      },
188 	{ KS,         KS,     0x17, "5"      },
189 	{ KS,         KS,     0x16, "6"      },
190 	{ KS,         KS,     0x1a, "7"      },
191 	{ KS,         KS,     0x1c, "8"      },
192 	{ KS,         KS,     0x19, "9"      },
193 	{ KS,         KS,     0x1d, "0"      },
194 	{ KS,         KS,     0x1b, "-"      },
195 	{ KS,         KS,     0x18, "="      },
196 	{ KS * 2,     KS,     0x33, "delete" },
197 	{ KS / 2,     KS,     0x00, NULL     },
198 	{ KS,         KS,     0x72, "ins"    },
199 	{ KS,         KS,     0x73, "hom"    },
200 	{ KS,         KS,     0x74, "pgu"    },
201 	{ KS / 2,     KS,     0x00, NULL     },
202 	{ KS,         KS,     0x47, "clr"    },
203 	{ KS,         KS,     0x51, "="      },
204 	{ KS,         KS,     0x4b, "/"      },
205 	{ KS,         KS,     0x43, "*"      },
206 	{ 0,          0,      0x00, NULL     },
207 
208 	{ KS * 3 / 2, KS,     0x30, "tab"    },
209 	{ KS,         KS,     0x0c, "Q"      },
210 	{ KS,         KS,     0x0d, "W"      },
211 	{ KS,         KS,     0x0e, "E"      },
212 	{ KS,         KS,     0x0f, "R"      },
213 	{ KS,         KS,     0x11, "T"      },
214 	{ KS,         KS,     0x10, "Y"      },
215 	{ KS,         KS,     0x20, "U"      },
216 	{ KS,         KS,     0x22, "I"      },
217 	{ KS,         KS,     0x1f, "O"      },
218 	{ KS,         KS,     0x23, "P"      },
219 	{ KS,         KS,     0x21, "["      },
220 	{ KS,         KS,     0x1e, "]"      },
221 	{ KS * 3 / 2, KS,     0x2a, "\\"     },
222 	{ KS / 2,     KS,     0x00, NULL     },
223 	{ KS,         KS,     0x75, "del"    },
224 	{ KS,         KS,     0x77, "end"    },
225 	{ KS,         KS,     0x79, "pgd"    },
226 	{ KS / 2,     KS,     0x00, NULL     },
227 	{ KS,         KS,     0x59, "7"      },
228 	{ KS,         KS,     0x5b, "8"      },
229 	{ KS,         KS,     0x5c, "9"      },
230 	{ KS,         KS,     0x4e, "-"      },
231 	{ 0,          0,      0x00, NULL     },
232 
233 	{ KS * 2,     KS,     0x39, "caps"   },
234 	{ KS,         KS,     0x00, "A"      },
235 	{ KS,         KS,     0x01, "S"      },
236 	{ KS,         KS,     0x02, "D"      },
237 	{ KS,         KS,     0x03, "F"      },
238 	{ KS,         KS,     0x05, "G"      },
239 	{ KS,         KS,     0x04, "H"      },
240 	{ KS,         KS,     0x26, "J"      },
241 	{ KS,         KS,     0x28, "K"      },
242 	{ KS,         KS,     0x25, "L"      },
243 	{ KS,         KS,     0x29, ";"      },
244 	{ KS,         KS,     0x27, "\xd3"   },
245 	{ KS * 2,     KS,     0x24, "return" },
246 	{ KS * 4,     KS,     0x00, NULL     },
247 	{ KS,         KS,     0x56, "4"      },
248 	{ KS,         KS,     0x57, "5"      },
249 	{ KS,         KS,     0x58, "6"      },
250 	{ KS,         KS,     0x45, "+"      },
251 	{ 0,          0,      0x00, NULL     },
252 
253 	{ KS * 5 / 2, KS,     0x38, "shift"  },
254 	{ KS,         KS,     0x06, "Z"      },
255 	{ KS,         KS,     0x07, "X"      },
256 	{ KS,         KS,     0x08, "C"      },
257 	{ KS,         KS,     0x09, "V"      },
258 	{ KS,         KS,     0x0b, "B"      },
259 	{ KS,         KS,     0x2d, "N"      },
260 	{ KS,         KS,     0x2e, "M"      },
261 	{ KS,         KS,     0x2b, ","      },
262 	{ KS,         KS,     0x2f, "."      },
263 	{ KS,         KS,     0x2c, "/"      },
264 	{ KS * 5 / 2, KS,     0x38, "shift"  },
265 	{ KS * 3 / 2, KS,     0x00, NULL     },
266 	{ KS,         KS,     0x7e, "up"     },
267 	{ KS * 3 / 2, KS,     0x00, NULL     },
268 	{ KS,         KS,     0x53, "1"      },
269 	{ KS,         KS,     0x54, "2"      },
270 	{ KS,         KS,     0x55, "3"      },
271 	{ KS,         KS * 2, 0x4c, "ent"    },
272 	{ 0,          0,      0x00, NULL     },
273 
274 	{ KS * 3 / 2, KS,     0x3b, "ctrl"   },
275 	{ KS * 3 / 2, KS,     0x3a, "opt"    },
276 	{ KS * 3 / 2, KS,     0x37, "cmd"    },
277 	{ KS * 6,     KS,     0x31, "   "    },
278 	{ KS * 3 / 2, KS,     0x37, "cmd"    },
279 	{ KS * 3 / 2, KS,     0x3a, "opt"    },
280 	{ KS * 3 / 2, KS,     0x3b, "ctrl"   },
281 	{ KS / 2,     KS,     0x00, NULL     },
282 	{ KS,         KS,     0x7b, "lt"     },
283 	{ KS,         KS,     0x7d, "dn"     },
284 	{ KS,         KS,     0x7c, "rt"     },
285 	{ KS / 2,     KS,     0x00, NULL     },
286 	{ KS * 2,     KS,     0x52, "0"      },
287 	{ KS,         KS,     0x41, "."      },
288 	{ 0,          0,      0x00, NULL     }
289 };
290 
291 static void CreateIconTableImage (void);
292 static void ReleaseIconTableImage (void);
293 static void CreateKeyLayoutImage (void);
294 static void ReleaseKeyLayoutImage (void);
295 static void CreateIconPlaceImage (void);
296 static void UpdateIconPlaceImage (void);
297 static void ReleaseIconPlaceImage (void);
298 static void DrawPlacedIcon (CGContextRef, int);
299 static void DrawDraggedIcon (CGContextRef, int, CGPoint *);
300 static Boolean KeyCodeInUse (int);
301 static int FindHitKey (HIPoint, CGRect *, CGPoint *);
302 static pascal OSStatus KeyWindowEventHandler (EventHandlerCallRef, EventRef, void *);
303 static pascal OSStatus KeyLegendEventHandler (EventHandlerCallRef, EventRef, void *);
304 static pascal OSStatus KeyLayoutEventHandler (EventHandlerCallRef, EventRef, void *);
305 
306 #define	kCustomLayoutViewClassID	CFSTR("com.snes9x.macos.snes9x.keylayout")
307 
308 
ConfigureKeyboard(void)309 void ConfigureKeyboard (void)
310 {
311 	OSStatus	err;
312 	IBNibRef	nibRef;
313 
314 	err = CreateNibReference(kMacS9XCFString, &nibRef);
315 	if (err == noErr)
316 	{
317 		WindowRef	tWindowRef;
318 
319 		err = CreateWindowFromNib(nibRef, CFSTR("Keyboard"), &tWindowRef);
320 		if (err == noErr)
321 		{
322 			EventHandlerRef	wref, iref1, iref2;
323 			EventHandlerUPP	wUPP, iUPP;
324 			EventTypeSpec	wEvents[] = { { kEventClassWindow,   kEventWindowClose         },
325 										  { kEventClassCommand,  kEventCommandProcess      },
326 										  { kEventClassCommand,  kEventCommandUpdateStatus } },
327 							cEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct   },
328 										  { kEventClassHIObject, kEventHIObjectDestruct    },
329 										  { kEventClassHIObject, kEventHIObjectInitialize  },
330 										  { kEventClassControl,  kEventControlDraw         },
331 										  { kEventClassControl,  kEventControlHitTest      },
332 										  { kEventClassControl,  kEventControlTrack        } },
333 							iEvents[] = { { kEventClassControl,  kEventControlDraw         } };
334 			HIObjectRef		hiObject;
335 			HIViewRef		contentView, image1, image2;
336 			HIViewID		cid;
337 			HIRect			frame;
338 			Rect			winBounds;
339 
340 			UpdateIconPlaceImage();
341 
342 			keyInDrag = false;
343 			dragKey = -1;
344 			dragKeyOfs = CGPointMake(0.0f, 0.0f);
345 			dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
346 			mousePos = CGPointMake(0.0f, 0.0f);
347 
348 			err = noErr;
349 			if (theClass == NULL)
350 				err = HIObjectRegisterSubclass(kCustomLayoutViewClassID, kHIViewClassID, 0, KeyLayoutEventHandler, GetEventTypeCount(cEvents), cEvents, NULL, &theClass);
351 
352 			if (err == noErr)
353 			{
354 				err = HIObjectCreate(kCustomLayoutViewClassID, NULL, &hiObject);
355 				if (err == noErr)
356 				{
357 					GetWindowBounds(tWindowRef, kWindowContentRgn, &winBounds);
358 
359 					frame.origin.x = 2.0f;
360 					frame.origin.y = 2.0f;
361 					frame.size.width  = (float) (winBounds.right - winBounds.left) - 4.0f;
362 					frame.size.height = (float) kKeyLayoutHeight + 36.0f;
363 
364 					ofsx = (float) (((int) frame.size.width  - kKeyLayoutWidth ) >> 1) + 1.0f;
365 					ofsy = (float) (((int) frame.size.height - kKeyLayoutHeight) >> 1) + 1.0f;
366 
367 					customView = (HIViewRef) hiObject;
368 
369 					HIViewFindByID(HIViewGetRoot(tWindowRef), kHIViewWindowContentID, &contentView);
370 					HIViewAddSubview(contentView, customView);
371 					HIViewSetFrame(customView, &frame);
372 					HIViewSetVisible(customView, true);
373 
374 					cid.signature = 'Lgnd';
375 					cid.id = 0;
376 					HIViewFindByID(contentView, cid, &image1);
377 					cid.id = 1;
378 					HIViewFindByID(contentView, cid, &image2);
379 					iUPP = NewEventHandlerUPP(KeyLegendEventHandler);
380 					err = InstallControlEventHandler(image1, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image1, &iref1);
381 					err = InstallControlEventHandler(image2, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image2, &iref2);
382 
383 					wUPP = NewEventHandlerUPP(KeyWindowEventHandler);
384 					err = InstallWindowEventHandler(tWindowRef, wUPP, GetEventTypeCount(wEvents), wEvents, (void *) tWindowRef, &wref);
385 
386 					MoveWindowPosition(tWindowRef, kWindowKeyConfig, false);
387 					ShowWindow(tWindowRef);
388 					err = RunAppModalLoopForWindow(tWindowRef);
389 					HideWindow(tWindowRef);
390 					SaveWindowPosition(tWindowRef, kWindowKeyConfig);
391 
392 					err = RemoveEventHandler(iref2);
393 					err = RemoveEventHandler(iref1);
394 					DisposeEventHandlerUPP(iUPP);
395 
396 					err = RemoveEventHandler(wref);
397 					DisposeEventHandlerUPP(wUPP);
398 				}
399 			}
400 
401 			CFRelease(tWindowRef);
402 		}
403 
404 		DisposeNibReference(nibRef);
405 	}
406 }
407 
CreateIconTableImage(void)408 static void CreateIconTableImage (void)
409 {
410 	CGContextRef		ctx;
411 	CGDataProviderRef	prov;
412 	CGColorSpaceRef		color;
413 	CGRect				rct;
414 
415 	rct = CGRectMake(0.0f, 0.0f, (float) kIconSize, (float) kIconSize);
416 
417 	iconTableCGWld = (Ptr) malloc(kIconSize * kKeys * (kIconSize + 1) * 4);
418 	if (!iconTableCGWld)
419 		QuitWithFatalError(0, "keyboard 08");
420 
421 	ctx = NULL;
422 
423 	color = CGColorSpaceCreateDeviceRGB();
424 	if (color)
425 	{
426 		ctx = CGBitmapContextCreate(iconTableCGWld, kIconSize * kKeys, kIconSize, 8, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
427 		CGColorSpaceRelease(color);
428 	}
429 
430 	if (!ctx)
431 		QuitWithFatalError(0, "keyboard 09");
432 
433 	CGContextTranslateCTM(ctx, 0.0f, (float) kIconSize);
434 	CGContextScaleCTM(ctx, 1.0f, -1.0f);
435 
436 	// SNES pads
437 	for (int i = macPadIconIndex; i < macPadIconIndex + 12 * 2; i++)
438 	{
439 		if (systemVersion >= 0x1040)
440 			CGContextDrawImage(ctx, rct, macIconImage[i]);
441 	#ifdef MAC_PANTHER_SUPPORT
442 		else
443 			PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
444 	#endif
445 		rct = CGRectOffset(rct, kIconSize, 0);
446 	}
447 
448 	// Function buttons
449 	for (int i = macFunctionIconIndex; i < macFunctionIconIndex + 17; i++)
450 	{
451 		if (systemVersion >= 0x1040)
452 			CGContextDrawImage(ctx, rct, macIconImage[i]);
453 	#ifdef MAC_PANTHER_SUPPORT
454 		else
455 			PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
456 	#endif
457 		rct = CGRectOffset(rct, kIconSize, 0);
458 	}
459 
460 	CGContextRelease(ctx);
461 
462 	iconTableImage = NULL;
463 
464 	prov = CGDataProviderCreateWithData(NULL, iconTableCGWld, kIconSize * kKeys * kIconSize * 4, NULL);
465 	if (prov)
466 	{
467 		color = CGColorSpaceCreateDeviceRGB();
468 		if (color)
469 		{
470 			iconTableImage = CGImageCreate(kIconSize * kKeys, kIconSize, 8, 32, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
471 			CGColorSpaceRelease(color);
472 		}
473 
474 		CGDataProviderRelease(prov);
475 	}
476 
477 	if (!iconTableImage)
478 		QuitWithFatalError(0, "keyboard 10");
479 }
480 
ReleaseIconTableImage(void)481 static void ReleaseIconTableImage (void)
482 {
483 	CGImageRelease(iconTableImage);
484 	free(iconTableCGWld);
485 }
486 
CreateKeyLayoutImage(void)487 static void CreateKeyLayoutImage (void)
488 {
489 	CGContextRef		ctx;
490 	CGDataProviderRef	prov;
491 	CGColorSpaceRef		color;
492 	CGAffineTransform	flipMatrix;
493 	CGRect				rct, r;
494 	int					index, scancode;
495 
496 	rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
497 	for (int i = 0; i < 0x80; i++)
498 		keyRect[i][0] = keyRect[i][1] = rct;
499 
500 	keyLayoutWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
501 	if (!keyLayoutWorld)
502 		QuitWithFatalError(0, "keyboard 02");
503 
504 	ctx = NULL;
505 
506 	color = CGColorSpaceCreateDeviceRGB();
507 	if (color)
508 	{
509 		ctx = CGBitmapContextCreate(keyLayoutWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
510 		CGColorSpaceRelease(color);
511 	}
512 
513 	if (!ctx)
514 		QuitWithFatalError(0, "keyboard 04");
515 
516 	CGContextSetLineJoin(ctx, kCGLineJoinMiter);
517 
518 	flipMatrix = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
519 	CGContextSelectFont(ctx, "Helvetica", 10.0f, kCGEncodingMacRoman);
520 	CGContextSetTextDrawingMode(ctx, kCGTextFill);
521 	CGContextSetTextMatrix(ctx, flipMatrix);
522 
523 	rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
524 	CGContextClearRect(ctx, rct);
525 
526 	index = 0;
527 	rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
528 
529 	for (int i = 0; i < 7; i++)
530 	{
531 		while (keys[index].keyWidth)
532 		{
533 			rct.size.width = (float) keys[index].keyWidth;
534 
535 			if (keys[index].keyLabel)
536 			{
537 				rct.size.height = (float) keys[index].keyHeight;
538 				scancode = keys[index].scancode;
539 
540 				if (keyRect[scancode][0].size.height < 1.0)
541 					keyRect[scancode][0] = rct;
542 				else
543 					keyRect[scancode][1] = rct;
544 
545 				r = rct;
546 
547 				r.origin.x += 1.0f;
548 				r.origin.y += 1.0f;
549 				r.size.width  -= 1.0f;
550 				r.size.height -= 1.0f;
551 
552 				CGContextSetRGBStrokeColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
553 				CGContextStrokeRect(ctx, r);
554 
555 				float	h, p;
556 
557 				CGRectInset(r, 2.0f, 2.0f);
558 				h = r.size.height;
559 				for (float f = h; f >= 1.0f; f -= 1.0f)
560 				{
561 					p = (155.0f + (h - f)) / 180.0f;
562 					CGContextSetRGBFillColor(ctx, p, p, p, 1.0f);
563 					CGContextFillRect(ctx, r);
564 					r.size.height -= 1.0f;
565 				}
566 
567 				CGContextSetRGBFillColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
568 				CGContextShowTextAtPoint(ctx, rct.origin.x + 3.0f, rct.origin.y + rct.size.height - 3.0f, keys[index].keyLabel, strlen(keys[index].keyLabel));
569 			}
570 
571 			rct.origin.x += rct.size.width;
572 			index++;
573 		}
574 
575 		rct.origin.y += kKeySize;
576 		rct.origin.x  = rct.size.width = 0;
577 		index++;
578 	}
579 
580 	CGContextRelease(ctx);
581 
582 	keyLayoutImage = NULL;
583 
584 	prov = CGDataProviderCreateWithData(NULL, keyLayoutWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
585 	if (prov)
586 	{
587 		color = CGColorSpaceCreateDeviceRGB();
588 		if (color)
589 		{
590 			keyLayoutImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
591 			CGColorSpaceRelease(color);
592 		}
593 
594 		CGDataProviderRelease(prov);
595 	}
596 
597 	if (!keyLayoutImage)
598 		QuitWithFatalError(0, "keyboard 05");
599 }
600 
ReleaseKeyLayoutImage(void)601 static void ReleaseKeyLayoutImage (void)
602 {
603 	CGImageRelease(keyLayoutImage);
604 	free(keyLayoutWorld);
605 }
606 
CreateIconPlaceImage(void)607 static void CreateIconPlaceImage (void)
608 {
609 	iconPlaceWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
610 	if (!iconPlaceWorld)
611 		QuitWithFatalError(0, "keyboard 06");
612 
613 	iconPlaceImage = NULL;
614 
615 	UpdateIconPlaceImage();
616 }
617 
UpdateIconPlaceImage(void)618 static void UpdateIconPlaceImage (void)
619 {
620 	CGContextRef		ctx;
621 	CGDataProviderRef	prov;
622 	CGColorSpaceRef		color;
623 	CGRect				rct;
624 
625 	if (iconPlaceImage)
626 		CGImageRelease(iconPlaceImage);
627 
628 	iconPlaceImage = NULL;
629 
630 	color = CGColorSpaceCreateDeviceRGB();
631 	if (color)
632 	{
633 		ctx = CGBitmapContextCreate(iconPlaceWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
634 		if (ctx)
635 		{
636 			rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
637 			CGContextDrawImage(ctx, rct, keyLayoutImage);
638 
639 			for (int i = 0; i < kKeys; i++)
640 				DrawPlacedIcon(ctx, i);
641 
642 			CGContextRelease(ctx);
643 		}
644 
645 		prov = CGDataProviderCreateWithData(NULL, iconPlaceWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
646 		if (prov)
647 		{
648 			iconPlaceImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
649 			CGDataProviderRelease(prov);
650 		}
651 
652 		CGColorSpaceRelease(color);
653 	}
654 
655 	if (!iconPlaceImage)
656 		QuitWithFatalError(0, "keyboard 07");
657 }
658 
ReleaseIconPlaceImage(void)659 static void ReleaseIconPlaceImage (void)
660 {
661 	CGImageRelease(iconPlaceImage);
662 	free(iconPlaceWorld);
663 }
664 
InitKeyboard(void)665 void InitKeyboard (void)
666 {
667 	theClass = NULL;
668 
669 	memcpy(defaultKeys, keyCode, sizeof(keyCode));
670 
671 	CreateIconTableImage();
672 	CreateKeyLayoutImage();
673 	CreateIconPlaceImage();
674 }
675 
DeinitKeyboard(void)676 void DeinitKeyboard (void)
677 {
678 	ReleaseIconPlaceImage();
679 	ReleaseKeyLayoutImage();
680 	ReleaseIconTableImage();
681 }
682 
DrawPlacedIcon(CGContextRef ctx,int which)683 static void DrawPlacedIcon (CGContextRef ctx, int which)
684 {
685 	CGRect	keyBounds, srcRect, dstRect;
686 
687 	CGContextSaveGState(ctx);
688 
689 	CGContextSetRGBFillColor(ctx, 0.40f, 0.40f, 0.65f, 0.5f);
690 
691 	for (int each = 0; each <= 1; each++)
692 	{
693 		keyBounds = keyRect[keyCode[which]][each];
694 
695 		if (keyBounds.size.height > 1.0f)
696 		{
697 			keyBounds.origin.x += 1.0f;
698 			keyBounds.origin.y += 1.0f;
699 			keyBounds.size.width  -= 1.0f;
700 			keyBounds.size.height -= 1.0f;
701 
702 			CGContextFillRect(ctx, keyBounds);
703 
704 			keyBounds.origin.x -= 1.0f;
705 			keyBounds.origin.y -= 1.0f;
706 			keyBounds.size.width  += 1.0f;
707 			keyBounds.size.height += 1.0f;
708 
709 			srcRect.origin.x = (float) (which * kIconSize);
710 			srcRect.origin.y = 0.0f;
711 			srcRect.size.width  = (float) kIconSize;
712 			srcRect.size.height = (float) kIconSize;
713 
714 			dstRect.origin.x = keyBounds.origin.x + (keyBounds.size.width  - kIconSize) / 2.0f;
715 			dstRect.origin.y = keyBounds.origin.y + (keyBounds.size.height - kIconSize) / 2.0f;
716 			dstRect.size.width  = (float) kIconSize;
717 			dstRect.size.height = (float) kIconSize;
718 
719 			DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
720 		}
721 	}
722 
723 	CGContextRestoreGState(ctx);
724 }
725 
DrawDraggedIcon(CGContextRef ctx,int which,CGPoint * offset)726 static void DrawDraggedIcon (CGContextRef ctx, int which, CGPoint *offset)
727 {
728 	CGRect	srcRect, dstRect;
729 
730 	CGContextSaveGState(ctx);
731 
732 	srcRect.origin.x = (float) (which * kIconSize);
733 	srcRect.origin.y = 0.0f;
734 	srcRect.size.width  = (float) kIconSize;
735 	srcRect.size.height = (float) kIconSize;
736 
737 	dstRect.origin.x = mousePos.x + offset->x;
738 	dstRect.origin.y = mousePos.y + offset->y;
739 	dstRect.size.width  = (float) kIconSize;
740 	dstRect.size.height = (float) kIconSize;
741 
742 	CGContextSetAlpha(ctx, 0.5f);
743 	DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
744 
745 	CGContextRestoreGState(ctx);
746 }
747 
KeyCodeInUse(int code)748 static Boolean KeyCodeInUse (int code)
749 {
750 	for (int i = 0; i < kKeys; i++)
751 		if (keyCode[i] == code)
752 			return (true);
753 
754 	return (false);
755 }
756 
FindHitKey(HIPoint where,CGRect * keybounds,CGPoint * offset)757 static int FindHitKey (HIPoint where, CGRect *keybounds, CGPoint *offset)
758 {
759 	int	hit;
760 
761 	hit = -1;
762 	*offset = CGPointMake(0.0f, 0.0f);
763 	*keybounds = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
764 
765 	for (int which = 0; which < kKeys; which++)
766 	{
767 		for (int each = 0; each <= 1; each++)
768 		{
769 			if (CGRectContainsPoint(keyRect[keyCode[which]][each], where))
770 			{
771 				hit = which;
772 
773 				*keybounds = keyRect[keyCode[which]][each];
774 				offset->x = keybounds->origin.x + (keybounds->size.width  - kIconSize) / 2.0f - where.x + 18.0f;
775 				offset->y = keybounds->origin.y + (keybounds->size.height - kIconSize) / 2.0f - where.y + 18.0f;
776 			}
777 		}
778 	}
779 
780 	return (hit);
781 }
782 
KeyWindowEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)783 static pascal OSStatus KeyWindowEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
784 {
785 	OSStatus	err, result = eventNotHandledErr;
786 	WindowRef	tWindowRef = (WindowRef) inUserData;
787 
788 	switch (GetEventClass(inEvent))
789 	{
790 		case kEventClassWindow:
791 			switch (GetEventKind(inEvent))
792 			{
793 				case kEventWindowClose:
794 					QuitAppModalLoopForWindow(tWindowRef);
795 					result = noErr;
796 			}
797 
798 			break;
799 
800 		case kEventClassCommand:
801 			switch (GetEventKind(inEvent))
802 			{
803 				HICommand	tHICommand;
804 
805 				case kEventCommandUpdateStatus:
806 					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
807 					if (err == noErr && tHICommand.commandID == 'clos')
808 					{
809 						UpdateMenuCommandStatus(true);
810 						result = noErr;
811 					}
812 
813 					break;
814 
815 				case kEventCommandProcess:
816 					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
817 					if (err == noErr)
818 					{
819 						if (tHICommand.commandID == 'DFLT')
820 						{
821 							memcpy(keyCode, defaultKeys, sizeof(keyCode));
822 							UpdateIconPlaceImage();
823 							HIViewSetNeedsDisplay(customView, true);
824 							result = noErr;
825 						}
826 					}
827 			}
828 	}
829 
830 	return (result);
831 }
832 
KeyLegendEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)833 static pascal OSStatus KeyLegendEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
834 {
835     OSStatus	err, result = eventNotHandledErr;
836 	HIViewRef	view = (HIViewRef) inUserData;
837 
838 	switch (GetEventClass(inEvent))
839 	{
840 		case kEventClassControl:
841 			switch (GetEventKind(inEvent))
842 			{
843 				case kEventControlDraw:
844 					CGContextRef	ctx;
845 
846 					err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(CGContextRef), NULL, &ctx);
847 					if (err == noErr)
848 					{
849 						HIViewID	cid;
850 						HIRect		bounds;
851 
852 						GetControlID(view, &cid);
853 						HIViewGetBounds(view, &bounds);
854 						CGContextTranslateCTM(ctx, 0, bounds.size.height);
855 						CGContextScaleCTM(ctx, 1.0f, -1.0f);
856 						CGContextDrawImage(ctx, CGRectMake(0, 0, kIconSize, kIconSize), macIconImage[macLegendIconIndex + cid.id]);
857 
858 						result = noErr;
859 					}
860 			}
861 	}
862 
863 	return (result);
864 }
865 
KeyLayoutEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)866 static pascal OSStatus KeyLayoutEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
867 {
868 	OSStatus		err, result = eventNotHandledErr;
869 	CustomViewData	*data = (CustomViewData *) inUserData;
870 
871 	switch (GetEventClass(inEvent))
872 	{
873 		case kEventClassHIObject:
874 			switch (GetEventKind(inEvent))
875 			{
876 				case kEventHIObjectConstruct:
877 					data = (CustomViewData *) calloc(1, sizeof(CustomViewData));
878 					if (data)
879 					{
880 						HIViewRef	epView;
881 
882 						err = GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView);
883 						if (err == noErr)
884 						{
885 							data->view = epView;
886 							result = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(data), &data);
887 						}
888 					}
889 
890 					break;
891 
892 				case kEventHIObjectDestruct:
893 					if (data)
894 						free(data);
895 
896 					result = noErr;
897 					break;
898 
899 				case kEventHIObjectInitialize:
900 					result = CallNextEventHandler(inHandlerRef, inEvent);
901 			}
902 
903 			break;
904 
905 		case kEventClassControl:
906 			switch (GetEventKind(inEvent))
907 			{
908 				case kEventControlDraw:
909 					CGContextRef	ctx;
910 
911 					err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(ctx), NULL, &ctx);
912 					if (err == noErr)
913 					{
914 						HIRect	bounds, srcRect, dstRect;
915 
916 						HIViewGetBounds(customView, &bounds);
917 						srcRect = CGRectMake(0, 0, kKeyLayoutWidth, kKeyLayoutHeight);
918 
919 						dstRect.origin.x = (float) (((int) bounds.size.width  - kKeyLayoutWidth ) >> 1);
920 						dstRect.origin.y = (float) (((int) bounds.size.height - kKeyLayoutHeight) >> 1);
921 						dstRect.size.width  = (float) kKeyLayoutWidth;
922 						dstRect.size.height = (float) kKeyLayoutHeight;
923 
924 						DrawSubCGImage(ctx, iconPlaceImage, srcRect, dstRect);
925 						if (keyInDrag && (dragKey != -1))
926 							DrawDraggedIcon(ctx, dragKey, &dragKeyOfs);
927 					}
928 
929 					result = noErr;
930 					break;
931 
932 				case kEventControlHitTest:
933 					ControlPartCode	part;
934 
935 					part = kControlButtonPart;
936 					result = SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(part), &part);
937 
938 					break;
939 
940       			case kEventControlTrack:
941                     MouseTrackingResult	trackResult;
942 					WindowRef			window;
943 					HIViewRef			contentView;
944 					HIPoint				hipt;
945 
946  					dragKey = -1;
947 					dragKeyOfs = CGPointMake(0.0f, 0.0f);
948 					dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
949 					mousePos = CGPointMake(0.0f, 0.0f);
950 					trackResult = kMouseTrackingMouseDown;
951 
952 					window = GetControlOwner(customView);
953 					HIViewFindByID(HIViewGetRoot(window), kHIViewWindowContentID, &contentView);
954 
955 				#ifdef MAC_TIGER_PANTHER_SUPPORT
956 					CGrafPtr	oldPort;
957 					Point		qdpt;
958 					Boolean		portChanged = false;
959 
960 					if (systemVersion < 0x1050)
961 						portChanged = QDSwapPort(GetWindowPort(window), &oldPort);
962 				#endif
963 
964 					err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(hipt), NULL, &hipt);
965 					if (err == noErr)
966 					{
967 						hipt.x -= ofsx;
968 						hipt.y -= ofsy;
969 
970 						dragKey = FindHitKey(hipt, &dragKeyRect, &dragKeyOfs);
971 						if (dragKey != -1)
972 						{
973 							keyInDrag = true;
974 
975 							while (trackResult != kMouseTrackingMouseUp)
976 							{
977 								if (CGPointEqualToPoint(mousePos, hipt) == 0)
978 								{
979 									mousePos = hipt;
980 									HIViewSetNeedsDisplay(customView, true);
981 								}
982 
983 								if (systemVersion >= 0x1050)
984 								{
985 									err = HIViewTrackMouseLocation(customView, 0, kEventDurationForever, 0, NULL, &hipt, NULL, NULL, &trackResult);
986 									hipt.x -= ofsx;
987 									hipt.y -= ofsy;
988 								}
989 							#ifdef MAC_TIGER_PANTHER_SUPPORT
990 								else
991 								{
992 									TrackMouseLocation(NULL, &qdpt, &trackResult);
993 									hipt.x = qdpt.h - ofsx;
994 									hipt.y = qdpt.v - ofsy;
995 									HIViewConvertPoint(&hipt, contentView, customView);
996 								}
997 							#endif
998 							}
999 
1000 							keyInDrag = false;
1001 
1002 							for (int code = 0; code < 0x80; code++)
1003 							{
1004 								for (int each = 0; each <= 1; each++)
1005 								{
1006 									if (CGRectContainsPoint(keyRect[code][each], mousePos))
1007 									{
1008 										if (!KeyCodeInUse(code))
1009 										{
1010 											keyCode[dragKey] = code;
1011 											UpdateIconPlaceImage();
1012 										}
1013 									}
1014 								}
1015 							}
1016 
1017 							HIViewSetNeedsDisplay(customView, true);
1018 						}
1019 					}
1020 
1021 				#ifdef MAC_TIGER_PANTHER_SUPPORT
1022 					if (systemVersion < 0x1050)
1023 					{
1024 						if (portChanged)
1025 							QDSwapPort(oldPort, NULL);
1026 					}
1027 				#endif
1028 
1029 					result = noErr;
1030 			}
1031 	}
1032 
1033 	return (result);
1034 }
1035