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