1 /* Mednafen - Multi-system Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Xodnizel
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #include "nes.h"
23 #include "x6502.h"
24 #include "sound.h"
25 #include "input.h"
26 #include "vsuni.h"
27 #include "fds.h"
28 #include "input/cursor.h"
29 
30 namespace MDFN_IEN_NES
31 {
32 
33 MDFN_HIDE extern INPUTC *MDFN_InitZapper(int w);
34 MDFN_HIDE extern INPUTC *MDFN_InitPowerpadA(int w);
35 MDFN_HIDE extern INPUTC *MDFN_InitPowerpadB(int w);
36 MDFN_HIDE extern INPUTC *MDFN_InitArkanoid(int w);
37 
38 MDFN_HIDE extern INPUTCFC *MDFN_InitArkanoidFC(void);
39 MDFN_HIDE extern INPUTCFC *MDFN_InitSpaceShadow(void);
40 MDFN_HIDE extern INPUTCFC *MDFN_InitFKB(void);
41 MDFN_HIDE extern INPUTCFC *MDFN_InitHS(void);
42 MDFN_HIDE extern INPUTCFC *MDFN_InitMahjong(void);
43 MDFN_HIDE extern INPUTCFC *MDFN_InitPartyTap(void);
44 MDFN_HIDE extern INPUTCFC *MDFN_InitFamilyTrainerA(void);
45 MDFN_HIDE extern INPUTCFC *MDFN_InitFamilyTrainerB(void);
46 MDFN_HIDE extern INPUTCFC *MDFN_InitOekaKids(void);
47 MDFN_HIDE extern INPUTCFC *MDFN_InitTopRider(void);
48 MDFN_HIDE extern INPUTCFC *MDFN_InitBBattler2(void);
49 
50 static const IDIISG GamepadIDII =
51 {
52  IDIIS_ButtonCR("a", "A", 7),
53  IDIIS_ButtonCR("b", "B", 6),
54  IDIIS_Button("select", "SELECT", 4),
55  IDIIS_Button("start", "START", 5),
56  IDIIS_Button("up", "UP ↑", 0, "down"),
57  IDIIS_Button("down", "DOWN ↓", 1, "up"),
58  IDIIS_Button("left", "LEFT ←", 2, "right"),
59  IDIIS_Button("right", "RIGHT →", 3, "left"),
60 };
61 
62 static const IDIISG ZapperIDII =
63 {
64  { "x_axis", "X Axis", -1, IDIT_POINTER_X },
65  { "y_axis", "Y Axis", -1, IDIT_POINTER_Y },
66  IDIIS_Button("trigger", "Trigger", 0),
67  IDIIS_Button("away_trigger", "Away Trigger", 1),
68 };
69 
70 static const IDIISG PowerpadIDII =
71 {
72  IDIIS_Button("1", "1", 0),
73  IDIIS_Button("2", "2", 1),
74  IDIIS_Button("3", "3", 2),
75  IDIIS_Button("4", "4", 3),
76  IDIIS_Button("5", "5", 4),
77  IDIIS_Button("6", "6", 5),
78  IDIIS_Button("7", "7", 6),
79  IDIIS_Button("8", "8", 7),
80  IDIIS_Button("9", "9", 8),
81  IDIIS_Button("10", "10", 9),
82  IDIIS_Button("11", "11", 10),
83  IDIIS_Button("12", "12", 11),
84 };
85 
86 static const IDIISG ArkanoidIDII =
87 {
88  { "x_axis", "X Axis", -1, IDIT_POINTER_X },
89  IDIIS_Button("button", "Button", 0),
90 };
91 
92 static const IDIISG FKBIDII =
93 {
94  IDIIS_Button("f1", "F1", 0),
95  IDIIS_Button("f2", "F2", 1),
96  IDIIS_Button("f3", "F3", 2),
97  IDIIS_Button("f4", "F4", 3),
98  IDIIS_Button("f5", "F5", 4),
99  IDIIS_Button("f6", "F6", 5),
100  IDIIS_Button("f7", "F7", 6),
101  IDIIS_Button("f8", "F8", 7),
102 
103  IDIIS_Button("1", "1", 8),
104  IDIIS_Button("2", "2", 9),
105  IDIIS_Button("3", "3", 10),
106  IDIIS_Button("4", "4", 11),
107  IDIIS_Button("5", "5", 12),
108  IDIIS_Button("6", "6", 13),
109  IDIIS_Button("7", "7", 14),
110  IDIIS_Button("8", "8", 15),
111  IDIIS_Button("9", "9", 16),
112  IDIIS_Button("0", "0", 17),
113  IDIIS_Button("minus", "-", 18),
114  IDIIS_Button("caret", "^", 19),
115  IDIIS_Button("backslash", "\\", 20),
116  IDIIS_Button("stop", "STOP", 21),
117 
118  IDIIS_Button("escape", "ESC", 22),
119  IDIIS_Button("q", "Q", 23),
120  IDIIS_Button("w", "W", 24),
121  IDIIS_Button("e", "E", 25),
122  IDIIS_Button("r", "R", 26),
123  IDIIS_Button("t", "T", 27),
124  IDIIS_Button("y", "Y", 28),
125  IDIIS_Button("u", "U", 29),
126  IDIIS_Button("i", "I", 30),
127  IDIIS_Button("o", "O", 31),
128  IDIIS_Button("p", "P", 32),
129  IDIIS_Button("at", "@", 33),
130  IDIIS_Button("left_bracket", "[", 34),
131  IDIIS_Button("return", "RETURN", 35),
132  IDIIS_Button("ctrl", "CTR", 36),
133  IDIIS_Button("a", "A", 37),
134  IDIIS_Button("s", "S", 38),
135  IDIIS_Button("d", "D", 39),
136  IDIIS_Button("f", "F", 40),
137  IDIIS_Button("g", "G", 41),
138  IDIIS_Button("h", "H", 42),
139  IDIIS_Button("j", "J", 43),
140  IDIIS_Button("k", "K", 44),
141  IDIIS_Button("l", "L", 45),
142  IDIIS_Button("semicolon", ";", 46),
143  IDIIS_Button("colon", ":", 47),
144  IDIIS_Button("right_bracket", "]", 48),
145  IDIIS_Button("kana", "カナ", 49),
146  IDIIS_Button("left_shift", "Left SHIFT", 50),
147  IDIIS_Button("z", "Z", 51),
148  IDIIS_Button("x", "X", 52),
149  IDIIS_Button("c", "C", 53),
150  IDIIS_Button("v", "V", 54),
151  IDIIS_Button("b", "B", 55),
152  IDIIS_Button("n", "N", 56),
153  IDIIS_Button("m", "M", 57),
154  IDIIS_Button("comma", ",", 58),
155  IDIIS_Button("period", ".", 59),
156  IDIIS_Button("slash", "/", 60),
157  IDIIS_Button("empty", "Empty", 61),
158  IDIIS_Button("right_shift", "Right SHIFT", 62),
159  IDIIS_Button("graph", "GRPH", 63),
160  IDIIS_Button("space", "SPACE", 64),
161 
162  IDIIS_Button("clear", "CLR", 65),
163  IDIIS_Button("insert", "INS", 66),
164  IDIIS_Button("delete", "DEL", 67),
165  IDIIS_Button("up", "UP", 68),
166  IDIIS_Button("left", "LEFT", 69),
167  IDIIS_Button("right", "RIGHT", 70),
168  IDIIS_Button("down", "DOWN", 71),
169 };
170 
171 static const IDIISG HypershotIDII =
172 {
173  IDIIS_ButtonCR("i_run", "I, RUN", 0),
174  IDIIS_ButtonCR("i_jump", "I, JUMP", 1),
175  IDIIS_ButtonCR("ii_run", "II, RUN", 2),
176  IDIIS_ButtonCR("ii_jump", "II, JUMP", 3),
177 };
178 
179 static const IDIISG MahjongIDII =
180 {
181  IDIIS_Button("1", "1", 0),
182  IDIIS_Button("2", "2", 1),
183  IDIIS_Button("3", "3", 2),
184  IDIIS_Button("4", "4", 3),
185  IDIIS_Button("5", "5", 4),
186  IDIIS_Button("6", "6", 5),
187  IDIIS_Button("7", "7", 6),
188  IDIIS_Button("8", "8", 7),
189  IDIIS_Button("9", "9", 8),
190  IDIIS_Button("10", "10", 9),
191  IDIIS_Button("11", "11", 10),
192  IDIIS_Button("12", "12", 11),
193  IDIIS_Button("13", "13", 12),
194  IDIIS_Button("14", "14", 13),
195  IDIIS_Button("15", "15", 14),
196  IDIIS_Button("16", "16", 15),
197  IDIIS_Button("17", "17", 16),
198  IDIIS_Button("18", "18", 17),
199  IDIIS_Button("19", "19", 18),
200  IDIIS_Button("20", "20", 19),
201  IDIIS_Button("21", "21", 20),
202 };
203 
204 static const IDIISG PartyTapIDII =
205 {
206  IDIIS_Button("buzzer_1", "Buzzer 1", 0),
207  IDIIS_Button("buzzer_2", "Buzzer 2", 1),
208  IDIIS_Button("buzzer_3", "Buzzer 3", 2),
209  IDIIS_Button("buzzer_4", "Buzzer 4", 3),
210  IDIIS_Button("buzzer_5", "Buzzer 5", 4),
211  IDIIS_Button("buzzer_6", "Buzzer 6", 5),
212 };
213 
214 static const IDIISG FTrainerIDII =
215 {
216  IDIIS_Button("1", "1", 0),
217  IDIIS_Button("2", "2", 1),
218  IDIIS_Button("3", "3", 2),
219  IDIIS_Button("4", "4", 3),
220  IDIIS_Button("5", "5", 4),
221  IDIIS_Button("6", "6", 5),
222  IDIIS_Button("7", "7", 6),
223  IDIIS_Button("8", "8", 7),
224  IDIIS_Button("9", "9", 8),
225  IDIIS_Button("10", "10", 9),
226  IDIIS_Button("11", "11", 10),
227  IDIIS_Button("12", "12", 11),
228 };
229 
230 static const IDIISG OekaIDII =
231 {
232  { "x_axis", "X Axis", -1, IDIT_POINTER_X },
233  { "y_axis", "Y Axis", -1, IDIT_POINTER_Y },
234  IDIIS_Button("button", "Button", 0),
235 };
236 
237 static const IDIISG BBattler2IDII =
238 {
239  { "new", "New", -1, IDIT_BYTE_SPECIAL },
240  { "bd1", "Barcode Digit 1", -1, IDIT_BYTE_SPECIAL },
241  { "bd2", "Barcode Digit 2", -1, IDIT_BYTE_SPECIAL },
242  { "bd3", "Barcode Digit 3", -1, IDIT_BYTE_SPECIAL },
243  { "bd4", "Barcode Digit 4", -1, IDIT_BYTE_SPECIAL },
244  { "bd5", "Barcode Digit 5", -1, IDIT_BYTE_SPECIAL },
245  { "bd6", "Barcode Digit 6", -1, IDIT_BYTE_SPECIAL },
246  { "bd7", "Barcode Digit 7", -1, IDIT_BYTE_SPECIAL },
247  { "bd8", "Barcode Digit 8", -1, IDIT_BYTE_SPECIAL },
248  { "bd9", "Barcode Digit 9", -1, IDIT_BYTE_SPECIAL },
249  { "bd10", "Barcode Digit 10", -1, IDIT_BYTE_SPECIAL },
250  { "bd11", "Barcode Digit 11", -1, IDIT_BYTE_SPECIAL },
251  { "bd12", "Barcode Digit 12", -1, IDIT_BYTE_SPECIAL },
252  { "bd13", "Barcode Digit 13", -1, IDIT_BYTE_SPECIAL },
253 };
254 
255 static const std::vector<InputDeviceInfoStruct> InputDeviceInfoNESPort34 =
256 {
257  // None
258  {
259   "none",
260   "none",
261   NULL,
262   IDII_Empty
263  },
264 
265  // Gamepad
266  {
267   "gamepad",
268   "Gamepad",
269   NULL,
270   GamepadIDII
271  },
272 
273 };
274 
275 static const std::vector<InputDeviceInfoStruct> InputDeviceInfoNESPort =
276 {
277  // None
278  {
279   "none",
280   "none",
281   NULL,
282   IDII_Empty
283  },
284 
285  // Gamepad
286  {
287   "gamepad",
288   "Gamepad",
289   NULL,
290   GamepadIDII
291  },
292 
293  // Zapper
294  {
295   "zapper",
296   "Zapper",
297   NULL,
298   ZapperIDII
299  },
300 
301  // Powerpad A
302  {
303   "powerpada",
304   "Power Pad Side A",
305   NULL,
306   PowerpadIDII
307  },
308 
309  // Powerpad B
310  {
311   "powerpadb",
312   "Power Pad Side B",
313   NULL,
314   PowerpadIDII
315  },
316 
317  // Arkanoid
318  {
319   "arkanoid",
320   "Arkanoid Paddle",
321   NULL,
322   ArkanoidIDII
323  },
324 
325 
326 };
327 
328 static const std::vector<InputDeviceInfoStruct> InputDeviceInfoFamicomPort =
329 {
330  // None
331  {
332   "none",
333   "none",
334   NULL,
335   IDII_Empty
336  },
337 
338  // Arkanoid
339  {
340   "arkanoid",
341   "Arkanoid Paddle",
342   NULL,
343   ArkanoidIDII
344  },
345 
346  // Space Shadow Gun
347  {
348   "shadow",
349   "Space Shadow Gun",
350   NULL,
351   ZapperIDII
352  },
353 
354  // 4-player
355  {
356   "4player",
357   "4-player Adapter",
358   NULL,
359   IDII_Empty
360  },
361 
362  // Family Keyboard
363  {
364   "fkb",
365   "Family Keyboard",
366   NULL,
367   FKBIDII,
368   InputDeviceInfoStruct::FLAG_KEYBOARD
369  },
370 
371  // Hypershot
372  {
373   "hypershot",
374   "Hypershot Paddles",
375   NULL,
376   HypershotIDII
377  },
378 
379  // Mahjong
380  {
381   "mahjong",
382   "Mahjong Controller",
383   NULL,
384   MahjongIDII
385  },
386 
387  // Party Tap
388  {
389   "partytap",
390   "Party Tap",
391   NULL,
392   PartyTapIDII
393  },
394 
395  // Family Trainer A
396  {
397   "ftrainera",
398   "Family Trainer Side A",
399   NULL,
400   FTrainerIDII
401  },
402 
403  // Family Trainer B
404  {
405   "ftrainerb",
406   "Family Trainer Side B",
407   NULL,
408   FTrainerIDII
409  },
410 
411  // Oeka Kids
412  {
413   "oekakids",
414   "Oeka Kids Tablet",
415   NULL,
416   OekaIDII
417  },
418 
419  // Barcode Battler II
420  {
421   "bworld",
422   "Barcode Battler II",
423   NULL,
424   BBattler2IDII
425  },
426 
427 };
428 
429 // The temptation is there, but don't change the "fcexp" default setting to anything other than "none", as the presence of a device
430 // there by default will cause compatibility problems with games.
431 const std::vector<InputPortInfoStruct> NESPortInfo =
432 {
433  { "port1", "Port 1", InputDeviceInfoNESPort, "gamepad" },
434  { "port2", "Port 2", InputDeviceInfoNESPort, "gamepad" },
435  { "port3", "Port 3", InputDeviceInfoNESPort34, "gamepad" },
436  { "port4", "Port 4", InputDeviceInfoNESPort34, "gamepad" },
437  { "fcexp", "Famicom Expansion Port", InputDeviceInfoFamicomPort, "none" },
438 };
439 
440 static uint8 joy_readbit[2];
441 static uint8 joy[4]={0,0,0,0};
442 static uint8 LastStrobe;
443 
444 /* This function is a quick hack to get the NSF player to use emulated gamepad
445    input.
446 */
MDFN_GetJoyJoy(void)447 uint8 MDFN_GetJoyJoy(void)
448 {
449  return(joy[0]|joy[1]|joy[2]|joy[3]);
450 }
451 MDFN_HIDE extern uint8 coinon;
452 
453 static int FSDisable=0;	/* Set to 1 if NES-style four-player adapter is disabled. */
454 
455 static const char *JPType[5] = { "none", "none", "none", "none", "none" };
456 static void *InputDataPtr[5];
457 
458 void (*InputScanlineHook)(uint8 *bg, uint32 linets, int final);
459 
460 
461 static INPUTC DummyJPort = {0, 0, 0, 0, 0, NULL};
462 static INPUTC *JPorts[4] = {&DummyJPort, &DummyJPort, &DummyJPort, &DummyJPort};
463 static INPUTCFC *FCExp = NULL;
464 
ReadGPVS(int w)465 static uint8 ReadGPVS(int w)
466 {
467                 uint8 ret=0;
468 
469                 if(joy_readbit[w]>=8)
470                  ret=1;
471                 else
472                 {
473                  ret = ((joy[w]>>(joy_readbit[w]))&1);
474                  if(!fceuindbg)
475                   joy_readbit[w]++;
476                 }
477                 return ret;
478 }
479 
ReadGP(int w)480 static uint8 ReadGP(int w)
481 {
482                 uint8 ret;
483 
484                 if(joy_readbit[w]>=8)
485                  ret = ((joy[2+w]>>(joy_readbit[w]&7))&1);
486                 else
487                  ret = ((joy[w]>>(joy_readbit[w]))&1);
488                 if(joy_readbit[w]>=16) ret=0;
489                 if(FSDisable)
490 		{
491 	  	 if(joy_readbit[w]>=8) ret|=1;
492 		}
493 		else
494 		{
495                  if(joy_readbit[w]==19-w) ret|=1;
496 		}
497 		if(!fceuindbg)
498 		 joy_readbit[w]++;
499                 return ret;
500 }
501 
DECLFR(JPRead)502 static DECLFR(JPRead)
503 {
504 	uint8 ret=0;
505 
506 	if(JPorts[A&1]->Read)
507 	 ret|=JPorts[A&1]->Read(A&1);
508 
509 	if(FCExp)
510 	{
511 	 if(FCExp->Read)
512 	 {
513 	  ret=FCExp->Read(A&1,ret);
514 	 }
515 	}
516 	ret|=X.DB&0xC0;
517 	return(ret);
518 }
519 
DECLFW(B4016)520 static DECLFW(B4016)
521 {
522 	if(FCExp)
523 	 if(FCExp->Write)
524 	  FCExp->Write(V&7);
525 
526 	if(JPorts[0]->Write)
527 	 JPorts[0]->Write(V&1);
528         if(JPorts[1]->Write)
529          JPorts[1]->Write(V&1);
530 
531         if((LastStrobe&1) && (!(V&1)))
532         {
533 	 /* This strobe code is just for convenience.  If it were
534 	    with the code in input / *.c, it would more accurately represent
535 	    what's really going on.  But who wants accuracy? ;)
536 	    Seriously, though, this shouldn't be a problem.
537 	 */
538 	 if(JPorts[0]->Strobe)
539 	  JPorts[0]->Strobe(0);
540          if(JPorts[1]->Strobe)
541           JPorts[1]->Strobe(1);
542 	 if(FCExp)
543 	  if(FCExp->Strobe)
544 	   FCExp->Strobe();
545 	 }
546          LastStrobe=V&0x1;
547 }
548 
StrobeGP(int w)549 static void StrobeGP(int w)
550 {
551 	joy_readbit[w]=0;
552 }
553 
StateActionGP(int w,StateMem * sm,const unsigned load,const bool data_only)554 static void StateActionGP(int w, StateMem *sm, const unsigned load, const bool data_only)
555 {
556  SFORMAT StateRegs[] =
557  {
558   SFVAR(joy_readbit[w]),
559   SFVAR(joy[w + 0]),
560   SFVAR(joy[w + 2]),
561   SFEND
562  };
563 
564  MDFNSS_StateAction(sm, load, data_only, StateRegs, w ? "INP1" : "INP0", true);
565 
566  if(load)
567  {
568 
569  }
570 }
571 
572 static uint8 F4ReadBit[2];
StateActionGPFC(StateMem * sm,const unsigned load,const bool data_only)573 static void StateActionGPFC(StateMem *sm, const unsigned load, const bool data_only)
574 {
575  SFORMAT StateRegs[] =
576  {
577   SFPTR8(F4ReadBit, 2),
578   SFPTR8(joy, 4),
579   SFEND
580  };
581 
582  MDFNSS_StateAction(sm, load, data_only, StateRegs,"INPF", true);
583 
584  if(load)
585  {
586 
587  }
588 }
589 
StrobeFami4(void)590 static void StrobeFami4(void)
591 {
592  F4ReadBit[0]=F4ReadBit[1]=0;
593 }
594 
ReadFami4(int w,uint8 ret)595 static uint8 ReadFami4(int w, uint8 ret)
596 {
597  ret&=1;
598 
599  ret |= ((joy[2+w]>>(F4ReadBit[w]))&1)<<1;
600  if(F4ReadBit[w]>=8) ret|=2;
601  else F4ReadBit[w]++;
602 
603  return(ret);
604 }
605 
UpdateGamepad(int w,void * data)606 static void UpdateGamepad(int w, void *data)
607 {
608  joy[w] = *(uint8*)data;
609 }
610 
611 static INPUTCFC FAMI4C = { ReadFami4,0,StrobeFami4,0,0,0, StateActionGPFC };
612 static INPUTC GPC = {ReadGP,0,StrobeGP,UpdateGamepad,0,0, StateActionGP };
613 static INPUTC GPCVS = {ReadGPVS,0,StrobeGP,UpdateGamepad,0,0, StateActionGP };
614 
MDFN_DrawInput(uint8 * pix,int pix_y)615 void MDFN_DrawInput(uint8* pix, int pix_y)
616 {
617  for(unsigned i = 0; i < 2; i++)
618  {
619   if(JPorts[i]->Draw)
620    JPorts[i]->Draw(i, pix, pix_y);
621  }
622 
623  if(FCExp && FCExp->Draw)
624   FCExp->Draw(pix, pix_y);
625 }
626 
MDFN_UpdateInput(void)627 void MDFN_UpdateInput(void)
628 {
629 	int x;
630 
631 	for(x = 0; x < 4;x++)
632 	{
633  	 if(JPorts[x]->Update)
634 	  JPorts[x]->Update(x, InputDataPtr[x]);
635 	}
636 
637 	if(FCExp)
638 	 if(FCExp->Update)
639 	  FCExp->Update(InputDataPtr[4]);
640 
641 	if(NESIsVSUni && coinon)
642 	 coinon--;
643 
644 	if(NESIsVSUni)
645 	 MDFN_VSUniSwap(&joy[0], &joy[1]);
646 }
647 
648 MDFN_HIDE extern uint8 vsdip;	// FIXME
649 
DECLFR(VSUNIRead0)650 static DECLFR(VSUNIRead0)
651 {
652         uint8 ret=0;
653 
654         if(JPorts[0]->Read)
655          ret|=(JPorts[0]->Read(0))&1;
656 
657         ret|=(vsdip&3)<<3;
658         if(coinon)
659          ret|=0x4;
660         return ret;
661 }
662 
DECLFR(VSUNIRead1)663 static DECLFR(VSUNIRead1)
664 {
665         uint8 ret=0;
666 
667         if(JPorts[1]->Read)
668          ret|=(JPorts[1]->Read(1))&1;
669         ret|=vsdip&0xFC;
670         return ret;
671 }
672 
SLHLHook(uint8 * pix,uint32 linets,int final)673 static void SLHLHook(uint8 *pix, uint32 linets, int final)
674 {
675  int x;
676 
677  for(x=0;x<2;x++)
678   if(JPorts[x]->SLHook)
679    JPorts[x]->SLHook(x, pix, linets, final);
680  if(FCExp)
681   if(FCExp->SLHook)
682    FCExp->SLHook(pix, linets, final);
683 }
684 
CheckSLHook(void)685 static void CheckSLHook(void)
686 {
687         InputScanlineHook=0;
688         if(JPorts[0]->SLHook || JPorts[1]->SLHook)
689          InputScanlineHook=SLHLHook;
690         if(FCExp)
691          if(FCExp->SLHook)
692           InputScanlineHook=SLHLHook;
693 }
694 
SetInputStuff(int x)695 static void SetInputStuff(int x)
696 {
697         const char *ts = JPType[x];
698 
699 	if(x == 4)
700 	{
701 	 if(!strcmp(ts, "none"))
702 	  FCExp = NULL;
703 	 else if(!strcmp(ts, "arkanoid"))
704 	  FCExp = MDFN_InitArkanoidFC();
705          else if(!strcmp(ts, "shadow"))
706 	  FCExp=MDFN_InitSpaceShadow();
707          else if(!strcmp(ts, "oekakids"))
708 	  FCExp=MDFN_InitOekaKids();
709          else if(!strcmp(ts, "4player"))
710 	 {
711 	  FCExp=&FAMI4C;
712 	  memset(&F4ReadBit,0,sizeof(F4ReadBit));
713 	 }
714          else if(!strcmp(ts, "fkb"))
715 	  FCExp=MDFN_InitFKB();
716          else if(!strcmp(ts, "hypershot"))
717 	  FCExp=MDFN_InitHS();
718          else if(!strcmp(ts, "mahjong"))
719 	  FCExp=MDFN_InitMahjong();
720          else if(!strcmp(ts, "partytap"))
721 	  FCExp=MDFN_InitPartyTap();
722          else if(!strcmp(ts, "ftrainera"))
723 	  FCExp=MDFN_InitFamilyTrainerA();
724          else if(!strcmp(ts, "ftrainerb"))
725 	  FCExp=MDFN_InitFamilyTrainerB();
726          else if(!strcmp(ts, "bworld"))
727 	  FCExp=MDFN_InitBBattler2();
728 	}
729 	else
730 	{
731 	 if(!strcmp(ts, "gamepad"))
732 	 {
733            if(NESIsVSUni)
734 	    JPorts[x] = &GPCVS;
735 	   else
736 	    JPorts[x]=&GPC;
737 	 }
738 	 else if(!strcmp(ts, "arkanoid"))
739 	  JPorts[x]=MDFN_InitArkanoid(x);
740 	 else if(!strcmp(ts, "zapper"))
741 	  JPorts[x]=MDFN_InitZapper(x);
742 	 else if(!strcmp(ts, "powerpada"))
743 	  JPorts[x]=MDFN_InitPowerpadA(x);
744 	 else if(!strcmp(ts, "powerpadb"))
745 	  JPorts[x]=MDFN_InitPowerpadB(x);
746 	 else if(!strcmp(ts, "none"))
747 	  JPorts[x]=&DummyJPort;
748         }
749 
750 	CheckSLHook();
751 }
752 
NESINPUT_Power(void)753 void NESINPUT_Power(void)
754 {
755 	memset(joy_readbit,0,sizeof(joy_readbit));
756         memset(joy,0,sizeof(joy));
757 	LastStrobe = 0;
758 
759 	for(int x = 0; x < 5; x++)
760          SetInputStuff(x);
761 }
762 
MDFNNES_SetInput(unsigned port,const char * type,uint8 * ptr)763 void MDFNNES_SetInput(unsigned port, const char *type, uint8 *ptr)
764 {
765  JPType[port] = type;
766  InputDataPtr[port] = ptr;
767  SetInputStuff(port);
768 }
769 
NESINPUT_StateAction(StateMem * sm,const unsigned load,const bool data_only)770 void NESINPUT_StateAction(StateMem *sm, const unsigned load, const bool data_only)
771 {
772  SFORMAT StateRegs[] =
773  {
774    SFVARN(LastStrobe, "LSTS"),
775    SFEND
776  };
777 
778  if(load && !data_only)	// Kludgey forced initialization of variables in case a section or variable is missing.
779  {
780   for(unsigned x = 0; x < 5; x++)
781    SetInputStuff(x);
782  }
783 
784  MDFNSS_StateAction(sm, load, data_only, StateRegs, "INPT");
785 
786  if(JPorts[0]->StateAction)
787   JPorts[0]->StateAction(0, sm, load, data_only);
788  if(JPorts[1]->StateAction)
789   JPorts[1]->StateAction(1, sm, load, data_only);
790 
791  if(FCExp && FCExp->StateAction)
792   FCExp->StateAction(sm, load, data_only);
793 
794  if(load)
795  {
796 
797  }
798 }
799 
800 static writefunc Other4016WHandler;
801 
DECLFW(B4016_Chained)802 static DECLFW(B4016_Chained)
803 {
804  Other4016WHandler(A, V);
805  B4016(A, V);
806 }
807 
NESINPUT_PaletteChanged(void)808 void NESINPUT_PaletteChanged(void)
809 {
810  NESCURSOR_PaletteChanged();
811 }
812 
NESINPUT_Init(void)813 void NESINPUT_Init(void)
814 {
815  FSDisable = MDFN_GetSettingB("nes.nofs");
816 
817  if(NESIsVSUni)
818  {
819   SetReadHandler(0x4016, 0x4016, VSUNIRead0);
820   SetReadHandler(0x4017, 0x4017, VSUNIRead1);
821  }
822  else
823   SetReadHandler(0x4016, 0x4017, JPRead);
824 
825  Other4016WHandler = GetWriteHandler(0x4016);
826 
827  if(Other4016WHandler != BNull)
828   SetWriteHandler(0x4016, 0x4016, B4016_Chained);
829  else
830   SetWriteHandler(0x4016, 0x4016, B4016);
831 }
832 
833 
834 
MDFNNES_DoSimpleCommand(int cmd)835 void MDFNNES_DoSimpleCommand(int cmd)
836 {
837  if(cmd >= MDFN_MSC_TOGGLE_DIP0 && cmd <= MDFN_MSC_TOGGLE_DIP7)
838  {
839 	MDFN_VSUniToggleDIP(cmd - MDFN_MSC_TOGGLE_DIP0);
840  }
841  else switch(cmd)
842  {
843    case MDFN_MSC_INSERT_COIN:
844 		MDFN_VSUniCoin();
845 		break;
846 
847    case MDFN_MSC_POWER:
848 		PowerNES();
849 		break;
850 
851    case MDFN_MSC_RESET:
852 		ResetNES();
853 		break;
854  }
855 }
856 
857 }
858