1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181 /***********************************************************************************
182 SNES9X for Mac OS (c) Copyright John Stiles
183
184 Snes9x for Mac OS X
185
186 (c) Copyright 2001 - 2011 zones
187 (c) Copyright 2002 - 2005 107
188 (c) Copyright 2002 PB1400c
189 (c) Copyright 2004 Alexander and Sander
190 (c) Copyright 2004 - 2005 Steven Seeger
191 (c) Copyright 2005 Ryan Vogt
192 ***********************************************************************************/
193
194
195 #include "port.h"
196
197 #include "mac-prefix.h"
198 #include "mac-dialog.h"
199 #include "mac-gworld.h"
200 #include "mac-os.h"
201 #include "mac-keyboard.h"
202
203 #define kmUpArrowKey 0x7E
204 #define kmDownArrowKey 0x7D
205 #define kmRightArrowKey 0x7C
206 #define kmLeftArrowKey 0x7B
207 #define kmReturnKey 0x24
208 #define kmTabKey 0x30
209 #define kmShiftKey 0x38
210 #define kmControlKey 0x3B
211 #define kmOptionKey 0x3A
212 #define kmCommandKey 0x37
213 #define kmXKey 0x07
214 #define kmZKey 0x06
215 #define kmKP2Key 0x54
216 #define kmKP4Key 0x56
217 #define kmKP5Key 0x57
218 #define kmKP6Key 0x58
219 #define kmKP8Key 0x5B
220 #define kmKPEnterKey 0x4C
221 #define kmKPPlusKey 0x45
222 #define kmKP0Key 0x52
223 #define kmKPPeriodKey 0x41
224 #define kmHomeKey 0x73
225 #define kmPageUpKey 0x74
226 #define kmEndKey 0x77
227 #define kmPageDownKey 0x79
228 #define kmBackslashKey 0x2A
229 #define km1Key 0x12
230 #define km0Key 0x1D
231 #define kmIKey 0x22
232 #define kmJKey 0x26
233 #define kmKKey 0x28
234 #define kmLKey 0x25
235 #define kmTildeKey 0x32
236 #define kmRKey 0x0F
237 #define kmBKey 0x0B
238 #define kmNKey 0x2D
239 #define kmMKey 0x2E
240 #define kmSpaceKey 0x31
241 #define kmSlashKey 0x2C
242 #define kmPeriodKey 0x2F
243 #define kmQKey 0x0C
244 #define kmWKey 0x0D
245 #define kmEscKey 0x35
246 #define kmCommaKey 0x2B
247
248 #define kIconSize 16
249 #define kKeySize 24
250 #define KS kKeySize
251
252 uint8 keyCode[kKeys] =
253 {
254 kmUpArrowKey,
255 kmDownArrowKey,
256 kmLeftArrowKey,
257 kmRightArrowKey,
258 kmShiftKey,
259 kmOptionKey,
260 kmControlKey,
261 kmCommandKey,
262 kmZKey,
263 kmXKey,
264 kmReturnKey,
265 kmTabKey,
266
267 kmKP8Key,
268 kmKP2Key,
269 kmKP4Key,
270 kmKP6Key,
271 kmPageDownKey,
272 kmPageUpKey,
273 kmEndKey,
274 kmHomeKey,
275 kmKP0Key,
276 kmKPPeriodKey,
277 kmKPEnterKey,
278 kmKPPlusKey,
279
280 kmBackslashKey,
281 km1Key,
282 km0Key,
283 kmTildeKey,
284 kmRKey,
285 kmBKey,
286 kmNKey,
287 kmMKey,
288 kmSpaceKey,
289 kmSlashKey,
290 kmPeriodKey,
291 kmQKey,
292 kmWKey,
293 kmEscKey,
294 kmCommaKey
295 };
296
297 typedef struct
298 {
299 int keyWidth, keyHeight;
300 uint8 scancode;
301 const char *keyLabel;
302 } KeyboardLayout;
303
304 typedef struct
305 {
306 HIViewRef view;
307 } CustomViewData;
308
309 static CGImageRef iconTableImage;
310 static CGImageRef keyLayoutImage;
311 static CGImageRef iconPlaceImage;
312 static Ptr iconTableCGWld;
313 static Ptr keyLayoutWorld;
314 static Ptr iconPlaceWorld;
315
316 static CGRect keyRect[0x80][2];
317 static uint8 defaultKeys[kKeys];
318
319 static HIObjectClassRef theClass;
320 static HIViewRef customView;
321 static HIPoint mousePos;
322 static float ofsx, ofsy;
323 static int dragKey;
324 static CGPoint dragKeyOfs;
325 static CGRect dragKeyRect;
326 static volatile Boolean keyInDrag;
327
328 static const int kKeyLayoutWidth = kKeySize * 23 + 1,
329 kKeyLayoutHeight = kKeySize * 7 + 1;
330
331 static KeyboardLayout keys[] =
332 {
333 { KS, KS, 0x35, "esc" },
334 { KS, KS, 0x00, NULL },
335 { KS, KS, 0x7a, "F1" },
336 { KS, KS, 0x78, "F2" },
337 { KS, KS, 0x63, "F3" },
338 { KS, KS, 0x76, "F4" },
339 { KS / 2, KS, 0x00, NULL },
340 { KS, KS, 0x60, "F5" },
341 { KS, KS, 0x61, "F6" },
342 { KS, KS, 0x62, "F7" },
343 { KS, KS, 0x64, "F8" },
344 { KS / 2, KS, 0x00, NULL },
345 { KS, KS, 0x65, "F9" },
346 { KS, KS, 0x6d, "F10" },
347 { KS, KS, 0x67, "F11" },
348 { KS, KS, 0x6f, "F12" },
349 { KS / 2, KS, 0x00, NULL },
350 { KS, KS, 0x69, "F13" },
351 { KS, KS, 0x6b, "F14" },
352 { KS, KS, 0x71, "F15" },
353 { 0, 0, 0x00, NULL },
354
355 { 0, 0, 0x00, NULL },
356
357 { KS, KS, 0x32, "`" },
358 { KS, KS, 0x12, "1" },
359 { KS, KS, 0x13, "2" },
360 { KS, KS, 0x14, "3" },
361 { KS, KS, 0x15, "4" },
362 { KS, KS, 0x17, "5" },
363 { KS, KS, 0x16, "6" },
364 { KS, KS, 0x1a, "7" },
365 { KS, KS, 0x1c, "8" },
366 { KS, KS, 0x19, "9" },
367 { KS, KS, 0x1d, "0" },
368 { KS, KS, 0x1b, "-" },
369 { KS, KS, 0x18, "=" },
370 { KS * 2, KS, 0x33, "delete" },
371 { KS / 2, KS, 0x00, NULL },
372 { KS, KS, 0x72, "ins" },
373 { KS, KS, 0x73, "hom" },
374 { KS, KS, 0x74, "pgu" },
375 { KS / 2, KS, 0x00, NULL },
376 { KS, KS, 0x47, "clr" },
377 { KS, KS, 0x51, "=" },
378 { KS, KS, 0x4b, "/" },
379 { KS, KS, 0x43, "*" },
380 { 0, 0, 0x00, NULL },
381
382 { KS * 3 / 2, KS, 0x30, "tab" },
383 { KS, KS, 0x0c, "Q" },
384 { KS, KS, 0x0d, "W" },
385 { KS, KS, 0x0e, "E" },
386 { KS, KS, 0x0f, "R" },
387 { KS, KS, 0x11, "T" },
388 { KS, KS, 0x10, "Y" },
389 { KS, KS, 0x20, "U" },
390 { KS, KS, 0x22, "I" },
391 { KS, KS, 0x1f, "O" },
392 { KS, KS, 0x23, "P" },
393 { KS, KS, 0x21, "[" },
394 { KS, KS, 0x1e, "]" },
395 { KS * 3 / 2, KS, 0x2a, "\\" },
396 { KS / 2, KS, 0x00, NULL },
397 { KS, KS, 0x75, "del" },
398 { KS, KS, 0x77, "end" },
399 { KS, KS, 0x79, "pgd" },
400 { KS / 2, KS, 0x00, NULL },
401 { KS, KS, 0x59, "7" },
402 { KS, KS, 0x5b, "8" },
403 { KS, KS, 0x5c, "9" },
404 { KS, KS, 0x4e, "-" },
405 { 0, 0, 0x00, NULL },
406
407 { KS * 2, KS, 0x39, "caps" },
408 { KS, KS, 0x00, "A" },
409 { KS, KS, 0x01, "S" },
410 { KS, KS, 0x02, "D" },
411 { KS, KS, 0x03, "F" },
412 { KS, KS, 0x05, "G" },
413 { KS, KS, 0x04, "H" },
414 { KS, KS, 0x26, "J" },
415 { KS, KS, 0x28, "K" },
416 { KS, KS, 0x25, "L" },
417 { KS, KS, 0x29, ";" },
418 { KS, KS, 0x27, "\xd3" },
419 { KS * 2, KS, 0x24, "return" },
420 { KS * 4, KS, 0x00, NULL },
421 { KS, KS, 0x56, "4" },
422 { KS, KS, 0x57, "5" },
423 { KS, KS, 0x58, "6" },
424 { KS, KS, 0x45, "+" },
425 { 0, 0, 0x00, NULL },
426
427 { KS * 5 / 2, KS, 0x38, "shift" },
428 { KS, KS, 0x06, "Z" },
429 { KS, KS, 0x07, "X" },
430 { KS, KS, 0x08, "C" },
431 { KS, KS, 0x09, "V" },
432 { KS, KS, 0x0b, "B" },
433 { KS, KS, 0x2d, "N" },
434 { KS, KS, 0x2e, "M" },
435 { KS, KS, 0x2b, "," },
436 { KS, KS, 0x2f, "." },
437 { KS, KS, 0x2c, "/" },
438 { KS * 5 / 2, KS, 0x38, "shift" },
439 { KS * 3 / 2, KS, 0x00, NULL },
440 { KS, KS, 0x7e, "up" },
441 { KS * 3 / 2, KS, 0x00, NULL },
442 { KS, KS, 0x53, "1" },
443 { KS, KS, 0x54, "2" },
444 { KS, KS, 0x55, "3" },
445 { KS, KS * 2, 0x4c, "ent" },
446 { 0, 0, 0x00, NULL },
447
448 { KS * 3 / 2, KS, 0x3b, "ctrl" },
449 { KS * 3 / 2, KS, 0x3a, "opt" },
450 { KS * 3 / 2, KS, 0x37, "cmd" },
451 { KS * 6, KS, 0x31, " " },
452 { KS * 3 / 2, KS, 0x37, "cmd" },
453 { KS * 3 / 2, KS, 0x3a, "opt" },
454 { KS * 3 / 2, KS, 0x3b, "ctrl" },
455 { KS / 2, KS, 0x00, NULL },
456 { KS, KS, 0x7b, "lt" },
457 { KS, KS, 0x7d, "dn" },
458 { KS, KS, 0x7c, "rt" },
459 { KS / 2, KS, 0x00, NULL },
460 { KS * 2, KS, 0x52, "0" },
461 { KS, KS, 0x41, "." },
462 { 0, 0, 0x00, NULL }
463 };
464
465 static void CreateIconTableImage (void);
466 static void ReleaseIconTableImage (void);
467 static void CreateKeyLayoutImage (void);
468 static void ReleaseKeyLayoutImage (void);
469 static void CreateIconPlaceImage (void);
470 static void UpdateIconPlaceImage (void);
471 static void ReleaseIconPlaceImage (void);
472 static void DrawPlacedIcon (CGContextRef, int);
473 static void DrawDraggedIcon (CGContextRef, int, CGPoint *);
474 static Boolean KeyCodeInUse (int);
475 static int FindHitKey (HIPoint, CGRect *, CGPoint *);
476 static pascal OSStatus KeyWindowEventHandler (EventHandlerCallRef, EventRef, void *);
477 static pascal OSStatus KeyLegendEventHandler (EventHandlerCallRef, EventRef, void *);
478 static pascal OSStatus KeyLayoutEventHandler (EventHandlerCallRef, EventRef, void *);
479
480 #define kCustomLayoutViewClassID CFSTR("com.snes9x.macos.snes9x.keylayout")
481
482
ConfigureKeyboard(void)483 void ConfigureKeyboard (void)
484 {
485 OSStatus err;
486 IBNibRef nibRef;
487
488 err = CreateNibReference(kMacS9XCFString, &nibRef);
489 if (err == noErr)
490 {
491 WindowRef tWindowRef;
492
493 err = CreateWindowFromNib(nibRef, CFSTR("Keyboard"), &tWindowRef);
494 if (err == noErr)
495 {
496 EventHandlerRef wref, iref1, iref2;
497 EventHandlerUPP wUPP, iUPP;
498 EventTypeSpec wEvents[] = { { kEventClassWindow, kEventWindowClose },
499 { kEventClassCommand, kEventCommandProcess },
500 { kEventClassCommand, kEventCommandUpdateStatus } },
501 cEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct },
502 { kEventClassHIObject, kEventHIObjectDestruct },
503 { kEventClassHIObject, kEventHIObjectInitialize },
504 { kEventClassControl, kEventControlDraw },
505 { kEventClassControl, kEventControlHitTest },
506 { kEventClassControl, kEventControlTrack } },
507 iEvents[] = { { kEventClassControl, kEventControlDraw } };
508 HIObjectRef hiObject;
509 HIViewRef contentView, image1, image2;
510 HIViewID cid;
511 HIRect frame;
512 Rect winBounds;
513
514 UpdateIconPlaceImage();
515
516 keyInDrag = false;
517 dragKey = -1;
518 dragKeyOfs = CGPointMake(0.0f, 0.0f);
519 dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
520 mousePos = CGPointMake(0.0f, 0.0f);
521
522 err = noErr;
523 if (theClass == NULL)
524 err = HIObjectRegisterSubclass(kCustomLayoutViewClassID, kHIViewClassID, 0, KeyLayoutEventHandler, GetEventTypeCount(cEvents), cEvents, NULL, &theClass);
525
526 if (err == noErr)
527 {
528 err = HIObjectCreate(kCustomLayoutViewClassID, NULL, &hiObject);
529 if (err == noErr)
530 {
531 GetWindowBounds(tWindowRef, kWindowContentRgn, &winBounds);
532
533 frame.origin.x = 2.0f;
534 frame.origin.y = 2.0f;
535 frame.size.width = (float) (winBounds.right - winBounds.left) - 4.0f;
536 frame.size.height = (float) kKeyLayoutHeight + 36.0f;
537
538 ofsx = (float) (((int) frame.size.width - kKeyLayoutWidth ) >> 1) + 1.0f;
539 ofsy = (float) (((int) frame.size.height - kKeyLayoutHeight) >> 1) + 1.0f;
540
541 customView = (HIViewRef) hiObject;
542
543 HIViewFindByID(HIViewGetRoot(tWindowRef), kHIViewWindowContentID, &contentView);
544 HIViewAddSubview(contentView, customView);
545 HIViewSetFrame(customView, &frame);
546 HIViewSetVisible(customView, true);
547
548 cid.signature = 'Lgnd';
549 cid.id = 0;
550 HIViewFindByID(contentView, cid, &image1);
551 cid.id = 1;
552 HIViewFindByID(contentView, cid, &image2);
553 iUPP = NewEventHandlerUPP(KeyLegendEventHandler);
554 err = InstallControlEventHandler(image1, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image1, &iref1);
555 err = InstallControlEventHandler(image2, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image2, &iref2);
556
557 wUPP = NewEventHandlerUPP(KeyWindowEventHandler);
558 err = InstallWindowEventHandler(tWindowRef, wUPP, GetEventTypeCount(wEvents), wEvents, (void *) tWindowRef, &wref);
559
560 MoveWindowPosition(tWindowRef, kWindowKeyConfig, false);
561 ShowWindow(tWindowRef);
562 err = RunAppModalLoopForWindow(tWindowRef);
563 HideWindow(tWindowRef);
564 SaveWindowPosition(tWindowRef, kWindowKeyConfig);
565
566 err = RemoveEventHandler(iref2);
567 err = RemoveEventHandler(iref1);
568 DisposeEventHandlerUPP(iUPP);
569
570 err = RemoveEventHandler(wref);
571 DisposeEventHandlerUPP(wUPP);
572 }
573 }
574
575 CFRelease(tWindowRef);
576 }
577
578 DisposeNibReference(nibRef);
579 }
580 }
581
CreateIconTableImage(void)582 static void CreateIconTableImage (void)
583 {
584 CGContextRef ctx;
585 CGDataProviderRef prov;
586 CGColorSpaceRef color;
587 CGRect rct;
588
589 rct = CGRectMake(0.0f, 0.0f, (float) kIconSize, (float) kIconSize);
590
591 iconTableCGWld = (Ptr) malloc(kIconSize * kKeys * (kIconSize + 1) * 4);
592 if (!iconTableCGWld)
593 QuitWithFatalError(0, "keyboard 08");
594
595 ctx = NULL;
596
597 color = CGColorSpaceCreateDeviceRGB();
598 if (color)
599 {
600 ctx = CGBitmapContextCreate(iconTableCGWld, kIconSize * kKeys, kIconSize, 8, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
601 CGColorSpaceRelease(color);
602 }
603
604 if (!ctx)
605 QuitWithFatalError(0, "keyboard 09");
606
607 CGContextTranslateCTM(ctx, 0.0f, (float) kIconSize);
608 CGContextScaleCTM(ctx, 1.0f, -1.0f);
609
610 // SNES pads
611 for (int i = macPadIconIndex; i < macPadIconIndex + 12 * 2; i++)
612 {
613 if (systemVersion >= 0x1040)
614 CGContextDrawImage(ctx, rct, macIconImage[i]);
615 #ifdef MAC_PANTHER_SUPPORT
616 else
617 PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
618 #endif
619 rct = CGRectOffset(rct, kIconSize, 0);
620 }
621
622 // Function buttons
623 for (int i = macFunctionIconIndex; i < macFunctionIconIndex + 17; i++)
624 {
625 if (systemVersion >= 0x1040)
626 CGContextDrawImage(ctx, rct, macIconImage[i]);
627 #ifdef MAC_PANTHER_SUPPORT
628 else
629 PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
630 #endif
631 rct = CGRectOffset(rct, kIconSize, 0);
632 }
633
634 CGContextRelease(ctx);
635
636 iconTableImage = NULL;
637
638 prov = CGDataProviderCreateWithData(NULL, iconTableCGWld, kIconSize * kKeys * kIconSize * 4, NULL);
639 if (prov)
640 {
641 color = CGColorSpaceCreateDeviceRGB();
642 if (color)
643 {
644 iconTableImage = CGImageCreate(kIconSize * kKeys, kIconSize, 8, 32, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
645 CGColorSpaceRelease(color);
646 }
647
648 CGDataProviderRelease(prov);
649 }
650
651 if (!iconTableImage)
652 QuitWithFatalError(0, "keyboard 10");
653 }
654
ReleaseIconTableImage(void)655 static void ReleaseIconTableImage (void)
656 {
657 CGImageRelease(iconTableImage);
658 free(iconTableCGWld);
659 }
660
CreateKeyLayoutImage(void)661 static void CreateKeyLayoutImage (void)
662 {
663 CGContextRef ctx;
664 CGDataProviderRef prov;
665 CGColorSpaceRef color;
666 CGAffineTransform flipMatrix;
667 CGRect rct, r;
668 int index, scancode;
669
670 rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
671 for (int i = 0; i < 0x80; i++)
672 keyRect[i][0] = keyRect[i][1] = rct;
673
674 keyLayoutWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
675 if (!keyLayoutWorld)
676 QuitWithFatalError(0, "keyboard 02");
677
678 ctx = NULL;
679
680 color = CGColorSpaceCreateDeviceRGB();
681 if (color)
682 {
683 ctx = CGBitmapContextCreate(keyLayoutWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
684 CGColorSpaceRelease(color);
685 }
686
687 if (!ctx)
688 QuitWithFatalError(0, "keyboard 04");
689
690 CGContextSetLineJoin(ctx, kCGLineJoinMiter);
691
692 flipMatrix = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
693 CGContextSelectFont(ctx, "Helvetica", 10.0f, kCGEncodingMacRoman);
694 CGContextSetTextDrawingMode(ctx, kCGTextFill);
695 CGContextSetTextMatrix(ctx, flipMatrix);
696
697 rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
698 CGContextClearRect(ctx, rct);
699
700 index = 0;
701 rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
702
703 for (int i = 0; i < 7; i++)
704 {
705 while (keys[index].keyWidth)
706 {
707 rct.size.width = (float) keys[index].keyWidth;
708
709 if (keys[index].keyLabel)
710 {
711 rct.size.height = (float) keys[index].keyHeight;
712 scancode = keys[index].scancode;
713
714 if (keyRect[scancode][0].size.height < 1.0)
715 keyRect[scancode][0] = rct;
716 else
717 keyRect[scancode][1] = rct;
718
719 r = rct;
720
721 r.origin.x += 1.0f;
722 r.origin.y += 1.0f;
723 r.size.width -= 1.0f;
724 r.size.height -= 1.0f;
725
726 CGContextSetRGBStrokeColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
727 CGContextStrokeRect(ctx, r);
728
729 float h, p;
730
731 CGRectInset(r, 2.0f, 2.0f);
732 h = r.size.height;
733 for (float f = h; f >= 1.0f; f -= 1.0f)
734 {
735 p = (155.0f + (h - f)) / 180.0f;
736 CGContextSetRGBFillColor(ctx, p, p, p, 1.0f);
737 CGContextFillRect(ctx, r);
738 r.size.height -= 1.0f;
739 }
740
741 CGContextSetRGBFillColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
742 CGContextShowTextAtPoint(ctx, rct.origin.x + 3.0f, rct.origin.y + rct.size.height - 3.0f, keys[index].keyLabel, strlen(keys[index].keyLabel));
743 }
744
745 rct.origin.x += rct.size.width;
746 index++;
747 }
748
749 rct.origin.y += kKeySize;
750 rct.origin.x = rct.size.width = 0;
751 index++;
752 }
753
754 CGContextRelease(ctx);
755
756 keyLayoutImage = NULL;
757
758 prov = CGDataProviderCreateWithData(NULL, keyLayoutWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
759 if (prov)
760 {
761 color = CGColorSpaceCreateDeviceRGB();
762 if (color)
763 {
764 keyLayoutImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
765 CGColorSpaceRelease(color);
766 }
767
768 CGDataProviderRelease(prov);
769 }
770
771 if (!keyLayoutImage)
772 QuitWithFatalError(0, "keyboard 05");
773 }
774
ReleaseKeyLayoutImage(void)775 static void ReleaseKeyLayoutImage (void)
776 {
777 CGImageRelease(keyLayoutImage);
778 free(keyLayoutWorld);
779 }
780
CreateIconPlaceImage(void)781 static void CreateIconPlaceImage (void)
782 {
783 iconPlaceWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
784 if (!iconPlaceWorld)
785 QuitWithFatalError(0, "keyboard 06");
786
787 iconPlaceImage = NULL;
788
789 UpdateIconPlaceImage();
790 }
791
UpdateIconPlaceImage(void)792 static void UpdateIconPlaceImage (void)
793 {
794 CGContextRef ctx;
795 CGDataProviderRef prov;
796 CGColorSpaceRef color;
797 CGRect rct;
798
799 if (iconPlaceImage)
800 CGImageRelease(iconPlaceImage);
801
802 iconPlaceImage = NULL;
803
804 color = CGColorSpaceCreateDeviceRGB();
805 if (color)
806 {
807 ctx = CGBitmapContextCreate(iconPlaceWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
808 if (ctx)
809 {
810 rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
811 CGContextDrawImage(ctx, rct, keyLayoutImage);
812
813 for (int i = 0; i < kKeys; i++)
814 DrawPlacedIcon(ctx, i);
815
816 CGContextRelease(ctx);
817 }
818
819 prov = CGDataProviderCreateWithData(NULL, iconPlaceWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
820 if (prov)
821 {
822 iconPlaceImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
823 CGDataProviderRelease(prov);
824 }
825
826 CGColorSpaceRelease(color);
827 }
828
829 if (!iconPlaceImage)
830 QuitWithFatalError(0, "keyboard 07");
831 }
832
ReleaseIconPlaceImage(void)833 static void ReleaseIconPlaceImage (void)
834 {
835 CGImageRelease(iconPlaceImage);
836 free(iconPlaceWorld);
837 }
838
InitKeyboard(void)839 void InitKeyboard (void)
840 {
841 theClass = NULL;
842
843 memcpy(defaultKeys, keyCode, sizeof(keyCode));
844
845 CreateIconTableImage();
846 CreateKeyLayoutImage();
847 CreateIconPlaceImage();
848 }
849
DeinitKeyboard(void)850 void DeinitKeyboard (void)
851 {
852 ReleaseIconPlaceImage();
853 ReleaseKeyLayoutImage();
854 ReleaseIconTableImage();
855 }
856
DrawPlacedIcon(CGContextRef ctx,int which)857 static void DrawPlacedIcon (CGContextRef ctx, int which)
858 {
859 CGRect keyBounds, srcRect, dstRect;
860
861 CGContextSaveGState(ctx);
862
863 CGContextSetRGBFillColor(ctx, 0.40f, 0.40f, 0.65f, 0.5f);
864
865 for (int each = 0; each <= 1; each++)
866 {
867 keyBounds = keyRect[keyCode[which]][each];
868
869 if (keyBounds.size.height > 1.0f)
870 {
871 keyBounds.origin.x += 1.0f;
872 keyBounds.origin.y += 1.0f;
873 keyBounds.size.width -= 1.0f;
874 keyBounds.size.height -= 1.0f;
875
876 CGContextFillRect(ctx, keyBounds);
877
878 keyBounds.origin.x -= 1.0f;
879 keyBounds.origin.y -= 1.0f;
880 keyBounds.size.width += 1.0f;
881 keyBounds.size.height += 1.0f;
882
883 srcRect.origin.x = (float) (which * kIconSize);
884 srcRect.origin.y = 0.0f;
885 srcRect.size.width = (float) kIconSize;
886 srcRect.size.height = (float) kIconSize;
887
888 dstRect.origin.x = keyBounds.origin.x + (keyBounds.size.width - kIconSize) / 2.0f;
889 dstRect.origin.y = keyBounds.origin.y + (keyBounds.size.height - kIconSize) / 2.0f;
890 dstRect.size.width = (float) kIconSize;
891 dstRect.size.height = (float) kIconSize;
892
893 DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
894 }
895 }
896
897 CGContextRestoreGState(ctx);
898 }
899
DrawDraggedIcon(CGContextRef ctx,int which,CGPoint * offset)900 static void DrawDraggedIcon (CGContextRef ctx, int which, CGPoint *offset)
901 {
902 CGRect srcRect, dstRect;
903
904 CGContextSaveGState(ctx);
905
906 srcRect.origin.x = (float) (which * kIconSize);
907 srcRect.origin.y = 0.0f;
908 srcRect.size.width = (float) kIconSize;
909 srcRect.size.height = (float) kIconSize;
910
911 dstRect.origin.x = mousePos.x + offset->x;
912 dstRect.origin.y = mousePos.y + offset->y;
913 dstRect.size.width = (float) kIconSize;
914 dstRect.size.height = (float) kIconSize;
915
916 CGContextSetAlpha(ctx, 0.5f);
917 DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
918
919 CGContextRestoreGState(ctx);
920 }
921
KeyCodeInUse(int code)922 static Boolean KeyCodeInUse (int code)
923 {
924 for (int i = 0; i < kKeys; i++)
925 if (keyCode[i] == code)
926 return (true);
927
928 return (false);
929 }
930
FindHitKey(HIPoint where,CGRect * keybounds,CGPoint * offset)931 static int FindHitKey (HIPoint where, CGRect *keybounds, CGPoint *offset)
932 {
933 int hit;
934
935 hit = -1;
936 *offset = CGPointMake(0.0f, 0.0f);
937 *keybounds = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
938
939 for (int which = 0; which < kKeys; which++)
940 {
941 for (int each = 0; each <= 1; each++)
942 {
943 if (CGRectContainsPoint(keyRect[keyCode[which]][each], where))
944 {
945 hit = which;
946
947 *keybounds = keyRect[keyCode[which]][each];
948 offset->x = keybounds->origin.x + (keybounds->size.width - kIconSize) / 2.0f - where.x + 18.0f;
949 offset->y = keybounds->origin.y + (keybounds->size.height - kIconSize) / 2.0f - where.y + 18.0f;
950 }
951 }
952 }
953
954 return (hit);
955 }
956
KeyWindowEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)957 static pascal OSStatus KeyWindowEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
958 {
959 OSStatus err, result = eventNotHandledErr;
960 WindowRef tWindowRef = (WindowRef) inUserData;
961
962 switch (GetEventClass(inEvent))
963 {
964 case kEventClassWindow:
965 switch (GetEventKind(inEvent))
966 {
967 case kEventWindowClose:
968 QuitAppModalLoopForWindow(tWindowRef);
969 result = noErr;
970 }
971
972 break;
973
974 case kEventClassCommand:
975 switch (GetEventKind(inEvent))
976 {
977 HICommand tHICommand;
978
979 case kEventCommandUpdateStatus:
980 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
981 if (err == noErr && tHICommand.commandID == 'clos')
982 {
983 UpdateMenuCommandStatus(true);
984 result = noErr;
985 }
986
987 break;
988
989 case kEventCommandProcess:
990 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
991 if (err == noErr)
992 {
993 if (tHICommand.commandID == 'DFLT')
994 {
995 memcpy(keyCode, defaultKeys, sizeof(keyCode));
996 UpdateIconPlaceImage();
997 HIViewSetNeedsDisplay(customView, true);
998 result = noErr;
999 }
1000 }
1001 }
1002 }
1003
1004 return (result);
1005 }
1006
KeyLegendEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)1007 static pascal OSStatus KeyLegendEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
1008 {
1009 OSStatus err, result = eventNotHandledErr;
1010 HIViewRef view = (HIViewRef) inUserData;
1011
1012 switch (GetEventClass(inEvent))
1013 {
1014 case kEventClassControl:
1015 switch (GetEventKind(inEvent))
1016 {
1017 case kEventControlDraw:
1018 CGContextRef ctx;
1019
1020 err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(CGContextRef), NULL, &ctx);
1021 if (err == noErr)
1022 {
1023 HIViewID cid;
1024 HIRect bounds;
1025
1026 GetControlID(view, &cid);
1027 HIViewGetBounds(view, &bounds);
1028 CGContextTranslateCTM(ctx, 0, bounds.size.height);
1029 CGContextScaleCTM(ctx, 1.0f, -1.0f);
1030 CGContextDrawImage(ctx, CGRectMake(0, 0, kIconSize, kIconSize), macIconImage[macLegendIconIndex + cid.id]);
1031
1032 result = noErr;
1033 }
1034 }
1035 }
1036
1037 return (result);
1038 }
1039
KeyLayoutEventHandler(EventHandlerCallRef inHandlerRef,EventRef inEvent,void * inUserData)1040 static pascal OSStatus KeyLayoutEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
1041 {
1042 OSStatus err, result = eventNotHandledErr;
1043 CustomViewData *data = (CustomViewData *) inUserData;
1044
1045 switch (GetEventClass(inEvent))
1046 {
1047 case kEventClassHIObject:
1048 switch (GetEventKind(inEvent))
1049 {
1050 case kEventHIObjectConstruct:
1051 data = (CustomViewData *) calloc(1, sizeof(CustomViewData));
1052 if (data)
1053 {
1054 HIViewRef epView;
1055
1056 err = GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView);
1057 if (err == noErr)
1058 {
1059 data->view = epView;
1060 result = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(data), &data);
1061 }
1062 }
1063
1064 break;
1065
1066 case kEventHIObjectDestruct:
1067 if (data)
1068 free(data);
1069
1070 result = noErr;
1071 break;
1072
1073 case kEventHIObjectInitialize:
1074 result = CallNextEventHandler(inHandlerRef, inEvent);
1075 }
1076
1077 break;
1078
1079 case kEventClassControl:
1080 switch (GetEventKind(inEvent))
1081 {
1082 case kEventControlDraw:
1083 CGContextRef ctx;
1084
1085 err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(ctx), NULL, &ctx);
1086 if (err == noErr)
1087 {
1088 HIRect bounds, srcRect, dstRect;
1089
1090 HIViewGetBounds(customView, &bounds);
1091 srcRect = CGRectMake(0, 0, kKeyLayoutWidth, kKeyLayoutHeight);
1092
1093 dstRect.origin.x = (float) (((int) bounds.size.width - kKeyLayoutWidth ) >> 1);
1094 dstRect.origin.y = (float) (((int) bounds.size.height - kKeyLayoutHeight) >> 1);
1095 dstRect.size.width = (float) kKeyLayoutWidth;
1096 dstRect.size.height = (float) kKeyLayoutHeight;
1097
1098 DrawSubCGImage(ctx, iconPlaceImage, srcRect, dstRect);
1099 if (keyInDrag && (dragKey != -1))
1100 DrawDraggedIcon(ctx, dragKey, &dragKeyOfs);
1101 }
1102
1103 result = noErr;
1104 break;
1105
1106 case kEventControlHitTest:
1107 ControlPartCode part;
1108
1109 part = kControlButtonPart;
1110 result = SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(part), &part);
1111
1112 break;
1113
1114 case kEventControlTrack:
1115 MouseTrackingResult trackResult;
1116 WindowRef window;
1117 HIViewRef contentView;
1118 HIPoint hipt;
1119
1120 dragKey = -1;
1121 dragKeyOfs = CGPointMake(0.0f, 0.0f);
1122 dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
1123 mousePos = CGPointMake(0.0f, 0.0f);
1124 trackResult = kMouseTrackingMouseDown;
1125
1126 window = GetControlOwner(customView);
1127 HIViewFindByID(HIViewGetRoot(window), kHIViewWindowContentID, &contentView);
1128
1129 #ifdef MAC_TIGER_PANTHER_SUPPORT
1130 CGrafPtr oldPort;
1131 Point qdpt;
1132 Boolean portChanged = false;
1133
1134 if (systemVersion < 0x1050)
1135 portChanged = QDSwapPort(GetWindowPort(window), &oldPort);
1136 #endif
1137
1138 err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(hipt), NULL, &hipt);
1139 if (err == noErr)
1140 {
1141 hipt.x -= ofsx;
1142 hipt.y -= ofsy;
1143
1144 dragKey = FindHitKey(hipt, &dragKeyRect, &dragKeyOfs);
1145 if (dragKey != -1)
1146 {
1147 keyInDrag = true;
1148
1149 while (trackResult != kMouseTrackingMouseUp)
1150 {
1151 if (CGPointEqualToPoint(mousePos, hipt) == 0)
1152 {
1153 mousePos = hipt;
1154 HIViewSetNeedsDisplay(customView, true);
1155 }
1156
1157 if (systemVersion >= 0x1050)
1158 {
1159 err = HIViewTrackMouseLocation(customView, 0, kEventDurationForever, 0, NULL, &hipt, NULL, NULL, &trackResult);
1160 hipt.x -= ofsx;
1161 hipt.y -= ofsy;
1162 }
1163 #ifdef MAC_TIGER_PANTHER_SUPPORT
1164 else
1165 {
1166 TrackMouseLocation(NULL, &qdpt, &trackResult);
1167 hipt.x = qdpt.h - ofsx;
1168 hipt.y = qdpt.v - ofsy;
1169 HIViewConvertPoint(&hipt, contentView, customView);
1170 }
1171 #endif
1172 }
1173
1174 keyInDrag = false;
1175
1176 for (int code = 0; code < 0x80; code++)
1177 {
1178 for (int each = 0; each <= 1; each++)
1179 {
1180 if (CGRectContainsPoint(keyRect[code][each], mousePos))
1181 {
1182 if (!KeyCodeInUse(code))
1183 {
1184 keyCode[dragKey] = code;
1185 UpdateIconPlaceImage();
1186 }
1187 }
1188 }
1189 }
1190
1191 HIViewSetNeedsDisplay(customView, true);
1192 }
1193 }
1194
1195 #ifdef MAC_TIGER_PANTHER_SUPPORT
1196 if (systemVersion < 0x1050)
1197 {
1198 if (portChanged)
1199 QDSwapPort(oldPort, NULL);
1200 }
1201 #endif
1202
1203 result = noErr;
1204 }
1205 }
1206
1207 return (result);
1208 }
1209