1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 #pragma comment(linker, \
8     "\"/manifestdependency:type='Win32' "\
9     "name='Microsoft.Windows.Common-Controls' "\
10     "version='6.0.0.0' "\
11     "processorArchitecture='*' "\
12     "publicKeyToken='6595b64144ccf1df' "\
13     "language='*'\"")
14 
15 
16 //  Win32 GUI code
17 //  (c) Copyright 2003-2006 blip, Nach, Matthew Kendora, funkyass and nitsuja
18 
19 #ifdef __MINGW32__
20 #define _WIN32_IE 0x0501
21 #define _WIN32_WINNT 0x0501
22 #endif
23 
24 #pragma warning(disable: 4091)
25 #include <shlobj.h>
26 #pragma warning(default: 4091)
27 #include <objidl.h>
28 #include <shlwapi.h>
29 #include <Shobjidl.h>
30 #include <dbt.h>
31 
32 #include "wsnes9x.h"
33 #include "win32_sound.h"
34 #include "win32_display.h"
35 #include "CCGShader.h"
36 #include "../shaders/glsl.h"
37 #include "CShaderParamDlg.h"
38 #include "../snes9x.h"
39 #include "../memmap.h"
40 #include "../cpuexec.h"
41 #include "../display.h"
42 #include "../cheats.h"
43 #include "../netplay.h"
44 #include "../apu/apu.h"
45 #include "../movie.h"
46 #include "../controls.h"
47 #include "../conffile.h"
48 #include "../statemanager.h"
49 #include "AVIOutput.h"
50 #include "InputCustom.h"
51 #include <vector>
52 #include <string>
53 
54 #ifdef DEBUGGER
55 #include "../debug.h"
56 #endif
57 
58 #if (((defined(_MSC_VER) && _MSC_VER >= 1300)) || defined(__MINGW32__))
59 	// both MINGW and VS.NET use fstream instead of fstream.h which is deprecated
60 	#include <fstream>
61 	using namespace std;
62 #else
63 	// for VC++ 6
64 	#include <fstream.h>
65 #endif
66 
67 #include <sys/stat.h>
68 //#include "string_cache.h"
69 #include "wlanguage.h"
70 #include "../language.h"
71 
72 #include <commctrl.h>
73 #include <io.h>
74 #include <time.h>
75 #include <direct.h>
76 
77 extern SNPServer NPServer;
78 
79 #include <ctype.h>
80 
81 #ifdef _MSC_VER
82 #define F_OK 0
83 #define X_OK 1
84 #define W_OK 2
85 #define R_OK 4
86 #endif
87 
88 __int64 PCBase, PCFrameTime, PCFrameTimeNTSC, PCFrameTimePAL, PCStart, PCEnd;
89 DWORD PCStartTicks, PCEndTicks;
90 
91 INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
92 INT_PTR CALLBACK DlgInfoProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
93 INT_PTR CALLBACK DlgAboutProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
94 INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
95 INT_PTR CALLBACK DlgEmulatorHacksProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
96 
97 INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
98 INT_PTR CALLBACK DlgMultiROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
99 LRESULT CALLBACK DlgChildSplitProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
100 INT_PTR CALLBACK DlgNPProgress(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
101 INT_PTR CALLBACK DlgNetConnect(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
102 INT_PTR CALLBACK DlgNPOptions(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
103 INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
104 INT_PTR CALLBACK DlgInputConfig(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
105 INT_PTR CALLBACK DlgHotkeyConfig(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
106 INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
107 INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
108 INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
109 INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
110 INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
111 HRESULT CALLBACK EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
112 int WinSearchCheatDatabase();
113 
114 VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
115 
116 void S9xDetectJoypads();
117 
118 #define NOTKNOWN "Unknown Company "
119 #define HEADER_SIZE 512
120 #define INFO_LEN (0xFF - 0xC0)
121 
122 #define WM_CUSTKEYDOWN	(WM_USER+50)
123 #define WM_CUSTKEYUP	(WM_USER+51)
124 
125 #define TIMER_SCANJOYPADS  (99999)
126 #define NC_SEARCHDB 0x8000
127 
128 #ifdef UNICODE
129 #define S9XW_SHARD_PATH SHARD_PATHW
130 #else
131 #define S9XW_SHARD_PATH SHARD_PATHA
132 #endif
133 
134 /*****************************************************************************/
135 /* Global variables                                                          */
136 /*****************************************************************************/
137 struct sGUI GUI;
138 typedef struct sExtList
139 {
140 	TCHAR* extension;
141 	bool compressed;
142 	struct sExtList* next;
143 } ExtList;
144 HANDLE SoundEvent;
145 
146 ExtList* valid_ext=NULL;
147 void MakeExtFile(void);
148 void LoadExts(void);
149 void ClearExts(void);
150 static bool ExtensionIsValid(const TCHAR *filename);
151 
152 extern FILE *trace_fs;
153 extern SCheatData Cheat;
154 extern bool8 do_frame_adjust;
155 
156 TCHAR multiRomA[MAX_PATH] = { 0 }; // lazy, should put in sGUI and add init to {0} somewhere
157 TCHAR multiRomB[MAX_PATH] = { 0 };
158 
159 HINSTANCE g_hInst;
160 
161 #ifdef DEBUGGER
162 #include "../debug.h"
163 #endif
164 
165 struct SJoypad Joypad[16] = {
166     {
167         true,					/* Joypad 1 enabled */
168 			VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN,	/* Left, Right, Up, Down */
169 			0, 0, 0, 0,             /* Left_Up, Left_Down, Right_Up, Right_Down */
170 			VK_SPACE, VK_RETURN,    /* Start, Select */
171 			'V', 'C',				/* A B */
172 			'D', 'X',				/* X Y */
173 			'A', 'S'				/* L R */
174     },
175     {
176 			true,                                  /* Joypad 2 enabled */
177 				'J', 'L', 'I', 'K',	/* Left, Right, Up, Down */
178 				0, 0, 0, 0,         /* Left_Up, Left_Down, Right_Up, Right_Down */
179 				'P', 'O',          /* Start, Select */
180 				'H', 'G',			/* A B */
181 				'T', 'F',			/* X Y */
182 				'Y', 'U'			/* L R */
183 		},
184 		{
185 				false,                                  /* Joypad 3 disabled */
186 					0, 0, 0, 0,
187 					0, 0, 0, 0,
188 					0, 0,
189 					0, 0, 0, 0, 0, 0
190 			},
191 			{
192 					false,                                  /* Joypad 4 disabled */
193 						0, 0, 0, 0,
194 						0, 0, 0, 0,
195 						0, 0,
196 						0, 0, 0, 0, 0, 0
197 				},
198 				{
199 						false,                                  /* Joypad 5 disabled */
200 							0, 0, 0, 0,
201 							0, 0, 0, 0,
202 							0, 0,
203 							0, 0, 0, 0, 0, 0
204 					},
205 				{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 6 disabled */
206 				{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 7 disabled */
207 				{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 8 disabled */
208 	{
209 			false,                                  /* Joypad 1 Turbo disabled */
210 				0, 0, 0, 0,
211 				0, 0, 0, 0,
212 				0, 0,
213 				0, 0, 0, 0, 0, 0
214 		},
215 	{
216 			false,                                  /* Joypad 2 Turbo disabled */
217 				0, 0, 0, 0,
218 				0, 0, 0, 0,
219 				0, 0,
220 				0, 0, 0, 0, 0, 0
221 		},
222 	{
223 			false,                                  /* Joypad 3 Turbo disabled */
224 				0, 0, 0, 0,
225 				0, 0, 0, 0,
226 				0, 0,
227 				0, 0, 0, 0, 0, 0
228 		},
229 	{
230 			false,                                  /* Joypad 4 Turbo disabled */
231 				0, 0, 0, 0,
232 				0, 0, 0, 0,
233 				0, 0,
234 				0, 0, 0, 0, 0, 0
235 		},
236 	{
237 			false,                                  /* Joypad 5 Turbo disabled */
238 				0, 0, 0, 0,
239 				0, 0, 0, 0,
240 				0, 0,
241 				0, 0, 0, 0, 0, 0
242 		},
243 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 6 Turbo disabled */
244 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 7 Turbo disabled */
245 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },/* Joypad 8 Turbo disabled */
246 };
247 
248 // stores on/off toggle info for each key of each controller
249 SJoypad ToggleJoypadStorage [8] = {
250 	{
251 			false,
252 				0, 0, 0, 0,
253 				0, 0, 0, 0,
254 				0, 0,
255 				0, 0, 0, 0, 0, 0
256 		},
257 	{
258 			false,
259 				0, 0, 0, 0,
260 				0, 0, 0, 0,
261 				0, 0,
262 				0, 0, 0, 0, 0, 0
263 		},
264 	{
265 			false,
266 				0, 0, 0, 0,
267 				0, 0, 0, 0,
268 				0, 0,
269 				0, 0, 0, 0, 0, 0
270 		},
271 	{
272 			false,
273 				0, 0, 0, 0,
274 				0, 0, 0, 0,
275 				0, 0,
276 				0, 0, 0, 0, 0, 0
277 		},
278 	{
279 			false,
280 				0, 0, 0, 0,
281 				0, 0, 0, 0,
282 				0, 0,
283 				0, 0, 0, 0, 0, 0
284 		},
285 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
286 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
287 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
288 };
289 
290 SJoypad TurboToggleJoypadStorage [8] = {
291 	{
292 			false,
293 				0, 0, 0, 0,
294 				0, 0, 0, 0,
295 				0, 0,
296 				0, 0, 0, 0, 0, 0
297 		},
298 	{
299 			false,
300 				0, 0, 0, 0,
301 				0, 0, 0, 0,
302 				0, 0,
303 				0, 0, 0, 0, 0, 0
304 		},
305 	{
306 			false,
307 				0, 0, 0, 0,
308 				0, 0, 0, 0,
309 				0, 0,
310 				0, 0, 0, 0, 0, 0
311 		},
312 	{
313 			false,
314 				0, 0, 0, 0,
315 				0, 0, 0, 0,
316 				0, 0,
317 				0, 0, 0, 0, 0, 0
318 		},
319 	{
320 			false,
321 				0, 0, 0, 0,
322 				0, 0, 0, 0,
323 				0, 0,
324 				0, 0, 0, 0, 0, 0
325 		},
326 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
327 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
328 			{ false, 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, 0, 0, 0, 0 },
329 };
330 
331 struct SCustomKeys CustomKeys = {
332 	{/*VK_OEM_PLUS*/0xBB,0}, // speed+ (=)
333 	{/*VK_OEM_MINUS*/0xBD,0}, // speed- (-)
334 	{VK_PAUSE,0}, // pause (PAUSE)
335 	{/*VK_OEM_5*/0xDC,0}, // frame advance (\)
336 	{/*VK_OEM_PLUS*/0xBB,CUSTKEY_SHIFT_MASK}, // skip+ (_)
337 	{/*VK_OEM_MINUS*/0xBD,CUSTKEY_SHIFT_MASK}, // skip- (+)
338 	{/*VK_OEM_3*/0xC0,0}, // superscope turbo (`)
339 	{/*VK_OEM_2*/0xBF,0}, // superscope pause (/)
340 	{/*VK_OEM_PERIOD*/0xBE,0}, // frame counter (.)
341 	{'8',CUSTKEY_SHIFT_MASK}, // movie read-only (*)
342 	{{VK_F1,CUSTKEY_SHIFT_MASK}, // save keys
343 	 {VK_F2,CUSTKEY_SHIFT_MASK},
344 	 {VK_F3,CUSTKEY_SHIFT_MASK},
345 	 {VK_F4,CUSTKEY_SHIFT_MASK},
346 	 {VK_F5,CUSTKEY_SHIFT_MASK},
347 	 {VK_F6,CUSTKEY_SHIFT_MASK},
348 	 {VK_F7,CUSTKEY_SHIFT_MASK},
349 	 {VK_F8,CUSTKEY_SHIFT_MASK},
350 	 {VK_F9,CUSTKEY_SHIFT_MASK},
351 	 {VK_F10,CUSTKEY_SHIFT_MASK}},
352 	{{VK_F1,0}, // load keys
353 	 {VK_F2,0},
354 	 {VK_F3,0},
355 	 {VK_F4,0},
356 	 {VK_F5,0},
357 	 {VK_F6,0},
358 	 {VK_F7,0},
359 	 {VK_F8,0},
360 	 {VK_F9,0},
361 	 {VK_F10,0}},
362 	{VK_TAB,0}, // fast forward (TAB)
363 	{0,0}, // fast forward toggle
364 	{/*VK_OEM_COMMA*/0xBC,0}, // show pressed keys/buttons (,)
365 	{VK_F12,0}, // save screenshot (F12)
366 	{0,0}, // slot plus (disabled by default)
367 	{0,0}, // slot minus (disabled by default)
368 	{0,0}, // slot save (disabled by default)
369 	{0,0}, // slot load (disabled by default)
370 	{0,0}, // background layer 1
371 	{0,0}, // background layer 2
372 	{0,0}, // background layer 3
373 	{0,0}, // background layer 4
374 	{0,0}, // sprite layer
375 	{0,0}, // Clipping Windows
376 //	{'8',0}, // BG Layering hack
377 	{0,0}, // Transparency
378 //	{'6',CUSTKEY_SHIFT_MASK}, // GLCube Mode
379 //	{'9',CUSTKEY_SHIFT_MASK}, // Interpolate Mode 7
380 	{'6',0}, // Joypad Swap
381 	{'7',0}, // Switch Controllers
382 	{VK_NEXT,CUSTKEY_SHIFT_MASK}, // Turbo A
383 	{VK_END,CUSTKEY_SHIFT_MASK}, // Turbo B
384 	{VK_HOME,CUSTKEY_SHIFT_MASK}, // Turbo Y
385 	{VK_PRIOR,CUSTKEY_SHIFT_MASK}, // Turbo X
386 	{VK_INSERT,CUSTKEY_SHIFT_MASK}, // Turbo L
387 	{VK_DELETE,CUSTKEY_SHIFT_MASK}, // Turbo R
388 	{0,0}, // Turbo Start
389 	{0,0}, // Turbo Select
390 	{0,0}, // Turbo Left
391 	{0,0}, // Turbo Up
392 	{0,0}, // Turbo Right
393 	{0,0}, // Turbo Down
394 	{{0,0}, // Select save slot 0
395 	 {0,0}, // Select save slot 1
396 	 {0,0}, // Select save slot 2
397 	 {0,0}, // Select save slot 3
398 	 {0,0}, // Select save slot 4
399 	 {0,0}, // Select save slot 5
400 	 {0,0}, // Select save slot 6
401 	 {0,0}, // Select save slot 7
402 	 {0,0}, // Select save slot 8
403 	 {0,0}}, // Select save slot 9
404 	{'R',CUSTKEY_CTRL_MASK|CUSTKEY_SHIFT_MASK}, // Reset Game
405 	{0,0}, // Toggle Cheats
406 	{0,0},
407     {'R',0}, // Rewind
408 };
409 
410 
411 struct SSoundRates
412 {
413     uint32 rate;
414     int ident;
415 } SoundRates[9] = {
416     { 8000, ID_SOUND_8000HZ},
417     {11025, ID_SOUND_11025HZ},
418     {16000, ID_SOUND_16000HZ},
419     {22050, ID_SOUND_22050HZ},
420     {30000, ID_SOUND_30000HZ},
421 	{32000, ID_SOUND_32000HZ},
422     {35000, ID_SOUND_35000HZ},
423     {44100, ID_SOUND_44100HZ},
424     {48000, ID_SOUND_48000HZ}
425 };
426 
427 static uint32 FrameTimings[] = {
428 	4000, 4000, 8333, 11667, 16667, 20000, 33333, 66667, 133333, 300000, 500000, 1000000, 1000000
429 };
430 
431 // Languages supported by Snes9x: Windows
432 // 0 - English [Default]
433 struct sLanguages Languages[] = {
434 	{ IDR_MENU_US,
435 		TEXT("Failed to initialize currently selected display output!\n Try switching to a different output method in the display settings."),
436 		TEXT("DirectDraw failed to set the selected display mode!"),
437 		TEXT("DirectSound failed to initialize; no sound will be played."),
438 		TEXT("These settings won't take effect until you restart the emulator."),
439 		TEXT("The frame timer failed to initialize, please do NOT select the automatic framerate option or Snes9x will crash!")}
440 };
441 
442 struct OpenMovieParams
443 {
444 	TCHAR Path[_MAX_PATH];
445 	bool8 ReadOnly;
446 	bool8 DisplayInput;
447 	uint8 ControllersMask;
448 	uint8 Opts;
449 	uint8 SyncFlags;
450 	wchar_t Metadata[MOVIE_MAX_METADATA];
451 };
452 
453 
454 
455 StateManager stateMan;
456 
457 std::vector<dMode> dm;
458 /*****************************************************************************/
459 /* WinProc                                                                   */
460 /*****************************************************************************/
461 void DoAVIOpen(const TCHAR* filename);
462 void DoAVIClose(int reason);
463 void RestoreGUIDisplay ();
464 void RestoreSNESDisplay ();
465 void FreezeUnfreezeDialog(bool8 freeze);
466 void FreezeUnfreezeSlot(int slot, bool8 freeze);
467 void FreezeUnfreeze (const char *filename, bool8 freeze);
468 void CheckDirectoryIsWritable (const char *filename);
469 static void CheckMenuStates ();
470 static void ResetFrameTimer ();
471 static bool LoadROM (const TCHAR *filename, const TCHAR *filename2 = NULL);
472 static bool LoadROMMulti (const TCHAR *filename, const TCHAR *filename2);
473 bool8 S9xLoadROMImage (const TCHAR *string);
474 #ifdef NETPLAY_SUPPORT
475 static void EnableServer (bool8 enable);
476 #endif
477 void WinDeleteRecentGamesList ();
478 const TCHAR* WinParseCommandLineAndLoadConfigFile (TCHAR *line);
479 void WinRegisterConfigItems ();
480 void WinSaveConfigFile ();
481 void WinSetDefaultValues ();
482 void WinLockConfigFile ();
483 void WinUnlockConfigFile ();
484 void WinCleanupConfigData ();
485 
486 #include "../ppu.h"
487 #include "../snapshot.h"
488 void S9xSetRecentGames ();
489 void S9xAddToRecentGames (const TCHAR *filename);
490 void S9xRemoveFromRecentGames (int i);
491 
absToRel(TCHAR * relPath,const TCHAR * absPath,const TCHAR * baseDir)492 static void absToRel(TCHAR* relPath, const TCHAR* absPath, const TCHAR* baseDir)
493 {
494 	lstrcpy(relPath, absPath);
495 	if(!_tcsncicmp(absPath, baseDir, lstrlen(baseDir)))
496 	{
497 		TCHAR temp [MAX_PATH];
498 		temp[MAX_PATH-3]=TEXT('\0');
499 		const TCHAR* relative = absPath+lstrlen(baseDir);
500 		while(relative[0]==TEXT('\\') || relative[0]==TEXT('/'))
501 			relative++;
502 		relPath[0]=TEXT('.'); relPath[1]=TEXT('\\');
503 		lstrcpy(relPath+2, relative);
504 	}
505 }
506 
SendMenuCommand(UINT uID)507 BOOL SendMenuCommand (UINT uID)
508 {
509 	MENUITEMINFO mii;
510 
511 	CheckMenuStates();
512 
513 	mii.cbSize = sizeof(mii);
514 	mii.fMask  = MIIM_STATE;
515 	if (!GetMenuItemInfo(GUI.hMenu, uID, FALSE, &mii))
516 		return FALSE;
517 	if (!(mii.fState & MFS_DISABLED))
518 		return SendMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(uID),(LPARAM)(NULL));
519 	else
520 		return FALSE;
521 }
522 
PostMenuCommand(UINT uID)523 BOOL PostMenuCommand (UINT uID)
524 {
525 	MENUITEMINFO mii;
526 
527 	CheckMenuStates();
528 
529 	mii.cbSize = sizeof(mii);
530 	mii.fMask  = MIIM_STATE;
531 	if (!GetMenuItemInfo(GUI.hMenu, uID, FALSE, &mii))
532 		return FALSE;
533 	if (!(mii.fState & MFS_DISABLED))
534 		return PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(uID),(LPARAM)(NULL));
535 	else
536 		return FALSE;
537 }
538 
S9xMouseOn()539 void S9xMouseOn ()
540 {
541 	if(Settings.StopEmulation)
542 		return;
543 
544     if (GUI.ControllerOption==SNES_MOUSE || GUI.ControllerOption==SNES_MOUSE_SWAPPED)
545     {
546 		if(Settings.Paused)
547 			SetCursor (GUI.Arrow);
548 		else
549 	        SetCursor (NULL);
550     }
551     else if (GUI.ControllerOption!=SNES_SUPERSCOPE && GUI.ControllerOption!=SNES_JUSTIFIER && GUI.ControllerOption!=SNES_JUSTIFIER_2 && GUI.ControllerOption!=SNES_MACSRIFLE)
552     {
553         SetCursor (GUI.Arrow);
554         GUI.CursorTimer = 60;
555     }
556     else
557 	{
558 		if(Settings.Paused)
559 			SetCursor (GUI.GunSight);
560 		else
561 	        SetCursor (NULL);
562 	}
563 }
564 
ControllerOptionsFromControllers()565 void ControllerOptionsFromControllers()
566 {
567    enum controllers controller[2];
568    int8 ids[4];
569    S9xGetController(0, &controller[0], &ids[0], &ids[1], &ids[2], &ids[3]);
570    S9xGetController(1, &controller[1], &ids[0], &ids[1], &ids[2], &ids[3]);
571 
572    GUI.ControllerOption = SNES_JOYPAD;
573 
574    if (controller[0] == CTL_JOYPAD && controller[1] == CTL_MP5)
575       GUI.ControllerOption = SNES_MULTIPLAYER5;
576    else if (controller[0] == CTL_MP5 && controller[1] == CTL_MP5)
577       GUI.ControllerOption = SNES_MULTIPLAYER8;
578    else if (controller[0] == CTL_MOUSE && controller[1] == CTL_JOYPAD)
579       GUI.ControllerOption = SNES_MOUSE;
580    else if (controller[0] == CTL_JOYPAD && controller[1] == CTL_MOUSE)
581       GUI.ControllerOption = SNES_MOUSE_SWAPPED;
582    else if (controller[0] == CTL_JOYPAD && controller[1] == CTL_SUPERSCOPE)
583       GUI.ControllerOption = SNES_SUPERSCOPE;
584    else if (controller[0] == CTL_JOYPAD && controller[1] == CTL_JUSTIFIER && !ids[0])
585       GUI.ControllerOption = SNES_JUSTIFIER;
586    else if (controller[0] == CTL_JOYPAD && controller[1] == CTL_JUSTIFIER && ids[0])
587       GUI.ControllerOption = SNES_JUSTIFIER_2;
588    else if (controller[0] == CTL_JOYPAD && controller[1] == CTL_MACSRIFLE)
589       GUI.ControllerOption = SNES_MACSRIFLE;
590    else if (controller[0] == CTL_JOYPAD)
591       GUI.ControllerOption = SNES_JOYPAD;
592 
593 }
594 
ChangeInputDevice(void)595 void ChangeInputDevice(void)
596 {
597 	Settings.MouseMaster = false;
598 	Settings.JustifierMaster = false;
599 	Settings.SuperScopeMaster = false;
600 	Settings.MultiPlayer5Master = false;
601 	Settings.MacsRifleMaster = false;
602 
603 	switch(GUI.ControllerOption)
604 	{
605 	case SNES_MOUSE:
606 		Settings.MouseMaster = true;
607 		S9xSetController(0, CTL_MOUSE,      0, 0, 0, 0);
608 		S9xSetController(1, CTL_JOYPAD,     1, 0, 0, 0);
609 		break;
610 	case SNES_MOUSE_SWAPPED:
611 		Settings.MouseMaster = true;
612 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
613 		S9xSetController(1, CTL_MOUSE,      1, 0, 0, 0);
614 		break;
615 	case SNES_SUPERSCOPE:
616 		Settings.SuperScopeMaster = true;
617 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
618 		S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0);
619 		break;
620 	case SNES_MULTIPLAYER5:
621 		Settings.MultiPlayer5Master = true;
622 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
623 		S9xSetController(1, CTL_MP5,        1, 2, 3, 4);
624 		break;
625 	case SNES_MULTIPLAYER8:
626 		Settings.MultiPlayer5Master = true;
627 		S9xSetController(0, CTL_MP5,        0, 1, 2, 3);
628 		S9xSetController(1, CTL_MP5,        4, 5, 6, 7);
629 		break;
630 	case SNES_JUSTIFIER:
631 		Settings.JustifierMaster = true;
632 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
633 		S9xSetController(1, CTL_JUSTIFIER,  0, 0, 0, 0);
634 		break;
635 	case SNES_JUSTIFIER_2:
636 		Settings.JustifierMaster = true;
637 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
638 		S9xSetController(1, CTL_JUSTIFIER,  1, 0, 0, 0);
639 		break;
640 	case SNES_MACSRIFLE:
641 		Settings.MacsRifleMaster = true;
642 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
643 		S9xSetController(1, CTL_MACSRIFLE,  0, 0, 0, 0);
644 		break;
645 	default:
646 	case SNES_JOYPAD:
647 		S9xSetController(0, CTL_JOYPAD,     0, 0, 0, 0);
648 		if (Joypad[1].Enabled)
649 			S9xSetController(1, CTL_JOYPAD,     1, 0, 0, 0);
650 		else
651 			S9xSetController(1, CTL_NONE,       0, 0, 0, 0);
652 		break;
653 	}
654 
655     GUI.ControlForced = 0xff;
656 }
657 
CenterCursor()658 static void CenterCursor()
659 {
660 	if(GUI.ControllerOption==SNES_MOUSE || GUI.ControllerOption==SNES_MOUSE_SWAPPED)
661 	{
662 		if(GUI.hWnd == GetActiveWindow() && !S9xMoviePlaying())
663 		{
664 			POINT cur, middle;
665 			RECT size;
666 
667 			GetClientRect (GUI.hWnd, &size);
668 			middle.x = (size.right - size.left) >> 1;
669 			middle.y = (size.bottom - size.top) >> 1;
670 			ClientToScreen (GUI.hWnd, &middle);
671 			GetCursorPos (&cur);
672 			int dX = middle.x-cur.x;
673 			int dY = middle.y-cur.y;
674 			if(dX || dY)
675 			{
676 				GUI.MouseX -= dX;
677 				GUI.MouseY -= dY;
678 				SetCursorPos (middle.x, middle.y);
679 //				GUI.IgnoreNextMouseMove = true;
680 			}
681 		}
682 	}
683 }
684 
685 
S9xRestoreWindowTitle()686 void S9xRestoreWindowTitle ()
687 {
688     TCHAR buf [1024];
689     if (Memory.ROMFilename[0])
690     {
691         char def[_MAX_FNAME];
692         _splitpath(Memory.ROMFilename, NULL, NULL, def, NULL);
693         _stprintf(buf, TEXT("%s - %s %s"), (wchar_t *)Utf8ToWide(def), WINDOW_TITLE, TEXT(VERSION));
694     }
695     else
696         _stprintf(buf, TEXT("%s %s"), WINDOW_TITLE, TEXT(VERSION));
697 
698     SetWindowText (GUI.hWnd, buf);
699 }
700 
S9xDisplayStateChange(const char * str,bool8 on)701 void S9xDisplayStateChange (const char *str, bool8 on)
702 {
703     static char string [100];
704 
705     sprintf (string, "%s %s", str, on ? "on" : "off");
706     S9xSetInfoString (string);
707 }
708 
UpdateScale(RenderFilter & Scale,RenderFilter & NextScale)709 static void UpdateScale(RenderFilter & Scale, RenderFilter & NextScale)
710 {
711 	Scale = NextScale;
712 }
713 
714 static char InfoString [100];
715 static uint32 prevPadReadFrame = (uint32)-1;
716 static bool skipNextFrameStop = false;
717 
HandleKeyMessage(WPARAM wParam,LPARAM lParam)718 int HandleKeyMessage(WPARAM wParam, LPARAM lParam)
719 {
720 	// update toggles
721 	for (int J = 0; J < 5; J++)
722 	{
723 		extern bool S9xGetState (WORD KeyIdent);
724 		if(Joypad[J].Enabled && (!S9xGetState(Joypad[J+8].Autohold))) // enabled and Togglify
725 		{
726 			SJoypad & p = ToggleJoypadStorage[J];
727 			if(wParam == Joypad[J].L) p.L = !p.L;
728 			if(wParam == Joypad[J].R) p.R = !p.R;
729 			if(wParam == Joypad[J].A) p.A = !p.A;
730 			if(wParam == Joypad[J].B) p.B = !p.B;
731 			if(wParam == Joypad[J].Y) p.Y = !p.Y;
732 			if(wParam == Joypad[J].X) p.X = !p.X;
733 			if(wParam == Joypad[J].Start) p.Start = !p.Start;
734 			if(wParam == Joypad[J].Select) p.Select = !p.Select;
735 			if(wParam == Joypad[J].Left) p.Left = !p.Left;
736 			if(wParam == Joypad[J].Right) p.Right = !p.Right;
737 			if(wParam == Joypad[J].Up) p.Up = !p.Up;
738 			if(wParam == Joypad[J].Down) p.Down = !p.Down;
739 //			if(wParam == Joypad[J].Left_Down) p.Left_Down = !p.Left_Down;
740 //			if(wParam == Joypad[J].Left_Up) p.Left_Up = !p.Left_Up;
741 //			if(wParam == Joypad[J].Right_Down) p.Right_Down = !p.Right_Down;
742 //			if(wParam == Joypad[J].Right_Up) p.Right_Up = !p.Right_Up;
743 			if(!Settings.UpAndDown)
744 			{
745 				if(p.Left && p.Right)
746 					p.Left = p.Right = false;
747 				if(p.Up && p.Down)
748 					p.Up = p.Down = false;
749 			}
750 		}
751 		if(Joypad[J].Enabled && (!S9xGetState(Joypad[J+8].Autofire))) // enabled and turbo-togglify (TurboTog)
752 		{
753 			SJoypad & p = TurboToggleJoypadStorage[J];
754 			if(wParam == Joypad[J].L) p.L = !p.L;
755 			if(wParam == Joypad[J].R) p.R = !p.R;
756 			if(wParam == Joypad[J].A) p.A = !p.A;
757 			if(wParam == Joypad[J].B) p.B = !p.B;
758 			if(wParam == Joypad[J].Y) p.Y = !p.Y;
759 			if(wParam == Joypad[J].X) p.X = !p.X;
760 			if(wParam == Joypad[J].Start) p.Start = !p.Start;
761 			if(wParam == Joypad[J].Select) p.Select = !p.Select;
762 			if(wParam == Joypad[J].Left) p.Left = !p.Left;
763 			if(wParam == Joypad[J].Right) p.Right = !p.Right;
764 			if(wParam == Joypad[J].Up) p.Up = !p.Up;
765 			if(wParam == Joypad[J].Down) p.Down = !p.Down;
766 //			if(wParam == Joypad[J].Left_Down) p.Left_Down = !p.Left_Down;
767 //			if(wParam == Joypad[J].Left_Up) p.Left_Up = !p.Left_Up;
768 //			if(wParam == Joypad[J].Right_Down) p.Right_Down = !p.Right_Down;
769 //			if(wParam == Joypad[J].Right_Up) p.Right_Up = !p.Right_Up;
770 			if(!Settings.UpAndDown)
771 			{
772 				if(p.Left && p.Right)
773 					p.Left = p.Right = false;
774 				if(p.Up && p.Down)
775 					p.Up = p.Down = false;
776 			}
777 		}
778 		if(wParam == Joypad[J+8].ClearAll) // clear all
779 		{
780 			{
781 				SJoypad & p = ToggleJoypadStorage[J];
782 				p.L = false;
783 				p.R = false;
784 				p.A = false;
785 				p.B = false;
786 				p.Y = false;
787 				p.X = false;
788 				p.Start = false;
789 				p.Select = false;
790 				p.Left = false;
791 				p.Right = false;
792 				p.Up = false;
793 				p.Down = false;
794 			}
795 			{
796 				SJoypad & p = TurboToggleJoypadStorage[J];
797 				p.L = false;
798 				p.R = false;
799 				p.A = false;
800 				p.B = false;
801 				p.Y = false;
802 				p.X = false;
803 				p.Start = false;
804 				p.Select = false;
805 				p.Left = false;
806 				p.Right = false;
807 				p.Up = false;
808 				p.Down = false;
809 			}
810 		}
811 	}
812 
813 
814 	bool hitHotKey = false;
815 
816     // if this is not a gamepad press and background hotkeys are disabled, skip it if we do not have focus
817     if (!GUI.BackgroundKeyHotkeys && !(wParam & 0x8000) && GUI.hWnd != GetForegroundWindow())
818     {
819         return 0;
820     }
821 
822 	if(!(wParam == 0 || wParam == VK_ESCAPE)) // if it's the 'disabled' key, it's never pressed as a hotkey
823 	{
824 		int modifiers = 0;
825 		if(GetAsyncKeyState(VK_MENU))
826 			modifiers |= CUSTKEY_ALT_MASK;
827 		if(GetAsyncKeyState(VK_CONTROL))
828 			modifiers |= CUSTKEY_CTRL_MASK;
829 		if(GetAsyncKeyState(VK_SHIFT))
830 			modifiers |= CUSTKEY_SHIFT_MASK;
831 
832 		{
833 			for(int i = 0 ; i < 10 ; i++)
834 			{
835 				if(wParam == CustomKeys.Save[i].key
836 				&& modifiers == CustomKeys.Save[i].modifiers)
837 				{
838 					FreezeUnfreezeSlot (i, true);
839 					hitHotKey = true;
840 				}
841 				if(wParam == CustomKeys.Load[i].key
842 				&& modifiers == CustomKeys.Load[i].modifiers)
843 				{
844 					FreezeUnfreezeSlot (i, false);
845 					hitHotKey = true;
846 				}
847 			}
848 
849 			if(wParam == CustomKeys.SlotSave.key
850 			&& modifiers == CustomKeys.SlotSave.modifiers)
851 			{
852 				FreezeUnfreezeSlot (GUI.CurrentSaveSlot, true);
853 				hitHotKey = true;
854 			}
855 			if(wParam == CustomKeys.SlotLoad.key
856 			&& modifiers == CustomKeys.SlotLoad.modifiers)
857 			{
858 				FreezeUnfreezeSlot (GUI.CurrentSaveSlot, false);
859 				hitHotKey = true;
860 			}
861 			if(wParam == CustomKeys.SlotPlus.key
862 			&& modifiers == CustomKeys.SlotPlus.modifiers)
863 			{
864 				GUI.CurrentSaveSlot++;
865 				if(GUI.CurrentSaveSlot > 9)
866 					GUI.CurrentSaveSlot = 0;
867 
868 				static char str [64];
869 				sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot);
870 				S9xSetInfoString(str);
871 
872 				hitHotKey = true;
873 			}
874 			if(wParam == CustomKeys.SlotMinus.key
875 			&& modifiers == CustomKeys.SlotMinus.modifiers)
876 			{
877 				GUI.CurrentSaveSlot--;
878 				if(GUI.CurrentSaveSlot < 0)
879 					GUI.CurrentSaveSlot = 9;
880 
881 				static char str [64];
882 				sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot);
883 				S9xSetInfoString(str);
884 
885 				hitHotKey = true;
886 			}
887 		}
888 
889 
890 		if(wParam == CustomKeys.FrameAdvance.key
891 		&& modifiers == CustomKeys.FrameAdvance.modifiers)
892 		{
893 			static DWORD lastTime = 0;
894 			if((int)(timeGetTime() - lastTime) > 20)
895 			{
896 				lastTime = timeGetTime();
897 				if(Settings.Paused || GUI.FASkipsNonInput)
898 				{
899 					prevPadReadFrame = (uint32)-1;
900 					Settings.Paused = false;
901 					S9xMouseOn();
902 					GUI.IgnoreNextMouseMove = true;
903 					Settings.Paused = true;
904 
905 					Settings.FrameAdvance = true;
906 					GUI.FrameAdvanceJustPressed = 2;
907 					// kick the main thread out of GetMessage (just in case)
908 					SendMessage(GUI.hWnd, WM_NULL, 0, 0);
909 				}
910 				else
911 				{
912 					Settings.Paused = true;
913 				}
914 
915 				CenterCursor();
916 			}
917 
918 			hitHotKey = true;
919 		}
920 		if(wParam == CustomKeys.FrameCount.key
921 		&& modifiers == CustomKeys.FrameCount.modifiers)
922 		{
923 			if (S9xMovieActive()
924 #ifdef NETPLAY_SUPPORT
925 			|| Settings.NetPlay
926 #endif
927 			)
928 				S9xMovieToggleFrameDisplay ();
929 			else
930 				S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_ERR_NOFRAMETOGGLE);
931 			hitHotKey = true;
932 		}
933 		if(wParam == CustomKeys.Pause.key
934 		&& modifiers == CustomKeys.Pause.modifiers)
935 		{
936 			Settings.Paused = Settings.Paused ^ true;
937 			Settings.FrameAdvance = false;
938 			GUI.FrameAdvanceJustPressed = 0;
939 			CenterCursor();
940 			if(!Settings.Paused)
941 				S9xMouseOn();
942 			hitHotKey = true;
943 		}
944 		if(wParam == CustomKeys.ReadOnly.key
945 		&& modifiers == CustomKeys.ReadOnly.modifiers)
946 		{
947 			if (S9xMovieActive())
948 				S9xMovieToggleRecState();
949 			else
950 				S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_ERR_NOREADONLYTOGGLE);
951 			hitHotKey = true;
952 		}
953 		if(wParam == CustomKeys.FastForward.key
954 		&& modifiers == CustomKeys.FastForward.modifiers)
955 		{
956 			if(!Settings.TurboMode)
957 				S9xMessage (S9X_INFO, S9X_TURBO_MODE, WINPROC_TURBOMODE_TEXT);
958 			Settings.TurboMode = TRUE;
959 			hitHotKey = true;
960 		}
961 		if(wParam == CustomKeys.FastForwardToggle.key
962 		&& modifiers == CustomKeys.FastForwardToggle.modifiers)
963 		{
964 			Settings.TurboMode ^= TRUE;
965 			if (Settings.TurboMode)
966 				S9xMessage (S9X_INFO, S9X_TURBO_MODE,
967 				WINPROC_TURBOMODE_ON);
968 			else
969 				S9xMessage (S9X_INFO, S9X_TURBO_MODE,
970 				WINPROC_TURBOMODE_OFF);
971 			hitHotKey = true;
972 		}
973 		if(wParam == CustomKeys.ShowPressed.key
974 		&& modifiers == CustomKeys.ShowPressed.modifiers)
975 		{
976 			Settings.DisplayPressedKeys = Settings.DisplayPressedKeys?0:2;
977 
978 			if(Settings.DisplayPressedKeys==2)
979 				S9xMessage(S9X_INFO, S9X_MOVIE_INFO, INPUT_INFO_DISPLAY_ENABLED);
980 			else
981 				S9xMessage(S9X_INFO, S9X_MOVIE_INFO, INPUT_INFO_DISPLAY_DISABLED);
982 
983 			hitHotKey = true;
984 		}
985 		if(wParam == CustomKeys.SaveScreenShot.key
986 		&& modifiers == CustomKeys.SaveScreenShot.modifiers)
987 		{
988 			Settings.TakeScreenshot=true;
989 		}
990 		if(wParam == CustomKeys.ScopePause.key
991 		&& modifiers == CustomKeys.ScopePause.modifiers)
992 		{
993 			GUI.superscope_pause = 1;
994 			hitHotKey = true;
995 		}
996 		if(wParam == CustomKeys.ScopeTurbo.key
997 		&& modifiers == CustomKeys.ScopeTurbo.modifiers)
998 		{
999 			GUI.superscope_turbo = 1;
1000 			hitHotKey = true;
1001 		}
1002 		if(wParam == CustomKeys.SkipDown.key
1003 		&& modifiers == CustomKeys.SkipDown.modifiers)
1004 		{
1005 			if (Settings.SkipFrames <= 1)
1006 				Settings.SkipFrames = AUTO_FRAMERATE;
1007 			else
1008 				if (Settings.SkipFrames != AUTO_FRAMERATE)
1009 					Settings.SkipFrames--;
1010 
1011 				if (Settings.SkipFrames == AUTO_FRAMERATE)
1012 					S9xSetInfoString (WINPROC_AUTOSKIP);
1013 				else
1014 				{
1015 					sprintf (InfoString, WINPROC_FRAMESKIP,
1016 						Settings.SkipFrames - 1);
1017 					S9xSetInfoString (InfoString);
1018 				}
1019 			hitHotKey = true;
1020 		}
1021 		if(wParam == CustomKeys.SkipUp.key
1022 		&& modifiers == CustomKeys.SkipUp.modifiers)
1023 		{
1024 			if (Settings.SkipFrames == AUTO_FRAMERATE)
1025 				Settings.SkipFrames = 1;
1026 			else
1027 				if (Settings.SkipFrames < 10)
1028 					Settings.SkipFrames++;
1029 
1030 				if (Settings.SkipFrames == AUTO_FRAMERATE)
1031 					S9xSetInfoString (WINPROC_AUTOSKIP);
1032 				else
1033 				{
1034 					sprintf (InfoString, WINPROC_FRAMESKIP,
1035 						Settings.SkipFrames - 1);
1036 					S9xSetInfoString (InfoString);
1037 				}
1038 			hitHotKey = true;
1039 		}
1040 		if(wParam == CustomKeys.SpeedDown.key
1041 		&& modifiers == CustomKeys.SpeedDown.modifiers)
1042 		{
1043 			// Increase emulated frame time
1044 			int i;
1045 			for(i=1; FrameTimings[i]<Settings.FrameTime; ++i)
1046 				;
1047 			Settings.FrameTime = FrameTimings[i+1];
1048 			ResetFrameTimer ();
1049 //					sprintf (InfoString, WINPROC_EMUFRAMETIME,
1050 //						Settings.FrameTime / 1);
1051 			sprintf (InfoString, "Speed: %.0f%% (%.1f ms/frame)", ((Settings.PAL?Settings.FrameTimePAL:Settings.FrameTimeNTSC) * 100.0f) / (float)Settings.FrameTime, Settings.FrameTime*0.001f);
1052 			S9xSetInfoString (InfoString);
1053 			hitHotKey = true;
1054 		}
1055 		if(wParam == CustomKeys.SpeedUp.key
1056 		&& modifiers == CustomKeys.SpeedUp.modifiers)
1057 		{
1058 			// Decrease emulated frame time
1059 			int i;
1060 			for(i=1; FrameTimings[i]<Settings.FrameTime; ++i)
1061 				;
1062 			Settings.FrameTime = FrameTimings[i-1];
1063 
1064 			ResetFrameTimer ();
1065 //					sprintf (InfoString, WINPROC_EMUFRAMETIME,
1066 //						Settings.FrameTime / 1);
1067 			sprintf (InfoString, "Speed: %.0f%% (%.1f ms/frame)", ((Settings.PAL?Settings.FrameTimePAL:Settings.FrameTimeNTSC) * 100.0f) / (float)Settings.FrameTime, Settings.FrameTime*0.001f);
1068 			S9xSetInfoString (InfoString);
1069 			hitHotKey = true;
1070 		}
1071 		if(wParam == CustomKeys.BGL1.key
1072 		&& modifiers == CustomKeys.BGL1.modifiers)
1073 		{
1074 			Settings.BG_Forced ^= 1;
1075 			S9xDisplayStateChange (WINPROC_BG1, !(Settings.BG_Forced & 1));
1076 		}
1077 		if(wParam == CustomKeys.BGL2.key
1078 		&& modifiers == CustomKeys.BGL2.modifiers)
1079 		{
1080 			Settings.BG_Forced ^= 2;
1081 			S9xDisplayStateChange (WINPROC_BG2, !(Settings.BG_Forced & 2));
1082 		}
1083 		if(wParam == CustomKeys.BGL3.key
1084 		&& modifiers == CustomKeys.BGL3.modifiers)
1085 		{
1086 			Settings.BG_Forced ^= 4;
1087 			S9xDisplayStateChange (WINPROC_BG3, !(Settings.BG_Forced & 4));
1088 		}
1089 		if(wParam == CustomKeys.BGL4.key
1090 		&& modifiers == CustomKeys.BGL4.modifiers)
1091 		{
1092 			Settings.BG_Forced ^= 8;
1093 			S9xDisplayStateChange (WINPROC_BG4, !(Settings.BG_Forced & 8));
1094 		}
1095 		if(wParam == CustomKeys.BGL5.key
1096 		&& modifiers == CustomKeys.BGL5.modifiers)
1097 		{
1098 			Settings.BG_Forced ^= 16;
1099 			S9xDisplayStateChange (WINPROC_SPRITES, !(Settings.BG_Forced & 16));
1100 		}
1101 		if(wParam == CustomKeys.ResetGame.key
1102 		&& modifiers == CustomKeys.ResetGame.modifiers)
1103 		{
1104 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_FILE_RESET),(LPARAM)(NULL));
1105 		}
1106 		if(wParam == CustomKeys.ToggleCheats.key
1107 		&& modifiers == CustomKeys.ToggleCheats.modifiers)
1108 		{
1109 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_CHEAT_APPLY),(LPARAM)(NULL));
1110 		}
1111 		if(wParam == CustomKeys.JoypadSwap.key
1112 		&& modifiers == CustomKeys.JoypadSwap.modifiers)
1113 		{
1114 			if(!S9xMoviePlaying())
1115 			{
1116 				S9xApplyCommand(S9xGetCommandT("SwapJoypads"),1,0);
1117 			}
1118 		}
1119 		if(wParam == CustomKeys.SwitchControllers.key
1120 		&& modifiers == CustomKeys.SwitchControllers.modifiers)
1121 		{
1122 			if((!S9xMovieActive() || !S9xMovieGetFrameCounter()))
1123 			{
1124 //				int prevControllerOption = GUI.ControllerOption;
1125 //				do {
1126 					++GUI.ControllerOption %= SNES_MAX_CONTROLLER_OPTIONS;
1127 //				} while(!((1<<GUI.ControllerOption) & GUI.ValidControllerOptions) && prevControllerOption != GUI.ControllerOption);
1128 
1129 				ChangeInputDevice();
1130 
1131 				if (GUI.ControllerOption == SNES_MOUSE || GUI.ControllerOption == SNES_MOUSE_SWAPPED)
1132 					CenterCursor();
1133 
1134 				S9xReportControllers();
1135 			}
1136 		}
1137 		if(wParam == CustomKeys.QuitS9X.key
1138 		&& modifiers == CustomKeys.QuitS9X.modifiers)
1139 		{
1140 			PostMessage(GUI.hWnd,WM_CLOSE,(WPARAM)NULL,(LPARAM)(NULL));
1141 		}
1142         if(wParam == CustomKeys.Rewind.key
1143 		&& modifiers == CustomKeys.Rewind.modifiers)
1144 		{
1145             if(!Settings.Rewinding)
1146                 S9xMessage (S9X_INFO, 0, GUI.rewindBufferSize?WINPROC_REWINDING_TEXT:WINPROC_REWINDING_DISABLED);
1147             Settings.Rewinding = true;
1148 			hitHotKey = true;
1149         }
1150 
1151 		if (wParam == CustomKeys.SaveFileSelect.key
1152 			&& modifiers == CustomKeys.SaveFileSelect.modifiers)
1153 		{
1154 			FreezeUnfreezeDialog(TRUE);
1155 			hitHotKey = true;
1156 		}
1157 		if (wParam == CustomKeys.LoadFileSelect.key
1158 			&& modifiers == CustomKeys.LoadFileSelect.modifiers)
1159 		{
1160 			FreezeUnfreezeDialog(FALSE);
1161 			hitHotKey = true;
1162 		}
1163 
1164 		if (wParam == CustomKeys.Mute.key
1165 			&& modifiers == CustomKeys.Mute.modifiers)
1166 		{
1167 			GUI.Mute = !GUI.Mute;
1168 			hitHotKey = true;
1169 		}
1170 		//if(wParam == CustomKeys.BGLHack.key
1171 		//&& modifiers == CustomKeys.BGLHack.modifiers)
1172 		//{
1173 		//	Settings.BGLayering = !Settings.BGLayering;
1174 		//	S9xDisplayStateChange (WINPROC_BGHACK,
1175 		//		Settings.BGLayering);
1176 		//}
1177 		//if(wParam == CustomKeys.InterpMode7.key
1178 		//&& modifiers == CustomKeys.InterpMode7.modifiers)
1179 		//{
1180 		//	Settings.Mode7Interpolate ^= TRUE;
1181 		//	S9xDisplayStateChange (WINPROC_MODE7INTER,
1182 		//		Settings.Mode7Interpolate);
1183 		//}
1184 
1185 		if(wParam == CustomKeys.TurboA.key && modifiers == CustomKeys.TurboA.modifiers)
1186 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_A),(LPARAM)(NULL));
1187 		if(wParam == CustomKeys.TurboB.key && modifiers == CustomKeys.TurboB.modifiers)
1188 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_B),(LPARAM)(NULL));
1189 		if(wParam == CustomKeys.TurboY.key && modifiers == CustomKeys.TurboY.modifiers)
1190 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_Y),(LPARAM)(NULL));
1191 		if(wParam == CustomKeys.TurboX.key && modifiers == CustomKeys.TurboX.modifiers)
1192 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_X),(LPARAM)(NULL));
1193 		if(wParam == CustomKeys.TurboL.key && modifiers == CustomKeys.TurboL.modifiers)
1194 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_L),(LPARAM)(NULL));
1195 		if(wParam == CustomKeys.TurboR.key && modifiers == CustomKeys.TurboR.modifiers)
1196 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_R),(LPARAM)(NULL));
1197 		if(wParam == CustomKeys.TurboStart.key && modifiers == CustomKeys.TurboStart.modifiers)
1198 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_START),(LPARAM)(NULL));
1199 		if(wParam == CustomKeys.TurboSelect.key && modifiers == CustomKeys.TurboSelect.modifiers)
1200 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_SELECT),(LPARAM)(NULL));
1201 		if(wParam == CustomKeys.TurboLeft.key && modifiers == CustomKeys.TurboLeft.modifiers)
1202 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_LEFT),(LPARAM)(NULL));
1203 		if(wParam == CustomKeys.TurboUp.key && modifiers == CustomKeys.TurboUp.modifiers)
1204 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_UP),(LPARAM)(NULL));
1205 		if(wParam == CustomKeys.TurboRight.key && modifiers == CustomKeys.TurboRight.modifiers)
1206 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_RIGHT),(LPARAM)(NULL));
1207 		if(wParam == CustomKeys.TurboDown.key && modifiers == CustomKeys.TurboDown.modifiers)
1208 			PostMessage(GUI.hWnd, WM_COMMAND, (WPARAM)(ID_TURBO_DOWN),(LPARAM)(NULL));
1209 
1210 		for(int i = 0 ; i < 10 ; i++)
1211 		{
1212 			if(wParam == CustomKeys.SelectSave[i].key && modifiers == CustomKeys.SelectSave[i].modifiers)
1213 			{
1214 				GUI.CurrentSaveSlot = i;
1215 
1216 				static char str [64];
1217 				sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot);
1218 				S9xSetInfoString(str);
1219 
1220 				hitHotKey = true;
1221 			}
1222 		}
1223 
1224 		if(wParam == CustomKeys.Transparency.key
1225 		&& modifiers == CustomKeys.Transparency.modifiers)
1226 		{
1227 //					if (Settings.SixteenBit)
1228 			{
1229 				Settings.Transparency = !Settings.Transparency;
1230 				S9xDisplayStateChange (WINPROC_TRANSPARENCY,
1231 					Settings.Transparency);
1232 			}
1233 //					else
1234 //					{
1235 //						S9xSetInfoString ("Transparency requires Sixteen Bit mode.");
1236 //					}
1237 		}
1238 		if(wParam == CustomKeys.ClippingWindows.key
1239 		&& modifiers == CustomKeys.ClippingWindows.modifiers)
1240 		{
1241 			Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows;
1242 			S9xDisplayStateChange (WINPROC_CLIPWIN,
1243 				!Settings.DisableGraphicWindows);
1244 		}
1245 
1246 		// don't pull down menu if alt is a hotkey or the menu isn't there, unless no game is running
1247 		if(!Settings.StopEmulation && ((wParam == VK_MENU || wParam == VK_F10) && (hitHotKey || GetMenu (GUI.hWnd) == NULL) && !GetAsyncKeyState(VK_F4)))
1248 			return 0;
1249 	}
1250 
1251 	if(!hitHotKey)
1252 	switch (wParam)
1253 	{
1254 		case VK_ESCAPE:
1255 			if(
1256                 GUI.outputMethod!=DIRECTDRAW &&
1257                 GUI.FullScreen && !GUI.EmulateFullscreen)
1258 				ToggleFullScreen();
1259 			else
1260 				if (GetMenu (GUI.hWnd) == NULL)
1261 					SetMenu (GUI.hWnd, GUI.hMenu);
1262 				else
1263 					SetMenu (GUI.hWnd, NULL);
1264 
1265 			//UpdateBackBuffer();
1266 			if (GetMenu( GUI.hWnd) != NULL)
1267 				DrawMenuBar (GUI.hWnd);
1268 			break;
1269 	}
1270 	return 1;
1271 }
1272 
DoOpenRomDialog(TCHAR filename[_MAX_PATH],bool noCustomDlg=false)1273 static bool DoOpenRomDialog(TCHAR filename [_MAX_PATH], bool noCustomDlg = false)
1274 {
1275 	if(GUI.CustomRomOpen && !noCustomDlg)
1276 	{
1277 		try
1278 		{
1279 			INITCOMMONCONTROLSEX icex;
1280 			icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
1281 			icex.dwICC   = ICC_LISTVIEW_CLASSES|ICC_TREEVIEW_CLASSES;
1282 			InitCommonControlsEx(&icex); // this could cause failure if the common control DLL isn't found
1283 
1284 			return (1 <= DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_OPEN_ROM), GUI.hWnd, DlgOpenROMProc, (LPARAM)filename));
1285 		}
1286 		catch(...) {} // use standard dialog if the special one fails
1287 
1288 		GUI.CustomRomOpen = false; // if crashed, turn off custom for next time
1289 	}
1290 
1291 	// standard file dialog
1292 	{
1293 		OPENFILENAME ofn;
1294 		static TCHAR szFileName[MAX_PATH] = {0};
1295 		TCHAR szPathName[MAX_PATH];
1296 		_tfullpath(szPathName, S9xGetDirectoryT(ROM_DIR), MAX_PATH);
1297 
1298 		// a limited strcat that doesn't mind null characters
1299 #define strcat0(to,from) do{memcpy(to,from,sizeof(from)-1);to+=(sizeof(from)/sizeof(TCHAR))-1;}while(false)
1300 
1301 		// make filter string using entries in valid_ext
1302 		TCHAR lpfilter [8192] = {0};
1303 		TCHAR* lpfilterptr = lpfilter;
1304 		for(int i=0; i<2; i++)
1305 		{
1306 			if(!i)
1307 				strcat0(lpfilterptr, FILE_INFO_ROM_FILE_TYPE);
1308 			else
1309 				strcat0(lpfilterptr, FILE_INFO_UNCROM_FILE_TYPE);
1310 			strcat0(lpfilterptr, TEXT("\0"));
1311 			if(valid_ext) // add valid extensions to string
1312 			{
1313 				ExtList* ext = valid_ext;
1314 				int extlen_approx = 0;
1315 				bool first = true;
1316 				while(ext && (extlen_approx < 2048))
1317 				{
1318 					if((!i || !ext->compressed) && ext->extension && lstrlen(ext->extension) < 256)
1319 					{
1320 						if(!first)
1321 							lstrcat(lpfilterptr, TEXT(";*."));
1322 						else
1323 						{
1324 							lstrcat(lpfilterptr, TEXT("*."));
1325 							first = false;
1326 						}
1327 						lstrcat(lpfilterptr, ext->extension);
1328 						extlen_approx += lstrlen(ext->extension) + 3;
1329 					}
1330 					ext = ext->next;
1331 				}
1332 				lpfilterptr += lstrlen(lpfilterptr);
1333 			}
1334 			else
1335 				strcat0(lpfilterptr, TEXT("*.smc"));
1336 			strcat0(lpfilterptr, TEXT("\0"));
1337 		}
1338 		strcat0(lpfilterptr, FILE_INFO_ANY_FILE_TYPE);
1339 		strcat0(lpfilterptr, TEXT("\0*.*\0\0"));
1340 
1341 		memset((LPVOID)&ofn, 0, sizeof(OPENFILENAME));
1342 		ofn.lStructSize = sizeof(OPENFILENAME);
1343 		ofn.hwndOwner = GUI.hWnd;
1344 		ofn.lpstrFilter = lpfilter;
1345 		ofn.lpstrFile = szFileName;
1346 		ofn.lpstrDefExt = TEXT("smc");
1347 		ofn.nMaxFile = MAX_PATH;
1348 		ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
1349 		ofn.lpstrInitialDir = szPathName;
1350 		if(GetOpenFileName(&ofn))
1351 		{
1352 			_tcsncpy(filename, ofn.lpstrFile, _MAX_PATH);
1353 			return true;
1354 		}
1355 		return false;
1356 	}
1357 }
1358 
WinMoviePlay(LPCTSTR filename)1359 bool WinMoviePlay(LPCTSTR filename)
1360 {
1361 	struct MovieInfo info;
1362 	int err;
1363 
1364 	if (Settings.StopEmulation) {
1365 		SendMenuCommand(ID_FILE_LOAD_GAME);
1366 		if (Settings.StopEmulation)
1367 			return false;
1368 	}
1369 
1370 	err = S9xMovieGetInfo(_tToChar(filename), &info);
1371 	if (err != SUCCESS) {
1372 		TCHAR* err_string = MOVIE_ERR_COULD_NOT_OPEN;
1373 		switch(err)
1374 		{
1375 		case FILE_NOT_FOUND:
1376 			err_string = MOVIE_ERR_NOT_FOUND_SHORT;
1377 			break;
1378 		case WRONG_FORMAT:
1379 			err_string = MOVIE_ERR_WRONG_FORMAT_SHORT;
1380 			break;
1381 		case WRONG_VERSION:
1382 			err_string = MOVIE_ERR_WRONG_VERSION_SHORT;
1383 			break;
1384 		}
1385 		S9xSetInfoString(_tToChar(err_string));
1386 		return false;
1387 	}
1388 
1389 	while (info.ROMCRC32 != Memory.ROMCRC32 || strcmp(info.ROMName, Memory.RawROMName) != 0) {
1390 		TCHAR temp[512];
1391 		wsprintf(temp, TEXT("Movie's ROM: crc32=%08X, name=%s\nCurrent ROM: crc32=%08X, name=%s\n\nstill want to play the movie?"),
1392 			info.ROMCRC32, _tFromMS932(info.ROMName), Memory.ROMCRC32, _tFromMS932(Memory.RawROMName));
1393 		int sel = MessageBox(GUI.hWnd, temp, SNES9X_INFO, MB_ABORTRETRYIGNORE|MB_ICONQUESTION);
1394 		switch (sel) {
1395 		case IDABORT:
1396 			return false;
1397 		case IDRETRY:
1398 			SendMenuCommand(ID_FILE_LOAD_GAME);
1399 			if (Settings.StopEmulation)
1400 				return false;
1401 			break;
1402 		default:
1403 			goto romcheck_exit;
1404 		}
1405 	}
1406 	romcheck_exit:
1407 
1408 	err = S9xMovieOpen (_tToChar(filename), GUI.MovieReadOnly);
1409 	if(err != SUCCESS)
1410 	{
1411 		TCHAR* err_string = MOVIE_ERR_COULD_NOT_OPEN;
1412 		switch(err)
1413 		{
1414 		case FILE_NOT_FOUND:
1415 			err_string = MOVIE_ERR_NOT_FOUND_SHORT;
1416 			break;
1417 		case WRONG_FORMAT:
1418 			err_string = MOVIE_ERR_WRONG_FORMAT_SHORT;
1419 			break;
1420 		case WRONG_VERSION:
1421 			err_string = MOVIE_ERR_WRONG_VERSION_SHORT;
1422 			break;
1423 		}
1424 		S9xSetInfoString(_tToChar(err_string));
1425 		return false;
1426 	}
1427 	return true;
1428 }
1429 
1430 static bool startingMovie = false;
1431 
1432 HWND cheatSearchHWND = NULL;
1433 
1434 
1435 #define MOVIE_LOCKED_SETTING	if(S9xMovieActive()) {MessageBox(GUI.hWnd,TEXT("That setting is locked while a movie is active."),TEXT("Notice"),MB_OK|MB_ICONEXCLAMATION); break;}
1436 
WinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1437 LRESULT CALLBACK WinProc(
1438 						 HWND hWnd,
1439 						 UINT uMsg,
1440 						 WPARAM wParam,
1441 						 LPARAM lParam)
1442 {
1443     unsigned int i;
1444     //bool showFPS;
1445 #ifdef NETPLAY_SUPPORT
1446     TCHAR hostname [100];
1447 #endif
1448     switch (uMsg)
1449     {
1450 	case WM_CREATE:
1451 		g_hInst = ((LPCREATESTRUCT)lParam)->hInstance;
1452 		DragAcceptFiles(hWnd, TRUE);
1453 		return 0;
1454 	case WM_KEYDOWN:
1455 		if(GUI.BackgroundInput && !GUI.InactivePause)
1456 			break;
1457 	case WM_CUSTKEYDOWN:
1458 	case WM_SYSKEYDOWN:
1459 		{
1460 			if(!HandleKeyMessage(wParam,lParam))
1461 				return 0;
1462 	        break;
1463 		}
1464 
1465 	case WM_KEYUP:
1466 	case WM_CUSTKEYUP:
1467 		{
1468 			int modifiers = 0;
1469 			if(GetAsyncKeyState(VK_MENU) || wParam == VK_MENU)
1470 				modifiers |= CUSTKEY_ALT_MASK;
1471 			if(GetAsyncKeyState(VK_CONTROL)|| wParam == VK_CONTROL)
1472 				modifiers |= CUSTKEY_CTRL_MASK;
1473 			if(GetAsyncKeyState(VK_SHIFT)|| wParam == VK_SHIFT)
1474 				modifiers |= CUSTKEY_SHIFT_MASK;
1475 
1476 			if(wParam == CustomKeys.FastForward.key
1477 			&& modifiers == CustomKeys.FastForward.modifiers)
1478 			{
1479 				Settings.TurboMode = FALSE;
1480 			}
1481 			if(wParam == CustomKeys.ScopePause.key
1482 			&& modifiers == CustomKeys.ScopePause.modifiers)
1483 			{
1484 				GUI.superscope_pause = 0;
1485 			}
1486             if(wParam == CustomKeys.Rewind.key
1487 		    && modifiers == CustomKeys.Rewind.modifiers)
1488 		    {
1489                 Settings.Rewinding = false;
1490             }
1491 
1492 		}
1493 		break;
1494 
1495 	case WM_DROPFILES:
1496 		HDROP hDrop;
1497 		UINT fileCount;
1498 		TCHAR droppedFile[PATH_MAX];
1499 
1500 		hDrop = (HDROP)wParam;
1501 		fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
1502 		if (fileCount == 1) {
1503 			DragQueryFile(hDrop, 0, droppedFile, PATH_MAX);
1504 
1505 			LPCTSTR ext = PathFindExtension(droppedFile);
1506 			if (ExtensionIsValid(droppedFile)) {
1507 				LoadROM(droppedFile);
1508 			}
1509 			else if (lstrcmpi(ext, TEXT(".smv")) == 0) {
1510 				WinMoviePlay(droppedFile);
1511 			}
1512 			else {
1513 				S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Unknown file extension.");
1514 			}
1515 		}
1516 		DragFinish(hDrop);
1517 
1518 		return 0;
1519 
1520 	case WM_COMMAND:
1521 		switch (wParam & 0xffff)
1522 		{
1523 		case ID_FILE_AVI_RECORDING:
1524 			if (!GUI.AVIOut)
1525 				PostMessage(GUI.hWnd, WM_COMMAND, ID_FILE_WRITE_AVI, NULL);
1526 			else
1527 				PostMessage(GUI.hWnd, WM_COMMAND, ID_FILE_STOP_AVI, NULL);
1528 			break;
1529 		case ID_FILE_WRITE_AVI:
1530 			{
1531 				RestoreGUIDisplay ();  //exit DirectX
1532 				OPENFILENAME  ofn;
1533 				TCHAR  szFileName[MAX_PATH];
1534 				TCHAR  szPathName[MAX_PATH];
1535 				SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR));
1536 				_tfullpath(szPathName, GUI.MovieDir, MAX_PATH);
1537 				_tmkdir(szPathName);
1538 
1539 				szFileName[0] = TEXT('\0');
1540 
1541 				memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) );
1542 				ofn.lStructSize = sizeof(OPENFILENAME);
1543 				ofn.hwndOwner = GUI.hWnd;
1544 				ofn.lpstrFilter = FILE_INFO_AVI_FILE_TYPE TEXT("\0*.avi\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0");
1545 				ofn.lpstrFile = szFileName;
1546 				ofn.lpstrDefExt = TEXT("avi");
1547 				ofn.nMaxFile = MAX_PATH;
1548 				ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
1549 				ofn.lpstrInitialDir = szPathName;
1550 				if(GetSaveFileName( &ofn ))
1551 				{
1552 					DoAVIOpen(szFileName);
1553 				}
1554 				RestoreSNESDisplay ();// re-enter after dialog
1555 			}
1556 			break;
1557 		case ID_FILE_STOP_AVI:
1558 			DoAVIClose(0);
1559 			ReInitSound();				// reenable sound output
1560 			break;
1561 		case ID_FILE_MOVIE_STOP:
1562 			S9xMovieStop(FALSE);
1563 			break;
1564 		case ID_FILE_MOVIE_PLAY:
1565 			{
1566 				RestoreGUIDisplay ();  //exit DirectX
1567 				OpenMovieParams op;
1568 				memset(&op, 0, sizeof(op));
1569 				if(DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_OPENMOVIE), hWnd, DlgOpenMovie, (LPARAM)&op) &&
1570 					op.Path[0]!='\0')
1571 				{
1572 					int err=S9xMovieOpen (_tToChar(op.Path), op.ReadOnly);
1573 					if(err!=SUCCESS)
1574 					{
1575 						TCHAR* err_string=MOVIE_ERR_COULD_NOT_OPEN;
1576 						switch(err)
1577 						{
1578 						case FILE_NOT_FOUND:
1579 							err_string=MOVIE_ERR_NOT_FOUND;
1580 							break;
1581 						case WRONG_FORMAT:
1582 							err_string=MOVIE_ERR_WRONG_FORMAT;
1583 							break;
1584 						case WRONG_VERSION:
1585 							err_string=MOVIE_ERR_WRONG_VERSION;
1586 							break;
1587 						}
1588 						MessageBox( hWnd, err_string, SNES9X_INFO, MB_OK);
1589 					}
1590 				}
1591 				RestoreSNESDisplay ();// re-enter after dialog
1592 			}
1593 			break;
1594 		case ID_FILE_MOVIE_RECORD:
1595 			{
1596 				RestoreGUIDisplay ();  //exit DirectX
1597 				OpenMovieParams op;
1598 				memset(&op, 0, sizeof(op));
1599 				if(DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_CREATEMOVIE), hWnd, DlgCreateMovie, (LPARAM)&op) &&
1600 					op.Path[0]!='\0')
1601 				{
1602 					startingMovie = true;
1603 					int err=S9xMovieCreate (_tToChar(op.Path), op.ControllersMask, op.Opts, op.Metadata, wcslen(op.Metadata));
1604 					startingMovie = false;
1605 					if(err!=SUCCESS)
1606 					{
1607 						TCHAR* err_string=MOVIE_ERR_COULD_NOT_OPEN;
1608 						switch(err)
1609 						{
1610 						case FILE_NOT_FOUND:
1611 							err_string=MOVIE_ERR_NOT_FOUND;
1612 							break;
1613 						case WRONG_FORMAT:
1614 							err_string=MOVIE_ERR_WRONG_FORMAT;
1615 							break;
1616 						case WRONG_VERSION:
1617 							err_string=MOVIE_ERR_WRONG_VERSION;
1618 							break;
1619 						}
1620 						MessageBox( hWnd, err_string, SNES9X_INFO, MB_OK);
1621 					}
1622 				}
1623 				RestoreSNESDisplay ();// re-enter after dialog
1624 			}
1625 			break;
1626 		case IDM_SNES_JOYPAD:
1627 			MOVIE_LOCKED_SETTING
1628 			GUI.ControllerOption = SNES_JOYPAD;
1629 			ChangeInputDevice();
1630 			break;
1631 		case IDM_ENABLE_MULTITAP:
1632 			MOVIE_LOCKED_SETTING
1633 			GUI.ControllerOption = SNES_MULTIPLAYER5;
1634 			ChangeInputDevice();
1635 			break;
1636 		case IDM_SCOPE_TOGGLE:
1637 			MOVIE_LOCKED_SETTING
1638 			GUI.ControllerOption = SNES_SUPERSCOPE;
1639 			ChangeInputDevice();
1640 			break;
1641 		case IDM_JUSTIFIER:
1642 			MOVIE_LOCKED_SETTING
1643 			GUI.ControllerOption = SNES_JUSTIFIER;
1644 			ChangeInputDevice();
1645 			break;
1646 		case IDM_MOUSE_TOGGLE:
1647 			MOVIE_LOCKED_SETTING
1648 			GUI.ControllerOption = SNES_MOUSE;
1649 			ChangeInputDevice();
1650 			break;
1651 		case IDM_MOUSE_SWAPPED:
1652 			MOVIE_LOCKED_SETTING
1653 			GUI.ControllerOption = SNES_MOUSE_SWAPPED;
1654 			ChangeInputDevice();
1655 			break;
1656 		case IDM_MULTITAP8:
1657 			MOVIE_LOCKED_SETTING
1658 			GUI.ControllerOption = SNES_MULTIPLAYER8;
1659 			ChangeInputDevice();
1660 			break;
1661 		case IDM_JUSTIFIERS:
1662 			MOVIE_LOCKED_SETTING
1663 			GUI.ControllerOption = SNES_JUSTIFIER_2;
1664 			ChangeInputDevice();
1665 			break;
1666 		case IDM_MACSRIFLE_TOGGLE:
1667 			MOVIE_LOCKED_SETTING
1668 			GUI.ControllerOption = SNES_MACSRIFLE;
1669 			ChangeInputDevice();
1670 			break;
1671 
1672 			//start turbo
1673 		case ID_TURBO_R:
1674 			GUI.TurboMask^=TURBO_R_MASK;
1675 			if(GUI.TurboMask&TURBO_R_MASK)
1676 				S9xSetInfoString (WINPROC_TURBO_R_ON);
1677 			else S9xSetInfoString (WINPROC_TURBO_R_OFF);
1678 			break;
1679 		case ID_TURBO_L:
1680 			GUI.TurboMask^=TURBO_L_MASK;
1681 			if(GUI.TurboMask&TURBO_L_MASK)
1682 				S9xSetInfoString (WINPROC_TURBO_L_ON);
1683 			else S9xSetInfoString (WINPROC_TURBO_L_OFF);
1684 			break;
1685 		case ID_TURBO_A:
1686 			GUI.TurboMask^=TURBO_A_MASK;
1687 			if(GUI.TurboMask&TURBO_A_MASK)
1688 				S9xSetInfoString (WINPROC_TURBO_A_ON);
1689 			else S9xSetInfoString (WINPROC_TURBO_A_OFF);
1690 			break;
1691 		case ID_TURBO_B:
1692 			GUI.TurboMask^=TURBO_B_MASK;
1693 			if(GUI.TurboMask&TURBO_B_MASK)
1694 				S9xSetInfoString (WINPROC_TURBO_B_ON);
1695 			else S9xSetInfoString (WINPROC_TURBO_B_OFF);
1696 			break;
1697 		case ID_TURBO_Y:
1698 			GUI.TurboMask^=TURBO_Y_MASK;
1699 			if(GUI.TurboMask&TURBO_Y_MASK)
1700 				S9xSetInfoString (WINPROC_TURBO_Y_ON);
1701 			else S9xSetInfoString (WINPROC_TURBO_Y_OFF);
1702 			break;
1703 		case ID_TURBO_X:
1704 			GUI.TurboMask^=TURBO_X_MASK;
1705 			if(GUI.TurboMask&TURBO_X_MASK)
1706 				S9xSetInfoString (WINPROC_TURBO_X_ON);
1707 			else S9xSetInfoString (WINPROC_TURBO_X_OFF);
1708 			break;
1709 		case ID_TURBO_START:
1710 			GUI.TurboMask^=TURBO_STA_MASK;
1711 			if(GUI.TurboMask&TURBO_STA_MASK)
1712 				S9xSetInfoString (WINPROC_TURBO_START_ON);
1713 			else S9xSetInfoString (WINPROC_TURBO_START_OFF);
1714 			break;
1715 		case ID_TURBO_SELECT:
1716 			GUI.TurboMask^=TURBO_SEL_MASK;
1717 			if(GUI.TurboMask&TURBO_SEL_MASK)
1718 				S9xSetInfoString (WINPROC_TURBO_SEL_ON);
1719 			else S9xSetInfoString (WINPROC_TURBO_SEL_OFF);
1720 			break;
1721 		case ID_TURBO_LEFT:
1722 			GUI.TurboMask^=TURBO_LEFT_MASK;
1723 			if(GUI.TurboMask&TURBO_LEFT_MASK)
1724 				S9xSetInfoString (WINPROC_TURBO_LEFT_ON);
1725 			else S9xSetInfoString (WINPROC_TURBO_LEFT_OFF);
1726 			break;
1727 		case ID_TURBO_UP:
1728 			GUI.TurboMask^=TURBO_UP_MASK;
1729 			if(GUI.TurboMask&TURBO_UP_MASK)
1730 				S9xSetInfoString (WINPROC_TURBO_UP_ON);
1731 			else S9xSetInfoString (WINPROC_TURBO_UP_OFF);
1732 			break;
1733 		case ID_TURBO_RIGHT:
1734 			GUI.TurboMask^=TURBO_RIGHT_MASK;
1735 			if(GUI.TurboMask&TURBO_RIGHT_MASK)
1736 				S9xSetInfoString (WINPROC_TURBO_RIGHT_ON);
1737 			else S9xSetInfoString (WINPROC_TURBO_RIGHT_OFF);
1738 			break;
1739 		case ID_TURBO_DOWN:
1740 			GUI.TurboMask^=TURBO_DOWN_MASK;
1741 			if(GUI.TurboMask&TURBO_DOWN_MASK)
1742 				S9xSetInfoString (WINPROC_TURBO_DOWN_ON);
1743 			else S9xSetInfoString (WINPROC_TURBO_DOWN_OFF);
1744 			break;
1745 			//end turbo
1746 		case ID_OPTIONS_DISPLAY:
1747 			{
1748 				RestoreGUIDisplay ();
1749 
1750 				if(GUI.FullScreen)
1751 					ToggleFullScreen();
1752 				DialogBox(g_hInst, MAKEINTRESOURCE(IDD_NEWDISPLAY), hWnd, DlgFunky);
1753 
1754 				SwitchToGDI();
1755 
1756 				RestoreSNESDisplay ();
1757 
1758 				S9xGraphicsDeinit();
1759 				S9xSetWinPixelFormat ();
1760 				S9xInitUpdate();
1761 				S9xGraphicsInit();
1762 
1763 				IPPU.RenderThisFrame = false;
1764 
1765 
1766 				RECT rect;
1767 				GetClientRect (GUI.hWnd, &rect);
1768 				InvalidateRect (GUI.hWnd, &rect, true);
1769 				break;
1770 			}
1771 
1772 		case ID_OPTIONS_JOYPAD:
1773             RestoreGUIDisplay ();
1774 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_INPUTCONFIG), hWnd, DlgInputConfig);
1775             RestoreSNESDisplay ();
1776             ChangeInputDevice ();
1777             break;
1778 
1779 		case ID_OPTIONS_KEYCUSTOM:
1780             RestoreGUIDisplay ();
1781 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_KEYCUSTOM), hWnd, DlgHotkeyConfig);
1782             RestoreSNESDisplay ();
1783             break;
1784 
1785 		case ID_EMULATION_BACKGROUNDINPUT:
1786 			GUI.BackgroundInput = !GUI.BackgroundInput;
1787 			if(!GUI.hHotkeyTimer)
1788 				GUI.hHotkeyTimer = timeSetEvent (32, 0, (LPTIMECALLBACK)HotkeyTimer, 0, TIME_PERIODIC);
1789 			break;
1790 
1791         case ID_INPUT_BACKGROUNDKEYBOARDHOTKEYS:
1792             GUI.BackgroundKeyHotkeys = !GUI.BackgroundKeyHotkeys;
1793             break;
1794 
1795         case ID_INPUT_DETECTGAMEPADCHANGES:
1796             S9xDetectJoypads();
1797             break;
1798 
1799 		case ID_FILE_LOADMULTICART:
1800 			{
1801 				RestoreGUIDisplay ();
1802 
1803 				const bool ok = (1 <= DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_MULTICART), GUI.hWnd, DlgMultiROMProc, (LPARAM)NULL));
1804 
1805 				if(ok)
1806 				{
1807 					LoadROM(multiRomA, multiRomB);
1808 				}
1809 
1810 				RestoreSNESDisplay ();
1811 			}
1812 			break;
1813 
1814 		case ID_FILE_LOAD_GAME:
1815 			{
1816 				TCHAR filename [_MAX_PATH];
1817 
1818 				RestoreGUIDisplay ();
1819 
1820 				if(DoOpenRomDialog(filename)) {
1821 					LoadROM(filename);
1822 				}
1823 
1824 				RestoreSNESDisplay ();
1825 			}
1826 			break;
1827 
1828 		case ID_FILE_EXIT:
1829             S9xSetPause (PAUSE_EXIT);
1830             PostMessage (hWnd, WM_CLOSE, 0, 0);
1831             break;
1832 
1833 		case ID_WINDOW_HIDEMENUBAR:
1834             if( GetMenu( GUI.hWnd) == NULL)
1835                 SetMenu( GUI.hWnd, GUI.hMenu);
1836             else
1837                 SetMenu( GUI.hWnd, NULL);
1838             break;
1839 
1840 #ifdef NETPLAY_SUPPORT
1841 		case ID_NETPLAY_SERVER:
1842             S9xRestoreWindowTitle ();
1843             EnableServer (!Settings.NetPlayServer);
1844 			if(Settings.NetPlayServer)
1845 			{
1846 				TCHAR localhostmsg [512];
1847 				// FIXME: need winsock2.h for this, don't know how to include it
1848 				//struct addrinfo *aiList = NULL;
1849 				//if(getaddrinfo("localhost", Settings.Port, NULL, &aiList) == 0)
1850 				//{
1851 				//	sprintf(localhostmsg, "Your server address is: %s", aiList->ai_canonname);
1852 				//	MessageBox(GUI.hWnd,localhostmsg,"Note",MB_OK);
1853 				//}
1854 				//else
1855 				{
1856 					char localhostname [256];
1857 					gethostname(localhostname,256);
1858 					_stprintf(localhostmsg, TEXT("Your host name is: %s\nYour port number is: %d"), (TCHAR *)_tFromChar(localhostname), Settings.Port);
1859 					MessageBox(GUI.hWnd,localhostmsg,TEXT("Note"),MB_OK);
1860 				}
1861 			}
1862             break;
1863         case ID_NETPLAY_CONNECT:
1864             RestoreGUIDisplay ();
1865 			if(1<=DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_NETCONNECT), hWnd, DlgNetConnect,(LPARAM)&hostname))
1866 
1867             {
1868 
1869 
1870 				S9xSetPause (PAUSE_NETPLAY_CONNECT);
1871 
1872 				if (!S9xNPConnectToServer (_tToChar(hostname), Settings.Port,
1873 					Memory.ROMName))
1874                 {
1875                     S9xClearPause (PAUSE_NETPLAY_CONNECT);
1876                 }
1877             }
1878 
1879 			RestoreSNESDisplay ();
1880             break;
1881         case ID_NETPLAY_DISCONNECT:
1882             if (Settings.NetPlay)
1883             {
1884                 Settings.NetPlay = FALSE;
1885                 S9xNPDisconnect ();
1886             }
1887             if (Settings.NetPlayServer)
1888             {
1889                 Settings.NetPlayServer = FALSE;
1890                 S9xNPStopServer ();
1891             }
1892             break;
1893         case ID_NETPLAY_OPTIONS:
1894 			{
1895 				bool8 old_netplay_server = Settings.NetPlayServer;
1896 				RestoreGUIDisplay ();
1897 				if(1<=DialogBox(g_hInst, MAKEINTRESOURCE(IDD_NPOPTIONS), hWnd, DlgNPOptions))
1898 				{
1899 					if (old_netplay_server != Settings.NetPlayServer)
1900 					{
1901 						Settings.NetPlayServer = old_netplay_server;
1902 						S9xRestoreWindowTitle ();
1903 						EnableServer (!Settings.NetPlayServer);
1904 					}
1905 				}
1906 				RestoreSNESDisplay ();
1907 				break;
1908 			}
1909         case ID_NETPLAY_SYNC:
1910             S9xNPServerQueueSyncAll ();
1911             break;
1912         case ID_NETPLAY_ROM:
1913             if (NPServer.SyncByReset)
1914             {
1915 			if (MessageBox (GUI.hWnd, TEXT(WINPROC_NET_RESTART), SNES9X_WARN,
1916 											MB_OKCANCEL | MB_ICONWARNING) == IDCANCEL)
1917 											break;
1918             }
1919             S9xNPServerQueueSendingROMImage ();
1920             break;
1921         case ID_NETPLAY_SEND_ROM_ON_CONNECT:
1922             NPServer.SendROMImageOnConnect ^= TRUE;
1923             break;
1924         case ID_NETPLAY_SYNC_BY_RESET:
1925             NPServer.SyncByReset ^= TRUE;
1926             break;
1927 #endif
1928         case ID_SOUND_8000HZ:
1929 		case ID_SOUND_11025HZ:
1930 		case ID_SOUND_16000HZ:
1931 		case ID_SOUND_22050HZ:
1932 		case ID_SOUND_30000HZ:
1933 		case ID_SOUND_35000HZ:
1934 		case ID_SOUND_44100HZ:
1935 		case ID_SOUND_48000HZ:
1936 		case ID_SOUND_32000HZ:
1937             for( i = 0; i < COUNT(SoundRates); i ++)
1938 				if (SoundRates[i].ident == (int) wParam)
1939 				{
1940                     Settings.SoundPlaybackRate = SoundRates [i].rate;
1941 					GUI.Mute = false;
1942 					ReInitSound();
1943                     break;
1944 				}
1945 				break;
1946 
1947 		case ID_SOUND_16MS:
1948 			GUI.SoundBufferSize = 16;
1949 			ReInitSound();
1950 			break;
1951 		case ID_SOUND_32MS:
1952 			GUI.SoundBufferSize = 32;
1953 			ReInitSound();
1954 			break;
1955 		case ID_SOUND_48MS:
1956 			GUI.SoundBufferSize = 48;
1957 			ReInitSound();
1958 			break;
1959 		case ID_SOUND_64MS:
1960 			GUI.SoundBufferSize = 64;
1961 			ReInitSound();
1962 			break;
1963 		case ID_SOUND_80MS:
1964 			GUI.SoundBufferSize = 80;
1965 			ReInitSound();
1966 			break;
1967 		case ID_SOUND_96MS:
1968 			GUI.SoundBufferSize = 96;
1969 			ReInitSound();
1970 			break;
1971 		case ID_SOUND_112MS:
1972 			GUI.SoundBufferSize = 112;
1973 			ReInitSound();
1974 			break;
1975 		case ID_SOUND_128MS:
1976 			GUI.SoundBufferSize = 128;
1977 			ReInitSound();
1978 			break;
1979 		case ID_SOUND_144MS:
1980 			GUI.SoundBufferSize = 144;
1981 			ReInitSound();
1982 			break;
1983 		case ID_SOUND_160MS:
1984 			GUI.SoundBufferSize = 160;
1985 			ReInitSound();
1986 			break;
1987 		case ID_SOUND_176MS:
1988 			GUI.SoundBufferSize = 176;
1989 			ReInitSound();
1990 			break;
1991 		case ID_SOUND_192MS:
1992 			GUI.SoundBufferSize = 192;
1993 			ReInitSound();
1994 			break;
1995 		case ID_SOUND_208MS:
1996 			GUI.SoundBufferSize = 208;
1997 			ReInitSound();
1998 			break;
1999 
2000 
2001         case ID_CHANNELS_CHANNEL1: S9xToggleSoundChannel(0); break;
2002         case ID_CHANNELS_CHANNEL2: S9xToggleSoundChannel(1); break;
2003         case ID_CHANNELS_CHANNEL3: S9xToggleSoundChannel(2); break;
2004         case ID_CHANNELS_CHANNEL4: S9xToggleSoundChannel(3); break;
2005         case ID_CHANNELS_CHANNEL5: S9xToggleSoundChannel(4); break;
2006         case ID_CHANNELS_CHANNEL6: S9xToggleSoundChannel(5); break;
2007         case ID_CHANNELS_CHANNEL7: S9xToggleSoundChannel(6); break;
2008         case ID_CHANNELS_CHANNEL8: S9xToggleSoundChannel(7); break;
2009         case ID_CHANNELS_ENABLEALL: S9xToggleSoundChannel(8); break;
2010 
2011 		case ID_SOUND_NOSOUND:
2012 			S9xSetSoundMute(!GUI.Mute);
2013 			GUI.Mute = !GUI.Mute;
2014             break;
2015 
2016         case ID_SOUND_SYNC:
2017             Settings.SoundSync = !Settings.SoundSync;
2018 			S9xDisplayStateChange (WINPROC_SYNC_SND, Settings.SoundSync);
2019             break;
2020         case ID_SOUND_OPTIONS:
2021 			{
2022 				RestoreGUIDisplay ();
2023 				if(1<=DialogBoxParam(g_hInst,MAKEINTRESOURCE(IDD_SOUND_OPTS),hWnd,DlgSoundConf, (LPARAM)&Settings))
2024 				{
2025 					ReInitSound();
2026 				}
2027 				RestoreSNESDisplay ();
2028 				break;
2029 			}
2030 		case ID_WINDOW_FULLSCREEN:
2031 			ToggleFullScreen ();
2032 			break;
2033 		case ID_WINDOW_SIZE_1X:
2034 		case ID_WINDOW_SIZE_2X:
2035 		case ID_WINDOW_SIZE_3X:
2036 		case ID_WINDOW_SIZE_4X:
2037 			UINT factor, newWidth, newHeight;
2038 			RECT margins;
2039 			factor = (wParam & 0xffff) - ID_WINDOW_SIZE_1X + 1;
2040 			newWidth = GUI.AspectWidth * factor;
2041 			newHeight = (GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * factor;
2042 
2043 			margins = GetWindowMargins(GUI.hWnd,newWidth);
2044 			newHeight += margins.top + margins.bottom;
2045 			newWidth += margins.left + margins.right;
2046 
2047 			SetWindowPos(GUI.hWnd, NULL, 0, 0, newWidth, newHeight, SWP_NOMOVE);
2048 			break;
2049 		case ID_WINDOW_STRETCH:
2050 			GUI.Stretch = !GUI.Stretch;
2051 			WinDisplayApplyChanges();
2052 			WinRefreshDisplay();
2053 			break;
2054 		case ID_WINDOW_ASPECTRATIO:
2055 			GUI.AspectRatio = !GUI.AspectRatio;
2056 			WinDisplayApplyChanges();
2057 			WinRefreshDisplay();
2058 			break;
2059 		case ID_WINDOW_BILINEAR:
2060 			Settings.BilinearFilter = !Settings.BilinearFilter;
2061 			WinDisplayApplyChanges();
2062 			WinRefreshDisplay();
2063 			break;
2064 		case ID_VIDEO_SHOWFRAMERATE:
2065 			Settings.DisplayFrameRate = !Settings.DisplayFrameRate;
2066 			break;
2067 		case ID_SAVESCREENSHOT:
2068 			Settings.TakeScreenshot=true;
2069 			break;
2070 		case ID_FILE_SAVE_SPC_DATA:
2071 			S9xDumpSPCSnapshot();
2072 			S9xMessage(S9X_INFO, 0, INFO_SAVE_SPC);
2073 			break;
2074 		case ID_FILE_SAVE_SRAM_DATA: {
2075 			bool8 success = Memory.SaveSRAM (S9xGetFilename (".srm", SRAM_DIR));
2076 			if(!success)
2077 				S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_INFO, SRM_SAVE_FAILED);
2078 		}	break;
2079 		case ID_SAVEMEMPACK: {
2080 			const char *filename = S9xGetFilenameInc(".bs", SRAM_DIR);
2081 			bool8 success = Memory.SaveMPAK(filename);
2082 			if (!success)
2083 				S9xMessage(S9X_ERROR, 0, MPAK_SAVE_FAILED);
2084 			else
2085 			{
2086 				sprintf(String, "Saved Memory Pack %s", filename);
2087 				S9xMessage(S9X_INFO, 0, String);
2088 			}
2089 		}	break;
2090 		case ID_FILE_RESET:
2091 #ifdef NETPLAY_SUPPORT
2092 			if (Settings.NetPlayServer)
2093 			{
2094 				S9xNPReset ();
2095 				ReInitSound();
2096 			}
2097 			else
2098 				if (!Settings.NetPlay)
2099 #endif
2100 				{
2101 					S9xMovieUpdateOnReset ();
2102 					if(S9xMoviePlaying())
2103 						S9xMovieStop (TRUE);
2104 					S9xSoftReset ();
2105 					ReInitSound();
2106 				}
2107 				if(!S9xMovieRecording())
2108 					Settings.Paused = false;
2109 				break;
2110 		case ID_FILE_PAUSE:
2111 			Settings.Paused = !Settings.Paused;
2112 			Settings.FrameAdvance = false;
2113 			GUI.FrameAdvanceJustPressed = 0;
2114 			break;
2115         case ID_FILE_LOAD0:
2116 			FreezeUnfreezeSlot (0, FALSE);
2117 			break;
2118 		case ID_FILE_LOAD1:
2119 			FreezeUnfreezeSlot (1, FALSE);
2120 			break;
2121 		case ID_FILE_LOAD2:
2122 			FreezeUnfreezeSlot (2, FALSE);
2123 			break;
2124 		case ID_FILE_LOAD3:
2125 			FreezeUnfreezeSlot (3, FALSE);
2126 			break;
2127 		case ID_FILE_LOAD4:
2128 			FreezeUnfreezeSlot (4, FALSE);
2129 			break;
2130 		case ID_FILE_LOAD5:
2131 			FreezeUnfreezeSlot (5, FALSE);
2132 			break;
2133 		case ID_FILE_LOAD6:
2134 			FreezeUnfreezeSlot (6, FALSE);
2135 			break;
2136 		case ID_FILE_LOAD7:
2137 			FreezeUnfreezeSlot (7, FALSE);
2138 			break;
2139 		case ID_FILE_LOAD8:
2140 			FreezeUnfreezeSlot (8, FALSE);
2141 			break;
2142 		case ID_FILE_LOAD9:
2143 			FreezeUnfreezeSlot (9, FALSE);
2144 			break;
2145 		case ID_FILE_LOAD_OOPS:
2146 			FreezeUnfreezeSlot(-1, FALSE);
2147 			break;
2148         case ID_FILE_LOAD_FILE:
2149             FreezeUnfreezeDialog(FALSE);
2150             break;
2151         case ID_FILE_SAVE0:
2152             FreezeUnfreezeSlot (0, TRUE);
2153 			break;
2154 		case ID_FILE_SAVE1:
2155 			FreezeUnfreezeSlot (1, TRUE);
2156 			break;
2157 		case ID_FILE_SAVE2:
2158 			FreezeUnfreezeSlot (2, TRUE);
2159 			break;
2160 		case ID_FILE_SAVE3:
2161 			FreezeUnfreezeSlot (3, TRUE);
2162 			break;
2163 		case ID_FILE_SAVE4:
2164 			FreezeUnfreezeSlot (4, TRUE);
2165 			break;
2166 		case ID_FILE_SAVE5:
2167 			FreezeUnfreezeSlot (5, TRUE);
2168 			break;
2169 		case ID_FILE_SAVE6:
2170 			FreezeUnfreezeSlot (6, TRUE);
2171 			break;
2172 		case ID_FILE_SAVE7:
2173 			FreezeUnfreezeSlot (7, TRUE);
2174 			break;
2175 		case ID_FILE_SAVE8:
2176 			FreezeUnfreezeSlot (8, TRUE);
2177 			break;
2178 		case ID_FILE_SAVE9:
2179 			FreezeUnfreezeSlot (9, TRUE);
2180 			break;
2181         case ID_FILE_SAVE_FILE:
2182             FreezeUnfreezeDialog(TRUE);
2183             break;
2184 		case ID_CHEAT_ENTER:
2185 			RestoreGUIDisplay ();
2186 			while (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEATER), hWnd, DlgCheater) == NC_SEARCHDB)
2187 			{
2188 				WinSearchCheatDatabase();
2189 			}
2190 			S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
2191 			RestoreSNESDisplay ();
2192 			break;
2193 		case ID_CHEAT_SEARCH:
2194 			RestoreGUIDisplay ();
2195 			if(!cheatSearchHWND) // create and show non-modal cheat search window
2196 			{
2197 				cheatSearchHWND = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_SEARCH), hWnd, DlgCheatSearch); // non-modal/modeless
2198 				ShowWindow(cheatSearchHWND, SW_SHOW);
2199 			}
2200 			else // already open so just reactivate the window
2201 			{
2202 				SetActiveWindow(cheatSearchHWND);
2203 			}
2204 			RestoreSNESDisplay ();
2205 			break;
2206 		case ID_CHEAT_SEARCH_MODAL:
2207 			RestoreGUIDisplay ();
2208 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_SEARCH), hWnd, DlgCheatSearch); // modal
2209 			S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
2210 			RestoreSNESDisplay ();
2211 			break;
2212 		case ID_CHEAT_APPLY:
2213 			Settings.ApplyCheats = !Settings.ApplyCheats;
2214 			if (!Settings.ApplyCheats){
2215 				S9xCheatsDisable ();
2216 				S9xMessage (S9X_INFO, S9X_GAME_GENIE_CODE_ERROR, CHEATS_INFO_DISABLED);
2217 			}else{
2218 				S9xCheatsEnable ();
2219 				bool on = false;
2220 				extern struct SCheatData Cheat;
2221 				for (uint32 i = 0; i < Cheat.g.size() && !on; i++)
2222 					if (Cheat.g [i].enabled)
2223 						on = true;
2224 				S9xMessage (S9X_INFO, S9X_GAME_GENIE_CODE_ERROR, on ? CHEATS_INFO_ENABLED : CHEATS_INFO_ENABLED_NONE);
2225 			}
2226 			break;
2227 		case ID_EMULATION_PAUSEWHENINACTIVE:
2228 			GUI.InactivePause = !GUI.InactivePause;
2229 			break;
2230 		case ID_OPTIONS_SETTINGS:
2231 			RestoreGUIDisplay ();
2232 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_EMU_SETTINGS), hWnd, DlgEmulatorProc);
2233 			RestoreSNESDisplay ();
2234 			break;
2235         case ID_EMULATION_HACKS:
2236 			if (MessageBoxA(hWnd,
2237 				"The settings in this dialog should only be used for compatibility "
2238 				"with old ROM hacks or if you otherwise know what you're doing.\n\n"
2239 				"If any problems occur, click \"Set Defaults\" to reset the options to normal.",
2240 				"Warning: Unsupported",
2241 				MB_ICONWARNING | MB_OKCANCEL) != IDOK)
2242 				break;
2243 
2244             RestoreGUIDisplay();
2245 			i = DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG_HACKS), hWnd, DlgEmulatorHacksProc);
2246             if (i == 1)
2247                 S9xReset();
2248             else
2249                 RestoreSNESDisplay();
2250             break;
2251 		case ID_HELP_ABOUT:
2252 			RestoreGUIDisplay ();
2253 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, DlgAboutProc);
2254 			RestoreSNESDisplay ();
2255 			break;
2256 		case ID_FRAME_ADVANCE:
2257 			Settings.Paused = true;
2258 			Settings.FrameAdvance = true;
2259 			break;
2260 #ifdef DEBUGGER
2261 		case ID_DEBUG_TRACE:
2262 			S9xDebugProcessCommand("T");
2263 			break;
2264 
2265 		case ID_DEBUG_FRAME_ADVANCE:
2266 			CPU.Flags |= FRAME_ADVANCE_FLAG;
2267 			ICPU.FrameAdvanceCount = 1;
2268 			Settings.Paused = FALSE;
2269 			break;
2270 		case ID_DEBUG_APU_TRACE:
2271 			// TODO: reactivate once APU debugger works again
2272 			//spc_core->debug_toggle_trace();
2273 			break;
2274 #endif
2275 		case IDM_ROM_INFO:
2276 			RestoreGUIDisplay ();
2277 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ROM_INFO), hWnd, DlgInfoProc);
2278 			RestoreSNESDisplay ();
2279 			break;
2280 		default:
2281 			if ((wParam & 0xffff) >= 0xFF00)
2282 			{
2283 				int i = (wParam & 0xffff) - 0xFF00;
2284 				int j = 0;
2285 				{
2286 					while (j < MAX_RECENT_GAMES_LIST_SIZE && j != i)
2287 						j++;
2288 					if (i == j)
2289 					{
2290 
2291 						if (!LoadROM(GUI.RecentGames [i])) {
2292 							sprintf (String, ERR_ROM_NOT_FOUND, (char *)_tToChar(GUI.RecentGames [i]));
2293 							S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String);
2294 							S9xRemoveFromRecentGames(i);
2295 						}
2296 					}
2297 				}
2298 			}
2299 			break;
2300         }
2301         break;
2302 
2303 	case WM_EXITMENULOOP:
2304 		UpdateWindow(GUI.hWnd);
2305 		DrawMenuBar(GUI.hWnd);
2306 		S9xClearPause (PAUSE_MENU);
2307 		break;
2308 
2309 	case WM_ENTERMENULOOP:
2310 		S9xSetPause (PAUSE_MENU);
2311 		CheckMenuStates ();
2312 
2313 		SwitchToGDI();
2314 		DrawMenuBar(GUI.hWnd);
2315 		break;
2316 
2317 	case WM_CLOSE:
2318 		SaveMainWinPos();
2319 		break;
2320 
2321 	case WM_DESTROY:
2322 		Memory.SaveSRAM(S9xGetFilename(".srm", SRAM_DIR));
2323 		GUI.hWnd = NULL;
2324 		PostQuitMessage (0);
2325 		return (0);
2326 	case WM_PAINT:
2327         {
2328 			// refresh screen
2329 			WinRefreshDisplay();
2330             break;
2331         }
2332 	case WM_SYSCOMMAND:
2333         {
2334             // Prevent screen saver from starting if not paused
2335 			//kode54 says add the ! to fix the screensaver pevention.
2336             if (!(Settings.ForcedPause || Settings.StopEmulation ||
2337 				(Settings.Paused && !Settings.FrameAdvance)) &&
2338                 (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER))
2339                 return (0);
2340             break;
2341         }
2342 	case WM_ACTIVATE:
2343 		if (LOWORD(wParam) == WA_INACTIVE)
2344 		{
2345 			if(GUI.InactivePause)
2346 			{
2347 				S9xSetPause (PAUSE_INACTIVE_WINDOW);
2348 			}
2349 		}
2350 		else
2351 		{
2352 			Settings.TurboMode = false;
2353 ///			if(GUI.InactivePause)
2354 			{
2355 				S9xClearPause (PAUSE_INACTIVE_WINDOW);
2356 			}
2357 			IPPU.ColorsChanged = TRUE;
2358 		}
2359 		break;
2360 	case WM_QUERYNEWPALETTE:
2361 		//            if (!GUI.FullScreen && GUI.ScreenDepth == 8)
2362 		//                RealizePalette (GUI.WindowDC);
2363 		break;
2364 	case WM_SIZE:
2365 		if (wParam == SIZE_MINIMIZED && GUI.InactivePause)
2366 		{
2367 			S9xSetPause(PAUSE_INACTIVE_WINDOW);
2368 		}
2369 		WinChangeWindowSize(LOWORD(lParam),HIWORD(lParam));
2370 		break;
2371 	case WM_MOVE:
2372 		//if (!VOODOO_MODE && !GUI.FullScreen && !Settings.ForcedPause)
2373 		//{
2374 		//	GetWindowRect (GUI.hWnd, &GUI.window_size);
2375 		//}
2376 
2377 		break;
2378 	case WM_ENTERSIZEMOVE:
2379 		S9xSetPause(PAUSE_MENU);
2380 		break;
2381 	case WM_EXITSIZEMOVE:
2382 		S9xClearPause(PAUSE_MENU);
2383 		break;
2384 	case WM_DISPLAYCHANGE:
2385 		if (!GUI.FullScreen && !(Settings.ForcedPause & PAUSE_TOGGLE_FULL_SCREEN))
2386 		{
2387 			WinDisplayReset();
2388 		}
2389 		break;
2390 	case WM_MOUSEMOVE:
2391 		if(Settings.StopEmulation)
2392 		{
2393 			SetCursor (GUI.Arrow);
2394 			break;
2395 		}
2396 		// Lo-word of lparam is xpos, hi-word is ypos
2397 //		if (!GUI.IgnoreNextMouseMove)
2398 		{
2399 			//POINT p;
2400 			//p.x = GET_X_LPARAM(lParam);
2401 			//p.y = GET_Y_LPARAM(lParam);
2402 			//ClientToScreen (GUI.hWnd, &p);
2403 			if ((!Settings.ForcedPause && !Settings.StopEmulation &&
2404 				!(Settings.Paused && !Settings.FrameAdvance)) &&
2405 				(GUI.ControllerOption==SNES_MOUSE || GUI.ControllerOption==SNES_MOUSE_SWAPPED)
2406 			   )
2407 			{
2408 				CenterCursor();
2409 			}
2410 			else if (GUI.ControllerOption==SNES_SUPERSCOPE || GUI.ControllerOption==SNES_JUSTIFIER || GUI.ControllerOption==SNES_JUSTIFIER_2 || GUI.ControllerOption==SNES_MACSRIFLE)
2411 			{
2412 				RECT size;
2413 				GetClientRect (GUI.hWnd, &size);
2414 				if(!(GUI.Scale)&&!(GUI.Stretch))
2415 				{
2416 					int x,y, startx, starty;
2417 					x=GET_X_LPARAM(lParam);
2418 					y=GET_Y_LPARAM(lParam);
2419 
2420 //					int theight;
2421 //					(IPPU.RenderedScreenHeight> 256)? theight= SNES_HEIGHT_EXTENDED<<1: theight = SNES_HEIGHT_EXTENDED;
2422 					int theight = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT;
2423 					if(IPPU.RenderedScreenHeight > SNES_HEIGHT_EXTENDED) theight <<= 1;
2424 
2425 					startx= size.right-IPPU.RenderedScreenWidth;
2426 					startx/=2;
2427 					starty= size.bottom-theight;
2428 					starty/=2;
2429 
2430 					if(x<startx)
2431 						GUI.MouseX=0;
2432 					else if(x>(startx+IPPU.RenderedScreenWidth))
2433 						GUI.MouseX=IPPU.RenderedScreenWidth;
2434 					else GUI.MouseX=x-startx;
2435 
2436 					if(y<starty)
2437 						GUI.MouseY=0;
2438 					else if(y>(starty+theight))
2439 						GUI.MouseY=theight;
2440 					else GUI.MouseY=y-starty;
2441 				}
2442 				else if(!(GUI.Stretch))
2443 				{
2444 					int x,y, startx, starty, sizex, sizey;
2445 					x=GET_X_LPARAM(lParam);
2446 					y=GET_Y_LPARAM(lParam);
2447 
2448 					if (IPPU.RenderedScreenWidth>256)
2449 						sizex=IPPU.RenderedScreenWidth;
2450 					else sizex=IPPU.RenderedScreenWidth*2;
2451 
2452 					int theight = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT;
2453 					sizey = (IPPU.RenderedScreenHeight > SNES_HEIGHT_EXTENDED) ? theight : (theight << 1);
2454 
2455 					startx= size.right-sizex;
2456 					startx/=2;
2457 					starty= size.bottom-sizey;
2458 					starty/=2;
2459 					if(x<startx)
2460 						GUI.MouseX=0;
2461 					else if(x>(startx+sizex))
2462 						GUI.MouseX=sizex;
2463 					else GUI.MouseX=x-startx;
2464 
2465 					if(y<starty)
2466 						GUI.MouseY=0;
2467 					else if(y>(starty+sizey))
2468 						GUI.MouseY=sizey;
2469 					else GUI.MouseY=y-starty;
2470 
2471 					GUI.MouseX=(GUI.MouseX*IPPU.RenderedScreenWidth)/sizex;
2472 					GUI.MouseY=(GUI.MouseY*IPPU.RenderedScreenHeight)/sizey;
2473 				}
2474 				else
2475 				{
2476 					int sizex = IPPU.RenderedScreenWidth;
2477 					int sizey = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT;
2478 					sizey = (IPPU.RenderedScreenHeight > SNES_HEIGHT_EXTENDED) ? (sizey << 1) : sizey;
2479 					int width = size.right, height = size.bottom, xdiff = 0, ydiff = 0;
2480 					if(GUI.AspectRatio)
2481 					{
2482 						if(width > sizex*height/sizey)
2483 						{
2484 							xdiff = width - sizex*height/sizey;
2485 							width -= xdiff;
2486 							xdiff >>= 1;
2487 						}
2488 						else if(height > sizey*width/sizex)
2489 						{
2490 							ydiff = height - sizey*width/sizex;
2491 							height -= ydiff;
2492 							ydiff >>= 1;
2493 						}
2494 					}
2495 					GUI.MouseX=(GET_X_LPARAM(lParam)-xdiff)*sizex/width;
2496 					GUI.MouseY=(GET_Y_LPARAM(lParam)-ydiff)*sizey/height;
2497 				}
2498 			}
2499 			else
2500 			{
2501 //				GUI.MouseX = p.x;
2502 //				GUI.MouseY = p.y;
2503 			}
2504 		}
2505 //		else
2506 //			GUI.IgnoreNextMouseMove = false;
2507 
2508 		if(!GUI.IgnoreNextMouseMove)
2509 			S9xMouseOn ();
2510 		else
2511 			GUI.IgnoreNextMouseMove = false;
2512 		return 0;
2513 	case WM_LBUTTONDOWN:
2514 		S9xMouseOn ();
2515 		GUI.MouseButtons |= 1;
2516 		break;
2517 	case WM_LBUTTONUP:
2518 		S9xMouseOn ();
2519 		GUI.MouseButtons &= ~1;
2520 		break;
2521 	case WM_RBUTTONDOWN:
2522 		S9xMouseOn ();
2523 		GUI.MouseButtons |= 2;
2524 		break;
2525 	case WM_RBUTTONUP:
2526 		S9xMouseOn ();
2527 		GUI.MouseButtons &= ~2;
2528 		if(GUI.ControllerOption==SNES_JUSTIFIER || GUI.ControllerOption==SNES_JUSTIFIER_2)
2529 		{
2530 			RECT size;
2531 			GetClientRect (GUI.hWnd, &size);
2532 			GUI.MouseButtons&=~1;
2533 			GUI.MouseX=(IPPU.RenderedScreenWidth*(lParam & 0xffff))/(size.right-size.left);
2534 			GUI.MouseY=(((lParam >> 16) & 0xffff)*IPPU.RenderedScreenHeight)/(size.bottom-size.top);
2535 		}
2536 		break;
2537 	case WM_MBUTTONDOWN:
2538 		S9xMouseOn ();
2539 		GUI.MouseButtons |= 4;
2540 		break;
2541 	case WM_MBUTTONUP:
2542 		S9xMouseOn ();
2543 		GUI.MouseButtons &= ~4;
2544 		break;
2545 #ifdef NETPLAY_SUPPORT
2546 	case WM_USER + 3:
2547 		NetPlay.Answer = S9xLoadROMImage (_tFromChar((const char *) lParam));
2548 		SetEvent (NetPlay.ReplyEvent);
2549 		break;
2550 	case WM_USER + 2:
2551 		S9xMessage (0, 0, NetPlay.WarningMsg);
2552 		break;
2553 	case WM_USER + 1:
2554 		RestoreGUIDisplay ();
2555 		S9xRestoreWindowTitle ();
2556 		MessageBox (GUI.hWnd, _tFromChar(NetPlay.ErrorMsg),
2557 			SNES9X_NP_ERROR, MB_OK | MB_ICONSTOP);
2558 		RestoreSNESDisplay ();
2559 		break;
2560 	case WM_USER:
2561 		if (NetPlay.ActionMsg [0] == 0)
2562 			S9xRestoreWindowTitle ();
2563 		else
2564 		{
2565 			TCHAR buf [NP_MAX_ACTION_LEN + 10];
2566 
2567 			_stprintf (buf, TEXT("%s %3d%%"), (TCHAR *)_tFromChar(NetPlay.ActionMsg), (int) lParam);
2568 			SetWindowText (GUI.hWnd, buf);
2569 		}
2570 #if 0
2571 		if ((int) lParam >= 0)
2572 		{
2573 			RestoreGUIDisplay ();
2574 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_NETPLAYPROGRESS), hWnd, DlgNPProgress);
2575 		}
2576 		else
2577 		{
2578 			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_NETPLAYPROGRESS), hWnd, DlgNPProgress);
2579 			RestoreSNESDisplay ();
2580 		}
2581 #endif
2582 		break;
2583 #endif
2584 	}
2585     return DefWindowProc (hWnd, uMsg, wParam, lParam);
2586 }
2587 
2588 /*****************************************************************************/
2589 /* WinInit                                                                   */
2590 /*****************************************************************************/
WinInit(HINSTANCE hInstance)2591 BOOL WinInit( HINSTANCE hInstance)
2592 {
2593     WNDCLASSEX wndclass;
2594 	memset(&wndclass, 0, sizeof(wndclass));
2595 	wndclass.cbSize = sizeof(wndclass);
2596 
2597     wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2598     wndclass.lpfnWndProc = WinProc;
2599     wndclass.hInstance = hInstance;
2600     wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1));
2601     wndclass.hIconSm = NULL;
2602     wndclass.hCursor = NULL;
2603     wndclass.lpszMenuName = NULL;
2604     wndclass.lpszClassName = TEXT("Snes9x: WndClass");
2605 	wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
2606 
2607     GUI.hInstance = hInstance;
2608 
2609     if (!RegisterClassEx (&wndclass))
2610 	{
2611 		MessageBox (NULL, TEXT("Failed to register windows class"), TEXT("Internal Error"), MB_OK | MB_ICONSTOP);
2612         return FALSE;
2613 	}
2614 
2615 	GUI.hMenu = LoadMenu(GUI.hInstance, MAKEINTRESOURCE(IDR_MENU_US));
2616     if (GUI.hMenu == NULL)
2617 	{
2618 		MessageBox (NULL, TEXT("Failed to initialize the menu.\nThis could indicate a failure of your operating system;\ntry closing some other windows or programs, or restart your computer, before opening Snes9x again.\nOr, if you compiled this program yourself, ensure that Snes9x was built with the proper resource files."), TEXT("Snes9x - Menu Initialization Failure"), MB_OK | MB_ICONSTOP);
2619 //        return FALSE; // disabled: try to function without the menu
2620 	}
2621 #ifdef DEBUGGER
2622 	if(GUI.hMenu) {
2623 		InsertMenu(GUI.hMenu,ID_OPTIONS_SETTINGS,MF_BYCOMMAND | MF_STRING | MF_ENABLED,ID_DEBUG_FRAME_ADVANCE,TEXT("&Debug Frame Advance"));
2624 		InsertMenu(GUI.hMenu,ID_OPTIONS_SETTINGS,MF_BYCOMMAND | MF_STRING | MF_ENABLED,ID_DEBUG_TRACE,TEXT("&Trace"));
2625 		InsertMenu(GUI.hMenu,ID_OPTIONS_SETTINGS,MF_BYCOMMAND | MF_STRING | MF_ENABLED,ID_DEBUG_APU_TRACE,TEXT("&APU Trace"));
2626 		InsertMenu(GUI.hMenu,ID_OPTIONS_SETTINGS,MF_BYCOMMAND | MF_SEPARATOR | MF_ENABLED,NULL,NULL);
2627 	}
2628 #endif
2629 
2630     TCHAR buf [100];
2631     _stprintf(buf, TEXT("%s %s"), WINDOW_TITLE, TEXT(VERSION));
2632 
2633     DWORD dwExStyle;
2634     DWORD dwStyle;
2635     RECT rect;
2636 
2637     rect.left = rect.top = 0;
2638     rect.right = MAX_SNES_WIDTH;
2639     rect.bottom = MAX_SNES_HEIGHT;
2640     dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
2641     dwStyle = WS_OVERLAPPEDWINDOW;
2642 
2643     AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
2644     if ((GUI.hWnd = CreateWindowEx (
2645         dwExStyle,
2646         TEXT("Snes9x: WndClass"),
2647         buf,
2648         WS_CLIPSIBLINGS |
2649         WS_CLIPCHILDREN |
2650         dwStyle,
2651         0, 0,
2652         rect.right - rect.left, rect.bottom - rect.top,
2653         NULL,
2654         GUI.hMenu,
2655         hInstance,
2656         NULL)) == NULL)
2657         return FALSE;
2658 
2659     GUI.hDC = GetDC (GUI.hWnd);
2660     GUI.GunSight = LoadCursor (hInstance, MAKEINTRESOURCE (IDC_CURSOR_SCOPE));
2661     GUI.Arrow = LoadCursor (NULL, IDC_ARROW);
2662     GUI.Accelerators = LoadAccelerators (hInstance, MAKEINTRESOURCE (IDR_SNES9X_ACCELERATORS));
2663     Settings.ForcedPause = 0;
2664     Settings.StopEmulation = TRUE;
2665     Settings.Paused = FALSE;
2666 
2667 	GUI.AVIOut = NULL;
2668 
2669     return TRUE;
2670 }
2671 
2672 
2673 
S9xExtraUsage()2674 void S9xExtraUsage ()
2675 {
2676 }
2677 
2678 // handles joystick hotkey presses
HotkeyTimer(UINT idEvent,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)2679 VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
2680 {
2681 //	static int lastTime = timeGetTime();
2682 //	if(timeGetTime() - lastTime > 5)
2683 	{
2684 		bool S9xGetState (WORD KeyIdent);
2685 
2686 		if(GUI.JoystickHotkeys)
2687 		{
2688 			static int counter = 0;
2689 			static uint32 joyState[6][53];
2690             for(int j = 0 ; j < 6 ; j++)
2691             {
2692 			    for(int i = 0 ; i < 53 ; i++)
2693 			    {
2694                     if(counter%2 && !joyState[j][i])
2695 					    continue;
2696 
2697                     WPARAM wp = (WPARAM)(0x8000 | (j << 8) | i);
2698 				    bool active = !S9xGetState(wp);
2699 				    if(active)
2700 				    {
2701 					    if(joyState[j][i] < ULONG_MAX) // 0xffffffffUL
2702 						    joyState[j][i]++;
2703 					    if(joyState[j][i] == 1 || joyState[j][i] >= 12)
2704 						    PostMessage(GUI.hWnd, WM_CUSTKEYDOWN, wp,(LPARAM)(NULL));
2705 				    }
2706 				    else
2707 					    if(joyState[j][i])
2708 					    {
2709 						    joyState[j][i] = 0;
2710 						    PostMessage(GUI.hWnd, WM_CUSTKEYUP, wp,(LPARAM)(NULL));
2711 					    }
2712 			    }
2713             }
2714             counter++;
2715 		}
2716 		if(GUI.BackgroundInput && !GUI.InactivePause)
2717 		{
2718 			static int counter = 0;
2719 			static uint32 joyState [256];
2720 			for(int i = 0 ; i < 255 ; i++)
2721 			{
2722 				if(counter%2 && !joyState[i])
2723 					continue;
2724 
2725 				// special case for escape since S9xGetState ignores it
2726 				bool active;
2727 				if (i == VK_ESCAPE)
2728 					active = (GetKeyState(VK_ESCAPE) & 0x80) != 0;
2729 				else
2730 					active = !S9xGetState(i);
2731 				if(active)
2732 				{
2733 					if(joyState[i] < ULONG_MAX) // 0xffffffffUL
2734 						joyState[i]++;
2735 					if(joyState[i] == 1 || joyState[i] >= 12)
2736 						PostMessage(GUI.hWnd, WM_CUSTKEYDOWN, (WPARAM)(i),(LPARAM)(NULL));
2737 				}
2738 				else
2739 					if(joyState[i])
2740 					{
2741 						joyState[i] = 0;
2742 						PostMessage(GUI.hWnd, WM_CUSTKEYUP, (WPARAM)(i),(LPARAM)(NULL));
2743 					}
2744 			}
2745 			counter++;
2746 		}
2747 //		lastTime = timeGetTime();
2748 	}
2749 }
2750 
FrameTimer(UINT idEvent,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)2751 void CALLBACK FrameTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
2752 {
2753 	// QueryPerformanceCounter is unreliable on newfangled frequency-switching computers,
2754 	// yet is absolutely necessary for best performance on somewhat older computers (even ones that are capable of frequency switching but don't do it very often).
2755 	// Thus, we keep two timers and use the QueryPerformanceCounter one unless the other (more accurate but less precise)
2756 	// one differs from it by more than a few milliseconds.
2757 
2758     QueryPerformanceCounter((LARGE_INTEGER*)&PCEnd);
2759 	PCEndTicks = timeGetTime()*1000;
2760 
2761 	const __int64 PCElapsedPrecise = PCEnd - PCStart;
2762 	const __int64 PCElapsedAccurate = (__int64)(PCEndTicks - PCStartTicks) * PCBase / 1000000;
2763 	const bool useTicksTimer = (abs((int)(PCElapsedPrecise - PCElapsedAccurate)) > (PCBase >> 7)); // if > 7.8 ms difference, settle for accuracy at the sacrifice of precision
2764 
2765     while ((!useTicksTimer && (PCEnd      - PCStart     ) >= PCFrameTime) ||
2766 		   ( useTicksTimer && (PCEndTicks - PCStartTicks) >= PCFrameTime * 1000000 / PCBase))
2767 	{
2768         if (GUI.FrameCount == GUI.LastFrameCount)
2769             GUI.IdleCount++;
2770         else
2771         {
2772             GUI.IdleCount = 0;
2773             GUI.LastFrameCount = GUI.FrameCount;
2774         }
2775 
2776 #ifdef NETPLAY_SUPPORT
2777 		//    if (Settings.NetPlay && !Settings.NetPlayServer)
2778 		//        return;
2779         if (Settings.NetPlay && !Settings.NetPlayServer)
2780             return;
2781 
2782 		//-    if (Settings.NetPlayServer)
2783 		//-    {
2784 		//-        if (Settings.Paused || Settings.StopEmulation || Settings.ForcedPause)
2785         if (Settings.NetPlayServer)
2786 		{
2787 			//-            WaitForSingleObject (GUI.ServerTimerSemaphore, 0);
2788             if ((Settings.Paused && !Settings.FrameAdvance) || Settings.StopEmulation || Settings.ForcedPause)
2789             {
2790                 WaitForSingleObject (GUI.ServerTimerSemaphore, 0);
2791                 return;
2792             }
2793             ReleaseSemaphore (GUI.ServerTimerSemaphore, 1, NULL);
2794 
2795             if (Settings.NetPlay)
2796                 return;
2797         }
2798         else
2799 #endif
2800 		{
2801 			if (Settings.SkipFrames != AUTO_FRAMERATE || Settings.TurboMode ||
2802 				(Settings.Paused /*&& !Settings.FrameAdvance*/) || Settings.StopEmulation || Settings.ForcedPause)
2803 			{
2804 				WaitForSingleObject (GUI.FrameTimerSemaphore, 0);
2805 				PCStart = PCEnd;
2806 				PCStartTicks = PCEndTicks;
2807 				return;
2808 			}
2809 			//        ReleaseSemaphore (GUI.ServerTimerSemaphore, 1, NULL);
2810 			ReleaseSemaphore (GUI.FrameTimerSemaphore, 1, NULL);
2811 
2812 			//        if (Settings.NetPlay)
2813 			//            return;
2814 			//    }
2815 			//    else
2816 			//#endif
2817 			//    if (Settings.SkipFrames != AUTO_FRAMERATE || Settings.TurboMode ||
2818 			//        Settings.Paused || Settings.StopEmulation || Settings.ForcedPause)
2819 			//    {
2820 			//        WaitForSingleObject (GUI.FrameTimerSemaphore, 0);
2821 			//        return;
2822 			//    }
2823 			//    ReleaseSemaphore (GUI.FrameTimerSemaphore, 1, NULL);
2824 			PCStart += PCFrameTime;
2825 			PCStartTicks += (DWORD)(PCFrameTime * 1000000 / PCBase);
2826 		}
2827 	}
2828 }
2829 
EnsureInputDisplayUpdated()2830 static void EnsureInputDisplayUpdated()
2831 {
2832 	if(GUI.FrameAdvanceJustPressed==1 && Settings.Paused && Settings.DisplayPressedKeys==2 && GUI.ControllerOption != SNES_JOYPAD && GUI.ControllerOption != SNES_MULTIPLAYER5 && GUI.ControllerOption != SNES_MULTIPLAYER8)
2833 		WinRefreshDisplay();
2834 }
2835 
2836 // for "frame advance skips non-input frames" feature
S9xOnSNESPadRead()2837 void S9xOnSNESPadRead()
2838 {
2839 	if(!GUI.FASkipsNonInput)
2840 		return;
2841 
2842 	if(prevPadReadFrame != IPPU.TotalEmulatedFrames) // we want <= 1 calls per frame
2843 	{
2844 		prevPadReadFrame = IPPU.TotalEmulatedFrames;
2845 
2846 		if(Settings.FrameAdvance && Settings.Paused && !skipNextFrameStop)
2847 		{
2848 			Settings.FrameAdvance = false;
2849 
2850 			EnsureInputDisplayUpdated();
2851 
2852 			// wait until either unpause or next frame advance
2853 			// note: using GUI.hWnd instead of NULL for PeekMessage/GetMessage breaks some non-modal dialogs
2854 			MSG msg;
2855 			while (Settings.StopEmulation || (Settings.Paused && !Settings.FrameAdvance) ||
2856 				Settings.ForcedPause ||
2857 				PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
2858 			{
2859 				if (!GetMessage (&msg, NULL, 0, 0))
2860 				{
2861 					PostMessage(GUI.hWnd, WM_QUIT, 0,0);
2862 					return;
2863 				}
2864 
2865 				if (!TranslateAccelerator (GUI.hWnd, GUI.Accelerators, &msg))
2866 				{
2867 					TranslateMessage (&msg);
2868 					DispatchMessage (&msg);
2869 				}
2870 			}
2871 
2872 		}
2873 		else
2874 		{
2875 			skipNextFrameStop = false;
2876 		}
2877 	}
2878 }
2879 
2880 
2881 enum
2882 {
2883 	k_HD = 0x80000000,
2884 
2885 	k_JP = 0x01000000,
2886 	k_MO = 0x02000000,
2887 	k_SS = 0x04000000,
2888 	k_LG = 0x08000000,
2889 	k_RF = 0x10000000,
2890 
2891 	k_BT = 0x00100000,
2892 	k_PT = 0x00200000,
2893 	k_PS = 0x00400000,
2894 
2895 	k_C1 = 0x00000100,
2896 	k_C2 = 0x00000200,
2897 	k_C3 = 0x00000400,
2898 	k_C4 = 0x00000800,
2899 	k_C5 = 0x00001000,
2900 	k_C6 = 0x00002000,
2901 	k_C7 = 0x00004000,
2902 	k_C8 = 0x00008000
2903 };
2904 
2905 enum
2906 {
2907 	kWinCMapPad1PX            = k_HD | k_BT | k_JP | k_C1,
2908 	kWinCMapPad1PA,
2909 	kWinCMapPad1PB,
2910 	kWinCMapPad1PY,
2911 	kWinCMapPad1PL,
2912 	kWinCMapPad1PR,
2913 	kWinCMapPad1PSelect,
2914 	kWinCMapPad1PStart,
2915 	kWinCMapPad1PUp,
2916 	kWinCMapPad1PDown,
2917 	kWinCMapPad1PLeft,
2918 	kWinCMapPad1PRight,
2919 
2920 	kWinCMapPad2PX            = k_HD | k_BT | k_JP | k_C2,
2921 	kWinCMapPad2PA,
2922 	kWinCMapPad2PB,
2923 	kWinCMapPad2PY,
2924 	kWinCMapPad2PL,
2925 	kWinCMapPad2PR,
2926 	kWinCMapPad2PSelect,
2927 	kWinCMapPad2PStart,
2928 	kWinCMapPad2PUp,
2929 	kWinCMapPad2PDown,
2930 	kWinCMapPad2PLeft,
2931 	kWinCMapPad2PRight,
2932 
2933 	kWinCMapPad3PX            = k_HD | k_BT | k_JP | k_C3,
2934 	kWinCMapPad3PA,
2935 	kWinCMapPad3PB,
2936 	kWinCMapPad3PY,
2937 	kWinCMapPad3PL,
2938 	kWinCMapPad3PR,
2939 	kWinCMapPad3PSelect,
2940 	kWinCMapPad3PStart,
2941 	kWinCMapPad3PUp,
2942 	kWinCMapPad3PDown,
2943 	kWinCMapPad3PLeft,
2944 	kWinCMapPad3PRight,
2945 
2946 	kWinCMapPad4PX            = k_HD | k_BT | k_JP | k_C4,
2947 	kWinCMapPad4PA,
2948 	kWinCMapPad4PB,
2949 	kWinCMapPad4PY,
2950 	kWinCMapPad4PL,
2951 	kWinCMapPad4PR,
2952 	kWinCMapPad4PSelect,
2953 	kWinCMapPad4PStart,
2954 	kWinCMapPad4PUp,
2955 	kWinCMapPad4PDown,
2956 	kWinCMapPad4PLeft,
2957 	kWinCMapPad4PRight,
2958 
2959 	kWinCMapPad5PX            = k_HD | k_BT | k_JP | k_C5,
2960 	kWinCMapPad5PA,
2961 	kWinCMapPad5PB,
2962 	kWinCMapPad5PY,
2963 	kWinCMapPad5PL,
2964 	kWinCMapPad5PR,
2965 	kWinCMapPad5PSelect,
2966 	kWinCMapPad5PStart,
2967 	kWinCMapPad5PUp,
2968 	kWinCMapPad5PDown,
2969 	kWinCMapPad5PLeft,
2970 	kWinCMapPad5PRight,
2971 
2972 	kWinCMapPad6PX            = k_HD | k_BT | k_JP | k_C6,
2973 	kWinCMapPad6PA,
2974 	kWinCMapPad6PB,
2975 	kWinCMapPad6PY,
2976 	kWinCMapPad6PL,
2977 	kWinCMapPad6PR,
2978 	kWinCMapPad6PSelect,
2979 	kWinCMapPad6PStart,
2980 	kWinCMapPad6PUp,
2981 	kWinCMapPad6PDown,
2982 	kWinCMapPad6PLeft,
2983 	kWinCMapPad6PRight,
2984 
2985 	kWinCMapPad7PX            = k_HD | k_BT | k_JP | k_C7,
2986 	kWinCMapPad7PA,
2987 	kWinCMapPad7PB,
2988 	kWinCMapPad7PY,
2989 	kWinCMapPad7PL,
2990 	kWinCMapPad7PR,
2991 	kWinCMapPad7PSelect,
2992 	kWinCMapPad7PStart,
2993 	kWinCMapPad7PUp,
2994 	kWinCMapPad7PDown,
2995 	kWinCMapPad7PLeft,
2996 	kWinCMapPad7PRight,
2997 
2998 	kWinCMapPad8PX            = k_HD | k_BT | k_JP | k_C8,
2999 	kWinCMapPad8PA,
3000 	kWinCMapPad8PB,
3001 	kWinCMapPad8PY,
3002 	kWinCMapPad8PL,
3003 	kWinCMapPad8PR,
3004 	kWinCMapPad8PSelect,
3005 	kWinCMapPad8PStart,
3006 	kWinCMapPad8PUp,
3007 	kWinCMapPad8PDown,
3008 	kWinCMapPad8PLeft,
3009 	kWinCMapPad8PRight,
3010 
3011 	kWinCMapMouse1PL          = k_HD | k_BT | k_MO | k_C1,
3012 	kWinCMapMouse1PR,
3013 	kWinCMapMouse2PL          = k_HD | k_BT | k_MO | k_C2,
3014 	kWinCMapMouse2PR,
3015 
3016 	kWinCMapScopeOffscreen    = k_HD | k_BT | k_SS | k_C1,
3017 	kWinCMapScopeFire,
3018 	kWinCMapScopeCursor,
3019 	kWinCMapScopeTurbo,
3020 	kWinCMapScopePause,
3021 
3022 	kWinCMapLGun1Offscreen    = k_HD | k_BT | k_LG | k_C1,
3023 	kWinCMapLGun1Trigger,
3024 	kWinCMapLGun1Start,
3025 	kWinCMapLGun2Offscreen    = k_HD | k_BT | k_LG | k_C2,
3026 	kWinCMapLGun2Trigger,
3027 	kWinCMapLGun2Start,
3028 
3029 	kWinCMapMacsRifleTrigger  = k_HD | k_BT | k_RF | k_C1,
3030 
3031 	kWinCMapMouse1Pointer     = k_HD | k_PT | k_MO | k_C1,
3032 	kWinCMapMouse2Pointer     = k_HD | k_PT | k_MO | k_C2,
3033 	kWinCMapSuperscopePointer = k_HD | k_PT | k_SS | k_C1,
3034 	kWinCMapJustifier1Pointer = k_HD | k_PT | k_LG | k_C1,
3035 	kWinCMapMacsRiflePointer  = k_HD | k_PT | k_RF | k_C1,
3036 
3037 	kWinCMapPseudoPtrBase     = k_HD | k_PS | k_LG | k_C2	// for Justifier 2P
3038 };
3039 
3040 
3041 
3042 #define	ASSIGN_BUTTONf(n, s)	S9xMapButton (n, cmd = S9xGetCommandT(s), false)
3043 #define	ASSIGN_BUTTONt(n, s)	S9xMapButton (n, cmd = S9xGetCommandT(s), true)
3044 #define	ASSIGN_POINTRf(n, s)	S9xMapPointer(n, cmd = S9xGetCommandT(s), false)
3045 #define	ASSIGN_POINTRt(n, s)	S9xMapPointer(n, cmd = S9xGetCommandT(s), true)
3046 
3047 #define KeyIsPressed(km, k)		(1 & (((unsigned char *) km) [(k) >> 3] >> ((k) & 7)))
3048 
S9xSetupDefaultKeymap(void)3049 void S9xSetupDefaultKeymap(void)
3050 {
3051 	s9xcommand_t	cmd;
3052 
3053 	ASSIGN_BUTTONf(kWinCMapPad1PX,         "Joypad1 X");
3054 	ASSIGN_BUTTONf(kWinCMapPad1PA,         "Joypad1 A");
3055 	ASSIGN_BUTTONf(kWinCMapPad1PB,         "Joypad1 B");
3056 	ASSIGN_BUTTONf(kWinCMapPad1PY,         "Joypad1 Y");
3057 	ASSIGN_BUTTONf(kWinCMapPad1PL,         "Joypad1 L");
3058 	ASSIGN_BUTTONf(kWinCMapPad1PR,         "Joypad1 R");
3059 	ASSIGN_BUTTONf(kWinCMapPad1PSelect,    "Joypad1 Select");
3060 	ASSIGN_BUTTONf(kWinCMapPad1PStart,     "Joypad1 Start");
3061 	ASSIGN_BUTTONf(kWinCMapPad1PUp,        "Joypad1 Up");
3062 	ASSIGN_BUTTONf(kWinCMapPad1PDown,      "Joypad1 Down");
3063 	ASSIGN_BUTTONf(kWinCMapPad1PLeft,      "Joypad1 Left");
3064 	ASSIGN_BUTTONf(kWinCMapPad1PRight,     "Joypad1 Right");
3065 
3066 	ASSIGN_BUTTONf(kWinCMapPad2PX,         "Joypad2 X");
3067 	ASSIGN_BUTTONf(kWinCMapPad2PA,         "Joypad2 A");
3068 	ASSIGN_BUTTONf(kWinCMapPad2PB,         "Joypad2 B");
3069 	ASSIGN_BUTTONf(kWinCMapPad2PY,         "Joypad2 Y");
3070 	ASSIGN_BUTTONf(kWinCMapPad2PL,         "Joypad2 L");
3071 	ASSIGN_BUTTONf(kWinCMapPad2PR,         "Joypad2 R");
3072 	ASSIGN_BUTTONf(kWinCMapPad2PSelect,    "Joypad2 Select");
3073 	ASSIGN_BUTTONf(kWinCMapPad2PStart,     "Joypad2 Start");
3074 	ASSIGN_BUTTONf(kWinCMapPad2PUp,        "Joypad2 Up");
3075 	ASSIGN_BUTTONf(kWinCMapPad2PDown,      "Joypad2 Down");
3076 	ASSIGN_BUTTONf(kWinCMapPad2PLeft,      "Joypad2 Left");
3077 	ASSIGN_BUTTONf(kWinCMapPad2PRight,     "Joypad2 Right");
3078 
3079 	ASSIGN_BUTTONf(kWinCMapPad3PX,         "Joypad3 X");
3080 	ASSIGN_BUTTONf(kWinCMapPad3PA,         "Joypad3 A");
3081 	ASSIGN_BUTTONf(kWinCMapPad3PB,         "Joypad3 B");
3082 	ASSIGN_BUTTONf(kWinCMapPad3PY,         "Joypad3 Y");
3083 	ASSIGN_BUTTONf(kWinCMapPad3PL,         "Joypad3 L");
3084 	ASSIGN_BUTTONf(kWinCMapPad3PR,         "Joypad3 R");
3085 	ASSIGN_BUTTONf(kWinCMapPad3PSelect,    "Joypad3 Select");
3086 	ASSIGN_BUTTONf(kWinCMapPad3PStart,     "Joypad3 Start");
3087 	ASSIGN_BUTTONf(kWinCMapPad3PUp,        "Joypad3 Up");
3088 	ASSIGN_BUTTONf(kWinCMapPad3PDown,      "Joypad3 Down");
3089 	ASSIGN_BUTTONf(kWinCMapPad3PLeft,      "Joypad3 Left");
3090 	ASSIGN_BUTTONf(kWinCMapPad3PRight,     "Joypad3 Right");
3091 
3092 	ASSIGN_BUTTONf(kWinCMapPad4PX,         "Joypad4 X");
3093 	ASSIGN_BUTTONf(kWinCMapPad4PA,         "Joypad4 A");
3094 	ASSIGN_BUTTONf(kWinCMapPad4PB,         "Joypad4 B");
3095 	ASSIGN_BUTTONf(kWinCMapPad4PY,         "Joypad4 Y");
3096 	ASSIGN_BUTTONf(kWinCMapPad4PL,         "Joypad4 L");
3097 	ASSIGN_BUTTONf(kWinCMapPad4PR,         "Joypad4 R");
3098 	ASSIGN_BUTTONf(kWinCMapPad4PSelect,    "Joypad4 Select");
3099 	ASSIGN_BUTTONf(kWinCMapPad4PStart,     "Joypad4 Start");
3100 	ASSIGN_BUTTONf(kWinCMapPad4PUp,        "Joypad4 Up");
3101 	ASSIGN_BUTTONf(kWinCMapPad4PDown,      "Joypad4 Down");
3102 	ASSIGN_BUTTONf(kWinCMapPad4PLeft,      "Joypad4 Left");
3103 	ASSIGN_BUTTONf(kWinCMapPad4PRight,     "Joypad4 Right");
3104 
3105 	ASSIGN_BUTTONf(kWinCMapPad5PX,         "Joypad5 X");
3106 	ASSIGN_BUTTONf(kWinCMapPad5PA,         "Joypad5 A");
3107 	ASSIGN_BUTTONf(kWinCMapPad5PB,         "Joypad5 B");
3108 	ASSIGN_BUTTONf(kWinCMapPad5PY,         "Joypad5 Y");
3109 	ASSIGN_BUTTONf(kWinCMapPad5PL,         "Joypad5 L");
3110 	ASSIGN_BUTTONf(kWinCMapPad5PR,         "Joypad5 R");
3111 	ASSIGN_BUTTONf(kWinCMapPad5PSelect,    "Joypad5 Select");
3112 	ASSIGN_BUTTONf(kWinCMapPad5PStart,     "Joypad5 Start");
3113 	ASSIGN_BUTTONf(kWinCMapPad5PUp,        "Joypad5 Up");
3114 	ASSIGN_BUTTONf(kWinCMapPad5PDown,      "Joypad5 Down");
3115 	ASSIGN_BUTTONf(kWinCMapPad5PLeft,      "Joypad5 Left");
3116 	ASSIGN_BUTTONf(kWinCMapPad5PRight,     "Joypad5 Right");
3117 
3118 	ASSIGN_BUTTONf(kWinCMapPad6PX,         "Joypad6 X");
3119 	ASSIGN_BUTTONf(kWinCMapPad6PA,         "Joypad6 A");
3120 	ASSIGN_BUTTONf(kWinCMapPad6PB,         "Joypad6 B");
3121 	ASSIGN_BUTTONf(kWinCMapPad6PY,         "Joypad6 Y");
3122 	ASSIGN_BUTTONf(kWinCMapPad6PL,         "Joypad6 L");
3123 	ASSIGN_BUTTONf(kWinCMapPad6PR,         "Joypad6 R");
3124 	ASSIGN_BUTTONf(kWinCMapPad6PSelect,    "Joypad6 Select");
3125 	ASSIGN_BUTTONf(kWinCMapPad6PStart,     "Joypad6 Start");
3126 	ASSIGN_BUTTONf(kWinCMapPad6PUp,        "Joypad6 Up");
3127 	ASSIGN_BUTTONf(kWinCMapPad6PDown,      "Joypad6 Down");
3128 	ASSIGN_BUTTONf(kWinCMapPad6PLeft,      "Joypad6 Left");
3129 	ASSIGN_BUTTONf(kWinCMapPad6PRight,     "Joypad6 Right");
3130 
3131 	ASSIGN_BUTTONf(kWinCMapPad7PX,         "Joypad7 X");
3132 	ASSIGN_BUTTONf(kWinCMapPad7PA,         "Joypad7 A");
3133 	ASSIGN_BUTTONf(kWinCMapPad7PB,         "Joypad7 B");
3134 	ASSIGN_BUTTONf(kWinCMapPad7PY,         "Joypad7 Y");
3135 	ASSIGN_BUTTONf(kWinCMapPad7PL,         "Joypad7 L");
3136 	ASSIGN_BUTTONf(kWinCMapPad7PR,         "Joypad7 R");
3137 	ASSIGN_BUTTONf(kWinCMapPad7PSelect,    "Joypad7 Select");
3138 	ASSIGN_BUTTONf(kWinCMapPad7PStart,     "Joypad7 Start");
3139 	ASSIGN_BUTTONf(kWinCMapPad7PUp,        "Joypad7 Up");
3140 	ASSIGN_BUTTONf(kWinCMapPad7PDown,      "Joypad7 Down");
3141 	ASSIGN_BUTTONf(kWinCMapPad7PLeft,      "Joypad7 Left");
3142 	ASSIGN_BUTTONf(kWinCMapPad7PRight,     "Joypad7 Right");
3143 
3144 	ASSIGN_BUTTONf(kWinCMapPad8PX,         "Joypad8 X");
3145 	ASSIGN_BUTTONf(kWinCMapPad8PA,         "Joypad8 A");
3146 	ASSIGN_BUTTONf(kWinCMapPad8PB,         "Joypad8 B");
3147 	ASSIGN_BUTTONf(kWinCMapPad8PY,         "Joypad8 Y");
3148 	ASSIGN_BUTTONf(kWinCMapPad8PL,         "Joypad8 L");
3149 	ASSIGN_BUTTONf(kWinCMapPad8PR,         "Joypad8 R");
3150 	ASSIGN_BUTTONf(kWinCMapPad8PSelect,    "Joypad8 Select");
3151 	ASSIGN_BUTTONf(kWinCMapPad8PStart,     "Joypad8 Start");
3152 	ASSIGN_BUTTONf(kWinCMapPad8PUp,        "Joypad8 Up");
3153 	ASSIGN_BUTTONf(kWinCMapPad8PDown,      "Joypad8 Down");
3154 	ASSIGN_BUTTONf(kWinCMapPad8PLeft,      "Joypad8 Left");
3155 	ASSIGN_BUTTONf(kWinCMapPad8PRight,     "Joypad8 Right");
3156 
3157 	ASSIGN_BUTTONt(kWinCMapMouse1PL,       "Mouse1 L");
3158 	ASSIGN_BUTTONt(kWinCMapMouse1PR,       "Mouse1 R");
3159 	ASSIGN_BUTTONt(kWinCMapMouse2PL,       "Mouse2 L");
3160 	ASSIGN_BUTTONt(kWinCMapMouse2PR,       "Mouse2 R");
3161 
3162 	ASSIGN_BUTTONt(kWinCMapScopeOffscreen, "Superscope AimOffscreen");
3163 	ASSIGN_BUTTONt(kWinCMapScopeFire,      "Superscope Fire");
3164 	ASSIGN_BUTTONt(kWinCMapScopeCursor,    "Superscope Cursor");
3165 	ASSIGN_BUTTONt(kWinCMapScopeTurbo,     "Superscope ToggleTurbo");
3166 	ASSIGN_BUTTONt(kWinCMapScopePause,     "Superscope Pause");
3167 
3168 	ASSIGN_BUTTONt(kWinCMapLGun1Offscreen, "Justifier1 AimOffscreen");
3169 	ASSIGN_BUTTONt(kWinCMapLGun1Trigger,   "Justifier1 Trigger");
3170 	ASSIGN_BUTTONt(kWinCMapLGun1Start,     "Justifier1 Start");
3171 	ASSIGN_BUTTONt(kWinCMapLGun2Offscreen, "Justifier2 AimOffscreen");
3172 	ASSIGN_BUTTONt(kWinCMapLGun2Trigger,   "Justifier2 Trigger");
3173 	ASSIGN_BUTTONt(kWinCMapLGun2Start,     "Justifier2 Start");
3174 
3175 	ASSIGN_BUTTONt(kWinCMapMacsRifleTrigger,  "MacsRifle Trigger");
3176 
3177 	ASSIGN_POINTRt(kWinCMapMouse1Pointer,     "Pointer Mouse1");
3178 	ASSIGN_POINTRt(kWinCMapMouse2Pointer,     "Pointer Mouse2");
3179 	ASSIGN_POINTRt(kWinCMapSuperscopePointer, "Pointer Superscope");
3180 	ASSIGN_POINTRt(kWinCMapJustifier1Pointer, "Pointer Justifier1");
3181 	ASSIGN_POINTRt(kWinCMapMacsRiflePointer,  "Pointer MacsRifle");
3182 
3183 	ASSIGN_POINTRf(PseudoPointerBase,         "Pointer Justifier2");
3184 	ASSIGN_BUTTONf(kWinCMapPseudoPtrBase + 0, "ButtonToPointer 1u Med");
3185 	ASSIGN_BUTTONf(kWinCMapPseudoPtrBase + 1, "ButtonToPointer 1d Med");
3186 	ASSIGN_BUTTONf(kWinCMapPseudoPtrBase + 2, "ButtonToPointer 1l Med");
3187 	ASSIGN_BUTTONf(kWinCMapPseudoPtrBase + 3, "ButtonToPointer 1r Med");
3188 }
3189 
ControlPadFlagsToS9xReportButtons(int n,uint32 p)3190 void ControlPadFlagsToS9xReportButtons(int n, uint32 p)
3191 {
3192 	uint32	base = k_HD | k_BT | k_JP | (0x100 << n);
3193 
3194 	S9xReportButton(base +  0, (p & 0x0040) != 0);
3195 	S9xReportButton(base +  1, (p & 0x0080) != 0);
3196 	S9xReportButton(base +  2, (p & 0x8000) != 0);
3197 	S9xReportButton(base +  3, (p & 0x4000) != 0);
3198 	S9xReportButton(base +  4, (p & 0x0020) != 0);
3199 	S9xReportButton(base +  5, (p & 0x0010) != 0);
3200 	S9xReportButton(base +  6, (p & 0x2000) != 0);
3201 	S9xReportButton(base +  7, (p & 0x1000) != 0);
3202 	S9xReportButton(base +  8, (p & 0x0800) != 0);
3203 	S9xReportButton(base +  9, (p & 0x0400) != 0);
3204 	S9xReportButton(base + 10, (p & 0x0200) != 0);
3205 	S9xReportButton(base + 11, (p & 0x0100) != 0);
3206 }
3207 
ControlPadFlagsToS9xPseudoPointer(uint32 p)3208 void ControlPadFlagsToS9xPseudoPointer(uint32 p)
3209 {
3210 	// prevent screwiness caused by trying to move the pointer left+right or up+down
3211 	if((p & 0x0c00) == 0x0c00) p &= ~0x0c00;
3212 	if((p & 0x0300) == 0x0300) p &= ~0x0300;
3213 
3214 	// checks added to prevent a lack of right/down movement from breaking left/up movement
3215 	if(!(p & 0x0400))
3216 		S9xReportButton(kWinCMapPseudoPtrBase + 0, (p & 0x0800) != 0);
3217 	if(!(p & 0x0800))
3218 		S9xReportButton(kWinCMapPseudoPtrBase + 1, (p & 0x0400) != 0);
3219 	if(!(p & 0x0100))
3220 		S9xReportButton(kWinCMapPseudoPtrBase + 2, (p & 0x0200) != 0);
3221 	if(!(p & 0x0200))
3222 		S9xReportButton(kWinCMapPseudoPtrBase + 3, (p & 0x0100) != 0);
3223 }
3224 
ProcessInput(void)3225 static void ProcessInput(void)
3226 {
3227 	extern void S9xWinScanJoypads ();
3228 #ifdef NETPLAY_SUPPORT
3229     if (!Settings.NetPlay)
3230 #endif
3231 	S9xWinScanJoypads ();
3232 
3233 	extern uint32 joypads [8];
3234 	for(int i = 0 ; i < 8 ; i++)
3235 		ControlPadFlagsToS9xReportButtons(i, joypads[i]);
3236 
3237 	if (GUI.ControllerOption==SNES_JUSTIFIER_2)
3238 		ControlPadFlagsToS9xPseudoPointer(joypads[1]);
3239 }
3240 
3241 //static void WinDisplayString (const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap);
3242 
3243 
3244 
3245 
3246 /*****************************************************************************/
3247 /* WinMain                                                                   */
3248 /*****************************************************************************/
3249 void DeinitS9x(void);
3250 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)3251 int WINAPI WinMain(
3252 				   HINSTANCE hInstance,
3253 				   HINSTANCE hPrevInstance,
3254 				   LPSTR lpCmdLine,
3255 				   int nCmdShow)
3256 {
3257 	Settings.StopEmulation = TRUE;
3258 
3259 	SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR));
3260 
3261 	// Redirect stderr and stdout to file. It wouldn't go to any commandline anyway.
3262 	FILE* fout = freopen("stdout.txt", "w", stdout);
3263 	if(fout) setvbuf(fout, NULL, _IONBF, 0);
3264 	FILE* ferr = freopen("stderr.txt", "w", stderr);
3265 	if(ferr) setvbuf(ferr, NULL, _IONBF, 0);
3266 
3267 	DWORD wSoundTimerRes;
3268 
3269 	LoadExts();
3270 
3271 	WinRegisterConfigItems ();
3272 
3273 	ConfigFile::SetAlphaSort(false);
3274 	ConfigFile::SetTimeSort(false);
3275 
3276     const TCHAR *rom_filename = WinParseCommandLineAndLoadConfigFile (GetCommandLine());
3277     WinSaveConfigFile ();
3278 	WinLockConfigFile ();
3279 
3280     ControllerOptionsFromControllers();
3281     ChangeInputDevice();
3282 
3283     WinInit (hInstance);
3284 	if(GUI.HideMenu)
3285 	{
3286 		SetMenu (GUI.hWnd, NULL);
3287 	}
3288 
3289     DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
3290     ZeroMemory(&notificationFilter, sizeof(notificationFilter));
3291     notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
3292     notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
3293     RegisterDeviceNotification(GUI.hWnd, &notificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
3294 
3295 	InitRenderFilters();
3296 
3297     GUI.ControlForced = 0xff;
3298     Settings.Rewinding = false;
3299 
3300     S9xSetRecentGames ();
3301 
3302 	RestoreMainWinPos();
3303 
3304 	void InitSnes9x (void);
3305 	InitSnes9x ();
3306 
3307 	if(GUI.FullScreen) {
3308 		GUI.FullScreen = false;
3309 		ToggleFullScreen();
3310 	}
3311 
3312     TIMECAPS tc;
3313     if (timeGetDevCaps(&tc, sizeof(TIMECAPS))== TIMERR_NOERROR)
3314     {
3315 #ifdef __MINGW32__
3316         wSoundTimerRes = min<int>(max<int>(tc.wPeriodMin, 1), tc.wPeriodMax);
3317 #else
3318         wSoundTimerRes = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
3319 #endif
3320         timeBeginPeriod (wSoundTimerRes);
3321     }
3322 	else
3323 	{
3324 		wSoundTimerRes = 5;
3325         timeBeginPeriod (wSoundTimerRes);
3326 	}
3327 
3328     QueryPerformanceFrequency((LARGE_INTEGER*)&PCBase);
3329     QueryPerformanceCounter((LARGE_INTEGER*)&PCStart);
3330 	PCEnd = PCStart;
3331 	PCEndTicks = timeGetTime()*1000;
3332 	PCStartTicks = timeGetTime()*1000;
3333     PCFrameTime = PCFrameTimeNTSC = (__int64)((float)PCBase / 60.09881389744051f);
3334     PCFrameTimePAL = PCBase / 50;
3335 
3336 
3337     Settings.StopEmulation = TRUE;
3338     GUI.hFrameTimer = timeSetEvent (20, 0, (LPTIMECALLBACK)FrameTimer, 0, TIME_PERIODIC);
3339 
3340 	if(GUI.JoystickHotkeys || GUI.BackgroundInput)
3341 	    GUI.hHotkeyTimer = timeSetEvent (32, 0, (LPTIMECALLBACK)HotkeyTimer, 0, TIME_PERIODIC);
3342 	else
3343 		GUI.hHotkeyTimer = 0;
3344 
3345     GUI.FrameTimerSemaphore = CreateSemaphore (NULL, 0, 10, NULL);
3346     GUI.ServerTimerSemaphore = CreateSemaphore (NULL, 0, 10, NULL);
3347 
3348     if (GUI.hFrameTimer == 0)
3349     {
3350         MessageBox( GUI.hWnd, Languages[ GUI.Language].errFrameTimer, TEXT("Snes9x - Frame Timer"), MB_OK | MB_ICONINFORMATION);
3351     }
3352 
3353 	if (rom_filename)
3354 	{
3355 		if (Settings.Multi) // we found -cartB parameter
3356 		{
3357 			lstrcpy(multiRomA, rom_filename); // for the mutli cart dialog
3358 			LoadROM(rom_filename, multiRomB);
3359 		}
3360 		else
3361 		{
3362 			LoadROM(rom_filename);
3363 		}
3364 
3365 		if (*Settings.InitialSnapshotFilename)
3366 		{
3367 			S9xUnfreezeGame(Settings.InitialSnapshotFilename);
3368 		}
3369 	}
3370 
3371 	S9xUnmapAllControls();
3372 	S9xSetupDefaultKeymap();
3373 
3374 	DWORD lastTime = timeGetTime();
3375 
3376     MSG msg;
3377 
3378     while (TRUE)
3379     {
3380 		EnsureInputDisplayUpdated();
3381 
3382 		// note: using GUI.hWnd instead of NULL for PeekMessage/GetMessage breaks some non-modal dialogs
3383         while (Settings.StopEmulation || (Settings.Paused && !Settings.FrameAdvance) ||
3384 			Settings.ForcedPause ||
3385 			PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
3386         {
3387             if (!GetMessage (&msg, NULL, 0, 0))
3388                 goto loop_exit; // got WM_QUIT
3389 
3390             if (!TranslateAccelerator (GUI.hWnd, GUI.Accelerators, &msg))
3391             {
3392                 TranslateMessage (&msg);
3393                 DispatchMessage (&msg);
3394             }
3395 
3396 			S9xSetSoundMute(GUI.Mute || Settings.ForcedPause || (Settings.Paused && (!Settings.FrameAdvance || GUI.FAMute)));
3397         }
3398 
3399 #ifdef NETPLAY_SUPPORT
3400         if (!Settings.NetPlay || !NetPlay.PendingWait4Sync ||
3401             WaitForSingleObject (GUI.ClientSemaphore, 100) != WAIT_TIMEOUT)
3402         {
3403             if (NetPlay.PendingWait4Sync)
3404             {
3405                 NetPlay.PendingWait4Sync = FALSE;
3406                 NetPlay.FrameCount++;
3407                 S9xNPStepJoypadHistory ();
3408             }
3409 #endif
3410 			if(watches[0].on)
3411 			{
3412 				// copy the memory used by each active watch
3413 				for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
3414 				{
3415 					if(watches[i].on)
3416 					{
3417 						int address = watches[i].address - 0x7E0000;
3418 						const uint8* source;
3419 						if(address < 0x20000)
3420 							source = Memory.RAM + address ;
3421 						else if(address < 0x30000)
3422 							source = Memory.SRAM + address  - 0x20000;
3423 						else
3424 							source = Memory.FillRAM + address  - 0x30000;
3425 
3426 						CopyMemory(Cheat.CWatchRAM + address, source, watches[i].size);
3427 					}
3428 				}
3429 			}
3430 			if(cheatSearchHWND)
3431 			{
3432 				if(timeGetTime() - lastTime >= 100)
3433 				{
3434 					SendMessage(cheatSearchHWND, WM_COMMAND, (WPARAM)(IDC_REFRESHLIST),(LPARAM)(NULL));
3435 					lastTime = timeGetTime();
3436 				}
3437 			}
3438 
3439 			// the following is a hack to allow frametimes greater than 100ms,
3440 			// without affecting the responsiveness of the GUI
3441 			BOOL run_loop=false;
3442 			do_frame_adjust=false;
3443 			if (Settings.TurboMode || Settings.FrameAdvance || Settings.SkipFrames != AUTO_FRAMERATE
3444 #ifdef NETPLAY_SUPPORT
3445 			|| Settings.NetPlay
3446 #endif
3447 			)
3448 			{
3449 				run_loop=true;
3450 			}
3451 			else
3452 			{
3453 				LONG prev;
3454 				BOOL success;
3455 				if ((success = ReleaseSemaphore (GUI.FrameTimerSemaphore, 1, &prev)) &&
3456 					prev == 0)
3457 				{
3458 					WaitForSingleObject (GUI.FrameTimerSemaphore, 0);
3459 					if (WaitForSingleObject (GUI.FrameTimerSemaphore, 100) == WAIT_OBJECT_0)
3460 					{
3461 						run_loop=true;
3462 					}
3463 				}
3464 				else
3465 				{
3466 					if (success)
3467 						WaitForSingleObject (GUI.FrameTimerSemaphore, 0);
3468 					WaitForSingleObject (GUI.FrameTimerSemaphore, 0);
3469 
3470 					run_loop=true;
3471 					do_frame_adjust=true;
3472 				}
3473 			}
3474 
3475 
3476 			if(Settings.FrameAdvance)
3477 			{
3478 				if(GFX.InfoStringTimeout > 4)
3479 					GFX.InfoStringTimeout = 4;
3480 
3481 				if(!GUI.FASkipsNonInput)
3482 					Settings.FrameAdvance = false;
3483 			}
3484 			if(GUI.FrameAdvanceJustPressed)
3485 				GUI.FrameAdvanceJustPressed--;
3486 
3487 			if(run_loop)
3488 			{
3489 				ProcessInput();
3490 
3491                 if(GUI.rewindBufferSize
3492 #ifdef NETPLAY_SUPPORT
3493                     &&!Settings.NetPlay
3494 #endif
3495                     ) {
3496                     if(Settings.Rewinding) {
3497                         Settings.Rewinding = stateMan.pop();
3498                     } else {
3499                         if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0)
3500                             stateMan.push();
3501                     }
3502                 }
3503 
3504 				S9xMainLoop();
3505 				GUI.FrameCount++;
3506 			}
3507 
3508 #ifdef NETPLAY_SUPPORT
3509         }
3510 #endif
3511         if (CPU.Flags & DEBUG_MODE_FLAG)
3512         {
3513             Settings.Paused = TRUE;
3514             Settings.FrameAdvance = false;
3515             CPU.Flags &= ~DEBUG_MODE_FLAG;
3516         }
3517         if (GUI.CursorTimer)
3518         {
3519             if (--GUI.CursorTimer == 0)
3520             {
3521                 if (GUI.ControllerOption != SNES_SUPERSCOPE && GUI.ControllerOption != SNES_JUSTIFIER && GUI.ControllerOption != SNES_JUSTIFIER_2 && GUI.ControllerOption != SNES_MACSRIFLE)
3522                     SetCursor (NULL);
3523             }
3524         }
3525     }
3526 
3527 loop_exit:
3528 
3529 	Settings.StopEmulation = TRUE;
3530 
3531 	// stop sound playback
3532 	CloseSoundDevice();
3533 
3534     if (GUI.hHotkeyTimer)
3535         timeKillEvent (GUI.hHotkeyTimer);
3536 
3537     if( GUI.hFrameTimer)
3538     {
3539         timeKillEvent (GUI.hFrameTimer);
3540         timeEndPeriod (wSoundTimerRes);
3541     }
3542 
3543     if (!Settings.StopEmulation)
3544     {
3545         Memory.SaveSRAM (S9xGetFilename (".srm", SRAM_DIR));
3546         S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
3547     }
3548     //if (!VOODOO_MODE && !GUI.FullScreen)
3549     //    GetWindowRect (GUI.hWnd, &GUI.window_size);
3550 
3551 
3552 	// this goes here, because the avi
3553 	// recording might have messed with
3554 	// the auto frame skip setting
3555 	// (it needs to come before WinSave)
3556 	DoAVIClose(0);
3557 
3558 	S9xMovieShutdown (); // must happen before saving config
3559 
3560 	WinUnlockConfigFile ();
3561     WinSaveConfigFile ();
3562 	WinCleanupConfigData();
3563 
3564 	Memory.Deinit();
3565 
3566 	ClearExts();
3567 
3568 	DeInitRenderFilters();
3569 
3570 	S9xGraphicsDeinit();
3571 	S9xDeinitAPU();
3572 	WinDeleteRecentGamesList ();
3573 	DeinitS9x();
3574 
3575 	return msg.wParam;
3576 }
3577 
FreezeUnfreezeDialog(bool8 freeze)3578 void FreezeUnfreezeDialog(bool8 freeze)
3579 {
3580 	if (Settings.StopEmulation)
3581 		return;
3582 
3583     TCHAR filename[MAX_PATH];
3584     OPENFILENAME ofn;
3585 
3586     *filename = TEXT('\0');
3587     memset((LPVOID)&ofn, 0, sizeof(OPENFILENAME));
3588 
3589     ofn.lStructSize = sizeof(OPENFILENAME);
3590     ofn.hwndOwner = GUI.hWnd;
3591     ofn.lpstrFilter = TEXT("State files\0*.state;*.frz;*.0*\0All Files\0*.*\0\0");
3592     ofn.lpstrFile = filename;
3593     ofn.lpstrInitialDir = S9xGetDirectoryT(SNAPSHOT_DIR);
3594     ofn.lpstrTitle = TEXT("Select State");
3595     ofn.lpstrDefExt = TEXT("state");
3596     ofn.nMaxFile = MAX_PATH;
3597 
3598     if (freeze) {
3599         ofn.Flags = OFN_OVERWRITEPROMPT;
3600         if (GetSaveFileName(&ofn)) {
3601             FreezeUnfreeze(_tToChar(ofn.lpstrFile), freeze);
3602         }
3603     } else {
3604         ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
3605         if (GetOpenFileName(&ofn)) {
3606             FreezeUnfreeze(_tToChar(ofn.lpstrFile), freeze);
3607         }
3608     }
3609 }
3610 
FreezeUnfreezeSlot(int slot,bool8 freeze)3611 void FreezeUnfreezeSlot(int slot, bool8 freeze)
3612 {
3613     char filename[_MAX_PATH + 1];
3614     char ext[_MAX_EXT + 1];
3615 
3616 	if (slot == -1)
3617 		strcpy(ext, ".oops");
3618 	else
3619 		snprintf(ext, _MAX_EXT, ".%03d", slot);
3620     strcpy(filename, S9xGetFilename(ext, SNAPSHOT_DIR));
3621 
3622     FreezeUnfreeze(filename, freeze);
3623 }
3624 
FreezeUnfreeze(const char * filename,bool8 freeze)3625 void FreezeUnfreeze (const char *filename, bool8 freeze)
3626 {
3627 #ifdef NETPLAY_SUPPORT
3628     if (!freeze && Settings.NetPlay && !Settings.NetPlayServer)
3629     {
3630         S9xMessage (S9X_INFO, S9X_NETPLAY_NOT_SERVER,
3631 			"Only the server is allowed to load freeze files.");
3632         return;
3633     }
3634 #endif
3635 
3636 	if (GUI.ConfirmSaveLoad)
3637 	{
3638 		std::string msg, title;
3639 		if (freeze)
3640 		{
3641 			msg = "Are you sure you want to SAVE to\n";
3642 			title = "Confirm SAVE";
3643 		}
3644 		else
3645 		{
3646 			msg = "Are you sure you want to LOAD from\n";
3647 			title = "Confirm LOAD";
3648 		}
3649 		msg += filename;
3650 		int res = MessageBox(GUI.hWnd, _tFromChar(msg.c_str()), _tFromChar(title.c_str()), MB_YESNO | MB_ICONQUESTION);
3651 		if (res != IDYES)
3652 			return;
3653 	}
3654 
3655     S9xSetPause (PAUSE_FREEZE_FILE);
3656 
3657     if (freeze)
3658 	{
3659 //		extern bool diagnostic_freezing;
3660 //		if(GetAsyncKeyState('Q') && GetAsyncKeyState('W') && GetAsyncKeyState('E') && GetAsyncKeyState('R'))
3661 //		{
3662 //			diagnostic_freezing = true;
3663 //		}
3664         S9xFreezeGame (filename);
3665 //
3666 //		diagnostic_freezing = false;
3667 	}
3668     else
3669     {
3670 
3671         if (S9xUnfreezeGame (filename))
3672         {
3673 //	        S9xMessage (S9X_INFO, S9X_FREEZE_FILE_INFO, S9xBasename (filename));
3674 #ifdef NETPLAY_SUPPORT
3675             S9xNPServerQueueSendingFreezeFile (filename);
3676 #endif
3677 //            UpdateBackBuffer();
3678         }
3679 
3680 		// fix next frame advance after loading non-skipping state from a skipping state
3681 			skipNextFrameStop = true;
3682     }
3683 
3684     S9xClearPause (PAUSE_FREEZE_FILE);
3685 }
3686 
CheckDirectoryIsWritable(const char * filename)3687 void CheckDirectoryIsWritable (const char *filename)
3688 {
3689     FILE *fs = fopen (filename, "w+");
3690 
3691     if (fs == NULL)
3692 	MessageBox (GUI.hWnd, TEXT("The folder where Snes9x saves emulated save RAM files and\ngame save positions (freeze files) is currently set to a\nread-only folder.\n\nIf you do not change the game save folder, Snes9x will be\nunable to save your progress in this game. Change the folder\nfrom the Settings Dialog available from the Options menu.\n\nThe default save folder is called Saves, if no value is set.\n"),
3693 							 TEXT("Snes9x: Unable to save file warning"),
3694 							 MB_OK | MB_ICONINFORMATION);
3695     else
3696     {
3697         fclose (fs);
3698         remove (filename);
3699     }
3700 }
3701 
CheckMenuStates()3702 static void CheckMenuStates ()
3703 {
3704     MENUITEMINFO mii;
3705     unsigned int i;
3706 
3707     memset( &mii, 0, sizeof( mii));
3708     mii.cbSize = sizeof( mii);
3709     mii.fMask = MIIM_STATE;
3710 
3711 	mii.fState = (GUI.FullScreen||GUI.EmulatedFullscreen) ? MFS_CHECKED : MFS_UNCHECKED;
3712     SetMenuItemInfo (GUI.hMenu, ID_WINDOW_FULLSCREEN, FALSE, &mii);
3713 
3714 	mii.fState = GUI.Stretch ? MFS_CHECKED : MFS_UNCHECKED;
3715     SetMenuItemInfo (GUI.hMenu, ID_WINDOW_STRETCH, FALSE, &mii);
3716 
3717 	mii.fState = GUI.Stretch ? (GUI.AspectRatio ? MFS_CHECKED : MFS_UNCHECKED) : MFS_CHECKED|MFS_DISABLED;
3718     SetMenuItemInfo (GUI.hMenu, ID_WINDOW_ASPECTRATIO, FALSE, &mii);
3719 
3720 	mii.fState = Settings.BilinearFilter ? MFS_CHECKED : MFS_UNCHECKED;
3721 	if(!GUI.Stretch)
3722 		mii.fState |= MFS_DISABLED;
3723     SetMenuItemInfo (GUI.hMenu, ID_WINDOW_BILINEAR, FALSE, &mii);
3724 
3725 	mii.fState = Settings.DisplayFrameRate ? MFS_CHECKED : MFS_UNCHECKED;
3726     SetMenuItemInfo (GUI.hMenu, ID_VIDEO_SHOWFRAMERATE, FALSE, &mii);
3727 
3728 	mii.fState = (Settings.Paused && !Settings.StopEmulation) ? MFS_CHECKED : MFS_UNCHECKED;
3729     SetMenuItemInfo (GUI.hMenu, ID_FILE_PAUSE, FALSE, &mii);
3730 
3731 	mii.fState = (GUI.InactivePause) ? MFS_CHECKED : MFS_UNCHECKED;
3732     SetMenuItemInfo (GUI.hMenu, ID_EMULATION_PAUSEWHENINACTIVE, FALSE, &mii);
3733 
3734     mii.fState = MFS_UNCHECKED;
3735     if (Settings.StopEmulation)
3736         mii.fState |= MFS_DISABLED;
3737 	SetMenuItemInfo (GUI.hMenu, ID_FILE_SAVE_SPC_DATA, FALSE, &mii);
3738     SetMenuItemInfo (GUI.hMenu, ID_FILE_SAVE_SRAM_DATA, FALSE, &mii);
3739 
3740 	for(int i = ID_FILE_SAVE0; i <= ID_FILE_SAVE_FILE; i++)
3741 		SetMenuItemInfo (GUI.hMenu, i, FALSE, &mii);
3742 
3743 	for (int i = ID_FILE_LOAD0; i <= ID_FILE_LOAD_FILE; i++)
3744 		SetMenuItemInfo(GUI.hMenu, i, FALSE, &mii);
3745 
3746     SetMenuItemInfo (GUI.hMenu, ID_FILE_RESET, FALSE, &mii);
3747     SetMenuItemInfo (GUI.hMenu, ID_CHEAT_ENTER, FALSE, &mii);
3748     SetMenuItemInfo (GUI.hMenu, ID_CHEAT_SEARCH_MODAL, FALSE, &mii);
3749 	SetMenuItemInfo (GUI.hMenu, IDM_ROM_INFO, FALSE, &mii);
3750 
3751 	if (GUI.FullScreen)
3752         mii.fState |= MFS_DISABLED;
3753     SetMenuItemInfo (GUI.hMenu, ID_CHEAT_SEARCH, FALSE, &mii);
3754 
3755 #ifdef NETPLAY_SUPPORT
3756     if (Settings.NetPlay && !Settings.NetPlayServer)
3757         mii.fState = MFS_DISABLED;
3758     else
3759         mii.fState = Settings.NetPlayServer ? MFS_CHECKED : MFS_UNCHECKED;
3760     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_SERVER, FALSE, &mii);
3761 
3762     mii.fState = Settings.NetPlay && !Settings.NetPlayServer ? 0 : MFS_DISABLED;
3763     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_DISCONNECT, FALSE, &mii);
3764 
3765     mii.fState = Settings.NetPlay || Settings.NetPlayServer ? MFS_DISABLED : 0;
3766     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_CONNECT, FALSE, &mii);
3767 
3768     mii.fState = NPServer.SendROMImageOnConnect ? MFS_CHECKED : MFS_UNCHECKED;
3769     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_SEND_ROM_ON_CONNECT, FALSE, &mii);
3770 
3771     mii.fState = NPServer.SyncByReset ? MFS_CHECKED : MFS_UNCHECKED;
3772     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_SYNC_BY_RESET, FALSE, &mii);
3773 
3774     mii.fState = Settings.NetPlayServer ? 0 : MFS_DISABLED;
3775     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_SYNC, FALSE, &mii);
3776     SetMenuItemInfo (GUI.hMenu, ID_NETPLAY_ROM, FALSE, &mii);
3777 #endif
3778 
3779     mii.fState = Settings.ApplyCheats ? MFS_CHECKED : MFS_UNCHECKED;
3780     if (Settings.StopEmulation)
3781         mii.fState |= MFS_DISABLED;
3782     SetMenuItemInfo( GUI.hMenu, ID_CHEAT_APPLY, FALSE, &mii);
3783 
3784     mii.fState = MFS_UNCHECKED;
3785 	if (GUI.AVIOut)
3786         mii.fState |= MFS_DISABLED;
3787     SetMenuItemInfo (GUI.hMenu, ID_SOUND_OPTIONS, FALSE, &mii);
3788 
3789     SetMenuItemInfo (GUI.hMenu, ID_SOUND_NOSOUND, FALSE, &mii);
3790     for (i = 0; i < COUNT(SoundRates); i++)
3791         SetMenuItemInfo (GUI.hMenu, SoundRates[i].ident, FALSE, &mii);
3792 
3793     if (Settings.SoundPlaybackRate == 0 || GUI.Mute)
3794         mii.fState |= MFS_DISABLED;
3795 
3796     SetMenuItemInfo (GUI.hMenu, ID_SOUND_SYNC, FALSE, &mii);
3797     SetMenuItemInfo (GUI.hMenu, ID_SOUND_INTERPOLATED, FALSE, &mii);
3798 
3799     SetMenuItemInfo (GUI.hMenu, ID_SOUND_16MS, FALSE, &mii);
3800     SetMenuItemInfo (GUI.hMenu, ID_SOUND_32MS, FALSE, &mii);
3801     SetMenuItemInfo (GUI.hMenu, ID_SOUND_48MS, FALSE, &mii);
3802     SetMenuItemInfo (GUI.hMenu, ID_SOUND_64MS, FALSE, &mii);
3803     SetMenuItemInfo (GUI.hMenu, ID_SOUND_80MS, FALSE, &mii);
3804     SetMenuItemInfo (GUI.hMenu, ID_SOUND_96MS, FALSE, &mii);
3805     SetMenuItemInfo (GUI.hMenu, ID_SOUND_112MS, FALSE, &mii);
3806 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_128MS, FALSE, &mii);
3807 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_144MS, FALSE, &mii);
3808 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_160MS, FALSE, &mii);
3809 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_176MS, FALSE, &mii);
3810 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_192MS, FALSE, &mii);
3811 	SetMenuItemInfo (GUI.hMenu, ID_SOUND_208MS, FALSE, &mii);
3812 
3813     mii.fState = MFS_CHECKED;
3814 	if (GUI.AVIOut)
3815         mii.fState |= MFS_DISABLED;
3816 
3817     if (Settings.SoundPlaybackRate == 0 || GUI.Mute )
3818         SetMenuItemInfo (GUI.hMenu, ID_SOUND_NOSOUND, FALSE, &mii);
3819     else
3820     {
3821         for (i = 0; i < COUNT(SoundRates); i++)
3822         {
3823             if (SoundRates [i].rate == Settings.SoundPlaybackRate)
3824             {
3825                 SetMenuItemInfo (GUI.hMenu, SoundRates[i].ident, FALSE, &mii);
3826                 break;
3827             }
3828         }
3829     }
3830     if (Settings.SoundPlaybackRate == 0 || GUI.Mute)
3831         mii.fState |= MFS_DISABLED;
3832 
3833 	int id;
3834 	switch (GUI.SoundBufferSize)
3835     {
3836 	case 16:  id = ID_SOUND_16MS; break;
3837 	case 32:  id = ID_SOUND_32MS; break;
3838 	case 48:  id = ID_SOUND_48MS; break;
3839 	case 64:  id = ID_SOUND_64MS; break;
3840 	case 80:  id = ID_SOUND_80MS; break;
3841 	case 96:  id = ID_SOUND_96MS; break;
3842 	case 112: id = ID_SOUND_112MS; break;
3843 	case 128: id = ID_SOUND_128MS; break;
3844 	case 144: id = ID_SOUND_144MS; break;
3845 	case 160: id = ID_SOUND_160MS; break;
3846 	case 176: id = ID_SOUND_176MS; break;
3847 	case 192: id = ID_SOUND_192MS; break;
3848 	case 208: id = ID_SOUND_208MS; break;
3849     }
3850     SetMenuItemInfo (GUI.hMenu, id, FALSE, &mii);
3851 
3852     if (Settings.SoundSync)
3853         SetMenuItemInfo (GUI.hMenu, ID_SOUND_SYNC, FALSE, &mii);
3854 
3855 #ifdef DEBUGGER
3856     mii.fState = (CPU.Flags & TRACE_FLAG) ? MFS_CHECKED : MFS_UNCHECKED;
3857     SetMenuItemInfo (GUI.hMenu, ID_DEBUG_TRACE, FALSE, &mii);
3858 	// TODO: reactivate once APU debugger works again
3859 	//mii.fState = (spc_core->debug_is_enabled()) ? MFS_CHECKED : MFS_UNCHECKED;
3860 	mii.fState = MFS_UNCHECKED;
3861     SetMenuItemInfo (GUI.hMenu, ID_DEBUG_APU_TRACE, FALSE, &mii);
3862 #endif
3863 
3864 	mii.fState = (!Settings.StopEmulation) ? MFS_ENABLED : MFS_DISABLED;
3865     SetMenuItemInfo (GUI.hMenu, ID_FILE_MOVIE_PLAY, FALSE, &mii);
3866     SetMenuItemInfo (GUI.hMenu, ID_FILE_MOVIE_RECORD, FALSE, &mii);
3867 
3868 	mii.fState = (S9xMovieActive () && !Settings.StopEmulation) ? MFS_ENABLED : MFS_DISABLED;
3869     SetMenuItemInfo (GUI.hMenu, ID_FILE_MOVIE_STOP, FALSE, &mii);
3870 
3871 	mii.fState = (GUI.SoundChannelEnable & (1 << 0)) ? MFS_CHECKED : MFS_UNCHECKED;
3872     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL1, FALSE, &mii);
3873 	mii.fState = (GUI.SoundChannelEnable & (1 << 1)) ? MFS_CHECKED : MFS_UNCHECKED;
3874     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL2, FALSE, &mii);
3875 	mii.fState = (GUI.SoundChannelEnable & (1 << 2)) ? MFS_CHECKED : MFS_UNCHECKED;
3876     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL3, FALSE, &mii);
3877 	mii.fState = (GUI.SoundChannelEnable & (1 << 3)) ? MFS_CHECKED : MFS_UNCHECKED;
3878     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL4, FALSE, &mii);
3879 	mii.fState = (GUI.SoundChannelEnable & (1 << 4)) ? MFS_CHECKED : MFS_UNCHECKED;
3880     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL5, FALSE, &mii);
3881 	mii.fState = (GUI.SoundChannelEnable & (1 << 5)) ? MFS_CHECKED : MFS_UNCHECKED;
3882     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL6, FALSE, &mii);
3883 	mii.fState = (GUI.SoundChannelEnable & (1 << 6)) ? MFS_CHECKED : MFS_UNCHECKED;
3884     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL7, FALSE, &mii);
3885 	mii.fState = (GUI.SoundChannelEnable & (1 << 7)) ? MFS_CHECKED : MFS_UNCHECKED;
3886     SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL8, FALSE, &mii);
3887 
3888 	mii.fState = GUI.BackgroundInput ? MFS_CHECKED : MFS_UNCHECKED;
3889 	SetMenuItemInfo (GUI.hMenu, ID_EMULATION_BACKGROUNDINPUT, FALSE, &mii);
3890 
3891     mii.fState = GUI.BackgroundKeyHotkeys ? MFS_CHECKED : MFS_UNCHECKED;
3892     if (!GUI.BackgroundInput)
3893         mii.fState |= MFS_DISABLED;
3894     SetMenuItemInfo(GUI.hMenu, ID_INPUT_BACKGROUNDKEYBOARDHOTKEYS, FALSE, &mii);
3895 
3896 	UINT validFlag;
3897     ControllerOptionsFromControllers();
3898 
3899 	validFlag = (((1<<SNES_JOYPAD) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3900     mii.fState = validFlag | (GUI.ControllerOption == SNES_JOYPAD ? MFS_CHECKED : MFS_UNCHECKED);
3901     SetMenuItemInfo (GUI.hMenu, IDM_SNES_JOYPAD, FALSE, &mii);
3902 
3903 	validFlag = (((1<<SNES_MULTIPLAYER5) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3904     mii.fState = validFlag | (GUI.ControllerOption == SNES_MULTIPLAYER5 ? MFS_CHECKED : MFS_UNCHECKED);
3905     SetMenuItemInfo (GUI.hMenu, IDM_ENABLE_MULTITAP, FALSE, &mii);
3906 
3907 	validFlag = (((1<<SNES_MULTIPLAYER8) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3908     mii.fState = validFlag | (GUI.ControllerOption == SNES_MULTIPLAYER8 ? MFS_CHECKED : MFS_UNCHECKED);
3909     SetMenuItemInfo (GUI.hMenu, IDM_MULTITAP8, FALSE, &mii);
3910 
3911 	validFlag = (((1<<SNES_MOUSE) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3912     mii.fState = validFlag | (GUI.ControllerOption == SNES_MOUSE ? MFS_CHECKED : MFS_UNCHECKED);
3913     SetMenuItemInfo (GUI.hMenu, IDM_MOUSE_TOGGLE, FALSE, &mii);
3914 
3915 	validFlag = (((1<<SNES_MOUSE_SWAPPED) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3916     mii.fState = validFlag | (GUI.ControllerOption == SNES_MOUSE_SWAPPED ? MFS_CHECKED : MFS_UNCHECKED);
3917     SetMenuItemInfo (GUI.hMenu, IDM_MOUSE_SWAPPED, FALSE, &mii);
3918 
3919 	validFlag = (((1<<SNES_SUPERSCOPE) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3920     mii.fState = validFlag | (GUI.ControllerOption == SNES_SUPERSCOPE ? MFS_CHECKED : MFS_UNCHECKED);
3921     SetMenuItemInfo (GUI.hMenu, IDM_SCOPE_TOGGLE, FALSE, &mii);
3922 
3923 	validFlag = (((1<<SNES_JUSTIFIER) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3924     mii.fState = validFlag | (GUI.ControllerOption == SNES_JUSTIFIER ? MFS_CHECKED : MFS_UNCHECKED);
3925     SetMenuItemInfo (GUI.hMenu, IDM_JUSTIFIER, FALSE, &mii);
3926 
3927 	validFlag = (((1<<SNES_JUSTIFIER_2) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3928     mii.fState = validFlag | (GUI.ControllerOption == SNES_JUSTIFIER_2 ? MFS_CHECKED : MFS_UNCHECKED);
3929     SetMenuItemInfo (GUI.hMenu, IDM_JUSTIFIERS, FALSE, &mii);
3930 
3931 	validFlag = (((1<<SNES_MACSRIFLE) & GUI.ValidControllerOptions) && (!S9xMovieActive() || !S9xMovieGetFrameCounter())) ? MFS_ENABLED : MFS_DISABLED;
3932     mii.fState = validFlag | (GUI.ControllerOption == SNES_MACSRIFLE ? MFS_CHECKED : MFS_UNCHECKED);
3933     SetMenuItemInfo (GUI.hMenu, IDM_MACSRIFLE_TOGGLE, FALSE, &mii);
3934 
3935 	mii.fState = !Settings.StopEmulation ? MFS_ENABLED : MFS_DISABLED;
3936 	SetMenuItemInfo (GUI.hMenu, ID_FILE_AVI_RECORDING, FALSE, &mii);
3937 
3938 	memset(&mii, 0, sizeof(mii));
3939 	mii.cbSize = sizeof(mii);
3940 	mii.fMask = MIIM_STRING;
3941 
3942 	mii.dwTypeData = !GUI.AVIOut ? TEXT("Start AVI Recording...") : TEXT("Stop AVI Recording");
3943 	SetMenuItemInfo (GUI.hMenu, ID_FILE_AVI_RECORDING, FALSE, &mii);
3944 }
3945 
ResetFrameTimer()3946 static void ResetFrameTimer ()
3947 {
3948     QueryPerformanceCounter((LARGE_INTEGER*)&PCStart);
3949 	PCStartTicks = timeGetTime()*1000;
3950     if (Settings.FrameTime == Settings.FrameTimeNTSC)
3951         PCFrameTime = PCFrameTimeNTSC;
3952     else if (Settings.FrameTime == Settings.FrameTimePAL)
3953         PCFrameTime = PCFrameTimePAL;
3954     else
3955         PCFrameTime = (__int64)((double)(PCBase * Settings.FrameTime) * .000001);
3956 
3957 	// determines if we can do sound sync
3958 	GUI.AllowSoundSync = Settings.PAL ? Settings.FrameTime == Settings.FrameTimePAL : Settings.FrameTime == Settings.FrameTimeNTSC;
3959 
3960     if (GUI.hFrameTimer)
3961         timeKillEvent (GUI.hFrameTimer);
3962 
3963     GUI.hFrameTimer = timeSetEvent ((Settings.FrameTime+500)/1000, 0, (LPTIMECALLBACK)FrameTimer, 0, TIME_PERIODIC);
3964 }
3965 
LoadROMPlain(const TCHAR * filename)3966 static bool LoadROMPlain(const TCHAR *filename)
3967 {
3968 	if (!filename || !*filename)
3969 		return (FALSE);
3970 	SetCurrentDirectory(S9xGetDirectoryT(ROM_DIR));
3971     if (Memory.LoadROM (_tToChar(filename)))
3972     {
3973 		S9xStartCheatSearch (&Cheat);
3974         ReInitSound();
3975 		ResetFrameTimer();
3976         return (TRUE);
3977     }
3978     return (FALSE);
3979 }
3980 
LoadROMMulti(const TCHAR * filename,const TCHAR * filename2)3981 static bool LoadROMMulti(const TCHAR *filename, const TCHAR *filename2)
3982 {
3983 	SetCurrentDirectory(S9xGetDirectoryT(ROM_DIR));
3984 	if (Memory.LoadMultiCart(_tToChar(filename), _tToChar(filename2)))
3985 	{
3986 		S9xStartCheatSearch(&Cheat);
3987 		ReInitSound();
3988 		ResetFrameTimer();
3989 		return (TRUE);
3990 	}
3991 	return (FALSE);
3992 }
3993 
LoadROM(const TCHAR * filename,const TCHAR * filename2)3994 static bool LoadROM(const TCHAR *filename, const TCHAR *filename2 /*= NULL*/) {
3995 
3996 #ifdef NETPLAY_SUPPORT
3997 	if (Settings.NetPlay && !Settings.NetPlayServer)
3998 	{
3999 		S9xMessage (S9X_INFO, S9X_NETPLAY_NOT_SERVER,
4000 			WINPROC_DISCONNECT);
4001 		return false;
4002 	}
4003 #endif
4004 
4005 	if (!Settings.StopEmulation) {
4006 		Memory.SaveSRAM (S9xGetFilename (".srm", SRAM_DIR));
4007 		S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
4008 	}
4009 
4010 	if(filename2)
4011 		Settings.StopEmulation = !LoadROMMulti(filename, filename2);
4012 	else
4013 		Settings.StopEmulation = !LoadROMPlain(filename);
4014 
4015 	if (!Settings.StopEmulation) {
4016 		bool8 loadedSRAM = Memory.LoadSRAM (S9xGetFilename (".srm", SRAM_DIR));
4017 		if(!loadedSRAM) // help migration from earlier Snes9x versions by checking ROM directory for savestates
4018 			Memory.LoadSRAM (S9xGetFilename (".srm", ROMFILENAME_DIR));
4019 		if(!filename2) // no recent for multi cart
4020 			S9xAddToRecentGames (filename);
4021 		CheckDirectoryIsWritable (S9xGetFilename (".---", SNAPSHOT_DIR));
4022 
4023 #ifdef NETPLAY_SUPPORT
4024 		if (NPServer.SendROMImageOnConnect)
4025 			S9xNPServerQueueSendingROMImage ();
4026 		else
4027 			S9xNPServerQueueSendingLoadROMRequest (Memory.ROMName);
4028 #endif
4029         if(GUI.rewindBufferSize)
4030 		{
4031 		#if !_WIN64
4032 			if (GUI.rewindBufferSize > 1024) GUI.rewindBufferSize = 1024;
4033 		#endif
4034             stateMan.init(GUI.rewindBufferSize * 1024 * 1024);
4035 		}
4036 	}
4037 
4038 	if(GUI.ControllerOption == SNES_SUPERSCOPE || GUI.ControllerOption == SNES_MACSRIFLE)
4039 		SetCursor (GUI.GunSight);
4040 	else {
4041 		SetCursor (GUI.Arrow);
4042 		GUI.CursorTimer = 60;
4043 	}
4044 	Settings.Paused = false;
4045     S9xRestoreWindowTitle();
4046 
4047 	return !Settings.StopEmulation;
4048 }
4049 
S9xLoadROMImage(const TCHAR * string)4050 bool8 S9xLoadROMImage (const TCHAR *string)
4051 {
4052     RestoreGUIDisplay ();
4053     TCHAR *buf = new TCHAR [200 + lstrlen (string)];
4054     _stprintf (buf, TEXT("The NetPlay server is requesting you load the following game:\n '%s'"),
4055 		string);
4056 
4057     MessageBox (GUI.hWnd, buf,
4058 		SNES9X_INFO,
4059 		MB_OK | MB_ICONINFORMATION);
4060 
4061     delete buf;
4062 
4063     TCHAR FileName [_MAX_PATH];
4064 
4065 	if(DoOpenRomDialog(FileName)) {
4066         return LoadROM(FileName);
4067     }
4068     else
4069         return (FALSE);
4070 
4071     return (TRUE);
4072 }
4073 
4074 /*****************************************************************************/
4075 #ifdef NETPLAY_SUPPORT
EnableServer(bool8 enable)4076 void EnableServer (bool8 enable)
4077 {
4078     if (enable != Settings.NetPlayServer)
4079     {
4080         if (Settings.NetPlay && !Settings.NetPlayServer)
4081         {
4082             Settings.NetPlay = FALSE;
4083             S9xNPDisconnect ();
4084         }
4085 
4086         if (enable)
4087         {
4088             S9xSetPause (PAUSE_NETPLAY_CONNECT);
4089             Settings.NetPlayServer = S9xNPStartServer (Settings.Port);
4090             Sleep (1000);
4091 
4092             if (!S9xNPConnectToServer ("127.0.0.1", Settings.Port,
4093 				Memory.ROMName))
4094             {
4095                 S9xClearPause (PAUSE_NETPLAY_CONNECT);
4096             }
4097         }
4098         else
4099         {
4100             Settings.NetPlayServer = FALSE;
4101             S9xNPStopServer ();
4102         }
4103     }
4104 }
4105 #endif
4106 
S9xAddToRecentGames(const TCHAR * filename)4107 void S9xAddToRecentGames (const TCHAR *filename)
4108 {
4109     // Make sure its not in the list already
4110     int i;
4111 	for(i = 0; i < MAX_RECENT_GAMES_LIST_SIZE; i++)
4112         if (!*GUI.RecentGames[i] || lstrcmp (filename, GUI.RecentGames[i]) == 0)
4113             break;
4114 
4115 	const bool underMax = (i < MAX_RECENT_GAMES_LIST_SIZE);
4116 	if(underMax && *GUI.RecentGames[i])
4117 	{
4118 		// It is in the list, move it to the head of the list.
4119 		TCHAR temp [MAX_PATH];
4120 		lstrcpy(temp, GUI.RecentGames[i]);
4121 		for(int j = i; j > 0; j--)
4122 			lstrcpy(GUI.RecentGames[j], GUI.RecentGames[j-1]);
4123 
4124 		lstrcpy(GUI.RecentGames[0], temp);
4125 	}
4126 	else
4127 	{
4128 		// Not in the list, add it.
4129 		if(underMax)
4130 			// Extend the recent game list length by 1.
4131 			memmove(&GUI.RecentGames[1], &GUI.RecentGames[0], MAX_PATH*i*sizeof(TCHAR));
4132 		else
4133 			// Throw the last item off the end of the list
4134 			memmove(&GUI.RecentGames[1], &GUI.RecentGames[0], MAX_PATH*(i-1)*sizeof(TCHAR));
4135 
4136 		lstrcpy(GUI.RecentGames[0], filename);
4137 
4138 		WinSaveConfigFile();
4139 	}
4140 
4141     S9xSetRecentGames();
4142 }
4143 
S9xRemoveFromRecentGames(int i)4144 void S9xRemoveFromRecentGames (int i)
4145 {
4146 	if (*GUI.RecentGames [i])
4147 	{
4148 		for (int j = i; j < MAX_RECENT_GAMES_LIST_SIZE-1; j++)
4149 			lstrcpy(GUI.RecentGames [j], GUI.RecentGames [j + 1]);
4150 		*GUI.RecentGames [MAX_RECENT_GAMES_LIST_SIZE-1] = TEXT('\0');
4151 
4152 		S9xSetRecentGames ();
4153 	}
4154 }
4155 
4156 #ifdef UNICODE
4157 
4158 /* OV2: We need dynamic binding to this function as it is not present in
4159    windows versions < vista. Since the jumplist is a win7 feature this
4160    is not a problem.
4161 */
4162 typedef HRESULT (STDAPICALLTYPE *SHCIFPN) (__in PCWSTR pszPath, __in_opt IBindCtx *pbc, __in REFIID riid, __deref_out void **ppv);
4163 
Win7_JLSetRecentGames(ICustomDestinationList * pcdl,IObjectArray * poaRemoved,UINT maxSlots)4164 HRESULT Win7_JLSetRecentGames(ICustomDestinationList *pcdl, IObjectArray *poaRemoved, UINT maxSlots)
4165 {
4166     IObjectCollection *poc;
4167 
4168 	HMODULE S32dll = GetModuleHandle(TEXT("shell32.dll"));
4169 	SHCIFPN SHCreateIFPN = (SHCIFPN)GetProcAddress(S32dll,"SHCreateItemFromParsingName");
4170 	if(!SHCreateIFPN) {
4171 		return S_FALSE;
4172 	}
4173 	HRESULT hr = CoCreateInstance
4174                     (CLSID_EnumerableObjectCollection,
4175                     NULL,
4176                     CLSCTX_INPROC_SERVER,
4177                     IID_PPV_ARGS(&poc));
4178     if (SUCCEEDED(hr)) {
4179 		UINT max_list = MIN(maxSlots,GUI.MaxRecentGames);
4180 		for (UINT i = 0; i < max_list && *GUI.RecentGames[i]; i++) {
4181             IShellItem *psi;
4182 			if(SUCCEEDED(SHCreateIFPN(GUI.RecentGames[i],NULL,IID_PPV_ARGS(&psi)))) {
4183                 hr = poc->AddObject(psi);
4184                 psi->Release();
4185             }
4186         }
4187 
4188         IObjectArray *poa;
4189         hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
4190         if (SUCCEEDED(hr)) {
4191             hr = pcdl->AppendCategory(TEXT("ROMs"), poa);
4192             poa->Release();
4193         }
4194         poc->Release();
4195     }
4196     return hr;
4197 }
4198 
Win7_CreateJumpList()4199 void Win7_CreateJumpList()
4200 {
4201     ICustomDestinationList *pcdl;
4202     HRESULT hr = CoCreateInstance(
4203                     CLSID_DestinationList,
4204                     NULL,
4205                     CLSCTX_INPROC_SERVER,
4206                     IID_PPV_ARGS(&pcdl));
4207     if (SUCCEEDED(hr)) {
4208         UINT maxSlots;
4209         IObjectArray *poaRemoved;
4210         hr = pcdl->BeginList(&maxSlots, IID_PPV_ARGS(&poaRemoved));
4211         if (SUCCEEDED(hr)) {
4212             hr = Win7_JLSetRecentGames(pcdl, poaRemoved,maxSlots);
4213             if (SUCCEEDED(hr)) {
4214                 hr = pcdl->CommitList();
4215             }
4216             poaRemoved->Release();
4217         }
4218 		pcdl->Release();
4219     }
4220 }
4221 #endif
4222 
S9xSetRecentGames()4223 void S9xSetRecentGames ()
4224 {
4225     HMENU file = GetSubMenu (GUI.hMenu, 0);
4226     if (file)
4227     {
4228         HMENU recent = GetSubMenu (file, 1);
4229         if (recent)
4230         {
4231             MENUITEMINFO mii;
4232             TCHAR name [256 + 10];
4233             int i;
4234 
4235             // Clear out the menu first
4236             for (i = GetMenuItemCount (recent) - 1; i >= 0; i--)
4237                 RemoveMenu (recent, i, MF_BYPOSITION);
4238 
4239             mii.cbSize = sizeof (mii);
4240             mii.fMask = MIIM_TYPE | MIIM_DATA | MIIM_STATE | MIIM_ID;
4241             mii.fType = MFT_STRING;
4242             mii.fState = MFS_UNCHECKED;
4243 
4244             for (i = 0; i < MAX_RECENT_GAMES_LIST_SIZE && i < GUI.MaxRecentGames && *GUI.RecentGames [i]; i++)
4245             {
4246                 // Build up a menu item string in the form:
4247                 // 1. <basename of ROM image name>
4248 
4249                 _stprintf (name, TEXT("&%c. "), i < 9 ? '1' + i : 'A' + i - 9);
4250 
4251 				// append the game title to name, with formatting modifications as necessary
4252 				{
4253 					TCHAR baseName [256];
4254 					lstrcpy (baseName, _tFromChar(S9xBasename (_tToChar(GUI.RecentGames [i]))));
4255 					int pos = lstrlen (name), baseNameLen = lstrlen (baseName);
4256 					for (int j = 0; j < baseNameLen ; j++)
4257 					{
4258 						TCHAR c = baseName [j];
4259 						name [pos++] = c;
4260 
4261 						// & is a special character in Windows menus,
4262 						// so we have to change & to && when copying over the game title
4263 						// otherwise "Pocky & Rocky (U).smc" will show up as "Pocky _Rocky (U).smc", for example
4264 						if(c == TEXT('&'))
4265 							name [pos++] = TEXT('&');
4266 					}
4267 					name [pos] = TEXT('\0');
4268 				}
4269 
4270 				mii.dwTypeData = name;
4271                 mii.cch = lstrlen (name) + 1;
4272                 mii.wID = 0xFF00 + i;
4273 
4274                 InsertMenuItem (recent, 0xFF00 + i, FALSE, &mii);
4275             }
4276 #ifdef UNICODE
4277 			Win7_CreateJumpList();
4278 #endif
4279         }
4280     }
4281 }
4282 
GetWindowMargins(HWND hwnd,UINT width)4283 RECT GetWindowMargins(HWND hwnd, UINT width)
4284 {
4285 	RECT rcMargins = {0,0,0,0};
4286 
4287 	AdjustWindowRectEx(&rcMargins, GetWindowStyle(hwnd), !GUI.HideMenu, GetWindowExStyle(hwnd));
4288 
4289 	rcMargins.left = abs(rcMargins.left);
4290 	rcMargins.top = abs(rcMargins.top);
4291 
4292 	if (!GUI.HideMenu) {
4293 		RECT rcTemp = {0,0,(LONG)width,0x7FFF}; // 0x7FFF="Infinite" height
4294 		SendMessage(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcTemp);
4295 
4296 		// Adjust our previous calculation to compensate for menu
4297 		// wrapping.
4298 		rcMargins.top = rcTemp.top;
4299 	}
4300 
4301 	return rcMargins;
4302 }
4303 
WinDeleteRecentGamesList()4304 void WinDeleteRecentGamesList ()
4305 {
4306 	for(int i=0;i<MAX_RECENT_GAMES_LIST_SIZE;i++)
4307 		GUI.RecentGames[i][0]=TEXT('\0');
4308 }
4309 
CreateToolTip(int toolID,HWND hDlg,TCHAR * pText)4310 BOOL CreateToolTip(int toolID, HWND hDlg, TCHAR* pText)
4311 {
4312     // toolID:  the resource ID of the control.
4313     // hDlg:    the handle of the dialog box.
4314     // pText:   the text that appears in the tooltip.
4315     // g_hInst: the global instance handle.
4316 
4317     if (!toolID || !hDlg || !pText)
4318     {
4319         return FALSE;
4320     }
4321     // Get the window of the tool.
4322     HWND hwndTool = GetDlgItem(hDlg, toolID);
4323 
4324     // Create the tooltip.
4325     HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
4326                               WS_POPUP |TTS_ALWAYSTIP | TTS_BALLOON,
4327                               CW_USEDEFAULT, CW_USEDEFAULT,
4328                               CW_USEDEFAULT, CW_USEDEFAULT,
4329                               hDlg, NULL,
4330                               g_hInst, NULL);
4331 
4332    if (!hwndTool || !hwndTip)
4333    {
4334        return FALSE;
4335    }
4336 
4337     // Associate the tooltip with the tool.
4338     TOOLINFO toolInfo = { 0 };
4339     toolInfo.cbSize = sizeof(toolInfo);
4340     toolInfo.hwnd = hDlg;
4341     toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
4342     toolInfo.uId = (UINT_PTR)hwndTool;
4343     toolInfo.lpszText = pText;
4344     SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
4345 
4346     return TRUE;
4347 }
4348 
UpdateAudioDeviceDropdown(HWND hCtl)4349 void UpdateAudioDeviceDropdown(HWND hCtl)
4350 {
4351     std::vector<std::wstring> device_list = GetAvailableSoundDevices();
4352 
4353     ComboBox_ResetContent(hCtl);
4354 
4355     int num_devices = device_list.size();
4356 
4357     if (!num_devices)
4358     {
4359         ComboBox_AddString(hCtl, _T("Default"));
4360     }
4361     else
4362     {
4363         for (int i = 0; i < num_devices; i++)
4364         {
4365             ComboBox_AddString(hCtl, device_list[i].c_str());
4366         }
4367     }
4368 }
4369 
DlgSoundConf(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)4370 INT_PTR CALLBACK DlgSoundConf(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
4371 {
4372 	HWND hTrackbar;
4373 	TCHAR valTxt[10];
4374 
4375     // temporary GUI state for restoring after switching devices (need to actually switch devices to get output devices)
4376     static int prevDriver;
4377 
4378 	switch(msg)
4379 	{
4380 	    case WM_INITDIALOG:
4381         {
4382             WinRefreshDisplay();
4383 
4384             prevDriver = GUI.SoundDriver;
4385 
4386             // FIXME: these strings should come from wlanguage.h
4387 
4388             CreateToolTip(IDC_INRATEEDIT, hDlg, TEXT("For each 'Input rate' samples generated by the SNES, 'Playback rate' samples will produced. If you experience crackling you can try to lower this setting."));
4389             CreateToolTip(IDC_INRATE, hDlg, TEXT("For each 'Input rate' samples generated by the SNES, 'Playback rate' samples will produced. If you experience crackling you can try to lower this setting."));
4390             CreateToolTip(IDC_DYNRATECONTROL, hDlg, TEXT("Try to dynamically adjust the input rate to never overflow or underflow the sound buffer."));
4391 
4392             HWND output_dropdown = GetDlgItem(hDlg, IDC_OUTPUT_DEVICE);
4393             UpdateAudioDeviceDropdown(output_dropdown);
4394             ComboBox_SetCurSel(output_dropdown, FindAudioDeviceIndex(GUI.AudioDevice));
4395 
4396             int pos;
4397             pos = SendDlgItemMessage(hDlg, IDC_DRIVER, CB_INSERTSTRING, -1, (LPARAM)TEXT("WaveOut"));
4398             SendDlgItemMessage(hDlg, IDC_DRIVER, CB_SETITEMDATA, pos, WIN_WAVEOUT_DRIVER);
4399             pos = SendDlgItemMessage(hDlg, IDC_DRIVER, CB_INSERTSTRING, -1, (LPARAM)TEXT("XAudio2"));
4400             SendDlgItemMessage(hDlg, IDC_DRIVER, CB_SETITEMDATA, pos, WIN_XAUDIO2_SOUND_DRIVER);
4401             SendDlgItemMessage(hDlg, IDC_DRIVER, CB_SETCURSEL, 0, 0);
4402             for (pos = 0; pos < SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETCOUNT, 0, 0); pos++) {
4403                 if (SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETITEMDATA, pos, 0) == GUI.SoundDriver) {
4404                     SendDlgItemMessage(hDlg, IDC_DRIVER, CB_SETCURSEL, pos, 0);
4405                     break;
4406                 }
4407             }
4408 
4409             if (WinGetAutomaticInputRate() < 1)
4410             {
4411                 EnableWindow(GetDlgItem(hDlg, IDC_AUTOMATICINPUTRATE), 0);
4412                 GUI.AutomaticInputRate = false;
4413             }
4414 
4415             EnableWindow(GetDlgItem(hDlg, IDC_INRATEEDIT), !GUI.AutomaticInputRate);
4416             EnableWindow(GetDlgItem(hDlg, IDC_INRATE), !GUI.AutomaticInputRate);
4417 
4418             SendDlgItemMessage(hDlg, IDC_INRATE, TBM_SETRANGE, TRUE, MAKELONG(0, 20));
4419             SendDlgItemMessage(hDlg, IDC_INRATE, TBM_SETPOS, TRUE, (Settings.SoundInputRate - 31100) / 50);
4420             SendDlgItemMessage(hDlg, IDC_INRATE, TBM_SETTICFREQ, 1, 0);
4421             _sntprintf(valTxt, 10, TEXT("%d"), Settings.SoundInputRate);
4422             Edit_SetText(GetDlgItem(hDlg, IDC_INRATEEDIT), valTxt);
4423 
4424             // regular volume
4425             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_REGULAR, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
4426             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_REGULAR, TBM_SETPOS, TRUE, 100 - GUI.VolumeRegular);
4427             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_REGULAR, TBM_SETTICFREQ, 10, 0);
4428             _sntprintf(valTxt, 10, TEXT("%d"), GUI.VolumeRegular);
4429             Edit_SetText(GetDlgItem(hDlg, IDC_EDIT_VOLUME_REGULAR), valTxt);
4430 
4431             // turbo volume
4432             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_TURBO, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
4433             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_TURBO, TBM_SETPOS, TRUE, 100 - GUI.VolumeTurbo);
4434             SendDlgItemMessage(hDlg, IDC_SLIDER_VOLUME_TURBO, TBM_SETTICFREQ, 10, 0);
4435             _sntprintf(valTxt, 10, TEXT("%d"), GUI.VolumeTurbo);
4436             Edit_SetText(GetDlgItem(hDlg, IDC_EDIT_VOLUME_TURBO), valTxt);
4437 
4438 
4439             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 0, (LPARAM)TEXT("8 KHz"));
4440             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 1, (LPARAM)TEXT("11 KHz"));
4441             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 2, (LPARAM)TEXT("16 KHz"));
4442             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 3, (LPARAM)TEXT("22 KHz"));
4443             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 4, (LPARAM)TEXT("30 KHz"));
4444             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 5, (LPARAM)TEXT("32 KHz"));
4445             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 6, (LPARAM)TEXT("35 KHz"));
4446             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 7, (LPARAM)TEXT("44 KHz"));
4447             SendDlgItemMessage(hDlg, IDC_RATE, CB_INSERTSTRING, 8, (LPARAM)TEXT("48 KHz"));
4448 
4449             int temp;
4450             switch (Settings.SoundPlaybackRate)
4451             {
4452                 case 8000:temp = 0; break;
4453                 case 11025:temp = 1; break;
4454                 case 16000:temp = 2; break;
4455                 case 22050:temp = 3; break;
4456                 case 30000:temp = 4; break;
4457                 case 0:
4458                 default:
4459                 case 32000:temp = 5; break;
4460                 case 35000:temp = 6; break;
4461                 case 44000:
4462                 case 44100:temp = 7; break;
4463                 case 48000:temp = 8; break;
4464             }
4465             SendDlgItemMessage(hDlg, IDC_RATE, CB_SETCURSEL, temp, 0);
4466 
4467             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 0, (LPARAM)TEXT("16 ms"));
4468             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 1, (LPARAM)TEXT("32 ms"));
4469             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 2, (LPARAM)TEXT("48 ms"));
4470             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 3, (LPARAM)TEXT("64 ms"));
4471             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 4, (LPARAM)TEXT("80 ms"));
4472             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 5, (LPARAM)TEXT("96 ms"));
4473             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 6, (LPARAM)TEXT("112 ms"));
4474             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 7, (LPARAM)TEXT("128 ms"));
4475             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 8, (LPARAM)TEXT("144 ms"));
4476             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 9, (LPARAM)TEXT("160 ms"));
4477             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 10, (LPARAM)TEXT("176 ms"));
4478             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 11, (LPARAM)TEXT("192 ms"));
4479             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_INSERTSTRING, 12, (LPARAM)TEXT("208 ms"));
4480 
4481             SendDlgItemMessage(hDlg, IDC_BUFLEN, CB_SETCURSEL, ((GUI.SoundBufferSize / 16) - 1), 0);
4482 
4483             if (Settings.DynamicRateControl)
4484                 SendDlgItemMessage(hDlg, IDC_DYNRATECONTROL, BM_SETCHECK, BST_CHECKED, 0);
4485 
4486             if (GUI.Mute)
4487                 SendDlgItemMessage(hDlg, IDC_MUTE, BM_SETCHECK, BST_CHECKED, 0);
4488             if (GUI.FAMute)
4489                 SendDlgItemMessage(hDlg, IDC_FAMT, BM_SETCHECK, BST_CHECKED, 0);
4490 
4491             if (Settings.SoundSync)
4492                 SendDlgItemMessage(hDlg, IDC_SYNC_TO_SOUND_CPU, BM_SETCHECK, BST_CHECKED, 0);
4493 
4494             if (GUI.AutomaticInputRate)
4495                 SendDlgItemMessage(hDlg, IDC_AUTOMATICINPUTRATE, BM_SETCHECK, BST_CHECKED, 0);
4496 
4497             return true;
4498         }
4499 		case WM_PAINT:
4500 		{
4501 		    PAINTSTRUCT ps;
4502 		    BeginPaint (hDlg, &ps);
4503 
4504 		    EndPaint (hDlg, &ps);
4505 		}
4506 		return true;
4507 		case WM_HSCROLL:
4508 		case WM_VSCROLL:
4509 		{
4510 			WORD loword_w = LOWORD(wParam);
4511 			if (loword_w == TB_THUMBPOSITION || loword_w == TB_THUMBTRACK || loword_w == TB_ENDTRACK) {
4512 				HWND trackHwnd = (HWND)lParam;
4513 				WORD scrollPos = SendMessage(trackHwnd, TBM_GETPOS, 0, 0);
4514 				int trackValue = 100 - scrollPos;
4515 				int editId = 0;
4516 				if (trackHwnd == GetDlgItem(hDlg, IDC_INRATE))
4517 				{
4518 					trackValue = 31100 + 50 * scrollPos;
4519 					editId = IDC_INRATEEDIT;
4520 				}
4521 				else if (trackHwnd == GetDlgItem(hDlg, IDC_SLIDER_VOLUME_REGULAR))
4522 				{
4523 					editId = IDC_EDIT_VOLUME_REGULAR;
4524 				}
4525 				else if (trackHwnd == GetDlgItem(hDlg, IDC_SLIDER_VOLUME_TURBO))
4526 				{
4527 					editId = IDC_EDIT_VOLUME_TURBO;
4528 				}
4529 				_sntprintf(valTxt, 10, TEXT("%d"), trackValue);
4530 				Edit_SetText(GetDlgItem(hDlg, editId), valTxt);
4531 				return true;
4532 			}
4533 		}
4534 		break;
4535 		case WM_COMMAND:
4536 			switch(LOWORD(wParam))
4537 			{
4538 				case IDOK:
4539 				{
4540 					GUI.SoundDriver=SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETITEMDATA,
4541 										SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETCURSEL, 0,0),0);
4542 					Settings.DynamicRateControl=IsDlgButtonChecked(hDlg, IDC_DYNRATECONTROL);
4543 					Settings.SoundSync=IsDlgButtonChecked(hDlg, IDC_SYNC_TO_SOUND_CPU);
4544 					GUI.Mute=IsDlgButtonChecked(hDlg, IDC_MUTE);
4545 					GUI.FAMute=IsDlgButtonChecked(hDlg, IDC_FAMT)!=0;
4546 
4547 
4548 					switch(SendDlgItemMessage(hDlg, IDC_RATE,CB_GETCURSEL,0,0))
4549 					{
4550 					case 0: Settings.SoundPlaybackRate=8000;	break;
4551 					case 1: Settings.SoundPlaybackRate=11025;	break;
4552 					case 2: Settings.SoundPlaybackRate=16000;	break;
4553 					case 3: Settings.SoundPlaybackRate=22050;	break;
4554 					case 4: Settings.SoundPlaybackRate=30000;	break;
4555 					case 5: Settings.SoundPlaybackRate=32000;	break;
4556 					case 6: Settings.SoundPlaybackRate=35000;	break;
4557 					case 7: Settings.SoundPlaybackRate=44100;	break;
4558 					case 8: Settings.SoundPlaybackRate=48000;	break;
4559 					}
4560 
4561 					GUI.SoundBufferSize=(16*(1+(SendDlgItemMessage(hDlg,IDC_BUFLEN,CB_GETCURSEL,0,0))));
4562 
4563 					Edit_GetText(GetDlgItem(hDlg,IDC_INRATEEDIT),valTxt,10);
4564 					int sliderVal=_tstoi(valTxt);
4565 					Settings.SoundInputRate = sliderVal>0?sliderVal:32000;
4566 
4567 					GUI.AutomaticInputRate = IsDlgButtonChecked(hDlg, IDC_AUTOMATICINPUTRATE);
4568 
4569 					// regular volume
4570 					Edit_GetText(GetDlgItem(hDlg, IDC_EDIT_VOLUME_REGULAR), valTxt, 10);
4571 					sliderVal = _tstoi(valTxt);
4572 					GUI.VolumeRegular = (sliderVal >= 0 && sliderVal <= 100) ? sliderVal : 100;
4573 
4574 					// turbo volume
4575 					Edit_GetText(GetDlgItem(hDlg, IDC_EDIT_VOLUME_TURBO), valTxt, 10);
4576 					sliderVal = _tstoi(valTxt);
4577 					GUI.VolumeTurbo = (sliderVal >= 0 && sliderVal <= 100) ? sliderVal : 100;
4578 
4579                     // output device
4580                     Edit_GetText(GetDlgItem(hDlg, IDC_OUTPUT_DEVICE), GUI.AudioDevice, MAX_AUDIO_NAME_LENGTH);
4581 
4582 					WinSaveConfigFile();
4583 
4584 					// already done in WinProc on return
4585 					// ReInitSound();
4586 
4587                     EndDialog(hDlg, 1);
4588                     return true;
4589 				}
4590 
4591 				case IDCANCEL:
4592                     GUI.SoundDriver = prevDriver;
4593 					EndDialog(hDlg, 1);
4594 					return true;
4595 
4596 				case IDC_AUTOMATICINPUTRATE:
4597                 {
4598                     bool temp_auto_input_rate = IsDlgButtonChecked(hDlg, IDC_AUTOMATICINPUTRATE);
4599                     EnableWindow(GetDlgItem(hDlg, IDC_INRATEEDIT), !temp_auto_input_rate);
4600                     EnableWindow(GetDlgItem(hDlg, IDC_INRATE), !temp_auto_input_rate);
4601 
4602                     if (temp_auto_input_rate)
4603                     {
4604                         int newrate = WinGetAutomaticInputRate();
4605                         if (newrate)
4606                         {
4607                             SendDlgItemMessage(hDlg, IDC_INRATE, TBM_SETPOS, TRUE, (newrate - 31100) / 50);
4608                             _sntprintf(valTxt, 10, TEXT("%d"), newrate);
4609                             Edit_SetText(GetDlgItem(hDlg, IDC_INRATEEDIT), valTxt);
4610                         }
4611                         else
4612                         {
4613                             SendDlgItemMessage(hDlg, IDC_AUTOMATICINPUTRATE, BM_SETCHECK, BST_UNCHECKED, 0);
4614                         }
4615                     }
4616 
4617                     return true;
4618                 }
4619 				case IDC_DRIVER:
4620 					if(CBN_SELCHANGE==HIWORD(wParam))
4621 					{
4622 						int driver = SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETITEMDATA,
4623 										SendDlgItemMessage(hDlg, IDC_DRIVER, CB_GETCURSEL, 0,0),0);
4624 
4625 						switch(driver) {
4626 							case WIN_WAVEOUT_DRIVER:
4627 								SendDlgItemMessage(hDlg,IDC_BUFLEN,CB_SETCURSEL,3,0);
4628 								break;
4629 							case WIN_XAUDIO2_SOUND_DRIVER:
4630 								SendDlgItemMessage(hDlg,IDC_BUFLEN,CB_SETCURSEL,3,0);
4631 								break;
4632 							default:
4633 								SendDlgItemMessage(hDlg,IDC_BUFLEN,CB_SETCURSEL,7,0);
4634 								break;
4635 						}
4636 
4637                         // get current selected device name, switch driver, try to select the same
4638                         HWND output_dropdown = GetDlgItem(hDlg, IDC_OUTPUT_DEVICE);
4639                         TCHAR selected_device[MAX_AUDIO_NAME_LENGTH];
4640                         Edit_GetText(output_dropdown, selected_device, MAX_AUDIO_NAME_LENGTH);
4641                         GUI.SoundDriver = driver;
4642                         ReInitSound();
4643                         UpdateAudioDeviceDropdown(output_dropdown);
4644                         ComboBox_SetCurSel(output_dropdown, FindAudioDeviceIndex(selected_device));
4645 						return true;
4646 					}
4647 					else return false;
4648 				case IDC_INRATEEDIT:
4649 					if(HIWORD(wParam)==EN_UPDATE) {
4650 						Edit_GetText(GetDlgItem(hDlg,IDC_INRATEEDIT),valTxt,10);
4651 						int sliderVal=_tstoi(valTxt);
4652 						SendDlgItemMessage(hDlg, IDC_INRATE, TBM_SETPOS,TRUE,(sliderVal - 31100)/50);
4653 					}
4654 					break;
4655 				default: return false;
4656 
4657 
4658 		}
4659 	}
4660 	return false;
4661 }
4662 
4663 //  SetSelProc
4664 //  Callback procedure to set the initial selection of the (folder) browser.
SetSelProc(HWND hWnd,UINT uMsg,LPARAM lParam,LPARAM lpData)4665 int CALLBACK SetSelProc( HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
4666 {
4667     if (uMsg==BFFM_INITIALIZED) {
4668         ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData );
4669     }
4670     return 0;
4671 }
4672 
StaticRAMBitSize()4673 const char *StaticRAMBitSize ()
4674 {
4675     static char tmp [20];
4676 
4677     sprintf (tmp, " (%dKbit)", 8*(Memory.SRAMMask + 1) / 1024);
4678     return (tmp);
4679 }
4680 
DlgInfoProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)4681 INT_PTR CALLBACK DlgInfoProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
4682 {
4683 	switch(msg)
4684 	{
4685 	case WM_INITDIALOG:
4686 		WinRefreshDisplay();
4687 		{
4688 			char temp[100];
4689 			char romtext[4096];
4690 			sprintf(romtext, "File: %s\r\nName: %s\r\n", Memory.ROMFilename, Memory.RawROMName);
4691 			sprintf(temp, "Speed: %02X/%s\r\nROM Map: %s\r\nType: %02x\r\n", Memory.ROMSpeed, ((Memory.ROMSpeed&0x10)!=0)?"FastROM":"SlowROM",(Memory.HiROM)?"HiROM":"LoROM",Memory.ROMType);
4692 			strcat(romtext, temp);
4693 			strcat(romtext, "Kart contents: ");
4694 			strcat(romtext, Memory.KartContents ());
4695 			strcat(romtext, "\r\nHeader ROM Size: ");
4696 			strcat(romtext, Memory.Size());
4697 			sprintf(temp, "\r\nCalculated ROM Size: %d Mbits", Memory.CalculatedSize/0x20000);
4698 			strcat(romtext, temp);
4699 
4700 			strcat(romtext, "\r\nSRAM size: ");
4701 			strcat(romtext, Memory.StaticRAMSize ());
4702 			strcat(romtext, StaticRAMBitSize());
4703 			strcat(romtext, "\r\nActual Checksum: ");
4704 			sprintf(temp, "%04X", Memory.CalculatedChecksum);
4705 			strcat(romtext, temp);
4706 			strcat(romtext, "\r\nHeader Checksum: ");
4707 			sprintf(temp, "%04X", Memory.ROMChecksum);
4708 			strcat(romtext, temp);
4709 			strcat(romtext, "\r\nHeader Checksum Compliment: ");
4710 			sprintf(temp, "%04X", Memory.ROMComplementChecksum);
4711 			strcat(romtext, temp);
4712 			strcat(romtext, "\r\nOutput: ");
4713 			if(Memory.ROMRegion>12||Memory.ROMRegion<2)
4714 				strcat(romtext, "NTSC 60Hz");
4715 			else strcat(romtext, "PAL 50Hz");
4716 
4717 			sprintf(temp, "\r\nCRC32:\t%08X", Memory.ROMCRC32);
4718 			strcat(romtext, temp);
4719 
4720 
4721 			strcat(romtext, "\r\nLicensee: ");
4722 
4723 			int tmp=Memory.CompanyId;
4724 			if(tmp==0)
4725 				tmp=(Memory.HiROM)?Memory.ROM[0x0FFDA]:Memory.ROM[0x7FDA];
4726 			switch(tmp)
4727 				//				switch(((Memory.ROMSpeed&0x0F)!=0)?Memory.ROM[0x0FFDA]:Memory.ROM[0x7FDA])
4728 				//				switch(atoi(Memory.CompanyId))
4729 				//				switch(((Memory.CompanyId[0]-'0')*16)+(Memory.CompanyId[1]-'0'))
4730 			{
4731 			case 0:strcat(romtext, "INVALID COMPANY");break;
4732 			case 1:strcat(romtext, "Nintendo");break;
4733 			case 2:strcat(romtext, "Ajinomoto");break;
4734 			case 3:strcat(romtext, "Imagineer-Zoom");break;
4735 			case 4:strcat(romtext, "Chris Gray Enterprises Inc.");break;
4736 			case 5:strcat(romtext, "Zamuse");break;
4737 			case 6:strcat(romtext, "Falcom");break;
4738 			case 7:strcat(romtext, NOTKNOWN "7");break;
4739 			case 8:strcat(romtext, "Capcom");break;
4740 			case 9:strcat(romtext, "HOT-B");break;
4741 			case 10:strcat(romtext, "Jaleco");break;
4742 			case 11:strcat(romtext, "Coconuts");break;
4743 			case 12:strcat(romtext, "Rage Software");break;
4744 			case 13:strcat(romtext, "Micronet"); break; //Acc. ZFE
4745 			case 14:strcat(romtext, "Technos");break;
4746 			case 15:strcat(romtext, "Mebio Software");break;
4747 			case 16:strcat(romtext, "SHOUEi System"); break; //Acc. ZFE
4748 			case 17:strcat(romtext, "Starfish");break; //UCON 64
4749 			case 18:strcat(romtext, "Gremlin Graphics");break;
4750 			case 19:strcat(romtext, "Electronic Arts");break;
4751 			case 20:strcat(romtext, "NCS / Masaya"); break; //Acc. ZFE
4752 			case 21:strcat(romtext, "COBRA Team");break;
4753 			case 22:strcat(romtext, "Human/Field");break;
4754 			case 23:strcat(romtext, "KOEI");break;
4755 			case 24:strcat(romtext, "Hudson Soft");break;
4756 			case 25:strcat(romtext, "Game Village");break;//uCON64
4757 			case 26:strcat(romtext, "Yanoman");break;
4758 			case 27:strcat(romtext, NOTKNOWN "27");break;
4759 			case 28:strcat(romtext, "Tecmo");break;
4760 			case 29:strcat(romtext, NOTKNOWN "29");break;
4761 			case 30:strcat(romtext, "Open System");break;
4762 			case 31:strcat(romtext, "Virgin Games");break;
4763 			case 32:strcat(romtext, "KSS");break;
4764 			case 33:strcat(romtext, "Sunsoft");break;
4765 			case 34:strcat(romtext, "POW");break;
4766 			case 35:strcat(romtext, "Micro World");break;
4767 			case 36:strcat(romtext, NOTKNOWN "36");break;
4768 			case 37:strcat(romtext, NOTKNOWN "37");break;
4769 			case 38:strcat(romtext, "Enix");break;
4770 			case 39:strcat(romtext, "Loriciel/Electro Brain");break;//uCON64
4771 			case 40:strcat(romtext, "Kemco");break;
4772 			case 41:strcat(romtext, "Seta Co.,Ltd.");break;
4773 			case 42:strcat(romtext, "Culture Brain"); break; //Acc. ZFE
4774 			case 43:strcat(romtext, "Irem Japan");break;//Irem? Gun Force J
4775 			case 44:strcat(romtext, "Pal Soft"); break; //Acc. ZFE
4776 			case 45:strcat(romtext, "Visit Co.,Ltd.");break;
4777 			case 46:strcat(romtext, "INTEC Inc."); break; //Acc. ZFE
4778 			case 47:strcat(romtext, "System Sacom Corp."); break; //Acc. ZFE
4779 			case 48:strcat(romtext, "Viacom New Media");break; //Zoop!
4780 			case 49:strcat(romtext, "Carrozzeria");break;
4781 			case 50:strcat(romtext, "Dynamic");break;
4782 			case 51:strcat(romtext, "Nintendo");break;
4783 			case 52:strcat(romtext, "Magifact");break;
4784 			case 53:strcat(romtext, "Hect");break;
4785 			case 54:strcat(romtext, NOTKNOWN "54");break;
4786 			case 55:strcat(romtext, NOTKNOWN "55");break;
4787 			case 56:strcat(romtext, "Capcom Europe");break;//Capcom? BOF2(E) MM7 (E)
4788 			case 57:strcat(romtext, "Accolade Europe");break;//Accolade?Bubsy 2 (E)
4789 			case 58:strcat(romtext, NOTKNOWN "58");break;
4790 			case 59:strcat(romtext, "Arcade Zone");break;//uCON64
4791 			case 60:strcat(romtext, "Empire Software");break;
4792 			case 61:strcat(romtext, "Loriciel");break;
4793 			case 62:strcat(romtext, "Gremlin Graphics"); break; //Acc. ZFE
4794 			case 63:strcat(romtext, NOTKNOWN "63");break;
4795 			case 64:strcat(romtext, "Seika Corp.");break;
4796 			case 65:strcat(romtext, "UBI Soft");break;
4797 			case 66:strcat(romtext, NOTKNOWN "66");break;
4798 			case 67:strcat(romtext, NOTKNOWN "67");break;
4799 			case 68:strcat(romtext, "LifeFitness Exertainment");break;//?? Exertainment Mountain Bike Rally (U).zip
4800 			case 69:strcat(romtext, NOTKNOWN "69");break;
4801 			case 70:strcat(romtext, "System 3");break;
4802 			case 71:strcat(romtext, "Spectrum Holobyte");break;
4803 			case 72:strcat(romtext, NOTKNOWN "72");break;
4804 			case 73:strcat(romtext, "Irem");break;
4805 			case 74:strcat(romtext, NOTKNOWN "74");break;
4806 			case 75:strcat(romtext, "Raya Systems/Sculptured Software");break;
4807 			case 76:strcat(romtext, "Renovation Products");break;
4808 			case 77:strcat(romtext, "Malibu Games/Black Pearl");break;
4809 			case 78:strcat(romtext, NOTKNOWN "78");break;
4810 			case 79:strcat(romtext, "U.S. Gold");break;
4811 			case 80:strcat(romtext, "Absolute Entertainment");break;
4812 			case 81:strcat(romtext, "Acclaim");break;
4813 			case 82:strcat(romtext, "Activision");break;
4814 			case 83:strcat(romtext, "American Sammy");break;
4815 			case 84:strcat(romtext, "GameTek");break;
4816 			case 85:strcat(romtext, "Hi Tech Expressions");break;
4817 			case 86:strcat(romtext, "LJN Toys");break;
4818 			case 87:strcat(romtext, NOTKNOWN "87");break;
4819 			case 88:strcat(romtext, NOTKNOWN "88");break;
4820 			case 89:strcat(romtext, NOTKNOWN "89");break;
4821 			case 90:strcat(romtext, "Mindscape");break;
4822 			case 91:strcat(romtext, "Romstar, Inc."); break; //Acc. ZFE
4823 			case 92:strcat(romtext, NOTKNOWN "92");break;
4824 			case 93:strcat(romtext, "Tradewest");break;
4825 			case 94:strcat(romtext, NOTKNOWN "94");break;
4826 			case 95:strcat(romtext, "American Softworks Corp.");break;
4827 			case 96:strcat(romtext, "Titus");break;
4828 			case 97:strcat(romtext, "Virgin Interactive Entertainment");break;
4829 			case 98:strcat(romtext, "Maxis");break;
4830 			case 99:strcat(romtext, "Origin/FCI/Pony Canyon");break;//uCON64
4831 			case 100:strcat(romtext, NOTKNOWN "100");break;
4832 			case 101:strcat(romtext, NOTKNOWN "101");break;
4833 			case 102:strcat(romtext, NOTKNOWN "102");break;
4834 			case 103:strcat(romtext, "Ocean");break;
4835 			case 104:strcat(romtext, NOTKNOWN "104");break;
4836 			case 105:strcat(romtext, "Electronic Arts");break;
4837 			case 106:strcat(romtext, NOTKNOWN "106");break;
4838 			case 107:strcat(romtext, "Laser Beam");break;
4839 			case 108:strcat(romtext, NOTKNOWN "108");break;
4840 			case 109:strcat(romtext, NOTKNOWN "109");break;
4841 			case 110:strcat(romtext, "Elite");break;
4842 			case 111:strcat(romtext, "Electro Brain");break;
4843 			case 112:strcat(romtext, "Infogrames");break;
4844 			case 113:strcat(romtext, "Interplay");break;
4845 			case 114:strcat(romtext, "LucasArts");break;
4846 			case 115:strcat(romtext, "Parker Brothers");break;
4847 			case 116:strcat(romtext, "Konami");break;//uCON64
4848 			case 117:strcat(romtext, "STORM");break;
4849 			case 118:strcat(romtext, NOTKNOWN "118");break;
4850 			case 119:strcat(romtext, NOTKNOWN "119");break;
4851 			case 120:strcat(romtext, "THQ Software");break;
4852 			case 121:strcat(romtext, "Accolade Inc.");break;
4853 			case 122:strcat(romtext, "Triffix Entertainment");break;
4854 			case 123:strcat(romtext, NOTKNOWN "123");break;
4855 			case 124:strcat(romtext, "Microprose");break;
4856 			case 125:strcat(romtext, NOTKNOWN "125");break;
4857 			case 126:strcat(romtext, NOTKNOWN "126");break;
4858 			case 127:strcat(romtext, "Kemco");break;
4859 			case 128:strcat(romtext, "Misawa");break;
4860 			case 129:strcat(romtext, "Teichio");break;
4861 			case 130:strcat(romtext, "Namco Ltd.");break;
4862 			case 131:strcat(romtext, "Lozc");break;
4863 			case 132:strcat(romtext, "Koei");break;
4864 			case 133:strcat(romtext, NOTKNOWN "133");break;
4865 			case 134:strcat(romtext, "Tokuma Shoten Intermedia");break;
4866 			case 135:strcat(romtext, "Tsukuda Original"); break; //Acc. ZFE
4867 			case 136:strcat(romtext, "DATAM-Polystar");break;
4868 			case 137:strcat(romtext, NOTKNOWN "137");break;
4869 			case 138:strcat(romtext, NOTKNOWN "138");break;
4870 			case 139:strcat(romtext, "Bullet-Proof Software");break;
4871 			case 140:strcat(romtext, "Vic Tokai");break;
4872 			case 141:strcat(romtext, NOTKNOWN "141");break;
4873 			case 142:strcat(romtext, "Character Soft");break;
4874 			case 143:strcat(romtext, "I\'\'Max");break;
4875 			case 144:strcat(romtext, "Takara");break;
4876 			case 145:strcat(romtext, "CHUN Soft");break;
4877 			case 146:strcat(romtext, "Video System Co., Ltd.");break;
4878 			case 147:strcat(romtext, "BEC");break;
4879 			case 148:strcat(romtext, NOTKNOWN "148");break;
4880 			case 149:strcat(romtext, "Varie");break;
4881 			case 150:strcat(romtext, "Yonezawa / S'Pal Corp."); break; //Acc. ZFE
4882 			case 151:strcat(romtext, "Kaneco");break;
4883 			case 152:strcat(romtext, NOTKNOWN "152");break;
4884 			case 153:strcat(romtext, "Pack in Video");break;
4885 			case 154:strcat(romtext, "Nichibutsu");break;
4886 			case 155:strcat(romtext, "TECMO");break;
4887 			case 156:strcat(romtext, "Imagineer Co.");break;
4888 			case 157:strcat(romtext, NOTKNOWN "157");break;
4889 			case 158:strcat(romtext, NOTKNOWN "158");break;
4890 			case 159:strcat(romtext, NOTKNOWN "159");break;
4891 			case 160:strcat(romtext, "Telenet");break;
4892 			case 161:strcat(romtext, "Hori"); break; //Acc. uCON64
4893 			case 162:strcat(romtext, NOTKNOWN "162");break;
4894 			case 163:strcat(romtext, NOTKNOWN "163");break;
4895 			case 164:strcat(romtext, "Konami");break;
4896 			case 165:strcat(romtext, "K.Amusement Leasing Co.");break;
4897 			case 166:strcat(romtext, NOTKNOWN "166");break;
4898 			case 167:strcat(romtext, "Takara");break;
4899 			case 168:strcat(romtext, NOTKNOWN "168");break;
4900 			case 169:strcat(romtext, "Technos Jap.");break;
4901 			case 170:strcat(romtext, "JVC");break;
4902 			case 171:strcat(romtext, NOTKNOWN "171");break;
4903 			case 172:strcat(romtext, "Toei Animation");break;
4904 			case 173:strcat(romtext, "Toho");break;
4905 			case 174:strcat(romtext, NOTKNOWN "174");break;
4906 			case 175:strcat(romtext, "Namco Ltd.");break;
4907 			case 176:strcat(romtext, "Media Rings Corp."); break; //Acc. ZFE
4908 			case 177:strcat(romtext, "ASCII Co. Activison");break;
4909 			case 178:strcat(romtext, "Bandai");break;
4910 			case 179:strcat(romtext, NOTKNOWN "179");break;
4911 			case 180:strcat(romtext, "Enix America");break;
4912 			case 181:strcat(romtext, NOTKNOWN "181");break;
4913 			case 182:strcat(romtext, "Halken");break;
4914 			case 183:strcat(romtext, NOTKNOWN "183");break;
4915 			case 184:strcat(romtext, NOTKNOWN "184");break;
4916 			case 185:strcat(romtext, NOTKNOWN "185");break;
4917 			case 186:strcat(romtext, "Culture Brain");break;
4918 			case 187:strcat(romtext, "Sunsoft");break;
4919 			case 188:strcat(romtext, "Toshiba EMI");break;
4920 			case 189:strcat(romtext, "Sony Imagesoft");break;
4921 			case 190:strcat(romtext, NOTKNOWN "190");break;
4922 			case 191:strcat(romtext, "Sammy");break;
4923 			case 192:strcat(romtext, "Taito");break;
4924 			case 193:strcat(romtext, NOTKNOWN "193");break;
4925 			case 194:strcat(romtext, "Kemco");break;
4926 			case 195:strcat(romtext, "Square");break;
4927 			case 196:strcat(romtext, "Tokuma Soft");break;
4928 			case 197:strcat(romtext, "Data East");break;
4929 			case 198:strcat(romtext, "Tonkin House");break;
4930 			case 199:strcat(romtext, NOTKNOWN "199");break;
4931 			case 200:strcat(romtext, "KOEI");break;
4932 			case 201:strcat(romtext, NOTKNOWN "201");break;
4933 			case 202:strcat(romtext, "Konami USA");break;
4934 			case 203:strcat(romtext, "NTVIC");break;
4935 			case 204:strcat(romtext, NOTKNOWN "204");break;
4936 			case 205:strcat(romtext, "Meldac");break;
4937 			case 206:strcat(romtext, "Pony Canyon");break;
4938 			case 207:strcat(romtext, "Sotsu Agency/Sunrise");break;
4939 			case 208:strcat(romtext, "Disco/Taito");break;
4940 			case 209:strcat(romtext, "Sofel");break;
4941 			case 210:strcat(romtext, "Quest Corp.");break;
4942 			case 211:strcat(romtext, "Sigma");break;
4943 			case 212:strcat(romtext, "Ask Kodansha Co., Ltd."); break; //Acc. ZFE
4944 			case 213:strcat(romtext, NOTKNOWN "213");break;
4945 			case 214:strcat(romtext, "Naxat");break;
4946 			case 215:strcat(romtext, NOTKNOWN "215");break;
4947 			case 216:strcat(romtext, "Capcom Co., Ltd.");break;
4948 			case 217:strcat(romtext, "Banpresto");break;
4949 			case 218:strcat(romtext, "Tomy");break;
4950 			case 219:strcat(romtext, "Acclaim");break;
4951 			case 220:strcat(romtext, NOTKNOWN "220");break;
4952 			case 221:strcat(romtext, "NCS");break;
4953 			case 222:strcat(romtext, "Human Entertainment");break;
4954 			case 223:strcat(romtext, "Altron");break;
4955 			case 224:strcat(romtext, "Jaleco");break;
4956 			case 225:strcat(romtext, NOTKNOWN "225");break;
4957 			case 226:strcat(romtext, "Yutaka");break;
4958 			case 227:strcat(romtext, NOTKNOWN "227");break;
4959 			case 228:strcat(romtext, "T&ESoft");break;
4960 			case 229:strcat(romtext, "EPOCH Co.,Ltd.");break;
4961 			case 230:strcat(romtext, NOTKNOWN "230");break;
4962 			case 231:strcat(romtext, "Athena");break;
4963 			case 232:strcat(romtext, "Asmik");break;
4964 			case 233:strcat(romtext, "Natsume");break;
4965 			case 234:strcat(romtext, "King Records");break;
4966 			case 235:strcat(romtext, "Atlus");break;
4967 			case 236:strcat(romtext, "Sony Music Entertainment");break;
4968 			case 237:strcat(romtext, NOTKNOWN "237");break;
4969 			case 238:strcat(romtext, "IGS");break;
4970 			case 239:strcat(romtext, NOTKNOWN "239");break;
4971 			case 240:strcat(romtext, NOTKNOWN "240");break;
4972 			case 241:strcat(romtext, "Motown Software");break;
4973 			case 242:strcat(romtext, "Left Field Entertainment");break;
4974 			case 243:strcat(romtext, "Beam Software");break;
4975 			case 244:strcat(romtext, "Tec Magik");break;
4976 			case 245:strcat(romtext, NOTKNOWN "245");break;
4977 			case 246:strcat(romtext, NOTKNOWN "246");break;
4978 			case 247:strcat(romtext, NOTKNOWN "247");break;
4979 			case 248:strcat(romtext, NOTKNOWN "248");break;
4980 			case 249:strcat(romtext, "Cybersoft");break;
4981 			case 250:strcat(romtext, NOTKNOWN "250");break;
4982 			case 251:strcat(romtext, "Psygnosis"); break; //Acc. ZFE
4983 			case 252:strcat(romtext, NOTKNOWN "252");break;
4984 			case 253:strcat(romtext, NOTKNOWN "253");break;
4985 			case 254:strcat(romtext, "Davidson"); break; //Acc. uCON64
4986 			case 255:strcat(romtext, NOTKNOWN "255");break;
4987 			default:strcat(romtext, NOTKNOWN);break;
4988 				}
4989 
4990 				strcat(romtext, "\r\nROM Version: ");
4991 				sprintf(temp, "1.%d", (Memory.HiROM)?Memory.ROM[0x0FFDB]:Memory.ROM[0x7FDB]);
4992 				strcat(romtext, temp);
4993 				strcat(romtext, "\r\nRegion: ");
4994 				switch(Memory.ROMRegion)
4995 				{
4996 				case 0:
4997 					strcat(romtext, "Japan");
4998 					break;
4999 				case 1:
5000 					strcat(romtext, "USA/Canada");
5001 					break;
5002 				case 2:
5003 					strcat(romtext, "Oceania, Europe, and Asia");
5004 					break;
5005 				case 3:
5006 					strcat(romtext, "Sweden");
5007 					break;
5008 				case 4:
5009 					strcat(romtext, "Finland");
5010 					break;
5011 				case 5:
5012 					strcat(romtext, "Denmark");
5013 					break;
5014 				case 6:
5015 					strcat(romtext, "France");
5016 					break;
5017 				case 7:
5018 					strcat(romtext, "Holland");
5019 					break;
5020 				case 8:
5021 					strcat(romtext, "Spain");
5022 					break;
5023 				case 9:
5024 					strcat(romtext, "Germany, Austria, and Switzerland");
5025 					break;
5026 				case 10:
5027 					strcat(romtext, "Italy");
5028 					break;
5029 				case 11:
5030 					strcat(romtext, "Hong Kong and China");
5031 					break;
5032 				case 12:
5033 					strcat(romtext, "Indonesia");
5034 					break;
5035 				case 13:
5036 					strcat(romtext, "South Korea");
5037 					break;
5038 				case 14:strcat(romtext, "Unknown region 14");break;
5039 				default:strcat(romtext, "Unknown region 15");break;
5040 				}
5041                 SendDlgItemMessage(hDlg, IDC_ROM_DATA, WM_SETTEXT, 0, (LPARAM)((TCHAR *)_tFromMS932(romtext)));
5042 				break;
5043 			}
5044 			case WM_CTLCOLORSTATIC:
5045 
5046 				if(GetDlgCtrlID((HWND)lParam)==IDC_ROM_DATA && GUI.InfoColor!=WIN32_WHITE)
5047 				{
5048 					SetTextColor((HDC)wParam, GUI.InfoColor);
5049 					SetBkColor((HDC)wParam, RGB(0,0,0));
5050 					return (INT_PTR)GetStockObject( BLACK_BRUSH );
5051 				}
5052 				break;
5053 			case WM_PAINT:
5054 				break;
5055 
5056 			case WM_COMMAND:
5057 				{
5058 					switch(LOWORD(wParam))
5059 					{
5060 					case IDOK:
5061 					case IDCANCEL:
5062 						EndDialog(hDlg, 0);
5063 						return true;
5064 						break;
5065 					default: break;
5066 					}
5067 				}
5068 			default:
5069 				break;
5070 	}
5071 	return FALSE;
5072 }
5073 
DlgAboutProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)5074 INT_PTR CALLBACK DlgAboutProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
5075 {
5076 
5077 	switch(msg)
5078 	{
5079 	case WM_INITDIALOG:
5080 		WinRefreshDisplay();
5081 		{
5082 			TCHAR buf[2048];//find better way of dealing.
5083 			_stprintf(buf,DISCLAIMER_TEXT,TEXT(VERSION));
5084 			SetDlgItemText(hDlg, IDC_DISCLAIMER, buf);
5085 			SetWindowText(hDlg, ABOUT_DIALOG_TITLE APP_NAME);
5086 		}
5087 		return true;
5088 	case WM_PAINT:
5089 		{
5090 		PAINTSTRUCT ps;
5091 		BeginPaint (hDlg, &ps);
5092 
5093 		EndPaint (hDlg, &ps);
5094 		}
5095 		return true;
5096 	case WM_COMMAND:
5097 		{
5098 			switch(LOWORD(wParam))
5099 			{
5100 			case IDOK:
5101 			case IDCANCEL:
5102 				EndDialog(hDlg, 0);
5103 				return true;
5104 				break;
5105 			default: return false; break;
5106 			}
5107 		}
5108 	default:return false;
5109 	}
5110 }
5111 
DlgEmulatorHacksProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)5112 INT_PTR CALLBACK DlgEmulatorHacksProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
5113 {
5114     UDACCEL accel = { 0, 10 };
5115     bool must_reset = 0;
5116 
5117     switch (msg)
5118     {
5119     case WM_INITDIALOG:
5120 
5121         SendDlgItemMessage(hDlg, IDC_SFX_CLOCK_SPEED_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)400, (short)50));
5122         SendDlgItemMessage(hDlg, IDC_SFX_CLOCK_SPEED_SPIN, UDM_SETPOS, 0, Settings.SuperFXClockMultiplier);
5123         SendDlgItemMessage(hDlg, IDC_SFX_CLOCK_SPEED_SPIN, UDM_SETACCEL, 1, (LPARAM)&accel);
5124 
5125         SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_ADDSTRING, 0, (LPARAM)TEXT("None"));
5126         SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_ADDSTRING, 0, (LPARAM)TEXT("Low"));
5127         SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_ADDSTRING, 0, (LPARAM)TEXT("Medium"));
5128         SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_ADDSTRING, 0, (LPARAM)TEXT("Max"));
5129         SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_SETCURSEL, Settings.OverclockMode, 0);
5130 
5131         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_ADDSTRING, 0, (LPARAM)TEXT("None"));
5132         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_ADDSTRING, 0, (LPARAM)TEXT("Linear"));
5133         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_ADDSTRING, 0, (LPARAM)TEXT("Gaussian (SNES Hardware)"));
5134         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_ADDSTRING, 0, (LPARAM)TEXT("Cubic"));
5135         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_ADDSTRING, 0, (LPARAM)TEXT("Sinc"));
5136         SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_SETCURSEL, Settings.InterpolationMethod, 0);
5137 
5138         CheckDlgButton(hDlg, IDC_INVALID_VRAM, !Settings.BlockInvalidVRAMAccessMaster);
5139         CheckDlgButton(hDlg, IDC_SEPARATE_ECHO_BUFFER, Settings.SeparateEchoBuffer);
5140         CheckDlgButton(hDlg, IDC_NO_SPRITE_LIMIT, Settings.MaxSpriteTilesPerLine == 128);
5141 
5142         return true;
5143         break;
5144 
5145     case WM_COMMAND:
5146 
5147         switch (LOWORD(wParam))
5148         {
5149         case IDOK:
5150             if (((Settings.BlockInvalidVRAMAccessMaster != !IsDlgButtonChecked(hDlg, IDC_INVALID_VRAM)) ||
5151                 (Settings.SeparateEchoBuffer != IsDlgButtonChecked(hDlg, IDC_SEPARATE_ECHO_BUFFER)))
5152                 && !Settings.StopEmulation)
5153             {
5154 
5155                 if (MessageBoxA(hDlg, "To make the requested changes, the game will need to be reset.", "Reset Required", MB_OKCANCEL) != IDOK)
5156                     return false;
5157                 must_reset = true;
5158             }
5159 
5160             Settings.SuperFXClockMultiplier = SendDlgItemMessage(hDlg, IDC_SFX_CLOCK_SPEED_SPIN, UDM_GETPOS, 0, 0);
5161             Settings.OverclockMode = SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_GETCURSEL, 0, 0);
5162             Settings.InterpolationMethod = SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_GETCURSEL, 0, 0);
5163             Settings.BlockInvalidVRAMAccessMaster = !IsDlgButtonChecked(hDlg, IDC_INVALID_VRAM);
5164             Settings.SeparateEchoBuffer = IsDlgButtonChecked(hDlg, IDC_SEPARATE_ECHO_BUFFER);
5165             Settings.MaxSpriteTilesPerLine = IsDlgButtonChecked(hDlg, IDC_NO_SPRITE_LIMIT) ? 128 : 34;
5166 
5167             switch (Settings.OverclockMode)
5168             {
5169             default:
5170             case 0:
5171                 Settings.OneClockCycle = 6;
5172                 Settings.OneSlowClockCycle = 8;
5173                 Settings.TwoClockCycles = 12;
5174                 break;
5175             case 1:
5176                 Settings.OneClockCycle = 6;
5177                 Settings.OneSlowClockCycle = 6;
5178                 Settings.TwoClockCycles = 12;
5179                 break;
5180             case 2:
5181                 Settings.OneClockCycle = 4;
5182                 Settings.OneSlowClockCycle = 6;
5183                 Settings.TwoClockCycles = 8;
5184                 break;
5185             case 3:
5186                 Settings.OneClockCycle = 3;
5187                 Settings.OneSlowClockCycle = 4;
5188                 Settings.TwoClockCycles = 6;
5189                 break;
5190             }
5191 
5192             EndDialog(hDlg, must_reset);
5193             return true;
5194 
5195         case IDCANCEL:
5196             EndDialog(hDlg, 0);
5197             return true;
5198 
5199 		case IDC_SET_DEFAULTS:
5200 			SendDlgItemMessage(hDlg, IDC_SFX_CLOCK_SPEED_SPIN, UDM_SETPOS, 0, 100);
5201 			SendDlgItemMessage(hDlg, IDC_CPU_OVERCLOCK, CB_SETCURSEL, 0, 0);
5202 			SendDlgItemMessage(hDlg, IDC_SOUND_INTERPOLATION, CB_SETCURSEL, 2, 0);
5203 			CheckDlgButton(hDlg, IDC_INVALID_VRAM, false);
5204 			CheckDlgButton(hDlg, IDC_SEPARATE_ECHO_BUFFER, false);
5205 			CheckDlgButton(hDlg, IDC_NO_SPRITE_LIMIT, false);
5206 			break;
5207         default:
5208             break;
5209         }
5210 
5211         return true;
5212         break;
5213 
5214     default:
5215         return false;
5216     }
5217 }
5218 
DlgEmulatorProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)5219 INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
5220 {
5221 	static TCHAR paths[10][MAX_PATH];
5222 	static int which = 0;
5223 	switch(msg)
5224 	{
5225 	case WM_INITDIALOG:
5226 		WinRefreshDisplay();
5227 		{
5228 			SetWindowText(hDlg, EMUSET_TITLE);
5229 			SetDlgItemText(hDlg, IDC_LABEL_FREEZE, EMUSET_LABEL_DIRECTORY);
5230 			SetDlgItemText(hDlg, IDOK, BUTTON_OK);
5231 			SetDlgItemText(hDlg, IDCANCEL, BUTTON_CANCEL);
5232 			SetDlgItemText(hDlg, IDC_LABEL_ASRAM, EMUSET_LABEL_ASRAM);
5233 			SetDlgItemText(hDlg, IDC_LABEL_ASRAM_TEXT, EMUSET_LABEL_ASRAM_TEXT);
5234 			SetDlgItemText(hDlg, IDC_LABEL_SMAX, EMUSET_LABEL_SMAX);
5235 			SetDlgItemText(hDlg, IDC_LABEL_SMAX_TEXT, EMUSET_LABEL_SMAX_TEXT);
5236 			SetDlgItemText(hDlg, IDC_LABEL_STURBO_TEXT, EMUSET_LABEL_STURBO_TEXT);
5237 			SetDlgItemText(hDlg, IDC_LABEL_STURBO, EMUSET_LABEL_STURBO);
5238 			SetDlgItemText(hDlg, IDC_BROWSE, EMUSET_BROWSE);
5239 			SetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, GUI.FreezeFileDir);
5240 			SetDlgItemText(hDlg, IDC_CONFIG_NAME_BOX, TEXT(S9X_CONF_FILE_NAME));
5241 			SendDlgItemMessage(hDlg, IDC_SRAM_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)99, (short)0));
5242 			SendDlgItemMessage(hDlg, IDC_SRAM_SPIN,UDM_SETPOS,0, Settings.AutoSaveDelay);
5243 			SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP, UDM_SETRANGE, 0, MAKELPARAM((short)59, (short)0));
5244 			SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP,UDM_SETPOS,0, Settings.AutoMaxSkipFrames);
5245 			SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_SETRANGE, 0, MAKELPARAM((short)600, (short)0));
5246 			SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP,UDM_SETPOS,0, Settings.TurboSkipFrames);
5247             SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)4000, (short)0));
5248             SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN,UDM_SETPOS,0, GUI.rewindBufferSize);
5249             SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)300, (short)1));
5250             SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN,UDM_SETPOS,0, GUI.rewindGranularity);
5251 			SendDlgItemMessage(hDlg, IDC_SFXSPEED_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)400, (short)50));
5252 			SendDlgItemMessage(hDlg, IDC_SFXSPEED_SPIN, UDM_SETPOS, 0, Settings.SuperFXClockMultiplier);
5253 			CheckDlgButton(hDlg,IDC_INACTIVE_PAUSE,GUI.InactivePause ? BST_CHECKED : BST_UNCHECKED);
5254 			CheckDlgButton(hDlg,IDC_CUSTOMROMOPEN,GUI.CustomRomOpen ? BST_CHECKED : BST_UNCHECKED);
5255 			CheckDlgButton(hDlg,IDC_HIRESAVI,GUI.AVIHiRes ? BST_CHECKED : BST_UNCHECKED);
5256 			CheckDlgButton(hDlg, IDC_CONFIRMSAVELOAD, GUI.ConfirmSaveLoad ? BST_CHECKED : BST_UNCHECKED);
5257 
5258 			int inum = 0;
5259 			lstrcpy(paths[inum++],GUI.RomDir);
5260 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_ROMS);
5261 			lstrcpy(paths[inum++],GUI.ScreensDir);
5262 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SCREENS);
5263 			lstrcpy(paths[inum++],GUI.MovieDir);
5264 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_MOVIES);
5265 			lstrcpy(paths[inum++],GUI.SPCDir);
5266 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SPCS);
5267 			lstrcpy(paths[inum++],GUI.FreezeFileDir);
5268 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SAVES);
5269 			lstrcpy(paths[inum++],GUI.SRAMFileDir);
5270 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SRAM);
5271 			lstrcpy(paths[inum++],GUI.PatchDir);
5272 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_PATCHES);
5273 			lstrcpy(paths[inum++], GUI.CheatDir);
5274 			SendDlgItemMessage(hDlg, IDC_DIRCOMBO, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_CHEATS);
5275 			lstrcpy(paths[inum++],GUI.BiosDir);
5276 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_BIOS);
5277 			lstrcpy(paths[inum++],GUI.SatDir);
5278 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SATDATA);
5279 
5280 			SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_SETCURSEL,(WPARAM)0,0);
5281  			SetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, paths[0]);
5282 			which = 0;
5283 
5284 			SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR));
5285 		}
5286 		case WM_PAINT:
5287 		{
5288 		PAINTSTRUCT ps;
5289 		BeginPaint (hDlg, &ps);
5290 
5291 		EndPaint (hDlg, &ps);
5292 		}
5293 		return true;
5294 	case WM_COMMAND:
5295 		{
5296 			switch(LOWORD(wParam))
5297 			{
5298 			case IDC_BROWSE:
5299 				{
5300 					LPMALLOC lpm=NULL;
5301 					LPITEMIDLIST iidl=NULL;
5302 					BROWSEINFO bi;
5303 					memset(&bi, 0, sizeof(BROWSEINFO));
5304 					TCHAR path[MAX_PATH];
5305 					_tfullpath(path, paths[which], MAX_PATH);
5306 					TCHAR title[]=SETTINGS_TITLE_SELECTFOLDER;
5307 					bi.hwndOwner=hDlg;
5308 					bi.pszDisplayName=path;
5309 					bi.lpszTitle=title;
5310 					bi.lpfn = SetSelProc;
5311 					bi.lParam = (LPARAM)(LPCSTR) path;
5312                     bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
5313 					iidl=SHBrowseForFolder(&bi);
5314 					if(iidl) SHGetPathFromIDList(iidl, path);
5315 
5316 					SHGetMalloc(&lpm);
5317 					lpm->Free(iidl);
5318 					absToRel(paths[which], path, S9xGetDirectoryT(DEFAULT_DIR));
5319  					SetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, paths[which]);
5320 				}
5321 				break;
5322 			case IDC_CUSTOM_FOLDER_FIELD:
5323 				which = SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_GETCURSEL,0,0);
5324 				GetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, paths[which], MAX_PATH);
5325 				break;
5326 			case IDC_DIRCOMBO:
5327 				which = SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_GETCURSEL,0,0);
5328  				SetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, paths[which]);
5329 				break;
5330 			case IDOK:
5331 				{
5332 					int inum = 0;
5333 					lstrcpy(GUI.RomDir,paths[inum++]);
5334 					lstrcpy(GUI.ScreensDir,paths[inum++]);
5335 					lstrcpy(GUI.MovieDir,paths[inum++]);
5336 					lstrcpy(GUI.SPCDir,paths[inum++]);
5337 					lstrcpy(GUI.FreezeFileDir,paths[inum++]);
5338 					lstrcpy(GUI.SRAMFileDir,paths[inum++]);
5339 					lstrcpy(GUI.PatchDir,paths[inum++]);
5340 					lstrcpy(GUI.CheatDir, paths[inum++]);
5341 					lstrcpy(GUI.BiosDir,paths[inum++]);
5342 					lstrcpy(GUI.SatDir,paths[inum++]);
5343 
5344 					GUI.InactivePause = (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_INACTIVE_PAUSE));
5345 					GUI.CustomRomOpen = (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_CUSTOMROMOPEN));
5346 					GUI.AVIHiRes = (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_HIRESAVI));
5347 					GUI.ConfirmSaveLoad = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_CONFIRMSAVELOAD));
5348 
5349 					Settings.TurboSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_GETPOS, 0,0);
5350 					Settings.AutoMaxSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP, UDM_GETPOS, 0,0);
5351 					Settings.AutoSaveDelay=SendDlgItemMessage(hDlg, IDC_SRAM_SPIN, UDM_GETPOS, 0,0);
5352                     GUI.rewindGranularity = SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_GETPOS, 0,0);
5353 					Settings.SuperFXClockMultiplier = SendDlgItemMessage(hDlg, IDC_SFXSPEED_SPIN, UDM_GETPOS, 0, 0);
5354                     if(GUI.rewindGranularity==0) GUI.rewindGranularity = 1;
5355                     unsigned int newRewindBufSize = SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_GETPOS, 0,0);
5356                     if(GUI.rewindBufferSize != newRewindBufSize) {
5357                         GUI.rewindBufferSize = newRewindBufSize;
5358                         if(!Settings.StopEmulation) stateMan.init(GUI.rewindBufferSize * 1024 * 1024);
5359                     }
5360 
5361 					WinSaveConfigFile();
5362 				}
5363 				/* fall through */
5364 			case IDCANCEL:
5365 				EndDialog(hDlg, 0);
5366 				return true;
5367 				break;
5368 			default: return false; break;
5369 			}
5370 		}
5371 	default:return false;
5372 	}
5373 }
5374 
5375 #define SKIP_FLOPPY
5376 
ExtensionIsValid(const TCHAR * filename)5377 static bool ExtensionIsValid(const TCHAR * filename)
5378 {
5379 	ExtList* curr=valid_ext;
5380 	while(curr!=NULL)
5381 	{
5382 		if(curr->extension==NULL)
5383 		{
5384 			if(NULL==_tcsstr(filename, TEXT(".")))
5385 				return true;
5386 		}
5387 		else if(filename[(lstrlen(filename)-1)-lstrlen(curr->extension)]=='.')
5388 		{
5389 			if(0==_tcsncicmp(&filename[(lstrlen(filename))-lstrlen(curr->extension)],
5390 				curr->extension, lstrlen(curr->extension)))
5391 				return true;
5392 		}
5393 		curr=curr->next;
5394 	}
5395 	return false;
5396 }
5397 
IsCompressed(const TCHAR * filename)5398 bool IsCompressed(const TCHAR* filename)
5399 {
5400 	ExtList* curr=valid_ext;
5401 	while(curr!=NULL)
5402 	{
5403 		if(curr->extension==NULL)
5404 		{
5405 			if(NULL==_tcsstr(filename, TEXT(".")))
5406 				return curr->compressed;
5407 		}
5408 		else if(filename[(lstrlen(filename)-1)-lstrlen(curr->extension)]=='.')
5409 		{
5410 			if(0==_tcsncicmp(&filename[(lstrlen(filename))-lstrlen(curr->extension)],
5411 				curr->extension, lstrlen(curr->extension)))
5412 				return curr->compressed;
5413 		}
5414 		curr=curr->next;
5415 	}
5416 	return false;
5417 }
5418 
AllASCII(char * b,int size)5419 inline bool AllASCII(char *b, int size)
5420 {
5421 	for (int i = 0; i < size; i++)
5422 	{
5423 		if (b[i] < 32 || b[i] > 126)
5424 		{
5425 			return(false);
5426 		}
5427 	}
5428 	return(true);
5429 }
5430 
InfoScore(char * Buffer)5431 inline int InfoScore(char *Buffer)
5432 {
5433 	int score = 0;
5434 	if (Buffer[28] + (Buffer[29] << 8) +
5435 		Buffer[30] + (Buffer[31] << 8) == 0xFFFF)
5436 	{	score += 3; }
5437 
5438 	if (Buffer[26] == 0x33) { score += 2; }
5439 	if ((Buffer[21] & 0xf) < 4) {	score += 2; }
5440 	if (!(Buffer[61] & 0x80)) { score -= 4; }
5441 	if ((1 << (Buffer[23] - 7)) > 48) { score -= 1; }
5442 	if (Buffer[25] < 14) { score += 1; }
5443 	if (!AllASCII(Buffer, 20)) { score -= 1; }
5444 
5445 	return (score);
5446 }
5447 
sum(unsigned char * array,unsigned int size=HEADER_SIZE)5448 inline unsigned short sum(unsigned char *array, unsigned int size = HEADER_SIZE)
5449 {
5450 	unsigned short theSum = 0;
5451 	for (unsigned int i = 0; i < size; i++)
5452 	{
5453 		theSum += array[i];
5454 	}
5455 	return(theSum);
5456 }
5457 
rominfo(const TCHAR * filename,TCHAR * namebuffer,TCHAR * sizebuffer)5458 void rominfo(const TCHAR *filename, TCHAR *namebuffer, TCHAR *sizebuffer)
5459 {
5460 	lstrcpy(namebuffer, ROM_ITEM_DESCNOTAVAILABLE);
5461 	lstrcpy(sizebuffer, TEXT("? Mbits"));
5462 
5463 #ifdef UNZIP_SUPPORT
5464 	if(IsCompressed(filename))
5465 	{
5466 		unzFile uf = unzOpen(_tToChar(filename));
5467 		if(uf)
5468 		{
5469 			unz_file_info info;
5470 			if(UNZ_OK == unzGetCurrentFileInfo(uf, &info, 0,0,0,0,0,0))
5471 			{
5472 				if (info.uncompressed_size < 0x8000) // Smaller than a block
5473 					lstrcpy(namebuffer, ROM_ITEM_NOTAROM);
5474 				else
5475 					lstrcpy(namebuffer, ROM_ITEM_COMPRESSEDROMDESCRIPTION);
5476 
5477 				// should subtract header size, so this may be slightly off, but it's better than "? MBits"
5478 				double MBitD = (double)(info.uncompressed_size - 0) / 0x100000 * 8;
5479 				int MBitI = (int)MBitD;
5480 				int sizeIndex;
5481 				if(0!=(MBitI / 10))
5482 				{
5483 					sizebuffer[0] = MBitI / 10 + TEXT('0');
5484 					sizeIndex = 1;
5485 				}
5486 				else
5487 					sizeIndex = 0;
5488 				sizebuffer[sizeIndex+0] = MBitI % 10 + TEXT('0');
5489 				sizebuffer[sizeIndex+1] = TEXT('.');
5490 				sizebuffer[sizeIndex+2] = (char)((MBitD - MBitI) * 10) + TEXT('0');
5491 				sizebuffer[sizeIndex+3] = (char)((int)((MBitD - MBitI) * 100) % 10) + TEXT('0');
5492 				sizebuffer[sizeIndex+4] = TEXT(' ');
5493 				sizebuffer[sizeIndex+5] = TEXT('M');
5494 				sizebuffer[sizeIndex+6] = TEXT('b');
5495 				sizebuffer[sizeIndex+7] = TEXT('i');
5496 				sizebuffer[sizeIndex+8] = TEXT('t');
5497 				sizebuffer[sizeIndex+9] = TEXT('\0');
5498 			}
5499 			unzClose(uf);
5500 		}
5501 		return;
5502 	}
5503 #endif
5504 
5505 	struct _stat filestats;
5506 	_tstat(filename, &filestats);
5507 
5508 	int HeaderSize = 0;
5509 
5510 	if (filestats.st_size >= 0x8000)
5511 	{
5512 		ifstream ROMFile(filename, ios::in | ios::binary);
5513 		if (ROMFile)
5514 		{
5515 			int HasHeadScore = 0, NoHeadScore = 0,
5516 				HeadRemain = filestats.st_size & 0x7FFF;
5517 
5518 			switch(HeadRemain)
5519 			{
5520 			case 0:
5521 				NoHeadScore += 3;
5522 				break;
5523 
5524 			case HEADER_SIZE:
5525 				HasHeadScore += 2;
5526 				break;
5527 			}
5528 
5529 			unsigned char HeaderBuffer[HEADER_SIZE];
5530 			ROMFile.read((char *)HeaderBuffer, HEADER_SIZE);
5531 
5532 			if (sum(HeaderBuffer) < 2500) { HasHeadScore += 2; }
5533 
5534 			//SMC/SWC Header
5535 			if (HeaderBuffer[8] == 0xAA &&
5536 				HeaderBuffer[9] == 0xBB &&
5537 				HeaderBuffer[10]== 4)
5538 			{ HasHeadScore += 3; }
5539 			//FIG Header
5540 			else if ((HeaderBuffer[4] == 0x77 && HeaderBuffer[5] == 0x83) ||
5541 				(HeaderBuffer[4] == 0xDD && HeaderBuffer[5] == 0x82) ||
5542 				(HeaderBuffer[4] == 0xDD && HeaderBuffer[5] == 2) ||
5543 				(HeaderBuffer[4] == 0xF7 && HeaderBuffer[5] == 0x83) ||
5544 				(HeaderBuffer[4] == 0xFD && HeaderBuffer[5] == 0x82) ||
5545 				(HeaderBuffer[4] == 0x00 && HeaderBuffer[5] == 0x80) ||
5546 				(HeaderBuffer[4] == 0x47 && HeaderBuffer[5] == 0x83) ||
5547 				(HeaderBuffer[4] == 0x11 && HeaderBuffer[5] == 2))
5548 			{ HasHeadScore += 2; }
5549 			else if (!strncmp("GAME DOCTOR SF 3", (char *)HeaderBuffer, 16))
5550 			{ HasHeadScore += 5; }
5551 
5552 			HeaderSize = HasHeadScore > NoHeadScore ? HEADER_SIZE : 0;
5553 
5554 			bool EHi = false;
5555 			if (filestats.st_size - HeaderSize >= 0x500000)
5556 			{
5557 				ROMFile.seekg(0x40FFC0 + HeaderSize, ios::beg);
5558 				ROMFile.read((char *)HeaderBuffer, INFO_LEN);
5559 				if (InfoScore((char *)HeaderBuffer) > 1)
5560 				{
5561 					EHi = true;
5562 					_tcsncpy(namebuffer, _tFromMS932((char *)HeaderBuffer), 21);
5563 				}
5564 			}
5565 
5566 			if (!EHi)
5567 			{
5568 				if (filestats.st_size - HeaderSize >= 0x10000)
5569 				{
5570 					char LoHead[INFO_LEN], HiHead[INFO_LEN];
5571 
5572 					ROMFile.seekg(0x7FC0 + HeaderSize, ios::beg);
5573 					ROMFile.read(LoHead, INFO_LEN);
5574 					int LoScore = InfoScore(LoHead);
5575 
5576 					ROMFile.seekg(0xFFC0 + HeaderSize, ios::beg);
5577 					ROMFile.read(HiHead, INFO_LEN);
5578 					int HiScore = InfoScore(HiHead);
5579 
5580 					_tcsncpy(namebuffer, _tFromMS932(LoScore > HiScore ? LoHead : HiHead), 21);
5581 
5582 					if (filestats.st_size - HeaderSize >= 0x20000)
5583 					{
5584 						ROMFile.seekg((filestats.st_size - HeaderSize) / 2 + 0x7FC0 + HeaderSize, ios::beg);
5585 						ROMFile.read(LoHead, INFO_LEN);
5586 						int IntLScore = InfoScore(LoHead) / 2;
5587 
5588 						if (IntLScore > LoScore && IntLScore > HiScore)
5589 						{
5590 							_tcsncpy(namebuffer, _tFromMS932(LoHead), 21);
5591 						}
5592 					}
5593 				}
5594 				else //ROM only has one block
5595 				{
5596 					char buf[21];
5597 					ROMFile.seekg(0x7FC0 + HeaderSize, ios::beg);
5598 					ROMFile.read(buf, 21);
5599 					_tcsncpy(namebuffer,_tFromMS932(buf),21);
5600 				}
5601 			}
5602 			ROMFile.close();
5603 		}
5604 		else //Couldn't open file
5605 		{
5606 			lstrcpy(namebuffer, ROM_ITEM_CANTOPEN);
5607 		}
5608 	}
5609 	else //Smaller than a block
5610 	{
5611 		lstrcpy(namebuffer, ROM_ITEM_NOTAROM);
5612 	}
5613 
5614 	double MBitD = (double)(filestats.st_size - HeaderSize) / 0x100000 * 8;
5615 	int MBitI = (int)MBitD;
5616 	int sizeIndex;
5617 	if(0!=(MBitI / 10))
5618 	{
5619 		sizebuffer[0] = MBitI / 10 + TEXT('0');
5620 		sizeIndex = 1;
5621 	}
5622 	else
5623 		sizeIndex = 0;
5624 	sizebuffer[sizeIndex+0] = MBitI % 10 + TEXT('0');
5625 	sizebuffer[sizeIndex+1] = TEXT('.');
5626 	sizebuffer[sizeIndex+2] = (char)((MBitD - MBitI) * 10) + TEXT('0');
5627 	sizebuffer[sizeIndex+3] = (char)((int)((MBitD - MBitI) * 100) % 10) + TEXT('0');
5628 	sizebuffer[sizeIndex+4] = TEXT(' ');
5629 	sizebuffer[sizeIndex+5] = TEXT('M');
5630 	sizebuffer[sizeIndex+6] = TEXT('b');
5631 	sizebuffer[sizeIndex+7] = TEXT('i');
5632 	sizebuffer[sizeIndex+8] = TEXT('t');
5633 	sizebuffer[sizeIndex+9] = TEXT('\0');
5634 	namebuffer[21] = TEXT('\0');
5635 }
5636 
GetPathFromTree(HWND hDlg,UINT tree,TCHAR * selected,HTREEITEM hItem)5637 void GetPathFromTree( HWND hDlg, UINT tree, TCHAR* selected, HTREEITEM hItem)
5638 {
5639 	TVITEM tv;
5640 	TCHAR temp[MAX_PATH];
5641 	temp[0]=('\0');
5642 	memset(&tv, 0, sizeof(TVITEM));
5643 	HTREEITEM hTreeTemp=hItem;
5644 
5645 	if(tv.iImage==7)
5646 	{
5647 		tv.mask=TVIF_HANDLE|TVIF_IMAGE;
5648 		tv.hItem=hTreeTemp;
5649 		tv.iImage=6;
5650 		TreeView_SetItem(GetDlgItem(hDlg, tree),&tv);
5651 		memset(&tv, 0, sizeof(TVITEM));
5652 	}
5653 
5654 	tv.mask=TVIF_HANDLE|TVIF_TEXT;
5655 	tv.hItem=hTreeTemp;
5656 	tv.pszText=temp;
5657 	tv.cchTextMax =MAX_PATH;
5658 	TreeView_GetItem(GetDlgItem(hDlg, tree), &tv);
5659 
5660 	_stprintf(selected, TEXT("%s"), temp);
5661 	while(TreeView_GetParent(GetDlgItem(hDlg, tree), hTreeTemp))
5662 	{
5663 		temp[0]=TEXT('\0');
5664 		hTreeTemp=TreeView_GetParent(GetDlgItem(hDlg, tree), hTreeTemp);
5665 		tv.mask=TVIF_HANDLE|TVIF_TEXT;
5666 		tv.hItem=hTreeTemp;
5667 		tv.pszText=temp;
5668 		tv.cchTextMax =MAX_PATH;
5669 		TreeView_GetItem(GetDlgItem(hDlg, tree), &tv);
5670 		_stprintf(temp, TEXT("%s\\%s"),temp, selected);
5671 		lstrcpy(selected, temp);
5672 	}
5673 }
5674 
5675 typedef struct RomDataCacheNode
5676 {
5677 	TCHAR* fname;
5678 	TCHAR* rname;
5679 	TCHAR* rmbits;
5680 	struct RomDataCacheNode* next;
5681 } RomDataList;
5682 
ClearCacheList(RomDataList * rdl)5683 void ClearCacheList(RomDataList* rdl)
5684 {
5685 	RomDataList* temp=rdl;
5686 	RomDataList* temp2=NULL;
5687 	if(rdl==NULL)
5688 		return;
5689 	do
5690 	{
5691 		temp2=temp->next;
5692 		if(temp->fname)
5693 			delete [] temp->fname;
5694 		if(temp->rmbits)
5695 			delete [] temp->rmbits;
5696 		if(temp->rname)
5697 			delete [] temp->rname;
5698 		delete temp;
5699 		temp=temp2;
5700 	}
5701 	while(temp!=NULL);
5702 }
5703 
5704 
ExpandDir(TCHAR * selected,HTREEITEM hParent,HWND hDlg)5705 void ExpandDir(TCHAR * selected, HTREEITEM hParent, HWND hDlg)
5706 {
5707 	TCHAR temp[MAX_PATH];
5708 	WIN32_FIND_DATA wfd;
5709 	memset(&wfd, 0, sizeof(WIN32_FIND_DATA));
5710 	lstrcat(selected, TEXT("\\*"));
5711 	HANDLE hFind=FindFirstFile(selected,&wfd);
5712 	selected[(lstrlen(selected)-1)]=TEXT('\0');
5713 
5714 	do
5715 	{
5716 		if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
5717 		{
5718 			if(lstrcmp(wfd.cFileName, TEXT("."))&&lstrcmp(wfd.cFileName, TEXT("..")))
5719 			{
5720 				//skip these, add the rest.
5721 				TV_INSERTSTRUCT tvis;
5722 				memset(&tvis, 0, sizeof(TV_INSERTSTRUCT));
5723 				tvis.hParent=hParent;
5724 				tvis.hInsertAfter=TVI_SORT;
5725 				tvis.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
5726 				tvis.item.pszText=wfd.cFileName;
5727 				tvis.item.cchTextMax=MAX_PATH;
5728 				const bool locked = (wfd.dwFileAttributes&(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ENCRYPTED|FILE_ATTRIBUTE_OFFLINE))!=0;
5729 				const bool hidden = (wfd.dwFileAttributes&(FILE_ATTRIBUTE_HIDDEN))!=0;
5730 				tvis.item.iImage=hidden?9:(locked?8:7);
5731 				tvis.item.iSelectedImage=locked?8:6;
5732 				HTREEITEM hNewTree=TreeView_InsertItem(GetDlgItem(hDlg, IDC_ROM_DIR),&tvis);
5733 
5734 				lstrcpy(temp, selected);
5735 				lstrcat(temp, wfd.cFileName);
5736 				lstrcat(temp, TEXT("\\*"));
5737 
5738 				bool subdir=false;
5739 				WIN32_FIND_DATA wfd2;
5740 				memset(&wfd2, 0, sizeof(WIN32_FIND_DATA));
5741 				HANDLE hFind2=FindFirstFile(temp,&wfd2);
5742 				do
5743 				{
5744 					if(wfd2.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
5745 					{
5746 						if(lstrcmp(wfd2.cFileName, TEXT("."))&&lstrcmp(wfd2.cFileName, TEXT("..")))
5747 						{
5748 							subdir=true;
5749 						}
5750 					}
5751 				}
5752 				while(FindNextFile(hFind2, &wfd2)&&!subdir);
5753 
5754 				if(subdir)
5755 				{
5756 					TV_INSERTSTRUCT tvis;
5757 					memset(&tvis, 0, sizeof(TV_INSERTSTRUCT));
5758 					tvis.hParent=hNewTree;
5759 					tvis.hInsertAfter=TVI_SORT;
5760 					TreeView_InsertItem(GetDlgItem(hDlg, IDC_ROM_DIR),&tvis);
5761 
5762 				}
5763 				FindClose(hFind2);
5764 
5765 			}
5766 		}
5767 	}
5768 	while(FindNextFile(hFind, &wfd));
5769 
5770 	FindClose(hFind);
5771 	//scan for folders
5772 }
5773 
5774 
5775 
ListFilesFromFolder(HWND hDlg,RomDataList ** prdl)5776 void ListFilesFromFolder(HWND hDlg, RomDataList** prdl)
5777 {
5778 	RomDataList* rdl= *prdl;
5779 	RomDataList* current=NULL;
5780 	int count=0;
5781 	TVITEM tv;
5782 	TCHAR temp[MAX_PATH];
5783 	TCHAR selected[MAX_PATH]; // directory path
5784 	temp[0]='\0';
5785 	memset(&tv, 0, sizeof(TVITEM));
5786 	HTREEITEM hTreeItem=TreeView_GetSelection(GetDlgItem(hDlg, IDC_ROM_DIR));
5787 
5788 	GetPathFromTree(hDlg, IDC_ROM_DIR, selected, hTreeItem);
5789 
5790 	SendDlgItemMessage(hDlg, IDC_ROMLIST, WM_SETREDRAW, FALSE, 0);
5791 	ListView_DeleteAllItems(GetDlgItem(hDlg, IDC_ROMLIST));
5792 	ClearCacheList(rdl);
5793 	rdl=NULL;
5794 	//Add items here.
5795 
5796 	WIN32_FIND_DATA wfd;
5797 	memset(&wfd, 0, sizeof(WIN32_FIND_DATA));
5798 
5799 	lstrcat(selected, TEXT("\\*"));
5800 
5801 	HANDLE hFind=FindFirstFile(selected, &wfd);
5802 	selected[(lstrlen(selected)-1)]=TEXT('\0');
5803 	do
5804 	{
5805 		if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
5806 			continue;
5807 		if(ExtensionIsValid(wfd.cFileName))
5808 		{
5809 			RomDataList* newitem=new RomDataList;
5810 			memset(newitem, 0, sizeof(RomDataList));
5811 			newitem->fname=new TCHAR[1+lstrlen(wfd.cFileName)];
5812 			lstrcpy(newitem->fname, wfd.cFileName);
5813 
5814 			// hide ntldr and no-name files
5815 			if(!newitem->fname || !*newitem->fname || (!lstrcmp(newitem->fname, TEXT("ntldr")) && lstrlen(selected)<4))
5816 				continue;
5817 
5818 			// too small to be a ROM
5819 			if (wfd.nFileSizeLow < 0x8000 && !IsCompressed(wfd.cFileName))
5820 				continue;
5821 
5822 			count++;
5823 
5824 			if(!rdl)
5825 				rdl=newitem;
5826 			else
5827 			{
5828 				if(0>_tcsicmp(newitem->fname,rdl->fname))
5829 				{
5830 					newitem->next=rdl;
5831 					rdl=newitem;
5832 				}
5833 				else
5834 				{
5835 					RomDataList* trail=rdl;
5836 					current=rdl->next;
5837 					while(current!=NULL&&0<_tcsicmp(newitem->fname,current->fname))
5838 					{
5839 						trail=current;
5840 						current=current->next;
5841 					}
5842 					newitem->next=current;
5843 					trail->next=newitem;
5844 				}
5845 			}
5846 		}
5847 	}
5848 	while(FindNextFile(hFind, &wfd));
5849 
5850 	FindClose(hFind);
5851 
5852 		SendDlgItemMessage(hDlg, IDC_ROMLIST, WM_SETREDRAW, TRUE, 0);
5853 	*prdl=rdl;
5854 	ListView_SetItemCountEx (GetDlgItem(hDlg, IDC_ROMLIST), count, 0);
5855 	ListView_SetItemState (GetDlgItem(hDlg,IDC_ROMLIST), 0, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
5856 }
5857 
5858 // load multicart rom dialog
DlgMultiROMProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)5859 INT_PTR CALLBACK DlgMultiROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
5860 {
5861 	switch(msg)
5862 	{
5863 	case WM_INITDIALOG:{
5864 		WinRefreshDisplay();
5865 		TCHAR path[MAX_PATH];
5866 		SetCurrentDirectory(S9xGetDirectoryT(BIOS_DIR));
5867 		_tfullpath(path, TEXT("stbios.bin"), MAX_PATH);
5868 		SetDlgItemText(hDlg, IDC_MULTICART_BIOSEDIT, path);
5869 		FILE* ftemp = _tfopen(path, TEXT("rb"));
5870 		if(ftemp)
5871 		{
5872 			fclose(ftemp);
5873 			SetDlgItemText(hDlg, IDC_MULTICART_BIOSNOTFOUND, MULTICART_BIOS_FOUND);
5874 		}
5875 		else
5876 			SetDlgItemText(hDlg, IDC_MULTICART_BIOSNOTFOUND, MULTICART_BIOS_NOT_FOUND);
5877 		SetDlgItemText(hDlg, IDC_MULTICART_EDITA, multiRomA);
5878 		SetDlgItemText(hDlg, IDC_MULTICART_EDITB, multiRomB);
5879 		break;}
5880 	case WM_COMMAND:
5881 		{
5882 			TCHAR rom1[MAX_PATH]={0}, rom2[MAX_PATH]={0};
5883 			SetCurrentDirectory(S9xGetDirectoryT(ROM_DIR));
5884 			switch(LOWORD(wParam))
5885 			{
5886 			case IDOK:
5887 				GetDlgItemText(hDlg, IDC_MULTICART_EDITA, multiRomA, MAX_PATH);
5888 				GetDlgItemText(hDlg, IDC_MULTICART_EDITB, multiRomB, MAX_PATH);
5889 				EndDialog(hDlg, 1);
5890 				return true;
5891 			case IDCANCEL:
5892 				EndDialog(hDlg, 0);
5893 				return true;
5894 			case IDC_MULTICART_SWAP:
5895 				GetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom2, MAX_PATH);
5896 				GetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom1, MAX_PATH);
5897 				SetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom1);
5898 				SetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom2);
5899 				break;
5900 			case IDC_MULTICART_BROWSEA:
5901 				if(!DoOpenRomDialog(rom1, true))
5902 					break;
5903 				SetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom1);
5904 				break;
5905 			case IDC_MULTICART_BROWSEB:
5906 				if(!DoOpenRomDialog(rom2, true))
5907 					break;
5908 				SetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom2);
5909 				break;
5910 			case IDC_MULTICART_CLEARA:
5911 				rom1[0] = TEXT('\0');
5912 				SetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom1);
5913 				break;
5914 			case IDC_MULTICART_CLEARB:
5915 				rom1[1] = TEXT('\0');
5916 				SetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom2);
5917 				break;
5918 			}
5919 		}
5920 	}
5921 	return false;
5922 }
5923 
MoveControlY(HWND hDlg,HWND hCtrl,unsigned int newY)5924 void MoveControlY(HWND hDlg, HWND hCtrl, unsigned int newY)
5925 {
5926 	RECT ctrlRect;
5927 	GetWindowRect(hCtrl, &ctrlRect);
5928 	POINT pt;
5929 	pt.x = ctrlRect.left;
5930 	pt.y = ctrlRect.top;
5931 	ScreenToClient(hDlg, &pt);
5932 	MoveWindow(hCtrl, pt.x, newY, ctrlRect.right - ctrlRect.left, ctrlRect.bottom - ctrlRect.top, FALSE);
5933 }
5934 
MoveOpenRomWindows(HWND hDlg,unsigned int newWidth,int newHeight)5935 void MoveOpenRomWindows(HWND hDlg, unsigned int newWidth, int newHeight)
5936 {
5937 	RECT rectRomList, rectDirList, rectSplitter, rectStatic, rectCombo, rectOk, rectCancel;
5938 
5939 	HWND romList = GetDlgItem(hDlg, IDC_ROMLIST);
5940 	HWND dirList = GetDlgItem(hDlg, IDC_ROM_DIR);
5941 	HWND splitter = GetDlgItem(hDlg, IDC_ROM_SPLITTER);
5942 	HWND memStatic = GetDlgItem(hDlg, IDC_STATIC_MEMORY_TYPE);
5943 	HWND memCombo = GetDlgItem(hDlg, IDC_MEM_TYPE);
5944 	HWND okButton = GetDlgItem(hDlg, IDOK);
5945 	HWND cancelButton = GetDlgItem(hDlg, IDCANCEL);
5946 
5947 	GetWindowRect(romList, &rectRomList);
5948 	GetWindowRect(dirList, &rectDirList);
5949 	GetWindowRect(splitter, &rectSplitter);
5950 	GetWindowRect(memStatic, &rectStatic);
5951 	GetWindowRect(memCombo, &rectCombo);
5952 	GetWindowRect(okButton, &rectOk);
5953 	GetWindowRect(cancelButton, &rectCancel);
5954 
5955 	unsigned int comboTop = newHeight - (rectCombo.bottom - rectCombo.top) - 5;
5956 	unsigned int staticTop = comboTop - (rectStatic.bottom - rectStatic.top);
5957 	unsigned int newListHeight = staticTop - 15;
5958 	POINT pt;
5959 	pt.x = rectRomList.left;
5960 	pt.y = rectRomList.top;
5961 	ScreenToClient(hDlg, &pt);
5962 	unsigned int newListWidth = newWidth - pt.x - 5;
5963 
5964 	unsigned int buttonTop = newHeight - (rectOk.bottom - rectOk.top) - 5;
5965 	unsigned int buttonLeft = newWidth - (rectOk.right - rectOk.left) - (rectCancel.right - rectCancel.left) - 5;
5966 	unsigned int buttonCancelLeft = buttonLeft + (rectOk.right - rectOk.left);
5967 
5968 	// only change width / height
5969 	SetWindowPos(romList, 0, 0, 0, newListWidth, newListHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
5970 	SetWindowPos(dirList, 0, 0, 0, rectDirList.right - rectDirList.left, newListHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
5971 	SetWindowPos(splitter, 0, 0, 0, rectSplitter.right - rectSplitter.left, newListHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
5972 
5973 	// only change y pos
5974 	MoveControlY(hDlg, memStatic, staticTop);
5975 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_STATIC_INTERLEAVE_MODE), staticTop);
5976 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_STATIC_VIDEO_SYSTEM), staticTop);
5977 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_STATIC_HEADER), staticTop);
5978 
5979 	MoveControlY(hDlg, memCombo, comboTop);
5980 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_INTERLEAVE), comboTop);
5981 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_VIDEO_MODE), comboTop);
5982 	MoveControlY(hDlg, GetDlgItem(hDlg, IDC_HEADER), comboTop);
5983 
5984 	// only change position
5985 	SetWindowPos(okButton, 0, buttonLeft, buttonTop, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOZORDER);
5986 	SetWindowPos(cancelButton, 0, buttonCancelLeft, buttonTop, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOZORDER);
5987 }
5988 
MoveSplitterRelativeDirList(HWND hDlg,int offset_x)5989 void MoveSplitterRelativeDirList(HWND hDlg, int offset_x)
5990 {
5991 	HWND hTree, hList, hSplitter;
5992 	RECT treeRect;
5993 	RECT listRect;
5994 	hTree = GetDlgItem(hDlg, IDC_ROM_DIR);
5995 	hList = GetDlgItem(hDlg, IDC_ROMLIST);
5996 	hSplitter = GetDlgItem(hDlg, IDC_ROM_SPLITTER);
5997 	GetWindowRect(hTree, &treeRect);
5998 
5999 	POINT p;
6000 	p.x = offset_x + treeRect.right;
6001 
6002 	p.y = treeRect.top;
6003 	GetWindowRect(hList, &listRect);
6004 
6005 	if (p.x > (listRect.right - 50))
6006 	{
6007 		offset_x -= (short)(p.x - (listRect.right - 50));
6008 		p.x = listRect.right - 50;
6009 	}
6010 
6011 
6012 	ScreenToClient(hDlg, &p);
6013 
6014 	if (p.x < 50)
6015 	{
6016 		offset_x += (short)(50 - p.x);
6017 		p.x = 50;
6018 	}
6019 
6020 	MoveWindow(hSplitter, p.x, p.y, listRect.left - treeRect.right, listRect.bottom - listRect.top, FALSE);
6021 	MoveWindow(hList, p.x + (listRect.left - treeRect.right), p.y, listRect.right - listRect.left - offset_x, listRect.bottom - listRect.top, TRUE);
6022 	p.x = treeRect.left;
6023 	p.y = treeRect.top;
6024 	ScreenToClient(hDlg, &p);
6025 	MoveWindow(hTree, p.x, p.y, treeRect.right - treeRect.left + offset_x, treeRect.bottom - treeRect.top, true);
6026 	InvalidateRect(hSplitter, NULL, true);
6027 }
6028 
SaveCustomDialogSettings(HWND hDlg)6029 void SaveCustomDialogSettings(HWND hDlg)
6030 {
6031 	WINDOWPLACEMENT wndPlacement = { 0 };
6032 	wndPlacement.length = sizeof(WINDOWPLACEMENT);
6033 	GetWindowPlacement(hDlg, &wndPlacement);
6034 	GUI.customRomDlgSettings.window_maximized = wndPlacement.showCmd == SW_SHOWMAXIMIZED;
6035 	GUI.customRomDlgSettings.window_size = wndPlacement.rcNormalPosition;
6036 
6037 	HWND dirList = GetDlgItem(hDlg, IDC_ROM_DIR);
6038 	HWND romList = GetDlgItem(hDlg, IDC_ROMLIST);
6039 	RECT dirRect;
6040 	GetWindowRect(dirList, &dirRect);
6041 	GUI.customRomDlgSettings.folderPaneWidth = dirRect.right - dirRect.left;
6042 
6043 	LVCOLUMN col;
6044 	memset(&col, 0, sizeof(LVCOLUMN));
6045 	col.mask = LVCF_WIDTH;
6046 
6047 	ListView_GetColumn(romList, 0, &col);
6048 	GUI.customRomDlgSettings.columnFilename = col.cx;
6049 
6050 	ListView_GetColumn(romList, 1, &col);
6051 	GUI.customRomDlgSettings.columnDescription = col.cx;
6052 
6053 	ListView_GetColumn(romList, 2, &col);
6054 	GUI.customRomDlgSettings.columnSize = col.cx;
6055 }
6056 
DlgOpenROMProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)6057 INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
6058 {
6059 	int rv=0;
6060 	static HWND hSplit;
6061 	static HIMAGELIST hIcons;
6062 	static TCHAR *filename;
6063 	static RomDataList* rdl;
6064 	static int selectionMarkOverride = -1;
6065 	static bool initDone = false;
6066 	static RomDataList* nextInvalidatedROM = NULL;
6067 	static int nextInvalidatedROMCounter = 0;
6068 	static HWND romList = NULL;
6069 	static HWND dirList = NULL;
6070 	switch(msg)
6071 	{
6072 	case WM_SIZE:
6073 		MoveOpenRomWindows(hDlg, LOWORD(lParam), HIWORD(lParam));
6074 		RedrawWindow(hDlg, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
6075 		break;
6076 	case WM_INITDIALOG:
6077 		WinRefreshDisplay();
6078 		{
6079 			initDone = false;
6080 
6081 			// suppress annoying "no disk in drive" errors
6082 			SetErrorMode(SEM_FAILCRITICALERRORS);
6083 
6084 			romList = GetDlgItem(hDlg,IDC_ROMLIST);
6085 			dirList = GetDlgItem(hDlg,IDC_ROM_DIR);
6086 			filename=(TCHAR*)lParam;
6087 			RECT treeRect;
6088 			RECT listRect;
6089 			WNDCLASSEX wcex;
6090 			TCHAR tempclassname[]=TEXT("S9xSplitter");
6091 			memset(&wcex, 0, sizeof(WNDCLASSEX));
6092 			wcex.cbSize=sizeof(WNDCLASSEX);
6093 			wcex.hInstance=g_hInst;
6094 			wcex.lpfnWndProc=DlgChildSplitProc;
6095 			wcex.lpszClassName=tempclassname;
6096 			wcex.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH);
6097 			wcex.hCursor=LoadCursor(NULL, IDC_SIZEWE);
6098 			ATOM aSplitter=RegisterClassEx(&wcex);
6099 			GetWindowRect(dirList, &treeRect);
6100 			GetWindowRect(romList, &listRect);
6101 			POINT p;
6102 
6103 			ListView_SetExtendedListViewStyle(romList, LVS_EX_FULLROWSELECT);
6104 
6105 			p.x=treeRect.right;
6106 			p.y=treeRect.top;
6107 			ScreenToClient(hDlg, &p);
6108 			hSplit=CreateWindow(TEXT("S9xSplitter"), TEXT(""),WS_CHILD|WS_VISIBLE , p.x, p.y, listRect.left-treeRect.right , listRect.bottom-listRect.top, hDlg, (HMENU)IDC_ROM_SPLITTER, g_hInst,0);
6109 
6110 			LVCOLUMN col;
6111 			static const LPTSTR temp1 = ROM_COLUMN_FILENAME;
6112 			memset(&col, 0, sizeof(LVCOLUMN));
6113 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH;
6114 			col.fmt=LVCFMT_LEFT;
6115 			col.iOrder=0;
6116 			col.cx= GUI.customRomDlgSettings.columnFilename;
6117 			col.cchTextMax=5;
6118 			col.pszText=temp1;
6119 
6120 			ListView_InsertColumn(romList,    0,   &col);
6121 
6122 			static const LPTSTR temp2 = ROM_COLUMN_DESCRIPTION;
6123 			memset(&col, 0, sizeof(LVCOLUMN));
6124 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
6125 			col.fmt=LVCFMT_LEFT;
6126 			col.iOrder=1;
6127 			col.cx= GUI.customRomDlgSettings.columnDescription;
6128 			col.cchTextMax=32;
6129 			col.pszText=temp2;
6130 			col.iSubItem=1;
6131 
6132 			ListView_InsertColumn(romList,    1,   &col);
6133 
6134 
6135 			static const LPTSTR temp3 = ROM_COLUMN_SIZE;
6136 			memset(&col, 0, sizeof(LVCOLUMN));
6137 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
6138 			col.fmt=LVCFMT_LEFT;
6139 			col.iOrder=2;
6140 			col.cx= GUI.customRomDlgSettings.columnSize;
6141 			col.cchTextMax=32;
6142 			col.pszText=temp3;
6143 			col.iSubItem=2;
6144 
6145 			ListView_InsertColumn(romList,    2,   &col);
6146 
6147 
6148 			SendDlgItemMessage(hDlg, IDC_MEM_TYPE,CB_INSERTSTRING,0,(LPARAM)ROM_OPTION_AUTODETECT);
6149 			SendDlgItemMessage(hDlg, IDC_MEM_TYPE,CB_INSERTSTRING,1,(LPARAM)ROM_OPTION_FORCEHIROM);
6150 			SendDlgItemMessage(hDlg, IDC_MEM_TYPE,CB_INSERTSTRING,2,(LPARAM)ROM_OPTION_FORCELOROM);
6151 			SendDlgItemMessage(hDlg, IDC_MEM_TYPE,CB_SETCURSEL,0,0);
6152 
6153 			SendDlgItemMessage(hDlg, IDC_VIDEO_MODE,CB_INSERTSTRING,0,(LPARAM)ROM_OPTION_AUTODETECT);
6154 			SendDlgItemMessage(hDlg, IDC_VIDEO_MODE,CB_INSERTSTRING,1,(LPARAM)ROM_OPTION_FORCEPAL);
6155 			SendDlgItemMessage(hDlg, IDC_VIDEO_MODE,CB_INSERTSTRING,2,(LPARAM)ROM_OPTION_FORCENTSC);
6156 			SendDlgItemMessage(hDlg, IDC_VIDEO_MODE,CB_SETCURSEL,0,0);
6157 
6158 			SendDlgItemMessage(hDlg, IDC_HEADER,CB_INSERTSTRING,0,(LPARAM)ROM_OPTION_AUTODETECT);
6159 			SendDlgItemMessage(hDlg, IDC_HEADER,CB_INSERTSTRING,1,(LPARAM)ROM_OPTION_FORCEHEADER);
6160 			SendDlgItemMessage(hDlg, IDC_HEADER,CB_INSERTSTRING,2,(LPARAM)ROM_OPTION_FORCENOHEADER);
6161 			SendDlgItemMessage(hDlg, IDC_HEADER,CB_SETCURSEL,0,0);
6162 
6163 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_INSERTSTRING,0,(LPARAM)ROM_OPTION_AUTODETECT);
6164 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_INSERTSTRING,1,(LPARAM)ROM_OPTION_NONINTERLEAVED);
6165 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_INSERTSTRING,2,(LPARAM)ROM_OPTION_MODE1);
6166 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_INSERTSTRING,3,(LPARAM)ROM_OPTION_MODE2);
6167 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_INSERTSTRING,4,(LPARAM)ROM_OPTION_GD24);
6168 			SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_SETCURSEL,0,0);
6169 
6170 			hIcons=ImageList_Create(16,16,ILC_COLOR24,10,10);
6171 
6172 			HANDLE hBitmap;
6173 
6174 #define ADD_IMAGE(IDB_NAME) \
6175 			hBitmap=LoadImage(g_hInst, MAKEINTRESOURCE(IDB_NAME), IMAGE_BITMAP, 0,0, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION); \
6176 			ImageList_Add(hIcons, (HBITMAP)hBitmap, NULL); \
6177 			DeleteObject(hBitmap);
6178 
6179 			ADD_IMAGE(IDB_HARDDRIVE); // 0
6180 			ADD_IMAGE(IDB_CDDRIVE); // 1
6181 			ADD_IMAGE(IDB_NETDRIVE); // 2
6182 			ADD_IMAGE(IDB_REMOVABLE); // 3
6183 			ADD_IMAGE(IDB_RAMDISK); // 4
6184 			ADD_IMAGE(IDB_UNKNOWN); // 5
6185 			ADD_IMAGE(IDB_OPENFOLDER); // 6
6186 			ADD_IMAGE(IDB_CLOSEDFOLDER); // 7
6187 			ADD_IMAGE(IDB_LOCKEDFOLDER); // 8
6188 			ADD_IMAGE(IDB_HIDDENFOLDER); // 9
6189 
6190 			TreeView_SetImageList(dirList, hIcons, TVSIL_NORMAL);
6191 
6192 //			DWORD dw;
6193 			TCHAR buffer[MAX_PATH];
6194 			TCHAR blah[MAX_PATH];
6195 			long result=ERROR_SUCCESS/*-1*/;
6196 			HTREEITEM hTreeDrive=NULL;
6197 
6198 			TCHAR drive [_MAX_DRIVE + 1];
6199 			lstrcpy (drive,TEXT("C:\\"));
6200 
6201 
6202 			_tfullpath (buffer, S9xGetDirectoryT(ROM_DIR), MAX_PATH);
6203 			_tsplitpath (buffer, drive, NULL, NULL, NULL);
6204 
6205 			DWORD driveMask=GetLogicalDrives();
6206 
6207 #ifndef SKIP_FLOPPY
6208 			for (int i=0;i<26;i++)
6209 #else
6210 				for (int i=2;i<26;i++)
6211 #endif
6212 				{
6213 					if(driveMask&(1<<i))
6214 					{
6215 						TCHAR driveName[4];
6216 						driveName[0]='A'+i;
6217 						driveName[1]=':';
6218 						driveName[2]='\\';
6219 						driveName[3]='\0';
6220 						UINT driveType=GetDriveType(driveName);
6221 						driveName[2]='\0';
6222 
6223 						TVINSERTSTRUCT tvis;
6224 						memset(&tvis, 0, sizeof(TVINSERTSTRUCT));
6225 
6226 						tvis.hParent=NULL;
6227 						tvis.hInsertAfter=TVI_ROOT;
6228 						tvis.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
6229 
6230 						switch(driveType)
6231 						{
6232 							case DRIVE_FIXED:     tvis.item.iSelectedImage=tvis.item.iImage=0; break;
6233 							case DRIVE_CDROM:     tvis.item.iSelectedImage=tvis.item.iImage=1; break;
6234 							case DRIVE_REMOTE:    tvis.item.iSelectedImage=tvis.item.iImage=2; break;
6235 							case DRIVE_REMOVABLE: tvis.item.iSelectedImage=tvis.item.iImage=3; break;
6236 							case DRIVE_RAMDISK:   tvis.item.iSelectedImage=tvis.item.iImage=4; break;
6237 							default:              tvis.item.iSelectedImage=tvis.item.iImage=5; break;
6238 						}
6239 
6240 						tvis.item.pszText=driveName;
6241 
6242 						HTREEITEM hTwee=TreeView_InsertItem(dirList,&tvis);
6243 
6244 						if(result==ERROR_SUCCESS && !_tcsnicmp(drive, driveName, 2))
6245 							hTreeDrive=hTwee;
6246 
6247 						TCHAR temp[10];
6248 						lstrcpy(temp, driveName);
6249 						lstrcat(temp, TEXT("\\*"));
6250 						bool subdir=false;
6251 
6252 						if(driveType==DRIVE_REMOVABLE || driveType == DRIVE_CDROM || driveType == DRIVE_UNKNOWN)
6253 						{
6254 								TV_INSERTSTRUCT tvis;
6255 								memset(&tvis, 0, sizeof(TV_INSERTSTRUCT));
6256 								tvis.hParent=hTwee;
6257 								tvis.hInsertAfter=TVI_SORT;
6258 								TreeView_InsertItem(dirList,&tvis);
6259 
6260 						}
6261 						else
6262 						{
6263 							WIN32_FIND_DATA wfd2;
6264 							memset(&wfd2, 0, sizeof(WIN32_FIND_DATA));
6265 							HANDLE hFind2=FindFirstFile(temp,&wfd2);
6266 							do
6267 							{
6268 								if(wfd2.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
6269 								{
6270 									if(lstrcmp(wfd2.cFileName, TEXT("."))&&lstrcmp(wfd2.cFileName, TEXT("..")))
6271 									{
6272 										subdir=true;
6273 									}
6274 								}
6275 							}
6276 							while(FindNextFile(hFind2, &wfd2)&&!subdir);
6277 
6278 							if(subdir)
6279 							{
6280 								TV_INSERTSTRUCT tvis;
6281 								memset(&tvis, 0, sizeof(TV_INSERTSTRUCT));
6282 								tvis.hParent=hTwee;
6283 								tvis.hInsertAfter=TVI_SORT;
6284 								TreeView_InsertItem(dirList,&tvis);
6285 							}
6286 							FindClose(hFind2);
6287 						}
6288 					}
6289 				}
6290 
6291 				SendDlgItemMessage(hDlg, IDC_ROM_DIR, WM_SETREDRAW, FALSE, 0);
6292 
6293 				if(result==ERROR_SUCCESS)
6294 				{
6295 					HTREEITEM hTreePrev;//,hTreeRoot;
6296 				//	hTreePrev=TreeView_GetRoot(dirList);
6297 				//	hTreeRoot=hTreeDrive;
6298 					hTreePrev=hTreeDrive;
6299 					HTREEITEM hTemp=hTreePrev;
6300 					TCHAR* temp=buffer;
6301 					TCHAR* temp2, * temp3;
6302 
6303 					do
6304 					{
6305 						temp2=_tcsstr(temp, TEXT("\\"));
6306 						temp3=_tcsstr(temp, TEXT("/"));
6307 						if(temp3 && temp3 < temp2)
6308 							temp2 = temp3;
6309 
6310 						TVITEM tvi;
6311 						memset(&tvi, 0, sizeof(TVITEM));
6312 						tvi.mask=TVIF_TEXT;
6313 						tvi.pszText=blah;
6314 						tvi.cchTextMax=MAX_PATH;
6315 						blah[0]=TEXT('\0');
6316 
6317 						if(temp2)
6318 							*temp2=TEXT('\0');
6319 
6320 						tvi.hItem=hTemp;
6321 						TreeView_GetItem(dirList, &tvi);
6322 
6323 						if(_tcsicmp(blah, temp) != 0)
6324 						{
6325 							do
6326 							{
6327 								tvi.mask=TVIF_TEXT;
6328 								tvi.pszText=blah;
6329 								tvi.cchTextMax=MAX_PATH;
6330 								hTemp=TreeView_GetNextSibling(dirList, hTemp);
6331 								tvi.hItem=hTemp;
6332 								TreeView_GetItem(dirList, &tvi);
6333 							}
6334 							while((hTemp != NULL) && (_tcsicmp(blah, temp) != 0));
6335 
6336 							if(hTemp!=NULL)
6337 							{
6338 								hTreePrev=hTemp;
6339 
6340 								TreeView_SelectItem(dirList, hTreePrev);
6341 								TreeView_EnsureVisible(dirList, hTreePrev);
6342 								if(temp2)
6343 									TreeView_Expand(dirList, hTreePrev, TVE_EXPAND);
6344 
6345 								hTemp=TreeView_GetChild(dirList, hTreePrev);
6346 							}
6347 						}
6348 						else
6349 						{
6350 							TreeView_SelectItem(dirList, hTemp);
6351 							TreeView_EnsureVisible(dirList, hTemp);
6352 							if(temp2)
6353 								TreeView_Expand(dirList, hTemp, TVE_EXPAND);
6354 
6355 							hTemp=TreeView_GetChild(dirList, hTemp);
6356 						}
6357 						if(temp2)
6358 							temp=temp2+1;
6359 						else
6360 							temp=NULL;
6361 					}
6362 					while(temp);
6363 
6364 					if(Memory.ROMFilename[0]!='\0')
6365 					{
6366 						LVFINDINFO lvfi;
6367 						memset(&lvfi, 0, sizeof(LVFINDINFO));
6368 						TCHAR filename[_MAX_PATH];
6369 						TCHAR *tmp, *tmp2;
6370 						lstrcpy(filename,_tFromChar(Memory.ROMFilename));
6371 						tmp = filename;
6372 						while(tmp2=_tcsstr(tmp, TEXT("\\")))
6373 							tmp=tmp2+sizeof(TCHAR);
6374 
6375 						lvfi.flags=LVFI_STRING;
6376 						lvfi.psz=tmp2;
6377 
6378 						int idx=ListView_FindItem(romList, -1, &lvfi);
6379 						ListView_SetSelectionMark(romList, idx);
6380 						ListView_SetItemState(romList, idx, LVIS_SELECTED|LVIS_FOCUSED,LVIS_FOCUSED|LVIS_SELECTED);
6381 						ListView_EnsureVisible(romList, idx, FALSE);
6382 
6383 					}
6384 					SendDlgItemMessage(hDlg, IDC_ROM_DIR, WM_SETREDRAW, TRUE, 0);
6385 				}
6386 				initDone = true;
6387 
6388 				ListView_EnsureVisible (romList, (int)SendMessage(romList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED), FALSE);
6389 
6390 				// start up the WM_TIMER event
6391 				nextInvalidatedROM = rdl;
6392 				nextInvalidatedROMCounter = 0;
6393 				SetTimer(hDlg,42,600,NULL);
6394 
6395 				WINDOWPLACEMENT wndPlacement = { 0 };
6396 				wndPlacement.length = sizeof(WINDOWPLACEMENT);
6397 				wndPlacement.showCmd = GUI.customRomDlgSettings.window_maximized ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
6398 				wndPlacement.rcNormalPosition = GUI.customRomDlgSettings.window_size;
6399 				SetWindowPlacement(hDlg, &wndPlacement);
6400 
6401 				RECT clientRect;
6402 				GetClientRect(hDlg, &clientRect);
6403 				MoveOpenRomWindows(hDlg, clientRect.right, clientRect.bottom);
6404 				MoveSplitterRelativeDirList(hDlg, GUI.customRomDlgSettings.folderPaneWidth - (treeRect.right - treeRect.left));
6405 
6406 				return true; //true sets the keyboard focus, in case we need this elsewhere
6407 		}
6408 		case WM_TIMER:
6409 			{
6410 				if(!initDone || !nextInvalidatedROM || !rdl)
6411 					return false;
6412 
6413 				// see if current selection needs filling in, and skip to that if so
6414 				int selected = (int)SendMessage(romList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED);
6415 				if(selected>=0)
6416 				{
6417 					RomDataList* curr=rdl;
6418 					for(int i=0;i<selected;i++)
6419 						if(curr) curr=curr->next;
6420 					if(curr && !curr->rname)
6421 					{
6422 						nextInvalidatedROM = curr;
6423 						nextInvalidatedROMCounter = selected;
6424 					}
6425 				}
6426 
6427 				LVHITTESTINFO lvhi;
6428 				lvhi.flags = LVHT_ONITEM;
6429 				lvhi.iItem = 0;
6430 				lvhi.iSubItem = 0;
6431 				lvhi.pt.x = 0;
6432 				lvhi.pt.y = 0;
6433 				ListView_HitTest(romList, &lvhi);
6434 				int firstVisibleItem = lvhi.iItem+1;
6435 				int lastVisibleItem = firstVisibleItem+20;
6436 
6437 				// skip up to 100 things that don't need updating
6438 				bool enteredValid = false;
6439 				if(nextInvalidatedROM->rname || nextInvalidatedROMCounter<firstVisibleItem || nextInvalidatedROMCounter>lastVisibleItem)
6440 				for(int i = 0 ; i < 100 ; i++)
6441 					if(nextInvalidatedROM->rname || (!enteredValid && (nextInvalidatedROMCounter<firstVisibleItem || nextInvalidatedROMCounter>lastVisibleItem)))
6442 					{
6443 						if(!enteredValid && nextInvalidatedROMCounter>=firstVisibleItem && nextInvalidatedROMCounter<lastVisibleItem)
6444 							enteredValid = true;
6445 						nextInvalidatedROM = nextInvalidatedROM->next;
6446 						if(nextInvalidatedROM)
6447 							nextInvalidatedROMCounter++;
6448 						else
6449 						{
6450 							nextInvalidatedROM = rdl;
6451 							nextInvalidatedROMCounter = 0;
6452 						}
6453 					}
6454 
6455 				// update 1 item, if it needs updating
6456 				if(!nextInvalidatedROM->rname)
6457 				{
6458 					TCHAR path[MAX_PATH];
6459 					TCHAR buffer[32];
6460 					TCHAR buffer2[32];
6461 					GetPathFromTree(hDlg, IDC_ROM_DIR, path, TreeView_GetSelection(dirList));
6462 					lstrcat(path, TEXT("\\"));
6463 					lstrcat(path, nextInvalidatedROM->fname);
6464 					rominfo(path, buffer, buffer2);
6465 					nextInvalidatedROM->rname=new TCHAR[lstrlen(buffer)+1];
6466 					lstrcpy(nextInvalidatedROM->rname, buffer);
6467 					nextInvalidatedROM->rmbits=new TCHAR[lstrlen(buffer2)+1];
6468 					lstrcpy(nextInvalidatedROM->rmbits, buffer2);
6469 
6470 					ListView_RedrawItems(romList,nextInvalidatedROMCounter,nextInvalidatedROMCounter);
6471 				}
6472 
6473 				// next timer
6474 				nextInvalidatedROM = nextInvalidatedROM->next;
6475 				if(nextInvalidatedROM)
6476 					nextInvalidatedROMCounter++;
6477 				else
6478 				{
6479 					nextInvalidatedROM = rdl;
6480 					nextInvalidatedROMCounter = 0;
6481 				}
6482 				SetTimer(hDlg,42,600,NULL);
6483 				return true;
6484 			}
6485 	case WM_PAINT:
6486 		{
6487 			PAINTSTRUCT ps;
6488 			BeginPaint (hDlg, &ps);
6489 
6490 		EndPaint (hDlg, &ps);
6491 		}
6492 		return true;
6493 
6494 	case WM_COMMAND:
6495 		{
6496 			switch(LOWORD(wParam))
6497 			{
6498 			case IDOK:
6499 				{
6500 					LVITEM lvi;
6501 					memset(&lvi, 0, sizeof(LVITEM));
6502 					//get selections
6503 					int list_index = selectionMarkOverride == -1 ? ListView_GetSelectionMark(romList) : selectionMarkOverride;
6504 					if(list_index!=-1 && (int)SendMessage(romList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED)!=-1)
6505 					{
6506 						rv=1;
6507 						TCHAR temp[MAX_PATH];
6508 						temp[0]='\0';
6509 						lvi.iItem=list_index;
6510 						lvi.mask=LVIF_TEXT;
6511 						lvi.pszText=filename;
6512 						lvi.cchTextMax=MAX_PATH;
6513 						ListView_GetItem(romList, &lvi);
6514 
6515 						lstrcpy(temp, filename);
6516 
6517 						HTREEITEM hTreeTemp=TreeView_GetSelection(dirList);
6518 						TVITEM tv;
6519 						memset(&tv, 0, sizeof(TVITEM));
6520 
6521 						tv.mask=TVIF_HANDLE|TVIF_TEXT;
6522 						tv.hItem=hTreeTemp;
6523 						tv.pszText=temp;
6524 						tv.cchTextMax =MAX_PATH;
6525 						TreeView_GetItem(dirList, &tv);
6526 						_stprintf(temp, TEXT("%s\\%s"), temp, filename);
6527 
6528 						lstrcpy(filename, temp);
6529 
6530 						while(TreeView_GetParent(dirList, hTreeTemp)!=NULL)
6531 						{
6532 							temp[0]=TEXT('\0');
6533 							hTreeTemp=TreeView_GetParent(dirList, hTreeTemp);
6534 							tv.mask=TVIF_HANDLE|TVIF_TEXT;
6535 							tv.hItem=hTreeTemp;
6536 							tv.pszText=temp;
6537 							tv.cchTextMax =MAX_PATH;
6538 							TreeView_GetItem(dirList, &tv);
6539 							_stprintf(temp, TEXT("%s\\%s"),temp, filename);
6540 							lstrcpy(filename, temp);
6541 						}
6542 
6543 						int iTemp=SendDlgItemMessage(hDlg, IDC_MEM_TYPE,CB_GETCURSEL,0,0);
6544 
6545 						Settings.ForceHiROM=Settings.ForceLoROM=FALSE;
6546 						if(iTemp==1)
6547 							Settings.ForceHiROM=TRUE;
6548 						else if(iTemp==2)
6549 							Settings.ForceLoROM=TRUE;
6550 
6551 						iTemp=SendDlgItemMessage(hDlg, IDC_INTERLEAVE,CB_GETCURSEL,0,0);
6552 
6553 						Settings.ForceNotInterleaved=Settings.ForceInterleaved=Settings.ForceInterleaved2=Settings.ForceInterleaveGD24=FALSE;
6554 						if(iTemp==1)
6555 							Settings.ForceNotInterleaved=TRUE;
6556 						else if(iTemp==2)
6557 							Settings.ForceInterleaved=TRUE;
6558 						else if(iTemp==3)
6559 							Settings.ForceInterleaved2=TRUE;
6560 						else if(iTemp==4)
6561 							Settings.ForceInterleaveGD24=TRUE;
6562 
6563 						iTemp=SendDlgItemMessage(hDlg, IDC_VIDEO_MODE,CB_GETCURSEL,0,0);
6564 
6565 						Settings.ForceNTSC=Settings.ForcePAL=FALSE;
6566 						if(iTemp==1)
6567 							Settings.ForcePAL=TRUE;
6568 						else if(iTemp==2)
6569 							Settings.ForceNTSC=TRUE;
6570 
6571 
6572 						iTemp=SendDlgItemMessage(hDlg, IDC_HEADER,CB_GETCURSEL,0,0);
6573 
6574 						Settings.ForceNoHeader=Settings.ForceHeader=FALSE;
6575 						if(iTemp==1)
6576 							Settings.ForceHeader=TRUE;
6577 						else if(iTemp==2)
6578 							Settings.ForceNoHeader=TRUE;
6579 
6580 						lstrcpy(temp, filename);
6581 						int i=lstrlen(temp);
6582 						while(temp[i]!=TEXT('\\') && temp[i]!=TEXT('/'))
6583 						{
6584 							temp[i]=TEXT('\0');
6585 							i--;
6586 						}
6587 						temp[i]=TEXT('\0');
6588 
6589 						if(!GUI.LockDirectories)
6590 							absToRel(GUI.RomDir, temp, S9xGetDirectoryT(DEFAULT_DIR));
6591 					}
6592 					else
6593 					{
6594 						return false;
6595 					}
6596 				}
6597 			case IDCANCEL:
6598 				SaveCustomDialogSettings(hDlg);
6599 				EndDialog(hDlg, rv);
6600 				ClearCacheList(rdl);
6601 				rdl=NULL;
6602 				DestroyWindow(hSplit);
6603 				UnregisterClass(TEXT("S9xSplitter"), g_hInst);
6604 				TreeView_DeleteAllItems(dirList);
6605 				ListView_DeleteAllItems(romList);
6606 				return true;
6607 				break;
6608 			default: return false; break;
6609 			}
6610 		}
6611 	case WM_NOTIFY:
6612 		{
6613 			if(lParam == 0)
6614 				return false;
6615 			NMHDR* pNmh=(NMHDR*)lParam;
6616 			static int foundItemOverride = -1;
6617 			switch(pNmh->idFrom)
6618 			{
6619 			case IDC_ROMLIST:
6620 				{
6621 					switch(pNmh->code)
6622 					{
6623 					// allow typing in a ROM filename (or part of it) to jump to it
6624 					// necessary to implement ourselves because Windows doesn't provide
6625 					// this functionality for virtual (owner data) lists such as this
6626 					case LVN_ODFINDITEM:
6627 						{
6628 							LRESULT pResult;
6629 
6630 							// pNMHDR has information about the item we should find
6631 							// In pResult we should save which item that should be selected
6632 							NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)lParam;
6633 
6634 							/* pFindInfo->iStart is from which item we should search.
6635 							We search to bottom, and then restart at top and will stop
6636 							at pFindInfo->iStart, unless we find an item that match
6637 							*/
6638 
6639 							// Set the default return value to -1
6640 							// That means we didn't find any match.
6641 							pResult = -1;
6642 
6643 							//Is search NOT based on string?
6644 							if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
6645 							{
6646 								//This will probably never happend...
6647 								return pResult;
6648 							}
6649 
6650 							//This is the string we search for
6651 							LPCTSTR searchstr = pFindInfo->lvfi.psz;
6652 
6653 							int startPos = pFindInfo->iStart;
6654 							//Is startPos outside the list (happens if last item is selected)
6655 							if(startPos >= ListView_GetItemCount(romList))
6656 								startPos = 0;
6657 
6658 							if(rdl==NULL)
6659 								return pResult;
6660 
6661 							RomDataList* curr=rdl;
6662 							for(int i=0;i<startPos;i++)
6663 								curr=curr->next;
6664 
6665 							int currentPos=startPos;
6666 							pResult=startPos;
6667 
6668 							bool looped = false;
6669 
6670 							// perform search
6671 							do
6672 							{
6673 								// does this word begin with all characters in searchstr?
6674 								if( _tcsnicmp(curr->fname, searchstr, lstrlen(searchstr)) == 0)
6675 								{
6676 									// select this item and stop search
6677 									pResult = currentPos;
6678 									break;
6679 								}
6680 								else if( _tcsnicmp(curr->fname, searchstr, lstrlen(searchstr)) > 0)
6681 								{
6682 									if(looped)
6683 									{
6684 										pResult = currentPos;
6685 										break;
6686 									}
6687 
6688 									// optimization: the items are ordered alphabetically, so go back to the top since we know it can't be anything further down
6689 									curr=rdl;
6690 									currentPos = 0;
6691 									looped = true;
6692 									continue;
6693 								}
6694 
6695 								//Go to next item
6696 								currentPos++;
6697 								curr=curr->next;
6698 
6699 								//Need to restart at top?
6700 								if(currentPos >= ListView_GetItemCount(romList))
6701 								{
6702 									currentPos = 0;
6703 									curr = rdl;
6704 								}
6705 
6706 							//Stop if back to start
6707 							}while(currentPos != startPos);
6708 
6709 							foundItemOverride = pResult;
6710 
6711 							// in case previously-selected item is 0
6712 							ListView_SetItemState (romList, 1, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
6713 
6714 							return pResult; // HACK: for some reason this selects the first item instead of what it's returning... current workaround is to manually re-select this return value upon the next changed event
6715 						}
6716 						break;
6717 					case LVN_ITEMCHANGED:
6718 						{
6719 							// hack - see note directly above
6720 							LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
6721 							if(lpnmlv->uNewState & (LVIS_SELECTED|LVIS_FOCUSED))
6722 							{
6723 								if(foundItemOverride != -1 && lpnmlv->iItem == 0)
6724 								{
6725 									ListView_SetItemState (romList, foundItemOverride, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
6726 									ListView_EnsureVisible (romList, foundItemOverride, FALSE);
6727 									selectionMarkOverride = foundItemOverride;
6728 									foundItemOverride = -1;
6729 								}
6730 								else
6731 								{
6732 									selectionMarkOverride = lpnmlv->iItem;
6733 								}
6734 							}
6735 						}
6736 						break;
6737 					case LVN_GETDISPINFO:
6738 						{
6739 							if(!initDone)
6740 								return false;
6741 							int i, j;
6742 							RomDataList* curr=rdl;
6743 							if(rdl==NULL)
6744 								return false;
6745 							NMLVDISPINFO * nmlvdi=(NMLVDISPINFO*)lParam;
6746 							j=nmlvdi->item.iItem;
6747 							for(i=0;i<j;i++)
6748 								if(curr) curr=curr->next;
6749 							if(curr==NULL)
6750 								return false;
6751 							//if(curr->rname==NULL && j==(int)SendMessage(romList, LVM_GETNEXTITEM, -1, LVNI_SELECTED))
6752 							//{
6753 							//	TCHAR path[MAX_PATH];
6754 							//	TCHAR buffer[32];
6755 							//	TCHAR buffer2[32];
6756 							//	GetPathFromTree(hDlg, IDC_ROM_DIR, path, TreeView_GetSelection(dirList));
6757 							//	strcat(path, "\\");
6758 							//	strcat(path, curr->fname);
6759 							//	rominfo(path, buffer, buffer2);
6760 							//	curr->rname=new char[strlen(buffer)+1];
6761 							//	strcpy(curr->rname, buffer);
6762 							//	curr->rmbits=new char[strlen(buffer2)+1];
6763 							//	strcpy(curr->rmbits, buffer2);
6764 							//}
6765 
6766 							if(nmlvdi->item.iSubItem==0)
6767 							{
6768 								nmlvdi->item.pszText=curr->fname?curr->fname:TEXT("");
6769 								nmlvdi->item.cchTextMax=MAX_PATH;
6770 							}
6771 							if(nmlvdi->item.iSubItem==1)
6772 							{
6773 								nmlvdi->item.pszText=curr->rname?curr->rname:TEXT("");
6774 								nmlvdi->item.cchTextMax=24;
6775 							}
6776 
6777 							if(nmlvdi->item.iSubItem==2)
6778 							{
6779 								nmlvdi->item.pszText=curr->rmbits?curr->rmbits:TEXT("");
6780 								nmlvdi->item.cchTextMax=11;
6781 							}
6782 							// nmlvdi->item.mask=LVIF_TEXT; // This is bad as wine relies on this to not change.
6783 						}
6784 						break;
6785 					case NM_DBLCLK:
6786 						{
6787 							PostMessage(hDlg, WM_COMMAND, (WPARAM)(IDOK),(LPARAM)(NULL));
6788 						}
6789 					default:break;
6790 					}
6791 				}
6792 				break;
6793 			case IDC_ROM_DIR:
6794 				{
6795 					switch(pNmh->code)
6796 					{
6797 					case TVN_ITEMEXPANDING:
6798 						{
6799 							TCHAR selected[MAX_PATH];
6800 							NMTREEVIEW* nmTv=(NMTREEVIEW*)lParam;
6801 
6802 							while(TreeView_GetChild(dirList,nmTv->itemNew.hItem))
6803 							{
6804 								TreeView_DeleteItem(dirList, TreeView_GetChild(dirList,nmTv->itemNew.hItem));
6805 							}
6806 
6807 							if(nmTv->action&TVE_EXPAND)
6808 							{
6809 
6810 								GetPathFromTree(hDlg, IDC_ROM_DIR, selected,nmTv->itemNew.hItem);
6811 								ExpandDir(selected, nmTv->itemNew.hItem, hDlg);
6812 							}
6813 							else
6814 							{
6815 								TVITEM tv;
6816 								memset(&tv, 0, sizeof(TVITEM));
6817 								HTREEITEM hTreeTemp=nmTv->itemNew.hItem;
6818 
6819 								if(tv.iImage==6)
6820 								{
6821 									tv.mask=TVIF_HANDLE|TVIF_IMAGE;
6822 									tv.hItem=hTreeTemp;
6823 									tv.iImage=7;
6824 									TreeView_SetItem(dirList,&tv);
6825 								}
6826 
6827 
6828 								TV_INSERTSTRUCT tvis;
6829 								memset(&tvis, 0, sizeof(TV_INSERTSTRUCT));
6830 								tvis.hParent=nmTv->itemNew.hItem;
6831 								tvis.hInsertAfter=TVI_SORT;
6832 								TreeView_InsertItem(dirList,&tvis);
6833 
6834 							}
6835 						}
6836 						return false;
6837 						break;
6838 					case TVN_SELCHANGED:
6839 						{
6840 							ListFilesFromFolder(hDlg, &rdl);
6841 							nextInvalidatedROM = rdl;
6842 							nextInvalidatedROMCounter = 0;
6843 						}
6844 					default:return false;
6845 					}
6846 				}
6847 			default:return false;
6848 			}
6849 		}
6850 	default:return false;
6851 	}
6852 	return false;
6853 }
6854 
DlgChildSplitProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)6855 LRESULT CALLBACK DlgChildSplitProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
6856 {
6857 	static bool PaintSpecial;
6858 	static short drag_x;
6859 	short temp_x;
6860 	switch(msg)
6861 	{
6862 	case WM_CREATE:
6863 		return 0;
6864 	case WM_SIZE:
6865         return 0;
6866     case WM_PAINT:
6867 		PAINTSTRUCT ps;
6868 		GetUpdateRect (hWnd, &ps.rcPaint, true);
6869 		ps.hdc=GetDC(hWnd);
6870 		ps.fErase=true;
6871 		BeginPaint(hWnd, &ps);
6872 		EndPaint(hWnd, &ps);
6873 		ReleaseDC(hWnd, ps.hdc);
6874         return 0;
6875     case WM_LBUTTONDOWN:
6876 		PaintSpecial=true;
6877 		drag_x=GET_X_LPARAM(lParam);
6878 		SetCapture(hWnd);
6879         return 0;
6880     case WM_LBUTTONUP:
6881 	{
6882 		PaintSpecial = false;
6883 		temp_x = (GET_X_LPARAM(lParam) - drag_x);
6884 		HWND hDlg = GetParent(hWnd);
6885 		MoveSplitterRelativeDirList(hDlg, temp_x);
6886 		ReleaseCapture();
6887 		return 0;
6888 	}
6889     case WM_MOUSEMOVE:
6890 	{
6891 		if (wParam & MK_LBUTTON)
6892 		{
6893 			//move paint location
6894 			PaintSpecial = true;
6895 			temp_x = (GET_X_LPARAM(lParam) - drag_x);
6896 			HWND hDlg = GetParent(hWnd);
6897 			MoveSplitterRelativeDirList(hDlg, temp_x);
6898 		}
6899 		return 0;
6900 	}
6901     case WM_CAPTURECHANGED:
6902 		PaintSpecial=false;
6903 		ReleaseCapture();
6904 		return 0;
6905     case WM_DESTROY:
6906         return 0;
6907 	default:return DefWindowProc(hWnd, msg, wParam, lParam);
6908 	}
6909 }
6910 
6911 
6912 
6913 
6914 #ifdef NETPLAY_SUPPORT
DlgNetConnect(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)6915 INT_PTR CALLBACK DlgNetConnect(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
6916 {
6917 //	HKEY hKey;
6918 	TCHAR defPort[5];
6919 	TCHAR portTemp[5];
6920 	TCHAR temp[100];
6921 //	char temp2[5];
6922 	static TCHAR* hostname;
6923 //	unsigned long cbData;
6924 //	static int i;
6925 	if(Settings.Port==0)
6926 	{
6927 		_itot(1996,defPort,10);
6928 	}
6929 	else
6930 	{
6931 		_itot(Settings.Port,defPort,10);
6932 	}
6933 
6934 	WORD chkLength;
6935 //	if(RegCreateKeyEx(HKEY_CURRENT_USER,MY_REG_KEY "\\1.x\\NetPlayServerHistory",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS, NULL, &hKey,NULL) == ERROR_SUCCESS){}
6936 
6937 	switch (msg)
6938 	{
6939 	case WM_INITDIALOG:
6940 		WinRefreshDisplay();
6941 		SetWindowText(hDlg,NPCON_TITLE);
6942 		SetDlgItemText(hDlg,IDC_LABEL_SERVERADDY,NPCON_LABEL_SERVERADDY);
6943 		SetDlgItemText(hDlg,IDC_LABEL_PORTNUM,NPCON_LABEL_PORTNUM);
6944 		SetDlgItemText(hDlg,IDC_CLEARHISTORY, NPCON_CLEARHISTORY);
6945 		SetDlgItemText(hDlg,IDOK,BUTTON_OK);
6946 		SetDlgItemText(hDlg,IDCANCEL,BUTTON_CANCEL);
6947 		hostname = (TCHAR *)lParam;
6948 		{
6949 			for(int i=0; i<MAX_RECENT_HOSTS_LIST_SIZE && *GUI.RecentHostNames[i]; i++)
6950 				SendDlgItemMessage(hDlg, IDC_HOSTNAME, CB_INSERTSTRING,i,(LPARAM)GUI.RecentHostNames[i]);
6951 		}
6952 
6953 		SendDlgItemMessage(hDlg, IDC_PORTNUMBER, WM_SETTEXT, 0, (LPARAM)defPort);
6954 
6955 		SendDlgItemMessage(hDlg, IDC_HOSTNAME, WM_SETTEXT, 0, (LPARAM)NPCON_ENTERHOST);
6956 
6957 		return TRUE;
6958 
6959 	case WM_COMMAND:
6960 		switch(LOWORD(wParam))
6961 		{
6962 		case IDC_CLEARHISTORY:
6963 			{
6964 				{
6965 					SendDlgItemMessage(hDlg,IDC_HOSTNAME,CB_RESETCONTENT,0,0);
6966 					SendDlgItemMessage(hDlg,IDC_HOSTNAME,CB_INSERTSTRING,0,(LPARAM)GUI.RecentHostNames[0]);
6967 					for(int i=1; i<MAX_RECENT_HOSTS_LIST_SIZE; i++)
6968 						*GUI.RecentHostNames[i] = TEXT('\0');
6969 				}
6970 				break;
6971 			}
6972 		case IDOK:
6973 			{
6974 
6975 				chkLength = (WORD) SendDlgItemMessage(hDlg,IDC_PORTNUMBER,EM_LINELENGTH,0,0);
6976 				*((LPWORD)portTemp) = chkLength;
6977 				SendDlgItemMessage(hDlg,IDC_PORTNUMBER,EM_GETLINE,0,(LPARAM)(LPCTSTR)portTemp);
6978 
6979 				if(_ttoi(portTemp)>65535||_ttoi(portTemp)<1024)
6980 				{
6981 					MessageBox(hDlg,TEXT("Port Number needs to be between 1024 and 65535"),TEXT("Error"),MB_OK);
6982 					break;
6983 				}
6984 				else
6985 				{
6986 					Settings.Port = _ttoi(portTemp);
6987 				}
6988 				//chkLength = (WORD) SendDlgItemMessage(hDlg,IDC_HOSTNAME,EM_LINELENGTH,0,0);
6989 				//if(chkLength > 0)
6990 				//{
6991 				//SendDlgItemMessage(hDlg,IDC_HOSTNAME,EM_GETLINE,0,(LPARAM)hostname);
6992 				SendDlgItemMessage(hDlg,IDC_HOSTNAME,WM_GETTEXT,100,(LPARAM)temp);
6993 				if(!lstrcmp(temp, NPCON_ENTERHOST))
6994 				{
6995 					MessageBox(hDlg,NPCON_PLEASE_ENTERHOST,TEXT("Error"),MB_OK);
6996 					break;
6997 				}
6998 				lstrcpy(hostname,temp);
6999 				//MessageBox(hDlg,temp,"hola",MB_OK);
7000 
7001 				// save hostname in recent list
7002 				{
7003 					int i;
7004 					for(i=0; i<MAX_RECENT_HOSTS_LIST_SIZE; i++)
7005 					{
7006 						if(!*GUI.RecentHostNames[i])
7007 						{
7008 							lstrcpy(GUI.RecentHostNames[i], hostname);
7009 							break;
7010 						}
7011 						else if(!_tcsicmp(GUI.RecentHostNames[i], hostname))
7012 							break;
7013 					}
7014 					if(i == MAX_RECENT_HOSTS_LIST_SIZE)
7015 						lstrcpy(GUI.RecentHostNames[1+(rand()%(MAX_RECENT_HOSTS_LIST_SIZE-1))], hostname);
7016 				}
7017 
7018 				unsigned long len;
7019 				len = lstrlen(temp);
7020 				if(len > 0)
7021 				{
7022 					EndDialog(hDlg,1);
7023 					return TRUE;
7024 				}
7025 				else
7026 				{
7027 					EndDialog(hDlg,0);
7028 					return TRUE;
7029 				}
7030 
7031 				break;
7032 				//}
7033 			}
7034 		case IDCANCEL:
7035 			{
7036 				EndDialog(hDlg, 0);
7037 				return TRUE;
7038 			}
7039 		default:break;
7040 		}
7041 	}
7042 	return FALSE;
7043 }
7044 #endif
SetInfoDlgColor(unsigned char r,unsigned char g,unsigned char b)7045 void SetInfoDlgColor(unsigned char r, unsigned char g, unsigned char b)
7046 {
7047 	GUI.InfoColor=RGB(r,g,b);
7048 }
7049 
7050 #define SNES9XWPROGID TEXT("Snes9x.Win32")
7051 #define SNES9XWPROGIDDESC TEXT("Snes9x ROM")
7052 #define SNES9XWAPPDESC TEXT("Snes9x is a portable, freeware Super Nintendo Entertainment System (SNES) emulator.")
7053 #define SNES9XWAPPNAME TEXT("Snes9x")
7054 #define REGCREATEKEY(key,subkey) \
7055 	if(regResult=RegCreateKeyEx(key, subkey,\
7056 					0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE , NULL , &hKey, NULL ) != ERROR_SUCCESS){\
7057 		return false;\
7058 	}
7059 #define REGSETVALUE(key,name,type,data,size) \
7060 	if(regResult=RegSetValueEx(key, name, NULL, type, (BYTE *)data, size) != ERROR_SUCCESS){\
7061 		RegCloseKey(hKey);\
7062 		return false;\
7063 	}
7064 
RegisterProgid()7065 bool RegisterProgid() {
7066 	LONG	regResult;
7067 	TCHAR	szRegKey[PATH_MAX];
7068 	TCHAR	szExePath[PATH_MAX];
7069     TCHAR   *szExeName;
7070 	HKEY	hKey;
7071 
7072 	szRegKey[PATH_MAX-1]=TEXT('\0');
7073 	GetModuleFileName(NULL, szExePath, PATH_MAX);
7074     szExeName = PathFindFileName(szExePath);
7075 
7076     /* Register ProgID (for use in Default Programs)
7077     */
7078     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\%s"),SNES9XWPROGID);
7079     REGCREATEKEY(HKEY_CURRENT_USER, szRegKey)
7080     REGSETVALUE(hKey,NULL,REG_SZ,SNES9XWPROGIDDESC,(lstrlen(SNES9XWPROGIDDESC) + 1) * sizeof(TCHAR))
7081     RegCloseKey(hKey);
7082 
7083     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\%s\\DefaultIcon"),SNES9XWPROGID);
7084     REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7085     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("%s,0"), szExePath);
7086     REGSETVALUE(hKey,NULL,REG_SZ,szRegKey,(lstrlen(szRegKey) + 1) * sizeof(TCHAR))
7087     RegCloseKey(hKey);
7088 
7089     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\%s\\shell"),SNES9XWPROGID);
7090     REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7091     REGSETVALUE(hKey,NULL,REG_SZ,TEXT("open"),5 * sizeof(TCHAR))
7092     RegCloseKey(hKey);
7093 
7094     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\%s\\shell\\open\\command"),SNES9XWPROGID);
7095     REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7096     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("\"%s\" \"%%L\""),szExePath);
7097     REGSETVALUE(hKey,NULL,REG_SZ,szRegKey,(lstrlen(szRegKey) + 1) * sizeof(TCHAR))
7098     RegCloseKey(hKey);
7099 
7100     /* Register Capabilities (for Default Programs)
7101     */
7102     REGCREATEKEY(HKEY_CURRENT_USER,TEXT("SOFTWARE\\Snes9x\\Capabilities"))
7103     REGSETVALUE(hKey,TEXT("ApplicationDescription"),REG_SZ,SNES9XWAPPDESC,(lstrlen(SNES9XWAPPDESC) + 1) * sizeof(TCHAR))
7104     REGSETVALUE(hKey,TEXT("ApplicationName"),REG_SZ,SNES9XWAPPNAME,(lstrlen(SNES9XWAPPNAME) + 1) * sizeof(TCHAR))
7105     RegCloseKey(hKey);
7106 
7107     REGCREATEKEY(HKEY_CURRENT_USER,TEXT("SOFTWARE\\RegisteredApplications"))
7108     REGSETVALUE(hKey,TEXT("Snes9x"),REG_SZ,TEXT("SOFTWARE\\Snes9x\\Capabilities"),(lstrlen(TEXT("SOFTWARE\\Snes9x\\Capabilities")) + 1) * sizeof(TCHAR))
7109     RegCloseKey(hKey);
7110 
7111     /* Register under Applications for use in OpenWithList
7112     */
7113     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\Applications\\%s"),szExeName);
7114 	REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7115 	RegCloseKey(hKey);
7116 
7117     _stprintf_s(szRegKey,PATH_MAX-1,TEXT("Software\\Classes\\Applications\\%s\\shell\\open\\command"),szExeName);
7118 	REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7119 	_stprintf_s(szRegKey,PATH_MAX-1,TEXT("\"%s\" \"%%L\""),szExePath);
7120 	REGSETVALUE(hKey,NULL,REG_SZ,szRegKey,(lstrlen(szRegKey) + 1) * sizeof(TCHAR))
7121 	RegCloseKey(hKey);
7122 
7123 	return true;
7124 }
7125 
RegisterExt(TCHAR * ext)7126 bool RegisterExt(TCHAR *ext) {
7127 	LONG	regResult;
7128 	TCHAR	szRegKey[PATH_MAX];
7129     TCHAR	szExePath[PATH_MAX];
7130     TCHAR   *szExeName;
7131 	HKEY	hKey;
7132 
7133     if(!ext || ext==TEXT('\0'))
7134         return false;
7135 
7136     GetModuleFileName(NULL, szExePath, PATH_MAX);
7137     szExeName = PathFindFileName(szExePath);
7138 
7139     /* Register .ext as S9x capability (for Default Programs)
7140     */
7141     REGCREATEKEY(HKEY_CURRENT_USER,TEXT("SOFTWARE\\Snes9x\\Capabilities\\FileAssociations"))
7142 	_stprintf_s(szRegKey,PATH_MAX-1,TEXT(".%s"),ext);
7143 	REGSETVALUE(hKey,szRegKey,REG_SZ,SNES9XWPROGID,(lstrlen(SNES9XWPROGID) + 1) * sizeof(TCHAR))
7144 	RegCloseKey(hKey);
7145 
7146     /* Register in OpenWithList - will not be taken as default icon, necessary for Jump List
7147     */
7148 	_stprintf(szRegKey,TEXT("Software\\Classes\\.%s\\OpenWithList\\%s"),ext,szExeName);
7149 	REGCREATEKEY(HKEY_CURRENT_USER,szRegKey)
7150 	RegCloseKey(hKey);
7151 
7152 	return true;
7153 }
7154 
RegisterExts(void)7155 void RegisterExts(void) {
7156 	ExtList *curr=valid_ext;
7157 	while(curr->next!=NULL) {
7158 		RegisterExt(curr->extension);
7159 		curr=curr->next;
7160 	}
7161 }
7162 
ClearExts(void)7163 void ClearExts(void)
7164 {
7165 	ExtList* temp;
7166 	ExtList* curr=valid_ext;
7167 	while(curr!=NULL)
7168 	{
7169 		temp=curr->next;
7170 		if(curr->extension)
7171 			delete [] curr->extension;
7172 		delete curr;
7173 		curr=temp;
7174 	}
7175 	valid_ext=NULL;
7176 
7177 }
7178 
LoadExts(void)7179 void LoadExts(void)
7180 {
7181 	char buffer[MAX_PATH+2];
7182 	if(valid_ext!=NULL)
7183 	{
7184 		ClearExts();
7185 	}
7186 	ExtList* curr;
7187 	valid_ext=new ExtList;
7188 	curr=valid_ext;
7189 	memset(curr, 0, sizeof(ExtList));
7190 	ifstream in;
7191 
7192 #if (((defined(_MSC_VER) && _MSC_VER >= 1300)) || defined(__MINGW32__))
7193 	in.open("Valid.Ext", ios::in);
7194 #else
7195 	in.open("Valid.Ext", ios::in|ios::nocreate);
7196 #endif
7197 	if (!in.is_open())
7198 	{
7199 		in.clear();
7200 		MakeExtFile();
7201 	#if (((defined(_MSC_VER) && _MSC_VER >= 1300)) || defined(__MINGW32__))
7202 		in.open("Valid.Ext", ios::in);
7203 	#else
7204 		in.open("Valid.Ext", ios::in|ios::nocreate);
7205 	#endif
7206 		if(!in.is_open())
7207 		{
7208 			MessageBox(GUI.hWnd, TEXT("Fatal Error: The File \"Valid.Ext\" could not be found or created."), TEXT("Error"), MB_ICONERROR|MB_OK);
7209 			PostQuitMessage(-1);
7210 		}
7211 	}
7212 
7213 	do
7214 	{
7215 		buffer[0]='\0';
7216 		in.getline(buffer,MAX_PATH+2);
7217 		if((*buffer)!='\0')
7218 		{
7219 			curr->next=new ExtList;
7220 			curr=curr->next;
7221 			memset(curr, 0, sizeof(ExtList));
7222 			if(_strnicmp(buffer+strlen(buffer)-1, "Y", 1)==0)
7223 				curr->compressed=true;
7224 			if(strlen(buffer)>1)
7225 			{
7226 				curr->extension=new TCHAR[strlen(buffer)];
7227 				_tcsncpy(curr->extension, _tFromChar(buffer), strlen(buffer)-1);
7228 				curr->extension[strlen(buffer)-1]='\0';
7229 			}
7230 			else curr->extension=NULL;
7231 		}
7232 	}
7233 	while(!in.eof());
7234 	in.close();
7235 	curr=valid_ext;
7236 	valid_ext=valid_ext->next;
7237 	delete curr;
7238 	RegisterProgid();
7239 	RegisterExts();
7240 }
7241 
MakeExtFile(void)7242 void MakeExtFile(void)
7243 {
7244 	ofstream out;
7245 	out.open("Valid.Ext");
7246 
7247 	out<<"smcN"<<endl;
7248 #ifdef UNZIP_SUPPORT
7249 	out<<"zipY"<<endl;
7250 	out<<"msu1Y"<<endl;
7251 #endif
7252 	out<<"gzY"<<endl;
7253 	out<<"swcN"<<endl;
7254 	out<<"figN"<<endl;
7255 	out<<"sfcN"<<endl;
7256 	out<<"bsN"<<endl;
7257 	out<<"jmaY"<<endl;
7258 	out.close();
7259 	SetFileAttributes(TEXT("Valid.Ext"), FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY);
7260 };
7261 #ifdef NETPLAY_SUPPORT
DlgNPOptions(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)7262 INT_PTR CALLBACK DlgNPOptions(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
7263 {
7264 	TCHAR defPort[5];
7265 	WORD chkLength;
7266 	if(Settings.Port==0)
7267 	{
7268 		_itot(1996,defPort,10);
7269 	}
7270 	else
7271 	{
7272 		_itot(Settings.Port,defPort,10);
7273 	}
7274 
7275 	switch (msg)
7276 	{
7277 	case WM_INITDIALOG:
7278 		WinRefreshDisplay();
7279 		SetWindowText(hDlg,NPOPT_TITLE);
7280 		SetDlgItemText(hDlg,IDC_LABEL_PORTNUM,NPOPT_LABEL_PORTNUM);
7281 		SetDlgItemText(hDlg,IDC_LABEL_PAUSEINTERVAL,NPOPT_LABEL_PAUSEINTERVAL);
7282 		SetDlgItemText(hDlg,IDC_LABEL_PAUSEINTERVAL_TEXT,NPOPT_LABEL_PAUSEINTERVAL_TEXT);
7283 		SetDlgItemText(hDlg,IDC_LABEL_MAXSKIP,NPOPT_LABEL_MAXSKIP);
7284 		SetDlgItemText(hDlg,IDC_SYNCBYRESET,NPOPT_SYNCBYRESET);
7285 		SetDlgItemText(hDlg,IDC_SENDROM,NPOPT_SENDROM);
7286 		SetDlgItemText(hDlg,IDC_ACTASSERVER,NPOPT_ACTASSERVER);
7287 		SetDlgItemText(hDlg,IDC_PORTNUMBLOCK,NPOPT_PORTNUMBLOCK);
7288 		SetDlgItemText(hDlg,IDC_CLIENTSETTINGSBLOCK,NPOPT_CLIENTSETTINGSBLOCK);
7289 		SetDlgItemText(hDlg,IDC_SERVERSETTINGSBLOCK,NPOPT_SERVERSETTINGSBLOCK);
7290 		SetDlgItemText(hDlg,IDOK,BUTTON_OK);
7291 		SetDlgItemText(hDlg,IDCANCEL,BUTTON_CANCEL);
7292 
7293 		SendDlgItemMessage(hDlg, IDC_PORTNUMBERA, WM_SETTEXT, 0, (LPARAM)defPort);
7294 		if(Settings.NetPlayServer)
7295 		{
7296 			SendDlgItemMessage(hDlg, IDC_ACTASSERVER, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7297 		}
7298 		if(NPServer.SendROMImageOnConnect)
7299 		{
7300 			SendDlgItemMessage(hDlg, IDC_SENDROM, BM_SETCHECK, BST_CHECKED,0);
7301 		}
7302 
7303 		if(NPServer.SyncByReset)
7304 		{
7305 			SendDlgItemMessage(hDlg, IDC_SYNCBYRESET, BM_SETCHECK, BST_CHECKED,0);
7306 		}
7307 		SendDlgItemMessage(hDlg, IDC_MAXSPIN, UDM_SETRANGE,0,MAKELPARAM((short)60,(short)0));
7308 		SendDlgItemMessage(hDlg, IDC_MAXSPIN, UDM_SETPOS,0,MAKELONG(NetPlay.MaxFrameSkip,0));
7309 		SendDlgItemMessage(hDlg, IDC_PAUSESPIN, UDM_SETRANGE,0,MAKELONG(30,0));
7310 		SendDlgItemMessage(hDlg, IDC_PAUSESPIN, UDM_SETPOS,0,MAKELONG(NetPlay.MaxBehindFrameCount,0));
7311 		return TRUE;
7312 	case WM_PAINT:
7313 		{
7314 			PAINTSTRUCT ps;
7315 			BeginPaint (hDlg, &ps);
7316 
7317 			EndPaint (hDlg, &ps);
7318 		}
7319 		return true;
7320 
7321 	case WM_COMMAND:
7322 		switch(LOWORD(wParam))
7323 		{
7324 		case IDOK:
7325 			{
7326 				NetPlay.MaxFrameSkip=(uint32)SendDlgItemMessage(hDlg, IDC_MAXSPIN, UDM_GETPOS,0,0);
7327 				NetPlay.MaxBehindFrameCount=(uint32)SendDlgItemMessage(hDlg, IDC_PAUSESPIN, UDM_GETPOS,0,0);
7328 				chkLength=(WORD)SendDlgItemMessage(hDlg,IDC_PORTNUMBERA,EM_LINELENGTH,0,0);
7329 				*((LPWORD)defPort) = chkLength;
7330 				SendDlgItemMessage(hDlg,IDC_PORTNUMBERA,EM_GETLINE,0,(LPARAM)defPort);
7331 				if(_ttoi(defPort)<1024||_ttoi(defPort)>65535)
7332 				{
7333 					MessageBox(hDlg,TEXT("Port Number needs to be betweeb 1024 and 65535"),TEXT("Error"),MB_OK);
7334 					break;
7335 				}
7336 				else
7337 				{
7338 					Settings.Port = _ttoi(defPort);
7339 				}
7340 				//MessageBox(hDlg,defPort,defPort,MB_OK);
7341 				Settings.NetPlayServer = IsDlgButtonChecked(hDlg,IDC_ACTASSERVER);
7342 				NPServer.SendROMImageOnConnect = IsDlgButtonChecked(hDlg,IDC_SENDROM);
7343 				NPServer.SyncByReset = IsDlgButtonChecked(hDlg,IDC_SYNCBYRESET);
7344 
7345 				EndDialog(hDlg,0);
7346 				WinSaveConfigFile();
7347 				return TRUE;
7348 			}
7349 		case IDCANCEL:
7350 			{
7351 				EndDialog(hDlg,0);
7352 				return TRUE;
7353 			}
7354 		}
7355 	}
7356 	return FALSE;
7357 }
7358 #endif
7359 
EnableDisableKeyFields(int index,HWND hDlg)7360 void EnableDisableKeyFields (int index, HWND hDlg)
7361 {
7362 	bool enableUnTurboable;
7363 	if(index < 5)
7364 	{
7365 		SetDlgItemText(hDlg,IDC_LABEL_RIGHT,INPUTCONFIG_LABEL_RIGHT);
7366 		SetDlgItemText(hDlg,IDC_LABEL_UPLEFT,INPUTCONFIG_LABEL_UPLEFT);
7367 		SetDlgItemText(hDlg,IDC_LABEL_UPRIGHT,INPUTCONFIG_LABEL_UPRIGHT);
7368 		SetDlgItemText(hDlg,IDC_LABEL_DOWNRIGHT,INPUTCONFIG_LABEL_DOWNRIGHT);
7369 		SetDlgItemText(hDlg,IDC_LABEL_UP,INPUTCONFIG_LABEL_UP);
7370 		SetDlgItemText(hDlg,IDC_LABEL_LEFT,INPUTCONFIG_LABEL_LEFT);
7371 		SetDlgItemText(hDlg,IDC_LABEL_DOWN,INPUTCONFIG_LABEL_DOWN);
7372 		SetDlgItemText(hDlg,IDC_LABEL_DOWNLEFT,INPUTCONFIG_LABEL_DOWNLEFT);
7373 		enableUnTurboable = true;
7374 	}
7375 	else
7376 	{
7377 		SetDlgItemText(hDlg,IDC_LABEL_UP,INPUTCONFIG_LABEL_MAKE_TURBO);
7378 		SetDlgItemText(hDlg,IDC_LABEL_LEFT,INPUTCONFIG_LABEL_MAKE_HELD);
7379 		SetDlgItemText(hDlg,IDC_LABEL_DOWN,INPUTCONFIG_LABEL_MAKE_TURBO_HELD);
7380 		SetDlgItemText(hDlg,IDC_LABEL_RIGHT,INPUTCONFIG_LABEL_CLEAR_TOGGLES_AND_TURBO);
7381 		SetDlgItemText(hDlg,IDC_LABEL_UPLEFT,INPUTCONFIG_LABEL_UNUSED);
7382 		SetDlgItemText(hDlg,IDC_LABEL_UPRIGHT,INPUTCONFIG_LABEL_UNUSED);
7383 		SetDlgItemText(hDlg,IDC_LABEL_DOWNLEFT,INPUTCONFIG_LABEL_UNUSED);
7384 		SetDlgItemText(hDlg,IDC_LABEL_DOWNRIGHT,INPUTCONFIG_LABEL_UNUSED);
7385 		SetDlgItemText(hDlg,IDC_UPLEFT,INPUTCONFIG_LABEL_UNUSED);
7386 		SetDlgItemText(hDlg,IDC_UPRIGHT,INPUTCONFIG_LABEL_UNUSED);
7387 		SetDlgItemText(hDlg,IDC_DWNLEFT,INPUTCONFIG_LABEL_UNUSED);
7388 		SetDlgItemText(hDlg,IDC_DWNRIGHT,INPUTCONFIG_LABEL_UNUSED);
7389 		enableUnTurboable = false;
7390 	}
7391 
7392 	EnableWindow(GetDlgItem(hDlg,IDC_UPLEFT), enableUnTurboable);
7393 	EnableWindow(GetDlgItem(hDlg,IDC_UPRIGHT), enableUnTurboable);
7394 	EnableWindow(GetDlgItem(hDlg,IDC_DWNRIGHT), enableUnTurboable);
7395 	EnableWindow(GetDlgItem(hDlg,IDC_DWNLEFT), enableUnTurboable);
7396 }
7397 
UpdateModeComboBox(HWND hComboBox)7398 void UpdateModeComboBox(HWND hComboBox)
7399 {
7400 	TCHAR modeTxt[80];
7401 	bool foundCurMode=false;
7402 	dMode curMode;
7403 
7404 	dm.clear();
7405 	ComboBox_ResetContent(hComboBox);
7406 	WinEnumDisplayModes(&dm);
7407 
7408 	for(int i=0;i<dm.size();i++) {
7409 		_stprintf( modeTxt, TEXT("%dx%d %dbit %dhz"), dm[i].width , dm[i].height, dm[i].depth ,dm[i].rate);
7410 		ComboBox_AddString(hComboBox,modeTxt);
7411 		if(GUI.FullscreenMode.width==dm[i].width&&GUI.FullscreenMode.height==dm[i].height&&GUI.FullscreenMode.rate==dm[i].rate&&GUI.FullscreenMode.depth==dm[i].depth) {
7412 			ComboBox_SetCurSel(hComboBox,i);
7413 			foundCurMode=true;
7414 		}
7415 	}
7416 	if(!foundCurMode) {
7417 		dm.push_back(GUI.FullscreenMode);
7418 		_stprintf( modeTxt, TEXT("Unsupported mode selected"));
7419 		ComboBox_AddString(hComboBox,modeTxt);
7420 		ComboBox_SetCurSel(hComboBox,ComboBox_GetCount(hComboBox)-1);
7421 	}
7422 
7423 }
7424 
7425 static WNDPROC lpfnOldWndProc;
7426 
GroupBoxCheckBoxTitle(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)7427 LRESULT CALLBACK GroupBoxCheckBoxTitle(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
7428 {
7429 	RECT checkBoxRect;
7430 	if(message==WM_PAINT) {
7431 		HWND checkHwnd=GetDlgItem(GetParent(hWnd),IDC_SHADER_ENABLED);
7432 		GetClientRect(checkHwnd,&checkBoxRect);
7433 		MapWindowPoints(checkHwnd,hWnd,(LPPOINT)&checkBoxRect,2);
7434 		ValidateRect(hWnd,&checkBoxRect);
7435 	}
7436 	return CallWindowProc(lpfnOldWndProc, hWnd, message, wParam, lParam);
7437 }
7438 
SelectOutputMethodInVideoDropdown(HWND hDlg,OutputMethod method)7439 void SelectOutputMethodInVideoDropdown(HWND hDlg, OutputMethod method)
7440 {
7441 	// select item with corresponding itemdata
7442 	int item_count = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_GETCOUNT, 0, 0);
7443 	for (int index = 0; index < item_count; index++) {
7444 		int item_data = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_GETITEMDATA, index, 0);
7445 		if (item_data == method)
7446 			SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_SETCURSEL, index, 0);
7447 	}
7448 }
7449 
DlgFunky(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)7450 INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
7451 {
7452 	int index;
7453 	TCHAR s[80];
7454 	char temp[80];
7455 	TCHAR openFileName[MAX_PATH];
7456 	OPENFILENAME ofn;
7457 
7458 	// temporary GUI state for restoring after previewing while selecting options
7459 	static int prevScale, prevScaleHiRes, prevPPL;
7460 	static bool prevStretch, prevAspectRatio, prevHeightExtend, prevAutoDisplayMessages, prevBilinearFilter, prevShaderEnabled, prevBlendHires, prevIntegerScaling, prevNTSCScanlines;
7461 	static int prevAspectWidth;
7462 	static OutputMethod prevOutputMethod;
7463 	static TCHAR prevD3DShaderFile[MAX_PATH],prevOGLShaderFile[MAX_PATH];
7464 
7465 	switch(msg)
7466 	{
7467 
7468 	case WM_INITDIALOG:
7469     {
7470         WinRefreshDisplay();
7471 
7472         CreateToolTip(IDC_EMUFULLSCREEN, hDlg, TEXT("Emulate fullscreen by creating a window that spans the entire screen when going fullscreen"));
7473         CreateToolTip(IDC_AUTOFRAME, hDlg, TEXT("Try to achieve 50/60 fps by limiting the speed and skipping at most 'max skipped frames'"));
7474         CreateToolTip(IDC_MAXSKIP, hDlg, TEXT("Try to achieve 50/60 fps by limiting the speed and skipping at most 'max skipped frames'"));
7475         CreateToolTip(IDC_FIXEDSKIP, hDlg, TEXT("Always skip a fixed number of frames - no speed limit"));
7476         CreateToolTip(IDC_SKIPCOUNT, hDlg, TEXT("Always skip a fixed number of frames - no speed limit"));
7477         CreateToolTip(IDC_HIRES, hDlg, TEXT("Support the hi-res mode that a few games use, otherwise render them in low-res"));
7478         CreateToolTip(IDC_HEIGHT_EXTEND, hDlg, TEXT("Display an extra 15 pixels at the bottom, which few games use. Also increases AVI output size from 256x224 to 256x240"));
7479         CreateToolTip(IDC_MESSAGES_IN_IMAGE, hDlg, TEXT("Draw text inside the SNES image (will get into AVIs, screenshots, and filters)"));
7480 		CreateToolTip(IDC_MESSAGES_SCALE, hDlg, TEXT("Try to scale messages with EPX instead of Simple, only works for 2x and 3x and when displaying after filters"));
7481 
7482         prevOutputMethod = GUI.outputMethod;
7483         prevScale = GUI.Scale;
7484         prevScaleHiRes = GUI.ScaleHiRes;
7485         prevPPL = GFX.RealPPL;
7486         prevStretch = GUI.Stretch;
7487         prevBilinearFilter = Settings.BilinearFilter;
7488         prevAspectRatio = GUI.AspectRatio;
7489         prevAspectWidth = GUI.AspectWidth;
7490 		prevIntegerScaling = GUI.IntegerScaling;
7491         prevHeightExtend = GUI.HeightExtend;
7492         prevAutoDisplayMessages = Settings.AutoDisplayMessages != 0;
7493         prevShaderEnabled = GUI.shaderEnabled;
7494         prevBlendHires = GUI.BlendHiRes;
7495 		prevNTSCScanlines = GUI.NTSCScanlines;
7496 
7497         lstrcpy(prevD3DShaderFile, GUI.D3DshaderFileName);
7498         lstrcpy(prevOGLShaderFile, GUI.OGLshaderFileName);
7499 
7500         _stprintf(s, TEXT("Current: %dx%d %dbit %dHz"), GUI.FullscreenMode.width, GUI.FullscreenMode.height, GUI.FullscreenMode.depth, GUI.FullscreenMode.rate);
7501         SendDlgItemMessage(hDlg, IDC_CURRMODE, WM_SETTEXT, 0, (LPARAM)s);
7502 
7503         if (GUI.DoubleBuffered)
7504             SendDlgItemMessage(hDlg, IDC_DBLBUFFER, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7505         if (GUI.Vsync)
7506             SendDlgItemMessage(hDlg, IDC_VSYNC, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7507 		if (GUI.ReduceInputLag)
7508 			SendDlgItemMessage(hDlg, IDC_REDUCEINPUTLAG, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7509 		if (GUI.NTSCScanlines)
7510 			SendDlgItemMessage(hDlg, IDC_NTSCSCANLINES, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7511         SendDlgItemMessage(hDlg, IDC_FRAMERATESKIPSLIDER, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, 9));
7512         if (Settings.SkipFrames != AUTO_FRAMERATE)
7513             SendDlgItemMessage(hDlg, IDC_FRAMERATESKIPSLIDER, TBM_SETPOS, (WPARAM)true, (LPARAM)Settings.SkipFrames);
7514         EnableWindow(GetDlgItem(hDlg, IDC_TRANS), TRUE);
7515         if (Settings.Transparency)
7516             SendDlgItemMessage(hDlg, IDC_TRANS, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7517 
7518         if (GUI.BlendHiRes)
7519             SendDlgItemMessage(hDlg, IDC_HIRESBLEND, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7520         if (GUI.HeightExtend)
7521             SendDlgItemMessage(hDlg, IDC_HEIGHT_EXTEND, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7522         if (Settings.AutoDisplayMessages)
7523             SendDlgItemMessage(hDlg, IDC_MESSAGES_IN_IMAGE, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7524 		if (GUI.filterMessagFont)
7525 			SendDlgItemMessage(hDlg, IDC_MESSAGES_SCALE, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7526         if (Settings.SkipFrames == AUTO_FRAMERATE)
7527             SendDlgItemMessage(hDlg, IDC_AUTOFRAME, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7528         if (GUI.Stretch)
7529         {
7530             SendDlgItemMessage(hDlg, IDC_STRETCH, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7531         }
7532 
7533 		if (GUI.AspectRatio)
7534 			SendDlgItemMessage(hDlg, IDC_ASPECT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7535 
7536 		EnableWindow(GetDlgItem(hDlg, IDC_INTEGERSCALING), GUI.AspectRatio);
7537 
7538 		if (GUI.IntegerScaling)
7539 			SendDlgItemMessage(hDlg, IDC_INTEGERSCALING, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7540 
7541 		SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_ADDSTRING, 0, (LPARAM)TEXT("8:7"));
7542         SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_ADDSTRING, 0, (LPARAM)TEXT("4:3"));
7543         switch (GUI.AspectWidth) {
7544         case 256:
7545             SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_SETCURSEL, (WPARAM)0, 0);
7546             break;
7547         case 299:
7548             SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_SETCURSEL, (WPARAM)1, 0);
7549             break;
7550         default:
7551             SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom"));
7552             SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_SETCURSEL, (WPARAM)2, 0);
7553             break;
7554         }
7555 
7556         if (GUI.FullScreen || GUI.EmulatedFullscreen)
7557             SendDlgItemMessage(hDlg, IDC_FULLSCREEN, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7558         if (GUI.EmulateFullscreen)
7559             SendDlgItemMessage(hDlg, IDC_EMUFULLSCREEN, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7560         if (Settings.BilinearFilter)
7561             SendDlgItemMessage(hDlg, IDC_BILINEAR, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7562         if (Settings.DisplayFrameRate)
7563             SendDlgItemMessage(hDlg, IDC_SHOWFPS, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7564 
7565         if (Settings.SkipFrames == AUTO_FRAMERATE) {
7566             SendDlgItemMessage(hDlg, IDC_AUTOFRAME, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7567             EnableWindow(GetDlgItem(hDlg, IDC_SKIPCOUNT), FALSE);
7568         }
7569         else {
7570             SendDlgItemMessage(hDlg, IDC_FIXEDSKIP, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7571             EnableWindow(GetDlgItem(hDlg, IDC_MAXSKIP), FALSE);
7572         }
7573         SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP, UDM_SETRANGE, 0, MAKELPARAM((short)59, (short)0));
7574         SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP, UDM_SETPOS, 0, Settings.AutoMaxSkipFrames);
7575         SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP_FIXED, UDM_SETRANGE, 0, MAKELPARAM((short)59, (short)0));
7576         SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP_FIXED, UDM_SETPOS, 0, Settings.SkipFrames == AUTO_FRAMERATE ? 0 : Settings.SkipFrames);
7577 
7578         if (GUI.shaderEnabled) {
7579             SendDlgItemMessage(hDlg, IDC_SHADER_ENABLED, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
7580             EnableWindow(GetDlgItem(hDlg, IDC_SHADER_HLSL_FILE), TRUE);
7581             EnableWindow(GetDlgItem(hDlg, IDC_SHADER_HLSL_BROWSE), TRUE);
7582             EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_FILE), TRUE);
7583             EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_BROWSE), TRUE);
7584 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_PARAMETERS), TRUE);
7585         }
7586         SetDlgItemText(hDlg, IDC_SHADER_HLSL_FILE, GUI.D3DshaderFileName);
7587         SetDlgItemText(hDlg, IDC_SHADER_GLSL_FILE, GUI.OGLshaderFileName);
7588 
7589         lpfnOldWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, IDC_SHADER_GROUP), GWLP_WNDPROC, (LONG_PTR)GroupBoxCheckBoxTitle);
7590 
7591         EnableWindow(GetDlgItem(hDlg, IDC_ASPECT), GUI.Stretch);
7592 
7593         // add output method to droplist with itemdata set to their enum value
7594         int inserted_index = -1;
7595 #if DIRECTDRAW_SUPPORT
7596         inserted_index = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_ADDSTRING, 0, (LPARAM)TEXT("DirectDraw"));
7597         SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_SETITEMDATA, inserted_index, DIRECTDRAW);
7598 #endif
7599         inserted_index = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_ADDSTRING, 0, (LPARAM)TEXT("Direct3D"));
7600         SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_SETITEMDATA, inserted_index, DIRECT3D);
7601         inserted_index = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_ADDSTRING, 0, (LPARAM)TEXT("OpenGL"));
7602         SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_SETITEMDATA, inserted_index, OPENGL);
7603 
7604 		SelectOutputMethodInVideoDropdown(hDlg, GUI.outputMethod);
7605 
7606         // add all the GUI.Scale filters to the combo box
7607         for (int filter = 0; filter < (int)NUM_FILTERS; filter++)
7608         {
7609             strcpy(temp, GetFilterName((RenderFilter)filter));
7610             SendDlgItemMessageA(hDlg, IDC_FILTERBOX, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)temp);
7611         }
7612         for (int filter = 0, hiResPos = 0; filter < (int)NUM_FILTERS; filter++)
7613         {
7614             if (GetFilterHiResSupport((RenderFilter)filter))
7615             {
7616                 strcpy(temp, GetFilterName((RenderFilter)filter));
7617                 SendDlgItemMessageA(hDlg, IDC_FILTERBOX2, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)temp);
7618                 if (GUI.ScaleHiRes == filter)
7619                     SendDlgItemMessage(hDlg, IDC_FILTERBOX2, CB_SETCURSEL, (WPARAM)hiResPos, 0);
7620                 hiResPos++;
7621             }
7622         }
7623 
7624         SendDlgItemMessage(hDlg, IDC_FILTERBOX, CB_SETCURSEL, (WPARAM)GUI.Scale, 0);
7625 
7626         UpdateModeComboBox(GetDlgItem(hDlg, IDC_RESOLUTION));
7627 
7628         // have to start focus on something like this or Escape won't exit the dialog
7629         SetFocus(hDlg);
7630 
7631         break;
7632     }
7633 	case WM_CLOSE:
7634 	case WM_DESTROY:
7635 		break;
7636 	case WM_COMMAND:
7637 
7638 		switch(LOWORD(wParam))
7639 		{
7640 		case IDC_STRETCH:
7641 			// for some reason this screws up the fullscreen mode clipper if it happens before the refresh
7642 			if(IsDlgButtonChecked(hDlg, IDC_STRETCH)==BST_CHECKED)
7643 			{
7644 				EnableWindow(GetDlgItem(hDlg, IDC_ASPECT), TRUE);
7645 			}
7646 			else
7647 			{
7648 				EnableWindow(GetDlgItem(hDlg, IDC_ASPECT), FALSE);
7649 			}
7650 
7651 			GUI.Stretch = (bool)(IsDlgButtonChecked(hDlg,IDC_STRETCH)==BST_CHECKED);
7652 			// refresh screen, so the user can see the new mode
7653 			// (assuming the dialog box isn't completely covering the game window)
7654 			WinDisplayApplyChanges();
7655 
7656 			WinRefreshDisplay();
7657 			break;
7658 
7659 		case IDC_BILINEAR:
7660 
7661 			Settings.BilinearFilter = (bool)(IsDlgButtonChecked(hDlg,IDC_BILINEAR)==BST_CHECKED);
7662 
7663 			//// refresh screen, so the user can see the new stretch mode
7664 			WinDisplayApplyChanges();
7665 
7666 			WinRefreshDisplay();
7667 			break;
7668 
7669 		case IDC_MESSAGES_IN_IMAGE:
7670 		case IDC_MESSAGES_SCALE:
7671 			Settings.AutoDisplayMessages = (bool)(IsDlgButtonChecked(hDlg,IDC_MESSAGES_IN_IMAGE)==BST_CHECKED);
7672 			GUI.filterMessagFont = (bool)(IsDlgButtonChecked(hDlg, IDC_MESSAGES_SCALE) == BST_CHECKED);
7673 			if(Settings.AutoDisplayMessages)
7674 			{
7675 				if(!GFX.InfoString || !*GFX.InfoString){
7676 					GFX.InfoString = "Test message!";
7677 					GFX.InfoStringTimeout = 1;
7678 				}
7679 				S9xDisplayMessages(GFX.Screen, GFX.RealPPL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, 1);
7680 				EnableWindow(GetDlgItem(hDlg, IDC_MESSAGES_SCALE), FALSE);
7681 			}
7682 			else
7683 			{
7684 				EnableWindow(GetDlgItem(hDlg, IDC_MESSAGES_SCALE), TRUE);
7685 			}
7686 			// refresh screen, so the user can see the new mode
7687 			WinRefreshDisplay();
7688 			break;
7689 
7690 		case IDC_INTEGERSCALING:
7691 			GUI.IntegerScaling = (bool)(IsDlgButtonChecked(hDlg, IDC_INTEGERSCALING) == BST_CHECKED);
7692 			WinDisplayApplyChanges();
7693 			WinRefreshDisplay();
7694 			break;
7695 
7696 		case IDC_ASPECT:
7697 			GUI.AspectRatio = (bool)(IsDlgButtonChecked(hDlg,IDC_ASPECT)==BST_CHECKED);
7698 			EnableWindow(GetDlgItem(hDlg, IDC_INTEGERSCALING), GUI.AspectRatio);
7699 			// refresh screen, so the user can see the new mode
7700 			WinDisplayApplyChanges();
7701 
7702 			WinRefreshDisplay();
7703 			break;
7704 		case IDC_ASPECTDROP:
7705 			if(HIWORD(wParam)==CBN_SELCHANGE) {
7706 				int newsel = SendDlgItemMessage(hDlg,IDC_ASPECTDROP,CB_GETCURSEL,0,0);
7707 				switch(newsel) {
7708 					case 0:
7709 						GUI.AspectWidth = 256;
7710 						break;
7711 					case 1:
7712 						GUI.AspectWidth = 299;
7713 						break;
7714 					default:
7715 						GUI.AspectWidth = prevAspectWidth;
7716 						break;
7717 				}
7718 				WinDisplayApplyChanges();
7719 				WinRefreshDisplay();
7720 			}
7721 			break;
7722 
7723 		case IDC_HEIGHT_EXTEND:
7724 			GUI.HeightExtend = (bool)(IsDlgButtonChecked(hDlg,IDC_HEIGHT_EXTEND)==BST_CHECKED);
7725 			// refresh screen, so the user can see the new mode
7726 			WinDisplayApplyChanges();
7727 
7728 			WinRefreshDisplay();
7729 			break;
7730 
7731 		case IDC_NTSCSCANLINES:
7732 			GUI.NTSCScanlines = (bool)(IsDlgButtonChecked(hDlg, IDC_NTSCSCANLINES) == BST_CHECKED);
7733 			WinDisplayApplyChanges();
7734 			WinRefreshDisplay();
7735 			break;
7736 
7737 		case IDC_HIRESBLEND:
7738 			GUI.BlendHiRes = (bool)(IsDlgButtonChecked(hDlg,IDC_HIRESBLEND)==BST_CHECKED);
7739 			WinRefreshDisplay();
7740 			break;
7741 
7742 		case IDC_AUTOFRAME:
7743 			if(BN_CLICKED==HIWORD(wParam)||BN_DBLCLK==HIWORD(wParam))
7744 			{
7745 				EnableWindow(GetDlgItem(hDlg, IDC_MAXSKIP), TRUE);
7746 				EnableWindow(GetDlgItem(hDlg, IDC_SKIPCOUNT), FALSE);
7747 				return true;
7748 
7749 			}
7750 			break;
7751 		case IDC_FIXEDSKIP:
7752 			if(BN_CLICKED==HIWORD(wParam)||BN_DBLCLK==HIWORD(wParam))
7753 			{
7754 				EnableWindow(GetDlgItem(hDlg, IDC_MAXSKIP), FALSE);
7755 				EnableWindow(GetDlgItem(hDlg, IDC_SKIPCOUNT), TRUE);
7756 				return true;
7757 
7758 			}
7759 			break;
7760 		case IDC_OUTPUTMETHOD:
7761 			if(HIWORD(wParam)==CBN_SELCHANGE) {
7762                 int index = SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_GETCURSEL, 0, 0);
7763 				OutputMethod newOut = (OutputMethod)SendDlgItemMessage(hDlg, IDC_OUTPUTMETHOD, CB_GETITEMDATA, index, 0);
7764 				if(GUI.outputMethod==newOut)
7765 					break;
7766 				if(GUI.FullScreen)
7767 					ToggleFullScreen();
7768 				GUI.outputMethod=newOut;
7769 
7770 				WinDisplayReset();
7771 				UpdateModeComboBox(GetDlgItem(hDlg,IDC_RESOLUTION));
7772 				WinRefreshDisplay();
7773 				UpdateWindow(GUI.hWnd);
7774 			}
7775 			break;
7776 		case IDC_SHADER_ENABLED:
7777 			GUI.shaderEnabled = (bool)(IsDlgButtonChecked(hDlg,IDC_SHADER_ENABLED)==BST_CHECKED);
7778 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GROUP),GUI.shaderEnabled);
7779 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_HLSL_FILE),GUI.shaderEnabled);
7780 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_HLSL_BROWSE),GUI.shaderEnabled);
7781 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_FILE),GUI.shaderEnabled);
7782 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_BROWSE),GUI.shaderEnabled);
7783 			EnableWindow(GetDlgItem(hDlg, IDC_SHADER_GLSL_PARAMETERS), GUI.shaderEnabled);
7784 
7785 			GetDlgItemText(hDlg,IDC_SHADER_HLSL_FILE,GUI.D3DshaderFileName,MAX_PATH);
7786 			GetDlgItemText(hDlg,IDC_SHADER_GLSL_FILE,GUI.OGLshaderFileName,MAX_PATH);
7787 			WinDisplayApplyChanges();
7788 			WinRefreshDisplay();
7789 			break;
7790 		case IDC_SHADER_HLSL_BROWSE:
7791 			GetDlgItemText(hDlg,IDC_SHADER_HLSL_FILE,openFileName,MAX_PATH);
7792 			memset((LPVOID)&ofn, 0, sizeof(OPENFILENAME));
7793 
7794 			ofn.lStructSize = sizeof(OPENFILENAME);
7795 			ofn.hwndOwner = hDlg;
7796 			ofn.lpstrFilter = TEXT("Shader Files\0*.shader;*.cg;*.cgp\0All Files\0*.*\0\0");
7797 			ofn.lpstrFile = openFileName;
7798 			ofn.lpstrTitle = TEXT("Select Shader");
7799 			ofn.lpstrDefExt = TEXT("shader");
7800 			ofn.nMaxFile = MAX_PATH;
7801 			ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
7802 			if(GetOpenFileName(&ofn)) {
7803 				SetDlgItemText(hDlg,IDC_SHADER_HLSL_FILE,openFileName);
7804 				lstrcpy(GUI.D3DshaderFileName,openFileName);
7805 				WinDisplayApplyChanges();
7806 				WinRefreshDisplay();
7807 			}
7808 			break;
7809 		case IDC_SHADER_GLSL_BROWSE:
7810 			GetDlgItemText(hDlg,IDC_SHADER_GLSL_FILE,openFileName,MAX_PATH);
7811 			memset((LPVOID)&ofn, 0, sizeof(OPENFILENAME));
7812 
7813 			ofn.lStructSize = sizeof(OPENFILENAME);
7814 			ofn.hwndOwner = hDlg;
7815 			ofn.lpstrFilter = TEXT("Shader Files\0*.shader;*.cg;*.cgp;*.glsl;*.glslp;*.slang;*.slangp\0All Files\0*.*\0\0");
7816 			ofn.lpstrFile = openFileName;
7817 			ofn.lpstrTitle = TEXT("Select Shader");
7818 			ofn.lpstrDefExt = TEXT("shader");
7819 			ofn.nMaxFile = MAX_PATH;
7820 			ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
7821 			if(GetOpenFileName(&ofn)) {
7822 				SetDlgItemText(hDlg,IDC_SHADER_GLSL_FILE,openFileName);
7823 				lstrcpy(GUI.OGLshaderFileName,openFileName);
7824 				WinDisplayApplyChanges();
7825 				WinRefreshDisplay();
7826 			}
7827 			break;
7828         case IDC_SHADER_GLSL_PARAMETERS:
7829         {
7830             GetDlgItemText(hDlg, IDC_SHADER_GLSL_FILE, GUI.OGLshaderFileName, MAX_PATH);
7831 			int len = lstrlen(GUI.OGLshaderFileName);
7832             if((len < 6 || _tcsncicmp(&GUI.OGLshaderFileName[len - 6], TEXT(".glslp"), 6)) &&
7833 			   (len < 7 || _tcsncicmp(&GUI.OGLshaderFileName[len - 7], TEXT(".slangp"), 7))) {
7834                 MessageBox(GUI.hWnd, TEXT("Parameters are only supported for .glslp and .slangp shaders"), TEXT("No Parameters"), MB_OK | MB_ICONINFORMATION);
7835                 break;
7836             }
7837 			ShowWindow(hDlg, SW_HIDE);
7838 			WinDisplayApplyChanges();
7839 			WinRefreshDisplay();
7840 			GLSLShader *shader = WinGetActiveGLSLShader();
7841 			if (shader) {
7842 				CShaderParamDlg dlg(*shader);
7843 				if (dlg.show()) {
7844 					SetDlgItemText(hDlg, IDC_SHADER_GLSL_FILE, GUI.OGLshaderFileName);
7845 					WinDisplayApplyChanges();
7846 					WinRefreshDisplay();
7847 				}
7848 			}
7849 			ShowWindow(hDlg, SW_SHOW);
7850             break;
7851         }
7852 		case IDC_FILTERBOX:
7853 			if(HIWORD(wParam)==CBN_SELCHANGE) {
7854 				int scale = (int)SendDlgItemMessage(hDlg,IDC_FILTERBOX,CB_GETCURSEL,0,0);
7855 				if(scale == GUI.Scale)
7856 					break;
7857 
7858 				const int oldScaleScale = max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes));
7859 
7860 //				UpdateScale(GUI.Scale, scale);
7861 				GUI.Scale = (RenderFilter)scale;
7862 
7863 
7864 				const int newScaleScale = max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes));
7865 
7866 				if(oldScaleScale != newScaleScale)
7867 					RestoreSNESDisplay();
7868 
7869 				// refresh screen, so the user can see the new filter
7870 				// (assuming the dialog box isn't completely covering the game window)
7871 				WinRefreshDisplay();
7872 
7873 				// set hi-res combo box to match the lo-res output filter as best as possible
7874 //				if(GetFilterHiResSupport(GUI.Scale))
7875 checkUpdateFilterBox2:
7876 				{
7877 					char textOriginal [256];
7878 					SendMessageA(GetDlgItem(hDlg, IDC_FILTERBOX), WM_GETTEXT, 256,(LPARAM)textOriginal);
7879 					int count = SendDlgItemMessage(hDlg,IDC_FILTERBOX2,CB_GETCOUNT,0,0);
7880 //					int scale = GUI.Scale;
7881 					bool switched = false;
7882 					for(int j=0; j<2 && !switched; j++){
7883 						if(j){
7884 							RenderFilter filter; // no match, set default for chosen scale
7885 							switch(GetFilterScale(GUI.Scale)){
7886 								case 1: filter = FILTER_SIMPLE1X; break;
7887 					   default: case 2: filter = FILTER_SIMPLE2X; break;
7888 								case 3: filter = FILTER_SIMPLE3X; break;
7889 								case 4: filter = FILTER_SIMPLE4X; break;
7890 								case 5: case 6: filter = FILTER_SIMPLE4X; break;
7891 							}
7892 							strcpy(textOriginal, GetFilterName(filter));
7893 						}
7894 						for(int i=0; i<count && !switched; i++){
7895 							int textLen = SendDlgItemMessageA(hDlg,IDC_FILTERBOX2,CB_GETLBTEXTLEN,(WPARAM)i,0);
7896 							char* text = new char[textLen+1];
7897 							SendDlgItemMessageA(hDlg,IDC_FILTERBOX2,CB_GETLBTEXT,(WPARAM)i,(LPARAM)text);
7898 							if(!stricmp(textOriginal, text)){
7899 								SendDlgItemMessageA(hDlg,IDC_FILTERBOX2,CB_SETCURSEL,(WPARAM)i,0);
7900 								switched = true;
7901 							}
7902 							delete[] text;
7903 						}
7904 					}
7905 					goto updateFilterBox2;
7906 				}
7907 			}
7908 			break;
7909 		case IDC_FILTERBOX2: // hi-res
7910 updateFilterBox2:
7911 			{
7912 				char text [256];
7913 				text[0] = '\0';
7914 				SendMessageA(GetDlgItem(hDlg, IDC_FILTERBOX2), WM_GETTEXT, 256,(LPARAM)text);
7915 
7916 				int scale = GUI.Scale;
7917 				for(int i=0; i<NUM_FILTERS; i++)
7918 					if(!stricmp(GetFilterName((RenderFilter)i), text))
7919 						scale = i;
7920 
7921 				if(scale == GUI.ScaleHiRes)
7922 					break;
7923 
7924 				const int oldScaleScale = max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes));
7925 
7926 //				UpdateScale(GUI.Scale, scale);
7927 				GUI.ScaleHiRes = (RenderFilter)scale;
7928 
7929 				const int newScaleScale = max(GetFilterScale(GUI.Scale), GetFilterScale(GUI.ScaleHiRes));
7930 
7931 				if(oldScaleScale != newScaleScale)
7932 					RestoreSNESDisplay();
7933 
7934 				// refresh screen, so the user can see the new filter
7935 				// (assuming the dialog box isn't completely covering the game window)
7936 				WinRefreshDisplay();
7937 			}
7938 			break;
7939 
7940 		case IDOK:
7941 			bool fullscreenWanted;
7942  			Settings.Transparency = IsDlgButtonChecked(hDlg, IDC_TRANS);
7943 			Settings.BilinearFilter = (bool)(IsDlgButtonChecked(hDlg,IDC_BILINEAR)==BST_CHECKED);
7944 			GUI.HeightExtend = IsDlgButtonChecked(hDlg, IDC_HEIGHT_EXTEND)!=0;
7945 			Settings.AutoDisplayMessages = IsDlgButtonChecked(hDlg, IDC_MESSAGES_IN_IMAGE);
7946 			GUI.filterMessagFont = IsDlgButtonChecked(hDlg, IDC_MESSAGES_SCALE);
7947 			GUI.DoubleBuffered = (bool)(IsDlgButtonChecked(hDlg, IDC_DBLBUFFER)==BST_CHECKED);
7948 			GUI.ReduceInputLag = (bool)(IsDlgButtonChecked(hDlg, IDC_REDUCEINPUTLAG) == BST_CHECKED);
7949 			GUI.Vsync = (bool)(IsDlgButtonChecked(hDlg, IDC_VSYNC
7950 
7951 				)==BST_CHECKED);
7952 			if(IsDlgButtonChecked(hDlg, IDC_AUTOFRAME))
7953 			{
7954 				Settings.SkipFrames=AUTO_FRAMERATE;
7955 				Settings.AutoMaxSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP, UDM_GETPOS, 0,0);
7956 			}
7957 			else
7958 			{
7959 				Settings.SkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP_DISP_FIXED, UDM_GETPOS, 0,0);
7960 			}
7961 
7962 
7963 			GUI.Stretch = (bool)(IsDlgButtonChecked(hDlg, IDC_STRETCH)==BST_CHECKED);
7964 			GUI.AspectRatio = (bool)(IsDlgButtonChecked(hDlg, IDC_ASPECT)==BST_CHECKED);
7965 			GUI.IntegerScaling = (bool)(IsDlgButtonChecked(hDlg, IDC_INTEGERSCALING) == BST_CHECKED);
7966 			fullscreenWanted = (bool)(IsDlgButtonChecked(hDlg, IDC_FULLSCREEN)==BST_CHECKED);
7967 			GUI.EmulateFullscreen = (bool)(IsDlgButtonChecked(hDlg, IDC_EMUFULLSCREEN)==BST_CHECKED);
7968 			Settings.DisplayFrameRate = IsDlgButtonChecked(hDlg, IDC_SHOWFPS);
7969 			GUI.BlendHiRes = (bool)(IsDlgButtonChecked(hDlg, IDC_HIRESBLEND)==BST_CHECKED);
7970 
7971 			index = ComboBox_GetCurSel(GetDlgItem(hDlg,IDC_RESOLUTION));
7972 
7973 			GUI.FullscreenMode = dm[index];
7974 
7975 			GetDlgItemText(hDlg,IDC_SHADER_HLSL_FILE,GUI.D3DshaderFileName,MAX_PATH);
7976 
7977 
7978 			// we might've changed the region that the game draws over
7979 			// (by turning on "maintain aspect ratio", or turning on "extend height" when "maintain aspect ratio" is already on),
7980 			// so we must invalidate the window to redraw black
7981 			// behind the possibly-newly-revealed areas of the window
7982 			RedrawWindow((HWND)GetParent(hDlg),NULL,NULL, RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ERASENOW);
7983 
7984 			WinSaveConfigFile();
7985 
7986 			if(GUI.FullScreen && (GUI.FullscreenMode.width < 512 || GUI.FullscreenMode.height < 478))
7987 				GUI.Scale = FILTER_NONE;
7988 
7989 			if(GUI.FullScreen && (GUI.FullscreenMode.width < 512 || GUI.FullscreenMode.height < 478))
7990 				GUI.ScaleHiRes = FILTER_SIMPLE1X;
7991 
7992 			EndDialog(hDlg,0);
7993 			WinDisplayApplyChanges();
7994 
7995 			// if we are emulating fullscreen and now want to change to regular fullscreen
7996 			// we want to switch back to the last window size
7997 			if(fullscreenWanted && GUI.EmulatedFullscreen && !GUI.EmulateFullscreen) {
7998 				GUI.EmulateFullscreen = true;
7999 				ToggleFullScreen();
8000 				GUI.EmulateFullscreen = false;
8001 			}
8002 			if(fullscreenWanted != GUI.EmulatedFullscreen) {
8003 				ToggleFullScreen();
8004 			}
8005 
8006 
8007 			return false;
8008 
8009 
8010 
8011 		case IDCANCEL:
8012 			SelectOutputMethodInVideoDropdown(hDlg, prevOutputMethod);
8013 			SendMessage(hDlg,WM_COMMAND,MAKEWPARAM(IDC_OUTPUTMETHOD,CBN_SELCHANGE),0);
8014 
8015 			{
8016 				//UpdateScale(GUI.Scale, prevScale);
8017 				GUI.Scale = (RenderFilter)prevScale;
8018 				GUI.ScaleHiRes = (RenderFilter)prevScaleHiRes;
8019 				GFX.RealPPL = prevPPL;
8020 				GUI.Stretch = prevStretch;
8021 				Settings.AutoDisplayMessages = prevAutoDisplayMessages;
8022 				Settings.BilinearFilter = prevBilinearFilter;
8023 				GUI.AspectRatio = prevAspectRatio;
8024 				GUI.AspectWidth = prevAspectWidth;
8025 				GUI.IntegerScaling = prevIntegerScaling;
8026 				GUI.HeightExtend = prevHeightExtend;
8027 				GUI.shaderEnabled = prevShaderEnabled;
8028 				GUI.BlendHiRes = prevBlendHires;
8029 				GUI.NTSCScanlines = prevNTSCScanlines;
8030 				lstrcpy(GUI.D3DshaderFileName,prevD3DShaderFile);
8031 				lstrcpy(GUI.OGLshaderFileName,prevOGLShaderFile);
8032 			}
8033 
8034 			EndDialog(hDlg,0);
8035 
8036 			return false;
8037 		}
8038 
8039 
8040 	}
8041 
8042 	return false;
8043 }
8044 
set_buttoninfo(int index,HWND hDlg)8045 static void set_buttoninfo(int index, HWND hDlg)
8046 {
8047 	SendDlgItemMessage(hDlg,IDC_UP,WM_USER+44,Joypad[index].Up,0);
8048 	SendDlgItemMessage(hDlg,IDC_LEFT,WM_USER+44,Joypad[index].Left,0);
8049 	SendDlgItemMessage(hDlg,IDC_DOWN,WM_USER+44,Joypad[index].Down,0);
8050 	SendDlgItemMessage(hDlg,IDC_RIGHT,WM_USER+44,Joypad[index].Right,0);
8051 	SendDlgItemMessage(hDlg,IDC_A,WM_USER+44,Joypad[index].A,0);
8052 	SendDlgItemMessage(hDlg,IDC_B,WM_USER+44,Joypad[index].B,0);
8053 	SendDlgItemMessage(hDlg,IDC_X,WM_USER+44,Joypad[index].X,0);
8054 	SendDlgItemMessage(hDlg,IDC_Y,WM_USER+44,Joypad[index].Y,0);
8055 	SendDlgItemMessage(hDlg,IDC_L,WM_USER+44,Joypad[index].L,0);
8056 	SendDlgItemMessage(hDlg,IDC_R,WM_USER+44,Joypad[index].R,0);
8057 	SendDlgItemMessage(hDlg,IDC_START,WM_USER+44,Joypad[index].Start,0);
8058 	SendDlgItemMessage(hDlg,IDC_SELECT,WM_USER+44,Joypad[index].Select,0);
8059 	if(index < 5)
8060 	{
8061 		SendDlgItemMessage(hDlg,IDC_UPLEFT,WM_USER+44,Joypad[index].Left_Up,0);
8062 		SendDlgItemMessage(hDlg,IDC_UPRIGHT,WM_USER+44,Joypad[index].Right_Up,0);
8063 		SendDlgItemMessage(hDlg,IDC_DWNLEFT,WM_USER+44,Joypad[index].Left_Down,0);
8064 		SendDlgItemMessage(hDlg,IDC_DWNRIGHT,WM_USER+44,Joypad[index].Right_Down,0);
8065 	}
8066 }
8067 
8068 void TranslateKey(WORD keyz,char *out);
8069 //HWND funky;
8070 SJoyState JoystickF [16];
8071 
8072 
8073 #ifdef NETPLAY_SUPPORT
DlgNPProgress(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)8074 INT_PTR CALLBACK DlgNPProgress(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
8075 {
8076 	SendDlgItemMessage(hDlg,IDC_NPPROGRESS,PBM_SETRANGE,0,(LPARAM)MAKELPARAM (0, 100));
8077 	SendDlgItemMessage(hDlg,IDC_NPPROGRESS,PBM_SETPOS,(WPARAM)(int)NetPlay.PercentageComplete,0);
8078 
8079 	return false;
8080 }
8081 #endif
DlgInputConfig(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)8082 INT_PTR CALLBACK DlgInputConfig(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
8083 {
8084 	TCHAR temp[256];
8085 	short C;
8086 	int i, which;
8087 	static int index=0;
8088 
8089 
8090 	static SJoypad pads[10];
8091 
8092 
8093 	//HBRUSH g_hbrBackground;
8094 
8095 	InitInputCustomControl();
8096 switch(msg)
8097 	{
8098 		case WM_PAINT:
8099 		{
8100 			PAINTSTRUCT ps;
8101 			BeginPaint (hDlg, &ps);
8102 
8103 			EndPaint (hDlg, &ps);
8104 		}
8105 		return true;
8106 	case WM_INITDIALOG:
8107 		WinRefreshDisplay();
8108 		SetWindowText(hDlg,INPUTCONFIG_TITLE);
8109 		SetDlgItemText(hDlg,IDC_JPTOGGLE,INPUTCONFIG_JPTOGGLE);
8110 		SetDlgItemText(hDlg,IDC_OK,BUTTON_OK);
8111 		SetDlgItemText(hDlg,IDC_CANCEL,BUTTON_CANCEL);
8112 		SetDlgItemText(hDlg,IDC_LABEL_UP,INPUTCONFIG_LABEL_UP);
8113 		SetDlgItemText(hDlg,IDC_LABEL_DOWN,INPUTCONFIG_LABEL_DOWN);
8114 		SetDlgItemText(hDlg,IDC_LABEL_LEFT,INPUTCONFIG_LABEL_LEFT);
8115 		SetDlgItemText(hDlg,IDC_LABEL_A,INPUTCONFIG_LABEL_A);
8116 		SetDlgItemText(hDlg,IDC_LABEL_B,INPUTCONFIG_LABEL_B);
8117 		SetDlgItemText(hDlg,IDC_LABEL_X,INPUTCONFIG_LABEL_X);
8118 		SetDlgItemText(hDlg,IDC_LABEL_Y,INPUTCONFIG_LABEL_Y);
8119 		SetDlgItemText(hDlg,IDC_LABEL_L,INPUTCONFIG_LABEL_L);
8120 		SetDlgItemText(hDlg,IDC_LABEL_R,INPUTCONFIG_LABEL_R);
8121 		SetDlgItemText(hDlg,IDC_LABEL_START,INPUTCONFIG_LABEL_START);
8122 		SetDlgItemText(hDlg,IDC_LABEL_SELECT,INPUTCONFIG_LABEL_SELECT);
8123 		SetDlgItemText(hDlg,IDC_LABEL_UPRIGHT,INPUTCONFIG_LABEL_UPRIGHT);
8124 		SetDlgItemText(hDlg,IDC_LABEL_UPLEFT,INPUTCONFIG_LABEL_UPLEFT);
8125 		SetDlgItemText(hDlg,IDC_LABEL_DOWNRIGHT,INPUTCONFIG_LABEL_DOWNRIGHT);
8126 		SetDlgItemText(hDlg,IDC_LABEL_DOWNLEFT,INPUTCONFIG_LABEL_DOWNLEFT);
8127 		SetDlgItemText(hDlg,IDC_LABEL_BLUE,INPUTCONFIG_LABEL_BLUE);
8128 
8129 		for(i=5;i<10;i++)
8130 			Joypad[i].Left_Up = Joypad[i].Right_Up = Joypad[i].Left_Down = Joypad[i].Right_Down = 0;
8131 
8132 		memcpy(pads, Joypad, 10*sizeof(SJoypad));
8133 
8134 		for( i=0;i<256;i++)
8135 			GetAsyncKeyState(i);
8136 
8137 		for( C = 0; C != 16; C ++)
8138 	        JoystickF[C].Attached = joyGetDevCaps( JOYSTICKID1+C, &JoystickF[C].Caps, sizeof( JOYCAPS)) == JOYERR_NOERROR;
8139 
8140 		for(i=1;i<6;i++)
8141 		{
8142 			_stprintf(temp,INPUTCONFIG_JPCOMBO,i);
8143 			SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)temp);
8144 		}
8145 
8146 		for(i=6;i<11;i++)
8147 		{
8148 			_stprintf(temp,INPUTCONFIG_JPCOMBO INPUTCONFIG_LABEL_CONTROLLER_TURBO_PANEL_MOD,i-5);
8149 			SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)temp);
8150 		}
8151 
8152 		SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_SETCURSEL,(WPARAM)0,0);
8153 
8154 		SendDlgItemMessage(hDlg,IDC_JPTOGGLE,BM_SETCHECK, Joypad[index].Enabled ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
8155 		SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, Settings.UpAndDown ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
8156 
8157 		set_buttoninfo(index,hDlg);
8158 
8159 		EnableDisableKeyFields(index,hDlg);
8160 
8161 		PostMessage(hDlg,WM_COMMAND, CBN_SELCHANGE<<16, 0);
8162 
8163 		SetFocus(GetDlgItem(hDlg,IDC_JPCOMBO));
8164 
8165 		return true;
8166 		break;
8167 	case WM_CLOSE:
8168 		EndDialog(hDlg, 0);
8169 		return TRUE;
8170 	case WM_USER+46:
8171 		// refresh command, for clicking away from a selected field
8172 		index = SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_GETCURSEL,0,0);
8173 		if(index > 4) index += 3; // skip controllers 6, 7, and 8 in the input dialog
8174 		set_buttoninfo(index,hDlg);
8175 		return TRUE;
8176 	case WM_USER+43:
8177 		//MessageBox(hDlg,"USER+43 CAUGHT","moo",MB_OK);
8178 		which = GetDlgCtrlID((HWND)lParam);
8179 		switch(which)
8180 		{
8181 		case IDC_UP:
8182 			Joypad[index].Up = wParam;
8183 
8184 			break;
8185 		case IDC_DOWN:
8186 			Joypad[index].Down = wParam;
8187 
8188 			break;
8189 		case IDC_LEFT:
8190 			Joypad[index].Left = wParam;
8191 
8192 			break;
8193 		case IDC_RIGHT:
8194 			Joypad[index].Right = wParam;
8195 
8196 			break;
8197 		case IDC_A:
8198 			Joypad[index].A = wParam;
8199 
8200 			break;
8201 		case IDC_B:
8202 			Joypad[index].B = wParam;
8203 
8204 			break;
8205 		case IDC_X:
8206 			Joypad[index].X = wParam;
8207 
8208 			break;
8209 		case IDC_Y:
8210 			Joypad[index].Y = wParam;
8211 
8212 			break;
8213 		case IDC_L:
8214 			Joypad[index].L = wParam;
8215 			break;
8216 
8217 		case IDC_R:
8218 			Joypad[index].R = wParam;
8219 
8220 			break;
8221 		case IDC_SELECT:
8222 			Joypad[index].Select = wParam;
8223 
8224 			break;
8225 		case IDC_START:
8226 			Joypad[index].Start = wParam;
8227 
8228 			break;
8229 		case IDC_UPLEFT:
8230 			Joypad[index].Left_Up = wParam;
8231 
8232 			break;
8233 		case IDC_UPRIGHT:
8234 			Joypad[index].Right_Up = wParam;
8235 
8236 			break;
8237 		case IDC_DWNLEFT:
8238 			Joypad[index].Left_Down = wParam;
8239 
8240             break;
8241 		case IDC_DWNRIGHT:
8242 			Joypad[index].Right_Down = wParam;
8243 
8244 			break;
8245 
8246 		}
8247 
8248 		set_buttoninfo(index,hDlg);
8249 
8250 		PostMessage(hDlg,WM_NEXTDLGCTL,0,0);
8251 		return true;
8252 	case WM_COMMAND:
8253 		switch(LOWORD(wParam))
8254 		{
8255 		case IDCANCEL:
8256 			memcpy(Joypad, pads, 10*sizeof(SJoypad));
8257 			EndDialog(hDlg,0);
8258 			break;
8259 
8260 		case IDOK:
8261 			Settings.UpAndDown = IsDlgButtonChecked(hDlg, IDC_ALLOWLEFTRIGHT);
8262 			WinSaveConfigFile();
8263 			EndDialog(hDlg,0);
8264 			break;
8265 
8266 		case IDC_JPTOGGLE: // joypad Enable toggle
8267 			index = SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_GETCURSEL,0,0);
8268 			if(index > 4) index += 3; // skip controllers 6, 7, and 8 in the input dialog
8269 			Joypad[index].Enabled=IsDlgButtonChecked(hDlg,IDC_JPTOGGLE);
8270 			set_buttoninfo(index, hDlg); // update display of conflicts
8271 			break;
8272 
8273 		}
8274 		switch(HIWORD(wParam))
8275 		{
8276 			case CBN_SELCHANGE:
8277 				index = SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_GETCURSEL,0,0);
8278 				SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_SETCURSEL,(WPARAM)index,0);
8279 				if(index > 4) index += 3; // skip controllers 6, 7, and 8 in the input dialog
8280 				if(index < 8)
8281 				{
8282 					SendDlgItemMessage(hDlg,IDC_JPTOGGLE,BM_SETCHECK, Joypad[index].Enabled ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
8283 					EnableWindow(GetDlgItem(hDlg,IDC_JPTOGGLE),TRUE);
8284 				}
8285 				else
8286 				{
8287 					SendDlgItemMessage(hDlg,IDC_JPTOGGLE,BM_SETCHECK, Joypad[index-8].Enabled ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
8288 					EnableWindow(GetDlgItem(hDlg,IDC_JPTOGGLE),FALSE);
8289 				}
8290 
8291 				set_buttoninfo(index,hDlg);
8292 
8293 				EnableDisableKeyFields(index,hDlg);
8294 
8295 				break;
8296 		}
8297 		return FALSE;
8298 
8299 	}
8300 
8301 	return FALSE;
8302 }
8303 
8304 
set_hotkeyinfo(HWND hDlg)8305 static void set_hotkeyinfo(HWND hDlg)
8306 {
8307 	int index = SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_GETCURSEL,0,0);
8308 
8309 	switch(index)
8310 	{
8311 	case 0:
8312 		// set page 1 fields
8313 		SendDlgItemMessage(hDlg,IDC_HOTKEY1,WM_USER+44,CustomKeys.SpeedUp.key,CustomKeys.SpeedUp.modifiers);
8314 		SendDlgItemMessage(hDlg,IDC_HOTKEY2,WM_USER+44,CustomKeys.SpeedDown.key,CustomKeys.SpeedDown.modifiers);
8315 		SendDlgItemMessage(hDlg,IDC_HOTKEY3,WM_USER+44,CustomKeys.Pause.key,CustomKeys.Pause.modifiers);
8316 		SendDlgItemMessage(hDlg,IDC_HOTKEY4,WM_USER+44,CustomKeys.FrameAdvance.key,CustomKeys.FrameAdvance.modifiers);
8317 		SendDlgItemMessage(hDlg,IDC_HOTKEY5,WM_USER+44,CustomKeys.FastForward.key,CustomKeys.FastForward.modifiers);
8318 		SendDlgItemMessage(hDlg,IDC_HOTKEY6,WM_USER+44,CustomKeys.SkipUp.key,CustomKeys.SkipUp.modifiers);
8319 		SendDlgItemMessage(hDlg,IDC_HOTKEY7,WM_USER+44,CustomKeys.SkipDown.key,CustomKeys.SkipDown.modifiers);
8320 		SendDlgItemMessage(hDlg,IDC_HOTKEY8,WM_USER+44,CustomKeys.ScopeTurbo.key,CustomKeys.ScopeTurbo.modifiers);
8321 		SendDlgItemMessage(hDlg,IDC_HOTKEY9,WM_USER+44,CustomKeys.ScopePause.key,CustomKeys.ScopePause.modifiers);
8322 		SendDlgItemMessage(hDlg,IDC_HOTKEY10,WM_USER+44,CustomKeys.ShowPressed.key,CustomKeys.ShowPressed.modifiers);
8323 		SendDlgItemMessage(hDlg,IDC_HOTKEY11,WM_USER+44,CustomKeys.FrameCount.key,CustomKeys.FrameCount.modifiers);
8324 		SendDlgItemMessage(hDlg,IDC_HOTKEY12,WM_USER+44,CustomKeys.ReadOnly.key,CustomKeys.ReadOnly.modifiers);
8325 		SendDlgItemMessage(hDlg,IDC_HOTKEY13,WM_USER+44,CustomKeys.SaveScreenShot.key,CustomKeys.SaveScreenShot.modifiers);
8326 		break;
8327 	case 1:
8328 		SendDlgItemMessage(hDlg,IDC_HOTKEY1,WM_USER+44,CustomKeys.BGL1.key,CustomKeys.BGL1.modifiers);
8329 		SendDlgItemMessage(hDlg,IDC_HOTKEY2,WM_USER+44,CustomKeys.BGL2.key,CustomKeys.BGL2.modifiers);
8330 		SendDlgItemMessage(hDlg,IDC_HOTKEY3,WM_USER+44,CustomKeys.BGL3.key,CustomKeys.BGL3.modifiers);
8331 		SendDlgItemMessage(hDlg,IDC_HOTKEY4,WM_USER+44,CustomKeys.BGL4.key,CustomKeys.BGL4.modifiers);
8332 		SendDlgItemMessage(hDlg,IDC_HOTKEY5,WM_USER+44,CustomKeys.BGL5.key,CustomKeys.BGL5.modifiers);
8333 		SendDlgItemMessage(hDlg,IDC_HOTKEY6,WM_USER+44,CustomKeys.ClippingWindows.key,CustomKeys.ClippingWindows.modifiers);
8334 		SendDlgItemMessage(hDlg,IDC_HOTKEY7,WM_USER+44,CustomKeys.Transparency.key,CustomKeys.Transparency.modifiers);
8335 		SendDlgItemMessage(hDlg,IDC_HOTKEY8,WM_USER+44,CustomKeys.FastForwardToggle.key,CustomKeys.FastForwardToggle.modifiers);
8336 		SendDlgItemMessage(hDlg,IDC_HOTKEY9,WM_USER+44,CustomKeys.Rewind.key,CustomKeys.Rewind.modifiers);
8337 		SendDlgItemMessage(hDlg,IDC_HOTKEY10,WM_USER+44,CustomKeys.SwitchControllers.key,CustomKeys.SwitchControllers.modifiers);
8338 		SendDlgItemMessage(hDlg,IDC_HOTKEY11,WM_USER+44,CustomKeys.JoypadSwap.key,CustomKeys.JoypadSwap.modifiers);
8339 		SendDlgItemMessage(hDlg,IDC_HOTKEY12,WM_USER+44,CustomKeys.ResetGame.key,CustomKeys.ResetGame.modifiers);
8340 		SendDlgItemMessage(hDlg,IDC_HOTKEY13,WM_USER+44,CustomKeys.ToggleCheats.key,CustomKeys.ToggleCheats.modifiers);
8341 		break;
8342 	case 2:
8343 		SendDlgItemMessage(hDlg,IDC_HOTKEY1,WM_USER+44,CustomKeys.TurboA.key,CustomKeys.TurboA.modifiers);
8344 		SendDlgItemMessage(hDlg,IDC_HOTKEY2,WM_USER+44,CustomKeys.TurboB.key,CustomKeys.TurboB.modifiers);
8345 		SendDlgItemMessage(hDlg,IDC_HOTKEY3,WM_USER+44,CustomKeys.TurboY.key,CustomKeys.TurboY.modifiers);
8346 		SendDlgItemMessage(hDlg,IDC_HOTKEY4,WM_USER+44,CustomKeys.TurboX.key,CustomKeys.TurboX.modifiers);
8347 		SendDlgItemMessage(hDlg,IDC_HOTKEY5,WM_USER+44,CustomKeys.TurboL.key,CustomKeys.TurboL.modifiers);
8348 		SendDlgItemMessage(hDlg,IDC_HOTKEY6,WM_USER+44,CustomKeys.TurboR.key,CustomKeys.TurboR.modifiers);
8349 		SendDlgItemMessage(hDlg,IDC_HOTKEY7,WM_USER+44,CustomKeys.TurboStart.key,CustomKeys.TurboStart.modifiers);
8350 		SendDlgItemMessage(hDlg,IDC_HOTKEY8,WM_USER+44,CustomKeys.TurboSelect.key,CustomKeys.TurboSelect.modifiers);
8351 		SendDlgItemMessage(hDlg,IDC_HOTKEY9,WM_USER+44,CustomKeys.TurboLeft.key,CustomKeys.TurboLeft.modifiers);
8352 		SendDlgItemMessage(hDlg,IDC_HOTKEY10,WM_USER+44,CustomKeys.TurboUp.key,CustomKeys.TurboUp.modifiers);
8353 		SendDlgItemMessage(hDlg,IDC_HOTKEY11,WM_USER+44,CustomKeys.TurboRight.key,CustomKeys.TurboRight.modifiers);
8354 		SendDlgItemMessage(hDlg,IDC_HOTKEY12,WM_USER+44,CustomKeys.TurboDown.key,CustomKeys.TurboDown.modifiers);
8355 		SendDlgItemMessage(hDlg,IDC_HOTKEY13,WM_USER+44, CustomKeys.Mute.key, CustomKeys.Mute.modifiers);
8356 		break;
8357 	case 3:
8358 		for(int i = 0 ; i < 10 ; i++)
8359 			SendDlgItemMessage(hDlg,IDC_HOTKEY1+i,WM_USER+44,CustomKeys.SelectSave[i].key,CustomKeys.SelectSave[i].modifiers);
8360 		SendDlgItemMessage(hDlg,IDC_HOTKEY11,WM_USER+44, CustomKeys.SaveFileSelect.key, CustomKeys.SaveFileSelect.modifiers);
8361 		SendDlgItemMessage(hDlg,IDC_HOTKEY12,WM_USER+44, CustomKeys.LoadFileSelect.key, CustomKeys.LoadFileSelect.modifiers);
8362 		SendDlgItemMessage(hDlg,IDC_HOTKEY13,WM_USER+44,CustomKeys.QuitS9X.key,CustomKeys.QuitS9X.modifiers);
8363 		break;
8364 	}
8365 
8366 	SendDlgItemMessage(hDlg,IDC_SLOTPLUS,WM_USER+44,CustomKeys.SlotPlus.key,CustomKeys.SlotPlus.modifiers);
8367 	SendDlgItemMessage(hDlg,IDC_SLOTMINUS,WM_USER+44,CustomKeys.SlotMinus.key,CustomKeys.SlotMinus.modifiers);
8368 	SendDlgItemMessage(hDlg,IDC_SLOTSAVE,WM_USER+44,CustomKeys.SlotSave.key,CustomKeys.SlotSave.modifiers);
8369 	SendDlgItemMessage(hDlg,IDC_SLOTLOAD,WM_USER+44,CustomKeys.SlotLoad.key,CustomKeys.SlotLoad.modifiers);
8370 	int i;
8371 	for(i = 0 ; i < 10 ; i++) SendDlgItemMessage(hDlg,IDC_SAVE1+i,WM_USER+44,CustomKeys.Save[i].key,CustomKeys.Save[i].modifiers);
8372 	for(i = 0 ; i < 10 ; i++) SendDlgItemMessage(hDlg,IDC_SAVE11+i,WM_USER+44,CustomKeys.Load[i].key,CustomKeys.Load[i].modifiers);
8373 
8374 	switch(index)
8375 	{
8376 	case 0:
8377 		// set page 1 label text
8378 		SetDlgItemText(hDlg,IDC_LABEL_HK1,HOTKEYS_LABEL_1_1);
8379 		SetDlgItemText(hDlg,IDC_LABEL_HK2,HOTKEYS_LABEL_1_2);
8380 		SetDlgItemText(hDlg,IDC_LABEL_HK3,HOTKEYS_LABEL_1_3);
8381 		SetDlgItemText(hDlg,IDC_LABEL_HK4,HOTKEYS_LABEL_1_4);
8382 		SetDlgItemText(hDlg,IDC_LABEL_HK5,HOTKEYS_LABEL_1_5);
8383 		SetDlgItemText(hDlg,IDC_LABEL_HK6,HOTKEYS_LABEL_1_6);
8384 		SetDlgItemText(hDlg,IDC_LABEL_HK7,HOTKEYS_LABEL_1_7);
8385 		SetDlgItemText(hDlg,IDC_LABEL_HK8,HOTKEYS_LABEL_1_8);
8386 		SetDlgItemText(hDlg,IDC_LABEL_HK9,HOTKEYS_LABEL_1_9);
8387 		SetDlgItemText(hDlg,IDC_LABEL_HK10,HOTKEYS_LABEL_1_10);
8388 		SetDlgItemText(hDlg,IDC_LABEL_HK11,HOTKEYS_LABEL_1_11);
8389 		SetDlgItemText(hDlg,IDC_LABEL_HK12,HOTKEYS_LABEL_1_12);
8390 		SetDlgItemText(hDlg,IDC_LABEL_HK13,HOTKEYS_LABEL_1_13);
8391 		break;
8392 	case 1:
8393 		SetDlgItemText(hDlg,IDC_LABEL_HK1,HOTKEYS_LABEL_2_1);
8394 		SetDlgItemText(hDlg,IDC_LABEL_HK2,HOTKEYS_LABEL_2_2);
8395 		SetDlgItemText(hDlg,IDC_LABEL_HK3,HOTKEYS_LABEL_2_3);
8396 		SetDlgItemText(hDlg,IDC_LABEL_HK4,HOTKEYS_LABEL_2_4);
8397 		SetDlgItemText(hDlg,IDC_LABEL_HK5,HOTKEYS_LABEL_2_5);
8398 		SetDlgItemText(hDlg,IDC_LABEL_HK6,HOTKEYS_LABEL_2_6);
8399 		SetDlgItemText(hDlg,IDC_LABEL_HK7,HOTKEYS_LABEL_2_7);
8400 		SetDlgItemText(hDlg,IDC_LABEL_HK8,HOTKEYS_LABEL_2_8);
8401 		SetDlgItemText(hDlg,IDC_LABEL_HK9,HOTKEYS_LABEL_2_9);
8402 		SetDlgItemText(hDlg,IDC_LABEL_HK10,HOTKEYS_LABEL_2_10);
8403 		SetDlgItemText(hDlg,IDC_LABEL_HK11,HOTKEYS_LABEL_2_11);
8404 		SetDlgItemText(hDlg,IDC_LABEL_HK12,HOTKEYS_LABEL_2_12);
8405 		SetDlgItemText(hDlg,IDC_LABEL_HK13,HOTKEYS_LABEL_2_13);
8406 		break;
8407 	case 2:
8408 		SetDlgItemText(hDlg,IDC_LABEL_HK1,HOTKEYS_LABEL_3_1);
8409 		SetDlgItemText(hDlg,IDC_LABEL_HK2,HOTKEYS_LABEL_3_2);
8410 		SetDlgItemText(hDlg,IDC_LABEL_HK3,HOTKEYS_LABEL_3_3);
8411 		SetDlgItemText(hDlg,IDC_LABEL_HK4,HOTKEYS_LABEL_3_4);
8412 		SetDlgItemText(hDlg,IDC_LABEL_HK5,HOTKEYS_LABEL_3_5);
8413 		SetDlgItemText(hDlg,IDC_LABEL_HK6,HOTKEYS_LABEL_3_6);
8414 		SetDlgItemText(hDlg,IDC_LABEL_HK7,HOTKEYS_LABEL_3_7);
8415 		SetDlgItemText(hDlg,IDC_LABEL_HK8,HOTKEYS_LABEL_3_8);
8416 		SetDlgItemText(hDlg,IDC_LABEL_HK9,HOTKEYS_LABEL_3_9);
8417 		SetDlgItemText(hDlg,IDC_LABEL_HK10,HOTKEYS_LABEL_3_10);
8418 		SetDlgItemText(hDlg,IDC_LABEL_HK11,HOTKEYS_LABEL_3_11);
8419 		SetDlgItemText(hDlg,IDC_LABEL_HK12,HOTKEYS_LABEL_3_12);
8420 		SetDlgItemText(hDlg,IDC_LABEL_HK13, HOTKEYS_LABEL_3_13);
8421 
8422 		break;
8423 	case 3:
8424 		for(int i = 0 ; i < 10 ; i++)
8425 		{
8426 			TCHAR temp [64];
8427 			_stprintf(temp, TEXT("Select Slot %d"), i);
8428 			SetDlgItemText(hDlg,IDC_LABEL_HK1+i,temp);
8429 		}
8430 		SetDlgItemText(hDlg, IDC_LABEL_HK11, HOTKEYS_LABEL_4_11);
8431 		SetDlgItemText(hDlg, IDC_LABEL_HK12, HOTKEYS_LABEL_4_12);
8432 		SetDlgItemText(hDlg,IDC_LABEL_HK13,HOTKEYS_LABEL_4_13);
8433 
8434 		break;
8435 	}
8436 }
8437 
8438 // DlgHotkeyConfig
DlgHotkeyConfig(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)8439 INT_PTR CALLBACK DlgHotkeyConfig(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
8440 {
8441 	int i, which;
8442 	static int index=0;
8443 
8444 
8445 	static SCustomKeys keys;
8446 
8447 
8448 	//HBRUSH g_hbrBackground;
8449 	InitKeyCustomControl();
8450 switch(msg)
8451 	{
8452 		case WM_PAINT:
8453 		{
8454 			PAINTSTRUCT ps;
8455 			BeginPaint (hDlg, &ps);
8456 
8457 			EndPaint (hDlg, &ps);
8458 		}
8459 		return true;
8460 	case WM_INITDIALOG:
8461 		WinRefreshDisplay();
8462 		SetWindowText(hDlg,HOTKEYS_TITLE);
8463 
8464 		// insert hotkey page list items
8465 		for(i=1 ; i <= 4 ; i++)
8466 		{
8467 			TCHAR temp[256];
8468 			_stprintf(temp,HOTKEYS_HKCOMBO,i);
8469 			SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)temp);
8470 		}
8471 
8472 		SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_SETCURSEL,(WPARAM)0,0);
8473 
8474 		memcpy(&keys, &CustomKeys, sizeof(SCustomKeys));
8475 		for( i=0;i<256;i++)
8476 		{
8477 			GetAsyncKeyState(i);
8478 		}
8479 
8480 		SetDlgItemText(hDlg,IDC_LABEL_BLUE,HOTKEYS_LABEL_BLUE);
8481 
8482 		set_hotkeyinfo(hDlg);
8483 
8484 		PostMessage(hDlg,WM_COMMAND, CBN_SELCHANGE<<16, 0);
8485 
8486 		SetFocus(GetDlgItem(hDlg,IDC_HKCOMBO));
8487 
8488 
8489 		return true;
8490 		break;
8491 	case WM_CLOSE:
8492 		EndDialog(hDlg, 0);
8493 		return TRUE;
8494 	case WM_USER+46:
8495 		// refresh command, for clicking away from a selected field
8496 		index = SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_GETCURSEL,0,0);
8497 		set_hotkeyinfo(hDlg);
8498 		return TRUE;
8499 	case WM_USER+43:
8500 	{
8501 		//MessageBox(hDlg,"USER+43 CAUGHT","moo",MB_OK);
8502 		int modifiers = 0;
8503 		if(GetAsyncKeyState(VK_MENU) || wParam == VK_MENU)
8504 			modifiers |= CUSTKEY_ALT_MASK;
8505 		if(GetAsyncKeyState(VK_CONTROL) || wParam == VK_CONTROL)
8506 			modifiers |= CUSTKEY_CTRL_MASK;
8507 		if(GetAsyncKeyState(VK_SHIFT) || wParam == VK_SHIFT)
8508 			modifiers |= CUSTKEY_SHIFT_MASK;
8509 
8510 		int index = SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_GETCURSEL,0,0);
8511 
8512 		which = GetDlgCtrlID((HWND)lParam);
8513 
8514 		switch(which)
8515 		{
8516 		case IDC_HOTKEY1:
8517 			if(index == 0) CustomKeys.SpeedUp.key = wParam, CustomKeys.SpeedUp.modifiers = modifiers;
8518 			if(index == 1) CustomKeys.BGL1.key = wParam,    CustomKeys.BGL1.modifiers = modifiers;
8519 			if(index == 2) CustomKeys.TurboA.key = wParam,    CustomKeys.TurboA.modifiers = modifiers;
8520 			if(index == 3) CustomKeys.SelectSave[0].key = wParam,	CustomKeys.SelectSave[0].modifiers = modifiers;
8521 			break;
8522 		case IDC_HOTKEY2:
8523 			if(index == 0) CustomKeys.SpeedDown.key = wParam, CustomKeys.SpeedDown.modifiers = modifiers;
8524 			if(index == 1) CustomKeys.BGL2.key = wParam,      CustomKeys.BGL2.modifiers = modifiers;
8525 			if(index == 2) CustomKeys.TurboB.key = wParam,    CustomKeys.TurboB.modifiers = modifiers;
8526 			if(index == 3) CustomKeys.SelectSave[1].key = wParam,	CustomKeys.SelectSave[1].modifiers = modifiers;
8527 			break;
8528 		case IDC_HOTKEY3:
8529 			if(index == 0) CustomKeys.Pause.key = wParam, CustomKeys.Pause.modifiers = modifiers;
8530 			if(index == 1) CustomKeys.BGL3.key = wParam,  CustomKeys.BGL3.modifiers = modifiers;
8531 			if(index == 2) CustomKeys.TurboY.key = wParam,    CustomKeys.TurboY.modifiers = modifiers;
8532 			if(index == 3) CustomKeys.SelectSave[2].key = wParam,	CustomKeys.SelectSave[2].modifiers = modifiers;
8533 			break;
8534 		case IDC_HOTKEY4:
8535 			if(index == 0) CustomKeys.FrameAdvance.key = wParam, CustomKeys.FrameAdvance.modifiers = modifiers;
8536 			if(index == 1) CustomKeys.BGL4.key = wParam,         CustomKeys.BGL4.modifiers = modifiers;
8537 			if(index == 2) CustomKeys.TurboX.key = wParam,    CustomKeys.TurboX.modifiers = modifiers;
8538 			if(index == 3) CustomKeys.SelectSave[3].key = wParam,	CustomKeys.SelectSave[3].modifiers = modifiers;
8539 			break;
8540 		case IDC_HOTKEY5:
8541 			if(index == 0) CustomKeys.FastForward.key = wParam, CustomKeys.FastForward.modifiers = modifiers;
8542 			if(index == 1) CustomKeys.BGL5.key = wParam,        CustomKeys.BGL5.modifiers = modifiers;
8543 			if(index == 2) CustomKeys.TurboL.key = wParam,    CustomKeys.TurboL.modifiers = modifiers;
8544 			if(index == 3) CustomKeys.SelectSave[4].key = wParam,	CustomKeys.SelectSave[4].modifiers = modifiers;
8545 			break;
8546 		case IDC_HOTKEY6:
8547 			if(index == 0) CustomKeys.SkipUp.key = wParam,          CustomKeys.SkipUp.modifiers = modifiers;
8548 			if(index == 1) CustomKeys.ClippingWindows.key = wParam, CustomKeys.ClippingWindows.modifiers = modifiers;
8549 			if(index == 2) CustomKeys.TurboR.key = wParam,    CustomKeys.TurboR.modifiers = modifiers;
8550 			if(index == 3) CustomKeys.SelectSave[5].key = wParam,	CustomKeys.SelectSave[5].modifiers = modifiers;
8551 			break;
8552 		case IDC_HOTKEY7:
8553 			if(index == 0) CustomKeys.SkipDown.key = wParam, CustomKeys.SkipDown.modifiers = modifiers;
8554 			if(index == 1) CustomKeys.Transparency.key = wParam, CustomKeys.Transparency.modifiers = modifiers;
8555 			if(index == 2) CustomKeys.TurboStart.key = wParam,    CustomKeys.TurboStart.modifiers = modifiers;
8556 			if(index == 3) CustomKeys.SelectSave[6].key = wParam,	CustomKeys.SelectSave[6].modifiers = modifiers;
8557 			break;
8558 		case IDC_HOTKEY8:
8559 			if(index == 0) CustomKeys.ScopeTurbo.key = wParam,  CustomKeys.ScopeTurbo.modifiers = modifiers;
8560 			if(index == 1) CustomKeys.FastForwardToggle.key = wParam, CustomKeys.FastForwardToggle.modifiers = modifiers;
8561 			if(index == 2) CustomKeys.TurboSelect.key = wParam,    CustomKeys.TurboSelect.modifiers = modifiers;
8562 			if(index == 3) CustomKeys.SelectSave[7].key = wParam,	CustomKeys.SelectSave[7].modifiers = modifiers;
8563 			break;
8564 		case IDC_HOTKEY9:
8565 			if(index == 0) CustomKeys.ScopePause.key = wParam, CustomKeys.ScopePause.modifiers = modifiers;
8566             if(index == 1) CustomKeys.Rewind.key = wParam,      CustomKeys.Rewind.modifiers = modifiers;
8567 			if(index == 2) CustomKeys.TurboLeft.key = wParam,    CustomKeys.TurboLeft.modifiers = modifiers;
8568 			if(index == 3) CustomKeys.SelectSave[8].key = wParam,	CustomKeys.SelectSave[8].modifiers = modifiers;
8569 			break;
8570 		case IDC_HOTKEY10:
8571 			if(index == 0) CustomKeys.ShowPressed.key = wParam, CustomKeys.ShowPressed.modifiers = modifiers;
8572 			if(index == 1) CustomKeys.SwitchControllers.key = wParam, CustomKeys.SwitchControllers.modifiers = modifiers;
8573 			if(index == 2) CustomKeys.TurboUp.key = wParam,    CustomKeys.TurboUp.modifiers = modifiers;
8574 			if(index == 3) CustomKeys.SelectSave[9].key = wParam,	CustomKeys.SelectSave[9].modifiers = modifiers;
8575 			break;
8576 		case IDC_HOTKEY11:
8577 			if(index == 0) CustomKeys.FrameCount.key = wParam,  CustomKeys.FrameCount.modifiers = modifiers;
8578 			if(index == 1) CustomKeys.JoypadSwap.key = wParam, CustomKeys.JoypadSwap.modifiers = modifiers;
8579 			if(index == 2) CustomKeys.TurboRight.key = wParam,    CustomKeys.TurboRight.modifiers = modifiers;
8580 			if(index == 3) CustomKeys.SaveFileSelect.key = wParam, CustomKeys.SaveFileSelect.modifiers = modifiers;
8581 			break;
8582 		case IDC_HOTKEY12:
8583 			if(index == 0) CustomKeys.ReadOnly.key = wParam,   CustomKeys.ReadOnly.modifiers = modifiers;
8584 			if(index == 1) CustomKeys.ResetGame.key = wParam,    CustomKeys.ResetGame.modifiers = modifiers;
8585 			if(index == 2) CustomKeys.TurboDown.key = wParam,    CustomKeys.TurboDown.modifiers = modifiers;
8586 			if(index == 3) CustomKeys.LoadFileSelect.key = wParam, CustomKeys.LoadFileSelect.modifiers = modifiers;
8587 			break;
8588 		case IDC_HOTKEY13:
8589 			if(index == 0) CustomKeys.SaveScreenShot.key = wParam,    CustomKeys.SaveScreenShot.modifiers = modifiers;
8590 			if(index == 1) CustomKeys.ToggleCheats.key = wParam,    CustomKeys.ToggleCheats.modifiers = modifiers;
8591 			if(index == 2) CustomKeys.Mute.key = wParam,  CustomKeys.Mute.modifiers = modifiers;
8592 			if(index == 3) CustomKeys.QuitS9X.key = wParam,  CustomKeys.QuitS9X.modifiers = modifiers;
8593 			break;
8594 
8595 		case IDC_SLOTPLUS:
8596 			CustomKeys.SlotPlus.key = wParam;
8597 			CustomKeys.SlotPlus.modifiers = modifiers;
8598 			break;
8599 
8600 		case IDC_SLOTMINUS:
8601 			CustomKeys.SlotMinus.key = wParam;
8602 			CustomKeys.SlotMinus.modifiers = modifiers;
8603 			break;
8604 
8605 		case IDC_SLOTLOAD:
8606 			CustomKeys.SlotLoad.key = wParam;
8607 			CustomKeys.SlotLoad.modifiers = modifiers;
8608 			break;
8609 
8610 		case IDC_SLOTSAVE:
8611 			CustomKeys.SlotSave.key = wParam;
8612 			CustomKeys.SlotSave.modifiers = modifiers;
8613 			break;
8614 		}
8615 
8616 		if(which >= IDC_SAVE1 && which <= IDC_SAVE10)
8617 		{
8618 			CustomKeys.Save[which-IDC_SAVE1].key = wParam;
8619 			CustomKeys.Save[which-IDC_SAVE1].modifiers = modifiers;
8620 		}
8621 		if(which >= IDC_SAVE11 && which <= IDC_SAVE20)
8622 		{
8623 			CustomKeys.Load[which-IDC_SAVE11].key = wParam;
8624 			CustomKeys.Load[which-IDC_SAVE11].modifiers = modifiers;
8625 		}
8626 
8627 		set_hotkeyinfo(hDlg);
8628 		PostMessage(hDlg,WM_NEXTDLGCTL,0,0);
8629 //		PostMessage(hDlg,WM_KILLFOCUS,0,0);
8630 	}
8631 		return true;
8632 	case WM_COMMAND:
8633 		switch(LOWORD(wParam))
8634 		{
8635 		case IDCANCEL:
8636 			memcpy(&CustomKeys, &keys, sizeof(SCustomKeys));
8637 			EndDialog(hDlg,0);
8638 			break;
8639 		case IDOK:
8640 			WinSaveConfigFile();
8641 			EndDialog(hDlg,0);
8642 			break;
8643 		}
8644 		switch(HIWORD(wParam))
8645 		{
8646 			case CBN_SELCHANGE:
8647 				index = SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_GETCURSEL,0,0);
8648 				SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_SETCURSEL,(WPARAM)index,0);
8649 
8650 				set_hotkeyinfo(hDlg);
8651 
8652 				SetFocus(GetDlgItem(hDlg,IDC_HKCOMBO));
8653 
8654 				break;
8655 		}
8656 		return FALSE;
8657 
8658 	}
8659 
8660 	return FALSE;
8661 }
8662 
8663 
8664 template<typename IntType>
ScanAddress(const TCHAR * str,IntType & value)8665 int ScanAddress(const TCHAR* str, IntType& value)
8666 {
8667 	int ret = 0;
8668 	if(_totlower(*str) == TEXT('s'))
8669 	{
8670 		ret = _stscanf(str+1, TEXT("%x"), &value);
8671 		value += 0x7E0000 + 0x20000;
8672 	}
8673 	else if(_totlower(*str) == TEXT('i'))
8674 	{
8675 		ret = _stscanf(str+1, TEXT("%x"), &value);
8676 		value += 0x7E0000 + 0x30000;
8677 	}
8678 	else
8679 	{
8680 		int plus = (*str == TEXT('0') && _totlower(str[1]) == TEXT('x')) ? 2 : 0;
8681 		ret = _stscanf(str+plus, TEXT("%x"), &value);
8682 	}
8683 	return ret;
8684 }
8685 
8686 enum CheatStatus{
8687 	Untouched,
8688 	Deleted,
8689 	Modified
8690 };
8691 typedef struct{
8692 	std::vector<DWORD> state;
8693 }CheatTracker;
8694 
WinSearchCheatDatabase()8695 int WinSearchCheatDatabase()
8696 {
8697 	std::string filename;
8698 	int result;
8699 	int reason = 0;
8700 
8701 	filename = S9xGetDirectory(CHEAT_DIR);
8702 	filename += "\\cheats.bml";
8703 	if (!(result = S9xImportCheatsFromDatabase(filename.c_str())))
8704 	{
8705 		return result;
8706 	}
8707 
8708 	if (result < reason)
8709 		reason = result;
8710 
8711 	filename = S9xGetDirectory(HOME_DIR);
8712 	filename += "\\cheats.bml";
8713 	if (!(result = S9xImportCheatsFromDatabase(filename.c_str())))
8714 	{
8715 		return result;
8716 	}
8717 
8718 	if (result < reason)
8719 		reason = result;
8720 
8721 	filename = S9xGetDirectory(ROM_DIR);
8722 	filename += "\\cheats.bml";
8723 	if (!(result = S9xImportCheatsFromDatabase(filename.c_str())))
8724 	{
8725 		return result;
8726 	}
8727 
8728 	if (result < reason)
8729 		reason = result;
8730 
8731 	MessageBox(GUI.hWnd,
8732 		reason == -1 ?
8733 			TEXT("The database file cheats.bml was not found. It is normally installed with "
8734 				"Snes9x, but you may also place a custom copy in your configuration or cheats directory.") :
8735 			TEXT("No matching game was found in the databases. If you are using a non-official "
8736 				"translation or modified copy, you may be able to find and manually enter the codes."),
8737 		reason == -1 ? TEXT("Couldn't Find Cheats Database") : TEXT("No Matching Game Found"),
8738 		MB_OK | MB_ICONEXCLAMATION);
8739 
8740 	return reason;
8741 }
8742 
8743 #define ITEM_QUERY(a, b, c, d, e)  memset(&a, 0, sizeof(LV_ITEM)); \
8744 						a.iItem= ListView_GetSelectionMark(GetDlgItem(hDlg, b)); \
8745 						a.iSubItem=c; \
8746 						a.mask=LVIF_TEXT; \
8747 						a.pszText=d; \
8748 						a.cchTextMax=e; \
8749 						ListView_GetItem(GetDlgItem(hDlg, b), &a);
8750 #define CHEAT_SIZE 1024
8751 
DlgCheater(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)8752 INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
8753 {
8754 	static bool internal_change;
8755 	static bool has_sel;
8756 	static int  sel_idx;
8757 	static uint8 new_sel;
8758 	static CheatTracker ct;
8759 	switch(msg)
8760 	{
8761 	case WM_INITDIALOG:
8762 			WinRefreshDisplay();
8763 
8764 			ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_CHEAT_LIST), LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES);
8765 
8766 			SendDlgItemMessage(hDlg, IDC_CHEAT_CODE, EM_LIMITTEXT, CHEAT_SIZE, 0);
8767 			SendDlgItemMessage(hDlg, IDC_CHEAT_DESCRIPTION, EM_LIMITTEXT, CHEAT_SIZE, 0);
8768 
8769 			LVCOLUMN col;
8770 			TCHAR temp[32];
8771 			lstrcpy(temp, SEARCH_COLUMN_CODE);
8772 			memset(&col, 0, sizeof(LVCOLUMN));
8773 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH;
8774 			col.fmt=LVCFMT_LEFT;
8775 			col.iOrder=0;
8776 			col.cx=100;
8777 			col.pszText=temp;
8778 
8779 			ListView_InsertColumn(GetDlgItem(hDlg,IDC_CHEAT_LIST),    0,   &col);
8780 
8781 			lstrcpy(temp,SEARCH_COLUMN_DESCRIPTION);
8782 			memset(&col, 0, sizeof(LVCOLUMN));
8783 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
8784 			col.fmt=LVCFMT_LEFT;
8785 			col.iOrder=2;
8786 			col.cx=300;
8787 			col.pszText=temp;
8788 			col.iSubItem=2;
8789 
8790 			ListView_InsertColumn(GetDlgItem(hDlg,IDC_CHEAT_LIST),    1,   &col);
8791 
8792 			ct.state.resize(Cheat.g.size());
8793 
8794 			for(uint32 counter =0; counter < Cheat.g.size(); counter++)
8795 			{
8796 				char *code_string;
8797 				int curr_idx = -1;
8798 				code_string = S9xCheatGroupToText(counter);
8799 				Utf8ToWide wstring(code_string);
8800 				delete[] code_string;
8801 
8802 				LVITEM lvi;
8803 				memset(&lvi, 0, sizeof(LVITEM));
8804 				lvi.mask = LVIF_TEXT | LVIF_PARAM;
8805 				lvi.cchTextMax = CHEAT_SIZE;
8806 				lvi.pszText = wstring;
8807 				lvi.lParam = counter; // we save the internal cheat index as lParam of list entry
8808 				lvi.iItem = counter;
8809 				curr_idx = ListView_InsertItem(GetDlgItem(hDlg,IDC_CHEAT_LIST), &lvi);
8810 
8811 				ct.state[counter] = Untouched;
8812 
8813 				Utf8ToWide wstring_name(Cheat.g[counter].name);
8814 				memset(&lvi, 0, sizeof(LVITEM));
8815 				lvi.iItem = curr_idx;
8816 				lvi.iSubItem = 1;
8817 				lvi.mask = LVIF_TEXT;
8818 				lvi.cchTextMax = CHEAT_SIZE;
8819 				lvi.pszText = wstring_name;
8820 				SendDlgItemMessage(hDlg,IDC_CHEAT_LIST, LVM_SETITEM, 0, (LPARAM)&lvi);
8821 
8822 				ListView_SetCheckState(GetDlgItem(hDlg,IDC_CHEAT_LIST), curr_idx, Cheat.g[counter].enabled);
8823 
8824 			}
8825 		return true;
8826 	case WM_PAINT:
8827 		{
8828 		PAINTSTRUCT ps;
8829 		BeginPaint (hDlg, &ps);
8830 
8831 		EndPaint (hDlg, &ps);
8832 		}
8833 		return true;
8834 	case WM_NOTIFY:
8835 		{
8836 			switch(LOWORD(wParam))
8837 			{
8838 			case IDC_CHEAT_LIST:
8839 				if(0==ListView_GetSelectedCount(GetDlgItem(hDlg, IDC_CHEAT_LIST)))
8840 				{
8841 					EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), false);
8842 					EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false);
8843 					has_sel=false;
8844 					sel_idx=-1;
8845 				}
8846 				else
8847 				{
8848 					EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), true);
8849 					if(!has_sel||sel_idx!=ListView_GetSelectionMark(GetDlgItem(hDlg, IDC_CHEAT_LIST)))
8850 					{
8851 						new_sel=3;
8852 						//change
8853 						TCHAR buf[CHEAT_SIZE];
8854 						LV_ITEM lvi;
8855 
8856 						internal_change = true; // do not enable update button
8857 
8858 						/* Code */
8859 						ITEM_QUERY (lvi, IDC_CHEAT_LIST, 0, buf, CHEAT_SIZE);
8860 						SetDlgItemText(hDlg, IDC_CHEAT_CODE, lvi.pszText);
8861 
8862 						/* Description */
8863 						ITEM_QUERY(lvi, IDC_CHEAT_LIST, 1, buf, CHEAT_SIZE);
8864 						SetDlgItemText(hDlg, IDC_CHEAT_DESCRIPTION, lvi.pszText);
8865 
8866 						internal_change = false;
8867 					}
8868 					sel_idx=ListView_GetSelectionMark(GetDlgItem(hDlg, IDC_CHEAT_LIST));
8869 					has_sel=true;
8870 				}
8871 
8872 					return true;
8873 			default: return false;
8874 			}
8875 		}
8876 	case WM_COMMAND:
8877 		{
8878 			switch(LOWORD(wParam))
8879 			{
8880 			case IDC_CHEAT_DESCRIPTION:
8881 				{
8882 					switch(HIWORD(wParam))
8883 					{
8884 					case EN_CHANGE:
8885 
8886 						if(internal_change)
8887 						{
8888 							return false;
8889 						}
8890 						if(!has_sel)
8891 							return true;
8892 
8893 						EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), true);
8894 						return true;
8895 					}
8896 					break;
8897 
8898 				}
8899 			case IDC_ADD_CHEAT:
8900 				{
8901 					char temp[CHEAT_SIZE];
8902 					TCHAR tempDesc[CHEAT_SIZE];
8903 					GetDlgItemTextA(hDlg, IDC_CHEAT_CODE, temp, CHEAT_SIZE);
8904 					GetDlgItemText(hDlg, IDC_CHEAT_DESCRIPTION, tempDesc, CHEAT_SIZE);
8905 
8906 					char *valid_cheat = S9xCheatValidate (temp);
8907 
8908 					if(valid_cheat)
8909 					{
8910 						Utf8ToWide wstring(valid_cheat);
8911 						delete[] valid_cheat;
8912 
8913 						int curr_idx = -1;
8914 
8915 						LVITEM lvi;
8916 						memset(&lvi, 0, sizeof(LVITEM));
8917 						lvi.mask = LVIF_TEXT | LVIF_PARAM;
8918 						lvi.pszText = wstring;
8919 						lvi.iItem = ListView_GetItemCount(GetDlgItem(hDlg,IDC_CHEAT_LIST));
8920 						lvi.lParam = -1; // -1 signals this is a new cheat
8921 						curr_idx = ListView_InsertItem(GetDlgItem(hDlg,IDC_CHEAT_LIST), &lvi);
8922 
8923 						SetDlgItemText(hDlg, IDC_CHEAT_CODE, wstring);
8924 
8925 						memset(&lvi, 0, sizeof(LVITEM));
8926 						lvi.iItem = curr_idx;
8927 						lvi.iSubItem = 1;
8928 						lvi.mask = LVIF_TEXT;
8929 						lvi.pszText = tempDesc;
8930 						lvi.cchTextMax = CHEAT_SIZE;
8931 						ListView_SetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
8932 
8933 						// unselect all items, select new item and make sure it is visible
8934 						ListView_SetItemState(GetDlgItem(hDlg, IDC_CHEAT_LIST), -1, 0, LVIS_FOCUSED | LVIS_SELECTED);
8935 						ListView_SetItemState(GetDlgItem(hDlg, IDC_CHEAT_LIST), curr_idx, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
8936 						ListView_EnsureVisible(GetDlgItem(hDlg, IDC_CHEAT_LIST), curr_idx, FALSE);
8937 					}
8938 				}
8939 				break;
8940 			case IDC_UPDATE_CHEAT:
8941 				{
8942 					unsigned int j;
8943 					TCHAR temp[CHEAT_SIZE];
8944 					char code[CHEAT_SIZE];
8945 					GetDlgItemTextA(hDlg, IDC_CHEAT_CODE, code, CHEAT_SIZE);
8946 
8947 					char *valid_cheat = S9xCheatValidate(code);
8948 
8949 					if(valid_cheat)
8950 					{
8951 						delete[] valid_cheat;
8952 
8953 						Utf8ToWide wstring(code);
8954 
8955 						LVITEM lvi;
8956 
8957 						// get index in internal cheat list, if present mark as modified
8958 						memset(&lvi, 0, sizeof(LVITEM));
8959 						lvi.mask = LVIF_PARAM;
8960 						lvi.iItem = sel_idx;
8961 						ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
8962 						if (lvi.lParam >= 0)
8963 							ct.state[lvi.lParam] = Modified;
8964 
8965 						memset(&lvi, 0, sizeof(LVITEM));
8966 						lvi.mask=LVIF_TEXT;
8967 						lvi.pszText=wstring;
8968 						lvi.iItem=sel_idx;
8969 						lvi.cchTextMax = CHEAT_SIZE;
8970 						ListView_SetItem(GetDlgItem(hDlg,IDC_CHEAT_LIST), &lvi);
8971 						SetDlgItemText(hDlg, IDC_CHEAT_CODE, wstring);
8972 
8973 						GetDlgItemText(hDlg, IDC_CHEAT_DESCRIPTION, temp, CHEAT_SIZE);
8974 
8975 						memset(&lvi, 0, sizeof(LVITEM));
8976 						lvi.iItem=sel_idx;
8977 						lvi.iSubItem = 1;
8978 						lvi.mask=LVIF_TEXT;
8979 						lvi.pszText=temp;
8980 						lvi.cchTextMax = CHEAT_SIZE;
8981 						SendDlgItemMessage(hDlg,IDC_CHEAT_LIST, LVM_SETITEM, 0, (LPARAM)&lvi);
8982 
8983 						// update done, disable update button
8984 						EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false);
8985 					}
8986 				}
8987 
8988 				break;
8989 			case IDC_DELETE_CHEAT:
8990 				{
8991 					LVITEM lvi;
8992 
8993 					// get index in internal cheat list, if present mark as deleted
8994 					memset(&lvi, 0, sizeof(LVITEM));
8995 					lvi.mask = LVIF_PARAM;
8996 					lvi.iItem = sel_idx;
8997 					ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
8998 					if (lvi.lParam >= 0)
8999 						ct.state[lvi.lParam] = Deleted;
9000 
9001 					// save index, deleting item removes selection
9002 					int old_sel = sel_idx;
9003 					ListView_DeleteItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), sel_idx);
9004 					ListView_SetItemState(GetDlgItem(hDlg, IDC_CHEAT_LIST), old_sel, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
9005 				}
9006 
9007 				break;
9008 			case IDC_DELETE_ALL:
9009 				if (MessageBox(hDlg,
9010 					TEXT("This will remove all cheats for this game."),
9011 					TEXT("Remove all"),
9012 					MB_OKCANCEL | MB_ICONWARNING) != IDOK)
9013 				{
9014 					break;
9015 				}
9016 				ListView_DeleteAllItems(GetDlgItem(hDlg, IDC_CHEAT_LIST));
9017 				for (unsigned int j = 0; j < Cheat.g.size(); j++)
9018 				{
9019 					ct.state[j] = Deleted;
9020 				}
9021 			case IDC_CLEAR_CHEATS:
9022 				internal_change = true;
9023 				SetDlgItemText(hDlg,IDC_CHEAT_CODE,TEXT(""));
9024 				SetDlgItemText(hDlg,IDC_CHEAT_DESCRIPTION,TEXT(""));
9025 				internal_change = false;
9026 				ListView_SetItemState(GetDlgItem(hDlg, IDC_CHEAT_LIST),sel_idx, 0, LVIS_SELECTED|LVIS_FOCUSED);
9027 				ListView_SetSelectionMark(GetDlgItem(hDlg, IDC_CHEAT_LIST), -1);
9028 				sel_idx=-1;
9029 				has_sel=false;
9030 				break;
9031 			case IDC_SEARCH_DB:
9032 				if (MessageBox(hDlg,
9033 					TEXT("This will apply current changes from the cheat dialog, try to import cheats from the cheat database, then reopen the dialog."),
9034 					TEXT("Search Database"),
9035 					MB_OKCANCEL | MB_ICONINFORMATION) == IDOK)
9036 				{
9037 					PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDOK, NC_SEARCHDB), (LPARAM)GetDlgItem(hDlg, IDOK));
9038 				}
9039 				break;
9040 			case IDC_CHEAT_CODE:
9041 				{
9042 					uint32 j, k;
9043 					long index;
9044 					char buffer[15];
9045 					char buffer2[15];
9046 					POINT point;
9047 					switch(HIWORD(wParam))
9048 					{
9049 					case EN_CHANGE:
9050 						if (internal_change)
9051 						{
9052 							return true;
9053 						}
9054 						char temp[CHEAT_SIZE];
9055 						char *valid_cheat = NULL;
9056 						GetDlgItemTextA(hDlg, IDC_CHEAT_CODE, temp, CHEAT_SIZE);
9057 
9058 						if (temp && temp[0] && (valid_cheat = S9xCheatValidate(temp)))
9059 						{
9060 							if (has_sel)
9061 								EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), true);
9062 							else
9063 								EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false);
9064 							EnableWindow(GetDlgItem(hDlg, IDC_ADD_CHEAT), true);
9065 							delete[] valid_cheat;
9066 						}
9067 						else
9068 						{
9069 							EnableWindow(GetDlgItem(hDlg, IDC_ADD_CHEAT), false);
9070 							EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false);
9071 						}
9072 
9073 						break;
9074 					}
9075 					break;
9076 				}
9077 			case IDOK:
9078 				{
9079 					bool hit;
9080 					unsigned int scanned;
9081 					for(int k = 0; k < ListView_GetItemCount(GetDlgItem(hDlg, IDC_CHEAT_LIST)); k++)
9082 					{
9083 						LVITEM lvi;
9084 
9085 						// get index in internal cheat list, if present mark as deleted
9086 						memset(&lvi, 0, sizeof(LVITEM));
9087 						lvi.mask = LVIF_PARAM;
9088 						lvi.iItem = k;
9089 						ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
9090 
9091 						int internal_index = lvi.lParam;
9092 
9093 						if(internal_index >= 0)
9094 						{
9095 							if(ct.state[internal_index]==(unsigned long)Modified) // modified in GUI, change in core
9096 							{
9097 								TCHAR wcode[CHEAT_SIZE];
9098 								TCHAR wdescription[CHEAT_SIZE];
9099 
9100 								memset(&lvi, 0, sizeof(LV_ITEM));
9101 								lvi.iItem = k;
9102 								lvi.mask = LVIF_TEXT;
9103 								lvi.pszText = wcode;
9104 								lvi.cchTextMax = CHEAT_SIZE;
9105 								ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
9106 
9107 								memset(&lvi, 0, sizeof(LV_ITEM));
9108 								lvi.iItem = k;
9109 								lvi.iSubItem = 1;
9110 								lvi.mask=LVIF_TEXT;
9111 								lvi.pszText = wdescription;
9112 								lvi.cchTextMax = CHEAT_SIZE;
9113 								ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
9114 
9115 								WideToUtf8 code(wcode);
9116 								WideToUtf8 description(wdescription);
9117 
9118 								S9xModifyCheatGroup(internal_index, description, code);
9119 							}
9120 
9121 							// set core state according to checkbox
9122 							if (ListView_GetCheckState(GetDlgItem(hDlg, IDC_CHEAT_LIST), k))
9123 								S9xEnableCheatGroup(internal_index);
9124 							else
9125 								S9xDisableCheatGroup(internal_index);
9126 						}
9127 						else // new cheat, add
9128 						{
9129 							TCHAR wcode[CHEAT_SIZE];
9130 							TCHAR wdescription[CHEAT_SIZE];
9131 
9132 							LV_ITEM lvi;
9133 							memset(&lvi, 0, sizeof(LV_ITEM));
9134 							lvi.iItem = k;
9135 							lvi.mask = LVIF_TEXT;
9136 							lvi.pszText = wcode;
9137 							lvi.cchTextMax = CHEAT_SIZE;
9138 							ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
9139 
9140 							memset(&lvi, 0, sizeof(LV_ITEM));
9141 							lvi.iItem = k;
9142 							lvi.iSubItem = 1;
9143 							lvi.mask = LVIF_TEXT;
9144 							lvi.pszText = wdescription;
9145 							lvi.cchTextMax = CHEAT_SIZE;
9146 							ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi);
9147 
9148 							WideToUtf8 code(wcode);
9149 							WideToUtf8 description(wdescription);
9150 
9151 							int index = S9xAddCheatGroup(description, code);
9152 
9153 							if (index >= 0)
9154 								if (ListView_GetCheckState(GetDlgItem(hDlg, IDC_CHEAT_LIST), k))
9155 									S9xEnableCheatGroup(index);
9156 						}
9157 					}
9158 
9159 					for(int l = ct.state.size() - 1; l >= 0; l-- )
9160 					{
9161 						if(ct.state[l]==Deleted)
9162 						{
9163 							S9xDeleteCheatGroup(l);
9164 						}
9165 					}
9166 				}
9167 			case IDCANCEL:
9168 				EndDialog(hDlg, HIWORD(wParam) == NC_SEARCHDB ? NC_SEARCHDB : 0);
9169 				return true;
9170 			default:
9171 				return false;
9172 			}
9173 		}
9174 	default: return false;
9175 	}
9176 }
9177 
9178 
9179 #define TEST_BIT(a,v) \
9180 ((a)[(v) >> 5] & (1 << ((v) & 31)))
9181 
CheatCount(int byteSub)9182 static inline int CheatCount(int byteSub)
9183 {
9184 	int a, b=0;
9185 //	for(a=0;a<0x32000-byteSub;a++)
9186 	for(a=0;a<0x30000-byteSub;a++) // hide IRAM from cheat dialog (it seems not to be searhed correctly)
9187 	{
9188 		if(TEST_BIT(Cheat.ALL_BITS, a))
9189 			b++;
9190 	}
9191 	return b;
9192 }
9193 
9194 
9195 struct ICheat
9196 {
9197     uint32  address;
9198     uint32  new_val;
9199     uint32  saved_val;
9200 	int		size;
9201     bool8   enabled;
9202     bool8   saved;
9203     char    name [22];
9204 	int format;
9205 };
9206 
TestRange(int val_type,S9xCheatDataSize bytes,uint32 value)9207 bool TestRange(int val_type, S9xCheatDataSize bytes,  uint32 value)
9208 {
9209 	if(val_type!=2)
9210 	{
9211 		if(bytes==S9X_8_BITS)
9212 		{
9213 			if(value<256)
9214 				return true;
9215 			else return false;
9216 		}
9217 		if(bytes==S9X_16_BITS)
9218 		{
9219 			if(value<65536)
9220 				return true;
9221 			else return false;
9222 		}
9223 		if(bytes==S9X_24_BITS)
9224 		{
9225 			if(value<16777216)
9226 				return true;
9227 			else return false;
9228 		}
9229 		//if it reads in, it's a valid 32-bit unsigned!
9230 		return true;
9231 	}
9232 	else
9233 	{
9234 		if(bytes==S9X_8_BITS)
9235 		{
9236 			if((int32)value<128 && (int32)value >= -128)
9237 				return true;
9238 			else return false;
9239 		}
9240 		if(bytes==S9X_16_BITS)
9241 		{
9242 			if((int32)value<32768 && (int32)value >= -32768)
9243 				return true;
9244 			else return false;
9245 		}
9246 		if(bytes==S9X_24_BITS)
9247 		{
9248 			if((int32)value<8388608 && (int32)value >= -8388608)
9249 				return true;
9250 			else return false;
9251 		}
9252 		//should be handled by sscanf
9253 		return true;
9254 	}
9255 }
9256 
9257 
DlgCheatSearch(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)9258 INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
9259 {
9260 	static S9xCheatDataSize bytes;
9261 	static int val_type;
9262 	static int use_entered;
9263 	static S9xCheatComparisonType comp_type;
9264 	switch(msg)
9265 	{
9266 	case WM_INITDIALOG:
9267 		{
9268 		WinRefreshDisplay();
9269 			if(val_type==0)
9270 				val_type=1;
9271 			ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_ADDYS), LVS_EX_FULLROWSELECT);
9272 
9273 			//defaults
9274 			SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_CHECKED, 0);
9275 			if(!use_entered)
9276 				SendDlgItemMessage(hDlg, IDC_PREV, BM_SETCHECK, BST_CHECKED, 0);
9277 			else if(use_entered==1)
9278 			{
9279 				SendDlgItemMessage(hDlg, IDC_ENTERED, BM_SETCHECK, BST_CHECKED, 0);
9280 				EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), true);
9281 				EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), true);
9282 			}
9283 			else if(use_entered==2)
9284 			{
9285 				SendDlgItemMessage(hDlg, IDC_ENTEREDADDRESS, BM_SETCHECK, BST_CHECKED, 0);
9286 				EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), true);
9287 				EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), true);
9288 			}
9289 			SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);
9290 			SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);
9291 
9292 			if(comp_type==S9X_GREATER_THAN)
9293 			{
9294 				SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9295 				SendDlgItemMessage(hDlg, IDC_GREATER_THAN, BM_SETCHECK, BST_CHECKED, 0);
9296 			}
9297 			else if(comp_type==S9X_LESS_THAN_OR_EQUAL)
9298 			{
9299 				SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9300 				SendDlgItemMessage(hDlg, IDC_LESS_THAN_EQUAL, BM_SETCHECK, BST_CHECKED, 0);
9301 
9302 			}
9303 			else if(comp_type==S9X_GREATER_THAN_OR_EQUAL)
9304 			{
9305 				SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9306 				SendDlgItemMessage(hDlg, IDC_GREATER_THAN_EQUAL, BM_SETCHECK, BST_CHECKED, 0);
9307 
9308 			}
9309 			else if(comp_type==S9X_EQUAL)
9310 			{
9311 				SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9312 				SendDlgItemMessage(hDlg, IDC_EQUAL, BM_SETCHECK, BST_CHECKED, 0);
9313 
9314 			}
9315 			else if(comp_type==S9X_NOT_EQUAL)
9316 			{
9317 				SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9318 				SendDlgItemMessage(hDlg, IDC_NOT_EQUAL, BM_SETCHECK, BST_CHECKED, 0);
9319 
9320 			}
9321 
9322 			if(val_type==2)
9323 			{
9324 				SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_UNCHECKED, 0);
9325 				SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0);
9326 
9327 			}
9328 			else if(val_type==3)
9329 			{
9330 				SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_UNCHECKED, 0);
9331 				SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0);
9332 			}
9333 
9334 			if(bytes==S9X_16_BITS)
9335 			{
9336 				SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9337 				SendDlgItemMessage(hDlg, IDC_2_BYTE, BM_SETCHECK, BST_CHECKED, 0);
9338 			}
9339 			else if(bytes==S9X_24_BITS)
9340 			{
9341 				SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9342 				SendDlgItemMessage(hDlg, IDC_3_BYTE, BM_SETCHECK, BST_CHECKED, 0);
9343 			}
9344 			else if(bytes==S9X_32_BITS)
9345 			{
9346 				SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9347 				SendDlgItemMessage(hDlg, IDC_4_BYTE, BM_SETCHECK, BST_CHECKED, 0);
9348 			}
9349 
9350 			LVCOLUMN col;
9351 			TCHAR temp[32];
9352 			lstrcpy(temp,TEXT("Address"));
9353 			memset(&col, 0, sizeof(LVCOLUMN));
9354 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH;
9355 			col.fmt=LVCFMT_LEFT;
9356 			col.iOrder=0;
9357 			col.cx=70;
9358 			col.cchTextMax=7;
9359 			col.pszText=temp;
9360 
9361 			ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDYS),   0,   &col);
9362 
9363 			lstrcpy(temp,TEXT("Curr. Value"));
9364 			memset(&col, 0, sizeof(LVCOLUMN));
9365 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
9366 			col.fmt=LVCFMT_LEFT;
9367 			col.iOrder=1;
9368 			col.cx=104;
9369 			col.cchTextMax=3;
9370 			col.pszText=temp;
9371 			col.iSubItem=1;
9372 
9373 			ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDYS),    1,   &col);
9374 
9375 			lstrcpy(temp,TEXT("Prev. Value"));
9376 			memset(&col, 0, sizeof(LVCOLUMN));
9377 			col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
9378 			col.fmt=LVCFMT_LEFT;
9379 			col.iOrder=2;
9380 			col.cx=104;
9381 			col.cchTextMax=32;
9382 			col.pszText=temp;
9383 			col.iSubItem=2;
9384 
9385 			ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDYS),    2,   &col);
9386 
9387 			{
9388 					int l = CheatCount(bytes);
9389 					ListView_SetItemCount (GetDlgItem(hDlg, IDC_ADDYS), l);
9390 			}
9391 
9392 		}
9393 		return true;
9394 
9395 		case WM_DESTROY:
9396 			{
9397 				cheatSearchHWND = NULL;
9398 				S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
9399 				break;
9400 			}
9401 
9402 		case WM_PAINT:
9403 		{
9404 		PAINTSTRUCT ps;
9405 		BeginPaint (hDlg, &ps);
9406 
9407 		EndPaint (hDlg, &ps);
9408 		}
9409 		return true;
9410 	case WM_NOTIFY:
9411 		{
9412 			static int selectionMarkOverride = -1;
9413 			static int foundItemOverride = -1;
9414 			if(wParam == IDC_ADDYS)
9415 			{
9416 				NMHDR * nmh=(NMHDR*)lParam;
9417 				if(nmh->hwndFrom == GetDlgItem(hDlg, IDC_ADDYS) && nmh->code == LVN_GETDISPINFO)
9418 				{
9419 					static TCHAR buf[12]; // the following code assumes this variable is static
9420 					int i, j;
9421 					NMLVDISPINFO * nmlvdi=(NMLVDISPINFO*)lParam;
9422 					j=nmlvdi->item.iItem;
9423 					j++;
9424 					for(i=0;i<(0x32000-bytes)&& j>0;i++)
9425 					{
9426 						if(TEST_BIT(Cheat.ALL_BITS, i))
9427 							j--;
9428 					}
9429 					if (i>=0x32000 && j!=0)
9430 					{
9431 						return false;
9432 					}
9433 					i--;
9434 					if(j=nmlvdi->item.iSubItem==0)
9435 					{
9436 						if(i < 0x20000)
9437 							_stprintf(buf, TEXT("%06X"), i+0x7E0000);
9438 						else if(i < 0x30000)
9439 							_stprintf(buf, TEXT("s%05X"), i-0x20000);
9440 						else
9441 							_stprintf(buf, TEXT("i%05X"), i-0x30000);
9442 						nmlvdi->item.pszText=buf;
9443 						nmlvdi->item.cchTextMax=8;
9444 					}
9445 					if(j=nmlvdi->item.iSubItem==1)
9446 					{
9447 						int q=0, r=0;
9448 						if(i < 0x20000)
9449 							for(r=0;r<=bytes;r++)
9450 								q+=(Cheat.RAM[i+r])<<(8*r);
9451 						else if(i < 0x30000)
9452 							for(r=0;r<=bytes;r++)
9453 								q+=(Cheat.SRAM[(i-0x20000)+r])<<(8*r);
9454 						else
9455 							for(r=0;r<=bytes;r++)
9456 								q+=(Cheat.FillRAM[(i-0x30000)+r])<<(8*r);
9457 						//needs to account for size
9458 						switch(val_type)
9459 						{
9460 						case 1:
9461 							_stprintf(buf, TEXT("%u"), q);
9462 							break;
9463 						case 3:
9464 							{
9465 								switch(bytes)
9466 								{
9467 									default:
9468 									case S9X_8_BITS:  _stprintf(buf, TEXT("%02X"), q&0xFF);break;
9469 									case S9X_16_BITS: _stprintf(buf, TEXT("%04X"), q&0xFFFF); break;
9470 									case S9X_24_BITS: _stprintf(buf, TEXT("%06X"), q&0xFFFFFF);break;
9471 									case S9X_32_BITS: _stprintf(buf, TEXT("%08X"), q);break;
9472 								}
9473 							}
9474 							break;
9475 						case 2:
9476 							default:
9477 								switch(bytes)
9478 								{
9479 									default:
9480 									case S9X_8_BITS:
9481 										if((q-128)<0)
9482 											_stprintf(buf, TEXT("%d"), q&0xFF);
9483 										else _stprintf(buf, TEXT("%d"), q-256);
9484 										break;
9485 									case S9X_16_BITS:
9486 										if((q-32768)<0)
9487 											_stprintf(buf, TEXT("%d"), q&0xFFFF);
9488 										else _stprintf(buf, TEXT("%d"), q-65536);
9489 										break;
9490 									case S9X_24_BITS:
9491 										if((q-0x800000)<0)
9492 											_stprintf(buf, TEXT("%d"), q&0xFFFFFF);
9493 										else _stprintf(buf, TEXT("%d"), q-0x1000000);
9494 										break;
9495 
9496 									case S9X_32_BITS: _stprintf(buf, TEXT("%d"), q);break;
9497 								}
9498 								break;
9499 						}
9500 						nmlvdi->item.pszText=buf;
9501 						nmlvdi->item.cchTextMax=4;
9502 					}
9503 					if(j=nmlvdi->item.iSubItem==2)
9504 					{
9505 						int q=0, r=0;
9506 						if(i < 0x20000)
9507 							for(r=0;r<=bytes;r++)
9508 								q+=(Cheat.CWRAM[i+r])<<(8*r);
9509 						else if(i < 0x30000)
9510 							for(r=0;r<=bytes;r++)
9511 								q+=(Cheat.CSRAM[(i-0x20000)+r])<<(8*r);
9512 						else
9513 							for(r=0;r<=bytes;r++)
9514 								q+=(Cheat.CIRAM[(i-0x30000)+r])<<(8*r);
9515 						//needs to account for size
9516 						switch(val_type)
9517 						{
9518 						case 1:
9519 							_stprintf(buf, TEXT("%u"), q);
9520 							break;
9521 						case 3:
9522 							{
9523 								switch(bytes)
9524 								{
9525 									default:
9526 									case S9X_8_BITS:_stprintf(buf, TEXT("%02X"), q&0xFF);break;
9527 									case S9X_16_BITS: _stprintf(buf, TEXT("%04X"), q&0xFFFF); break;
9528 									case S9X_24_BITS: _stprintf(buf, TEXT("%06X"), q&0xFFFFFF);break;
9529 									case S9X_32_BITS: _stprintf(buf, TEXT("%08X"), q);break;
9530 								}
9531 								break;
9532 							}
9533 						case 2:
9534 							default:
9535 								switch(bytes)
9536 								{
9537 									default:
9538 									case S9X_8_BITS:
9539 										if((q-128)<0)
9540 											_stprintf(buf, TEXT("%d"), q&0xFF);
9541 										else _stprintf(buf, TEXT("%d"), q-256);
9542 										break;
9543 									case S9X_16_BITS:
9544 										if((q-32768)<0)
9545 											_stprintf(buf, TEXT("%d"), q&0xFFFF);
9546 										else _stprintf(buf, TEXT("%d"), q-65536);
9547 										break;
9548 									case S9X_24_BITS:
9549 										if((q-0x800000)<0)
9550 											_stprintf(buf, TEXT("%d"), q&0xFFFFFF);
9551 										else _stprintf(buf, TEXT("%d"), q-0x1000000);
9552 										break;
9553 
9554 									case S9X_32_BITS: _stprintf(buf, TEXT("%d"), q);break;
9555 								}
9556 								break;
9557 						}
9558 						nmlvdi->item.pszText=buf;
9559 						nmlvdi->item.cchTextMax=4;
9560 					}
9561 					// nmlvdi->item.mask=LVIF_TEXT; // This is bad as wine relies on this to not change.
9562 
9563 				}
9564 				else if(nmh->hwndFrom == GetDlgItem(hDlg, IDC_ADDYS) && (nmh->code == (UINT)LVN_ITEMACTIVATE||nmh->code == (UINT)NM_CLICK))
9565 				{
9566 					bool enable=true;
9567 					if(-1==ListView_GetSelectionMark(nmh->hwndFrom))
9568 					{
9569 						enable=false;
9570 					}
9571 					EnableWindow(GetDlgItem(hDlg, IDC_C_ADD), enable);
9572                     EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), enable);
9573 				}
9574 				// allow typing in an address to jump to it
9575 				else if(nmh->hwndFrom == GetDlgItem(hDlg, IDC_ADDYS) && nmh->code == (UINT)LVN_ODFINDITEM)
9576 				{
9577 					LRESULT pResult;
9578 
9579 					// pNMHDR has information about the item we should find
9580 					// In pResult we should save which item that should be selected
9581 					NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)lParam;
9582 
9583 					/* pFindInfo->iStart is from which item we should search.
9584 					We search to bottom, and then restart at top and will stop
9585 					at pFindInfo->iStart, unless we find an item that match
9586 					*/
9587 
9588 					// Set the default return value to -1
9589 					// That means we didn't find any match.
9590 					pResult = -1;
9591 
9592 					//Is search NOT based on string?
9593 					if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
9594 					{
9595 						//This will probably never happend...
9596 						return pResult;
9597 					}
9598 
9599 					//This is the string we search for
9600 					const TCHAR *searchstr = pFindInfo->lvfi.psz;
9601 
9602 					int startPos = pFindInfo->iStart;
9603 					//Is startPos outside the list (happens if last item is selected)
9604 					if(startPos >= ListView_GetItemCount(GetDlgItem(hDlg,IDC_ADDYS)))
9605 						startPos = 0;
9606 
9607 					int currentPos, addrPos;
9608 					for(addrPos=0,currentPos=0;addrPos<(0x32000-bytes)&&currentPos<startPos;addrPos++)
9609 					{
9610 						if(TEST_BIT(Cheat.ALL_BITS, addrPos))
9611 							currentPos++;
9612 					}
9613 
9614 					pResult=currentPos;
9615 
9616 					if (addrPos>=0x32000 && addrPos!=0)
9617 						break;
9618 
9619 					// ignore leading 0's
9620 					while(searchstr[0] == '0' && searchstr[1] != '\0')
9621 						searchstr++;
9622 
9623 					int searchNum = 0;
9624 
9625 					ScanAddress(searchstr, searchNum);
9626 
9627 
9628 //					if (searchstr[0] != '7')
9629 //						break; // all searchable addresses begin with a 7
9630 
9631 					bool looped = false;
9632 
9633 					// perform search
9634 					do
9635 					{
9636 
9637 						if(addrPos == searchNum)
9638 						{
9639 							// select this item and stop search
9640 							pResult = currentPos;
9641 							break;
9642 						}
9643 						else if(addrPos > searchNum)
9644 						{
9645 							if(looped)
9646 							{
9647 								pResult = currentPos;
9648 								break;
9649 							}
9650 
9651 							// optimization: the items are ordered alphabetically, so go back to the top since we know it can't be anything further down
9652 							currentPos = 0;
9653 							addrPos = 0;
9654 							while(!TEST_BIT(Cheat.ALL_BITS, addrPos))
9655 								addrPos++;
9656 							looped = true;
9657 							continue;
9658 						}
9659 
9660 						//Go to next item
9661 						addrPos++;
9662 						while(!TEST_BIT(Cheat.ALL_BITS, addrPos))
9663 							addrPos++;
9664 						currentPos++;
9665 
9666 						//Need to restart at top?
9667 						if(currentPos >= ListView_GetItemCount(GetDlgItem(hDlg,IDC_ADDYS)))
9668 						{
9669 							currentPos = 0;
9670 							addrPos = 0;
9671 							while(!TEST_BIT(Cheat.ALL_BITS, addrPos))
9672 								addrPos++;
9673 						}
9674 
9675 					//Stop if back to start
9676 					}while(currentPos != startPos);
9677 
9678 					foundItemOverride = pResult;
9679 
9680 					// in case previously-selected item is 0
9681 					ListView_SetItemState (GetDlgItem(hDlg,IDC_ADDYS), 1, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
9682 
9683 					return pResult; // HACK: for some reason this selects the first item instead of what it's returning... current workaround is to manually re-select this return value upon the next changed event
9684 				}
9685 				else if(nmh->hwndFrom == GetDlgItem(hDlg, IDC_ADDYS) && nmh->code == LVN_ITEMCHANGED)
9686 				{
9687 					// hack - see note directly above
9688 					LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
9689 					if(lpnmlv->uNewState & (LVIS_SELECTED|LVIS_FOCUSED))
9690 					{
9691 						if(foundItemOverride != -1 && lpnmlv->iItem == 0)
9692 						{
9693 							ListView_SetItemState (GetDlgItem(hDlg,IDC_ADDYS), foundItemOverride, LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
9694 							ListView_EnsureVisible (GetDlgItem(hDlg,IDC_ADDYS), foundItemOverride, FALSE);
9695 							selectionMarkOverride = foundItemOverride;
9696 							foundItemOverride = -1;
9697 						}
9698 						else
9699 						{
9700 							selectionMarkOverride = lpnmlv->iItem;
9701 						}
9702 					}
9703 				}
9704 			}
9705 		}
9706 		break;
9707 	case WM_ACTIVATE:
9708 		ListView_RedrawItems(GetDlgItem(hDlg, IDC_ADDYS),0, 0x32000);
9709 		break;
9710 	case WM_COMMAND:
9711 		{
9712 			switch(LOWORD(wParam))
9713 			{
9714 			case IDC_LESS_THAN:
9715 			case IDC_GREATER_THAN:
9716 			case IDC_LESS_THAN_EQUAL:
9717 			case IDC_GREATER_THAN_EQUAL:
9718 			case IDC_EQUAL:
9719 			case IDC_NOT_EQUAL:
9720 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_LESS_THAN))
9721 					comp_type=S9X_LESS_THAN;
9722 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_GREATER_THAN))
9723 					comp_type=S9X_GREATER_THAN;
9724 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_LESS_THAN_EQUAL))
9725 					comp_type=S9X_LESS_THAN_OR_EQUAL;
9726 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_GREATER_THAN_EQUAL))
9727 					comp_type=S9X_GREATER_THAN_OR_EQUAL;
9728 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_EQUAL))
9729 					comp_type=S9X_EQUAL;
9730 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_NOT_EQUAL))
9731 					comp_type=S9X_NOT_EQUAL;
9732 
9733 				break;
9734 			case IDC_1_BYTE:
9735 			case IDC_2_BYTE:
9736 			case IDC_3_BYTE:
9737 			case IDC_4_BYTE:
9738 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_1_BYTE))
9739 					bytes=S9X_8_BITS;
9740 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_2_BYTE))
9741 					bytes=S9X_16_BITS;
9742 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_3_BYTE))
9743 					bytes=S9X_24_BITS;
9744 				else bytes=S9X_32_BITS;
9745 				{
9746 					int l = CheatCount(bytes);
9747 					ListView_SetItemCount (GetDlgItem(hDlg, IDC_ADDYS), l);
9748 				}
9749 
9750 				break;
9751 
9752 			case IDC_SIGNED:
9753 			case IDC_UNSIGNED:
9754 			case IDC_HEX:
9755 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_UNSIGNED))
9756 					val_type=1;
9757 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_SIGNED))
9758 					val_type=2;
9759 				else val_type=3;
9760 				ListView_RedrawItems(GetDlgItem(hDlg, IDC_ADDYS),0, 0x32000);
9761 				break;
9762 			case IDC_C_ADD:
9763 				{
9764 					// account for size
9765 					struct ICheat cht;
9766 //					int idx=-1;
9767 					LVITEM lvi;
9768 					static TCHAR buf[12]; // the following code assumes this variable is static, I think
9769 					memset(&cht, 0, sizeof(struct SCheat));
9770 
9771 					//retrieve and convert to SCheat
9772 
9773 					if(bytes==S9X_8_BITS)
9774 						cht.size=1;
9775 					else if (bytes==S9X_16_BITS)
9776 						cht.size=2;
9777 					else if (bytes==S9X_24_BITS)
9778 						cht.size=3;
9779 					else if (bytes==S9X_32_BITS)
9780 						cht.size=4;
9781 
9782 
9783 					ITEM_QUERY(lvi, IDC_ADDYS, 0, buf, 7);
9784 
9785 
9786 					ScanAddress(buf, cht.address);
9787 
9788 					memset(buf, 0, sizeof(TCHAR) * 7);
9789 					if(val_type==1)
9790 					{
9791 						ITEM_QUERY(lvi, IDC_ADDYS, 1, buf, 12);
9792 						_stscanf(buf, TEXT("%u"), &cht.new_val);
9793 						memset(buf, 0, sizeof(TCHAR) * 7);
9794 						ITEM_QUERY(lvi, IDC_ADDYS, 2, buf, 12);
9795 						_stscanf(buf, TEXT("%u"), &cht.saved_val);
9796 					}
9797 					else if(val_type==3)
9798 					{
9799 						ITEM_QUERY(lvi, IDC_ADDYS, 1, buf, 12);
9800 						_stscanf(buf, TEXT("%x"), &cht.new_val);
9801 						memset(buf, 0, sizeof(TCHAR) * 7);
9802 						ITEM_QUERY(lvi, IDC_ADDYS, 2, buf, 12);
9803 						_stscanf(buf, TEXT("%x"), &cht.saved_val);
9804 					}
9805 					else
9806 					{
9807 						ITEM_QUERY(lvi, IDC_ADDYS, 1, buf, 12);
9808 						_stscanf(buf, TEXT("%d"), &cht.new_val);
9809 						memset(buf, 0, sizeof(TCHAR) * 7);
9810 						ITEM_QUERY(lvi, IDC_ADDYS, 2, buf, 12);
9811 						_stscanf(buf, TEXT("%d"), &cht.saved_val);
9812 					}
9813 					cht.format=val_type;
9814 					//invoke dialog
9815 					DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_FROM_SEARCH), hDlg, DlgCheatSearchAdd, (LPARAM)&cht);
9816 				}
9817 				break;
9818 			case IDC_C_RESET:
9819 				S9xStartCheatSearch(&Cheat);
9820 				{
9821 					int l = CheatCount(bytes);
9822 					ListView_SetItemCount (GetDlgItem(hDlg, IDC_ADDYS), l);
9823 				}
9824 				ListView_RedrawItems(GetDlgItem(hDlg, IDC_ADDYS),0, 0x32000);
9825 				//val_type=1;
9826 				//SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);
9827 				//SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_UNCHECKED, 0);
9828 				//SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_UNCHECKED, 0);
9829 
9830 				//bytes=S9X_8_BITS;
9831 				//SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);
9832 				//SendDlgItemMessage(hDlg, IDC_2_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9833 				//SendDlgItemMessage(hDlg, IDC_3_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9834 				//SendDlgItemMessage(hDlg, IDC_4_BYTE, BM_SETCHECK, BST_UNCHECKED, 0);
9835 
9836 
9837 				//use_entered=0;
9838 				//SendDlgItemMessage(hDlg, IDC_PREV, BM_SETCHECK, BST_CHECKED, 0);
9839 				//SendDlgItemMessage(hDlg, IDC_ENTERED, BM_SETCHECK, BST_UNCHECKED, 0);
9840 				//SendDlgItemMessage(hDlg, IDC_ENTEREDADDRESS, BM_SETCHECK, BST_UNCHECKED, 0);
9841 				//EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), false);
9842 				//EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), false);
9843 
9844 				//comp_type=S9X_LESS_THAN;
9845 				//SendDlgItemMessage(hDlg, IDC_LESS_THAN, BM_SETCHECK, BST_CHECKED, 0);
9846 				//SendDlgItemMessage(hDlg, IDC_GREATER_THAN, BM_SETCHECK, BST_UNCHECKED, 0);
9847 				//SendDlgItemMessage(hDlg, IDC_LESS_THAN_EQUAL, BM_SETCHECK, BST_UNCHECKED, 0);
9848 				//SendDlgItemMessage(hDlg, IDC_GREATER_THAN_EQUAL, BM_SETCHECK, BST_UNCHECKED, 0);
9849 				//SendDlgItemMessage(hDlg, IDC_EQUAL, BM_SETCHECK, BST_UNCHECKED, 0);
9850 				//SendDlgItemMessage(hDlg, IDC_NOT_EQUAL, BM_SETCHECK, BST_UNCHECKED, 0);
9851 				return true;
9852 			case IDC_C_WATCH:
9853 				{
9854 					uint32 address = (uint32)-1;
9855 					TCHAR buf [12];
9856 					LVITEM lvi;
9857 					ITEM_QUERY(lvi, IDC_ADDYS, 0, buf, 7);
9858 					ScanAddress(buf, address);
9859 					{
9860 						memset(buf, 0, sizeof(TCHAR) * 7);
9861 
9862 						unsigned int i;
9863 						for(i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
9864 							if(!watches[i].on || watches[i].address == address)
9865 								break;
9866 						if(i >= sizeof(watches)/sizeof(*watches))
9867 							i = (unsigned int)(sizeof(watches)/sizeof(*watches)-1);
9868 
9869 						watches[i].on = true;
9870 
9871 						// account for size
9872 						if(bytes==S9X_8_BITS)
9873 							watches[i].size=1;
9874 						else if (bytes==S9X_16_BITS)
9875 							watches[i].size=2;
9876 						else if (bytes==S9X_24_BITS)
9877 							watches[i].size=3;
9878 						else if (bytes==S9X_32_BITS)
9879 							watches[i].size=4;
9880 
9881 						watches[i].format=val_type;
9882 						watches[i].address=address;
9883 						strncpy(watches[i].buf,_tToChar(buf),12);
9884 						if(address < 0x7E0000 + 0x20000)
9885 							sprintf(watches[i].desc, "%6X", address);
9886 						else if(address < 0x7E0000 + 0x30000)
9887 							sprintf(watches[i].desc, "s%05X", address - 0x7E0000 - 0x20000);
9888 						else
9889 							sprintf(watches[i].desc, "i%05X", address - 0x7E0000 - 0x30000);
9890 					}
9891 					{
9892 						RECT rect;
9893 						GetClientRect (GUI.hWnd, &rect);
9894 						InvalidateRect (GUI.hWnd, &rect, true);
9895 					}
9896 				}
9897 				break;
9898 			case IDC_C_CLEARWATCH:
9899 				{
9900 					for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
9901 						watches[i].on = false;
9902 					{
9903 						RECT rect;
9904 						GetClientRect (GUI.hWnd, &rect);
9905 						InvalidateRect (GUI.hWnd, &rect, true);
9906 					}
9907 				}
9908 				break;
9909 			case IDC_C_LOADWATCH:
9910 				{
9911 					OPENFILENAME  ofn;
9912 					TCHAR  szFileName[MAX_PATH];
9913 					TCHAR  szPathName[MAX_PATH];
9914 					lstrcpy(szFileName, TEXT("watches"));
9915 					_tfullpath(szPathName, S9xGetDirectoryT(CHEAT_DIR), MAX_PATH);
9916 
9917 					memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) );
9918 					ofn.lStructSize = sizeof(OPENFILENAME);
9919 					ofn.hwndOwner = GUI.hWnd;
9920 					ofn.lpstrFilter = FILE_INFO_TXT_FILE_TYPE TEXT("\0*.txt\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0");
9921 					ofn.lpstrFile = szFileName;
9922 					ofn.lpstrDefExt = TEXT("txt");
9923 					ofn.nMaxFile = MAX_PATH;
9924 					ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
9925 					ofn.lpstrInitialDir = szPathName;
9926 					if(GetOpenFileName( &ofn ))
9927 					{
9928 						FILE *file = _tfopen(szFileName, TEXT("r"));
9929 						if(file)
9930 						{
9931 							unsigned int i;
9932 							for(i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
9933 								watches[i].on = false;
9934 							for(i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
9935 							{
9936 								char nameStr [32];
9937 								nameStr[0]='?'; nameStr[1]='\0';
9938 								fscanf(file, " address = 0x%x, name = \"%31[^\"]\", size = %d, format = %d\n", &watches[i].address, nameStr, &watches[i].size, &watches[i].format);
9939 								if(nameStr[0] == '\0' || nameStr[0] == '?')
9940 								{
9941 									if(watches[i].address < 0x7E0000 + 0x20000)
9942 										sprintf(nameStr, "%06X", watches[i].address);
9943 									else if(watches[i].address < 0x7E0000 + 0x30000)
9944 										sprintf(nameStr, "s%05X", watches[i].address - 0x7E0000 - 0x20000);
9945 									else
9946 										sprintf(nameStr, "i%05X", watches[i].address - 0x7E0000 - 0x30000);
9947 								}
9948 								nameStr[31] = '\0';
9949 								if(!ferror(file))
9950 								{
9951 									watches[i].on = true;
9952 									watches[i].buf[0] = '\0';
9953 									strncpy(watches[i].desc, nameStr, sizeof(watches[i].desc)); watches[i].desc[sizeof(watches[i].desc)-1]='\0';
9954 								}
9955 								if(ferror(file) || feof(file))
9956 									break;
9957 							}
9958 							fclose(file);
9959 						}
9960 					}
9961 					{
9962 						RECT rect;
9963 						GetClientRect (GUI.hWnd, &rect);
9964 						InvalidateRect (GUI.hWnd, &rect, true);
9965 					}
9966 				}
9967 				break;
9968 			case IDC_C_SAVEWATCH:
9969 				{
9970 					OPENFILENAME  ofn;
9971 					TCHAR  szFileName[MAX_PATH];
9972 					TCHAR  szPathName[MAX_PATH];
9973 					lstrcpy(szFileName, TEXT("watches"));
9974 					_tfullpath(szPathName, S9xGetDirectoryT(CHEAT_DIR), MAX_PATH);
9975 
9976 					memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) );
9977 					ofn.lStructSize = sizeof(OPENFILENAME);
9978 					ofn.hwndOwner = GUI.hWnd;
9979 					ofn.lpstrFilter = FILE_INFO_TXT_FILE_TYPE TEXT("\0*.txt\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0");
9980 					ofn.lpstrFile = szFileName;
9981 					ofn.lpstrDefExt = TEXT("txt");
9982 					ofn.nMaxFile = MAX_PATH;
9983 					ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
9984 					ofn.lpstrInitialDir = szPathName;
9985 					if(GetSaveFileName( &ofn ))
9986 					{
9987 						FILE *file = _tfopen(szFileName, TEXT("w"));
9988 						if(file)
9989 						{
9990 							for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
9991 								if(watches[i].on)
9992 //									fprintf(file, "address = 0x%x, name = \"%6X\", size = %d, format = %d\n", watches[i].address, watches[i].address, watches[i].size, watches[i].format);
9993 									fprintf(file, "address = 0x%x, name = \"?\", size = %d, format = %d\n", watches[i].address, watches[i].size, watches[i].format);
9994 							fclose(file);
9995 						}
9996 					}
9997 					{
9998 						RECT rect;
9999 						GetClientRect (GUI.hWnd, &rect);
10000 						InvalidateRect (GUI.hWnd, &rect, true);
10001 					}
10002 				}
10003 				break;
10004 
10005 			case IDC_REFRESHLIST:
10006 				ListView_RedrawItems(GetDlgItem(hDlg, IDC_ADDYS),0, 0x32000);
10007 				break;
10008 
10009 			case IDC_ENTERED:
10010 			case IDC_ENTEREDADDRESS:
10011 			case IDC_PREV:
10012 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ENTERED))
10013 				{
10014 					use_entered=1;
10015 					EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), true);
10016 					EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), true);
10017 				}
10018 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ENTEREDADDRESS))
10019 				{
10020 					use_entered=2;
10021 					EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), true);
10022 					EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), true);
10023 				}
10024 				else
10025 				{
10026 					use_entered=0;
10027 					EnableWindow(GetDlgItem(hDlg, IDC_VALUE_ENTER), false);
10028 					EnableWindow(GetDlgItem(hDlg, IDC_ENTER_LABEL), false);
10029 				}
10030 				return true;
10031 				break;
10032 			case IDC_C_SEARCH:
10033 				{
10034 				val_type=0;
10035 
10036 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_LESS_THAN))
10037 					comp_type=S9X_LESS_THAN;
10038 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_GREATER_THAN))
10039 					comp_type=S9X_GREATER_THAN;
10040 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_LESS_THAN_EQUAL))
10041 					comp_type=S9X_LESS_THAN_OR_EQUAL;
10042 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_GREATER_THAN_EQUAL))
10043 					comp_type=S9X_GREATER_THAN_OR_EQUAL;
10044 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_EQUAL))
10045 					comp_type=S9X_EQUAL;
10046 				else comp_type=S9X_NOT_EQUAL;
10047 
10048 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_UNSIGNED))
10049 					val_type=1;
10050 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_SIGNED))
10051 					val_type=2;
10052 				else val_type=3;
10053 
10054 
10055 
10056 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_1_BYTE))
10057 					bytes=S9X_8_BITS;
10058 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_2_BYTE))
10059 					bytes=S9X_16_BITS;
10060 				else if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_3_BYTE))
10061 					bytes=S9X_24_BITS;
10062 				else bytes=S9X_32_BITS;
10063 
10064 
10065 				if(BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ENTERED) ||
10066 				   BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_ENTEREDADDRESS))
10067 				{
10068 					TCHAR buf[20];
10069 					GetDlgItemText(hDlg, IDC_VALUE_ENTER, buf, 20);
10070 					uint32 value;
10071 					int ret;
10072 					if(use_entered==2)
10073 					{
10074 						ret = ScanAddress(buf, value);
10075 						value -= 0x7E0000;
10076 						S9xSearchForAddress (&Cheat, comp_type, bytes, value, FALSE);
10077 					}
10078 					else
10079 					{
10080 						if(val_type==1)
10081 							ret=_stscanf(buf, TEXT("%ul"), &value);
10082 						else if (val_type==2)
10083 							ret=_stscanf(buf, TEXT("%d"), &value);
10084 						else ret=_stscanf(buf, TEXT("%x"), &value);
10085 
10086 
10087 						if(ret!=1||!TestRange(val_type, bytes, value))
10088 						{
10089 							MessageBox(hDlg, SEARCH_ERR_INVALIDSEARCHVALUE, SEARCH_TITLE_CHEATERROR, MB_OK);
10090 							return true;
10091 						}
10092 
10093 						S9xSearchForValue (&Cheat, comp_type,
10094 							bytes, value,
10095 							(val_type==2), FALSE);
10096 					}
10097 
10098 				}
10099 				else
10100 				{
10101 					S9xSearchForChange (&Cheat, comp_type,
10102                          bytes, (val_type==2), FALSE);
10103 				}
10104 				int l = CheatCount(bytes);
10105 				ListView_SetItemCount (GetDlgItem(hDlg, IDC_ADDYS), l);
10106 				}
10107 
10108 				// if non-modal, update "Prev. Value" column after Search
10109 				if(cheatSearchHWND)
10110 				{
10111 					CopyMemory(Cheat.CWRAM, Cheat.RAM, 0x20000);
10112 					CopyMemory(Cheat.CSRAM, Cheat.SRAM, 0x10000);
10113 					CopyMemory(Cheat.CIRAM, Cheat.FillRAM, 0x2000);
10114 				}
10115 
10116 
10117 				ListView_RedrawItems(GetDlgItem(hDlg, IDC_ADDYS),0, 0x32000);
10118 				return true;
10119 				break;
10120 			case IDOK:
10121 				CopyMemory(Cheat.CWRAM, Cheat.RAM, 0x20000);
10122 				CopyMemory(Cheat.CSRAM, Cheat.SRAM, 0x10000);
10123 				CopyMemory(Cheat.CIRAM, Cheat.FillRAM, 0x2000);
10124 				/* fall through */
10125 			case IDCANCEL:
10126                 if(cheatSearchHWND)
10127 					DestroyWindow(hDlg);
10128 				else
10129 					EndDialog(hDlg, 0);
10130 				return true;
10131 			default: break;
10132 			}
10133 		}
10134 	default: return false;
10135 	}
10136 	return false;
10137 }
10138 
DlgCheatSearchAdd(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)10139 INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
10140 {
10141 	static struct ICheat* new_cheat;
10142 	int ret=-1;
10143 	switch(msg)
10144 	{
10145 	case WM_INITDIALOG:
10146 		WinRefreshDisplay();
10147 		{
10148 			TCHAR buf [12];
10149 			new_cheat=(struct ICheat*)lParam;
10150 			_stprintf(buf, TEXT("%06X"), new_cheat->address);
10151 			SetDlgItemText(hDlg, IDC_NC_ADDRESS, buf);
10152 			switch(new_cheat->format)
10153 			{
10154 			default:
10155 			case 1://UNSIGNED
10156 				memset(buf,0,sizeof(TCHAR) * 12);
10157 				_stprintf(buf, TEXT("%u"), new_cheat->new_val);
10158 				SetDlgItemText(hDlg, IDC_NC_CURRVAL, buf);
10159 				memset(buf,0,sizeof(TCHAR) * 12);
10160 				_stprintf(buf, TEXT("%u"), new_cheat->saved_val);
10161 				SetDlgItemText(hDlg, IDC_NC_PREVVAL, buf);
10162 				SetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_NEWVAL), GWL_STYLE, ES_NUMBER |GetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_NEWVAL),GWL_STYLE));
10163 				SetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_CURRVAL), GWL_STYLE, ES_NUMBER |GetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_CURRVAL),GWL_STYLE));
10164 				SetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_PREVVAL), GWL_STYLE, ES_NUMBER |GetWindowLongPtr(GetDlgItem(hDlg, IDC_NC_PREVVAL),GWL_STYLE));
10165 				if(new_cheat->size==1)
10166 				{
10167 					SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 3, 0);
10168 					SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 3, 0);
10169 					SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 3, 0);
10170 
10171 				}
10172 				if(new_cheat->size==2)
10173 				{
10174 					SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 5, 0);
10175 					SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 5, 0);
10176 					SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 5, 0);
10177 
10178 				}
10179 				if(new_cheat->size==3)
10180 				{
10181 					SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 8, 0);
10182 					SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 8, 0);
10183 					SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 8, 0);
10184 
10185 				}
10186 				if(new_cheat->size==4)
10187 				{
10188 					SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 10, 0);
10189 					SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 10, 0);
10190 					SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 10, 0);
10191 
10192 				}
10193 				break;
10194 			case 3:
10195 				{
10196 					TCHAR formatstring[10];
10197 					_stprintf(formatstring, TEXT("%%%02dX"),new_cheat->size*2);
10198 					memset(buf,0,sizeof(TCHAR) * 12);
10199 					_stprintf(buf, formatstring, new_cheat->new_val);
10200 					SetDlgItemText(hDlg, IDC_NC_CURRVAL, buf);
10201 					memset(buf,0,sizeof(TCHAR) * 12);
10202 					_stprintf(buf, formatstring, new_cheat->saved_val);
10203 					SetDlgItemText(hDlg, IDC_NC_PREVVAL, buf);
10204 					SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, new_cheat->size*2, 0);
10205 					SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, new_cheat->size*2, 0);
10206 					SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, new_cheat->size*2, 0);
10207 
10208 				}
10209 				break; //HEX
10210 			case 2:
10211 			memset(buf,0,sizeof(TCHAR) * 12);
10212 			_stprintf(buf, TEXT("%d"), new_cheat->new_val);
10213 			SetDlgItemText(hDlg, IDC_NC_CURRVAL, buf);
10214 			memset(buf,0,sizeof(TCHAR) * 12);
10215 			_stprintf(buf, TEXT("%d"), new_cheat->saved_val);
10216 			SetDlgItemText(hDlg, IDC_NC_PREVVAL, buf);
10217 			if(new_cheat->size==1)
10218 			{
10219 				//-128
10220 				SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 4, 0);
10221 				SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 4, 0);
10222 				SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 4, 0);
10223 			}
10224 			if(new_cheat->size==2)
10225 			{
10226 				//-32768
10227 				SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 6, 0);
10228 				SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 6, 0);
10229 				SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 6, 0);
10230 			}
10231 			if(new_cheat->size==3)
10232 			{
10233 				//-8388608
10234 				SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 8, 0);
10235 				SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 8, 0);
10236 				SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 8, 0);
10237 			}
10238 			if(new_cheat->size==4)
10239 			{
10240 				//-2147483648
10241 				SendDlgItemMessage(hDlg, IDC_NC_CURRVAL,EM_SETLIMITTEXT, 11, 0);
10242 				SendDlgItemMessage(hDlg, IDC_NC_PREVVAL,EM_SETLIMITTEXT, 11, 0);
10243 				SendDlgItemMessage(hDlg, IDC_NC_NEWVAL,EM_SETLIMITTEXT, 11, 0);
10244 			}
10245 			break;
10246 			}
10247 		}
10248 			return true;
10249 		case WM_PAINT:
10250 		{
10251 		PAINTSTRUCT ps;
10252 		BeginPaint (hDlg, &ps);
10253 
10254 		EndPaint (hDlg, &ps);
10255 		}
10256 		return true;
10257 	case WM_COMMAND:
10258 		{
10259 			switch(LOWORD(wParam))
10260 			{
10261 			case IDOK:
10262 				{
10263 					int ret = 0;
10264 					TCHAR buf[23];
10265 					int temp=new_cheat->size;
10266 					S9xCheatDataSize tmp = S9X_8_BITS;
10267 					memset(new_cheat, 0, sizeof(struct SCheat));
10268 					new_cheat->size=temp;
10269 					GetDlgItemText(hDlg, IDC_NC_ADDRESS, buf, 7);
10270 					ScanAddress(buf, new_cheat->address);
10271 
10272 					if(temp==1)
10273 						tmp=S9X_8_BITS;
10274 					if(temp==2)
10275 						tmp=S9X_16_BITS;
10276 					if(temp==3)
10277 						tmp=S9X_24_BITS;
10278 					if(temp==4)
10279 						tmp=S9X_32_BITS;
10280 
10281 
10282 					if(0!=GetDlgItemText(hDlg, IDC_NC_NEWVAL, buf, 12))
10283 					{
10284 						if(new_cheat->format==2)
10285 							ret=_stscanf(buf, TEXT("%d"), &new_cheat->new_val);
10286 						else if(new_cheat->format==1)
10287 							ret=_stscanf(buf, TEXT("%u"), &new_cheat->new_val);
10288 						else if(new_cheat->format==3)
10289 							ret=_stscanf(buf, TEXT("%x"), &new_cheat->new_val);
10290 
10291 						if(ret!=1 || !TestRange(new_cheat->format, tmp, new_cheat->new_val))
10292 						{
10293 							MessageBox(hDlg, SEARCH_ERR_INVALIDNEWVALUE, SEARCH_TITLE_RANGEERROR, MB_OK);
10294 							return true;
10295 						}
10296 
10297 
10298 						if(0==GetDlgItemText(hDlg, IDC_NC_CURRVAL, buf, 12))
10299 							new_cheat->saved=FALSE;
10300 						else
10301 						{
10302 							int i;
10303 							if(new_cheat->format==2)
10304 								ret=_stscanf(buf, TEXT("%d"), &i);
10305 							else if(new_cheat->format==1)
10306 								ret=_stscanf(buf, TEXT("%u"), &i);
10307 							else if(new_cheat->format==3)
10308 								ret=_stscanf(buf, TEXT("%x"), &i);
10309 
10310 							if(ret!=1 || !TestRange(new_cheat->format, tmp, i))
10311 							{
10312 								MessageBox(hDlg, SEARCH_ERR_INVALIDCURVALUE, SEARCH_TITLE_RANGEERROR, MB_OK);
10313 								return true;
10314 							}
10315 
10316 
10317 							new_cheat->saved_val=i;
10318 							new_cheat->saved=TRUE;
10319 						}
10320 						TCHAR tempBuf[22];
10321 						GetDlgItemText(hDlg, IDC_NC_DESC, tempBuf, 22);
10322 						strncpy(new_cheat->name,_tToChar(tempBuf),22);
10323 
10324 						std::string code_string;
10325 						char code[10];
10326 						for (int byteIndex = 0; byteIndex < new_cheat->size; byteIndex++)
10327 						{
10328 							if (byteIndex > 0)
10329 								code_string += '+';
10330 							snprintf(code, 10, "%x=%x", new_cheat->address + byteIndex, (new_cheat->new_val >> (8 * byteIndex)) & 0xFF);
10331 							code_string += code;
10332 						}
10333 
10334 						int index = S9xAddCheatGroup(new_cheat->name, code_string.c_str());
10335 						if(index >= 0)
10336 							S9xEnableCheatGroup(index);
10337 
10338 						ret=0;
10339 					}
10340 				}
10341 
10342 			case IDCANCEL:
10343 				EndDialog(hDlg, ret);
10344 				return true;
10345 			default: break;
10346 			}
10347 		}
10348 	default: return false;
10349 	}
10350 }
10351 
set_movieinfo(const TCHAR * path,HWND hDlg)10352 static void set_movieinfo(const TCHAR* path, HWND hDlg)
10353 {
10354 	MovieInfo m;
10355 	int i;
10356 	int getInfoResult=FILE_NOT_FOUND;
10357 
10358 	if(lstrlen(path))
10359 		getInfoResult = S9xMovieGetInfo(_tToChar(path), &m);
10360 
10361 	if(getInfoResult!=FILE_NOT_FOUND)
10362 	{
10363 		TCHAR* p;
10364 		TCHAR tmpstr[128];
10365 		lstrcpyn(tmpstr, _tctime(&m.TimeCreated), 127);
10366 		tmpstr[127]=TEXT('\0');
10367 		if((p=_tcsrchr(tmpstr, TEXT('\n'))))
10368 			*p=TEXT('\0');
10369 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_DATE), tmpstr);
10370 
10371 		uint32 div = Memory.ROMFramesPerSecond;
10372 		if(!div) div = 60;
10373 		uint32 l=(m.LengthFrames+(div>>1))/div;
10374 		uint32 seconds=l%60;
10375 		l/=60;
10376 		uint32 minutes=l%60;
10377 		l/=60;
10378 		uint32 hours=l%60;
10379 		_stprintf(tmpstr, TEXT("%02d:%02d:%02d"), hours, minutes, seconds);
10380 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_LENGTH), tmpstr);
10381 		_stprintf(tmpstr, TEXT("%u"), m.LengthFrames);
10382 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_FRAMES), tmpstr);
10383 		_stprintf(tmpstr, TEXT("%u"), m.RerecordCount);
10384 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_RERECORD), tmpstr);
10385 	}
10386 	else
10387 	{
10388 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_DATE), TEXT(""));
10389 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_LENGTH), TEXT(""));
10390 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_FRAMES), TEXT(""));
10391 		SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_RERECORD), TEXT(""));
10392 	}
10393 
10394 	if(getInfoResult==SUCCESS)
10395 	{
10396 		// set author comment:
10397 		{
10398 ///			SetWindowTextW(GetDlgItem(hDlg, IDC_MOVIE_METADATA), m.Metadata); // won't work, because of & symbol
10399 
10400 			wchar_t metadata [MOVIE_MAX_METADATA];
10401 			int j, pos = 0, len = wcslen(m.Metadata);
10402 			for (j = 0; j < len ; j++)
10403 			{
10404 				wchar_t c = m.Metadata [j];
10405 				metadata [pos++] = c;
10406 
10407 				// & is a special character in Windows fields,
10408 				// so we have to change & to && when copying over the game title
10409 				// otherwise "Pocky & Rocky" will show up as "Pocky  Rocky", for example
10410 				if(c == (wchar_t)'&')
10411 					metadata [pos++] = (wchar_t)'&';
10412 			}
10413 			metadata [pos] = (wchar_t)'\0';
10414 
10415 			SetWindowTextW(GetDlgItem(hDlg, IDC_MOVIE_METADATA), metadata);
10416 		}
10417 		SetWindowText(GetDlgItem(hDlg, IDC_LABEL_MOVIEINFOBOX), MOVIE_LABEL_AUTHORINFO);
10418 
10419 		if(m.ReadOnly)
10420 		{
10421 			EnableWindow(GetDlgItem(hDlg, IDC_READONLY), FALSE);
10422 			SendDlgItemMessage(hDlg,IDC_READONLY,BM_SETCHECK,BST_CHECKED,0);
10423 		}
10424 		else
10425 		{
10426 			EnableWindow(GetDlgItem(hDlg, IDC_READONLY), TRUE);
10427 ///			SendDlgItemMessage(hDlg,IDC_READONLY,BM_SETCHECK,BST_UNCHECKED,0);
10428 		}
10429 		EnableWindow(GetDlgItem(hDlg, IDC_DISPLAY_INPUT), TRUE);
10430 
10431 		for(i=0; i<5; ++i)
10432 		{
10433 			SendDlgItemMessage(hDlg,IDC_JOY1+i,BM_SETCHECK,(m.ControllersMask & (1<<i)) ? BST_CHECKED : BST_UNCHECKED,0);
10434 		}
10435 
10436 		if(m.Opts & MOVIE_OPT_FROM_RESET)
10437 		{
10438 			SendDlgItemMessage(hDlg,IDC_RECORD_NOW,BM_SETCHECK,BST_UNCHECKED,0);
10439 			SendDlgItemMessage(hDlg,IDC_RECORD_RESET,BM_SETCHECK,BST_CHECKED,0);
10440 		}
10441 		else
10442 		{
10443 			SendDlgItemMessage(hDlg,IDC_RECORD_RESET,BM_SETCHECK,BST_UNCHECKED,0);
10444 			SendDlgItemMessage(hDlg,IDC_RECORD_NOW,BM_SETCHECK,BST_CHECKED,0);
10445 		}
10446 
10447 
10448 //		if(m.SyncFlags & MOVIE_SYNC_DATA_EXISTS)
10449 		{
10450 	//		SetWindowText(GetDlgItem(hDlg, IDC_LOADEDFROMMOVIE), _T(MOVIE_LABEL_SYNC_DATA_FROM_MOVIE));
10451 		}
10452 
10453 		{
10454 			TCHAR str [256];
10455 
10456 			if(m.SyncFlags & MOVIE_SYNC_HASROMINFO)
10457 			{
10458 				_stprintf(str, MOVIE_INFO_MOVIEROM MOVIE_INFO_ROMINFO, m.ROMCRC32, (TCHAR *)_tFromChar(m.ROMName));
10459 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIEROMINFO), str);
10460 			}
10461 			else
10462 			{
10463 				_stprintf(str, MOVIE_INFO_MOVIEROM MOVIE_INFO_ROMNOTSTORED);
10464 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIEROMINFO), str);
10465 			}
10466 
10467 			bool mismatch = (m.SyncFlags & MOVIE_SYNC_HASROMINFO) && m.ROMCRC32 != Memory.ROMCRC32;
10468 			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO TEXT("%s"), Memory.ROMCRC32, (TCHAR *)_tFromChar(Memory.ROMName), mismatch?MOVIE_INFO_MISMATCH:TEXT(""));
10469 			SetWindowText(GetDlgItem(hDlg, IDC_CURRENTROMINFO), str);
10470 
10471 			_stprintf(str, TEXT("%s"), mismatch?MOVIE_WARNING_MISMATCH:MOVIE_WARNING_OK);
10472 			SetWindowText(GetDlgItem(hDlg, IDC_PLAYWARN), str);
10473 		}
10474 
10475 		EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
10476 	}
10477 	else
10478 	{
10479 		// get the path of (where we think) the movie is
10480 		TCHAR tempPathStr [512];
10481 		lstrcpyn(tempPathStr, path, 512);
10482 		tempPathStr[511] = TEXT('\0');
10483 		TCHAR* slash = _tcsrchr(tempPathStr, TEXT('\\'));
10484 		slash = max(slash, _tcsrchr(tempPathStr, TEXT('/')));
10485 		if(slash) *slash = TEXT('\0');
10486 		TCHAR tempDirStr [512];
10487 		TCHAR dirStr [768];
10488 		_tfullpath(tempDirStr, tempPathStr, 512);
10489 		TCHAR* documeStr = _tcsstr(tempDirStr, TEXT("Documents and Settings"));
10490 		if(documeStr) { // abbreviate
10491 			lstrcpy(documeStr, documeStr+14);
10492 			lstrcpyn(documeStr, TEXT("docume~1"), 8);
10493 		}
10494 		_stprintf(dirStr, MOVIE_INFO_DIRECTORY, tempDirStr);
10495 
10496 		switch(getInfoResult)
10497 		{
10498 			default:
10499 				SetWindowText(GetDlgItem(hDlg, IDC_PLAYWARN), TEXT(""));
10500 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_METADATA), TEXT(""));
10501 				break;
10502 			case FILE_NOT_FOUND:
10503 				SetWindowText(GetDlgItem(hDlg, IDC_PLAYWARN), MOVIE_ERR_NOT_FOUND_SHORT);
10504 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_METADATA), MOVIE_ERR_NOT_FOUND);
10505 				break;
10506 			case WRONG_FORMAT:
10507 				SetWindowText(GetDlgItem(hDlg, IDC_PLAYWARN), MOVIE_ERR_WRONG_FORMAT_SHORT);
10508 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_METADATA), MOVIE_ERR_WRONG_FORMAT);
10509 				break;
10510 			case WRONG_VERSION:
10511 				SetWindowText(GetDlgItem(hDlg, IDC_PLAYWARN), MOVIE_ERR_WRONG_VERSION_SHORT);
10512 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_METADATA), MOVIE_ERR_WRONG_VERSION);
10513 				break;
10514 		}
10515 		SetWindowText(GetDlgItem(hDlg, IDC_LABEL_MOVIEINFOBOX), MOVIE_LABEL_ERRORINFO);
10516 
10517 		EnableWindow(GetDlgItem(hDlg, IDC_READONLY), FALSE);
10518 		EnableWindow(GetDlgItem(hDlg, IDC_DISPLAY_INPUT), FALSE);
10519 		SendDlgItemMessage(hDlg,IDC_READONLY,BM_SETCHECK,BST_UNCHECKED,0);
10520 		SendDlgItemMessage(hDlg,IDC_DISPLAY_INPUT,BM_SETCHECK,BST_UNCHECKED,0);
10521 
10522 
10523 		{
10524 			SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, Settings.UpAndDown ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
10525 			SendDlgItemMessage(hDlg,IDC_SYNC_TO_SOUND_CPU,BM_SETCHECK, Settings.SoundSync ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
10526 		}
10527 
10528 		{
10529 			TCHAR str [256];
10530 
10531 			// no movie loaded
10532 			SetWindowText(GetDlgItem(hDlg, IDC_MOVIEROMINFO), dirStr);
10533 
10534 			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO, Memory.ROMCRC32, (TCHAR *)_tFromChar(Memory.ROMName));
10535 			SetWindowText(GetDlgItem(hDlg, IDC_CURRENTROMINFO), str);
10536 		}
10537 
10538 		EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
10539 	}
10540 
10541 }
10542 
DlgOpenMovie(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)10543 INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
10544 {
10545 	static OpenMovieParams* op=NULL;
10546 	static TCHAR movieDirectory [MAX_PATH];
10547 
10548 	switch(msg)
10549 	{
10550 	case WM_INITDIALOG:
10551 		WinRefreshDisplay();
10552 		{
10553 			SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR));
10554 			_tfullpath (movieDirectory, GUI.MovieDir, MAX_PATH);
10555 			_tmkdir(movieDirectory);
10556 			SetCurrentDirectory(movieDirectory);
10557 
10558 			op=(OpenMovieParams*)lParam;
10559 
10560 			// get default filename
10561 			if(Memory.ROMFilename[0]!='\0')
10562 			{
10563 				static TCHAR filename [_MAX_PATH + 1];
10564 				TCHAR drive [_MAX_DRIVE + 1];
10565 				TCHAR dir [_MAX_DIR + 1];
10566 				TCHAR fname [_MAX_FNAME + 1];
10567 				TCHAR ext [_MAX_EXT + 1];
10568 				_tsplitpath (_tFromChar(Memory.ROMFilename), drive, dir, fname, ext);
10569 				_tmakepath (filename, TEXT(""), TEXT(""), fname, TEXT("smv"));
10570 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), filename);
10571 				set_movieinfo(filename, hDlg);
10572 			}
10573 			else
10574 			{
10575 				set_movieinfo(TEXT(""), hDlg);
10576 			}
10577 
10578 			SendDlgItemMessage(hDlg,IDC_READONLY,BM_SETCHECK,GUI.MovieReadOnly ? BST_CHECKED : BST_UNCHECKED,0);
10579 
10580 			SetDlgItemText(hDlg,IDC_LABEL_STARTSETTINGS, MOVIE_LABEL_STARTSETTINGS);
10581 			SetDlgItemText(hDlg,IDC_LABEL_CONTROLLERSETTINGS, MOVIE_LABEL_CONTSETTINGS);
10582 			SetDlgItemText(hDlg,IDC_LABEL_SYNCSETTINGS, MOVIE_LABEL_SYNCSETTINGS);
10583 		}
10584 		return true;
10585 
10586 	case WM_COMMAND:
10587 		{
10588 			switch(LOWORD(wParam))
10589 			{
10590 			case IDC_BROWSE_MOVIE:
10591 				{
10592 					OPENFILENAME  ofn;
10593 					TCHAR  szFileName[MAX_PATH];
10594 
10595 					szFileName[0] = TEXT('\0');
10596 
10597 					memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) );
10598 					ofn.lStructSize = sizeof(OPENFILENAME);
10599 					ofn.hwndOwner = hDlg;
10600 					ofn.lpstrFilter = MOVIE_FILETYPE_DESCRIPTION TEXT("\0*.smv\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0");
10601 					ofn.lpstrFile = szFileName;
10602 					ofn.lpstrDefExt = TEXT("smv");
10603 					ofn.nMaxFile = MAX_PATH;
10604 					ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; // hide previously-ignored read-only checkbox (the real read-only box is in the open-movie dialog itself)
10605 					ofn.lpstrInitialDir = movieDirectory;
10606 					if(GetOpenFileName( &ofn ))
10607 					{
10608 						SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), szFileName);
10609 
10610 						if(!GUI.LockDirectories)
10611 						{
10612 							TCHAR temp [256];
10613 							GetCurrentDirectory(MAX_PATH, temp);
10614 							absToRel(GUI.MovieDir, temp, S9xGetDirectoryT(DEFAULT_DIR));
10615 						}
10616 
10617 						set_movieinfo(szFileName, hDlg);
10618 					}
10619 					SetCurrentDirectory(movieDirectory);
10620 				}
10621 				return true;
10622 
10623 			case IDC_MOVIE_PATH:
10624 				{
10625 					TCHAR  szFileName[MAX_PATH];
10626 					GetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), szFileName, MAX_PATH);
10627 					set_movieinfo(szFileName, hDlg);
10628 				}
10629 				break;
10630 
10631 			case IDOK:
10632 				{
10633 					if(BST_CHECKED==SendDlgItemMessage(hDlg, IDC_READONLY, BM_GETCHECK,0,0))
10634 					{
10635 						op->ReadOnly=TRUE;
10636 						GUI.MovieReadOnly=TRUE;
10637 					}
10638 					else
10639 						GUI.MovieReadOnly=FALSE;
10640 					if(BST_CHECKED==SendDlgItemMessage(hDlg, IDC_DISPLAY_INPUT, BM_GETCHECK,0,0))
10641 						op->DisplayInput=TRUE;
10642 					GetDlgItemText(hDlg, IDC_MOVIE_PATH, op->Path, MAX_PATH);
10643 					SetCurrentDirectory(movieDirectory);
10644 				}
10645 				EndDialog(hDlg, 1);
10646 				return true;
10647 
10648 			case IDCANCEL:
10649 				EndDialog(hDlg, 0);
10650 				return true;
10651 
10652 			default:
10653 				break;
10654 			}
10655 		}
10656 
10657 	default:
10658 		return false;
10659 	}
10660 }
10661 
10662 // checks if the currently loaded ROM has an SRAM file in the saves directory that we have write access to
existsSRAM()10663 static bool existsSRAM ()
10664 {
10665   return(!access(S9xGetFilename(".srm", SRAM_DIR), R_OK|W_OK));
10666 }
10667 
DlgCreateMovie(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)10668 INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
10669 {
10670 	static OpenMovieParams* op=NULL;
10671 	static TCHAR movieDirectory [MAX_PATH];
10672 
10673 	switch(msg)
10674 	{
10675 	case WM_INITDIALOG:
10676 		{
10677 			WinRefreshDisplay();
10678 			SetCurrentDirectory(S9xGetDirectoryT(DEFAULT_DIR));
10679 			_tfullpath (movieDirectory, GUI.MovieDir, MAX_PATH);
10680 			_tmkdir(movieDirectory);
10681 			SetCurrentDirectory(movieDirectory);
10682 
10683 			// have to save here or the SRAM file might not exist when we check for it
10684 			// (which would cause clear SRAM option to not work)
10685 			Memory.SaveSRAM(S9xGetFilename (".srm", SRAM_DIR));
10686 
10687 
10688 			op=(OpenMovieParams*)lParam;
10689 
10690 			SendDlgItemMessage(hDlg,IDC_RECORD_RESET,BM_SETCHECK,BST_UNCHECKED,0);
10691 
10692 			int i;
10693 			for(i=1; i<5; ++i)
10694 			{
10695 				SendDlgItemMessage(hDlg,IDC_JOY1+i,BM_SETCHECK,BST_UNCHECKED,0);
10696 			}
10697 			SendDlgItemMessage(hDlg,IDC_JOY1,BM_SETCHECK,BST_CHECKED,0);
10698 
10699 			// get default filename
10700 			if(Memory.ROMFilename[0]!='\0')
10701 			{
10702 				static TCHAR filename [_MAX_PATH + 1];
10703 				TCHAR drive [_MAX_DRIVE + 1];
10704 				TCHAR dir [_MAX_DIR + 1];
10705 				TCHAR fname [_MAX_FNAME + 1];
10706 				TCHAR ext [_MAX_EXT + 1];
10707 				_tsplitpath (_tFromChar(Memory.ROMFilename), drive, dir, fname, ext);
10708 				_tmakepath (filename, TEXT(""), TEXT(""), fname, TEXT("smv"));
10709 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), filename);
10710 			}
10711 
10712 			//EnableWindow(GetDlgItem(hDlg, IDC_SYNC_TO_SOUND_CPU), Settings.SoundDriver<1||Settings.SoundDriver>3); // can't sync sound to CPU unless using "Snes9x DirectSound" driver
10713 
10714 			SendDlgItemMessage(hDlg,IDC_RECORD_RESET,BM_SETCHECK, (WPARAM)(GUI.MovieStartFromReset ? BST_CHECKED : BST_UNCHECKED), 0);
10715 			SendDlgItemMessage(hDlg,IDC_RECORD_NOW,BM_SETCHECK, (WPARAM)(GUI.MovieStartFromReset ? BST_UNCHECKED : BST_CHECKED), 0);
10716 			if(existsSRAM())
10717 			{
10718 				EnableWindow(GetDlgItem(hDlg, IDC_CLEARSRAM), GUI.MovieStartFromReset);
10719 				SendDlgItemMessage(hDlg,IDC_CLEARSRAM,BM_SETCHECK, (WPARAM)(GUI.MovieClearSRAM ? BST_CHECKED : BST_UNCHECKED), 0);
10720 			}
10721 			else
10722 			{
10723 				EnableWindow(GetDlgItem(hDlg, IDC_CLEARSRAM), false);
10724 				SendDlgItemMessage(hDlg,IDC_CLEARSRAM,BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
10725 			}
10726 
10727 			SetDlgItemText(hDlg,IDC_LABEL_STARTSETTINGS, MOVIE_LABEL_STARTSETTINGS);
10728 			SetDlgItemText(hDlg,IDC_LABEL_CONTROLLERSETTINGS, MOVIE_LABEL_CONTSETTINGS);
10729 			SetDlgItemText(hDlg,IDC_LABEL_SYNCSETTINGS, MOVIE_LABEL_SYNCSETTINGS);
10730 		}
10731 		return true;
10732 
10733 	case WM_COMMAND:
10734 		{
10735 			switch(LOWORD(wParam))
10736 			{
10737 			case IDC_BROWSE_MOVIE:
10738 				{
10739 					OPENFILENAME  ofn;
10740 					TCHAR  szFileName[MAX_PATH];
10741 
10742 					szFileName[0] = TEXT('\0');
10743 
10744 					memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) );
10745 					ofn.lStructSize = sizeof(OPENFILENAME);
10746 					ofn.hwndOwner = hDlg;
10747 					ofn.lpstrFilter = MOVIE_FILETYPE_DESCRIPTION TEXT("\0*.smv\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0");
10748 					ofn.lpstrFile = szFileName;
10749 					ofn.lpstrDefExt = TEXT("smv");
10750 					ofn.nMaxFile = MAX_PATH;
10751 					ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
10752 					ofn.lpstrInitialDir = movieDirectory;
10753 					if(GetSaveFileName( &ofn ))
10754 					{
10755 						SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), szFileName);
10756 
10757 						if(!GUI.LockDirectories)
10758 						{
10759 							TCHAR temp [256];
10760 							GetCurrentDirectory(MAX_PATH, temp);
10761 							absToRel(GUI.MovieDir, temp, S9xGetDirectoryT(DEFAULT_DIR));
10762 						}
10763 					}
10764 					SetCurrentDirectory(movieDirectory);
10765 				}
10766 				return true;
10767 
10768 			case IDOK:
10769 				{
10770 					GetDlgItemText(hDlg, IDC_MOVIE_PATH, op->Path, MAX_PATH);
10771 					GetDlgItemTextW(hDlg, IDC_MOVIE_METADATA, op->Metadata, MOVIE_MAX_METADATA);
10772 					int i;
10773 					for(i=wcslen(op->Metadata); i<32; i++)
10774 						wcscat(op->Metadata, L" ");
10775 					op->ControllersMask=0;
10776 					op->Opts=0;
10777 					for(i=0; i<5; ++i) // TODO: should we even bother with 8-controller recording? right now there are only 5 controller buttons in the dialog, so...
10778 					{
10779 						if(BST_CHECKED==SendDlgItemMessage(hDlg, IDC_JOY1+i, BM_GETCHECK,0,0))
10780 							op->ControllersMask |= (1<<i);
10781 					}
10782 					if(BST_CHECKED==SendDlgItemMessage(hDlg, IDC_RECORD_RESET, BM_GETCHECK,0,0))
10783 					{
10784 						op->Opts |= MOVIE_OPT_FROM_RESET;
10785 						GUI.MovieStartFromReset = TRUE;
10786 					}
10787 					else
10788 						GUI.MovieStartFromReset = FALSE;
10789 
10790 					op->SyncFlags = MOVIE_SYNC_DATA_EXISTS | MOVIE_SYNC_HASROMINFO;
10791 
10792 					if(IsDlgButtonChecked(hDlg, IDC_CLEARSRAM) && IsDlgButtonChecked(hDlg, IDC_RECORD_RESET) && existsSRAM())
10793 					{
10794 						GUI.MovieClearSRAM = TRUE;
10795 						remove(S9xGetFilename (".srm", SRAM_DIR)); // delete SRAM if it exists (maybe unnecessary?)
10796 						remove(S9xGetFilename (".srm", ROMFILENAME_DIR));
10797 						Memory.LoadSRAM(S9xGetFilename (".srm", SRAM_DIR)); // refresh memory (hard reset)
10798 					}
10799 					else if(!IsDlgButtonChecked(hDlg, IDC_CLEARSRAM) && IsDlgButtonChecked(hDlg, IDC_RECORD_RESET) && existsSRAM())
10800 					{
10801 						GUI.MovieClearSRAM = FALSE;
10802 					}
10803 					SetCurrentDirectory(movieDirectory);
10804 				}
10805 				EndDialog(hDlg, 1);
10806 				return true;
10807 
10808 			case IDCANCEL:
10809 				EndDialog(hDlg, 0);
10810 				return true;
10811 
10812 			case IDC_RECORD_NOW:
10813 				if(existsSRAM())
10814 				{
10815 					EnableWindow(GetDlgItem(hDlg, IDC_CLEARSRAM), false);
10816 				}
10817 				break;
10818 
10819 			case IDC_RECORD_RESET:
10820 				if(existsSRAM())
10821 				{
10822 					EnableWindow(GetDlgItem(hDlg, IDC_CLEARSRAM), true);
10823 				}
10824 				break;
10825 
10826 			default:
10827 				break;
10828 			}
10829 		}
10830 
10831 	default:
10832 		return false;
10833 	}
10834 }
10835 
10836 
10837 
10838 // MYO
S9xHandlePortCommand(s9xcommand_t cmd,int16 data1,int16 data2)10839 void S9xHandlePortCommand(s9xcommand_t cmd, int16 data1, int16 data2)
10840 {
10841 	return;
10842 }
10843 
10844 //  NYI
S9xChooseFilename(bool8 read_only)10845 const char *S9xChooseFilename (bool8 read_only)
10846 {
10847 	return NULL;
10848 }
10849 
10850 // NYI
S9xChooseMovieFilename(bool8 read_only)10851 const char *S9xChooseMovieFilename (bool8 read_only)
10852 {
10853 	return NULL;
10854 }
10855 
10856 
S9xStringInput(const char * msg)10857 const char * S9xStringInput(const char *msg)
10858 {
10859 	return NULL;
10860 }
10861 
S9xToggleSoundChannel(int c)10862 void S9xToggleSoundChannel (int c)
10863 {
10864 	if (c == 8)
10865 		GUI.SoundChannelEnable = 255;
10866     else
10867 		GUI.SoundChannelEnable ^= 1 << c;
10868 
10869 	S9xSetSoundControl(GUI.SoundChannelEnable);
10870 }
10871 
S9xPollButton(uint32 id,bool * pressed)10872 bool S9xPollButton(uint32 id, bool *pressed){
10873 	if(S9xMoviePlaying())
10874 		return false;
10875 
10876 	*pressed = false;
10877 
10878 #define CHECK_KEY(controller, button) (!S9xGetState(Joypad[controller].button) || (ToggleJoypadStorage[controller].button && !TurboToggleJoypadStorage[controller].button) || (IPPU.TotalEmulatedFrames%2 == ToggleJoypadStorage[controller].button && TurboToggleJoypadStorage[controller].button))
10879 
10880 	extern bool S9xGetState (WORD KeyIdent);
10881 	if (id & k_MO)	// mouse
10882 	{
10883 		switch (id & 0xFF)
10884 		{
10885 			case 0: *pressed = GUI.MouseButtons & 1 /* Left */ || ((id & k_C1) && (CHECK_KEY(0,A) || CHECK_KEY(0,L))) || ((id & k_C2) && (CHECK_KEY(1,A) || CHECK_KEY(1,L))); break;
10886 			case 1: *pressed = GUI.MouseButtons & 2 /* Right */ || ((id & k_C1) && (CHECK_KEY(0,B) || CHECK_KEY(0,R))) || ((id & k_C2) && (CHECK_KEY(1,B) || CHECK_KEY(1,R))); break;
10887 		}
10888 	}
10889 	else
10890 	if (id & k_SS)	// superscope
10891 	{
10892 		switch (id & 0xFF)
10893 		{
10894 			case 0:	*pressed = GUI.MouseX <= 0 || GUI.MouseY <= 0 || GUI.MouseX >= IPPU.RenderedScreenWidth || GUI.MouseY >= ((IPPU.RenderedScreenHeight> 256) ? SNES_HEIGHT_EXTENDED<<1 : SNES_HEIGHT_EXTENDED) || CHECK_KEY(1,X); break;
10895 			case 2:	*pressed = (GUI.MouseButtons & 2) /* Right */ || CHECK_KEY(1,B) || CHECK_KEY(1,R) ; break;
10896 			case 3:	*pressed = (GUI.MouseButtons & 4) /* Middle */ || GUI.superscope_turbo || CHECK_KEY(1,Y);	GUI.superscope_turbo=0; GUI.MouseButtons &= ~4; break;
10897 			case 4:	*pressed =                                        GUI.superscope_pause || CHECK_KEY(1,Start) || CHECK_KEY(1,Select);	break;
10898 			case 1:	*pressed = (GUI.MouseButtons & 1) /* Left */ || CHECK_KEY(1,A) || CHECK_KEY(1,L); break;
10899 		}
10900 	}
10901 	else
10902 	if (id & k_LG)	// justifier
10903 	{
10904 		if (id & k_C1)
10905 		{
10906 			switch (id & 0xFF)
10907 			{
10908 				case 0:	*pressed = GUI.MouseX <= 0 || GUI.MouseY <= 0 || GUI.MouseX >= IPPU.RenderedScreenWidth || GUI.MouseY >= ((IPPU.RenderedScreenHeight> 256) ? SNES_HEIGHT_EXTENDED<<1 : SNES_HEIGHT_EXTENDED) || CHECK_KEY(0,X) || CHECK_KEY(0,Start); break;
10909 				case 1:	*pressed = GUI.MouseButtons & 1 /* Left */  || CHECK_KEY(0,A) || CHECK_KEY(0,L); break;
10910 				case 2: *pressed = GUI.MouseButtons & 2 /* Right */  || CHECK_KEY(1,B) || CHECK_KEY(1,R); break;
10911 			}
10912 		}
10913 		else
10914 		{
10915 			switch (id & 0xFF)
10916 			{
10917 				case 0: *pressed = CHECK_KEY(1,Start) /* 2p Start */  || CHECK_KEY(1,X); break;
10918 				case 1:	*pressed = CHECK_KEY(1,A) /* 2p A */ || CHECK_KEY(1,L); break;
10919 				case 2: *pressed = CHECK_KEY(1,B) /* 2p B */ || CHECK_KEY(1,R); break;
10920 			}
10921 		}
10922 	}
10923 	else
10924 	if (id & k_RF)	// macsrifle
10925 	{
10926 		switch (id & 0xFF)
10927 		{
10928 			case 0:	*pressed = (GUI.MouseButtons & 1) /* Left */ || CHECK_KEY(1,A) || CHECK_KEY(1,L); break;
10929 		}
10930 	}
10931 
10932 	return (true);
10933 }
10934 
10935 // ??? NYI
S9xPollAxis(uint32 id,int16 * value)10936 bool S9xPollAxis(uint32 id, int16 *value){
10937     return false;
10938 }
10939 
S9xPollPointer(uint32 id,int16 * x,int16 * y)10940 bool S9xPollPointer(uint32 id, int16 *x, int16 *y){
10941 	if(S9xMoviePlaying())
10942 		return false;
10943 
10944 	if (id & k_PT)
10945 	{
10946 		*x = GUI.MouseX;
10947 		*y = GUI.MouseY;
10948 	}
10949 	else
10950 		*x = *y = 0;
10951 	return (true);
10952 }
10953 
10954 // adjusts settings based on ROM that was just loaded
S9xPostRomInit()10955 void S9xPostRomInit()
10956 {
10957 	// "Cheats are on" message if cheats are on and active,
10958 	// to make it less likely that someone will think there is some bug because of
10959 	// a lingering cheat they don't realize is on
10960 	if (Settings.ApplyCheats)
10961 	{
10962 		S9xCheatsEnable();
10963 		extern struct SCheatData Cheat;
10964 	    for (uint32 i = 0; i < Cheat.g.size(); i++)
10965 		{
10966 	        if (Cheat.g [i].enabled)
10967 			{
10968 				char String2 [1024];
10969 				sprintf(String2, "(CHEATS ARE ON!) %s", String);
10970 				strncpy(String, String2, 512);
10971 				break;
10972 			}
10973 		}
10974 	}
10975 
10976 	if(!S9xMovieActive() && !startingMovie)
10977 	{
10978 		// revert previously forced control
10979         if(GUI.ControlForced!=0xff) {
10980 			GUI.ControllerOption = GUI.ControlForced;
10981             ChangeInputDevice();
10982         }
10983 		int prevController = GUI.ControllerOption;
10984 		GUI.ValidControllerOptions = 0xFFFF;
10985 
10986 		// auto-joypad2 creates fast menu flicker
10987 		if (!Settings.DisableGameSpecificHacks)
10988 		{
10989 			if(strncmp(Memory.ROMName, "MAC:Basic Rifle", 15) == 0)
10990 			{
10991 				GUI.ControllerOption = SNES_MACSRIFLE;
10992 
10993 				ChangeInputDevice();
10994 			}
10995 		}
10996 
10997 		// NSRT controller settings
10998 		if (!strncmp((const char *)Memory.NSRTHeader+24, "NSRT", 4))
10999 		{
11000 			switch(Memory.NSRTHeader[29])
11001 			{
11002 				default: // unknown or unsupported
11003 					break;
11004 				case 0x00: // Gamepad / Gamepad
11005 					GUI.ControllerOption = SNES_JOYPAD;
11006 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD);
11007 					break;
11008 				case 0x10: // Mouse / Gamepad
11009 					GUI.ControllerOption = SNES_MOUSE;
11010 					GUI.ValidControllerOptions = (1<<SNES_MOUSE);
11011 					break;
11012 				case 0x20: // Mouse_or_Gamepad / Gamepad
11013 					if(GUI.ControllerOption == SNES_MOUSE_SWAPPED)
11014 						GUI.ControllerOption = SNES_MOUSE;
11015 					if(GUI.ControllerOption != SNES_MOUSE)
11016 						GUI.ControllerOption = SNES_JOYPAD;
11017 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD) | (1<<SNES_MOUSE);
11018 					break;
11019 				case 0x01: // Gamepad / Mouse
11020 					GUI.ControllerOption = SNES_MOUSE_SWAPPED;
11021 					GUI.ValidControllerOptions = (1<<SNES_MOUSE_SWAPPED);
11022 					break;
11023 				case 0x22: // Mouse_or_Gamepad / Mouse_or_Gamepad
11024 					if(GUI.ControllerOption != SNES_MOUSE && GUI.ControllerOption != SNES_MOUSE_SWAPPED)
11025 						GUI.ControllerOption = SNES_JOYPAD;
11026 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD) | (1<<SNES_MOUSE) | (1<<SNES_MOUSE_SWAPPED);
11027 					break;
11028 				case 0x03: // Gamepad / Superscope
11029 					GUI.ControllerOption = SNES_SUPERSCOPE;
11030 					GUI.ValidControllerOptions = (1<<SNES_SUPERSCOPE);
11031 					break;
11032 				case 0x04: // Gamepad / Gamepad_or_Superscope
11033 					if(GUI.ControllerOption == SNES_JUSTIFIER || GUI.ControllerOption == SNES_JUSTIFIER_2)
11034 						GUI.ControllerOption = SNES_SUPERSCOPE;
11035 					if(GUI.ControllerOption != SNES_SUPERSCOPE)
11036 						GUI.ControllerOption = SNES_JOYPAD;
11037 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD) | (1<<SNES_SUPERSCOPE);
11038 					break;
11039 				case 0x05: // Gamepad / Justifier
11040 					if(GUI.ControllerOption != SNES_JUSTIFIER_2)
11041 						GUI.ControllerOption = SNES_JUSTIFIER;
11042 					GUI.ValidControllerOptions = (1<<SNES_JUSTIFIER) | (1<<SNES_JUSTIFIER_2);
11043 					break;
11044 				case 0x06: // Gamepad / Multitap_or_Gamepad
11045 					GUI.ControllerOption = SNES_MULTIPLAYER5;
11046 					GUI.ValidControllerOptions = (1<<SNES_MULTIPLAYER5) | (1<<SNES_JOYPAD);
11047 					break;
11048 				case 0x66: // Multitap_or_Gamepad / Multitap_or_Gamepad
11049 					GUI.ControllerOption = SNES_MULTIPLAYER8;
11050 					GUI.ValidControllerOptions = (1<<SNES_MULTIPLAYER8) | (1<<SNES_MULTIPLAYER5) | (1<<SNES_JOYPAD);
11051 					break;
11052 				case 0x24: // Gamepad_or_Mouse / Gamepad_or_Superscope
11053 					if(GUI.ControllerOption == SNES_JUSTIFIER || GUI.ControllerOption == SNES_JUSTIFIER_2)
11054 						GUI.ControllerOption = SNES_SUPERSCOPE;
11055 					if(GUI.ControllerOption != SNES_SUPERSCOPE && GUI.ControllerOption != SNES_MOUSE)
11056 						GUI.ControllerOption = SNES_JOYPAD;
11057 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD) | (1<<SNES_MOUSE) | (1<<SNES_SUPERSCOPE);
11058 					break;
11059 				case 0x27: // Gamepad_or_Mouse / Gamepad_or_Mouse_or_Superscope
11060 					if(GUI.ControllerOption == SNES_JUSTIFIER || GUI.ControllerOption == SNES_JUSTIFIER_2)
11061 						GUI.ControllerOption = SNES_SUPERSCOPE;
11062 					if(GUI.ControllerOption != SNES_SUPERSCOPE && GUI.ControllerOption != SNES_MOUSE && GUI.ControllerOption != SNES_MOUSE_SWAPPED)
11063 						GUI.ControllerOption = SNES_JOYPAD;
11064 					GUI.ValidControllerOptions = (1<<SNES_JOYPAD) | (1<<SNES_MOUSE) | (1<<SNES_MOUSE_SWAPPED) | (1<<SNES_SUPERSCOPE);
11065 					break;
11066 				case 0x08: // Gamepad / Mouse_or_Multitap_or_Gamepad
11067 					if(GUI.ControllerOption == SNES_MOUSE)
11068 						GUI.ControllerOption = SNES_MOUSE_SWAPPED;
11069 					if(GUI.ControllerOption == SNES_MULTIPLAYER8)
11070 						GUI.ControllerOption = SNES_MULTIPLAYER5;
11071 					if(GUI.ControllerOption != SNES_MULTIPLAYER5 && GUI.ControllerOption != SNES_MOUSE_SWAPPED)
11072 						GUI.ControllerOption = SNES_JOYPAD;
11073 					GUI.ValidControllerOptions = (1<<SNES_MOUSE_SWAPPED) | (1<<SNES_MULTIPLAYER5) | (1<<SNES_JOYPAD);
11074 					break;
11075 			}
11076 			ChangeInputDevice();
11077 		}
11078 
11079 		// update menu and remember what (if anything) the control was forced from
11080 		GUI.ControlForced = prevController;
11081 	}
11082 
11083 	// reset fast-forward and other input-related GUI state
11084 	Settings.TurboMode = FALSE;
11085 	GUI.superscope_turbo = 0;
11086 	GUI.superscope_pause = 0;
11087 	GUI.MouseButtons = 0;
11088 	GUI.MouseX = 0;
11089 	GUI.MouseY = 0;
11090 	GUI.TurboMask = 0;
11091 	GUI.FrameAdvanceJustPressed = 0;
11092 
11093 	// black out the screen
11094  	for (uint32 y = 0; y < (uint32)IPPU.RenderedScreenHeight; y++)
11095 		memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL*2);
11096 }
11097