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