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 <IOKit/hid/IOHIDUsageTables.h>
198 #include "HID_Utilities_External.h"
199
200 #include "mac-prefix.h"
201 #include "mac-dialog.h"
202 #include "mac-os.h"
203 #include "mac-joypad.h"
204
205 #define kUp(i) (i * 4)
206 #define kDn(i) (i * 4 + 1)
207 #define kLf(i) (i * 4 + 2)
208 #define kRt(i) (i * 4 + 3)
209
210 #define kPadElemTypeNone 0
211 #define kPadElemTypeHat4 1
212 #define kPadElemTypeHat8 2
213 #define kPadElemTypeAxis 3
214 #define kPadElemTypeButton 4
215 #define kPadElemTypeOtherHat4 5
216 #define kPadElemTypeOtherHat8 6
217
218 #define kPadXAxis 1
219 #define kPadYAxis 0
220 #define kPadHat 0
221
222 #define kMaskUp 0x0800
223 #define kMaskDn 0x0400
224 #define kMaskLf 0x0200
225 #define kMaskRt 0x0100
226
227 typedef hu_device_t *pRecDevice;
228 typedef hu_element_t *pRecElement;
229
230 typedef struct actionStruct
231 {
232 pRecDevice fDevice;
233 pRecElement fElement;
234 long fValue;
235 long fOldValue;
236 } actionRec, *actionPtr;
237
238 typedef struct padDirectionInfo
239 {
240 int type;
241 pRecDevice device [2];
242 pRecElement element[2];
243 long max [2];
244 long maxmid [2];
245 long mid [2];
246 long midmin [2];
247 long min [2];
248 } directionInfo;
249
250 static actionRec gActionRecs[kNeedCount];
251 static directionInfo gDirectionInfo[MAC_MAX_PLAYERS];
252 static int gDirectionHint[MAC_MAX_PLAYERS];
253
254 static const HIViewID gControlIDs[kNeedCount] =
255 {
256 { '1_Up', 0 },
257 { '1_Dn', 0 },
258 { '1_Lf', 0 },
259 { '1_Rt', 0 },
260
261 { '2_Up', 0 },
262 { '2_Dn', 0 },
263 { '2_Lf', 0 },
264 { '2_Rt', 0 },
265
266 { '3_Up', 0 },
267 { '3_Dn', 0 },
268 { '3_Lf', 0 },
269 { '3_Rt', 0 },
270
271 { '4_Up', 0 },
272 { '4_Dn', 0 },
273 { '4_Lf', 0 },
274 { '4_Rt', 0 },
275
276 { '5_Up', 0 },
277 { '5_Dn', 0 },
278 { '5_Lf', 0 },
279 { '5_Rt', 0 },
280
281 { '6_Up', 0 },
282 { '6_Dn', 0 },
283 { '6_Lf', 0 },
284 { '6_Rt', 0 },
285
286 { '7_Up', 0 },
287 { '7_Dn', 0 },
288 { '7_Lf', 0 },
289 { '7_Rt', 0 },
290
291 { '8_Up', 0 },
292 { '8_Dn', 0 },
293 { '8_Lf', 0 },
294 { '8_Rt', 0 },
295
296 { '1__B', 0 },
297 { '1__A', 0 },
298 { '1__X', 0 },
299 { '1__Y', 0 },
300 { '1__L', 0 },
301 { '1__R', 0 },
302 { '1Sel', 0 },
303 { '1Srt', 0 },
304
305 { '2__B', 0 },
306 { '2__A', 0 },
307 { '2__X', 0 },
308 { '2__Y', 0 },
309 { '2__L', 0 },
310 { '2__R', 0 },
311 { '2Sel', 0 },
312 { '2Srt', 0 },
313
314 { '3__B', 0 },
315 { '3__A', 0 },
316 { '3__X', 0 },
317 { '3__Y', 0 },
318 { '3__L', 0 },
319 { '3__R', 0 },
320 { '3Sel', 0 },
321 { '3Srt', 0 },
322
323 { '4__B', 0 },
324 { '4__A', 0 },
325 { '4__X', 0 },
326 { '4__Y', 0 },
327 { '4__L', 0 },
328 { '4__R', 0 },
329 { '4Sel', 0 },
330 { '4Srt', 0 },
331
332 { '5__B', 0 },
333 { '5__A', 0 },
334 { '5__X', 0 },
335 { '5__Y', 0 },
336 { '5__L', 0 },
337 { '5__R', 0 },
338 { '5Sel', 0 },
339 { '5Srt', 0 },
340
341 { '6__B', 0 },
342 { '6__A', 0 },
343 { '6__X', 0 },
344 { '6__Y', 0 },
345 { '6__L', 0 },
346 { '6__R', 0 },
347 { '6Sel', 0 },
348 { '6Srt', 0 },
349
350 { '7__B', 0 },
351 { '7__A', 0 },
352 { '7__X', 0 },
353 { '7__Y', 0 },
354 { '7__L', 0 },
355 { '7__R', 0 },
356 { '7Sel', 0 },
357 { '7Srt', 0 },
358
359 { '8__B', 0 },
360 { '8__A', 0 },
361 { '8__X', 0 },
362 { '8__Y', 0 },
363 { '8__L', 0 },
364 { '8__R', 0 },
365 { '8Sel', 0 },
366 { '8Srt', 0 },
367
368 { '__FF', 0 },
369 { '_Frz', 0 },
370 { '_DeF', 0 },
371 { '_Snp', 0 },
372 { '_Esc', 0 },
373 { '_SPC', 0 },
374 { 'MouL', 0 },
375 { 'MouR', 0 },
376 { 'ScoT', 0 },
377 { 'ScoP', 0 },
378 { 'ScoC', 0 },
379 { 'Ofsc', 0 },
380 { '__Fn', 0 },
381 { '_Alt', 0 },
382 { 'FFUp', 0 },
383 { 'FFDn', 0 },
384 { '__TC', 0 }
385 };
386
387 static char gNeeds[kNeedCount][64] =
388 {
389 "1P Up",
390 "1P Down",
391 "1P Left",
392 "1P Right",
393
394 "2P Up",
395 "2P Down",
396 "2P Left",
397 "2P Right",
398
399 "3P Up",
400 "3P Down",
401 "3P Left",
402 "3P Right",
403
404 "4P Up",
405 "4P Down",
406 "4P Left",
407 "4P Right",
408
409 "5P Up",
410 "5P Down",
411 "5P Left",
412 "5P Right",
413
414 "6P Up",
415 "6P Down",
416 "6P Left",
417 "6P Right",
418
419 "7P Up",
420 "7P Down",
421 "7P Left",
422 "7P Right",
423
424 "8P Up",
425 "8P Down",
426 "8P Left",
427 "8P Right",
428
429 "1P B Button",
430 "1P A Button",
431 "1P X Button",
432 "1P Y Button",
433 "1P L Button",
434 "1P R Button",
435 "1P Select",
436 "1P Start",
437
438 "2P B Button",
439 "2P A Button",
440 "2P X Button",
441 "2P Y Button",
442 "2P L Button",
443 "2P R Button",
444 "2P Select",
445 "2P Start",
446
447 "3P B Button",
448 "3P A Button",
449 "3P X Button",
450 "3P Y Button",
451 "3P L Button",
452 "3P R Button",
453 "3P Select",
454 "3P Start",
455
456 "4P B Button",
457 "4P A Button",
458 "4P X Button",
459 "4P Y Button",
460 "4P L Button",
461 "4P R Button",
462 "4P Select",
463 "4P Start",
464
465 "5P B Button",
466 "5P A Button",
467 "5P X Button",
468 "5P Y Button",
469 "5P L Button",
470 "5P R Button",
471 "5P Select",
472 "5P Start",
473
474 "6P B Button",
475 "6P A Button",
476 "6P X Button",
477 "6P Y Button",
478 "6P L Button",
479 "6P R Button",
480 "6P Select",
481 "6P Start",
482
483 "7P B Button",
484 "7P A Button",
485 "7P X Button",
486 "7P Y Button",
487 "7P L Button",
488 "7P R Button",
489 "7P Select",
490 "7P Start",
491
492 "8P B Button",
493 "8P A Button",
494 "8P X Button",
495 "8P Y Button",
496 "8P L Button",
497 "8P R Button",
498 "8P Select",
499 "8P Start",
500
501 "Fast Forward",
502 "Freeze Game",
503 "Defrost Game",
504 "Screenshot",
505 "Break",
506 "Save SPC",
507 "Mouse Left",
508 "Mouse Right",
509 "Scope Turbo",
510 "Scope Pause",
511 "Scope Cursor",
512 "Offscreen",
513 "Fn Modifier",
514 "Alt Modifier",
515 "Turbo Speed Up",
516 "Turbo Speed Down",
517 "Turbo Control Modifier"
518 };
519
520 static int gIconNumber[kNeedCount] =
521 {
522 0,
523 1,
524 2,
525 3,
526
527 12,
528 13,
529 14,
530 15,
531
532 24,
533 25,
534 26,
535 27,
536
537 36,
538 37,
539 38,
540 39,
541
542 48,
543 49,
544 50,
545 51,
546
547 60,
548 61,
549 62,
550 63,
551
552 72,
553 73,
554 74,
555 75,
556
557 84,
558 85,
559 86,
560 87,
561
562 5,
563 7,
564 6,
565 4,
566 8,
567 9,
568 11,
569 10,
570
571 17,
572 19,
573 18,
574 16,
575 20,
576 21,
577 23,
578 22,
579
580 29,
581 31,
582 30,
583 28,
584 32,
585 33,
586 35,
587 34,
588
589 41,
590 43,
591 42,
592 40,
593 44,
594 45,
595 47,
596 46,
597
598 53,
599 55,
600 54,
601 52,
602 56,
603 57,
604 59,
605 58,
606
607 65,
608 67,
609 66,
610 64,
611 68,
612 69,
613 71,
614 70,
615
616 77,
617 79,
618 78,
619 76,
620 80,
621 81,
622 83,
623 82,
624
625 89,
626 91,
627 90,
628 88,
629 92,
630 93,
631 95,
632 94,
633
634 101,
635 102,
636 103,
637 104,
638 114,
639 105,
640 116,
641 117,
642 106,
643 107,
644 108,
645 109,
646 110,
647 111,
648 112,
649 113,
650 115
651 };
652
653 static void JoypadSetDirectionInfo (void);
654 static pascal void IdleTimer (EventLoopTimerRef, void *);
655 static pascal OSStatus ControllerEventHandler (EventHandlerCallRef, EventRef, void *);
656
657
SaveControllerSettings(void)658 void SaveControllerSettings (void)
659 {
660 CFStringRef keyCFStringRef;
661 Boolean syncFlag;
662
663 JoypadSetDirectionInfo();
664
665 for (int a = 0; a < kNeedCount; a++)
666 {
667 char needCStr[64], num[10];
668
669 strcpy(needCStr, gNeeds[a]);
670 if (padSetting > 1)
671 {
672 sprintf(num, "_%d", padSetting);
673 strcat(needCStr, num);
674 }
675
676 keyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s"), needCStr);
677 if (keyCFStringRef)
678 {
679 if (gActionRecs[a].fDevice && gActionRecs[a].fElement)
680 syncFlag = HIDSaveElementPref(keyCFStringRef, kCFPreferencesCurrentApplication, gActionRecs[a].fDevice, gActionRecs[a].fElement);
681 else
682 CFPreferencesSetAppValue(keyCFStringRef, NULL, kCFPreferencesCurrentApplication);
683
684 CFRelease(keyCFStringRef);
685 }
686 }
687
688 for (int a = 0; a < MAC_MAX_PLAYERS; a++)
689 {
690 keyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DirectionHint_%d_%d"), a, padSetting);
691 if (keyCFStringRef)
692 {
693 CFNumberRef numRef;
694 CFIndex v;
695
696 v = (CFIndex) gDirectionHint[a];
697 numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &v);
698 if (numRef)
699 {
700 CFPreferencesSetAppValue(keyCFStringRef, numRef, kCFPreferencesCurrentApplication);
701 CFRelease(numRef);
702 }
703
704 CFRelease(keyCFStringRef);
705 }
706 }
707
708 CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
709 }
710
LoadControllerSettings(void)711 void LoadControllerSettings (void)
712 {
713 CFStringRef keyCFStringRef;
714
715 for (int a = 0; a < kNeedCount; a++)
716 {
717 pRecDevice pDevice = NULL;
718 pRecElement pElement = NULL;
719 Boolean r = false;
720 char needCStr[64], num[10];
721
722 strcpy(needCStr, gNeeds[a]);
723 if (padSetting > 1)
724 {
725 sprintf(num, "_%d", padSetting);
726 strcat(needCStr, num);
727 }
728
729 keyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s"), needCStr);
730 if (keyCFStringRef)
731 {
732 r = HIDRestoreElementPref(keyCFStringRef, kCFPreferencesCurrentApplication, &pDevice, &pElement);
733 if (r && pDevice && pElement)
734 {
735 gActionRecs[a].fDevice = pDevice;
736 gActionRecs[a].fElement = pElement;
737 }
738 else
739 {
740 gActionRecs[a].fDevice = NULL;
741 gActionRecs[a].fElement = NULL;
742 }
743
744 CFRelease(keyCFStringRef);
745 }
746 }
747
748 for (int a = 0; a < MAC_MAX_PLAYERS; a++)
749 {
750 keyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DirectionHint_%d_%d"), a, padSetting);
751 if (keyCFStringRef)
752 {
753 Boolean r;
754
755 gDirectionHint[a] = (int) CFPreferencesGetAppIntegerValue(keyCFStringRef, kCFPreferencesCurrentApplication, &r);
756 if (!r)
757 gDirectionHint[a] = kPadElemTypeNone;
758
759 CFRelease(keyCFStringRef);
760 }
761 else
762 gDirectionHint[a] = kPadElemTypeNone;
763 }
764
765 JoypadSetDirectionInfo();
766 }
767
ControllerEventHandler(EventHandlerCallRef inHandlerCallRef,EventRef inEvent,void * inUserData)768 static pascal OSStatus ControllerEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
769 {
770 OSStatus err, result = eventNotHandledErr;
771 WindowRef tWindowRef;
772
773 tWindowRef = (WindowRef) inUserData;
774
775 switch (GetEventClass(inEvent))
776 {
777 case kEventClassWindow:
778 switch (GetEventKind(inEvent))
779 {
780 case kEventWindowClose:
781 QuitAppModalLoopForWindow(tWindowRef);
782 result = noErr;
783 break;
784 }
785
786 break;
787
788 case kEventClassCommand:
789 switch (GetEventKind(inEvent))
790 {
791 HICommand tHICommand;
792
793 case kEventCommandUpdateStatus:
794 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
795 if (err == noErr && tHICommand.commandID == 'clos')
796 {
797 UpdateMenuCommandStatus(true);
798 result = noErr;
799 }
800
801 break;
802
803 case kEventCommandProcess:
804 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
805 if (err == noErr)
806 {
807 if (tHICommand.commandID == 'CLRa')
808 {
809 ClearPadSetting();
810 result = noErr;
811 }
812 else
813 {
814 SInt32 command = -1, count;
815
816 for (count = 0; count < kNeedCount; count++)
817 if (tHICommand.commandID == gControlIDs[count].signature)
818 command = count;
819
820 if (command >= 0)
821 {
822 pRecDevice pDevice;
823 pRecElement pElement;
824
825 FlushEventQueue(GetCurrentEventQueue());
826
827 if (HIDConfigureAction(&pDevice, &pElement, 2.5f))
828 {
829 if (command < MAC_MAX_PLAYERS * 4) // Direction
830 {
831 int i = command >> 2; // Player
832 long curv = HIDGetElementValue(pDevice, pElement);
833
834 if (pElement->usage == kHIDUsage_GD_Hatswitch) // Hat Switch
835 {
836 gActionRecs[kUp(i)].fDevice = gActionRecs[kDn(i)].fDevice = gActionRecs[kLf(i)].fDevice = gActionRecs[kRt(i)].fDevice = pDevice;
837 gActionRecs[kUp(i)].fElement = gActionRecs[kDn(i)].fElement = gActionRecs[kLf(i)].fElement = gActionRecs[kRt(i)].fElement = pElement;
838
839 if (pDevice->vendorID == 1103) // Thrustmaster
840 gDirectionInfo[i].type = (pElement->max > 4) ? kPadElemTypeOtherHat8 : kPadElemTypeOtherHat4;
841 else
842 {
843 if (pElement->max > 4)
844 {
845 if (((command % 4 == 0) && (curv == 0)) || // Up : 0
846 ((command % 4 == 1) && (curv == 4)) || // Down : 4
847 ((command % 4 == 2) && (curv == 6)) || // Left : 6
848 ((command % 4 == 3) && (curv == 2))) // Right : 2
849 gDirectionInfo[i].type = kPadElemTypeOtherHat8;
850 else
851 gDirectionInfo[i].type = kPadElemTypeHat8;
852 }
853 else
854 {
855 if (((command % 4 == 0) && (curv == 0)) || // Up : 0
856 ((command % 4 == 1) && (curv == 2)) || // Down : 2
857 ((command % 4 == 2) && (curv == 3)) || // Left : 3
858 ((command % 4 == 3) && (curv == 1))) // Right : 1
859 gDirectionInfo[i].type = kPadElemTypeOtherHat4;
860 else
861 gDirectionInfo[i].type = kPadElemTypeHat4;
862 }
863 }
864
865 gDirectionInfo[i].device [kPadHat] = pDevice;
866 gDirectionInfo[i].element[kPadHat] = pElement;
867 gDirectionInfo[i].max [kPadHat] = pElement->max;
868 gDirectionInfo[i].min [kPadHat] = pElement->min;
869 }
870 else
871 if (pElement->max - pElement->min > 1) // Axis (maybe)
872 {
873 if ((command % 4 == 0) || (command % 4 == 1)) // Up or Dn
874 {
875 gActionRecs[kUp(i)].fDevice = gActionRecs[kDn(i)].fDevice = pDevice;
876 gActionRecs[kUp(i)].fElement = gActionRecs[kDn(i)].fElement = pElement;
877
878 gDirectionInfo[i].type = kPadElemTypeAxis;
879 gDirectionInfo[i].device [kPadYAxis] = pDevice;
880 gDirectionInfo[i].element[kPadYAxis] = pElement;
881 gDirectionInfo[i].max [kPadYAxis] = pElement->max;
882 gDirectionInfo[i].min [kPadYAxis] = pElement->min;
883 gDirectionInfo[i].mid [kPadYAxis] = (gDirectionInfo[i].max[kPadYAxis] + gDirectionInfo[i].min[kPadYAxis]) >> 1;
884 gDirectionInfo[i].maxmid [kPadYAxis] = (gDirectionInfo[i].max[kPadYAxis] + gDirectionInfo[i].mid[kPadYAxis]) >> 1;
885 gDirectionInfo[i].midmin [kPadYAxis] = (gDirectionInfo[i].mid[kPadYAxis] + gDirectionInfo[i].min[kPadYAxis]) >> 1;
886 }
887 else // Lf or Rt
888 {
889 gActionRecs[kLf(i)].fDevice = gActionRecs[kRt(i)].fDevice = pDevice;
890 gActionRecs[kLf(i)].fElement = gActionRecs[kRt(i)].fElement = pElement;
891
892 gDirectionInfo[i].type = kPadElemTypeAxis;
893 gDirectionInfo[i].device [kPadXAxis] = pDevice;
894 gDirectionInfo[i].element[kPadXAxis] = pElement;
895 gDirectionInfo[i].max [kPadXAxis] = pElement->max;
896 gDirectionInfo[i].min [kPadXAxis] = pElement->min;
897 gDirectionInfo[i].mid [kPadXAxis] = (gDirectionInfo[i].max[kPadXAxis] + gDirectionInfo[i].min[kPadXAxis]) >> 1;
898 gDirectionInfo[i].maxmid [kPadXAxis] = (gDirectionInfo[i].max[kPadXAxis] + gDirectionInfo[i].mid[kPadXAxis]) >> 1;
899 gDirectionInfo[i].midmin [kPadXAxis] = (gDirectionInfo[i].mid[kPadXAxis] + gDirectionInfo[i].min[kPadXAxis]) >> 1;
900 }
901 }
902 else // Button (maybe)
903 {
904 gActionRecs[command].fDevice = pDevice;
905 gActionRecs[command].fElement = pElement;
906 gDirectionInfo[i].type = kPadElemTypeButton;
907 }
908
909 gDirectionHint[i] = gDirectionInfo[i].type;
910 }
911 else
912 {
913 gActionRecs[command].fDevice = pDevice;
914 gActionRecs[command].fElement = pElement;
915 }
916 }
917 else
918 {
919 if (command < MAC_MAX_PLAYERS * 4) // Direction
920 {
921 int i = command >> 2; // Player
922
923 gActionRecs[kUp(i)].fDevice = gActionRecs[kDn(i)].fDevice = gActionRecs[kLf(i)].fDevice = gActionRecs[kRt(i)].fDevice = NULL;
924 gActionRecs[kUp(i)].fElement = gActionRecs[kDn(i)].fElement = gActionRecs[kLf(i)].fElement = gActionRecs[kRt(i)].fElement = NULL;
925
926 gDirectionInfo[i].type = gDirectionHint[i] = kPadElemTypeNone;
927 gDirectionInfo[i].device [0] = gDirectionInfo[i].device [1] = NULL;
928 gDirectionInfo[i].element[0] = gDirectionInfo[i].element[1] = NULL;
929 }
930 else
931 {
932 gActionRecs[command].fDevice = NULL;
933 gActionRecs[command].fElement = NULL;
934 }
935 }
936
937 gActionRecs[command].fValue = 0;
938 gActionRecs[command].fOldValue = -2;
939
940 FlushEventQueue(GetCurrentEventQueue());
941
942 result = noErr;
943 }
944 }
945 }
946
947 break;
948 }
949
950 break;
951 }
952
953 return (result);
954 }
955
IdleTimer(EventLoopTimerRef inTimer,void * userData)956 static pascal void IdleTimer (EventLoopTimerRef inTimer, void *userData)
957 {
958 static uint32 old[MAC_MAX_PLAYERS] = { ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0 };
959
960 HIViewRef ctl, root;
961 uint32 pad[MAC_MAX_PLAYERS];
962
963 root = HIViewGetRoot((WindowRef) userData);
964
965 for (int i = 0; i < MAC_MAX_PLAYERS; i++)
966 {
967 pad[i] = 0;
968 JoypadScanDirection(i, &(pad[i]));
969
970 if (old[i] != pad[i])
971 {
972 old[i] = pad[i];
973
974 HIViewFindByID(root, gControlIDs[kUp(i)], &ctl);
975 SetControl32BitValue(ctl, (pad[i] & kMaskUp) ? 1 : 0);
976 HIViewFindByID(root, gControlIDs[kDn(i)], &ctl);
977 SetControl32BitValue(ctl, (pad[i] & kMaskDn) ? 1 : 0);
978 HIViewFindByID(root, gControlIDs[kLf(i)], &ctl);
979 SetControl32BitValue(ctl, (pad[i] & kMaskLf) ? 1 : 0);
980 HIViewFindByID(root, gControlIDs[kRt(i)], &ctl);
981 SetControl32BitValue(ctl, (pad[i] & kMaskRt) ? 1 : 0);
982 }
983 }
984
985 for (int i = MAC_MAX_PLAYERS * 4; i < kNeedCount; i++)
986 {
987 gActionRecs[i].fValue = ISpKeyIsPressed(i);
988
989 if (gActionRecs[i].fOldValue != gActionRecs[i].fValue)
990 {
991 gActionRecs[i].fOldValue = gActionRecs[i].fValue;
992
993 HIViewFindByID(root, gControlIDs[i], &ctl);
994 SetControl32BitValue(ctl, (gActionRecs[i].fValue ? 1 : 0));
995 }
996 }
997 }
998
SetUpHID(void)999 void SetUpHID (void)
1000 {
1001 pRecDevice device;
1002
1003 HIDBuildDeviceList(NULL, NULL);
1004 device = HIDGetFirstDevice();
1005 if (!device)
1006 {
1007 hidExist = false;
1008 return;
1009 }
1010
1011 hidExist = true;
1012
1013 ClearPadSetting();
1014
1015 LoadControllerSettings();
1016 }
1017
ClearPadSetting(void)1018 void ClearPadSetting (void)
1019 {
1020 for (int i = 0; i < MAC_MAX_PLAYERS; i++)
1021 {
1022 gDirectionInfo[i].type = gDirectionHint[i] = kPadElemTypeNone;
1023 gDirectionInfo[i].device [0] = gDirectionInfo[i].device [1] = NULL;
1024 gDirectionInfo[i].element[0] = gDirectionInfo[i].element[1] = NULL;
1025 }
1026
1027 for (int i = 0; i < kNeedCount; i++)
1028 {
1029 gActionRecs[i].fDevice = NULL;
1030 gActionRecs[i].fElement = NULL;
1031 gActionRecs[i].fValue = 0;
1032 gActionRecs[i].fOldValue = -2;
1033 }
1034 }
1035
ReleaseHID(void)1036 void ReleaseHID (void)
1037 {
1038 if (hidExist)
1039 HIDReleaseDeviceList();
1040 }
1041
ConfigureHID(void)1042 void ConfigureHID (void)
1043 {
1044 OSStatus err;
1045 IBNibRef nibRef;
1046
1047 if (!hidExist)
1048 return;
1049
1050 err = CreateNibReference(kMacS9XCFString, &nibRef);
1051 if (err == noErr)
1052 {
1053 WindowRef tWindowRef;
1054
1055 err = CreateWindowFromNib(nibRef, CFSTR("Controllers"), &tWindowRef);
1056 if (err == noErr)
1057 {
1058 EventHandlerRef eref;
1059 EventLoopTimerRef tref;
1060 EventHandlerUPP eventUPP;
1061 EventLoopTimerUPP timerUPP;
1062 EventTypeSpec windowEvents[] = { { kEventClassCommand, kEventCommandProcess },
1063 { kEventClassCommand, kEventCommandUpdateStatus },
1064 { kEventClassWindow, kEventWindowClose } };
1065 HIViewRef ctl, root;
1066 HIViewID cid;
1067 CFStringRef str1, str2;
1068 ControlButtonContentInfo info;
1069
1070 LoadControllerSettings();
1071
1072 root = HIViewGetRoot(tWindowRef);
1073 cid.id = 0;
1074 cid.signature = 'PRES';
1075 HIViewFindByID(root, cid, &ctl);
1076 str1 = CFCopyLocalizedString(CFSTR("PresetNum"), "PresetNum");
1077 str2 = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, str1, padSetting);
1078 SetStaticTextCFString(ctl, str2, false);
1079 CFRelease(str2);
1080 CFRelease(str1);
1081
1082 if (systemVersion >= 0x1040)
1083 {
1084 info.contentType = kControlContentCGImageRef;
1085 for (int i = 0; i < kNeedCount; i++)
1086 {
1087 HIViewFindByID(root, gControlIDs[i], &ctl);
1088 info.u.imageRef = macIconImage[gIconNumber[i]];
1089 err = SetBevelButtonContentInfo(ctl, &info);
1090 }
1091 }
1092 #ifdef MAC_PANTHER_SUPPORT
1093 else
1094 {
1095 info.contentType = kControlContentIconRef;
1096 for (int i = 0; i < kNeedCount; i++)
1097 {
1098 HIViewFindByID(root, gControlIDs[i], &ctl);
1099 info.u.iconRef = macIconRef[gIconNumber[i]];
1100 err = SetBevelButtonContentInfo(ctl, &info);
1101 }
1102 }
1103 #endif
1104
1105 eventUPP = NewEventHandlerUPP(ControllerEventHandler);
1106 err = InstallWindowEventHandler(tWindowRef, eventUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) tWindowRef, &eref);
1107
1108 timerUPP = NewEventLoopTimerUPP(IdleTimer);
1109 err = InstallEventLoopTimer(GetCurrentEventLoop(), 0.0f, 0.1f, timerUPP, (void *) tWindowRef, &tref);
1110
1111 MoveWindowPosition(tWindowRef, kWindowControllers, false);
1112 ShowWindow(tWindowRef);
1113 err = RunAppModalLoopForWindow(tWindowRef);
1114 HideWindow(tWindowRef);
1115 SaveWindowPosition(tWindowRef, kWindowControllers);
1116
1117 err = RemoveEventLoopTimer(tref);
1118 DisposeEventLoopTimerUPP(timerUPP);
1119
1120 err = RemoveEventHandler(eref);
1121 DisposeEventHandlerUPP(eventUPP);
1122
1123 CFRelease(tWindowRef);
1124
1125 SaveControllerSettings();
1126 }
1127
1128 DisposeNibReference(nibRef);
1129 }
1130 }
1131
ISpKeyIsPressed(int needID)1132 long ISpKeyIsPressed (int needID)
1133 {
1134 return (gActionRecs[needID].fDevice ? HIDGetElementValue(gActionRecs[needID].fDevice, gActionRecs[needID].fElement) : 0);
1135 }
1136
JoypadScanDirection(int i,uint32 * pad)1137 void JoypadScanDirection (int i, uint32 *pad)
1138 {
1139 long state;
1140
1141 switch (gDirectionInfo[i].type)
1142 {
1143 case kPadElemTypeAxis: // Axis (maybe)
1144 if (gDirectionInfo[i].device[kPadYAxis]) // Y-Axis
1145 {
1146 state = HIDGetElementValue(gDirectionInfo[i].device[kPadYAxis], gDirectionInfo[i].element[kPadYAxis]);
1147 if (state >= gDirectionInfo[i].maxmid[kPadYAxis])
1148 *pad |= kMaskDn;
1149 else
1150 if (state <= gDirectionInfo[i].midmin[kPadYAxis])
1151 *pad |= kMaskUp;
1152 }
1153
1154 if (gDirectionInfo[i].device[kPadXAxis]) // X-Axis
1155 {
1156 state = HIDGetElementValue(gDirectionInfo[i].device[kPadXAxis], gDirectionInfo[i].element[kPadXAxis]);
1157 if (state >= gDirectionInfo[i].maxmid[kPadXAxis])
1158 *pad |= kMaskRt;
1159 else
1160 if (state <= gDirectionInfo[i].midmin[kPadXAxis])
1161 *pad |= kMaskLf;
1162 }
1163
1164 break;
1165
1166 case kPadElemTypeHat8: // Hat Switch (8 Directions)
1167 if (gDirectionInfo[i].device[kPadHat])
1168 {
1169 state = HIDGetElementValue(gDirectionInfo[i].device[kPadHat], gDirectionInfo[i].element[kPadHat]);
1170 switch (state)
1171 {
1172 case 1: *pad |= kMaskUp ; break;
1173 case 2: *pad |= (kMaskUp | kMaskRt); break;
1174 case 3: *pad |= kMaskRt ; break;
1175 case 4: *pad |= (kMaskRt | kMaskDn); break;
1176 case 5: *pad |= kMaskDn ; break;
1177 case 6: *pad |= (kMaskDn | kMaskLf); break;
1178 case 7: *pad |= kMaskLf ; break;
1179 case 8: *pad |= (kMaskLf | kMaskUp); break;
1180 }
1181 }
1182
1183 break;
1184
1185 case kPadElemTypeHat4: // Hat Switch (4 Directions)
1186 if (gDirectionInfo[i].device[kPadHat])
1187 {
1188 state = HIDGetElementValue(gDirectionInfo[i].device[kPadHat], gDirectionInfo[i].element[kPadHat]);
1189 switch (state)
1190 {
1191 case 1: *pad |= kMaskUp; break;
1192 case 2: *pad |= kMaskRt; break;
1193 case 3: *pad |= kMaskDn; break;
1194 case 4: *pad |= kMaskLf; break;
1195 }
1196 }
1197
1198 break;
1199
1200 case kPadElemTypeOtherHat8: // Hat Switch (8 Directions, Start at 0)
1201 if (gDirectionInfo[i].device[kPadHat])
1202 {
1203 state = HIDGetElementValue(gDirectionInfo[i].device[kPadHat], gDirectionInfo[i].element[kPadHat]);
1204 switch (state)
1205 {
1206 case 0: *pad |= kMaskUp ; break;
1207 case 1: *pad |= (kMaskUp | kMaskRt); break;
1208 case 2: *pad |= kMaskRt ; break;
1209 case 3: *pad |= (kMaskRt | kMaskDn); break;
1210 case 4: *pad |= kMaskDn ; break;
1211 case 5: *pad |= (kMaskDn | kMaskLf); break;
1212 case 6: *pad |= kMaskLf ; break;
1213 case 7: *pad |= (kMaskLf | kMaskUp); break;
1214 }
1215 }
1216
1217 break;
1218
1219 case kPadElemTypeOtherHat4: // Hat Switch (4 Directions, Start at 0)
1220 if (gDirectionInfo[i].device[kPadHat])
1221 {
1222 state = HIDGetElementValue(gDirectionInfo[i].device[kPadHat], gDirectionInfo[i].element[kPadHat]);
1223 switch (state)
1224 {
1225 case 0: *pad |= kMaskUp; break;
1226 case 1: *pad |= kMaskRt; break;
1227 case 2: *pad |= kMaskDn; break;
1228 case 3: *pad |= kMaskLf; break;
1229 }
1230 }
1231
1232 break;
1233
1234 case kPadElemTypeButton: // Button (maybe)
1235 if (gActionRecs[kUp(i)].fDevice && HIDGetElementValue(gActionRecs[kUp(i)].fDevice, gActionRecs[kUp(i)].fElement))
1236 *pad |= kMaskUp;
1237 if (gActionRecs[kDn(i)].fDevice && HIDGetElementValue(gActionRecs[kDn(i)].fDevice, gActionRecs[kDn(i)].fElement))
1238 *pad |= kMaskDn;
1239 if (gActionRecs[kLf(i)].fDevice && HIDGetElementValue(gActionRecs[kLf(i)].fDevice, gActionRecs[kLf(i)].fElement))
1240 *pad |= kMaskLf;
1241 if (gActionRecs[kRt(i)].fDevice && HIDGetElementValue(gActionRecs[kRt(i)].fDevice, gActionRecs[kRt(i)].fElement))
1242 *pad |= kMaskRt;
1243
1244 break;
1245 }
1246 }
1247
JoypadSetDirectionInfo(void)1248 static void JoypadSetDirectionInfo (void)
1249 {
1250 for (int i = 0; i < MAC_MAX_PLAYERS; i++)
1251 {
1252 if (((gActionRecs[kUp(i)].fDevice) && (gActionRecs[kUp(i)].fElement)) &&
1253 ((gActionRecs[kDn(i)].fDevice) && (gActionRecs[kDn(i)].fElement)) &&
1254 ((gActionRecs[kLf(i)].fDevice) && (gActionRecs[kLf(i)].fElement)) &&
1255 ((gActionRecs[kRt(i)].fDevice) && (gActionRecs[kRt(i)].fElement)))
1256 {
1257 if ((gActionRecs[kUp(i)].fDevice == gActionRecs[kDn(i)].fDevice) &&
1258 (gActionRecs[kDn(i)].fDevice == gActionRecs[kLf(i)].fDevice) &&
1259 (gActionRecs[kLf(i)].fDevice == gActionRecs[kRt(i)].fDevice) &&
1260 (gActionRecs[kUp(i)].fElement == gActionRecs[kDn(i)].fElement) &&
1261 (gActionRecs[kDn(i)].fElement == gActionRecs[kLf(i)].fElement) &&
1262 (gActionRecs[kLf(i)].fElement == gActionRecs[kRt(i)].fElement) &&
1263 (gActionRecs[kUp(i)].fElement->usage == kHIDUsage_GD_Hatswitch)) // Hat Switch
1264 {
1265 if ((gDirectionHint[i] == kPadElemTypeHat8) || (gDirectionHint[i] == kPadElemTypeOtherHat8) ||
1266 (gDirectionHint[i] == kPadElemTypeHat4) || (gDirectionHint[i] == kPadElemTypeOtherHat4))
1267 gDirectionInfo[i].type = gDirectionHint[i];
1268 else // Assuming...
1269 {
1270 if ((gActionRecs[kUp(i)].fDevice->vendorID == 1103) || (gActionRecs[kUp(i)].fElement->min == 0))
1271 gDirectionInfo[i].type = (gActionRecs[kUp(i)].fElement->max > 4) ? kPadElemTypeOtherHat8 : kPadElemTypeOtherHat4;
1272 else
1273 gDirectionInfo[i].type = (gActionRecs[kUp(i)].fElement->max > 4) ? kPadElemTypeHat8 : kPadElemTypeHat4;
1274
1275 gDirectionHint[i] = gDirectionInfo[i].type;
1276 }
1277
1278 gDirectionInfo[i].device [kPadHat] = gActionRecs[kUp(i)].fDevice;
1279 gDirectionInfo[i].element[kPadHat] = gActionRecs[kUp(i)].fElement;
1280 gDirectionInfo[i].max [kPadHat] = gActionRecs[kUp(i)].fElement->max;
1281 gDirectionInfo[i].min [kPadHat] = gActionRecs[kUp(i)].fElement->min;
1282 }
1283 else
1284 if ((gActionRecs[kUp(i)].fDevice == gActionRecs[kDn(i)].fDevice) &&
1285 (gActionRecs[kLf(i)].fDevice == gActionRecs[kRt(i)].fDevice) &&
1286 (gActionRecs[kUp(i)].fElement == gActionRecs[kDn(i)].fElement) &&
1287 (gActionRecs[kLf(i)].fElement == gActionRecs[kRt(i)].fElement) &&
1288 (gActionRecs[kUp(i)].fElement->max - gActionRecs[kUp(i)].fElement->min > 1) &&
1289 (gActionRecs[kLf(i)].fElement->max - gActionRecs[kLf(i)].fElement->min > 1)) // Axis (maybe)
1290 {
1291 gDirectionInfo[i].type = gDirectionHint[i] = kPadElemTypeAxis;
1292
1293 gDirectionInfo[i].device [kPadYAxis] = gActionRecs[kUp(i)].fDevice;
1294 gDirectionInfo[i].element[kPadYAxis] = gActionRecs[kUp(i)].fElement;
1295 gDirectionInfo[i].max [kPadYAxis] = gActionRecs[kUp(i)].fElement->max;
1296 gDirectionInfo[i].min [kPadYAxis] = gActionRecs[kUp(i)].fElement->min;
1297 gDirectionInfo[i].mid [kPadYAxis] = (gDirectionInfo[i].max[kPadYAxis] + gDirectionInfo[i].min[kPadYAxis]) >> 1;
1298 gDirectionInfo[i].maxmid [kPadYAxis] = (gDirectionInfo[i].max[kPadYAxis] + gDirectionInfo[i].mid[kPadYAxis]) >> 1;
1299 gDirectionInfo[i].midmin [kPadYAxis] = (gDirectionInfo[i].mid[kPadYAxis] + gDirectionInfo[i].min[kPadYAxis]) >> 1;
1300
1301 gDirectionInfo[i].device [kPadXAxis] = gActionRecs[kLf(i)].fDevice;
1302 gDirectionInfo[i].element[kPadXAxis] = gActionRecs[kLf(i)].fElement;
1303 gDirectionInfo[i].max [kPadXAxis] = gActionRecs[kLf(i)].fElement->max;
1304 gDirectionInfo[i].min [kPadXAxis] = gActionRecs[kLf(i)].fElement->min;
1305 gDirectionInfo[i].mid [kPadXAxis] = (gDirectionInfo[i].max[kPadXAxis] + gDirectionInfo[i].min[kPadXAxis]) >> 1;
1306 gDirectionInfo[i].maxmid [kPadXAxis] = (gDirectionInfo[i].max[kPadXAxis] + gDirectionInfo[i].mid[kPadXAxis]) >> 1;
1307 gDirectionInfo[i].midmin [kPadXAxis] = (gDirectionInfo[i].mid[kPadXAxis] + gDirectionInfo[i].min[kPadXAxis]) >> 1;
1308 }
1309 else // Button (maybe)
1310 gDirectionInfo[i].type = gDirectionHint[i] = kPadElemTypeButton;
1311 }
1312 else
1313 {
1314 gActionRecs[kUp(i)].fDevice = gActionRecs[kDn(i)].fDevice = gActionRecs[kLf(i)].fDevice = gActionRecs[kRt(i)].fDevice = NULL;
1315 gActionRecs[kUp(i)].fElement = gActionRecs[kDn(i)].fElement = gActionRecs[kLf(i)].fElement = gActionRecs[kRt(i)].fElement = NULL;
1316
1317 gDirectionInfo[i].type = gDirectionHint[i] = kPadElemTypeNone;
1318 gDirectionInfo[i].device [0] = gDirectionInfo[i].device [1] = NULL;
1319 gDirectionInfo[i].element[0] = gDirectionInfo[i].element[1] = NULL;
1320 }
1321 }
1322 }
1323