e4d0466c51ebce56512589100d13d066f3afbcfe
[fceu.git] / drivers / common / input.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include "../../state.h"
19 #include "../../general.h"
20 #include "../../input.h"
21 #include "../../svga.h"
22 #include "../../video.h"
23 #include "../libpicofe/input.h"
24 #include "input.h"
25
26 /* UsrInputType[] is user-specified.  InputType[] is current
27        (game loading can override user settings)
28 */
29 static int UsrInputType[2]={SI_GAMEPAD,SI_GAMEPAD};
30 static int UsrInputTypeFC={SI_NONE};
31
32 static int InputType[2];
33 static int InputTypeFC;
34
35 static uint32 JSreturn;
36
37 static int powerpadsc[2][12];
38 static int powerpadside=0;
39
40 static uint32 MouseData[3];
41 static uint8 fkbkeys[0x48];
42
43 static uint32 combo_acts = 0, combo_keys = 0;
44 static uint32 prev_emu_acts = 0;
45
46
47 static void setsoundvol(int soundvolume)
48 {
49         int soundvolIndex;
50         static char soundvolmeter[24];
51         static int prev_snd_on = 0;
52
53         if ((!!soundvolume) ^ prev_snd_on)
54         {
55                 FCEUI_Sound(Settings.sound_rate);
56                 prev_snd_on = !!soundvolume;
57         }
58
59         platform_set_volume(soundvolume);
60
61         // draw on screen :D
62         int meterval=soundvolume/5;
63         for (soundvolIndex = 0; soundvolIndex < 20; soundvolIndex++)
64         {
65                 if (soundvolIndex < meterval)
66                 {
67                         soundvolmeter[soundvolIndex]='*';
68                 }
69                 else
70                 {
71                         soundvolmeter[soundvolIndex]='_';
72                 }
73         }
74         soundvolmeter[20]=0;
75         FCEU_DispMessage("|%s|", soundvolmeter);
76 }
77
78
79 static void do_emu_acts(uint32 acts)
80 {
81         uint32 actsc = acts;
82         acts &= acts ^ prev_emu_acts;
83         prev_emu_acts = actsc;
84
85         if (acts & (EACT_SAVE_STATE | EACT_LOAD_STATE))
86         {
87                 int do_it = 1;
88                 int need_confirm = 0;
89                 const char *nm;
90                 char tmp[64];
91                 int keys, len;
92
93                 if (acts & EACT_LOAD_STATE)
94                 {
95                         if (Settings.sstate_confirm & 2)
96                         {
97                                 need_confirm = 1;
98                         }
99                 }
100                 else
101                 {
102                         if (Settings.sstate_confirm & 1)
103                         {
104                                 char *fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
105                                 FILE *st = fopen(fname, "rb");
106                                 free(fname);
107                                 if (st)
108                                 {
109                                         fclose(st);
110                                         need_confirm = 1;
111                                 }
112                         }
113                 }
114
115                 if (need_confirm) {
116                         strcpy(tmp, (acts & EACT_LOAD_STATE) ?
117                                 "LOAD STATE?" : "OVERWRITE SAVE?");
118                         len = strlen(tmp);
119                         nm = in_get_key_name(-1, -PBTN_MA3);
120                         snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);
121                         len = strlen(tmp);
122                         nm = in_get_key_name(-1, -PBTN_MBACK);
123                         snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);
124
125                         FCEU_DispMessage(tmp);
126                         FCEU_PutImage();
127                         FCEUD_Update(XBuf+8, NULL, 0);
128
129                         in_set_config_int(0, IN_CFG_BLOCKING, 1);
130                         while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))
131                                 ;
132                         while ( !((keys = in_menu_wait_any(NULL, 50)) & (PBTN_MA3|PBTN_MBACK)) )
133                                 ;
134                         if (keys & PBTN_MBACK)
135                                 do_it = 0;
136                         while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))
137                                 ;
138                         in_set_config_int(0, IN_CFG_BLOCKING, 0);
139
140                         FCEU_CancelDispMessage();
141                 }
142                 if (do_it) {
143                         if (acts & EACT_LOAD_STATE)
144                                 FCEUI_LoadState();
145                         else
146                                 FCEUI_SaveState();
147                 }
148
149                 RefreshThrottleFPS();
150         }
151         else if (acts & (EACT_NEXT_SLOT|EACT_PREV_SLOT))
152         {
153                 FILE *st;
154                 char *fname;
155
156                 CurrentState += (acts & EACT_NEXT_SLOT) ? 1 : -1;
157                 if (CurrentState > 9) CurrentState = 0;
158                 if (CurrentState < 0) CurrentState = 9;
159
160                 fname = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
161                 st=fopen(fname,"rb");
162                 free(fname);
163                 FCEU_DispMessage("[%s] State Slot %i", st ? "USED" : "FREE", CurrentState);
164                 if (st) fclose(st);
165         }
166         else if (acts & EACT_FDS_INSERT)
167         {
168                 if(FCEUGameInfo.type == GIT_FDS)
169                         FCEU_DoSimpleCommand(FCEUNPCMD_FDSINSERT);
170         }
171         else if (acts & EACT_FDS_SELECT)
172         {
173                 if(FCEUGameInfo.type == GIT_FDS)
174                         FCEU_DoSimpleCommand(FCEUNPCMD_FDSSELECT);
175         }
176         else if (acts & EACT_INSERT_COIN)
177         {
178                 if(FCEUGameInfo.type == GIT_VSUNI)
179                         FCEU_DoSimpleCommand(FCEUNPCMD_VSUNICOIN);
180         }
181 }
182
183
184 static void do_fake_mouse(uint32 acts)
185 {
186         static int x=256/2, y=240/2;
187         int speed = 3;
188
189         if (acts & NKEY_B_TURBO) speed = 1;
190         if (acts & NKEY_A_TURBO) speed = 5;
191
192         if (acts & NKEY_LEFT)
193         {
194                 x -= speed;
195                 if (x < 0) x = 0;
196         }
197         else if (acts & NKEY_RIGHT)
198         {
199                 x += speed;
200                 if (x > 255) x = 255;
201         }
202
203         if (acts & NKEY_UP)
204         {
205                 y -= speed;
206                 if (y < 0) y = 0;
207         }
208         else if (acts & NKEY_DOWN)
209         {
210                 y += speed;
211                 if (y > 239) y = 239;
212         }
213
214         MouseData[0] = x;
215         MouseData[1] = y;
216         MouseData[2] = 0;
217         if (acts & NKEY_A) MouseData[2] |= 1;
218         if (acts & NKEY_B) MouseData[2] |= 2;
219 }
220
221
222 static void FCEUD_UpdateInput(void)
223 {
224         static int volpushed_frames = 0;
225         static int turbo_rate_cnt_a[2] = {0,0}, turbo_rate_cnt_b[2] = {0,0};
226         uint32 all_acts[2], emu_acts;
227         int actions[IN_BINDTYPE_COUNT] = { 0, };
228
229         in_update(actions);
230         all_acts[0] = actions[IN_BINDTYPE_PLAYER12];
231         all_acts[1] = actions[IN_BINDTYPE_PLAYER12] >> 16;
232         emu_acts = actions[IN_BINDTYPE_EMU];
233
234         if (emu_acts & EACT_ENTER_MENU)
235         {
236                 Exit = 1;
237                 return;
238         }
239         else if (emu_acts & EACT_VOLUME_UP)
240         {
241                 /* wait for at least 10 updates, because user may be just trying to enter menu */
242                 if (volpushed_frames++ > 10 && (volpushed_frames&1)) {
243                         soundvol++;
244                         if (soundvol > 100) soundvol=100;
245                         //FCEUI_SetSoundVolume(soundvol);
246                         setsoundvol(soundvol);
247                 }
248         }
249         else if (emu_acts & EACT_VOLUME_DOWN)
250         {
251                 if (volpushed_frames++ > 10 && (volpushed_frames&1)) {
252                         soundvol-=1;
253                         if (soundvol < 0) soundvol=0;
254                         //FCEUI_SetSoundVolume(soundvol);
255                         setsoundvol(soundvol);
256                 }
257         }
258         else
259         {
260                 volpushed_frames = 0;
261         }
262
263         JSreturn = 0; // RLDU SEBA
264
265         if (InputType[1] != SI_GAMEPAD)
266         {
267                 /* try to feed fake mouse there */
268                 do_fake_mouse(all_acts[0]);
269         }
270
271         // player 1
272         JSreturn |= all_acts[0] & 0xff;
273         if (all_acts[0] & NKEY_A_TURBO) {
274                 turbo_rate_cnt_a[0] += Settings.turbo_rate_add;
275                 JSreturn |= (turbo_rate_cnt_a[0] >> 24) & 1;
276         }
277         if (all_acts[0] & NKEY_B_TURBO) {
278                 turbo_rate_cnt_b[0] += Settings.turbo_rate_add;
279                 JSreturn |= (turbo_rate_cnt_b[0] >> 23) & 2;
280         }
281
282         // player 2
283         JSreturn |= (all_acts[1] & 0xff) << 16;
284         if (all_acts[1] & NKEY_A_TURBO) {
285                 turbo_rate_cnt_a[1] += Settings.turbo_rate_add;
286                 JSreturn |= (turbo_rate_cnt_a[1] >> 8) & 0x10000;
287         }
288         if (all_acts[1] & NKEY_B_TURBO) {
289                 turbo_rate_cnt_b[1] += Settings.turbo_rate_add;
290                 JSreturn |= (turbo_rate_cnt_b[1] >> 7) & 0x20000;
291         }
292
293         do_emu_acts(emu_acts);
294 }
295
296
297 static void InitOtherInput(void)
298 {
299
300    void *InputDPtr;
301
302    int t;
303    int x;
304    int attrib;
305
306    printf("InitOtherInput: InputType[0]: %i, InputType[1]: %i, InputTypeFC: %i\n",
307         InputType[0], InputType[1], InputTypeFC);
308
309    for(t=0,x=0;x<2;x++)
310    {
311     attrib=0;
312     InputDPtr=0;
313     switch(InputType[x])
314     {
315       //case SI_POWERPAD:InputDPtr=&powerpadbuf[x];break;
316      case SI_GAMEPAD:InputDPtr=((uint8 *)&JSreturn)+(x<<1);break;
317      case SI_ARKANOID:InputDPtr=MouseData;t|=1;break;
318      case SI_ZAPPER:InputDPtr=MouseData;
319                                 t|=1;
320                                 attrib=1;
321                                 break;
322     }
323     FCEUI_SetInput(x,InputType[x],InputDPtr,attrib);
324    }
325
326    attrib=0;
327    InputDPtr=0;
328    switch(InputTypeFC)
329    {
330     case SIFC_SHADOW:InputDPtr=MouseData;t|=1;attrib=1;break;
331     case SIFC_ARKANOID:InputDPtr=MouseData;t|=1;break;
332     case SIFC_FKB:InputDPtr=fkbkeys;break;
333    }
334
335    FCEUI_SetInputFC(InputTypeFC,InputDPtr,attrib);
336    FCEUI_DisableFourScore(eoptions&EO_NOFOURSCORE);
337
338    inited|=16;
339 }
340
341
342 static void PrepareOtherInput(void)
343 {
344         uint32 act;
345
346         combo_acts = combo_keys = prev_emu_acts = 0;
347
348         for (act = 0; act < 32; act++)
349         {
350                 int u, keyc = 0, keyc2 = 0;
351                 if (act == 16 || act == 17) continue; // player2 flag
352                 if (act > 17)
353                 {
354                         for (u = 0; u < 32; u++)
355                                 if (Settings.KeyBinds[u] & (1 << act)) keyc++;
356                 }
357                 else
358                 {
359                         for (u = 0; u < 32; u++)
360                                 if ((Settings.KeyBinds[u] & 0x30000) == 0 && // pl. 1
361                                         (Settings.KeyBinds[u] & (1 << act))) keyc++;
362                         for (u = 0; u < 32; u++)
363                                 if ((Settings.KeyBinds[u] & 0x30000) == 1 && // pl. 2
364                                         (Settings.KeyBinds[u] & (1 << act))) keyc2++;
365                         if (keyc2 > keyc) keyc = keyc2;
366                 }
367                 if (keyc > 1)
368                 {
369                         // loop again and mark those keys and actions as combo
370                         for (u = 0; u < 32; u++)
371                         {
372                                 if (Settings.KeyBinds[u] & (1 << act)) {
373                                         combo_keys |= 1 << u;
374                                         combo_acts |= 1 << act;
375                                 }
376                         }
377                 }
378         }
379
380         // printf("generated combo_acts: %08x, combo_keys: %08x\n", combo_acts, combo_keys);
381 }
382