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