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