initial fce ultra 0.81 import
[fceu.git] / drivers / win / joystick.c
1 /* FCE Ultra - NES/Famicom Emulator\r
2  *\r
3  * Copyright notice for this file:\r
4  *  Copyright (C) 2002 Ben Parnell\r
5  *\r
6  * This program is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this program; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  */\r
20 \r
21 #include "common.h"\r
22 #include <dinput.h>\r
23 \r
24 #include "input.h"\r
25 #include "joystick.h"\r
26 \r
27 \r
28 HRESULT  ddrval;\r
29 \r
30 static GUID joyGUID[64];\r
31 \r
32 static int joycounter;\r
33 \r
34 static LPDIRECTINPUTDEVICE7 lpJoy[4]={0,0,0,0};\r
35 \r
36 int joyOptions[4]={0,0,0,0};\r
37 int joyA[4]={1,1,1,1};\r
38 int joyB[4]={0,0,0,0};\r
39 int joySelect[4]={2,2,2,2};\r
40 int joyStart[4]={3,3,3,3};\r
41 int joyUp[4]={4,4,4,4};\r
42 int joyDown[4]={5,5,5,5};\r
43 int joyLeft[4]={6,6,6,6};\r
44 int joyRight[4]={7,7,7,7};\r
45 \r
46 int joy[4]={0,0,0,0};\r
47 \r
48 static int JoyXMax[4];\r
49 static int JoyXMin[4];\r
50 \r
51 static int JoyYMax[4];\r
52 static int JoyYMin[4];\r
53 \r
54 static DIJOYSTATE2 JoyStatus;\r
55 \r
56 static void ShowDIJErr(int w, char *s)\r
57 {\r
58  char tempo[128];\r
59  sprintf(tempo,"DirectInput: Joystick %d: %s",w+1,s);\r
60  FCEUD_PrintError(tempo);\r
61 }\r
62 \r
63 static void JoyAutoRestore(HRESULT ddrval,LPDIRECTINPUTDEVICE7 lpJJoy)\r
64 {\r
65    switch(ddrval)\r
66     {\r
67      case DIERR_INPUTLOST:\r
68      case DIERR_NOTACQUIRED:\r
69                            IDirectInputDevice7_Acquire(lpJJoy);\r
70                            break;\r
71     }\r
72 }\r
73 \r
74 static int GetJoystickButton(int x)\r
75 {\r
76  int errc=0;\r
77  int z;\r
78 \r
79  if(lpJoy[x])\r
80  {\r
81    doagaino:\r
82    if(errc>8) return(-1);\r
83 \r
84    ddrval=IDirectInputDevice7_Poll(lpJoy[x]);\r
85    if(ddrval!=DI_OK && ddrval!=DI_NOEFFECT) {JoyAutoRestore(ddrval,lpJoy[x]);errc++;goto doagaino;}\r
86 \r
87    ddrval=IDirectInputDevice7_GetDeviceState(lpJoy[x],sizeof(JoyStatus),&JoyStatus);\r
88    if(ddrval!=DI_OK) {JoyAutoRestore(ddrval,lpJoy[x]);errc++;goto doagaino;}\r
89 \r
90    for(z=0;z<128;z++)\r
91     if(JoyStatus.rgbButtons[z]&0x80)\r
92      return z;\r
93  }\r
94  return(-1);\r
95 }\r
96 \r
97 uint32 GetJSOr(void)\r
98 {\r
99         unsigned long ret;\r
100         int x;\r
101         ret=0;\r
102 \r
103         for(x=0;x<4;x++)\r
104         {\r
105          if(lpJoy[x])\r
106          {\r
107 \r
108           ddrval=IDirectInputDevice7_Poll(lpJoy[x]);\r
109           if(ddrval!=DI_OK && ddrval!=DI_NOEFFECT) JoyAutoRestore(ddrval,lpJoy[x]);\r
110 \r
111           ddrval=IDirectInputDevice7_GetDeviceState(lpJoy[x],sizeof(JoyStatus),&JoyStatus);\r
112           if(ddrval!=DI_OK) JoyAutoRestore(ddrval,lpJoy[x]);\r
113 \r
114           if(joyOptions[x]&1)\r
115           {\r
116            if(JoyStatus.rgbButtons[joyUp[x]&127]&0x80) ret|=JOY_UP<<(x<<3);\r
117            if(JoyStatus.rgbButtons[joyDown[x]&127]&0x80) ret|=JOY_DOWN<<(x<<3);\r
118            if(JoyStatus.rgbButtons[joyLeft[x]&127]&0x80) ret|=JOY_LEFT<<(x<<3);\r
119            if(JoyStatus.rgbButtons[joyRight[x]&127]&0x80) ret|=JOY_RIGHT<<(x<<3);\r
120           }\r
121           else\r
122           {\r
123            if(JoyStatus.lX>=JoyXMax[x])\r
124             ret|=JOY_RIGHT<<(x<<3);\r
125            else if(JoyStatus.lX<=JoyXMin[x])\r
126             ret|=JOY_LEFT<<(x<<3);\r
127 \r
128            if(JoyStatus.lY>=JoyYMax[x])\r
129             ret|=JOY_DOWN<<(x<<3);\r
130            else if(JoyStatus.lY<=JoyYMin[x])\r
131             ret|=JOY_UP<<(x<<3);\r
132           }\r
133           if(JoyStatus.rgbButtons[joyA[x]&127]&0x80) ret|=1<<(x<<3);\r
134           if(JoyStatus.rgbButtons[joyB[x]&127]&0x80) ret|=2<<(x<<3);\r
135           if(JoyStatus.rgbButtons[joySelect[x]&127]&0x80) ret|=4<<(x<<3);\r
136           if(JoyStatus.rgbButtons[joyStart[x]&127]&0x80) ret|=8<<(x<<3);\r
137          }\r
138         }\r
139 \r
140         return ret;\r
141 }\r
142 \r
143 static void KillJoystick(int w)\r
144 {\r
145  if(lpJoy[w])\r
146  {\r
147   IDirectInputDevice7_Unacquire(lpJoy[w]);\r
148   IDirectInputDevice7_Release(lpJoy[w]);\r
149   lpJoy[w]=0;\r
150  }\r
151 }\r
152 \r
153 void KillJoysticks(void)\r
154 {\r
155  int x;\r
156  for(x=0;x<4;x++)\r
157   KillJoystick(x);\r
158 }\r
159 \r
160 static BOOL CALLBACK JoystickFound(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)\r
161 {\r
162    if(joycounter<64)\r
163    {\r
164     joyGUID[joycounter]=lpddi->guidInstance;\r
165     joycounter++;\r
166     if(pvRef)\r
167     {\r
168      SendDlgItemMessage(pvRef,106,CB_ADDSTRING,0,(LPARAM)(LPSTR)lpddi->tszProductName);\r
169      SendDlgItemMessage(pvRef,112,CB_ADDSTRING,0,(LPARAM)(LPSTR)lpddi->tszProductName);\r
170     }\r
171     return DIENUM_CONTINUE;\r
172    }\r
173    else\r
174     return 0;   \r
175 }\r
176 \r
177 void InitJoystick(int w, HWND wnd)\r
178 {\r
179   if(joy[w])\r
180   {\r
181    if(joy[w]>joycounter)\r
182    {\r
183     ShowDIJErr(w,"Not found."); \r
184     joy[w]=0;\r
185     return;\r
186    }\r
187    ddrval=IDirectInput7_CreateDeviceEx(lpDI,&joyGUID[joy[w]-1],&IID_IDirectInputDevice7,(LPVOID *)&lpJoy[w],0);\r
188    if(ddrval != DI_OK)\r
189    {   \r
190     ShowDIJErr(w,"Error creating device.");\r
191     joy[w]=0;\r
192     return;\r
193    }\r
194    ddrval=IDirectInputDevice7_SetCooperativeLevel(lpJoy[w],wnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);\r
195    if (ddrval != DI_OK)\r
196    {\r
197     ShowDIJErr(w,"Error setting cooperative level.");\r
198     KillJoystick(w);\r
199     joy[w]=0;\r
200     return;\r
201    }\r
202    ddrval=IDirectInputDevice7_SetDataFormat(lpJoy[w],&c_dfDIJoystick2);\r
203    if (ddrval != DI_OK)\r
204    {\r
205     ShowDIJErr(w,"Error setting data format.");\r
206     KillJoystick(w);\r
207     joy[w]=0;\r
208     return;\r
209    }\r
210 \r
211    {\r
212     DIPROPRANGE diprg;\r
213     int r;\r
214 \r
215     memset(&diprg,0,sizeof(DIPROPRANGE));\r
216     diprg.diph.dwSize=sizeof(DIPROPRANGE);\r
217     diprg.diph.dwHeaderSize=sizeof(DIPROPHEADER);\r
218     diprg.diph.dwHow=DIPH_BYOFFSET;\r
219     diprg.diph.dwObj=DIJOFS_X;\r
220     ddrval=IDirectInputDevice7_GetProperty(lpJoy[w],DIPROP_RANGE,&diprg.diph);\r
221     if(ddrval!=DI_OK)\r
222     {\r
223      ShowDIJErr(w,"Error getting X axis range.");\r
224      joy[w]=0;\r
225      KillJoystick(w);\r
226      joy[w]=0;\r
227      return;\r
228     }\r
229     r=diprg.lMax-diprg.lMin;\r
230     JoyXMax[w]=diprg.lMax-(r>>2);\r
231     JoyXMin[w]=diprg.lMin+(r>>2);\r
232 \r
233     memset(&diprg,0,sizeof(DIPROPRANGE));\r
234     diprg.diph.dwSize=sizeof(DIPROPRANGE);\r
235     diprg.diph.dwHeaderSize=sizeof(DIPROPHEADER);\r
236     diprg.diph.dwHow=DIPH_BYOFFSET;\r
237     diprg.diph.dwObj=DIJOFS_Y;\r
238     ddrval=IDirectInputDevice7_GetProperty(lpJoy[w],DIPROP_RANGE,&diprg.diph);\r
239     if(ddrval!=DI_OK)\r
240     {\r
241      ShowDIJErr(w,"Error getting X axis range.");\r
242      KillJoystick(w);\r
243      joy[w]=0;\r
244      return;\r
245     }\r
246     r=diprg.lMax-diprg.lMin;\r
247     JoyYMax[w]=diprg.lMax-(r>>2);\r
248     JoyYMin[w]=diprg.lMin+(r>>2);\r
249    }\r
250 \r
251   }\r
252 }\r
253 \r
254 void InitJoysticks(HWND wnd)\r
255 {\r
256  int x;\r
257 \r
258  joycounter=0;\r
259  IDirectInput7_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK,JoystickFound,0,DIEDFL_ATTACHEDONLY);\r
260  \r
261  for(x=0;x<4;x++)\r
262   InitJoystick(x,wnd);\r
263 }\r
264 \r
265 \r
266 static int joyconport;\r
267 \r
268 static BOOL CALLBACK JoyConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
269 {\r
270   char tempo[64];\r
271   int x;\r
272   static int bid;\r
273 \r
274   switch(uMsg) {\r
275    case WM_TIMER:\r
276                  if(bid>=200 && bid<=215)\r
277                  {\r
278                   int z;\r
279 \r
280                   /* GetJoystickButton() makes sure there is a joystick,\r
281                      so we don't need to here.\r
282                   */                     \r
283                   if(bid<=207)\r
284                   {\r
285                    if( (z=GetJoystickButton(joyconport))!=-1)\r
286                      SetDlgItemInt(hwndDlg,bid,z,0);\r
287                    }\r
288                    else\r
289                    {\r
290                     if( (z=GetJoystickButton(2+joyconport))!=-1)\r
291                      SetDlgItemInt(hwndDlg,bid,z,0);\r
292                    }\r
293                  }\r
294                 break;\r
295    case WM_INITDIALOG:\r
296                 bid=0;\r
297                 SetTimer(hwndDlg,666,20,0);     /* Every 20ms(50x a second).*/\r
298 \r
299                 InitJoysticks(hwndDlg);\r
300 \r
301                 SendDlgItemMessage(hwndDlg,106,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");\r
302                 SendDlgItemMessage(hwndDlg,112,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");\r
303 \r
304                 sprintf(tempo,"Virtual Gamepad %d",joyconport+1);\r
305                 SetDlgItemText(hwndDlg,102,tempo);\r
306                 sprintf(tempo,"Virtual Gamepad %d",joyconport+3);\r
307                 SetDlgItemText(hwndDlg,104,tempo);\r
308 \r
309                 for(x=0;x<=2;x+=2)\r
310                 {\r
311                  SetDlgItemInt(hwndDlg,200+(x<<2),joySelect[x+joyconport],0);\r
312                  SetDlgItemInt(hwndDlg,201+(x<<2),joyStart[x+joyconport],0);\r
313                  SetDlgItemInt(hwndDlg,202+(x<<2),joyB[x+joyconport],0);\r
314                  SetDlgItemInt(hwndDlg,203+(x<<2),joyA[x+joyconport],0);\r
315 \r
316                  SetDlgItemInt(hwndDlg,204+(x<<2),joyUp[x+joyconport],0);\r
317                  SetDlgItemInt(hwndDlg,205+(x<<2),joyDown[x+joyconport],0);\r
318                  SetDlgItemInt(hwndDlg,206+(x<<2),joyLeft[x+joyconport],0);\r
319                  SetDlgItemInt(hwndDlg,207+(x<<2),joyRight[x+joyconport],0);\r
320 \r
321                 }\r
322                 joycounter=0;\r
323                 IDirectInput7_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK,JoystickFound,hwndDlg,DIEDFL_ATTACHEDONLY);\r
324 \r
325                 SendDlgItemMessage(hwndDlg,106,CB_SETCURSEL,joy[0+joyconport],(LPARAM)(LPSTR)0);\r
326                 SendDlgItemMessage(hwndDlg,112,CB_SETCURSEL,joy[2+joyconport],(LPARAM)(LPSTR)0);\r
327                 \r
328                 if(joyOptions[joyconport]&1)\r
329                  CheckDlgButton(hwndDlg,300,BST_CHECKED);\r
330                 if(joyOptions[joyconport+2]&1)\r
331                  CheckDlgButton(hwndDlg,301,BST_CHECKED);               \r
332                 break;\r
333    case WM_CLOSE:\r
334    case WM_QUIT: goto gornk;\r
335    case WM_COMMAND:\r
336                 if(HIWORD(wParam)==EN_SETFOCUS)\r
337                 {\r
338                  bid=LOWORD(wParam);\r
339                 }\r
340                 else if(HIWORD(wParam)==EN_KILLFOCUS)\r
341                 {\r
342                  bid=0;\r
343                 }\r
344                 else if(HIWORD(wParam)==CBN_SELENDOK)\r
345                 {\r
346                  switch(LOWORD(wParam))\r
347                  {\r
348                   case 106:\r
349                    KillJoystick(joyconport);\r
350                    joy[0+(joyconport)]=SendDlgItemMessage(hwndDlg,106,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
351                    InitJoystick(joyconport,hwndDlg);\r
352                    SendDlgItemMessage(hwndDlg,106,CB_SETCURSEL,joy[0+joyconport],(LPARAM)(LPSTR)0);\r
353                    break;\r
354                   case 112:\r
355                    KillJoystick(2+joyconport);\r
356                    joy[2+(joyconport)]=SendDlgItemMessage(hwndDlg,112,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
357                    InitJoystick(2+joyconport,hwndDlg);                                      \r
358                    SendDlgItemMessage(hwndDlg,112,CB_SETCURSEL,joy[2+joyconport],(LPARAM)(LPSTR)0);\r
359                    break;\r
360                  }\r
361                 }\r
362 \r
363                 if(!(wParam>>16))\r
364                 switch(wParam&0xFFFF)\r
365                 {\r
366                  case 1:\r
367                         gornk:\r
368 \r
369                         KillTimer(hwndDlg,666);\r
370                         KillJoysticks();\r
371 \r
372                         for(x=0;x<=2;x+=2)\r
373                         {\r
374                          joySelect[x+(joyconport)]=GetDlgItemInt(hwndDlg,200+(x<<2),0,0);\r
375                          joyStart[x+(joyconport)]=GetDlgItemInt(hwndDlg,201+(x<<2),0,0);\r
376                          joyB[x+(joyconport)]=GetDlgItemInt(hwndDlg,202+(x<<2),0,0);\r
377                          joyA[x+(joyconport)]=GetDlgItemInt(hwndDlg,203+(x<<2),0,0);\r
378 \r
379                          joyUp[x+(joyconport)]=GetDlgItemInt(hwndDlg,204+(x<<2),0,0);\r
380                          joyDown[x+(joyconport)]=GetDlgItemInt(hwndDlg,205+(x<<2),0,0);\r
381                          joyLeft[x+(joyconport)]=GetDlgItemInt(hwndDlg,206+(x<<2),0,0);\r
382                          joyRight[x+(joyconport)]=GetDlgItemInt(hwndDlg,207+(x<<2),0,0);\r
383                         }\r
384                         if(IsDlgButtonChecked(hwndDlg,300)==BST_CHECKED)\r
385                          joyOptions[joyconport]|=1;\r
386                         else\r
387                          joyOptions[joyconport]&=~1;\r
388                         if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)\r
389                          joyOptions[joyconport+2]|=1;\r
390                         else\r
391                          joyOptions[joyconport+2]&=~1;                        \r
392                         EndDialog(hwndDlg,0);\r
393                         break;\r
394                }\r
395               }\r
396   return 0;\r
397 }\r
398 \r
399 void ConfigJoystickies(HWND hParent, int port)\r
400 {\r
401  joyconport=port;\r
402 \r
403  KillJoysticks();\r
404  DialogBox(fceu_hInstance,"JOYCONFIG",hParent,JoyConCallB);\r
405  InitJoysticks(hAppWnd);\r
406 }\r
407 \r