608404b6acc0f9fbd92890d974f8039b11c77c11
[fceu.git] / drivers / pc / input.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define JOY_A   1
22 #define JOY_B   2
23 #define JOY_SELECT      4
24 #define JOY_START       8
25 #define JOY_UP  0x10
26 #define JOY_DOWN        0x20
27 #define JOY_LEFT        0x40
28 #define JOY_RIGHT       0x80
29
30
31 #include "minimal.h"
32 extern int swapbuttons;
33 extern int stretch_offset;
34 extern int FSkip_setting;
35
36 extern void SetVideoScaling(int pixels,int width,int height);
37 INLINE long UpdateGamepadGP2X(void);
38
39
40
41 /* UsrInputType[] is user-specified.  InputType[] is current
42         (game loading can override user settings)
43 */
44 static int UsrInputType[2]={SI_GAMEPAD,SI_GAMEPAD};
45 static int InputType[2];
46
47 static int UsrInputTypeFC={SI_NONE};
48 static int InputTypeFC;
49
50 static uint32 JSreturn;
51 int NoWaiting=0;
52
53 #include "keyscan.h"
54
55 static int powerpadsc[2][12];
56 static int powerpadside=0;
57
58
59 static uint32 MouseData[3];
60 static uint8 fkbkeys[0x48];
61 unsigned long lastpad=0;
62
63 void FCEUD_UpdateInput(void)
64 {
65   int t=0;
66   long lastpad2=lastpad;
67   long pad = UpdateGamepadGP2X();
68   t=1;
69   //  JSreturn=(JSreturn&0xFF000000)|(JSreturn&0xFF)|((JSreturn&0xFF0000)>>8)|((JSreturn&0xFF00)<<8);
70   if(gametype==GIT_FDS)
71   {
72     NoWaiting&=~1;
73         if ((pad & GP2X_PUSH) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_L)) && (!(pad & GP2X_R)) && (!(lastpad2 & GP2X_PUSH)))
74         {
75       DriverInterface(DES_FDSSELECT,0);
76         }
77         else if ((pad & GP2X_L) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_PUSH)) && (!(pad & GP2X_R))&& (!(lastpad2 & GP2X_L)))
78         {
79       DriverInterface(DES_FDSINSERT,0);
80         }
81         else if ((pad & GP2X_R) && (!(pad & GP2X_SELECT)) && (!(pad & GP2X_L)) && (!(pad & GP2X_PUSH)) && (!(lastpad2 & GP2X_R)))
82         {
83       DriverInterface(DES_FDSEJECT,0);
84         }
85   }
86
87 }
88
89
90 //#ifdef GP2X
91
92 extern void ResetNES(void);
93 extern void CleanSurface(void);
94
95 char soundvolmeter[21];
96 int soundvolIndex=0;
97 int L_count=0;
98 int R_count=0;
99 extern int CurrentState;
100 int TurboFireOff=1;
101 int TurboFireTop=0;  // 0 is none  // 1 is  A & X turbo  // 2 is Y & B turbo
102 int TurboFireBottom=0;
103 int turbo_toggle_A=0;
104 int turbo_toggle_B=0;
105
106 static void setsoundvol(int soundvolume)
107 {
108     //FCEUI_SetSoundVolume(soundvol);
109     // draw on screen :D
110     gp2x_sound_volume(soundvolume, soundvolume);
111     int meterval=soundvolume/5;
112     for (soundvolIndex=0; soundvolIndex < 20; soundvolIndex++)
113     {
114        if (soundvolIndex < meterval)
115        {
116           soundvolmeter[soundvolIndex]='*';
117        }
118        else
119        {
120           soundvolmeter[soundvolIndex]='_';
121        }
122     }
123     soundvolmeter[20]=0;
124     FCEU_DispMessage("|%s|", soundvolmeter);
125 }
126 /**
127  * GP2x joystick reader
128  *
129  */
130 INLINE long UpdateGamepadGP2X(void)
131 {
132   uint32 JS=0;
133
134   unsigned long pad=gp2x_joystick_read();
135 #define down(b) (pad & GP2X_##b)
136 #define last_down(b) (lastpad & GP2X_##b)
137 #define L_down (pad & GP2X_L)
138 #define R_down (pad & GP2X_R)
139 #define last_L_down (lastpad & GP2X_L)
140 #define last_R_down (lastpad & GP2X_R)
141 #define shift      ((pad     & GP2X_PUSH) || ((pad     & (GP2X_VOL_UP|GP2X_VOL_DOWN)) == (GP2X_VOL_UP|GP2X_VOL_DOWN)))
142 #define last_shift ((lastpad & GP2X_PUSH) || ((lastpad & (GP2X_VOL_UP|GP2X_VOL_DOWN)) == (GP2X_VOL_UP|GP2X_VOL_DOWN)))
143
144   if (L_down && R_down && !(pad & GP2X_PUSH) && !(last_R_down && last_L_down))
145   {
146      ResetNES();
147      puts("Reset");
148      goto no_pad;
149   }
150
151   if (down(VOL_UP) && !down(VOL_DOWN))
152   {
153     soundvol+=1;
154     if (soundvol >= 100) soundvol=100;
155     //FCEUI_SetSoundVolume(soundvol);
156     setsoundvol(soundvol);
157   }
158   else if (down(VOL_DOWN) && !down(VOL_UP))
159   {
160     soundvol-=1;
161     if (soundvol < 0) soundvol=0;
162     //FCEUI_SetSoundVolume(soundvol);
163     setsoundvol(soundvol);
164   }
165
166   if (shift)
167   {
168     // only if it's something else then last time, and not moving around the joystick
169     if (!(pad & (GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT)))
170     {
171       if (down(SELECT))
172       {
173         if (last_down(SELECT) && last_shift)
174         {
175           // still pressed down from stretching from last one
176           goto no_pad;
177         }
178         if (stretch_offset == 32)
179         {
180           stretch_offset=0;
181         }
182         else
183         {
184           stretch_offset=32;
185         }
186
187         if (stretch_offset == 32)
188         {
189           SetVideoScaling(320, 320, 240);
190           CleanSurface();
191         }
192         else
193         {
194           SetVideoScaling(320, 256, 240);
195         }
196
197         goto no_pad;
198       }
199       else if (L_down && R_down)
200       {
201         FCEUI_CloseGame();
202         puts("Quit");
203         goto no_pad;
204       }
205       else if (R_down && !(last_R_down && last_shift))
206       {
207        FCEUI_LoadState();
208        goto no_pad;
209       }
210       else if (L_down && !(last_L_down && last_shift))
211       {
212        FCEUI_SaveState();
213        goto no_pad;
214       }
215       else if (down(A) && !(last_down(A) && last_shift))
216       {
217        FSkip_setting--;
218        if (FSkip_setting < 0) {
219         FSkip_setting = -1;
220         FCEUI_DispMessage("Auto frameskip");
221        }
222        else
223         FCEUI_DispMessage("Frameskip: %i", FSkip_setting);
224        goto no_pad;
225       }
226       else if (down(Y) && !(last_down(Y) && last_shift))
227       {
228        FSkip_setting++;
229        if (FSkip_setting > 8) FSkip_setting = 8;
230        FCEUI_DispMessage("Frameskip: %i", FSkip_setting);
231        goto no_pad;
232       }
233     }
234   }
235
236   // r is toggle savestate
237   if (R_down)
238   {
239         if (last_R_down)
240         {
241           R_count++;
242       if ((R_count & 31)== 31)
243       {
244                 CurrentState=(CurrentState+1) % 10;
245                 FCEUI_DispMessage("Now Using Save State %d", CurrentState);
246           }
247         }
248   }
249   else
250   {
251     R_count=0;
252   }
253
254   // l is toggle turbo
255   if (L_down)
256   {
257         if (last_L_down)
258         {
259           L_count++;
260       if ((L_count & 31)== 31)
261       {
262        // 0 is none  // 1 is  Y & B turbo  // 2 is X & A turbo
263         if ((!TurboFireTop) && (!TurboFireBottom))
264         {
265                 // was off
266                 TurboFireTop=1;
267                 TurboFireBottom=0;
268                 if (swapbuttons)
269                 {
270                   FCEUI_DispMessage("Turbo A and Y");
271                 }
272                 else
273                 {
274                   FCEUI_DispMessage("Turbo Y and B");
275                 }
276         }
277         else if (TurboFireTop)
278         {
279                 TurboFireTop=0;
280                 TurboFireBottom=1;
281                 if (swapbuttons)
282                 {
283                   FCEUI_DispMessage("Turbo X and B");
284                 }
285                 else
286                 {
287                   FCEUI_DispMessage("Turbo A and X");
288                 }
289         }
290         else
291         {
292                 TurboFireTop=0;
293                 TurboFireBottom=0;
294                 FCEUI_DispMessage("Turbo Off");
295         }
296
297           }
298         }
299   }
300   else
301   {
302     L_count=0;
303   }
304
305   //unsigned long padTmp=0;
306   // shift the bits in
307   // up
308   //padTmp=(pad & GP2X_UP) ;  // 1 is 2^0,
309   JS |= ((pad & GP2X_UP) << (4-0));  // 0x10 is 2^4
310
311   //padTmp=(pad & GP2X_DOWN);  // 0x10 is 2^4,
312   JS |= ((pad & GP2X_DOWN) << (5-4));  // 0x20 is 2^5
313
314   //padTmp=(pad & GP2X_LEFT);  // 0x4 is 2^2,
315   JS |= ((pad & GP2X_LEFT) << (6-2));  // 0x40 is 2^6
316
317   //padTmp=(pad & GP2X_RIGHT);  // 0x40 is 2^6,
318   JS |= ((pad & GP2X_RIGHT) << (7-6));  // 0x80 is 2^7
319
320
321 #define  A_down (pad & GP2X_A)
322 #define  B_down (pad & GP2X_B)
323 #define  X_down (pad & GP2X_X)
324 #define  Y_down (pad & GP2X_Y)
325
326   // should be 2 cycles held, 1 cycle release
327   turbo_toggle_A=(turbo_toggle_A+1) % 3;
328   turbo_toggle_B=(turbo_toggle_B+1) % 3;
329
330    // 0 is none  // 1 is  Y & B turbo  // 2 is X & A turbo
331   // B or X are both considered A
332   //padTmp=B_down >> 13;  // 2^13,
333
334    if (!(TurboFireTop && (!turbo_toggle_A)))
335    {
336     JS |= ((B_down >> 13) << 0);  // 0x1 is 2^0
337    }
338    // A or Y are both considered B
339    //padTmp=A_down >> 12;  // 2^13,
340    if (!(TurboFireBottom && (!turbo_toggle_B)))
341    {
342     JS |= ((A_down >> 12) << 1);  // 0x2 is 2^1
343    }
344
345   if (swapbuttons)
346   {
347    //padTmp=X_down >> 14;  // 2^13,
348    if (!(TurboFireBottom && (!turbo_toggle_A)))
349    {
350 //    JS |= ((X_down >> 14) << 0);  // 0x1 is 2^0
351     JS |= ((Y_down >> 15) << 0);  // 0x1 is 2^0
352    }
353
354    //padTmp=Y_down >> 15;  // 2^13,
355    if (!(TurboFireTop && (!turbo_toggle_B)))
356    {
357     JS |= ((X_down >> 14) << 1);  // 0x2 is 2^1
358    }
359   }
360   else
361   {
362    //padTmp=X_down >> 14;  // 2^13,
363    if (!(TurboFireBottom && (!turbo_toggle_A)))
364    {
365     JS |= ((X_down >> 14) << 0);  // 0x1 is 2^0
366    }
367
368    //padTmp=Y_down >> 15;  // 2^13,
369    if (!(TurboFireTop && (!turbo_toggle_B)))
370    {
371     JS |= ((Y_down >> 15) << 1);  // 0x2 is 2^1
372    }
373   }
374
375   // select
376   //padTmp=(pad & GP2X_SELECT) >> 9;  // 0x40 is 2^9,
377   JS |= (((pad & GP2X_SELECT) >> 9) << 2);  // 0x4 is 2^2
378
379   // start
380   //padTmp=(pad & GP2X_START) >> 8;  //   2^8,
381   JS |= (((pad & GP2X_START) >> 8) << 3);  // 0x8 is 2^3
382
383
384   JSreturn = JS;
385   lastpad=pad;
386
387   return pad;
388   //JSreturn=(JS&0xFF000000)|(JS&0xFF)|((JS&0xFF0000)>>8)|((JS&0xFF00)<<8);
389 no_pad:
390   JSreturn=0;
391   lastpad=pad;
392   return 0;
393 }
394 //#endif
395
396
397 static void InitOtherInput(void)
398 {
399
400    void *InputDPtr;
401
402    int t;
403    int x;
404    int attrib;
405
406    for(t=0,x=0;x<2;x++)
407    {
408     attrib=0;
409     InputDPtr=0;
410     switch(InputType[x])
411     {
412       //case SI_POWERPAD:InputDPtr=&powerpadbuf[x];break;
413      case SI_GAMEPAD:InputDPtr=((uint8 *)&JSreturn)+(x<<1);break;
414      case SI_ARKANOID:InputDPtr=MouseData;t|=1;break;
415      case SI_ZAPPER:InputDPtr=MouseData;
416                                 t|=1;
417                                 attrib=1;
418                                 break;
419     }
420     FCEUI_SetInput(x,InputType[x],InputDPtr,attrib);
421    }
422
423    attrib=0;
424    InputDPtr=0;
425    switch(InputTypeFC)
426    {
427     case SIFC_SHADOW:InputDPtr=MouseData;t|=1;attrib=1;break;
428     case SIFC_ARKANOID:InputDPtr=MouseData;t|=1;break;
429     case SIFC_FKB:InputDPtr=fkbkeys;break;
430    }
431
432    FCEUI_SetInputFC(InputTypeFC,InputDPtr,attrib);
433    FCEUI_DisableFourScore(eoptions&EO_NOFOURSCORE);
434
435    if(t && !(inited&16))
436    {
437     InitMouse();
438     inited|=16;
439    }
440 }