1 // Burner Input Dialog module
2 #include "burner.h"
3 
4 HWND hInpdDlg = NULL;							// Handle to the Input Dialog
5 static HWND hInpdList = NULL;
6 static unsigned char *LastVal = NULL;			// Last input values/defined
7 static int bLastValDefined = 0;					//
8 
9 static HWND hInpdGi = NULL, hInpdPci = NULL, hInpdAnalog = NULL;	// Combo boxes
10 
11 // Update which input is using which PC input
InpdUseUpdate()12 static int InpdUseUpdate()
13 {
14 	unsigned int i, j = 0;
15 	struct GameInp* pgi = NULL;
16 	if (hInpdList == NULL) {
17 		return 1;
18 	}
19 
20 	// Update the values of all the inputs
21 	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
22 		LVITEM LvItem;
23 		TCHAR* pszVal = NULL;
24 
25 		if (pgi->Input.pVal == NULL) {
26 			continue;
27 		}
28 
29 		pszVal = InpToDesc(pgi);
30 
31 		if (_tcscmp(pszVal, _T("code 0x00")) == 0)
32 			pszVal = _T("Unassigned (locked)");
33 
34 		memset(&LvItem, 0, sizeof(LvItem));
35 		LvItem.mask = LVIF_TEXT;
36 		LvItem.iItem = j;
37 		LvItem.iSubItem = 1;
38 		LvItem.pszText = pszVal;
39 
40 		SendMessage(hInpdList, LVM_SETITEM, 0, (LPARAM)&LvItem);
41 
42 		j++;
43 	}
44 
45 	for (i = 0, pgi = GameInp + nGameInpCount; i < nMacroCount; i++, pgi++) {
46 		LVITEM LvItem;
47 		TCHAR* pszVal = NULL;
48 
49 		if (pgi->nInput & GIT_GROUP_MACRO) {
50 			pszVal = InpMacroToDesc(pgi);
51 
52 			if (_tcscmp(pszVal, _T("code 0x00")) == 0)
53 				pszVal = _T("Unassigned (locked)");
54 
55 			memset(&LvItem, 0, sizeof(LvItem));
56 			LvItem.mask = LVIF_TEXT;
57 			LvItem.iItem = j;
58 			LvItem.iSubItem = 1;
59 			LvItem.pszText = pszVal;
60 
61 			SendMessage(hInpdList, LVM_SETITEM, 0, (LPARAM)&LvItem);
62 		}
63 
64 		j++;
65 	}
66 
67 	return 0;
68 }
69 
InpdUpdate()70 int InpdUpdate()
71 {
72 	unsigned int i, j = 0;
73 	struct GameInp* pgi = NULL;
74 	unsigned char* plv = NULL;
75 	unsigned short nThisVal;
76 	if (hInpdList == NULL) {
77 		return 1;
78 	}
79 	if (LastVal == NULL) {
80 		return 1;
81 	}
82 
83 	// Update the values of all the inputs
84 	for (i = 0, pgi = GameInp, plv = LastVal; i < nGameInpCount; i++, pgi++, plv++) {
85 		LVITEM LvItem;
86 		TCHAR szVal[16];
87 
88 		if (pgi->nType == 0) {
89 			continue;
90 		}
91 
92 		if (pgi->nType & BIT_GROUP_ANALOG) {
93 			if (bRunPause) {														// Update LastVal
94 				nThisVal = pgi->Input.nVal;
95 			} else {
96 				nThisVal = *pgi->Input.pShortVal;
97 			}
98 
99 			if (bLastValDefined && (pgi->nType != BIT_ANALOG_REL || nThisVal) && pgi->Input.nVal == *((unsigned short*)plv)) {
100 				j++;
101 				continue;
102 			}
103 
104 			*((unsigned short*)plv) = nThisVal;
105 		} else {
106 			if (bRunPause) {														// Update LastVal
107 				nThisVal = pgi->Input.nVal;
108 			} else {
109 				nThisVal = *pgi->Input.pVal;
110 			}
111 
112 			if (bLastValDefined && pgi->Input.nVal == *plv) {						// hasn't changed
113 				j++;
114 				continue;
115 			}
116 
117 			*plv = nThisVal;
118 		}
119 
120 		switch (pgi->nType) {
121 			case BIT_DIGITAL: {
122 				if (nThisVal == 0) {
123 					szVal[0] = 0;
124 				} else {
125 					if (nThisVal == 1) {
126 						_tcscpy(szVal, _T("ON"));
127 					} else {
128 						_stprintf(szVal, _T("0x%02X"), nThisVal);
129 					}
130 				}
131 				break;
132 			}
133 			case BIT_ANALOG_ABS: {
134 				_stprintf(szVal, _T("0x%02X"), nThisVal >> 8);
135 				break;
136 			}
137 			case BIT_ANALOG_REL: {
138 				if (nThisVal == 0) {
139 					szVal[0] = 0;
140 				}
141 				if ((short)nThisVal < 0) {
142 					_stprintf(szVal, _T("%d"), ((short)nThisVal) >> 8);
143 				}
144 				if ((short)nThisVal > 0) {
145 					_stprintf(szVal, _T("+%d"), ((short)nThisVal) >> 8);
146 				}
147 				break;
148 			}
149 			default: {
150 				_stprintf(szVal, _T("0x%02X"), nThisVal);
151 			}
152 		}
153 
154 		memset(&LvItem, 0, sizeof(LvItem));
155 		LvItem.mask = LVIF_TEXT;
156 		LvItem.iItem = j;
157 		LvItem.iSubItem = 2;
158 		LvItem.pszText = szVal;
159 
160 		SendMessage(hInpdList, LVM_SETITEM, 0, (LPARAM)&LvItem);
161 
162 		j++;
163 	}
164 
165 	bLastValDefined = 1;										// LastVal is now defined
166 
167 	return 0;
168 }
169 
InpdListBegin()170 static int InpdListBegin()
171 {
172 	LVCOLUMN LvCol;
173 	if (hInpdList == NULL) {
174 		return 1;
175 	}
176 
177 	// Full row select style:
178 	SendMessage(hInpdList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
179 
180 	// Make column headers
181 	memset(&LvCol, 0, sizeof(LvCol));
182 	LvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
183 
184 	LvCol.cx = 0xa0;
185 	LvCol.pszText = FBALoadStringEx(hAppInst, IDS_INPUT_INPUT, true);
186 	SendMessage(hInpdList, LVM_INSERTCOLUMN, 0, (LPARAM)&LvCol);
187 
188 	LvCol.cx = 0xa0;
189 	LvCol.pszText = FBALoadStringEx(hAppInst, IDS_INPUT_MAPPING, true);
190 	SendMessage(hInpdList, LVM_INSERTCOLUMN, 1, (LPARAM)&LvCol);
191 
192 	LvCol.cx = 0x38;
193 	LvCol.pszText = FBALoadStringEx(hAppInst, IDS_INPUT_STATE, true);
194 	SendMessage(hInpdList, LVM_INSERTCOLUMN, 2, (LPARAM)&LvCol);
195 
196 	return 0;
197 }
198 
199 // Make a list view of the game inputs
InpdListMake(int bBuild)200 int InpdListMake(int bBuild)
201 {
202 	unsigned int j = 0;
203 
204 	if (hInpdList == NULL) {
205 		return 1;
206 	}
207 
208 	bLastValDefined = 0;
209 	if (bBuild)	{
210 		SendMessage(hInpdList, LVM_DELETEALLITEMS, 0, 0);
211 	}
212 
213 	// Add all the input names to the list
214 	for (unsigned int i = 0; i < nGameInpCount; i++) {
215 		struct BurnInputInfo bii;
216 		LVITEM LvItem;
217 
218 		// Get the name of the input
219 		bii.szName = NULL;
220 		BurnDrvGetInputInfo(&bii, i);
221 
222 		// skip unused inputs
223 		if (bii.pVal == NULL) {
224 			continue;
225 		}
226 		if (bii.szName == NULL)	{
227 			bii.szName = "";
228 		}
229 
230 		memset(&LvItem, 0, sizeof(LvItem));
231 		LvItem.mask = LVIF_TEXT | LVIF_PARAM;
232 		LvItem.iItem = j;
233 		LvItem.iSubItem = 0;
234 		LvItem.pszText = ANSIToTCHAR(bii.szName, NULL, 0);
235 		LvItem.lParam = (LPARAM)i;
236 
237 		SendMessage(hInpdList, bBuild ? LVM_INSERTITEM : LVM_SETITEM, 0, (LPARAM)&LvItem);
238 
239 		j++;
240 	}
241 
242 	struct GameInp* pgi = GameInp + nGameInpCount;
243 	for (unsigned int i = 0; i < nMacroCount; i++, pgi++) {
244 		LVITEM LvItem;
245 
246 		if (pgi->nInput & GIT_GROUP_MACRO) {
247 			memset(&LvItem, 0, sizeof(LvItem));
248 			LvItem.mask = LVIF_TEXT | LVIF_PARAM;
249 			LvItem.iItem = j;
250 			LvItem.iSubItem = 0;
251 			LvItem.pszText = ANSIToTCHAR(pgi->Macro.szName, NULL, 0);
252 			LvItem.lParam = (LPARAM)j;
253 
254 			SendMessage(hInpdList, bBuild ? LVM_INSERTITEM : LVM_SETITEM, 0, (LPARAM)&LvItem);
255 		}
256 
257 		j++;
258 	}
259 
260 	InpdUseUpdate();
261 
262 	return 0;
263 }
264 
DisablePresets()265 static void DisablePresets()
266 {
267 	EnableWindow(hInpdPci, FALSE);
268 	EnableWindow(hInpdAnalog, FALSE);
269 	EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), FALSE);
270 	EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), FALSE);
271 }
272 
InitComboboxes()273 static void InitComboboxes()
274 {
275 	TCHAR szLabel[1024];
276 	HANDLE search;
277 	WIN32_FIND_DATA findData;
278 
279 	for (int i = 0; i < 4; i++) {
280 		_stprintf(szLabel, FBALoadStringEx(hAppInst, IDS_INPUT_INP_PLAYER, true), i + 1);
281 		SendMessage(hInpdGi, CB_ADDSTRING, 0, (LPARAM)szLabel);
282 	}
283 
284 	SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_INP_KEYBOARD, true));
285 	for (int i = 0; i < 3; i++) {
286 		_stprintf(szLabel, FBALoadStringEx(hAppInst, IDS_INPUT_INP_JOYSTICK, true), i);
287 		SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)szLabel);
288 	}
289 	SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_INP_XARCADEL, true));
290 	SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_INP_XARCADER, true));
291 	SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_INP_HOTRODL, true));
292 	SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_INP_HOTRODR, true));
293 
294 	// Scan presets directory for .ini files and add them to the list
295 	if ((search = FindFirstFile(_T("config/presets/*.ini"), &findData)) != INVALID_HANDLE_VALUE) {
296 		do {
297 			findData.cFileName[_tcslen(findData.cFileName) - 4] = 0;
298 			SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)findData.cFileName);
299 		} while (FindNextFile(search, &findData) != 0);
300 
301 		FindClose(search);
302 	}
303 }
304 
InpdInit()305 static int InpdInit()
306 {
307 	int nMemLen;
308 
309 	hInpdList = GetDlgItem(hInpdDlg, IDC_INPD_LIST);
310 
311 	// Allocate a last val array for the last input values
312 	nMemLen = nGameInpCount * sizeof(char);
313 	LastVal = (unsigned char*)malloc(nMemLen);
314 	if (LastVal == NULL) {
315 		return 1;
316 	}
317 	memset(LastVal, 0, nMemLen);
318 
319 	InpdListBegin();
320 	InpdListMake(1);
321 
322 	// Init the Combo boxes
323 	hInpdGi = GetDlgItem(hInpdDlg, IDC_INPD_GI);
324 	hInpdPci = GetDlgItem(hInpdDlg, IDC_INPD_PCI);
325 	hInpdAnalog = GetDlgItem(hInpdDlg, IDC_INPD_ANALOG);
326 	InitComboboxes();
327 
328 	DisablePresets();
329 
330 	return 0;
331 }
332 
InpdExit()333 static int InpdExit()
334 {
335 	// Exit the Combo boxes
336 	hInpdPci = NULL;
337 	hInpdGi = NULL;
338 	hInpdAnalog = NULL;
339 
340 	if (LastVal != NULL) {
341 		free(LastVal);
342 		LastVal = NULL;
343 	}
344 	hInpdList = NULL;
345 	hInpdDlg = NULL;
346 	if (!bAltPause && bRunPause) {
347 		bRunPause=0;
348 	}
349 	GameInpCheckMouse();
350 
351 	return 0;
352 }
353 
GameInpConfigOne(int nPlayer,int nPcDev,int nAnalog,struct GameInp * pgi,char * szi)354 static void GameInpConfigOne(int nPlayer, int nPcDev, int nAnalog, struct GameInp* pgi, char* szi)
355 {
356 	switch (nPcDev) {
357 		case  0:
358 			GamcPlayer(pgi, szi, nPlayer, -1);						// Keyboard
359 			GamcAnalogKey(pgi, szi, nPlayer, nAnalog);
360 			GamcMisc(pgi, szi, nPlayer);
361 			break;
362 		case  1:
363 			GamcPlayer(pgi, szi, nPlayer, 0);						// Joystick 1
364 			GamcAnalogJoy(pgi, szi, nPlayer, 0, nAnalog);
365 			GamcMisc(pgi, szi, nPlayer);
366 			break;
367 		case  2:
368 			GamcPlayer(pgi, szi, nPlayer, 1);						// Joystick 2
369 			GamcAnalogJoy(pgi, szi, nPlayer, 1, nAnalog);
370 			GamcMisc(pgi, szi, nPlayer);
371 			break;
372 		case  3:
373 			GamcPlayer(pgi, szi, nPlayer, 2);						// Joystick 3
374 			GamcAnalogJoy(pgi, szi, nPlayer, 2, nAnalog);
375 			GamcMisc(pgi, szi, nPlayer);
376 			break;
377 		case  4:
378 			GamcPlayerHotRod(pgi, szi, nPlayer, 0x10, nAnalog);		// X-Arcade left side
379 			GamcMisc(pgi, szi, -1);
380 			break;
381 		case  5:
382 			GamcPlayerHotRod(pgi, szi, nPlayer, 0x11, nAnalog);		// X-Arcade right side
383 			GamcMisc(pgi, szi, -1);
384 			break;
385 		case  6:
386 			GamcPlayerHotRod(pgi, szi, nPlayer, 0x00, nAnalog);		// HotRod left side
387 			GamcMisc(pgi, szi, -1);
388 			break;
389 		case  7:
390 			GamcPlayerHotRod(pgi, szi, nPlayer, 0x01, nAnalog);		// HotRod right size
391 			GamcMisc(pgi, szi, -1);
392 			break;
393 	}
394 }
395 
396 // Configure some of the game input
GameInpConfig(int nPlayer,int nPcDev,int nAnalog)397 static int GameInpConfig(int nPlayer, int nPcDev, int nAnalog)
398 {
399 	struct GameInp* pgi = NULL;
400 	unsigned int i;
401 
402 	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
403 		struct BurnInputInfo bii;
404 
405 		// Get the extra info about the input
406 		bii.szInfo = NULL;
407 		BurnDrvGetInputInfo(&bii, i);
408 		if (bii.pVal == NULL) {
409 			continue;
410 		}
411 		if (bii.szInfo == NULL) {
412 			bii.szInfo = "";
413 		}
414 		GameInpConfigOne(nPlayer, nPcDev, nAnalog, pgi, bii.szInfo);
415 	}
416 
417 	for (i = 0; i < nMacroCount; i++, pgi++) {
418 		GameInpConfigOne(nPlayer, nPcDev, nAnalog, pgi, pgi->Macro.szName);
419 	}
420 
421 	GameInpCheckLeftAlt();
422 
423 	return 0;
424 }
425 
426 // List item activated; find out which one
ListItemActivate()427 static int ListItemActivate()
428 {
429 	struct BurnInputInfo bii;
430 	LVITEM LvItem;
431 
432 	memset(&LvItem, 0, sizeof(LvItem));
433 	int nSel = SendMessage(hInpdList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED);
434 	if (nSel < 0) {
435 		return 1;
436 	}
437 
438 	// Get the corresponding input
439 	LvItem.mask = LVIF_PARAM;
440 	LvItem.iItem = nSel;
441 	LvItem.iSubItem = 0;
442 	SendMessage(hInpdList, LVM_GETITEM, 0, (LPARAM)&LvItem);
443 	nSel = LvItem.lParam;
444 
445 	if (nSel >= (int)(nGameInpCount + nMacroCount)) {	// out of range
446 		return 1;
447 	}
448 
449 	memset(&bii, 0, sizeof(bii));
450 	bii.nType = 0;
451 	int rc = BurnDrvGetInputInfo(&bii, nSel);
452 	if (bii.pVal == NULL && rc != 1) {                  // rc == 1 for a macro or system macro.
453 		return 1;
454 	}
455 
456 	DestroyWindow(hInpsDlg);							// Make sure any existing dialogs are gone
457 	DestroyWindow(hInpcDlg);							//
458 
459 	if (bii.nType & BIT_GROUP_CONSTANT) {
460 		// Dip switch is a constant - change it
461 		nInpcInput = nSel;
462 		InpcCreate();
463 	} else {
464 		if (GameInp[nSel].nInput == GIT_MACRO_CUSTOM) {
465 #if 0
466 			InpMacroCreate(nSel);
467 #endif
468 		} else {
469 			// Assign to a key
470 			nInpsInput = nSel;
471 			InpsCreate();
472 		}
473 	}
474 
475 	GameInpCheckLeftAlt();
476 
477 	return 0;
478 }
479 
480 #if 0
481 static int NewMacroButton()
482 {
483 	LVITEM LvItem;
484 	int nSel;
485 
486 	DestroyWindow(hInpsDlg);							// Make sure any existing dialogs are gone
487 	DestroyWindow(hInpcDlg);							//
488 
489 	nSel = SendMessage(hInpdList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED);
490 	if (nSel < 0) {
491 		nSel = -1;
492 	}
493 
494 	// Get the corresponding input
495 	LvItem.mask = LVIF_PARAM;
496 	LvItem.iItem = nSel;
497 	LvItem.iSubItem = 0;
498 	SendMessage(hInpdList, LVM_GETITEM, 0, (LPARAM)&LvItem);
499 	nSel = LvItem.lParam;
500 
501 	if (nSel >= (int)nGameInpCount && nSel < (int)(nGameInpCount + nMacroCount)) {
502 		if (GameInp[nSel].nInput != GIT_MACRO_CUSTOM) {
503 			nSel = -1;
504 		}
505 	} else {
506 		nSel = -1;
507 	}
508 
509 	InpMacroCreate(nSel);
510 
511 	return 0;
512 }
513 #endif
514 
DeleteInput(unsigned int i)515 static int DeleteInput(unsigned int i)
516 {
517 	struct BurnInputInfo bii;
518 
519 	if (i >= nGameInpCount) {
520 
521 		if (i < nGameInpCount + nMacroCount) {	// Macro
522 			GameInp[i].Macro.nMode = 0;
523 		} else { 								// out of range
524 			return 1;
525 		}
526 	} else {									// "True" input
527 		bii.nType = BIT_DIGITAL;
528 		BurnDrvGetInputInfo(&bii, i);
529 		if (bii.pVal == NULL) {
530 			return 1;
531 		}
532 		if (bii.nType & BIT_GROUP_CONSTANT) {	// Don't delete dip switches
533 			return 1;
534 		}
535 
536 		GameInp[i].nInput = 0;
537 	}
538 
539 	GameInpCheckLeftAlt();
540 
541 	return 0;
542 }
543 
544 // List item(s) deleted; find out which one(s)
ListItemDelete()545 static int ListItemDelete()
546 {
547 	int nStart = -1;
548 	LVITEM LvItem;
549 	int nRet;
550 
551 	while ((nRet = SendMessage(hInpdList, LVM_GETNEXTITEM, (WPARAM)nStart, LVNI_SELECTED)) != -1) {
552 		nStart = nRet;
553 
554 		// Get the corresponding input
555 		LvItem.mask = LVIF_PARAM;
556 		LvItem.iItem = nRet;
557 		LvItem.iSubItem = 0;
558 		SendMessage(hInpdList, LVM_GETITEM, 0, (LPARAM)&LvItem);
559 		nRet = LvItem.lParam;
560 
561 		DeleteInput(nRet);
562 	}
563 
564 	InpdListMake(0);							// refresh view
565 	return 0;
566 }
567 
InitAnalogOptions(int nGi,int nPci)568 static int InitAnalogOptions(int nGi, int nPci)
569 {
570 	// init analog options dialog
571 	int nAnalog = -1;
572 	if (nPci == (nPlayerDefaultControls[nGi] & 0x0F)) {
573 		nAnalog = nPlayerDefaultControls[nGi] >> 4;
574 	}
575 
576 	SendMessage(hInpdAnalog, CB_RESETCONTENT, 0, 0);
577 	if (nPci >= 1 && nPci <= 3) {
578 		// Absolute mode only for joysticks
579 		SendMessage(hInpdAnalog, CB_ADDSTRING, 0, (LPARAM)(LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_ANALOG_ABS, true));
580 	} else {
581 		if (nAnalog > 0) {
582 			nAnalog--;
583 		}
584 	}
585 	SendMessage(hInpdAnalog, CB_ADDSTRING, 0, (LPARAM)(LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_ANALOG_AUTO, true));
586 	SendMessage(hInpdAnalog, CB_ADDSTRING, 0, (LPARAM)(LPARAM)FBALoadStringEx(hAppInst, IDS_INPUT_ANALOG_NORMAL, true));
587 
588 	SendMessage(hInpdAnalog, CB_SETCURSEL, (WPARAM)nAnalog, 0);
589 
590 	return 0;
591 }
592 
SaveHardwarePreset()593 static void SaveHardwarePreset()
594 {
595 	TCHAR *szDefaultCpsFile = _T("config\\presets\\cps.ini");
596 	TCHAR *szDefaultNeogeoFile = _T("config\\presets\\neogeo.ini");
597 	TCHAR *szDefaultPgmFile = _T("config\\presets\\pgm.ini");
598 	TCHAR *szFileName = _T("config\\presets\\preset.ini");
599 	TCHAR *szHardwareString = _T("Generic hardware");
600 
601 	int nHardwareFlag = (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK);
602 
603 	if (nHardwareFlag == HARDWARE_CAPCOM_CPS1 || nHardwareFlag == HARDWARE_CAPCOM_CPS1_QSOUND || nHardwareFlag == HARDWARE_CAPCOM_CPS1_GENERIC || nHardwareFlag == HARDWARE_CAPCOM_CPSCHANGER || nHardwareFlag == HARDWARE_CAPCOM_CPS2 || nHardwareFlag == HARDWARE_CAPCOM_CPS3) {
604 		szFileName = szDefaultCpsFile;
605 		szHardwareString = _T("CPS-1/CPS-2/CPS-3 hardware");
606 	}
607 
608 	if (nHardwareFlag == HARDWARE_SNK_NEOGEO) {
609 		szFileName = szDefaultNeogeoFile;
610 		szHardwareString = _T("Neo-Geo hardware");
611 	}
612 
613 	if (nHardwareFlag == HARDWARE_IGS_PGM) {
614 		szFileName = szDefaultPgmFile;
615 		szHardwareString = _T("PGM hardware");
616 	}
617 
618 	FILE *fp = _tfopen(szFileName, _T("wt"));
619 	if (fp) {
620 		_ftprintf(fp, _T(APP_TITLE) _T(" - Hardware Default Preset\n\n"));
621 		_ftprintf(fp, _T("%s\n\n"), szHardwareString);
622 		_ftprintf(fp, _T("version 0x%06X\n\n"), nBurnVer);
623 		GameInpWrite(fp);
624 		fclose(fp);
625 	}
626 
627 	// add to dropdown (if not already there)
628 	TCHAR szPresetName[MAX_PATH] = _T("");
629 	int iCBItem = 0;
630 
631 	memcpy(szPresetName, szFileName + 15, (_tcslen(szFileName) - 19) * sizeof(TCHAR));
632 	iCBItem = SendMessage(hInpdPci, CB_FINDSTRING, -1, (LPARAM)szPresetName);
633 	if (iCBItem == -1) SendMessage(hInpdPci, CB_ADDSTRING, 0, (LPARAM)szPresetName);
634 
635 	// confirm to user
636 	FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_PRESET_SAVED), szFileName);
637 	FBAPopupDisplay(PUF_TYPE_INFO);
638 }
639 
UsePreset(bool bMakeDefault)640 int UsePreset(bool bMakeDefault)
641 {
642 	int nGi, nPci, nAnalog = 0;
643 	TCHAR szFilename[MAX_PATH] = _T("config\\presets\\");
644 
645 	nGi = SendMessage(hInpdGi, CB_GETCURSEL, 0, 0);
646 	if (nGi == CB_ERR) {
647 		return 1;
648 	}
649 	nPci = SendMessage(hInpdPci, CB_GETCURSEL, 0, 0);
650 	if (nPci == CB_ERR) {
651 		return 1;
652 	}
653 	if (nPci <= 7) {
654 		// Determine analog option
655 		nAnalog = SendMessage(hInpdAnalog, CB_GETCURSEL, 0, 0);
656 		if (nAnalog == CB_ERR) {
657 			return 1;
658 		}
659 
660 		if (nPci == 0 || nPci > 3) {				// No "Absolute" option for keyboard or X-Arcade/HotRod controls
661 			nAnalog++;
662 		}
663 
664 		GameInpConfig(nGi, nPci, nAnalog);			// Re-configure inputs
665 	} else {
666 		// Find out the filename of the preset ini
667 		SendMessage(hInpdPci, CB_GETLBTEXT, nPci, (LPARAM)(szFilename + _tcslen(szFilename)));
668 		_tcscat(szFilename, _T(".ini"));
669 
670 		GameInputAutoIni(nGi, szFilename, true);	// Read inputs from file
671 
672 		// Make sure all inputs are defined
673 		for (unsigned int i = 0, j = 0; i < nGameInpCount; i++) {
674 			if (GameInp[i].Input.pVal == NULL) {
675 				continue;
676 			}
677 
678 			if (GameInp[i].nInput == 0) {
679 				DeleteInput(j);
680 			}
681 
682 			j++;
683 		}
684 
685 		nPci = 0x0F;
686 	}
687 
688 	SendMessage(hInpdAnalog, CB_SETCURSEL, (WPARAM)-1, 0);
689 	SendMessage(hInpdPci, CB_SETCURSEL, (WPARAM)-1, 0);
690 	SendMessage(hInpdGi, CB_SETCURSEL, (WPARAM)-1, 0);
691 
692 	DisablePresets();
693 
694 	if (bMakeDefault) {
695 		nPlayerDefaultControls[nGi] = nPci | (nAnalog << 4);
696 		_tcscpy(szPlayerDefaultIni[nGi], szFilename);
697 	}
698 
699 	GameInpCheckLeftAlt();
700 
701 	return 0;
702 }
703 
DialogProc(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam)704 static INT_PTR CALLBACK DialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
705 {
706 	if (Msg == WM_INITDIALOG) {
707 		hInpdDlg = hDlg;
708 		InpdInit();
709 		if (!kNetGame && bAutoPause) {
710 			bRunPause = 1;
711 		}
712 
713 		return TRUE;
714 	}
715 
716 	if (Msg == WM_CLOSE) {
717 		EnableWindow(hScrnWnd, TRUE);
718 		DestroyWindow(hInpdDlg);
719 		return 0;
720 	}
721 
722 	if (Msg == WM_DESTROY) {
723 		InpdExit();
724 		return 0;
725 	}
726 
727 	if (Msg == WM_COMMAND) {
728 		int Id = LOWORD(wParam);
729 		int Notify = HIWORD(wParam);
730 
731 		if (Id == IDOK && Notify == BN_CLICKED) {
732 			ListItemActivate();
733 			return 0;
734 		}
735 		if (Id == IDCANCEL && Notify == BN_CLICKED) {
736 			SendMessage(hDlg, WM_CLOSE, 0, 0);
737 			return 0;
738 		}
739 
740 		if (Id == IDC_INPD_NEWMACRO && Notify == BN_CLICKED) {
741 
742 //			NewMacroButton();
743 
744 			return 0;
745 		}
746 
747 		if (Id == IDC_INPD_SAVE_AS_PRESET && Notify == BN_CLICKED) {
748 			SaveHardwarePreset();
749 			return 0;
750 		}
751 
752 		if (Id == IDC_INPD_USE && Notify == BN_CLICKED) {
753 
754 			UsePreset(false);
755 
756 			InpdListMake(0);								// refresh view
757 
758 			return 0;
759 		}
760 
761 		if (Id == IDC_INPD_DEFAULT && Notify == BN_CLICKED) {
762 
763 			UsePreset(true);
764 
765 			InpdListMake(0);								// refresh view
766 
767 			return 0;
768 		}
769 
770 		if (Id == IDC_INPD_GI && Notify == CBN_SELCHANGE) {
771 			int nGi;
772 			nGi = SendMessage(hInpdGi, CB_GETCURSEL, 0, 0);
773 			if (nGi == CB_ERR) {
774 				SendMessage(hInpdPci, CB_SETCURSEL, (WPARAM)-1, 0);
775 				SendMessage(hInpdAnalog, CB_SETCURSEL, (WPARAM)-1, 0);
776 
777 				DisablePresets();
778 
779 				return 0;
780 			}
781 			int nPci = nPlayerDefaultControls[nGi] & 0x0F;
782 			SendMessage(hInpdPci, CB_SETCURSEL, nPci, 0);
783 			EnableWindow(hInpdPci, TRUE);
784 
785 			if (nPci > 5) {
786 				SendMessage(hInpdAnalog, CB_SETCURSEL, (WPARAM)-1, 0);
787 				EnableWindow(hInpdAnalog, FALSE);
788 			} else {
789 				InitAnalogOptions(nGi, nPci);
790 				EnableWindow(hInpdAnalog, TRUE);
791 			}
792 
793 			EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), TRUE);
794 			EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), TRUE);
795 
796 			return 0;
797 		}
798 
799 		if (Id == IDC_INPD_PCI && Notify == CBN_SELCHANGE) {
800 			int nGi, nPci;
801 			nGi = SendMessage(hInpdGi, CB_GETCURSEL, 0, 0);
802 			if (nGi == CB_ERR) {
803 				return 0;
804 			}
805 			nPci = SendMessage(hInpdPci, CB_GETCURSEL, 0, 0);
806 			if (nPci == CB_ERR) {
807 				return 0;
808 			}
809 
810 			if (nPci > 7) {
811 				EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), TRUE);
812 				EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), TRUE);
813 
814 				SendMessage(hInpdAnalog, CB_SETCURSEL, (WPARAM)-1, 0);
815 				EnableWindow(hInpdAnalog, FALSE);
816 			} else {
817 				EnableWindow(hInpdAnalog, TRUE);
818 				InitAnalogOptions(nGi, nPci);
819 
820 				if (SendMessage(hInpdAnalog, CB_GETCURSEL, 0, 0) != CB_ERR) {
821 					EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), TRUE);
822 					EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), TRUE);
823 				} else {
824 					EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), FALSE);
825 					EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), FALSE);
826 				}
827 			}
828 
829 			return 0;
830 		}
831 
832 		if (Id == IDC_INPD_ANALOG && Notify == CBN_SELCHANGE) {
833 			if (SendMessage(hInpdAnalog, CB_GETCURSEL, 0, 0) != CB_ERR) {
834 				EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_DEFAULT), TRUE);
835 				EnableWindow(GetDlgItem(hInpdDlg, IDC_INPD_USE), TRUE);
836 			}
837 
838 			return 0;
839 		}
840 
841 	}
842 
843 	if (Msg == WM_NOTIFY && lParam != 0) {
844 		int Id = LOWORD(wParam);
845 		NMHDR* pnm = (NMHDR*)lParam;
846 
847 		if (Id == IDC_INPD_LIST && pnm->code == LVN_ITEMACTIVATE) {
848 			ListItemActivate();
849 		}
850 		if (Id == IDC_INPD_LIST && pnm->code == LVN_KEYDOWN) {
851 			NMLVKEYDOWN *pnmkd = (NMLVKEYDOWN*)lParam;
852 			if (pnmkd->wVKey == VK_DELETE) {
853 				ListItemDelete();
854 			}
855 		}
856 
857 		if (Id == IDC_INPD_LIST && pnm->code == NM_CUSTOMDRAW) {
858 			NMLVCUSTOMDRAW* plvcd = (NMLVCUSTOMDRAW*)lParam;
859 
860 			switch (plvcd->nmcd.dwDrawStage) {
861 				case CDDS_PREPAINT:
862                     SetWindowLongPtr(hInpdDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW);
863 					return 1;
864 				case CDDS_ITEMPREPAINT:
865 					if (plvcd->nmcd.dwItemSpec < nGameInpCount) {
866 						if (GameInp[plvcd->nmcd.dwItemSpec].nType & BIT_GROUP_CONSTANT) {
867 
868 							if (GameInp[plvcd->nmcd.dwItemSpec].nInput == 0) {
869 								plvcd->clrTextBk = RGB(0xDF, 0xDF, 0xDF);
870 
871 								SetWindowLongPtr(hInpdDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
872 								return 1;
873 							}
874 
875 							if (GameInp[plvcd->nmcd.dwItemSpec].nType == BIT_DIPSWITCH) {
876 								plvcd->clrTextBk = RGB(0xFF, 0xEF, 0xD7);
877 
878 								SetWindowLongPtr(hInpdDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
879 								return 1;
880 							}
881 						}
882 					}
883 
884 					if (plvcd->nmcd.dwItemSpec >= nGameInpCount) {
885 						if (GameInp[plvcd->nmcd.dwItemSpec].Macro.nMode) {
886 							plvcd->clrTextBk = RGB(0xFF, 0xCF, 0xCF);
887 						} else {
888 							plvcd->clrTextBk = RGB(0xFF, 0xEF, 0xEF);
889 						}
890 
891 						SetWindowLongPtr(hInpdDlg, DWLP_MSGRESULT, CDRF_NEWFONT);
892 						return 1;
893 					}
894 					return 1;
895 			}
896 		}
897 		return 0;
898 	}
899 
900 	return 0;
901 }
902 
InpdCreate()903 int InpdCreate()
904 {
905 	if (bDrvOkay == 0) {
906 		return 1;
907 	}
908 
909 	DestroyWindow(hInpdDlg);										// Make sure exitted
910 
911 	hInpdDlg = FBACreateDialog(hAppInst, MAKEINTRESOURCE(IDD_INPD), hScrnWnd, (DLGPROC)DialogProc);
912 	if (hInpdDlg == NULL) {
913 		return 1;
914 	}
915 
916 	WndInMid(hInpdDlg, hScrnWnd);
917 	ShowWindow(hInpdDlg, SW_NORMAL);
918 
919 	return 0;
920 }
921 
922 
923