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 #include <map>
8 #include <set>
9 #include <vector>
10 #include <string>
11 #include <algorithm>
12 #include <assert.h>
13 #include <ctype.h>
14 
15 #include "snes9x.h"
16 #include "memmap.h"
17 #include "apu/apu.h"
18 #include "snapshot.h"
19 #include "controls.h"
20 #include "crosshairs.h"
21 #include "movie.h"
22 #include "display.h"
23 #ifdef NETPLAY_SUPPORT
24 #include "netplay.h"
25 #endif
26 
27 using namespace	std;
28 
29 #define NONE					(-2)
30 #define MP5						(-1)
31 #define JOYPAD0					0
32 #define JOYPAD1					1
33 #define JOYPAD2					2
34 #define JOYPAD3					3
35 #define JOYPAD4					4
36 #define JOYPAD5					5
37 #define JOYPAD6					6
38 #define JOYPAD7					7
39 #define MOUSE0					8
40 #define MOUSE1					9
41 #define SUPERSCOPE				10
42 #define ONE_JUSTIFIER			11
43 #define TWO_JUSTIFIERS			12
44 #define MACSRIFLE				13
45 #define NUMCTLS					14 // This must be LAST
46 
47 #define POLL_ALL				NUMCTLS
48 
49 #define SUPERSCOPE_FIRE			0x80
50 #define SUPERSCOPE_CURSOR		0x40
51 #define SUPERSCOPE_TURBO		0x20
52 #define SUPERSCOPE_PAUSE		0x10
53 #define SUPERSCOPE_OFFSCREEN	0x02
54 
55 #define JUSTIFIER_TRIGGER		0x80
56 #define JUSTIFIER_START			0x20
57 #define JUSTIFIER_SELECT		0x08
58 
59 #define MACSRIFLE_TRIGGER		0x01
60 
61 #define MAP_UNKNOWN				(-1)
62 #define MAP_NONE				0
63 #define MAP_BUTTON				1
64 #define MAP_AXIS				2
65 #define MAP_POINTER				3
66 
67 #define FLAG_IOBIT0				(Memory.FillRAM[0x4213] & 0x40)
68 #define FLAG_IOBIT1				(Memory.FillRAM[0x4213] & 0x80)
69 #define FLAG_IOBIT(n)			((n) ? (FLAG_IOBIT1) : (FLAG_IOBIT0))
70 
71 bool8	pad_read = 0, pad_read_last = 0;
72 uint8	read_idx[2 /* ports */][2 /* per port */];
73 
74 struct exemulti
75 {
76 	int32				pos;
77 	bool8				data1;
78 	s9xcommand_t		*script;
79 };
80 
81 struct crosshair
82 {
83 	uint8				set;
84 	uint8				img;
85 	uint8				fg, bg;
86 };
87 
88 static struct
89 {
90 	int16				x, y;
91 	int16				V_adj;
92 	bool8				V_var;
93 	int16				H_adj;
94 	bool8				H_var;
95 	bool8				mapped;
96 }	pseudopointer[8];
97 
98 static struct
99 {
100 	uint16				buttons;
101 	uint16				turbos;
102 	uint16				toggleturbo;
103 	uint16				togglestick;
104 	uint8				turbo_ct;
105 }	joypad[8];
106 
107 static struct
108 {
109 	uint8				delta_x, delta_y;
110 	int16				old_x, old_y;
111 	int16				cur_x, cur_y;
112 	uint8				buttons;
113 	uint32				ID;
114 	struct crosshair	crosshair;
115 }	mouse[2];
116 
117 static struct
118 {
119 	int16				x, y;
120 	uint8				phys_buttons;
121 	uint8				next_buttons;
122 	uint8				read_buttons;
123 	uint32				ID;
124 	struct crosshair	crosshair;
125 }	superscope;
126 
127 static struct
128 {
129 	int16				x[2], y[2];
130 	uint8				buttons;
131 	bool8				offscreen[2];
132 	uint32				ID[2];
133 	struct crosshair	crosshair[2];
134 }	justifier;
135 
136 static struct
137 {
138 	int8				pads[4];
139 }	mp5[2];
140 
141 static struct
142 {
143 	int16				x, y;
144 	uint8				buttons;
145 	uint32				ID;
146 	struct crosshair	crosshair;
147 }	macsrifle;
148 
149 static set<struct exemulti *>		exemultis;
150 static set<uint32>					pollmap[NUMCTLS + 1];
151 static map<uint32, s9xcommand_t>	keymap;
152 static vector<s9xcommand_t *>		multis;
153 static uint8						turbo_time;
154 static uint8						pseudobuttons[256];
155 static bool8						FLAG_LATCH = FALSE;
156 static int32						curcontrollers[2] = { NONE,    NONE };
157 static int32						newcontrollers[2] = { JOYPAD0, NONE };
158 static char							buf[256];
159 
160 static const char	*color_names[32] =
161 {
162 	"Trans",
163 	"Black",
164 	"25Grey",
165 	"50Grey",
166 	"75Grey",
167 	"White",
168 	"Red",
169 	"Orange",
170 	"Yellow",
171 	"Green",
172 	"Cyan",
173 	"Sky",
174 	"Blue",
175 	"Violet",
176 	"MagicPink",
177 	"Purple",
178 	NULL,
179 	"tBlack",
180 	"t25Grey",
181 	"t50Grey",
182 	"t75Grey",
183 	"tWhite",
184 	"tRed",
185 	"tOrange",
186 	"tYellow",
187 	"tGreen",
188 	"tCyan",
189 	"tSky",
190 	"tBlue",
191 	"tViolet",
192 	"tMagicPink",
193 	"tPurple"
194 };
195 
196 static const char	*speed_names[4] =
197 {
198 	"Var",
199 	"Slow",
200 	"Med",
201 	"Fast"
202 };
203 
204 static const int	ptrspeeds[4] = { 1, 1, 4, 8 };
205 
206 // Note: these should be in asciibetical order!
207 #define THE_COMMANDS \
208 	S(BeginRecordingMovie), \
209 	S(ClipWindows), \
210 	S(Debugger), \
211 	S(DecEmuTurbo), \
212 	S(DecFrameRate), \
213 	S(DecFrameTime), \
214 	S(DecTurboSpeed), \
215 	S(EmuTurbo), \
216 	S(EndRecordingMovie), \
217 	S(ExitEmu), \
218 	S(IncEmuTurbo), \
219 	S(IncFrameRate), \
220 	S(IncFrameTime), \
221 	S(IncTurboSpeed), \
222 	S(LoadFreezeFile), \
223 	S(LoadMovie), \
224 	S(LoadOopsFile), \
225 	S(Pause), \
226 	S(QuickLoad000), \
227 	S(QuickLoad001), \
228 	S(QuickLoad002), \
229 	S(QuickLoad003), \
230 	S(QuickLoad004), \
231 	S(QuickLoad005), \
232 	S(QuickLoad006), \
233 	S(QuickLoad007), \
234 	S(QuickLoad008), \
235 	S(QuickLoad009), \
236 	S(QuickLoad010), \
237 	S(QuickSave000), \
238 	S(QuickSave001), \
239 	S(QuickSave002), \
240 	S(QuickSave003), \
241 	S(QuickSave004), \
242 	S(QuickSave005), \
243 	S(QuickSave006), \
244 	S(QuickSave007), \
245 	S(QuickSave008), \
246 	S(QuickSave009), \
247 	S(QuickSave010), \
248 	S(Reset), \
249 	S(SaveFreezeFile), \
250 	S(SaveSPC), \
251 	S(Screenshot), \
252 	S(SeekToFrame), \
253 	S(SoftReset), \
254 	S(SoundChannel0), \
255 	S(SoundChannel1), \
256 	S(SoundChannel2), \
257 	S(SoundChannel3), \
258 	S(SoundChannel4), \
259 	S(SoundChannel5), \
260 	S(SoundChannel6), \
261 	S(SoundChannel7), \
262 	S(SoundChannelsOn), \
263 	S(SwapJoypads), \
264 	S(ToggleBG0), \
265 	S(ToggleBG1), \
266 	S(ToggleBG2), \
267 	S(ToggleBG3), \
268 	S(ToggleEmuTurbo), \
269 	S(ToggleSprites), \
270 	S(ToggleTransparency) \
271 
272 #define S(x)	x
273 
274 enum command_numbers
275 {
276 	THE_COMMANDS,
277 	LAST_COMMAND
278 };
279 
280 #undef S
281 #define S(x)	#x
282 
283 static const char	*command_names[LAST_COMMAND + 1] =
284 {
285 	THE_COMMANDS,
286 	NULL
287 };
288 
289 #undef S
290 #undef THE_COMMANDS
291 
292 static void DisplayStateChange (const char *, bool8);
293 static void DoGunLatch (int, int);
294 static void DoMacsRifleLatch (int, int);
295 static int maptype (int);
296 static bool strless (const char *, const char *);
297 static int findstr (const char *, const char **, int);
298 static int get_threshold (const char **);
299 static const char * maptypename (int);
300 static int32 ApplyMulti (s9xcommand_t *, int32, int16);
301 static void do_polling (int);
302 static void UpdatePolledMouse (int);
303 
304 
operator +=(string & s,int i)305 static string& operator += (string &s, int i)
306 {
307 	snprintf(buf, sizeof(buf), "%d", i);
308 	s.append(buf);
309 	return (s);
310 }
311 
operator +=(string & s,double d)312 static string& operator += (string &s, double d)
313 {
314 	snprintf(buf, sizeof(buf), "%g", d);
315 	s.append(buf);
316 	return (s);
317 }
318 
DisplayStateChange(const char * str,bool8 on)319 static void DisplayStateChange (const char *str, bool8 on)
320 {
321 	snprintf(buf, sizeof(buf), "%s: %s", str, on ? "on":"off");
322 	S9xSetInfoString(buf);
323 }
324 
DoGunLatch(int x,int y)325 static void DoGunLatch (int x, int y)
326 {
327 	x += 40;
328 
329 	if (x > 295)
330 		x = 295;
331 	else
332 	if (x < 40)
333 		x = 40;
334 
335 	if (y > PPU.ScreenHeight - 1)
336 		y = PPU.ScreenHeight - 1;
337 	else
338 	if (y < 0)
339 		y = 0;
340 
341 	PPU.GunVLatch = (uint16) (y + 1);
342 	PPU.GunHLatch = (uint16) x;
343 }
344 
DoMacsRifleLatch(int x,int y)345 static void DoMacsRifleLatch (int x, int y)
346 {
347 	PPU.GunVLatch = (uint16) (y + 42);// + (int16) macsrifle.adjust_y;
348 	PPU.GunHLatch = (uint16) (x + 76);// + (int16) macsrifle.adjust_x;
349 }
350 
maptype(int t)351 static int maptype (int t)
352 {
353 	switch (t)
354 	{
355 		case S9xNoMapping:
356 			return (MAP_NONE);
357 
358 		case S9xButtonJoypad:
359 		case S9xButtonMouse:
360 		case S9xButtonSuperscope:
361 		case S9xButtonJustifier:
362 		case S9xButtonMacsRifle:
363 		case S9xButtonCommand:
364 		case S9xButtonPseudopointer:
365 		case S9xButtonPort:
366 		case S9xButtonMulti:
367 			return (MAP_BUTTON);
368 
369 		case S9xAxisJoypad:
370 		case S9xAxisPseudopointer:
371 		case S9xAxisPseudobuttons:
372 		case S9xAxisPort:
373 			return (MAP_AXIS);
374 
375 		case S9xPointer:
376 		case S9xPointerPort:
377 			return (MAP_POINTER);
378 
379 		default:
380 			return (MAP_UNKNOWN);
381 	}
382 }
383 
S9xControlsReset(void)384 void S9xControlsReset (void)
385 {
386 	S9xControlsSoftReset();
387 	mouse[0].buttons  &= ~0x30;
388 	mouse[1].buttons  &= ~0x30;
389 	justifier.buttons &= ~JUSTIFIER_SELECT;
390 	macsrifle.buttons = 0;
391 }
392 
S9xControlsSoftReset(void)393 void S9xControlsSoftReset (void)
394 {
395 	for (set<struct exemulti *>::iterator it = exemultis.begin(); it != exemultis.end(); it++)
396 		delete *it;
397 	exemultis.clear();
398 
399 	for (int i = 0; i < 2; i++)
400 		for (int j = 0; j < 2; j++)
401 			read_idx[i][j]=0;
402 
403 	FLAG_LATCH = FALSE;
404 
405 	curcontrollers[0] = newcontrollers[0];
406 	curcontrollers[1] = newcontrollers[1];
407 }
408 
S9xUnmapAllControls(void)409 void S9xUnmapAllControls (void)
410 {
411 	S9xControlsReset();
412 
413 	keymap.clear();
414 
415 	for (int i = 0; i < (int) multis.size(); i++)
416 		free(multis[i]);
417 	multis.clear();
418 
419 	for (int i = 0; i < NUMCTLS + 1; i++)
420 		pollmap[i].clear();
421 
422 	for (int i = 0; i < 8; i++)
423 	{
424 		pseudopointer[i].x = 0;
425 		pseudopointer[i].y = 0;
426 		pseudopointer[i].H_adj = 0;
427 		pseudopointer[i].V_adj = 0;
428 		pseudopointer[i].H_var = 0;
429 		pseudopointer[i].V_var = 0;
430 		pseudopointer[i].mapped = false;
431 
432 		joypad[i].buttons  = 0;
433 		joypad[i].turbos   = 0;
434 		joypad[i].turbo_ct = 0;
435 	}
436 
437 	for (int i = 0; i < 2; i++)
438 	{
439 		mouse[i].old_x = mouse[i].old_y = 0;
440 		mouse[i].cur_x = mouse[i].cur_y = 0;
441 		mouse[i].buttons = 1;
442 		mouse[i].ID = InvalidControlID;
443 
444 		if (!(mouse[i].crosshair.set & 1))
445 			mouse[i].crosshair.img = 0; // no image for mouse because its only logical position is game-specific, not known by the emulator
446 		if (!(mouse[i].crosshair.set & 2))
447 			mouse[i].crosshair.fg  = 5;
448 		if (!(mouse[i].crosshair.set & 4))
449 			mouse[i].crosshair.bg  = 1;
450 
451 		justifier.x[i] = justifier.y[i] = 0;
452 		justifier.offscreen[i] = 0;
453 		justifier.ID[i] = InvalidControlID;
454 
455 		if (!(justifier.crosshair[i].set & 1))
456 			justifier.crosshair[i].img = 4;
457 		if (!(justifier.crosshair[i].set & 2))
458 			justifier.crosshair[i].fg  = i ? 14 : 12;
459 		if (!(justifier.crosshair[i].set & 4))
460 			justifier.crosshair[i].bg  = 1;
461 	}
462 
463 	justifier.buttons = 0;
464 
465 	superscope.x = superscope.y = 0;
466 	superscope.phys_buttons = 0;
467 	superscope.next_buttons = 0;
468 	superscope.read_buttons = 0;
469 	superscope.ID = InvalidControlID;
470 
471 	if (!(superscope.crosshair.set & 1))
472 		superscope.crosshair.img = 2;
473 	if (!(superscope.crosshair.set & 2))
474 		superscope.crosshair.fg  = 5;
475 	if (!(superscope.crosshair.set & 4))
476 		superscope.crosshair.bg  = 1;
477 
478 	macsrifle.x = macsrifle.y = 0;
479 	macsrifle.buttons = 0;
480 	macsrifle.ID = InvalidControlID;
481 
482 	if (!(macsrifle.crosshair.set & 1))
483 		macsrifle.crosshair.img = 2;
484 	if (!(macsrifle.crosshair.set & 2))
485 		macsrifle.crosshair.fg  = 5;
486 	if (!(macsrifle.crosshair.set & 4))
487 		macsrifle.crosshair.bg  = 1;
488 
489 	memset(pseudobuttons, 0, sizeof(pseudobuttons));
490 
491 	turbo_time = 1;
492 }
493 
S9xSetController(int port,enum controllers controller,int8 id1,int8 id2,int8 id3,int8 id4)494 void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4)
495 {
496 	if (port < 0 || port > 1)
497 		return;
498 
499 	switch (controller)
500 	{
501 		case CTL_NONE:
502 			break;
503 
504 		case CTL_JOYPAD:
505 			if (id1 < 0 || id1 > 7)
506 				break;
507 
508 			newcontrollers[port] = JOYPAD0 + id1;
509 			return;
510 
511 		case CTL_MOUSE:
512 			if (id1 < 0 || id1 > 1)
513 				break;
514 			if (!Settings.MouseMaster)
515 			{
516 				S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled");
517 				break;
518 			}
519 
520 			newcontrollers[port] = MOUSE0 + id1;
521 			return;
522 
523 		case CTL_SUPERSCOPE:
524 			if (!Settings.SuperScopeMaster)
525 			{
526 				S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled");
527 				break;
528 			}
529 
530 			newcontrollers[port] = SUPERSCOPE;
531 			return;
532 
533 		case CTL_JUSTIFIER:
534 			if (id1 < 0 || id1 > 1)
535 				break;
536 			if (!Settings.JustifierMaster)
537 			{
538 				S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled");
539 				break;
540 			}
541 
542 			newcontrollers[port] = ONE_JUSTIFIER + id1;
543 			return;
544 
545 		case CTL_MACSRIFLE:
546 			if (!Settings.MacsRifleMaster)
547 			{
548 				S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled");
549 				break;
550 			}
551 
552 			newcontrollers[port] = MACSRIFLE;
553 			return;
554 
555 		case CTL_MP5:
556 			if (id1 < -1 || id1 > 7)
557 				break;
558 			if (id2 < -1 || id2 > 7)
559 				break;
560 			if (id3 < -1 || id3 > 7)
561 				break;
562 			if (id4 < -1 || id4 > 7)
563 				break;
564 			if (!Settings.MultiPlayer5Master)
565 			{
566 				S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled");
567 				break;
568 			}
569 
570 			newcontrollers[port] = MP5;
571 			mp5[port].pads[0] = (id1 < 0) ? NONE : JOYPAD0 + id1;
572 			mp5[port].pads[1] = (id2 < 0) ? NONE : JOYPAD0 + id2;
573 			mp5[port].pads[2] = (id3 < 0) ? NONE : JOYPAD0 + id3;
574 			mp5[port].pads[3] = (id4 < 0) ? NONE : JOYPAD0 + id4;
575 			return;
576 
577 		default:
578 			fprintf(stderr, "Unknown controller type %d\n", controller);
579 			break;
580 	}
581 
582 	newcontrollers[port] = NONE;
583 }
584 
S9xVerifyControllers(void)585 bool S9xVerifyControllers (void)
586 {
587 	bool	ret = false;
588 	int		port, i, used[NUMCTLS];
589 
590 	for (i = 0; i < NUMCTLS; used[i++] = 0) ;
591 
592 	for (port = 0; port < 2; port++)
593 	{
594 		switch (i = newcontrollers[port])
595 		{
596 			case MOUSE0:
597 			case MOUSE1:
598 				if (!Settings.MouseMaster)
599 				{
600 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled");
601 					newcontrollers[port] = NONE;
602 					ret = true;
603 					break;
604 				}
605 
606 				if (used[i]++ > 0)
607 				{
608 					snprintf(buf, sizeof(buf), "Mouse%d used more than once! Disabling extra instances", i - MOUSE0 + 1);
609 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
610 					newcontrollers[port] = NONE;
611 					ret = true;
612 					break;
613 				}
614 
615 				break;
616 
617 			case SUPERSCOPE:
618 				if (!Settings.SuperScopeMaster)
619 				{
620 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled");
621 					newcontrollers[port] = NONE;
622 					ret = true;
623 					break;
624 				}
625 
626 				if (used[i]++ > 0)
627 				{
628 					snprintf(buf, sizeof(buf), "Superscope used more than once! Disabling extra instances");
629 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
630 					newcontrollers[port] = NONE;
631 					ret = true;
632 					break;
633 				}
634 
635 				break;
636 
637 			case ONE_JUSTIFIER:
638 			case TWO_JUSTIFIERS:
639 				if (!Settings.JustifierMaster)
640 				{
641 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled");
642 					newcontrollers[port] = NONE;
643 					ret = true;
644 					break;
645 				}
646 
647 				if (used[ONE_JUSTIFIER]++ > 0)
648 				{
649 					snprintf(buf, sizeof(buf), "Justifier used more than once! Disabling extra instances");
650 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
651 					newcontrollers[port] = NONE;
652 					ret = true;
653 					break;
654 				}
655 
656 				break;
657 
658 			case MACSRIFLE:
659 				if (!Settings.MacsRifleMaster)
660 				{
661 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled");
662 					newcontrollers[port] = NONE;
663 					ret = true;
664 					break;
665 				}
666 
667 				if (used[i]++ > 0)
668 				{
669 					snprintf(buf, sizeof(buf), "M.A.C.S. Rifle used more than once! Disabling extra instances");
670 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
671 					newcontrollers[port] = NONE;
672 					ret = true;
673 					break;
674 				}
675 
676 				break;
677 
678 			case MP5:
679 				if (!Settings.MultiPlayer5Master)
680 				{
681 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled");
682 					newcontrollers[port] = NONE;
683 					ret = true;
684 					break;
685 				}
686 
687 				for (i = 0; i < 4; i++)
688 				{
689 					if (mp5[port].pads[i] != NONE)
690 					{
691 						if (used[mp5[port].pads[i] - JOYPAD0]++ > 0)
692 						{
693 							snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", mp5[port].pads[i] - JOYPAD0 + 1);
694 							S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
695 							mp5[port].pads[i] = NONE;
696 							ret = true;
697 							break;
698 						}
699 					}
700 				}
701 
702 				break;
703 
704 			case JOYPAD0:
705 			case JOYPAD1:
706 			case JOYPAD2:
707 			case JOYPAD3:
708 			case JOYPAD4:
709 			case JOYPAD5:
710 			case JOYPAD6:
711 			case JOYPAD7:
712 				if (used[i - JOYPAD0]++ > 0)
713 				{
714 					snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", i - JOYPAD0 + 1);
715 					S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf);
716 					newcontrollers[port] = NONE;
717 					ret = true;
718 					break;
719 				}
720 
721 				break;
722 
723 			default:
724 				break;
725 		}
726 	}
727 
728 	return (ret);
729 }
730 
S9xGetController(int port,enum controllers * controller,int8 * id1,int8 * id2,int8 * id3,int8 * id4)731 void S9xGetController (int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4)
732 {
733 	int	i;
734 
735 	*controller = CTL_NONE;
736 	*id1 = *id2 = *id3 = *id4 = -1;
737 
738 	if (port < 0 || port > 1)
739 		return;
740 
741 	switch (i = newcontrollers[port])
742 	{
743 		case MP5:
744 			*controller = CTL_MP5;
745 			*id1 = (mp5[port].pads[0] == NONE) ? -1 : mp5[port].pads[0] - JOYPAD0;
746 			*id2 = (mp5[port].pads[1] == NONE) ? -1 : mp5[port].pads[1] - JOYPAD0;
747 			*id3 = (mp5[port].pads[2] == NONE) ? -1 : mp5[port].pads[2] - JOYPAD0;
748 			*id4 = (mp5[port].pads[3] == NONE) ? -1 : mp5[port].pads[3] - JOYPAD0;
749 			return;
750 
751 		case JOYPAD0:
752 		case JOYPAD1:
753 		case JOYPAD2:
754 		case JOYPAD3:
755 		case JOYPAD4:
756 		case JOYPAD5:
757 		case JOYPAD6:
758 		case JOYPAD7:
759 			*controller = CTL_JOYPAD;
760 			*id1 = i - JOYPAD0;
761 			return;
762 
763 		case MOUSE0:
764 		case MOUSE1:
765 			*controller = CTL_MOUSE;
766 			*id1 = i - MOUSE0;
767 			return;
768 
769 		case SUPERSCOPE:
770 			*controller = CTL_SUPERSCOPE;
771 			*id1 = 1;
772 			return;
773 
774 		case ONE_JUSTIFIER:
775 		case TWO_JUSTIFIERS:
776 			*controller = CTL_JUSTIFIER;
777 			*id1 = i - ONE_JUSTIFIER;
778 			return;
779 
780 		case MACSRIFLE:
781 			*controller = CTL_MACSRIFLE;
782 			*id1 = 1;
783 			return;
784 	}
785 }
786 
S9xReportControllers(void)787 void S9xReportControllers (void)
788 {
789 	static char	mes[128];
790 	char		*c = mes;
791 
792 	S9xVerifyControllers();
793 
794 	for (int port = 0; port < 2; port++)
795 	{
796 		c += sprintf(c, "Port %d: ", port + 1);
797 
798 		switch (newcontrollers[port])
799 		{
800 			case NONE:
801 				c += sprintf(c, "<none>. ");
802 				break;
803 
804 			case MP5:
805 				c += sprintf(c, "MP5 with pads");
806 				for (int i = 0; i < 4; i++)
807 				{
808 					if (mp5[port].pads[i] == NONE)
809 						c += sprintf(c, " <none>. ");
810 					else
811 						c += sprintf(c, " #%d. ", mp5[port].pads[i] + 1 - JOYPAD0);
812 				}
813 
814 				break;
815 
816 			case JOYPAD0:
817 			case JOYPAD1:
818 			case JOYPAD2:
819 			case JOYPAD3:
820 			case JOYPAD4:
821 			case JOYPAD5:
822 			case JOYPAD6:
823 			case JOYPAD7:
824 				c += sprintf(c, "Pad #%d. ", (int) (newcontrollers[port] - JOYPAD0 + 1));
825 				break;
826 
827 			case MOUSE0:
828 			case MOUSE1:
829 				c += sprintf(c, "Mouse #%d. ", (int) (newcontrollers[port] - MOUSE0 + 1));
830 				break;
831 
832 			case SUPERSCOPE:
833 				if (port == 0)
834 					c += sprintf(c, "Superscope (cannot fire). ");
835 				else
836 					c += sprintf(c, "Superscope. ");
837 				break;
838 
839 			case ONE_JUSTIFIER:
840 				if (port == 0)
841 					c += sprintf(c, "Blue Justifier (cannot fire). ");
842 				else
843 					c += sprintf(c, "Blue Justifier. ");
844 				break;
845 
846 			case TWO_JUSTIFIERS:
847 				if (port == 0)
848 					c += sprintf(c, "Blue and Pink Justifiers (cannot fire). ");
849 				else
850 					c += sprintf(c, "Blue and Pink Justifiers. ");
851 				break;
852 
853 			case MACSRIFLE:
854 				if (port == 0)
855 					c += sprintf(c, "M.A.C.S. Rifle (cannot fire). ");
856 				else
857 					c += sprintf(c, "M.A.C.S. Rifle. ");
858 				break;
859 		}
860 	}
861 
862 	S9xMessage(S9X_INFO, S9X_CONFIG_INFO, mes);
863 }
864 
S9xGetCommandName(s9xcommand_t command)865 char * S9xGetCommandName (s9xcommand_t command)
866 {
867 	string	s;
868 	char	c;
869 
870 	switch (command.type)
871 	{
872 		case S9xButtonJoypad:
873 			if (command.button.joypad.buttons == 0)
874 				return (strdup("None"));
875 			if (command.button.joypad.buttons & 0x000f)
876 				return (strdup("None"));
877 
878 			s = "Joypad";
879 			s += command.button.joypad.idx + 1;
880 
881 			c = ' ';
882 			if (command.button.joypad.toggle)	{ if (c) s += c; s += "Toggle"; c = 0; }
883 			if (command.button.joypad.sticky)	{ if (c) s += c; s += "Sticky"; c = 0; }
884 			if (command.button.joypad.turbo )	{ if (c) s += c; s += "Turbo";  c = 0; }
885 
886 			c = ' ';
887 			if (command.button.joypad.buttons & SNES_UP_MASK    )	{ s += c; s += "Up";     c = '+'; }
888 			if (command.button.joypad.buttons & SNES_DOWN_MASK  )	{ s += c; s += "Down";   c = '+'; }
889 			if (command.button.joypad.buttons & SNES_LEFT_MASK  )	{ s += c; s += "Left";   c = '+'; }
890 			if (command.button.joypad.buttons & SNES_RIGHT_MASK )	{ s += c; s += "Right";  c = '+'; }
891 			if (command.button.joypad.buttons & SNES_A_MASK     )	{ s += c; s += "A";      c = '+'; }
892 			if (command.button.joypad.buttons & SNES_B_MASK     )	{ s += c; s += "B";      c = '+'; }
893 			if (command.button.joypad.buttons & SNES_X_MASK     )	{ s += c; s += "X";      c = '+'; }
894 			if (command.button.joypad.buttons & SNES_Y_MASK     )	{ s += c; s += "Y";      c = '+'; }
895 			if (command.button.joypad.buttons & SNES_TL_MASK    )	{ s += c; s += "L";      c = '+'; }
896 			if (command.button.joypad.buttons & SNES_TR_MASK    )	{ s += c; s += "R";      c = '+'; }
897 			if (command.button.joypad.buttons & SNES_START_MASK )	{ s += c; s += "Start";  c = '+'; }
898 			if (command.button.joypad.buttons & SNES_SELECT_MASK)	{ s += c; s += "Select"; c = '+'; }
899 
900 			break;
901 
902 		case S9xButtonMouse:
903 			if (!command.button.mouse.left && !command.button.mouse.right)
904 				return (strdup("None"));
905 
906 			s = "Mouse";
907 			s += command.button.mouse.idx + 1;
908 			s += " ";
909 
910 			if (command.button.mouse.left )	s += "L";
911 			if (command.button.mouse.right)	s += "R";
912 
913 			break;
914 
915 		case S9xButtonSuperscope:
916 			if (!command.button.scope.fire && !command.button.scope.cursor && !command.button.scope.turbo && !command.button.scope.pause && !command.button.scope.aim_offscreen)
917 				return (strdup("None"));
918 
919 			s = "Superscope";
920 
921 			if (command.button.scope.aim_offscreen)	s += " AimOffscreen";
922 
923 			c = ' ';
924 			if (command.button.scope.fire  )	{ s += c; s += "Fire";        c = '+'; }
925 			if (command.button.scope.cursor)	{ s += c; s += "Cursor";      c = '+'; }
926 			if (command.button.scope.turbo )	{ s += c; s += "ToggleTurbo"; c = '+'; }
927 			if (command.button.scope.pause )	{ s += c; s += "Pause";       c = '+'; }
928 
929 			break;
930 
931 		case S9xButtonJustifier:
932 			if (!command.button.justifier.trigger && !command.button.justifier.start && !command.button.justifier.aim_offscreen)
933 				return (strdup("None"));
934 
935 			s = "Justifier";
936 			s += command.button.justifier.idx + 1;
937 
938 			if (command.button.justifier.aim_offscreen)	s += " AimOffscreen";
939 
940 			c = ' ';
941 			if (command.button.justifier.trigger)	{ s += c; s += "Trigger"; c = '+'; }
942 			if (command.button.justifier.start  )	{ s += c; s += "Start";   c = '+'; }
943 
944 			break;
945 
946 		case S9xButtonMacsRifle:
947 			if (!command.button.macsrifle.trigger)
948 				return (strdup("None"));
949 
950 			s = "MacsRifle";
951 
952 			c = ' ';
953 			if (command.button.macsrifle.trigger)	{ s += c; s += "Trigger"; c = '+'; }
954 
955 			break;
956 
957 		case S9xButtonCommand:
958 			if (command.button.command >= LAST_COMMAND)
959 				return (strdup("None"));
960 
961 			return (strdup(command_names[command.button.command]));
962 
963 		case S9xPointer:
964 			if (!command.pointer.aim_mouse0 && !command.pointer.aim_mouse1 && !command.pointer.aim_scope && !command.pointer.aim_justifier0 && !command.pointer.aim_justifier1 && !command.pointer.aim_macsrifle)
965 				return (strdup("None"));
966 
967 			s = "Pointer";
968 
969 			c = ' ';
970 			if (command.pointer.aim_mouse0    )	{ s += c; s += "Mouse1";     c = '+'; }
971 			if (command.pointer.aim_mouse1    )	{ s += c; s += "Mouse2";     c = '+'; }
972 			if (command.pointer.aim_scope     )	{ s += c; s += "Superscope"; c = '+'; }
973 			if (command.pointer.aim_justifier0)	{ s += c; s += "Justifier1"; c = '+'; }
974 			if (command.pointer.aim_justifier1)	{ s += c; s += "Justifier2"; c = '+'; }
975 			if (command.pointer.aim_macsrifle)  { s += c; s += "MacsRifle";  c = '+'; }
976 
977 			break;
978 
979 		case S9xButtonPseudopointer:
980 			if (!command.button.pointer.UD && !command.button.pointer.LR)
981 				return (strdup("None"));
982 			if (command.button.pointer.UD == -2 || command.button.pointer.LR == -2)
983 				return (strdup("None"));
984 
985 			s = "ButtonToPointer ";
986 			s += command.button.pointer.idx + 1;
987 
988 			if (command.button.pointer.UD)	s += (command.button.pointer.UD == 1) ? 'd' : 'u';
989 			if (command.button.pointer.LR)	s += (command.button.pointer.LR == 1) ? 'r' : 'l';
990 
991 			s += " ";
992 			s += speed_names[command.button.pointer.speed_type];
993 
994 			break;
995 
996 		case S9xAxisJoypad:
997 			s = "Joypad";
998 			s += command.axis.joypad.idx + 1;
999 			s += " Axis ";
1000 
1001 			switch (command.axis.joypad.axis)
1002 			{
1003 				case 0:	s += (command.axis.joypad.invert ? "Right/Left" : "Left/Right");	break;
1004 				case 1:	s += (command.axis.joypad.invert ? "Down/Up"    : "Up/Down"   );	break;
1005 				case 2:	s += (command.axis.joypad.invert ? "A/Y"        : "Y/A"       );	break;
1006 				case 3:	s += (command.axis.joypad.invert ? "B/X"        : "X/B"       );	break;
1007 				case 4:	s += (command.axis.joypad.invert ? "R/L"        : "L/R"       );	break;
1008 				default:	return (strdup("None"));
1009 			}
1010 
1011 			s += " T=";
1012 			s += int((command.axis.joypad.threshold + 1) * 1000 / 256) / 10.0;
1013 			s += "%";
1014 
1015 			break;
1016 
1017 		case S9xAxisPseudopointer:
1018 			s = "AxisToPointer ";
1019 			s += command.axis.pointer.idx + 1;
1020 			s += command.axis.pointer.HV ? 'v' : 'h';
1021 			s += " ";
1022 
1023 			if (command.axis.pointer.invert)	s += "-";
1024 
1025 			s += speed_names[command.axis.pointer.speed_type];
1026 
1027 			break;
1028 
1029 		case S9xAxisPseudobuttons:
1030 			s = "AxisToButtons ";
1031 			s += command.axis.button.negbutton;
1032 			s += "/";
1033 			s += command.axis.button.posbutton;
1034 			s += " T=";
1035 			s += int((command.axis.button.threshold + 1) * 1000 / 256) / 10.0;
1036 			s += "%";
1037 
1038 			break;
1039 
1040 		case S9xButtonPort:
1041 		case S9xAxisPort:
1042 		case S9xPointerPort:
1043 			return (strdup("BUG: Port should have handled this instead of calling S9xGetCommandName()"));
1044 
1045 		case S9xNoMapping:
1046 			return (strdup("None"));
1047 
1048 		case S9xButtonMulti:
1049 		{
1050 			if (command.button.multi_idx >= (int) multis.size())
1051 				return (strdup("None"));
1052 
1053 			s = "{";
1054 			if (multis[command.button.multi_idx]->multi_press)	s = "+{";
1055 
1056 			bool	sep = false;
1057 
1058 			for (s9xcommand_t *m = multis[command.button.multi_idx]; m->multi_press != 3; m++)
1059 			{
1060 				if (m->type == S9xNoMapping)
1061 				{
1062 					s += ";";
1063 					sep = false;
1064 				}
1065 				else
1066 				{
1067 					if (sep)					s += ",";
1068 					if (m->multi_press == 1)	s += "+";
1069 					if (m->multi_press == 2)	s += "-";
1070 
1071 					s += S9xGetCommandName(*m);
1072 					sep = true;
1073 				}
1074 			}
1075 
1076 			s += "}";
1077 
1078 			break;
1079 		}
1080 
1081 		default:
1082 			return (strdup("BUG: Unknown command type"));
1083 	}
1084 
1085 	return (strdup(s.c_str()));
1086 }
1087 
strless(const char * a,const char * b)1088 static bool strless (const char *a, const char *b)
1089 {
1090 	return (strcmp(a, b) < 0);
1091 }
1092 
findstr(const char * needle,const char ** haystack,int numstr)1093 static int findstr (const char *needle, const char **haystack, int numstr)
1094 {
1095 	const char	**r;
1096 
1097 	r = lower_bound(haystack, haystack + numstr, needle, strless);
1098 	if (r >= haystack + numstr || strcmp(needle, *r))
1099 		return (-1);
1100 
1101 	return (r - haystack);
1102 }
1103 
get_threshold(const char ** ss)1104 static int get_threshold (const char **ss)
1105 {
1106 	const char	*s = *ss;
1107 	int			i;
1108 
1109 	if (s[0] != 'T' || s[1] != '=')
1110 		return (-1);
1111 
1112 	s += 2;
1113 	i = 0;
1114 
1115 	if (s[0] == '0')
1116 	{
1117 		if (s[1] != '.')
1118 			return (-1);
1119 
1120 		s++;
1121 	}
1122 	else
1123 	{
1124 		do
1125 		{
1126 			if (*s < '0' || *s > '9')
1127 				return (-1);
1128 
1129 			i = i * 10 + 10 * (*s - '0');
1130 			if (i > 1000)
1131 				return (-1);
1132 
1133 			s++;
1134 		}
1135 		while (*s != '.' && *s != '%');
1136 	}
1137 
1138 	if (*s == '.')
1139 	{
1140 		if (s[1] < '0' || s[1] > '9' || s[2] != '%')
1141 			return (-1);
1142 
1143 		i += s[1] - '0';
1144 	}
1145 
1146 	if (i > 1000)
1147 		return (-1);
1148 
1149 	*ss = s;
1150 
1151 	return (i);
1152 }
1153 
S9xGetCommandT(const char * name)1154 s9xcommand_t S9xGetCommandT (const char *name)
1155 {
1156 	s9xcommand_t	cmd;
1157 	int				i, j;
1158 	const char		*s;
1159 
1160 	memset(&cmd, 0, sizeof(cmd));
1161 	cmd.type         = S9xBadMapping;
1162 	cmd.multi_press  = 0;
1163 	cmd.button_norpt = 0;
1164 
1165 	if (!strcmp(name, "None"))
1166 		cmd.type = S9xNoMapping;
1167 	else
1168 	if (!strncmp(name, "Joypad", 6))
1169 	{
1170 		if (name[6] < '1' || name[6] > '8' || name[7] != ' ')
1171 			return (cmd);
1172 
1173 		if (!strncmp(name + 8, "Axis ", 5))
1174 		{
1175 			cmd.axis.joypad.idx = name[6] - '1';
1176 			s = name + 13;
1177 
1178 			if (!strncmp(s, "Left/Right ", 11))	{ j = 0; i = 0; s += 11; }
1179 			else
1180 			if (!strncmp(s, "Right/Left ", 11))	{ j = 0; i = 1; s += 11; }
1181 			else
1182 			if (!strncmp(s, "Up/Down ",     8))	{ j = 1; i = 0; s +=  8; }
1183 			else
1184 			if (!strncmp(s, "Down/Up ",     8))	{ j = 1; i = 1; s +=  8; }
1185 			else
1186 			if (!strncmp(s, "Y/A ",         4))	{ j = 2; i = 0; s +=  4; }
1187 			else
1188 			if (!strncmp(s, "A/Y ",         4))	{ j = 2; i = 1; s +=  4; }
1189 			else
1190 			if (!strncmp(s, "X/B ",         4))	{ j = 3; i = 0; s +=  4; }
1191 			else
1192 			if (!strncmp(s, "B/X ",         4))	{ j = 3; i = 1; s +=  4; }
1193 			else
1194 			if (!strncmp(s, "L/R ",         4))	{ j = 4; i = 0; s +=  4; }
1195 			else
1196 			if (!strncmp(s, "R/L ",         4))	{ j = 4; i = 1; s +=  4; }
1197 			else
1198 				return (cmd);
1199 
1200 			cmd.axis.joypad.axis      = j;
1201 			cmd.axis.joypad.invert    = i;
1202 			i = get_threshold(&s);
1203 			if (i < 0)
1204 				return (cmd);
1205 			cmd.axis.joypad.threshold = (i - 1) * 256 / 1000;
1206 
1207 			cmd.type = S9xAxisJoypad;
1208 		}
1209 		else
1210 		{
1211 			cmd.button.joypad.idx = name[6] - '1';
1212 			s = name + 8;
1213 			i = 0;
1214 
1215 			if ((cmd.button.joypad.toggle = strncmp(s, "Toggle", 6) ? 0 : 1))	s += i = 6;
1216 			if ((cmd.button.joypad.sticky = strncmp(s, "Sticky", 6) ? 0 : 1))	s += i = 6;
1217 			if ((cmd.button.joypad.turbo  = strncmp(s, "Turbo",  5) ? 0 : 1))	s += i = 5;
1218 
1219 			if (cmd.button.joypad.toggle && !(cmd.button.joypad.sticky || cmd.button.joypad.turbo))
1220 				return (cmd);
1221 
1222 			if (i)
1223 			{
1224 				if (*s != ' ')
1225 					return (cmd);
1226 				s++;
1227 			}
1228 
1229 			i = 0;
1230 
1231 			if (!strncmp(s, "Up",     2))	{ i |= SNES_UP_MASK;     s += 2; if (*s == '+') s++; }
1232 			if (!strncmp(s, "Down",   4))	{ i |= SNES_DOWN_MASK;   s += 4; if (*s == '+') s++; }
1233 			if (!strncmp(s, "Left",   4))	{ i |= SNES_LEFT_MASK;   s += 4; if (*s == '+') s++; }
1234 			if (!strncmp(s, "Right",  5))	{ i |= SNES_RIGHT_MASK;  s += 5; if (*s == '+') s++; }
1235 
1236 			if (*s == 'A')	{ i |= SNES_A_MASK;  s++; if (*s == '+') s++; }
1237 			if (*s == 'B')	{ i |= SNES_B_MASK;  s++; if (*s == '+') s++; }
1238 			if (*s == 'X')	{ i |= SNES_X_MASK;  s++; if (*s == '+') s++; }
1239 			if (*s == 'Y')	{ i |= SNES_Y_MASK;  s++; if (*s == '+') s++; }
1240 			if (*s == 'L')	{ i |= SNES_TL_MASK; s++; if (*s == '+') s++; }
1241 			if (*s == 'R')	{ i |= SNES_TR_MASK; s++; if (*s == '+') s++; }
1242 
1243 			if (!strncmp(s, "Start",  5))	{ i |= SNES_START_MASK;  s += 5; if (*s == '+') s++; }
1244 			if (!strncmp(s, "Select", 6))	{ i |= SNES_SELECT_MASK; s += 6; }
1245 
1246 			if (i == 0 || *s != 0 || *(s - 1) == '+')
1247 				return (cmd);
1248 
1249 			cmd.button.joypad.buttons = i;
1250 
1251 			cmd.type = S9xButtonJoypad;
1252 		}
1253 	}
1254 	else
1255 	if (!strncmp(name, "Mouse", 5))
1256 	{
1257 		if (name[5] < '1' || name[5] > '2' || name[6] != ' ')
1258 			return (cmd);
1259 
1260 		cmd.button.mouse.idx = name[5] - '1';
1261 		s = name + 7;
1262 		i = 0;
1263 
1264 		if ((cmd.button.mouse.left  = (*s == 'L')))	s += i = 1;
1265 		if ((cmd.button.mouse.right = (*s == 'R')))	s += i = 1;
1266 
1267 		if (i == 0 || *s != 0)
1268 			return (cmd);
1269 
1270 		cmd.type = S9xButtonMouse;
1271 	}
1272 	else
1273 	if (!strncmp(name, "Superscope ", 11))
1274 	{
1275 		s = name + 11;
1276 		i = 0;
1277 
1278 		if ((cmd.button.scope.aim_offscreen     = strncmp(s, "AimOffscreen", 12) ? 0 : 1))	{ s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); }
1279 		if ((cmd.button.scope.fire              = strncmp(s, "Fire",          4) ? 0 : 1))	{ s += i =  4; if (*s == '+') s++; }
1280 		if ((cmd.button.scope.cursor            = strncmp(s, "Cursor",        6) ? 0 : 1))	{ s += i =  6; if (*s == '+') s++; }
1281 		if ((cmd.button.scope.turbo             = strncmp(s, "ToggleTurbo",  11) ? 0 : 1))	{ s += i = 11; if (*s == '+') s++; }
1282 		if ((cmd.button.scope.pause             = strncmp(s, "Pause",         5) ? 0 : 1))	{ s += i =  5; }
1283 
1284 		if (i == 0 || *s != 0 || *(s - 1) == '+')
1285 			return (cmd);
1286 
1287 		cmd.type = S9xButtonSuperscope;
1288 	}
1289 	else
1290 	if (!strncmp(name, "Justifier", 9))
1291 	{
1292 		if (name[9] < '1' || name[9] > '2' || name[10] != ' ')
1293 			return (cmd);
1294 
1295 		cmd.button.justifier.idx = name[9] - '1';
1296 		s = name + 11;
1297 		i = 0;
1298 
1299 		if ((cmd.button.justifier.aim_offscreen = strncmp(s, "AimOffscreen", 12) ? 0 : 1))	{ s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); }
1300 		if ((cmd.button.justifier.trigger       = strncmp(s, "Trigger",       7) ? 0 : 1))	{ s += i =  7; if (*s == '+') s++; }
1301 		if ((cmd.button.justifier.start         = strncmp(s, "Start",         5) ? 0 : 1))	{ s += i =  5; }
1302 
1303 		if (i == 0 || *s != 0 || *(s - 1) == '+')
1304 			return (cmd);
1305 
1306 		cmd.type = S9xButtonJustifier;
1307 	}
1308 	else
1309 	if (!strncmp(name, "MacsRifle ", 10))
1310 	{
1311 		s = name + 10;
1312 		i = 0;
1313 
1314 		if ((cmd.button.macsrifle.trigger = strncmp(s, "Trigger", 7) ? 0 : 1))	{ s += i =  7; }
1315 
1316 		if (i == 0 || *s != 0 || *(s - 1) == '+')
1317 			return (cmd);
1318 
1319 		cmd.type = S9xButtonMacsRifle;
1320 	}
1321 	else
1322 	if (!strncmp(name, "Pointer ", 8))
1323 	{
1324 		s = name + 8;
1325 		i = 0;
1326 
1327 		if ((cmd.pointer.aim_mouse0     = strncmp(s, "Mouse1",      6) ? 0 : 1))	{ s += i =  6; if (*s == '+') s++; }
1328 		if ((cmd.pointer.aim_mouse1     = strncmp(s, "Mouse2",      6) ? 0 : 1))	{ s += i =  6; if (*s == '+') s++; }
1329 		if ((cmd.pointer.aim_scope      = strncmp(s, "Superscope", 10) ? 0 : 1))	{ s += i = 10; if (*s == '+') s++; }
1330 		if ((cmd.pointer.aim_justifier0 = strncmp(s, "Justifier1", 10) ? 0 : 1))	{ s += i = 10; if (*s == '+') s++; }
1331 		if ((cmd.pointer.aim_justifier1 = strncmp(s, "Justifier2", 10) ? 0 : 1))	{ s += i = 10; if (*s == '+') s++; }
1332 		if ((cmd.pointer.aim_macsrifle  = strncmp(s, "MacsRifle",   9) ? 0 : 1))	{ s += i =  9; }
1333 
1334 		if (i == 0 || *s != 0 || *(s - 1) == '+')
1335 			return (cmd);
1336 
1337 		cmd.type = S9xPointer;
1338 	}
1339 	else
1340 	if (!strncmp(name, "ButtonToPointer ", 16))
1341 	{
1342 		if (name[16] < '1' || name[16] > '8')
1343 			return (cmd);
1344 
1345 		cmd.button.pointer.idx = name[16] - '1';
1346 		s = name + 17;
1347 		i = 0;
1348 
1349 		if ((cmd.button.pointer.UD = (*s == 'u' ? -1 : (*s == 'd' ? 1 : 0))))	s += i = 1;
1350 		if ((cmd.button.pointer.LR = (*s == 'l' ? -1 : (*s == 'r' ? 1 : 0))))	s += i = 1;
1351 
1352 		if (i == 0 || *(s++) != ' ')
1353 			return (cmd);
1354 
1355 		for (i = 0; i < 4; i++)
1356 			if (!strcmp(s, speed_names[i]))
1357 				break;
1358 		if (i > 3)
1359 			return (cmd);
1360 
1361 		cmd.button.pointer.speed_type = i;
1362 
1363 		cmd.type = S9xButtonPseudopointer;
1364 	}
1365 	else
1366 	if (!strncmp(name, "AxisToPointer ", 14))
1367 	{
1368 		if (name[14] < '1' || name[14] > '8')
1369 			return (cmd);
1370 
1371 		cmd.axis.pointer.idx = name[14] - '1';
1372 		s= name + 15;
1373 		i = 0;
1374 
1375 		if (*s == 'h')
1376 			cmd.axis.pointer.HV = 0;
1377 		else
1378 		if (*s == 'v')
1379 			cmd.axis.pointer.HV = 1;
1380 		else
1381 			return (cmd);
1382 
1383 		if (s[1] != ' ')
1384 			return (cmd);
1385 
1386 		s += 2;
1387 		if ((cmd.axis.pointer.invert = *s == '-'))
1388 			s++;
1389 
1390 		for (i = 0; i < 4; i++)
1391 			if (!strcmp(s, speed_names[i]))
1392 				break;
1393 		if (i > 3)
1394 			return (cmd);
1395 
1396 		cmd.axis.pointer.speed_type = i;
1397 
1398 		cmd.type = S9xAxisPseudopointer;
1399 	}
1400 	else
1401 	if (!strncmp(name, "AxisToButtons ", 14))
1402 	{
1403 		s = name + 14;
1404 
1405 		if (s[0] == '0')
1406 		{
1407 			if (s[1] != '/')
1408 				return (cmd);
1409 
1410 			cmd.axis.button.negbutton = 0;
1411 			s += 2;
1412 		}
1413 		else
1414 		{
1415 			i = 0;
1416 			do
1417 			{
1418 				if (*s < '0' || *s > '9')
1419 					return (cmd);
1420 
1421 				i = i * 10 + *s - '0';
1422 				if (i > 255)
1423 					return (cmd);
1424 			}
1425 			while (*++s != '/');
1426 
1427 			cmd.axis.button.negbutton = i;
1428 			s++;
1429 		}
1430 
1431 		if (s[0] == '0')
1432 		{
1433 			if (s[1] != ' ')
1434 				return (cmd);
1435 
1436 			cmd.axis.button.posbutton = 0;
1437 			s += 2;
1438 		}
1439 		else
1440 		{
1441 			i = 0;
1442 			do
1443 			{
1444 				if (*s < '0' || *s > '9')
1445 					return (cmd);
1446 
1447 				i = i * 10 + *s - '0';
1448 				if (i > 255)
1449 					return (cmd);
1450 			}
1451 			while (*++s != ' ');
1452 
1453 			cmd.axis.button.posbutton = i;
1454 			s++;
1455 		}
1456 
1457 		i = get_threshold(&s);
1458 		if (i < 0)
1459 			return (cmd);
1460 		cmd.axis.button.threshold = (i - 1) * 256 / 1000;
1461 
1462 		cmd.type = S9xAxisPseudobuttons;
1463 	}
1464 	else
1465 	if (!strncmp(name, "MULTI#", 6))
1466 	{
1467 		i = strtol(name + 6, (char **) &s, 10);
1468 		if (s != NULL && *s != '\0')
1469 			return (cmd);
1470 		if (i >= (int) multis.size())
1471 			return (cmd);
1472 
1473 		cmd.button.multi_idx = i;
1474 		cmd.type = S9xButtonMulti;
1475 	}
1476 	else
1477 	if (((name[0] == '+' && name[1] == '{') || name[0] == '{') && name[strlen(name) - 1] == '}')
1478 	{
1479 		if (multis.size() > 2147483640)
1480 		{
1481 			fprintf(stderr, "Too many multis!");
1482 			return (cmd);
1483 		}
1484 
1485 		string	x;
1486 		int		n;
1487 
1488 		j = 2;
1489 		for (i = (name[0] == '+') ? 2 : 1; name[i] != '\0'; i++)
1490 		{
1491 			if (name[i] == ',' || name[i] == ';')
1492 			{
1493 				if (name[i] == ';')
1494 					j++;
1495 				if (++j > 2147483640)
1496 				{
1497 					fprintf(stderr, "Multi too long!");
1498 					return (cmd);
1499 				}
1500 			}
1501 
1502 			if (name[i] == '{')
1503 				return (cmd);
1504 		}
1505 
1506 		s9xcommand_t	*c = (s9xcommand_t *) calloc(j, sizeof(s9xcommand_t));
1507 		if (c == NULL)
1508 		{
1509 			perror("malloc error while parsing multi");
1510 			return (cmd);
1511 		}
1512 
1513 		n = 0;
1514 		i = (name[0] == '+') ? 2 : 1;
1515 
1516 		do
1517 		{
1518 			if (name[i] == ';')
1519 			{
1520 				c[n].type         = S9xNoMapping;
1521 				c[n].multi_press  = 0;
1522 				c[n].button_norpt = 0;
1523 
1524 				j = i;
1525 			}
1526 			else
1527 			if (name[i] == ',')
1528 			{
1529 				free(c);
1530 				return (cmd);
1531 			}
1532 			else
1533 			{
1534 				uint8	press = 0;
1535 
1536 				if (name[0] == '+')
1537 				{
1538 					if (name[i] == '+')
1539 						press = 1;
1540 					else
1541 					if (name[i] == '-')
1542 						press = 2;
1543 					else
1544 					{
1545 						free(c);
1546 						return (cmd);
1547 					}
1548 
1549 					i++;
1550 				}
1551 
1552 				for (j = i; name[j] != ';' && name[j] != ',' && name[j] != '}'; j++) ;
1553 
1554 				x.assign(name + i, j - i);
1555 				c[n] = S9xGetCommandT(x.c_str());
1556 				c[n].multi_press = press;
1557 
1558 				if (maptype(c[n].type) != MAP_BUTTON)
1559 				{
1560 					free(c);
1561 					return (cmd);
1562 				}
1563 
1564 				if (name[j] == ';')
1565 					j--;
1566 			}
1567 
1568 			i = j + 1;
1569 			n++;
1570 		}
1571 		while (name[i] != '\0');
1572 
1573 		c[n].type        = S9xNoMapping;
1574 		c[n].multi_press = 3;
1575 
1576 		multis.push_back(c);
1577 
1578 		cmd.button.multi_idx = multis.size() - 1;
1579 		cmd.type = S9xButtonMulti;
1580 	}
1581 	else
1582 	{
1583 		i = findstr(name, command_names, LAST_COMMAND);
1584 		if (i < 0)
1585 			return (cmd);
1586 
1587 		cmd.type = S9xButtonCommand;
1588 		cmd.button.command = i;
1589 	}
1590 
1591 	return (cmd);
1592 }
1593 
S9xGetAllSnes9xCommands(void)1594 const char ** S9xGetAllSnes9xCommands (void)
1595 {
1596 	return (command_names);
1597 }
1598 
S9xGetMapping(uint32 id)1599 s9xcommand_t S9xGetMapping (uint32 id)
1600 {
1601 	if (keymap.count(id) == 0)
1602 	{
1603 		s9xcommand_t	cmd;
1604 		cmd.type = S9xNoMapping;
1605 		return (cmd);
1606 	}
1607 	else
1608 		return (keymap[id]);
1609 }
1610 
maptypename(int t)1611 static const char * maptypename (int t)
1612 {
1613 	switch (t)
1614 	{
1615 		case MAP_NONE:		return ("unmapped");
1616 		case MAP_BUTTON:	return ("button");
1617 		case MAP_AXIS:		return ("axis");
1618 		case MAP_POINTER:	return ("pointer");
1619 		default:			return ("unknown");
1620 	}
1621 }
1622 
S9xUnmapID(uint32 id)1623 void S9xUnmapID (uint32 id)
1624 {
1625 	for (int i = 0; i < NUMCTLS + 1; i++)
1626 		pollmap[i].erase(id);
1627 
1628 	if (mouse[0].ID     == id)	mouse[0].ID     = InvalidControlID;
1629 	if (mouse[1].ID     == id)	mouse[1].ID     = InvalidControlID;
1630 	if (superscope.ID   == id)	superscope.ID   = InvalidControlID;
1631 	if (justifier.ID[0] == id)	justifier.ID[0] = InvalidControlID;
1632 	if (justifier.ID[1] == id)	justifier.ID[1] = InvalidControlID;
1633 	if (macsrifle.ID    == id)	macsrifle.ID    = InvalidControlID;
1634 
1635 	if (id >= PseudoPointerBase)
1636 		pseudopointer[id - PseudoPointerBase].mapped = false;
1637 
1638 	keymap.erase(id);
1639 }
1640 
S9xMapButton(uint32 id,s9xcommand_t mapping,bool poll)1641 bool S9xMapButton (uint32 id, s9xcommand_t mapping, bool poll)
1642 {
1643 	int	t;
1644 
1645 	if (id == InvalidControlID)
1646 	{
1647 		fprintf(stderr, "Cannot map InvalidControlID\n");
1648 		return (false);
1649 	}
1650 
1651 	t = maptype(mapping.type);
1652 
1653 	if (t == MAP_NONE)
1654 	{
1655 		S9xUnmapID(id);
1656 		return (true);
1657 	}
1658 
1659 	if (t != MAP_BUTTON)
1660 		return (false);
1661 
1662 	t = maptype(S9xGetMapping(id).type);
1663 
1664 	if (t != MAP_NONE && t != MAP_BUTTON)
1665 		fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to button\n", id, maptypename(t));
1666 
1667 	if (id >= PseudoPointerBase)
1668 	{
1669 		fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as a button\n", id - PseudoPointerBase);
1670 		return (false);
1671 	}
1672 
1673 	t = -1;
1674 
1675 	if (poll)
1676 	{
1677 		if (id >= PseudoButtonBase)
1678 			fprintf(stderr, "INFO: Ignoring attempt to set pseudo-button #%d to polling\n", id - PseudoButtonBase);
1679 		else
1680 		{
1681 			switch (mapping.type)
1682 			{
1683 				case S9xButtonJoypad:
1684 					t = JOYPAD0 + mapping.button.joypad.idx;
1685 					break;
1686 
1687 				case S9xButtonMouse:
1688 					t = MOUSE0 + mapping.button.mouse.idx;
1689 					break;
1690 
1691 				case S9xButtonSuperscope:
1692 					t = SUPERSCOPE;
1693 					break;
1694 
1695 				case S9xButtonJustifier:
1696 					t = ONE_JUSTIFIER + mapping.button.justifier.idx;
1697 					break;
1698 
1699 				case S9xButtonMacsRifle:
1700 					t = MACSRIFLE;
1701 					break;
1702 
1703 				case S9xButtonCommand:
1704 				case S9xButtonPseudopointer:
1705 				case S9xButtonPort:
1706 				case S9xButtonMulti:
1707 					t = POLL_ALL;
1708 					break;
1709 			}
1710 		}
1711 	}
1712 
1713 	S9xUnmapID(id);
1714 
1715 	keymap[id] = mapping;
1716 
1717 	if (t >= 0)
1718 		pollmap[t].insert(id);
1719 
1720 	return (true);
1721 }
1722 
S9xReportButton(uint32 id,bool pressed)1723 void S9xReportButton (uint32 id, bool pressed)
1724 {
1725 	if (keymap.count(id) == 0)
1726 		return;
1727 
1728 	if (keymap[id].type == S9xNoMapping)
1729 		return;
1730 
1731 	if (maptype(keymap[id].type) != MAP_BUTTON)
1732 	{
1733 		fprintf(stderr, "ERROR: S9xReportButton called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
1734 		return;
1735 	}
1736 
1737 	if (keymap[id].type == S9xButtonCommand)	// skips the "already-pressed check" unless it's a command, as a hack to work around the following problem:
1738 		if (keymap[id].button_norpt == pressed)	// FIXME: this makes the controls "stick" after loading a savestate while recording a movie and holding any button
1739 			return;
1740 
1741 	keymap[id].button_norpt = pressed;
1742 
1743 	S9xApplyCommand(keymap[id], pressed, 0);
1744 }
1745 
S9xMapPointer(uint32 id,s9xcommand_t mapping,bool poll)1746 bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll)
1747 {
1748 	int	t;
1749 
1750 	if (id == InvalidControlID)
1751 	{
1752 		fprintf(stderr, "Cannot map InvalidControlID\n");
1753 		return (false);
1754 	}
1755 
1756 	t = maptype(mapping.type);
1757 
1758 	if (t == MAP_NONE)
1759 	{
1760 		S9xUnmapID(id);
1761 		return (true);
1762 	}
1763 
1764 	if (t != MAP_POINTER)
1765 		return (false);
1766 
1767 	t = maptype(S9xGetMapping(id).type);
1768 
1769 	if (t != MAP_NONE && t != MAP_POINTER)
1770 		fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to pointer\n", id, maptypename(t));
1771 
1772 	if (id < PseudoPointerBase && id >= PseudoButtonBase)
1773 	{
1774 		fprintf(stderr, "ERROR: Refusing to map pseudo-button #%d as a pointer\n", id - PseudoButtonBase);
1775 		return (false);
1776 	}
1777 
1778 	if (mapping.type == S9xPointer)
1779 	{
1780 		if (mapping.pointer.aim_mouse0 && mouse[0].ID != InvalidControlID && mouse[0].ID != id)
1781 		{
1782 			fprintf(stderr, "ERROR: Rejecting attempt to control Mouse1 with two pointers\n");
1783 			return (false);
1784 		}
1785 
1786 		if (mapping.pointer.aim_mouse1 && mouse[1].ID != InvalidControlID && mouse[1].ID != id)
1787 		{
1788 			fprintf(stderr, "ERROR: Rejecting attempt to control Mouse2 with two pointers\n");
1789 			return (false);
1790 		}
1791 
1792 		if (mapping.pointer.aim_scope && superscope.ID != InvalidControlID && superscope.ID != id)
1793 		{
1794 			fprintf(stderr, "ERROR: Rejecting attempt to control SuperScope with two pointers\n");
1795 			return (false);
1796 		}
1797 
1798 		if (mapping.pointer.aim_justifier0 && justifier.ID[0] != InvalidControlID && justifier.ID[0] != id)
1799 		{
1800 			fprintf(stderr, "ERROR: Rejecting attempt to control Justifier1 with two pointers\n");
1801 			return (false);
1802 		}
1803 
1804 		if (mapping.pointer.aim_justifier1 && justifier.ID[1] != InvalidControlID && justifier.ID[1] != id)
1805 		{
1806 			fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n");
1807 			return (false);
1808 		}
1809 
1810 		if (mapping.pointer.aim_macsrifle && macsrifle.ID != InvalidControlID && macsrifle.ID != id)
1811 		{
1812 			fprintf(stderr, "ERROR: Rejecting attempt to control M.A.C.S. Rifle with two pointers\n");
1813 			return (false);
1814 		}
1815 	}
1816 
1817 	S9xUnmapID(id);
1818 
1819 	if (poll)
1820 	{
1821 		if (id >= PseudoPointerBase)
1822 			fprintf(stderr, "INFO: Ignoring attempt to set pseudo-pointer #%d to polling\n", id - PseudoPointerBase);
1823 		else
1824 		{
1825 			switch (mapping.type)
1826 			{
1827 				case S9xPointer:
1828 					if (mapping.pointer.aim_mouse0    )	pollmap[MOUSE0        ].insert(id);
1829 					if (mapping.pointer.aim_mouse1    )	pollmap[MOUSE1        ].insert(id);
1830 					if (mapping.pointer.aim_scope     )	pollmap[SUPERSCOPE    ].insert(id);
1831 					if (mapping.pointer.aim_justifier0)	pollmap[ONE_JUSTIFIER ].insert(id);
1832 					if (mapping.pointer.aim_justifier1)	pollmap[TWO_JUSTIFIERS].insert(id);
1833 					if (mapping.pointer.aim_macsrifle )	pollmap[MACSRIFLE     ].insert(id);
1834 					break;
1835 
1836 				case S9xPointerPort:
1837 					pollmap[POLL_ALL].insert(id);
1838 					break;
1839 			}
1840 		}
1841 	}
1842 
1843 	if (id >= PseudoPointerBase)
1844 		pseudopointer[id - PseudoPointerBase].mapped = true;
1845 
1846 	keymap[id] = mapping;
1847 
1848 	if (mapping.pointer.aim_mouse0    )	mouse[0].ID     = id;
1849 	if (mapping.pointer.aim_mouse1    )	mouse[1].ID     = id;
1850 	if (mapping.pointer.aim_scope     )	superscope.ID   = id;
1851 	if (mapping.pointer.aim_justifier0)	justifier.ID[0] = id;
1852 	if (mapping.pointer.aim_justifier1)	justifier.ID[1] = id;
1853 	if (mapping.pointer.aim_macsrifle )	macsrifle.ID    = id;
1854 
1855 	return (true);
1856 }
1857 
S9xReportPointer(uint32 id,int16 x,int16 y)1858 void S9xReportPointer (uint32 id, int16 x, int16 y)
1859 {
1860 	if (keymap.count(id) == 0)
1861 		return;
1862 
1863 	if (keymap[id].type == S9xNoMapping)
1864 		return;
1865 
1866 	if (maptype(keymap[id].type) != MAP_POINTER)
1867 	{
1868 		fprintf(stderr, "ERROR: S9xReportPointer called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
1869 		return;
1870 	}
1871 
1872 	S9xApplyCommand(keymap[id], x, y);
1873 }
1874 
S9xMapAxis(uint32 id,s9xcommand_t mapping,bool poll)1875 bool S9xMapAxis (uint32 id, s9xcommand_t mapping, bool poll)
1876 {
1877 	int	t;
1878 
1879 	if (id == InvalidControlID)
1880 	{
1881 		fprintf(stderr, "Cannot map InvalidControlID\n");
1882 		return (false);
1883 	}
1884 
1885 	t = maptype(mapping.type);
1886 
1887 	if (t == MAP_NONE)
1888 	{
1889 		S9xUnmapID(id);
1890 		return (true);
1891 	}
1892 
1893 	if (t != MAP_AXIS)
1894 		return (false);
1895 
1896 	t = maptype(S9xGetMapping(id).type);
1897 
1898 	if (t != MAP_NONE && t != MAP_AXIS)
1899 		fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to axis\n", id, maptypename(t));
1900 
1901 	if (id >= PseudoPointerBase)
1902 	{
1903 		fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as an axis\n", id - PseudoPointerBase);
1904 		return (false);
1905 	}
1906 
1907 	t = -1;
1908 
1909 	if (poll)
1910 	{
1911 		switch (mapping.type)
1912 		{
1913 			case S9xAxisJoypad:
1914 				t = JOYPAD0 + mapping.axis.joypad.idx;
1915 				break;
1916 
1917 			case S9xAxisPseudopointer:
1918 			case S9xAxisPseudobuttons:
1919 			case S9xAxisPort:
1920 				t=POLL_ALL;
1921 				break;
1922 		}
1923 	}
1924 
1925 	S9xUnmapID(id);
1926 
1927 	keymap[id] = mapping;
1928 
1929 	if (t >= 0)
1930 		pollmap[t].insert(id);
1931 
1932 	return (true);
1933 }
1934 
S9xReportAxis(uint32 id,int16 value)1935 void S9xReportAxis (uint32 id, int16 value)
1936 {
1937 	if (keymap.count(id) == 0)
1938 		return;
1939 
1940 	if (keymap[id].type == S9xNoMapping)
1941 		return;
1942 
1943 	if (maptype(keymap[id].type) != MAP_AXIS)
1944 	{
1945 		fprintf(stderr, "ERROR: S9xReportAxis called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id);
1946 		return;
1947 	}
1948 
1949 	S9xApplyCommand(keymap[id], value, 0);
1950 }
1951 
ApplyMulti(s9xcommand_t * multi,int32 pos,int16 data1)1952 static int32 ApplyMulti (s9xcommand_t *multi, int32 pos, int16 data1)
1953 {
1954 	while (1)
1955 	{
1956 		if (multi[pos].multi_press == 3)
1957 			return (-1);
1958 
1959 		if (multi[pos].type == S9xNoMapping)
1960 			break;
1961 
1962 		if (multi[pos].multi_press)
1963 			S9xApplyCommand(multi[pos], multi[pos].multi_press == 1, 0);
1964 		else
1965 			S9xApplyCommand(multi[pos], data1, 0);
1966 
1967 		pos++;
1968 	}
1969 
1970 	return (pos + 1);
1971 }
1972 
S9xApplyCommand(s9xcommand_t cmd,int16 data1,int16 data2)1973 void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
1974 {
1975 	int	i;
1976 
1977 	switch (cmd.type)
1978 	{
1979 		case S9xNoMapping:
1980 			return;
1981 
1982 		case S9xButtonJoypad:
1983 			if (cmd.button.joypad.toggle)
1984 			{
1985 				if (!data1)
1986 					return;
1987 
1988 				uint16	r = cmd.button.joypad.buttons;
1989 
1990 				if (cmd.button.joypad.turbo)	joypad[cmd.button.joypad.idx].toggleturbo ^= r;
1991 				if (cmd.button.joypad.sticky)	joypad[cmd.button.joypad.idx].togglestick ^= r;
1992 			}
1993 			else
1994 			{
1995 				uint16	r, s, t, st;
1996 
1997 				r = cmd.button.joypad.buttons;
1998 				st = r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo;
1999 				r ^= st;
2000 				t  = r & joypad[cmd.button.joypad.idx].toggleturbo;
2001 				r ^= t;
2002 				s  = r & joypad[cmd.button.joypad.idx].togglestick;
2003 				r ^= s;
2004 
2005 				if (cmd.button.joypad.turbo && cmd.button.joypad.sticky)
2006 				{
2007 					uint16	x = r; r = st; st = x;
2008 					x = s; s = t; t = x;
2009 				}
2010 				else
2011 				if (cmd.button.joypad.turbo)
2012 				{
2013 					uint16	x = r; r = t; t = x;
2014 					x = s; s = st; st = x;
2015 				}
2016 				else
2017 				if (cmd.button.joypad.sticky)
2018 				{
2019 					uint16	x = r; r = s; s = x;
2020 					x = t; t = st; st = x;
2021 				}
2022 
2023 				if (data1)
2024 				{
2025 					if (!Settings.UpAndDown && !S9xMoviePlaying()) // if up+down isn't allowed AND we are NOT playing a movie,
2026 					{
2027 						if (cmd.button.joypad.buttons & (SNES_LEFT_MASK | SNES_RIGHT_MASK))
2028 						{
2029 							// if we're pressing left or right, then unpress and unturbo them both first
2030 							// so we don't end up hittnig left AND right accidentally.
2031 							// Note though that the user can still do it on purpose, if Settings.UpAndDown = true.
2032 							// This is a feature, look up glitches in tLoZ:aLttP to find out why.
2033 							joypad[cmd.button.joypad.idx].buttons &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
2034 							joypad[cmd.button.joypad.idx].turbos  &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
2035 						}
2036 
2037 						if (cmd.button.joypad.buttons & (SNES_UP_MASK | SNES_DOWN_MASK))
2038 						{
2039 							// and ditto for up/down
2040 							joypad[cmd.button.joypad.idx].buttons &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
2041 							joypad[cmd.button.joypad.idx].turbos  &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
2042 						}
2043 					}
2044 
2045 					joypad[cmd.button.joypad.idx].buttons |= r;
2046 					joypad[cmd.button.joypad.idx].turbos  |= t;
2047 					joypad[cmd.button.joypad.idx].buttons ^= s;
2048 					joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & st);
2049 					joypad[cmd.button.joypad.idx].turbos  ^= st;
2050 				}
2051 				else
2052 				{
2053 					joypad[cmd.button.joypad.idx].buttons &= ~r;
2054 					joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & t);
2055 					joypad[cmd.button.joypad.idx].turbos  &= ~t;
2056 				}
2057 			}
2058 
2059 			return;
2060 
2061 		case S9xButtonMouse:
2062 			i = 0;
2063 			if (cmd.button.mouse.left )	i |= 0x40;
2064 			if (cmd.button.mouse.right)	i |= 0x80;
2065 
2066 			if (data1)
2067 				mouse[cmd.button.mouse.idx].buttons |=  i;
2068 			else
2069 				mouse[cmd.button.mouse.idx].buttons &= ~i;
2070 
2071 			return;
2072 
2073 		case S9xButtonSuperscope:
2074 			i = 0;
2075 			if (cmd.button.scope.fire         )	i |= SUPERSCOPE_FIRE;
2076 			if (cmd.button.scope.cursor       )	i |= SUPERSCOPE_CURSOR;
2077 			if (cmd.button.scope.pause        )	i |= SUPERSCOPE_PAUSE;
2078 			if (cmd.button.scope.aim_offscreen)	i |= SUPERSCOPE_OFFSCREEN;
2079 
2080 			if (data1)
2081 			{
2082 				superscope.phys_buttons |= i;
2083 
2084 				if (cmd.button.scope.turbo)
2085 				{
2086 					superscope.phys_buttons ^= SUPERSCOPE_TURBO;
2087 
2088 					if (superscope.phys_buttons & SUPERSCOPE_TURBO)
2089 						superscope.next_buttons |= superscope.phys_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
2090 					else
2091 						superscope.next_buttons &= ~(SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
2092 				}
2093 
2094 				superscope.next_buttons |= i & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR | SUPERSCOPE_PAUSE);
2095 
2096 				if (!S9xMovieActive()) // PPU modification during non-recordable command screws up movie synchronization
2097 					if ((superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) && curcontrollers[1] == SUPERSCOPE && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN))
2098 						DoGunLatch(superscope.x, superscope.y);
2099 			}
2100 			else
2101 			{
2102 				superscope.phys_buttons &= ~i;
2103 				superscope.next_buttons &= SUPERSCOPE_OFFSCREEN | ~i;
2104 			}
2105 
2106 			return;
2107 
2108 		case S9xButtonJustifier:
2109 			i = 0;
2110 			if (cmd.button.justifier.trigger)	i |= JUSTIFIER_TRIGGER;
2111 			if (cmd.button.justifier.start  )	i |= JUSTIFIER_START;
2112 			if (cmd.button.justifier.aim_offscreen)	justifier.offscreen[cmd.button.justifier.idx] = data1 ? 1 : 0;
2113 			i >>= cmd.button.justifier.idx;
2114 
2115 			if (data1)
2116 				justifier.buttons |=  i;
2117 			else
2118 				justifier.buttons &= ~i;
2119 
2120 			return;
2121 
2122 		case S9xButtonMacsRifle:
2123 			i = 0;
2124 			if (cmd.button.macsrifle.trigger) i |= MACSRIFLE_TRIGGER;
2125 
2126 			if(data1)
2127 				macsrifle.buttons |= i;
2128 			else
2129 				macsrifle.buttons &= ~i;
2130 
2131 			return;
2132 
2133 		case S9xButtonCommand:
2134 			if (((enum command_numbers) cmd.button.command) >= LAST_COMMAND)
2135 			{
2136 				fprintf(stderr, "Unknown command %04x\n", cmd.button.command);
2137 				return;
2138 			}
2139 
2140 			if (!data1)
2141 			{
2142 				switch (i = cmd.button.command)
2143 				{
2144 					case EmuTurbo:
2145 						Settings.TurboMode = FALSE;
2146 						break;
2147 				}
2148 			}
2149 			else
2150 			{
2151 				switch ((enum command_numbers) (i = cmd.button.command))
2152 				{
2153 					case ExitEmu:
2154 						S9xExit();
2155 						break;
2156 
2157 					case Reset:
2158 						S9xReset();
2159 						break;
2160 
2161 					case SoftReset:
2162 						S9xMovieUpdateOnReset();
2163 						if (S9xMoviePlaying())
2164 							S9xMovieStop(TRUE);
2165 						S9xSoftReset();
2166 						break;
2167 
2168 					case EmuTurbo:
2169 						Settings.TurboMode = TRUE;
2170 						break;
2171 
2172 					case ToggleEmuTurbo:
2173 						Settings.TurboMode = !Settings.TurboMode;
2174 						DisplayStateChange("Turbo mode", Settings.TurboMode);
2175 						break;
2176 
2177 					case ClipWindows:
2178 						Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows;
2179 						DisplayStateChange("Graphic clip windows", !Settings.DisableGraphicWindows);
2180 						break;
2181 
2182 					case Debugger:
2183 					#ifdef DEBUGGER
2184 						CPU.Flags |= DEBUG_MODE_FLAG;
2185 					#endif
2186 						break;
2187 
2188 					case IncFrameRate:
2189 						if (Settings.SkipFrames == AUTO_FRAMERATE)
2190 							Settings.SkipFrames = 1;
2191 						else
2192 						if (Settings.SkipFrames < 10)
2193 							Settings.SkipFrames++;
2194 
2195 						if (Settings.SkipFrames == AUTO_FRAMERATE)
2196 							S9xSetInfoString("Auto frame skip");
2197 						else
2198 						{
2199 							sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
2200 							S9xSetInfoString(buf);
2201 						}
2202 
2203 						break;
2204 
2205 					case DecFrameRate:
2206 						if (Settings.SkipFrames <= 1)
2207 							Settings.SkipFrames = AUTO_FRAMERATE;
2208 						else
2209 						if (Settings.SkipFrames != AUTO_FRAMERATE)
2210 							Settings.SkipFrames--;
2211 
2212 						if (Settings.SkipFrames == AUTO_FRAMERATE)
2213 							S9xSetInfoString("Auto frame skip");
2214 						else
2215 						{
2216 							sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
2217 							S9xSetInfoString(buf);
2218 						}
2219 
2220 						break;
2221 
2222 					case IncEmuTurbo:
2223 						if (Settings.TurboSkipFrames < 20)
2224 							Settings.TurboSkipFrames += 1;
2225 						else
2226 						if (Settings.TurboSkipFrames < 200)
2227 							Settings.TurboSkipFrames += 5;
2228 						sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
2229 						S9xSetInfoString(buf);
2230 						break;
2231 
2232 					case DecEmuTurbo:
2233 						if (Settings.TurboSkipFrames > 20)
2234 							Settings.TurboSkipFrames -= 5;
2235 						else
2236 						if (Settings.TurboSkipFrames > 0)
2237 							Settings.TurboSkipFrames -= 1;
2238 						sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
2239 						S9xSetInfoString(buf);
2240 						break;
2241 
2242 					case IncFrameTime: // Increase emulated frame time by 1ms
2243 						Settings.FrameTime += 1000;
2244 						sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
2245 						S9xSetInfoString(buf);
2246 						break;
2247 
2248 					case DecFrameTime: // Decrease emulated frame time by 1ms
2249 						if (Settings.FrameTime >= 1000)
2250 							Settings.FrameTime -= 1000;
2251 						sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
2252 						S9xSetInfoString(buf);
2253 						break;
2254 
2255 					case IncTurboSpeed:
2256 						if (turbo_time >= 120)
2257 							break;
2258 						turbo_time++;
2259 						sprintf(buf, "Turbo speed: %d", turbo_time);
2260 						S9xSetInfoString(buf);
2261 						break;
2262 
2263 					case DecTurboSpeed:
2264 						if (turbo_time <= 1)
2265 							break;
2266 						turbo_time--;
2267 						sprintf(buf, "Turbo speed: %d", turbo_time);
2268 						S9xSetInfoString(buf);
2269 						break;
2270 
2271 					case LoadFreezeFile:
2272 						S9xUnfreezeGame(S9xChooseFilename(TRUE));
2273 						break;
2274 
2275 					case SaveFreezeFile:
2276 						S9xFreezeGame(S9xChooseFilename(FALSE));
2277 						break;
2278 
2279 					case LoadOopsFile:
2280 					{
2281 						char	filename[PATH_MAX + 1];
2282 						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2283 
2284 						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2285 						snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
2286 
2287 						if (S9xUnfreezeGame(filename))
2288 						{
2289 							snprintf(buf, 256, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops");
2290 							S9xSetInfoString (buf);
2291 						}
2292 						else
2293 							S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Oops file not found");
2294 
2295 						break;
2296 					}
2297 
2298 					case Pause:
2299 						Settings.Paused = !Settings.Paused;
2300 						DisplayStateChange("Pause", Settings.Paused);
2301 					#if defined(NETPLAY_SUPPORT) && !defined(__WIN32__)
2302 						S9xNPSendPause(Settings.Paused);
2303 					#endif
2304 						break;
2305 
2306 					case QuickLoad000:
2307 					case QuickLoad001:
2308 					case QuickLoad002:
2309 					case QuickLoad003:
2310 					case QuickLoad004:
2311 					case QuickLoad005:
2312 					case QuickLoad006:
2313 					case QuickLoad007:
2314 					case QuickLoad008:
2315 					case QuickLoad009:
2316 					case QuickLoad010:
2317 					{
2318 						char	filename[PATH_MAX + 1];
2319 						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2320 
2321 						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2322 						snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickLoad000);
2323 
2324 						if (S9xUnfreezeGame(filename))
2325 						{
2326 							snprintf(buf, 256, "%s.%03d loaded", def, i - QuickLoad000);
2327 							S9xSetInfoString(buf);
2328 						}
2329 						else
2330 							S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Freeze file not found");
2331 
2332 						break;
2333 					}
2334 
2335 					case QuickSave000:
2336 					case QuickSave001:
2337 					case QuickSave002:
2338 					case QuickSave003:
2339 					case QuickSave004:
2340 					case QuickSave005:
2341 					case QuickSave006:
2342 					case QuickSave007:
2343 					case QuickSave008:
2344 					case QuickSave009:
2345 					case QuickSave010:
2346 					{
2347 						char	filename[PATH_MAX + 1];
2348 						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
2349 
2350 						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
2351 						snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000);
2352 
2353 						snprintf(buf, 256, "%s.%03d saved", def, i - QuickSave000);
2354 						S9xSetInfoString(buf);
2355 
2356 						S9xFreezeGame(filename);
2357 						break;
2358 					}
2359 
2360 					case SaveSPC:
2361 						S9xDumpSPCSnapshot();
2362 						break;
2363 
2364 					case Screenshot:
2365 						Settings.TakeScreenshot = TRUE;
2366 						break;
2367 
2368 					case SoundChannel0:
2369 					case SoundChannel1:
2370 					case SoundChannel2:
2371 					case SoundChannel3:
2372 					case SoundChannel4:
2373 					case SoundChannel5:
2374 					case SoundChannel6:
2375 					case SoundChannel7:
2376 						S9xToggleSoundChannel(i - SoundChannel0);
2377 						sprintf(buf, "Sound channel %d toggled", i - SoundChannel0);
2378 						S9xSetInfoString(buf);
2379 						break;
2380 
2381 					case SoundChannelsOn:
2382 						S9xToggleSoundChannel(8);
2383 						S9xSetInfoString("All sound channels on");
2384 						break;
2385 
2386 					case ToggleBG0:
2387 						Settings.BG_Forced ^= 1;
2388 						DisplayStateChange("BG#0", !(Settings.BG_Forced & 1));
2389 						break;
2390 
2391 					case ToggleBG1:
2392 						Settings.BG_Forced ^= 2;
2393 						DisplayStateChange("BG#1", !(Settings.BG_Forced & 2));
2394 						break;
2395 
2396 					case ToggleBG2:
2397 						Settings.BG_Forced ^= 4;
2398 						DisplayStateChange("BG#2", !(Settings.BG_Forced & 4));
2399 						break;
2400 
2401 					case ToggleBG3:
2402 						Settings.BG_Forced ^= 8;
2403 						DisplayStateChange("BG#3", !(Settings.BG_Forced & 8));
2404 						break;
2405 
2406 					case ToggleSprites:
2407 						Settings.BG_Forced ^= 16;
2408 						DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
2409 						break;
2410 
2411 					case ToggleTransparency:
2412 						Settings.Transparency = !Settings.Transparency;
2413 						DisplayStateChange("Transparency effects", Settings.Transparency);
2414 						break;
2415 
2416 					case BeginRecordingMovie:
2417 						if (S9xMovieActive())
2418 							S9xMovieStop(FALSE);
2419 						S9xMovieCreate(S9xChooseMovieFilename(FALSE), 0xFF, MOVIE_OPT_FROM_RESET, NULL, 0);
2420 						break;
2421 
2422 					case LoadMovie:
2423 						if (S9xMovieActive())
2424 							S9xMovieStop(FALSE);
2425 						S9xMovieOpen(S9xChooseMovieFilename(TRUE), FALSE);
2426 						break;
2427 
2428 					case EndRecordingMovie:
2429 						if (S9xMovieActive())
2430 							S9xMovieStop(FALSE);
2431 						break;
2432 
2433 					case SwapJoypads:
2434 						if ((curcontrollers[0] != NONE && !(curcontrollers[0] >= JOYPAD0 && curcontrollers[0] <= JOYPAD7)))
2435 						{
2436 							S9xSetInfoString("Cannot swap pads: port 1 is not a joypad");
2437 							break;
2438 						}
2439 
2440 						if ((curcontrollers[1] != NONE && !(curcontrollers[1] >= JOYPAD0 && curcontrollers[1] <= JOYPAD7)))
2441 						{
2442 							S9xSetInfoString("Cannot swap pads: port 2 is not a joypad");
2443 							break;
2444 						}
2445 
2446 #ifdef NETPLAY_SUPPORT
2447 						if (Settings.NetPlay && data2 != 1) { //data2 == 1 means it's sent by the netplay code
2448 							if (Settings.NetPlayServer) {
2449 								S9xNPSendJoypadSwap();
2450 							} else {
2451 								S9xSetInfoString("Netplay Client cannot swap pads.");
2452 								break;
2453 							}
2454 						}
2455 #endif
2456 
2457 						newcontrollers[1] = curcontrollers[0];
2458 						newcontrollers[0] = curcontrollers[1];
2459 
2460 						strcpy(buf, "Swap pads: P1=");
2461 						i = 14;
2462 						if (newcontrollers[0] == NONE)
2463 						{
2464 							strcpy(buf + i, "<none>");
2465 							i += 6;
2466 						}
2467 						else
2468 						{
2469 							sprintf(buf + i, "Joypad%d", newcontrollers[0] - JOYPAD0 + 1);
2470 							i += 7;
2471 						}
2472 
2473 						strcpy(buf + i, " P2=");
2474 						i += 4;
2475 						if (newcontrollers[1] == NONE)
2476 							strcpy(buf + i, "<none>");
2477 						else
2478 							sprintf(buf + i, "Joypad%d", newcontrollers[1] - JOYPAD0 + 1);
2479 
2480 						S9xSetInfoString(buf);
2481 						break;
2482 
2483 					case SeekToFrame:
2484 						if (S9xMovieActive())
2485 						{
2486 							sprintf(buf, "Select frame number (current: %d)", S9xMovieGetFrameCounter());
2487 							const char	*frameno = S9xStringInput(buf);
2488 							if (!frameno)
2489 								return;
2490 
2491 							int	frameDest = atoi(frameno);
2492 							if (frameDest > 0 && frameDest > (int) S9xMovieGetFrameCounter())
2493 							{
2494 								int	distance = frameDest - S9xMovieGetFrameCounter();
2495 								Settings.HighSpeedSeek = distance;
2496 							}
2497 						}
2498 
2499 						break;
2500 
2501 					case LAST_COMMAND:
2502 						break;
2503 				}
2504 			}
2505 
2506 			return;
2507 
2508 		case S9xPointer:
2509 			if (cmd.pointer.aim_mouse0)
2510 			{
2511 				mouse[0].cur_x = data1;
2512 				mouse[0].cur_y = data2;
2513 			}
2514 
2515 			if (cmd.pointer.aim_mouse1)
2516 			{
2517 				mouse[1].cur_x = data1;
2518 				mouse[1].cur_y = data2;
2519 			}
2520 
2521 			if (cmd.pointer.aim_scope)
2522 			{
2523 				superscope.x   = data1;
2524 				superscope.y   = data2;
2525 			}
2526 
2527 			if (cmd.pointer.aim_justifier0)
2528 			{
2529 				justifier.x[0] = data1;
2530 				justifier.y[0] = data2;
2531 			}
2532 
2533 			if (cmd.pointer.aim_justifier1)
2534 			{
2535 				justifier.x[1] = data1;
2536 				justifier.y[1] = data2;
2537 			}
2538 
2539 			if (cmd.pointer.aim_macsrifle)
2540 			{
2541 				macsrifle.x = data1;
2542 				macsrifle.y = data2;
2543 			}
2544 
2545 			return;
2546 
2547 		case S9xButtonPseudopointer:
2548 			if (data1)
2549 			{
2550 				if (cmd.button.pointer.UD)
2551 				{
2552 					if (!pseudopointer[cmd.button.pointer.idx].V_adj)
2553 						pseudopointer[cmd.button.pointer.idx].V_adj = cmd.button.pointer.UD * ptrspeeds[cmd.button.pointer.speed_type];
2554 					pseudopointer[cmd.button.pointer.idx].V_var = (cmd.button.pointer.speed_type == 0);
2555 				}
2556 
2557 				if (cmd.button.pointer.LR)
2558 				{
2559 					if (!pseudopointer[cmd.button.pointer.idx].H_adj)
2560 						pseudopointer[cmd.button.pointer.idx].H_adj = cmd.button.pointer.LR * ptrspeeds[cmd.button.pointer.speed_type];
2561 					pseudopointer[cmd.button.pointer.idx].H_var = (cmd.button.pointer.speed_type == 0);
2562 				}
2563 			}
2564 			else
2565 			{
2566 				if (cmd.button.pointer.UD)
2567 				{
2568 					pseudopointer[cmd.button.pointer.idx].V_adj = 0;
2569 					pseudopointer[cmd.button.pointer.idx].V_var = false;
2570 				}
2571 
2572 				if (cmd.button.pointer.LR)
2573 				{
2574 					pseudopointer[cmd.button.pointer.idx].H_adj = 0;
2575 					pseudopointer[cmd.button.pointer.idx].H_var = false;
2576 				}
2577 			}
2578 
2579 			return;
2580 
2581 		case S9xAxisJoypad:
2582 		{
2583 			uint16	pos, neg;
2584 
2585 			switch (cmd.axis.joypad.axis)
2586 			{
2587 				case 0: neg = SNES_LEFT_MASK;	pos = SNES_RIGHT_MASK;	break;
2588 				case 1: neg = SNES_UP_MASK;		pos = SNES_DOWN_MASK;	break;
2589 				case 2: neg = SNES_Y_MASK;		pos = SNES_A_MASK;		break;
2590 				case 3: neg = SNES_X_MASK;		pos = SNES_B_MASK;		break;
2591 				case 4: neg = SNES_TL_MASK;		pos = SNES_TR_MASK;		break;
2592 				default: return;
2593 			}
2594 
2595 			if (cmd.axis.joypad.invert)
2596 				data1 = -data1;
2597 
2598 			uint16	p, r;
2599 
2600 			p = r = 0;
2601 			if (data1 >  ((cmd.axis.joypad.threshold + 1) *  127))
2602 				p |= pos;
2603 			else
2604 				r |= pos;
2605 
2606 			if (data1 <= ((cmd.axis.joypad.threshold + 1) * -127))
2607 				p |= neg;
2608 			else
2609 				r |= neg;
2610 
2611 			joypad[cmd.axis.joypad.idx].buttons |= p;
2612 			joypad[cmd.axis.joypad.idx].buttons &= ~r;
2613 			joypad[cmd.axis.joypad.idx].turbos  &= ~(p | r);
2614 
2615 			return;
2616 		}
2617 
2618 		case S9xAxisPseudopointer:
2619 			if (data1 == 0)
2620 			{
2621 				if (cmd.axis.pointer.HV)
2622 				{
2623 					pseudopointer[cmd.axis.pointer.idx].V_adj = 0;
2624 					pseudopointer[cmd.axis.pointer.idx].V_var = false;
2625 				}
2626 				else
2627 				{
2628 					pseudopointer[cmd.axis.pointer.idx].H_adj = 0;
2629 					pseudopointer[cmd.axis.pointer.idx].H_var = false;
2630 				}
2631 			}
2632 			else
2633 			{
2634 				if (cmd.axis.pointer.invert)
2635 					data1 = -data1;
2636 
2637 				if (cmd.axis.pointer.HV)
2638 				{
2639 					if (!pseudopointer[cmd.axis.pointer.idx].V_adj)
2640 						pseudopointer[cmd.axis.pointer.idx].V_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767);
2641 					pseudopointer[cmd.axis.pointer.idx].V_var = (cmd.axis.pointer.speed_type == 0);
2642 				}
2643 				else
2644 				{
2645 					if (!pseudopointer[cmd.axis.pointer.idx].H_adj)
2646 						pseudopointer[cmd.axis.pointer.idx].H_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767);
2647 					pseudopointer[cmd.axis.pointer.idx].H_var = (cmd.axis.pointer.speed_type == 0);
2648 				}
2649 			}
2650 
2651 			return;
2652 
2653 		case S9xAxisPseudobuttons:
2654 			if (data1 >  ((cmd.axis.button.threshold + 1) *  127))
2655 			{
2656 				if (!pseudobuttons[cmd.axis.button.posbutton])
2657 				{
2658 					pseudobuttons[cmd.axis.button.posbutton] = 1;
2659 					S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, true);
2660 				}
2661 			}
2662 			else
2663 			{
2664 				if (pseudobuttons[cmd.axis.button.posbutton])
2665 				{
2666 					pseudobuttons[cmd.axis.button.posbutton] = 0;
2667 					S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, false);
2668 				}
2669 			}
2670 
2671 			if (data1 <= ((cmd.axis.button.threshold + 1) * -127))
2672 			{
2673 				if (!pseudobuttons[cmd.axis.button.negbutton])
2674 				{
2675 					pseudobuttons[cmd.axis.button.negbutton] = 1;
2676 					S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, true);
2677 				}
2678 			}
2679 			else
2680 			{
2681 				if (pseudobuttons[cmd.axis.button.negbutton])
2682 				{
2683 					pseudobuttons[cmd.axis.button.negbutton] = 0;
2684 					S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, false);
2685 				}
2686 			}
2687 
2688 			return;
2689 
2690 		case S9xButtonPort:
2691 		case S9xAxisPort:
2692 		case S9xPointerPort:
2693 			S9xHandlePortCommand(cmd, data1, data2);
2694 			return;
2695 
2696 		case S9xButtonMulti:
2697 			if (cmd.button.multi_idx >= (int) multis.size())
2698 				return;
2699 
2700 			if (multis[cmd.button.multi_idx]->multi_press && !data1)
2701 				return;
2702 
2703 			i = ApplyMulti(multis[cmd.button.multi_idx], 0, data1);
2704 			if (i >= 0)
2705 			{
2706 				struct exemulti	*e = new struct exemulti;
2707 				e->pos    = i;
2708 				e->data1  = data1 != 0;
2709 				e->script = multis[cmd.button.multi_idx];
2710 				exemultis.insert(e);
2711 			}
2712 
2713 			return;
2714 
2715 		default:
2716 			fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type);
2717 			return;
2718 	}
2719 }
2720 
do_polling(int mp)2721 static void do_polling (int mp)
2722 {
2723 	set<uint32>::iterator	itr;
2724 
2725 	if (S9xMoviePlaying())
2726 		return;
2727 
2728 	if (pollmap[mp].empty())
2729 		return;
2730 
2731 	for (itr = pollmap[mp].begin(); itr != pollmap[mp].end(); itr++)
2732 	{
2733 		switch (maptype(keymap[*itr].type))
2734 		{
2735 			case MAP_BUTTON:
2736 			{
2737 				bool	pressed = false;
2738 				if (S9xPollButton(*itr, &pressed))
2739 					S9xReportButton(*itr, pressed);
2740 				break;
2741 			}
2742 
2743 			case MAP_AXIS:
2744 			{
2745 				int16	value = 0;
2746 				if (S9xPollAxis(*itr, &value))
2747 					S9xReportAxis(*itr, value);
2748 				break;
2749 			}
2750 
2751 			case MAP_POINTER:
2752 			{
2753 				int16	x = 0, y = 0;
2754 				if (S9xPollPointer(*itr, &x, &y))
2755 					S9xReportPointer(*itr, x, y);
2756 				break;
2757 			}
2758 
2759 			default:
2760 				break;
2761 		}
2762 	}
2763 }
2764 
UpdatePolledMouse(int i)2765 static void UpdatePolledMouse (int i)
2766 {
2767 	int16	j;
2768 
2769 	j = mouse[i - MOUSE0].cur_x - mouse[i - MOUSE0].old_x;
2770 
2771 	if (j < -127)
2772 	{
2773 		mouse[i - MOUSE0].delta_x = 0xff;
2774 		mouse[i - MOUSE0].old_x -= 127;
2775 	}
2776 	else
2777 	if (j < 0)
2778 	{
2779 		mouse[i - MOUSE0].delta_x = 0x80 | -j;
2780 		mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x;
2781 	}
2782 	else
2783 	if (j > 127)
2784 	{
2785 		mouse[i - MOUSE0].delta_x = 0x7f;
2786 		mouse[i - MOUSE0].old_x += 127;
2787 	}
2788 	else
2789 	{
2790 		mouse[i - MOUSE0].delta_x = (uint8) j;
2791 		mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x;
2792 	}
2793 
2794 	j = mouse[i - MOUSE0].cur_y - mouse[i - MOUSE0].old_y;
2795 
2796 	if (j < -127)
2797 	{
2798 		mouse[i - MOUSE0].delta_y = 0xff;
2799 		mouse[i - MOUSE0].old_y -= 127;
2800 	}
2801 	else
2802 	if (j < 0)
2803 	{
2804 		mouse[i - MOUSE0].delta_y = 0x80 | -j;
2805 		mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y;
2806 	}
2807 	else
2808 	if (j > 127)
2809 	{
2810 		mouse[i - MOUSE0].delta_y = 0x7f;
2811 		mouse[i - MOUSE0].old_y += 127;
2812 	}
2813 	else
2814 	{
2815 		mouse[i - MOUSE0].delta_y = (uint8) j;
2816 		mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y;
2817 	}
2818 }
2819 
S9xSetJoypadLatch(bool latch)2820 void S9xSetJoypadLatch (bool latch)
2821 {
2822 	if (!latch && FLAG_LATCH)
2823 	{
2824 		// 1 written, 'plug in' new controllers now
2825 		curcontrollers[0] = newcontrollers[0];
2826 		curcontrollers[1] = newcontrollers[1];
2827 	}
2828 
2829 	if (latch && !FLAG_LATCH)
2830 	{
2831 		int	i;
2832 
2833 		for (int n = 0; n < 2; n++)
2834 		{
2835 			for (int j = 0; j < 2; j++)
2836 				read_idx[n][j] = 0;
2837 
2838 			switch (i = curcontrollers[n])
2839 			{
2840 				case MP5:
2841 					for (int j = 0, k; j < 4; ++j)
2842 					{
2843 						k = mp5[n].pads[j];
2844 						if (k == NONE)
2845 							continue;
2846 						do_polling(k);
2847 					}
2848 
2849 					break;
2850 
2851 				case JOYPAD0:
2852 				case JOYPAD1:
2853 				case JOYPAD2:
2854 				case JOYPAD3:
2855 				case JOYPAD4:
2856 				case JOYPAD5:
2857 				case JOYPAD6:
2858 				case JOYPAD7:
2859 					do_polling(i);
2860 					break;
2861 
2862 				case MOUSE0:
2863 				case MOUSE1:
2864 					do_polling(i);
2865 					if (!S9xMoviePlaying())
2866 						UpdatePolledMouse(i);
2867 					break;
2868 
2869 				case SUPERSCOPE:
2870 					if (superscope.next_buttons & SUPERSCOPE_FIRE)
2871 					{
2872 						superscope.next_buttons &= ~SUPERSCOPE_TURBO;
2873 						superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_TURBO;
2874 					}
2875 
2876 					if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR))
2877 					{
2878 						superscope.next_buttons &= ~SUPERSCOPE_OFFSCREEN;
2879 						superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_OFFSCREEN;
2880 					}
2881 
2882 					superscope.read_buttons = superscope.next_buttons;
2883 
2884 					superscope.next_buttons &= ~SUPERSCOPE_PAUSE;
2885 					if (!(superscope.phys_buttons & SUPERSCOPE_TURBO))
2886 						superscope.next_buttons &= ~(SUPERSCOPE_CURSOR | SUPERSCOPE_FIRE);
2887 
2888 					do_polling(i);
2889 					break;
2890 
2891 				case TWO_JUSTIFIERS:
2892 					do_polling(TWO_JUSTIFIERS);
2893 					// fall through
2894 
2895 				case ONE_JUSTIFIER:
2896 					justifier.buttons ^= JUSTIFIER_SELECT;
2897 					do_polling(ONE_JUSTIFIER);
2898 					break;
2899 
2900 				case MACSRIFLE:
2901 					do_polling(i);
2902 					break;
2903 
2904 				default:
2905 					break;
2906 			}
2907 		}
2908 	}
2909 
2910 	FLAG_LATCH = latch;
2911 }
2912 
2913 // prevent read_idx from overflowing (only latching resets it)
2914 // otherwise $4016/7 reads will start returning input data again
IncreaseReadIdxPost(uint8 & var)2915 static inline uint8 IncreaseReadIdxPost(uint8 &var)
2916 {
2917 	uint8 oldval = var;
2918 	if (var < 255)
2919 		var++;
2920 	return oldval;
2921 }
2922 
S9xReadJOYSERn(int n)2923 uint8 S9xReadJOYSERn (int n)
2924 {
2925 	int	i, j, r;
2926 
2927 	if (n > 1)
2928 		n -= 0x4016;
2929 	assert(n == 0 || n == 1);
2930 
2931 	uint8	bits = (OpenBus & ~3) | ((n == 1) ? 0x1c : 0);
2932 
2933 	if (FLAG_LATCH)
2934 	{
2935 		switch (i = curcontrollers[n])
2936 		{
2937 			case MP5:
2938 				return (bits | 2);
2939 
2940 			case JOYPAD0:
2941 			case JOYPAD1:
2942 			case JOYPAD2:
2943 			case JOYPAD3:
2944 			case JOYPAD4:
2945 			case JOYPAD5:
2946 			case JOYPAD6:
2947 			case JOYPAD7:
2948 				return (bits | ((joypad[i - JOYPAD0].buttons & 0x8000) ? 1 : 0));
2949 
2950 			case MOUSE0:
2951 			case MOUSE1:
2952 				mouse[i - MOUSE0].buttons += 0x10;
2953 				if ((mouse[i - MOUSE0].buttons & 0x30) == 0x30)
2954 					mouse[i - MOUSE0].buttons &= 0xcf;
2955 				return (bits);
2956 
2957 			case SUPERSCOPE:
2958 				return (bits | ((superscope.read_buttons & 0x80) ? 1 : 0));
2959 
2960 			case ONE_JUSTIFIER:
2961 			case TWO_JUSTIFIERS:
2962 				return (bits);
2963 
2964 			case MACSRIFLE:
2965 				do_polling(i);
2966 				return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0));
2967 
2968 			default:
2969 				return (bits);
2970 		}
2971 	}
2972 	else
2973 	{
2974 		switch (i = curcontrollers[n])
2975 		{
2976 			case MP5:
2977 				r = IncreaseReadIdxPost(read_idx[n][FLAG_IOBIT(n) ? 0 : 1]);
2978 				j = FLAG_IOBIT(n) ? 0 : 2;
2979 
2980 				for (i = 0; i < 2; i++, j++)
2981 				{
2982 					if (mp5[n].pads[j] == NONE)
2983 						continue;
2984 					if (r >= 16)
2985 						bits |= 1 << i;
2986 					else
2987 						bits |= ((joypad[mp5[n].pads[j] - JOYPAD0].buttons & (0x8000 >> r)) ? 1 : 0) << i;
2988 				}
2989 
2990 				return (bits);
2991 
2992 			case JOYPAD0:
2993 			case JOYPAD1:
2994 			case JOYPAD2:
2995 			case JOYPAD3:
2996 			case JOYPAD4:
2997 			case JOYPAD5:
2998 			case JOYPAD6:
2999 			case JOYPAD7:
3000 				if (read_idx[n][0] >= 16)
3001 				{
3002 					IncreaseReadIdxPost(read_idx[n][0]);
3003 					return (bits | 1);
3004 				}
3005 				else
3006 					return (bits | ((joypad[i - JOYPAD0].buttons & (0x8000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3007 
3008 			case MOUSE0:
3009 			case MOUSE1:
3010 				if (read_idx[n][0] < 8)
3011 				{
3012 					IncreaseReadIdxPost(read_idx[n][0]);
3013 					return (bits);
3014 				}
3015 				else
3016 				if (read_idx[n][0] < 16)
3017 					return (bits | ((mouse[i - MOUSE0].buttons & (0x8000     >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3018 				else
3019 				if (read_idx[n][0] < 24)
3020 					return (bits | ((mouse[i - MOUSE0].delta_y & (0x800000   >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3021 				else
3022 				if (read_idx[n][0] < 32)
3023 					return (bits | ((mouse[i - MOUSE0].delta_x & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3024 				else
3025 				{
3026 					IncreaseReadIdxPost(read_idx[n][0]);
3027 					return (bits | 1);
3028 				}
3029 
3030 			case SUPERSCOPE:
3031 				if (read_idx[n][0] < 8)
3032 					return (bits | ((superscope.read_buttons & (0x80 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3033 				else
3034 				{
3035 					IncreaseReadIdxPost(read_idx[n][0]);
3036 					return (bits | 1);
3037 				}
3038 
3039 			case ONE_JUSTIFIER:
3040 				if (read_idx[n][0] < 24)
3041 					return (bits | ((0xaa7000 >> IncreaseReadIdxPost(read_idx[n][0])) & 1));
3042 				else
3043 				if (read_idx[n][0] < 32)
3044 					return (bits | ((justifier.buttons & (JUSTIFIER_TRIGGER | JUSTIFIER_START | JUSTIFIER_SELECT) & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3045 				else
3046 				{
3047 					IncreaseReadIdxPost(read_idx[n][0]);
3048 					return (bits | 1);
3049 				}
3050 
3051 			case TWO_JUSTIFIERS:
3052 				if (read_idx[n][0] < 24)
3053 					return (bits | ((0xaa7000 >> IncreaseReadIdxPost(read_idx[n][0])) & 1));
3054 				else
3055 				if (read_idx[n][0] < 32)
3056 					return (bits | ((justifier.buttons & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0));
3057 				else
3058 				{
3059 					IncreaseReadIdxPost(read_idx[n][0]);
3060 					return (bits | 1);
3061 				}
3062 
3063 			case MACSRIFLE:
3064 				do_polling(i);
3065 				return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0));
3066 
3067 			default:
3068 				IncreaseReadIdxPost(read_idx[n][0]);
3069 				return (bits);
3070 		}
3071 	}
3072 }
3073 
S9xDoAutoJoypad(void)3074 void S9xDoAutoJoypad (void)
3075 {
3076 	int	i, j;
3077 
3078 	S9xSetJoypadLatch(1);
3079 	S9xSetJoypadLatch(0);
3080 
3081 	S9xMovieUpdate(false);
3082 
3083 	for (int n = 0; n < 2; n++)
3084 	{
3085 		switch (i = curcontrollers[n])
3086 		{
3087 			case MP5:
3088 				j = FLAG_IOBIT(n) ? 0 : 2;
3089 				for (i = 0; i < 2; i++, j++)
3090 				{
3091 					if (mp5[n].pads[j] == NONE)
3092 						WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, 0);
3093 					else
3094 						WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, joypad[mp5[n].pads[j] - JOYPAD0].buttons);
3095 				}
3096 
3097 				read_idx[n][FLAG_IOBIT(n) ? 0 : 1] = 16;
3098 				break;
3099 
3100 			case JOYPAD0:
3101 			case JOYPAD1:
3102 			case JOYPAD2:
3103 			case JOYPAD3:
3104 			case JOYPAD4:
3105 			case JOYPAD5:
3106 			case JOYPAD6:
3107 			case JOYPAD7:
3108 				read_idx[n][0] = 16;
3109 				WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, joypad[i - JOYPAD0].buttons);
3110 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3111 				break;
3112 
3113 			case MOUSE0:
3114 			case MOUSE1:
3115 				read_idx[n][0] = 16;
3116 				WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, mouse[i - MOUSE0].buttons);
3117 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3118 				break;
3119 
3120 			case SUPERSCOPE:
3121 				read_idx[n][0] = 16;
3122 				Memory.FillRAM[0x4218 + n * 2] = 0xff;
3123 				Memory.FillRAM[0x4219 + n * 2] = superscope.read_buttons;
3124 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3125 				break;
3126 
3127 			case ONE_JUSTIFIER:
3128 			case TWO_JUSTIFIERS:
3129 				read_idx[n][0] = 16;
3130 				WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0x000e);
3131 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3132 				break;
3133 
3134 			case MACSRIFLE:
3135 				read_idx[n][0] = 16;
3136 				Memory.FillRAM[0x4218 + n * 2] = 0xff;
3137 				Memory.FillRAM[0x4219 + n * 2] = macsrifle.buttons;
3138 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3139 				break;
3140 
3141 			default:
3142 				WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0);
3143 				WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0);
3144 				break;
3145 		}
3146 	}
3147 }
3148 
S9xControlEOF(void)3149 void S9xControlEOF (void)
3150 {
3151 	struct crosshair	*c;
3152 	int					i, j;
3153 
3154 	PPU.GunVLatch = 1000; // i.e., never latch
3155 	PPU.GunHLatch = 0;
3156 
3157 	for (int n = 0; n < 2; n++)
3158 	{
3159 		switch (i = curcontrollers[n])
3160 		{
3161 			case MP5:
3162 				for (j = 0; j < 4; ++j)
3163 				{
3164 					i = mp5[n].pads[j];
3165 					if (i == NONE)
3166 						continue;
3167 
3168 					if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time)
3169 					{
3170 						joypad[i - JOYPAD0].turbo_ct = 0;
3171 						joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos;
3172 					}
3173 				}
3174 
3175 				break;
3176 
3177 			case JOYPAD0:
3178 			case JOYPAD1:
3179 			case JOYPAD2:
3180 			case JOYPAD3:
3181 			case JOYPAD4:
3182 			case JOYPAD5:
3183 			case JOYPAD6:
3184 			case JOYPAD7:
3185 				if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time)
3186 				{
3187 					joypad[i - JOYPAD0].turbo_ct = 0;
3188 					joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos;
3189 				}
3190 
3191 				break;
3192 
3193 			case MOUSE0:
3194 			case MOUSE1:
3195 				c = &mouse[i - MOUSE0].crosshair;
3196 				if (IPPU.RenderThisFrame)
3197 					S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, mouse[i - MOUSE0].cur_x, mouse[i - MOUSE0].cur_y);
3198 				break;
3199 
3200 			case SUPERSCOPE:
3201 				if (n == 1 && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN))
3202 				{
3203 					if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR))
3204 						DoGunLatch(superscope.x, superscope.y);
3205 
3206 					c = &superscope.crosshair;
3207 					if (IPPU.RenderThisFrame)
3208 						S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, superscope.x, superscope.y);
3209 				}
3210 
3211 				break;
3212 
3213 			case TWO_JUSTIFIERS:
3214 				if (n == 1 && !justifier.offscreen[1])
3215 				{
3216 					c = &justifier.crosshair[1];
3217 					if (IPPU.RenderThisFrame)
3218 						S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[1], justifier.y[1]);
3219 				}
3220 
3221 				i = (justifier.buttons & JUSTIFIER_SELECT) ?  1 : 0;
3222 				goto do_justifier;
3223 
3224 			case ONE_JUSTIFIER:
3225 				i = (justifier.buttons & JUSTIFIER_SELECT) ? -1 : 0;
3226 
3227 			do_justifier:
3228 				if (n == 1)
3229 				{
3230 					if (i >= 0 && !justifier.offscreen[i])
3231 						DoGunLatch(justifier.x[i], justifier.y[i]);
3232 
3233 					if (!justifier.offscreen[0])
3234 					{
3235 						c = &justifier.crosshair[0];
3236 						if (IPPU.RenderThisFrame)
3237 							S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[0], justifier.y[0]);
3238 					}
3239 				}
3240 
3241 				break;
3242 
3243 			case MACSRIFLE:
3244 				if (n == 1)
3245 				{
3246 					DoMacsRifleLatch(macsrifle.x, macsrifle.y);
3247 
3248 					c = &macsrifle.crosshair;
3249 					if (IPPU.RenderThisFrame)
3250 						S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, macsrifle.x, macsrifle.y);
3251 				}
3252 
3253 				break;
3254 
3255 			default:
3256 				break;
3257 		}
3258 	}
3259 
3260 	for (int n = 0; n < 8; n++)
3261 	{
3262 		if (!pseudopointer[n].mapped)
3263 			continue;
3264 
3265 		if (pseudopointer[n].H_adj)
3266 		{
3267 			pseudopointer[n].x += pseudopointer[n].H_adj;
3268 			if (pseudopointer[n].x < 0)
3269 				pseudopointer[n].x = 0;
3270 			else
3271 			if (pseudopointer[n].x > 255)
3272 				pseudopointer[n].x = 255;
3273 
3274 			if (pseudopointer[n].H_var)
3275 			{
3276 				if (pseudopointer[n].H_adj < 0)
3277 				{
3278 					if (pseudopointer[n].H_adj > -ptrspeeds[3])
3279 						pseudopointer[n].H_adj--;
3280 				}
3281 				else
3282 				{
3283 					if (pseudopointer[n].H_adj <  ptrspeeds[3])
3284 						pseudopointer[n].H_adj++;
3285 				}
3286 			}
3287 		}
3288 
3289 		if (pseudopointer[n].V_adj)
3290 		{
3291 			pseudopointer[n].y += pseudopointer[n].V_adj;
3292 			if (pseudopointer[n].y < 0)
3293 				pseudopointer[n].y = 0;
3294 			else
3295 			if (pseudopointer[n].y > PPU.ScreenHeight - 1)
3296 				pseudopointer[n].y = PPU.ScreenHeight - 1;
3297 
3298 			if (pseudopointer[n].V_var)
3299 			{
3300 				if (pseudopointer[n].V_adj < 0)
3301 				{
3302 					if (pseudopointer[n].V_adj > -ptrspeeds[3])
3303 						pseudopointer[n].V_adj--;
3304 				}
3305 				else
3306 				{
3307 					if (pseudopointer[n].V_adj <  ptrspeeds[3])
3308 						pseudopointer[n].V_adj++;
3309 				}
3310 			}
3311 		}
3312 
3313 		S9xReportPointer(PseudoPointerBase + n, pseudopointer[n].x, pseudopointer[n].y);
3314 	}
3315 
3316 	set<struct exemulti *>::iterator	it, jt;
3317 
3318 	for (it = exemultis.begin(); it != exemultis.end(); it++)
3319 	{
3320 		i = ApplyMulti((*it)->script, (*it)->pos, (*it)->data1);
3321 
3322 		if (i >= 0)
3323 			(*it)->pos = i;
3324 		else
3325 		{
3326 			jt = it;
3327 			it--;
3328 			delete *jt;
3329 			exemultis.erase(jt);
3330 		}
3331 	}
3332 
3333 	do_polling(POLL_ALL);
3334 
3335 	pad_read_last = pad_read;
3336 	pad_read      = false;
3337 }
3338 
S9xSetControllerCrosshair(enum crosscontrols ctl,int8 idx,const char * fg,const char * bg)3339 void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg, const char *bg)
3340 {
3341 	struct crosshair	*c;
3342 	int8				fgcolor = -1, bgcolor = -1;
3343 	int					i, j;
3344 
3345 	if (idx < -1 || idx > 31)
3346 	{
3347 		fprintf(stderr, "S9xSetControllerCrosshair() called with invalid index\n");
3348 		return;
3349 	}
3350 
3351 	switch (ctl)
3352 	{
3353 		case X_MOUSE1:		c = &mouse[0].crosshair;		break;
3354 		case X_MOUSE2:		c = &mouse[1].crosshair;		break;
3355 		case X_SUPERSCOPE:	c = &superscope.crosshair;		break;
3356 		case X_JUSTIFIER1:	c = &justifier.crosshair[0];	break;
3357 		case X_JUSTIFIER2:	c = &justifier.crosshair[1];	break;
3358 		case X_MACSRIFLE:	c = &macsrifle.crosshair;		break;
3359 		default:
3360 			fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
3361 			return;
3362 	}
3363 
3364 	if (fg)
3365 	{
3366 		fgcolor = 0;
3367 		if (*fg == 't')
3368 		{
3369 			fg++;
3370 			fgcolor = 16;
3371 		}
3372 
3373 		for (i = 0; i < 16; i++)
3374 		{
3375 			for (j = 0; color_names[i][j] && fg[j] == color_names[i][j]; j++) ;
3376 
3377 			if (isalnum(fg[j]))
3378 				continue;
3379 
3380 			if (!color_names[i][j])
3381 				break;
3382 		}
3383 
3384 		fgcolor |= i;
3385 		if (i > 15 || fgcolor == 16)
3386 		{
3387 			fprintf(stderr, "S9xSetControllerCrosshair() called with invalid fgcolor\n");
3388 			return;
3389 		}
3390 	}
3391 
3392 	if (bg)
3393 	{
3394 		bgcolor = 0;
3395 		if (*bg == 't')
3396 		{
3397 			bg++;
3398 			bgcolor = 16;
3399 		}
3400 
3401 		for (i = 0; i < 16; i++)
3402 		{
3403 			for (j = 0; color_names[i][j] && bg[j] == color_names[i][j]; j++) ;
3404 
3405 			if (isalnum(bg[j]))
3406 				continue;
3407 
3408 			if (!color_names[i][j])
3409 				break;
3410 		}
3411 
3412 		bgcolor |= i;
3413 		if (i > 15 || bgcolor == 16)
3414 		{
3415 			fprintf(stderr, "S9xSetControllerCrosshair() called with invalid bgcolor\n");
3416 			return;
3417 		}
3418 	}
3419 
3420 	if (idx != -1)
3421 	{
3422 		c->set |= 1;
3423 		c->img = idx;
3424 	}
3425 
3426 	if (fgcolor != -1)
3427 	{
3428 		c->set |= 2;
3429 		c->fg = fgcolor;
3430 	}
3431 
3432 	if (bgcolor != -1)
3433 	{
3434 		c->set |= 4;
3435 		c->bg = bgcolor;
3436 	}
3437 }
3438 
S9xGetControllerCrosshair(enum crosscontrols ctl,int8 * idx,const char ** fg,const char ** bg)3439 void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg)
3440 {
3441 	struct crosshair	*c;
3442 
3443 	switch (ctl)
3444 	{
3445 		case X_MOUSE1:		c = &mouse[0].crosshair;		break;
3446 		case X_MOUSE2:		c = &mouse[1].crosshair;		break;
3447 		case X_SUPERSCOPE:	c = &superscope.crosshair;		break;
3448 		case X_JUSTIFIER1:	c = &justifier.crosshair[0];	break;
3449 		case X_JUSTIFIER2:	c = &justifier.crosshair[1];	break;
3450 		case X_MACSRIFLE:	c = &macsrifle.crosshair;		break;
3451 		default:
3452 			fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl);
3453 			return;
3454 	}
3455 
3456 	if (idx)
3457 		*idx = c->img;
3458 
3459 	if (fg)
3460 		*fg = color_names[c->fg];
3461 
3462 	if (bg)
3463 		*bg = color_names[c->bg];
3464 }
3465 
S9xControlPreSaveState(struct SControlSnapshot * s)3466 void S9xControlPreSaveState (struct SControlSnapshot *s)
3467 {
3468 	memset(s, 0, sizeof(*s));
3469 	s->ver = 4;
3470 
3471 	for (int j = 0; j < 2; j++)
3472 	{
3473 		s->port1_read_idx[j] = read_idx[0][j];
3474 		s->port2_read_idx[j] = read_idx[1][j];
3475 	}
3476 
3477 	for (int j = 0; j < 2; j++)
3478 		s->mouse_speed[j] = (mouse[j].buttons & 0x30) >> 4;
3479 
3480 	s->justifier_select = ((justifier.buttons & JUSTIFIER_SELECT) ? 1 : 0);
3481 
3482 #define COPY(x)	{ memcpy((char *) s->internal + i, &(x), sizeof(x)); i += sizeof(x); }
3483 
3484 	int	i = 0;
3485 
3486 	for (int j = 0; j < 8; j++)
3487 		COPY(joypad[j].buttons);
3488 
3489 	for (int j = 0; j < 2; j++)
3490 	{
3491 		COPY(mouse[j].delta_x);
3492 		COPY(mouse[j].delta_y);
3493 		COPY(mouse[j].old_x);
3494 		COPY(mouse[j].old_y);
3495 		COPY(mouse[j].cur_x);
3496 		COPY(mouse[j].cur_y);
3497 		COPY(mouse[j].buttons);
3498 	}
3499 
3500 	COPY(superscope.x);
3501 	COPY(superscope.y);
3502 	COPY(superscope.phys_buttons);
3503 	COPY(superscope.next_buttons);
3504 	COPY(superscope.read_buttons);
3505 
3506 	for (int j = 0; j < 2; j++)
3507 		COPY(justifier.x[j]);
3508 	for (int j = 0; j < 2; j++)
3509 		COPY(justifier.y[j]);
3510 	COPY(justifier.buttons);
3511 	for (int j = 0; j < 2; j++)
3512 		COPY(justifier.offscreen[j]);
3513 
3514 	for (int j = 0; j < 2; j++)
3515 		for (int k = 0; k < 2; k++)
3516 			COPY(mp5[j].pads[k]);
3517 
3518 	COPY(macsrifle.x);
3519 	COPY(macsrifle.y);
3520 	COPY(macsrifle.buttons);
3521 
3522 	assert(i == sizeof(s->internal) + sizeof(s->internal_macs));
3523 
3524 #undef COPY
3525 
3526 	s->pad_read      = pad_read;
3527 	s->pad_read_last = pad_read_last;
3528 }
3529 
S9xControlPostLoadState(struct SControlSnapshot * s)3530 void S9xControlPostLoadState (struct SControlSnapshot *s)
3531 {
3532 	if (curcontrollers[0] == MP5 && s->ver < 1)
3533 	{
3534 		// Crap. Old snes9x didn't support this.
3535 		S9xMessage(S9X_WARNING, S9X_FREEZE_FILE_INFO, "Old savestate has no support for MP5 in port 1.");
3536 		newcontrollers[0] = curcontrollers[0];
3537 		curcontrollers[0] = mp5[0].pads[0];
3538 	}
3539 
3540 	for (int j = 0; j < 2; j++)
3541 	{
3542 		read_idx[0][j] = s->port1_read_idx[j];
3543 		read_idx[1][j] = s->port2_read_idx[j];
3544 	}
3545 
3546 	for (int j = 0; j < 2; j++)
3547 		mouse[j].buttons |= (s->mouse_speed[j] & 3) << 4;
3548 
3549 	if (s->justifier_select & 1)
3550 		justifier.buttons |=  JUSTIFIER_SELECT;
3551 	else
3552 		justifier.buttons &= ~JUSTIFIER_SELECT;
3553 
3554 	FLAG_LATCH = (Memory.FillRAM[0x4016] & 1) == 1;
3555 
3556 	if (s->ver > 1)
3557 	{
3558 	#define COPY(x)	{ memcpy(&(x), (char *) s->internal + i, sizeof(x)); i += sizeof(x); }
3559 
3560 		int	i = 0;
3561 
3562 		for (int j = 0; j < 8; j++)
3563 			COPY(joypad[j].buttons);
3564 
3565 		for (int j = 0; j < 2; j++)
3566 		{
3567 			COPY(mouse[j].delta_x);
3568 			COPY(mouse[j].delta_y);
3569 			COPY(mouse[j].old_x);
3570 			COPY(mouse[j].old_y);
3571 			COPY(mouse[j].cur_x);
3572 			COPY(mouse[j].cur_y);
3573 			COPY(mouse[j].buttons);
3574 		}
3575 
3576 		COPY(superscope.x);
3577 		COPY(superscope.y);
3578 		COPY(superscope.phys_buttons);
3579 		COPY(superscope.next_buttons);
3580 		COPY(superscope.read_buttons);
3581 
3582 		for (int j = 0; j < 2; j++)
3583 			COPY(justifier.x[j]);
3584 		for (int j = 0; j < 2; j++)
3585 			COPY(justifier.y[j]);
3586 		COPY(justifier.buttons);
3587 		for (int j = 0; j < 2; j++)
3588 			COPY(justifier.offscreen[j]);
3589 		for (int j = 0; j < 2; j++)
3590 			for (int k = 0; k < 2; k++)
3591 				COPY(mp5[j].pads[k]);
3592 
3593 		assert(i == sizeof(s->internal));
3594 
3595 		if (s->ver > 3)
3596 		{
3597 			COPY(macsrifle.x);
3598 			COPY(macsrifle.y);
3599 			COPY(macsrifle.buttons);
3600 
3601 			assert(i == sizeof(s->internal) + sizeof(s->internal_macs));
3602 		}
3603 
3604 	#undef COPY
3605 	}
3606 
3607 	if (s->ver > 2)
3608 	{
3609 		pad_read      = s->pad_read;
3610 		pad_read_last = s->pad_read_last;
3611 	}
3612 }
3613 
MovieGetJoypad(int i)3614 uint16 MovieGetJoypad (int i)
3615 {
3616 	if (i < 0 || i > 7)
3617 		return (0);
3618 
3619 	return (joypad[i].buttons);
3620 }
3621 
MovieSetJoypad(int i,uint16 buttons)3622 void MovieSetJoypad (int i, uint16 buttons)
3623 {
3624 	if (i < 0 || i > 7)
3625 		return;
3626 
3627 	joypad[i].buttons = buttons;
3628 }
3629 
MovieGetMouse(int i,uint8 out[5])3630 bool MovieGetMouse (int i, uint8 out[5])
3631 {
3632 	if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1))
3633 		return (false);
3634 
3635 	int		n = curcontrollers[i] - MOUSE0;
3636 	uint8	*ptr = out;
3637 
3638 	WRITE_WORD(ptr, mouse[n].cur_x); ptr += 2;
3639 	WRITE_WORD(ptr, mouse[n].cur_y); ptr += 2;
3640 	*ptr = mouse[n].buttons;
3641 
3642 	return (true);
3643 }
3644 
MovieSetMouse(int i,uint8 in[5],bool inPolling)3645 void MovieSetMouse (int i, uint8 in[5], bool inPolling)
3646 {
3647 	if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1))
3648 		return;
3649 
3650 	int		n = curcontrollers[i] - MOUSE0;
3651 	uint8	*ptr = in;
3652 
3653 	mouse[n].cur_x = READ_WORD(ptr); ptr += 2;
3654 	mouse[n].cur_y = READ_WORD(ptr); ptr += 2;
3655 	mouse[n].buttons = *ptr;
3656 
3657 	if (inPolling)
3658 		UpdatePolledMouse(curcontrollers[i]);
3659 }
3660 
MovieGetScope(int i,uint8 out[6])3661 bool MovieGetScope (int i, uint8 out[6])
3662 {
3663 	if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE)
3664 		return (false);
3665 
3666 	uint8	*ptr = out;
3667 
3668 	WRITE_WORD(ptr, superscope.x); ptr += 2;
3669 	WRITE_WORD(ptr, superscope.y); ptr += 2;
3670 	*ptr++ = superscope.phys_buttons;
3671 	*ptr   = superscope.next_buttons;
3672 
3673 	return (true);
3674 }
3675 
MovieSetScope(int i,uint8 in[6])3676 void MovieSetScope (int i, uint8 in[6])
3677 {
3678 	if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE)
3679 		return;
3680 
3681 	uint8	*ptr = in;
3682 
3683 	superscope.x = READ_WORD(ptr); ptr += 2;
3684 	superscope.y = READ_WORD(ptr); ptr += 2;
3685 	superscope.phys_buttons = *ptr++;
3686 	superscope.next_buttons = *ptr;
3687 }
3688 
MovieGetJustifier(int i,uint8 out[11])3689 bool MovieGetJustifier (int i, uint8 out[11])
3690 {
3691 	if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS))
3692 		return (false);
3693 
3694 	uint8	*ptr = out;
3695 
3696 	WRITE_WORD(ptr, justifier.x[0]); ptr += 2;
3697 	WRITE_WORD(ptr, justifier.x[1]); ptr += 2;
3698 	WRITE_WORD(ptr, justifier.y[0]); ptr += 2;
3699 	WRITE_WORD(ptr, justifier.y[1]); ptr += 2;
3700 	*ptr++ = justifier.buttons;
3701 	*ptr++ = justifier.offscreen[0];
3702 	*ptr   = justifier.offscreen[1];
3703 
3704 	return (true);
3705 }
3706 
MovieSetJustifier(int i,uint8 in[11])3707 void MovieSetJustifier (int i, uint8 in[11])
3708 {
3709 	if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS))
3710 		return;
3711 
3712 	uint8	*ptr = in;
3713 
3714 	justifier.x[0] = READ_WORD(ptr); ptr += 2;
3715 	justifier.x[1] = READ_WORD(ptr); ptr += 2;
3716 	justifier.y[0] = READ_WORD(ptr); ptr += 2;
3717 	justifier.y[1] = READ_WORD(ptr); ptr += 2;
3718 	justifier.buttons      = *ptr++;
3719 	justifier.offscreen[0] = *ptr++;
3720 	justifier.offscreen[1] = *ptr;
3721 }
3722 
MovieGetMacsRifle(int i,uint8 out[5])3723 bool MovieGetMacsRifle (int i, uint8 out[5])
3724 {
3725 	if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE)
3726 		return (false);
3727 
3728 	uint8	*ptr = out;
3729 
3730 	WRITE_WORD(ptr, macsrifle.x); ptr += 2;
3731 	WRITE_WORD(ptr, macsrifle.y); ptr += 2;
3732 	*ptr = macsrifle.buttons;
3733 
3734 	return (true);
3735 }
3736 
MovieSetMacsRifle(int i,uint8 in[5])3737 void MovieSetMacsRifle (int i, uint8 in[5])
3738 {
3739 	if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE)
3740 		return;
3741 
3742 	uint8	*ptr = in;
3743 
3744 	macsrifle.x = READ_WORD(ptr); ptr += 2;
3745 	macsrifle.y = READ_WORD(ptr); ptr += 2;
3746 	macsrifle.buttons = *ptr;
3747 }
3748 
3749