gpfce patch
[fceu.git] / drivers / win / joystick.c
CommitLineData
c62d2810 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
28HRESULT ddrval;\r
29\r
30static GUID joyGUID[64];\r
31\r
32static int joycounter;\r
33\r
34static LPDIRECTINPUTDEVICE7 lpJoy[4]={0,0,0,0};\r
35\r
36int joyOptions[4]={0,0,0,0};\r
37int joyA[4]={1,1,1,1};\r
38int joyB[4]={0,0,0,0};\r
39int joySelect[4]={2,2,2,2};\r
40int joyStart[4]={3,3,3,3};\r
41int joyUp[4]={4,4,4,4};\r
42int joyDown[4]={5,5,5,5};\r
43int joyLeft[4]={6,6,6,6};\r
44int joyRight[4]={7,7,7,7};\r
45\r
46int joy[4]={0,0,0,0};\r
47\r
48static int JoyXMax[4];\r
49static int JoyXMin[4];\r
50\r
51static int JoyYMax[4];\r
52static int JoyYMin[4];\r
53\r
54static DIJOYSTATE2 JoyStatus;\r
55\r
56static 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
63static 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
74static 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
97uint32 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
143static 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
153void 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
160static 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
177void 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
254void 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
266static int joyconport;\r
267\r
268static 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
399void 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