/* FCE Ultra - NES/Famicom Emulator
 *
 * Copyright notice for this file:
 *  Copyright (C) 2020 mjbudd77
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include <QDir>

#include "Qt/main.h"
#include "Qt/throttle.h"
#include "Qt/config.h"

#include "fceu.h"
#include "ppu.h"
#include "video.h"
#include "../common/cheat.h"

#include "Qt/input.h"
#include "Qt/dface.h"

#include "Qt/sdl.h"
#include "Qt/sdl-video.h"
#include "Qt/AviRecord.h"
#include "Qt/unix-netplay.h"
#include "Qt/NetPlay.h"
#include "Qt/TasEditor/taseditor_config.h"

#ifdef WIN32
#include <windows.h>
#endif

//#include <unistd.h>

#include <csignal>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <cstdlib>

#ifdef WIN32
#include <direct.h>
#else
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif

extern bool force_grayscale;
extern bool palupdate;
extern  int palnotch;
extern  int palsaturation;
extern  int palsharpness;
extern  int palcontrast;
extern  int palbrightness;

int getHotKeyConfig( int i, const char **nameOut, const char **keySeqOut, const char **titleOut, const char **groupOut )
{
	const char *name = "";
	const char *keySeq = "";
	const char *title = NULL;
	const char *group = "Misc";

	switch ( i )
	{
		case HK_OPEN_ROM: 
			name = "OpenROM"; keySeq = "Ctrl+O"; title = "Open ROM"; group = "Tools";
		break;
		case HK_CLOSE_ROM: 
			name = "CloseROM"; keySeq = "Ctrl+C"; title = "Close ROM"; group = "Tools";
		break;
		case HK_CHEAT_MENU:
			name = "CheatMenu"; keySeq = ""; title = "Open Cheat Window"; group = "Tools";
		break;
		case HK_TOGGLE_ALL_CHEATS:
			name = "ToggleCheats"; keySeq = ""; title = "Toggle Global Cheat Enable"; group = "Tools";
		break;
		case HK_BIND_STATE:
			name = "BindState"; keySeq = ""; title = "Bind Save State to Movie"; group = "Movie";
		break;
		case HK_LOAD_LUA:
			name = "LoadLua"; keySeq = "Ctrl+L"; group = "Tools";
		break;
		case HK_TOGGLE_BG:
			name = "ToggleBG"; keySeq = "";	title = "Toggle Background Display"; group = "Misc";
		break;
		case HK_TOGGLE_FG:
			name = "ToggleFG"; keySeq = "";	title = "Toggle Object Display"; group = "Misc";
		break;
		// Save States
		case HK_SAVE_STATE:
			name = "SaveState"; keySeq = "I"; title = "Save State"; group = "State";
		break;
		case HK_SAVE_STATE_0:
			name = "SaveState0"; keySeq = "Shift+F10"; title = "Save State to Slot 0"; group = "State";
		break;
		case HK_SAVE_STATE_1:
			name = "SaveState1"; keySeq = "Shift+F1"; title = "Save State to Slot 1"; group = "State";
		break;
		case HK_SAVE_STATE_2:
			name = "SaveState2"; keySeq = "Shift+F2"; title = "Save State to Slot 2"; group = "State";
		break;
		case HK_SAVE_STATE_3:
			name = "SaveState3"; keySeq = "Shift+F3"; title = "Save State to Slot 3"; group = "State";
		break;
		case HK_SAVE_STATE_4:
			name = "SaveState4"; keySeq = "Shift+F4"; title = "Save State to Slot 4"; group = "State";
		break;
		case HK_SAVE_STATE_5:
			name = "SaveState5"; keySeq = "Shift+F5"; title = "Save State to Slot 5"; group = "State";
		break;
		case HK_SAVE_STATE_6:
			name = "SaveState6"; keySeq = "Shift+F6"; title = "Save State to Slot 6"; group = "State";
		break;
		case HK_SAVE_STATE_7:
			name = "SaveState7"; keySeq = "Shift+F7"; title = "Save State to Slot 7"; group = "State";
		break;
		case HK_SAVE_STATE_8:
			name = "SaveState8"; keySeq = "Shift+F8"; title = "Save State to Slot 8"; group = "State";
		break;
		case HK_SAVE_STATE_9:
			name = "SaveState9"; keySeq = "Shift+F9"; title = "Save State to Slot 9"; group = "State";
		break;
		// Load States
		case HK_LOAD_STATE:
			name = "LoadState"; keySeq = "P";	title = "Load State"; group = "State";
		break;
		case HK_LOAD_STATE_0:
			name = "LoadState0"; keySeq = "F10"; title = "Load State From Slot 0"; group = "State";
		break;
		case HK_LOAD_STATE_1:
			name = "LoadState1"; keySeq = "F1"; title = "Load State From Slot 1"; group = "State";
		break;
		case HK_LOAD_STATE_2:
			name = "LoadState2"; keySeq = "F2"; title = "Load State From Slot 2"; group = "State";
		break;
		case HK_LOAD_STATE_3:
			name = "LoadState3"; keySeq = "F3"; title = "Load State From Slot 3"; group = "State";
		break;
		case HK_LOAD_STATE_4:
			name = "LoadState4"; keySeq = "F4"; title = "Load State From Slot 4"; group = "State";
		break;
		case HK_LOAD_STATE_5:
			name = "LoadState5"; keySeq = "F5"; title = "Load State From Slot 5"; group = "State";
		break;
		case HK_LOAD_STATE_6:
			name = "LoadState6"; keySeq = "F6"; title = "Load State From Slot 6"; group = "State";
		break;
		case HK_LOAD_STATE_7:
			name = "LoadState7"; keySeq = "F7"; title = "Load State From Slot 7"; group = "State";
		break;
		case HK_LOAD_STATE_8:
			name = "LoadState8"; keySeq = "F8"; title = "Load State From Slot 8"; group = "State";
		break;
		case HK_LOAD_STATE_9:
			name = "LoadState9"; keySeq = "F9"; title = "Load State From Slot 9"; group = "State";
		break;
		case HK_FDS_SELECT:
			name = "FDSSelect"; keySeq = ""; title = "Switch FDS Disk Side"; group = "FDS";
		break;
		case HK_FDS_EJECT:
			name = "FDSEject"; keySeq = "";	title = "Eject FDS Disk"; group = "FDS";
		break;
		case HK_VS_INSERT_COIN:
			name = "VSInsertCoin"; keySeq = ""; title = "VS Insert Coin"; group = "VS";
		break;
		case HK_VS_TOGGLE_DIPSWITCH:
			name = "VSToggleDip"; keySeq = ""; title = "VS Toggle Dipswitch"; group = "VS";
		break;
		case HK_TOGGLE_FRAME_DISPLAY:
			name = "MovieToggleFrameDisplay"; keySeq = ".";	title = "Toggle Frame Display"; group = "Movie";
		break;
		case HK_TOGGLE_SUBTITLE:
			name = "SubtitleDisplay"; keySeq = ""; title = "Toggle Movie Subtitles"; group = "Movie";
		break;
		case HK_POWER:
			name = "Power"; keySeq = ""; title = "Power"; group = "Emulation";
		break;
		case HK_SOFT_RESET:
			name = "SoftReset"; keySeq = "Ctrl+R"; title = "Soft Reset"; group = "Emulation";
		break;
		case HK_HARD_RESET:
			name = "HardReset"; keySeq = "Ctrl+Shift+R"; title = "Hard Reset"; group = "Emulation";
		break;
		case HK_PAUSE:
			name = "Pause"; keySeq = "Pause"; title = "Pause"; group = "Emulation";
		break;
		case HK_QUIT:
			name = "Quit"; keySeq = "Ctrl+Q"; title = "Exit Application"; group = "Misc";
		break;
		case HK_SCREENSHOT:
			name = "Screenshot"; keySeq = "F12"; group = "Tools";
		break;
		case HK_DECREASE_SPEED:
			name = "DecreaseSpeed"; keySeq = "-"; group = "Speed";
		break;
		case HK_INCREASE_SPEED:
			name = "IncreaseSpeed"; keySeq = "="; group = "Speed";
		break;
		case HK_FRAME_ADVANCE:
			name = "FrameAdvance"; keySeq = "\\"; group = "Speed";
		break;
		case HK_TURBO:
			name = "Turbo"; keySeq = "Tab"; group = "Speed";
		break;
		case HK_SPEED_NORMAL:
			name = "Normal Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_QUARTER:
			name = "1/4x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_HALF:
			name = "1/2x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_2X:
			name = "2x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_4X:
			name = "4x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_8X:
			name = "8x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_SPEED_16X:
			name = "16x Speed"; keySeq = ""; group = "Speed";
		break;
		case HK_TOGGLE_INPUT_DISPLAY:
			name = "ToggleInputDisplay"; keySeq = ","; group = "Misc";
		break;
		case HK_MOVIE_TOGGLE_RW:
			name = "ToggleMovieRW"; keySeq = "Q"; group = "Movie";
		break;
		case HK_PLAY_MOVIE_FROM:
			name = "PlayMovieFrom"; keySeq = ""; group = "Movie";
		break;
		case HK_MOVIE_PLAY_RESTART:
			name = "PlayMovieFromBeginning"; keySeq = ""; group = "Movie";
		break;
		case HK_RECORD_MOVIE_TO:
			name = "RecordMovieTo"; keySeq = ""; group = "Movie";
		break;
		case HK_STOP_MOVIE:
			name = "StopMovie"; keySeq = ""; group = "Movie";
		break;
		case HK_RECORD_AVI:
			name = "RecordAvi"; keySeq = ""; group = "AVI";
		break;
		case HK_RECORD_AVI_TO:
			name = "RecordAviTo"; keySeq = ""; group = "AVI";
		break;
		case HK_STOP_AVI:
			name = "StopAvi"; keySeq = ""; group = "AVI";
		break;
		case HK_RECORD_WAV:
			name = "RecordWav"; keySeq = ""; group = "WAV";
		break;
		case HK_RECORD_WAV_TO:
			name = "RecordWavTo"; keySeq = ""; group = "WAV";
		break;
		case HK_STOP_WAV:
			name = "StopWav"; keySeq = ""; group = "WAV";
		break;
		case HK_MUTE_CAPTURE:
			name = "MuteCapture"; keySeq = "'";
		break;
		case HK_FA_LAG_SKIP:
			name = "FrameAdvanceLagSkip"; keySeq = "Delete";
		break;
		case HK_LAG_COUNTER_DISPLAY:
			name = "LagCounterDisplay"; keySeq = "/";
		break;
		case HK_SELECT_STATE_0:
			name = "SelectState0"; keySeq = "0"; title = "Select State Slot 0"; group = "State";
		break;
		case HK_SELECT_STATE_1:
			name = "SelectState1"; keySeq = "1"; title = "Select State Slot 1"; group = "State";
		break;
		case HK_SELECT_STATE_2:
			name = "SelectState2"; keySeq = "2"; title = "Select State Slot 2"; group = "State";
		break;
		case HK_SELECT_STATE_3:
			name = "SelectState3"; keySeq = "3"; title = "Select State Slot 3"; group = "State";
		break;
		case HK_SELECT_STATE_4:
			name = "SelectState4"; keySeq = "4"; title = "Select State Slot 4"; group = "State";
		break;
		case HK_SELECT_STATE_5:
			name = "SelectState5"; keySeq = "5"; title = "Select State Slot 5"; group = "State";
		break;
		case HK_SELECT_STATE_6:
			name = "SelectState6"; keySeq = "6"; title = "Select State Slot 6"; group = "State";
		break;
		case HK_SELECT_STATE_7:
			name = "SelectState7"; keySeq = "7"; title = "Select State Slot 7"; group = "State";
		break;
		case HK_SELECT_STATE_8:
			name = "SelectState8"; keySeq = "8"; title = "Select State Slot 8"; group = "State";
		break;
		case HK_SELECT_STATE_9:
			name = "SelectState9"; keySeq = "9"; title = "Select State Slot 9"; group = "State";
		break;
		case HK_SELECT_STATE_NEXT:
			name = "SelectStateNext"; keySeq = ""; title = "Select Next State Slot"; group = "State";
		break;
		case HK_SELECT_STATE_PREV:
			name = "SelectStatePrev"; keySeq = ""; title = "Select Previous State Slot"; group = "State";
		break;
		case HK_LOAD_PREV_STATE:
			name = "LoadPrevState"; keySeq = ""; title = "Load Previous Recorded State"; group = "State";
		break;
		case HK_LOAD_NEXT_STATE:
			name = "LoadNextState"; keySeq = ""; title = "Load Next Recorded State"; group = "State";
		break;
		case HK_VOLUME_MUTE:
			name = "VolumeMute"; keySeq = ""; title = "Sound Volume Mute"; group = "Sound";
		break;
		case HK_VOLUME_DOWN:
			name = "VolumeDown"; keySeq = ""; title = "Sound Volume Down"; group = "Sound";
		break;
		case HK_VOLUME_UP:
			name = "VolumeUp"; keySeq = ""; title = "Sound Volume Up"; group = "Sound";
		break;
		case HK_FKB_ENABLE:
			name = "FKB_Enable"; keySeq = "ScrollLock"; title = "Toggle Family Keyboard Enable";
		break;
		case HK_FULLSCREEN:
			name = "FullScreen"; keySeq = "Alt+Return"; title = "Toggle Fullscreen View";
		break;
		case HK_MAIN_MENU_HIDE:
			name = "MainMenuHide"; keySeq = "Alt+/"; title = "Toggle Main Menu Visibility";
		break;
		default:
		case HK_MAX:
			name = ""; keySeq = "";
		break;

	}

	if ( nameOut )
	{
		*nameOut = name;
	}
	if ( keySeqOut )
	{
		*keySeqOut = keySeq;
	}
	if ( titleOut )
	{
		if ( title == NULL )
		{
			title = name;
		}
		*titleOut = title;
	}
	if ( groupOut )
	{
		*groupOut = group;
	}
	return 0;
}


int getHotKeyIndexByName( const char *name )
{
	const char *nameOut;

	if ( name[0] == 0 )
	{
		return -1;
	}
	for (int i=0; i<HK_MAX; i++)
	{
		getHotKeyConfig( i, &nameOut, NULL );

		if ( strcmp( name, nameOut ) == 0 )
		{
			return i;
		}
	}
	return -1;
}

/**
 * Read a custom pallete from a file and load it into the core.
 */
int
LoadCPalette(const std::string &file)
{
	uint8 tmpp[192];
	FILE *fp;

	if(!(fp = FCEUD_UTF8fopen(file.c_str(), "rb"))) {
		char errorMsg[256];
		strcpy(errorMsg, "Error loading custom palette from file: ");
		strcat(errorMsg, file.c_str());
		FCEUD_PrintError(errorMsg);
		return 0;
	}
	size_t result = fread(tmpp, 1, 192, fp);
	if(result != 192) {
		char errorMsg[256];
		strcpy(errorMsg, "Error loading custom palette from file: ");
		strcat(errorMsg, file.c_str());
		FCEUD_PrintError(errorMsg);
		return 0;
	}
	FCEUI_SetUserPalette(tmpp, result/3);
	fclose(fp);
	return 1;
}

/**
 * Creates the subdirectories used for saving snapshots, movies, game
 * saves, etc.  Hopefully obsolete with new configuration system.
 */
static void
CreateDirs(const std::string &dir)
{
	const char *subs[]={"fcs","snaps","gameinfo","sav","cheats","avi","wav","movies","input", NULL };
	std::string subdir;
	int x=0;

#if defined(WIN32) || defined(NEED_MINGW_HACKS)
	mkdir(dir.c_str());
	chmod(dir.c_str(), 755);
	while ( subs[x] != NULL )
	{
		subdir = dir + PSS + subs[x];
		mkdir(subdir.c_str());
		x++;
	}
#else
	mkdir(dir.c_str(), S_IRWXU);
	while ( subs[x] != NULL )
	{
		subdir = dir + PSS + subs[x];
		mkdir(subdir.c_str(), S_IRWXU);
		x++;
	}
#endif
}

/**
 * Attempts to locate FCEU's application directory.  This will
 * hopefully become obsolete once the new configuration system is in
 * place.
 */
static void
GetBaseDirectory(std::string &dir)
{
	const char *home = getenv("FCEUX_HOME");
	const char *conf = getenv("FCEUX_CONFIG_DIR");

#ifdef WIN32
	// Windows users want base directory to be where executable resides.
	// Only way to override this behavior is to set an FCEUX_HOME 
	// environment variable prior to starting the application.
	//if ( home == NULL )
	//{
	//	home = getenv("USERPROFILE");
	//}
	//if ( home == NULL )
	//{
	//	home = getenv("HOMEPATH");
	//}
#else
	if ( home == NULL )
	{
		home = getenv("HOME");
	}
#endif

	if (conf)
	{
		dir = std::string(conf);
	}
	else if (home) 
	{
		dir = std::string(home) + "/.fceux";
	}
	else
	{
#ifdef WIN32
		char *exePath = new char[MAX_PATH + 1];
		GetModuleFileNameA(NULL, exePath, MAX_PATH + 1);

		char *lastBS = strrchr(exePath,'\\');
		if(lastBS) {
			*lastBS = 0;
		}

		dir = std::string(exePath);
		delete[] exePath;
#else
		dir = "";
#endif
	}
}

// returns a config structure with default options
// also creates config base directory (ie: /home/user/.fceux as well as subdirs
Config *
InitConfig()
{
	TASEDITOR_CONFIG  tasCfg;
	std::string dir, prefix, savPath, movPath;
	Config *config;

	GetBaseDirectory(dir);

	FCEUI_SetBaseDirectory(dir.c_str());
	CreateDirs(dir);

	config = new Config(dir);

	// sound options
	config->addOption('s', "sound", "SDL.Sound", 1);
	config->addOption("soundMute", "SDL.Sound.Mute", 0);
	config->addOption("volume", "SDL.Sound.Volume", 255);
	config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 255);
	config->addOption("square1vol", "SDL.Sound.Square1Volume", 255);
	config->addOption("square2vol", "SDL.Sound.Square2Volume", 255);
	config->addOption("noisevol", "SDL.Sound.NoiseVolume", 255);
	config->addOption("pcmvol", "SDL.Sound.PCMVolume", 255);
	config->addOption("soundrate", "SDL.Sound.Rate", 44100);
	config->addOption("soundq", "SDL.Sound.Quality", 1);
	config->addOption("soundrecord", "SDL.Sound.RecordFile", "");
	config->addOption("soundbufsize", "SDL.Sound.BufSize", 128);
	config->addOption("lowpass", "SDL.Sound.LowPass", 0);
	config->addOption("SDL.Sound.UseGlobalFocus", 1);
    
	config->addOption('g', "gamegenie", "SDL.GameGenie", 0);
	config->addOption("pal", "SDL.PAL", 0);
	config->addOption("autoPal", "SDL.AutoDetectPAL", 1);
	config->addOption("frameskip", "SDL.Frameskip", 0);
	config->addOption("intFrameRate", "SDL.IntFrameRate", 0);
	config->addOption("clipsides", "SDL.ClipSides", 0);
	config->addOption("nospritelim", "SDL.DisableSpriteLimit", 0);
	config->addOption("swapduty", "SDL.SwapDuty", 0);
	config->addOption("ramInit", "SDL.RamInitMethod", 0);
	config->addOption("SDL.FrameAdvanceDelay", 40);

	// color control
	config->addOption('p', "palette", "SDL.Palette", "");
	config->addOption("tint", "SDL.Tint", 56);
	config->addOption("hue", "SDL.Hue", 72);
	config->addOption("ntsccolor", "SDL.NTSCpalette", 0);
	config->addOption("SDL.ForceGrayScale", 0);
	config->addOption("SDL.DeempBitSwap", 0);
	config->addOption("SDL.PalNotch", 100);
	config->addOption("SDL.PalSaturation", 100);
	config->addOption("SDL.PalSharpness", 0);
	config->addOption("SDL.PalContrast", 100);
	config->addOption("SDL.PalBrightness", 50);

	// scanline settings
	config->addOption("SDL.ScanLineStartNTSC", 0+8);
	config->addOption("SDL.ScanLineEndNTSC", 239-8);
	config->addOption("SDL.ScanLineStartPAL", 0);
	config->addOption("SDL.ScanLineEndPAL", 239);

	// video controls
	config->addOption('f', "fullscreen", "SDL.Fullscreen", 0);
	config->addOption("videoDriver", "SDL.VideoDriver", 0);
	config->addOption("SDL.VideoBgColor", "#000000");
	config->addOption("SDL.UseBgPaletteForVideo", false);
	config->addOption("SDL.VideoVsync", 1);

	// set x/y res to 0 for automatic fullscreen resolution detection (no change)
	config->addOption('x', "xres", "SDL.XResolution", 0);
	config->addOption('y', "yres", "SDL.YResolution", 0);
	config->addOption("SDL.LastXRes", 0);
	config->addOption("SDL.LastYRes", 0);
	config->addOption("SDL.WinPosX" , 0);
	config->addOption("SDL.WinPosY" , 0);
	config->addOption("SDL.WinSizeX", 0);
	config->addOption("SDL.WinSizeY", 0);
	config->addOption("doublebuf", "SDL.DoubleBuffering", 1);
	config->addOption("autoscale", "SDL.AutoScale", 1);
	config->addOption("forceAspect", "SDL.ForceAspect", 0);
	config->addOption("aspectSelect", "SDL.AspectSelect", 3); // Standard (4:3)
	config->addOption("aspectX", "SDL.AspectX", 1.000);
	config->addOption("aspectY", "SDL.AspectY", 1.000);
	config->addOption("xscale", "SDL.XScale", 2.000);
	config->addOption("yscale", "SDL.YScale", 2.000);
	config->addOption("xstretch", "SDL.XStretch", 0);
	config->addOption("ystretch", "SDL.YStretch", 0);
	config->addOption("noframe", "SDL.NoFrame", 0);
	config->addOption("special", "SDL.SpecialFilter", 0);
	config->addOption("showfps", "SDL.ShowFPS", 0);
	config->addOption("togglemenu", "SDL.ToggleMenu", 0);
	config->addOption("cursorType", "SDL.CursorType", 0);
	config->addOption("cursorVis" , "SDL.CursorVis", 1);
	config->addOption("SDL.DrawInputAids", 1);
	config->addOption("SDL.ShowFrameCount", 0);
	config->addOption("SDL.ShowLagCount", 0);
	config->addOption("SDL.ShowRerecordCount", 0);
	config->addOption("SDL.ShowGuiMessages", 1);

	// OpenGL options
	config->addOption("opengl", "SDL.OpenGL", 1);
	config->addOption("openglip", "SDL.OpenGLip", 0);
	config->addOption("SDL.SpecialFilter", 0);
	config->addOption("SDL.SpecialFX", 0);
	config->addOption("SDL.Vsync", 1);
	#ifdef WIN32
	config->addOption("SDL.winFullScreenBorder", 0);
	#endif

	QString userName = qgetenv("USER");
    	if (userName.isEmpty())
	{
        	userName = qgetenv("USERNAME");
	}

	// network play options - netplay is broken
	config->addOption("server", "SDL.NetworkIsServer", 0);
	config->addOption('n', "net", "SDL.NetworkIP", "localhost");
	config->addOption('u', "user", "SDL.NetworkUsername", userName.toLocal8Bit().constData());
	config->addOption('w', "pass", "SDL.NetworkPassword", "");
	config->addOption('k', "netkey", "SDL.NetworkGameKey", "");
	config->addOption("port", "SDL.NetworkPort", NetPlayServer::DefaultPort);
	config->addOption("players", "SDL.NetworkPlayers", 1);
	config->addOption("SDL.NetPlayHostAllowClientRomLoadReq", 0);
	config->addOption("SDL.NetPlayHostAllowClientStateLoadReq", 0);
	config->addOption("SDL.NetPlayHostEnforceAppVersionChk", 1);
     
	// input configuration options
	config->addOption("input1", "SDL.Input.0", "GamePad.0");
	config->addOption("input2", "SDL.Input.1", "GamePad.1");
	config->addOption("input3", "SDL.Input.2", "Gamepad.2");
	config->addOption("input4", "SDL.Input.3", "Gamepad.3");

	config->addOption("autoInputPreset", "SDL.AutoInputPreset", 0);
	config->addOption("SDL.AutofireOnFrames" , 1);
	config->addOption("SDL.AutofireOffFrames", 1);
	config->addOption("SDL.AutofireCustomOnFrames" , 1);
	config->addOption("SDL.AutofireCustomOffFrames", 1);
	config->addOption("SDL.NewInputDeviceBehavior", 1);

	// display input
	config->addOption("inputdisplay", "SDL.InputDisplay", 0);

	// enable / disable opposite directionals (left + right or up + down simultaneously)
	config->addOption("opposite-directionals", "SDL.Input.EnableOppositeDirectionals", 0);
    
	// pause movie playback at frame x
	config->addOption("pauseframe", "SDL.PauseFrame", 0);
	config->addOption("recordhud", "SDL.RecordHUD", 0);
	config->addOption("moviemsg", "SDL.MovieMsg", 0);

#ifdef _USE_LIBAV
	config->addOption("SDL.AviDriver", AVI_DRIVER_LIBAV);
#else
	config->addOption("SDL.AviDriver", AVI_DRIVER_LIBGWAVI);
#endif

#if    defined(WIN32)
	config->addOption("SDL.AviVideoFormat", AVI_VFW);
#elif  defined(_USE_X264)
	config->addOption("SDL.AviVideoFormat", AVI_X264);
#else
	config->addOption("SDL.AviVideoFormat", AVI_RGB24);
#endif
	config->addOption("SDL.AviRecordAudio", 1);

#ifdef _USE_LIBAV
	config->addOption("SDL.AviFFmpegVideoCodec", "");
	config->addOption("SDL.AviFFmpegAudioCodec", "");
	config->addOption("SDL.AviFFmpegVideoPixFmt", -1);
	config->addOption("SDL.AviFFmpegAudioSmpFmt", -1);
	config->addOption("SDL.AviFFmpegAudioSmpRate", -1);
	config->addOption("SDL.AviFFmpegAudioChanLayout", -1);
#endif
#ifdef  WIN32
	config->addOption("SDL.AviVfwFccHandler", "");
#endif

	// Cheat Options
	config->addOption("SDL.CheatsDisabled", 0);
	config->addOption("SDL.CheatsDisableAutoLS", 0);
	config->addOption("SDL.CheatsWindowPause", 0);

	// Hex Editor Options
	config->addOption("SDL.HexEditBgColor", "#000000");
	config->addOption("SDL.HexEditFgColor", "#FFFFFF");
	config->addOption("SDL.HexEditCursorColorRC", "#000080");
	config->addOption("SDL.HexEditAltColColor"  , "#545454");
	config->addOption("SDL.HexEditFont"  , "");
	config->addOption("SDL.HexEditActivityHlgt", true);
	config->addOption("SDL.HexEditReverseVideo", true);
	config->addOption("SDL.HexEditRowColumnHlgt", false);
	config->addOption("SDL.HexEditAltnColumnColor", false);
	config->addOption("SDL.HexEditRefreshRate", 10);
    
	// Debugger Options
	config->addOption("autoLoadDebugFiles"     , "SDL.AutoLoadDebugFiles", 1);
	config->addOption("autoOpenDebugger"       , "SDL.AutoOpenDebugger"  , 0);
	config->addOption("debuggerPCPlacementMode", "SDL.DebuggerPCPlacement"  , 0);
	config->addOption("debuggerPCDLineOffset"  , "SDL.DebuggerPCLineOffset" , 0);
	config->addOption("SDL.DebuggerAsmFont"        , "");
	config->addOption("SDL.DebuggerStackFont"      , "");
	config->addOption("SDL.DebuggerCpuStatusFont"  , "");
	config->addOption("SDL.AsmSyntaxColorOpcode", "");
	config->addOption("SDL.AsmSyntaxColorAddress", "");
	config->addOption("SDL.AsmSyntaxColorImmediate", "");
	config->addOption("SDL.AsmSyntaxColorLabel", "");
	config->addOption("SDL.AsmSyntaxColorComment", "");
	config->addOption("SDL.AsmSyntaxColorPC", "");
	config->addOption("SDL.AsmShowByteCodes", 0);
	config->addOption("SDL.AsmShowTraceData", 0);
	config->addOption("SDL.AsmShowRomOffsets", 0);
	config->addOption("SDL.DebuggerShowSymNames", 1);
	config->addOption("SDL.DebuggerShowRegNames", 1);
	config->addOption("SDL.DebuggerBreakOnBadOpcodes", 0);
	config->addOption("SDL.DebuggerBreakOnUnloggedCode", 0);
	config->addOption("SDL.DebuggerBreakOnUnloggedData", 0);
	config->addOption("SDL.DebugAutoStartTraceLogger", 0);

	// Code Data Logger Options
	config->addOption("autoSaveCDL"  , "SDL.AutoSaveCDL", 1);
	config->addOption("autoLoadCDL"  , "SDL.AutoLoadCDL", 1);
	config->addOption("autoResumeCDL", "SDL.AutoResumeCDL", 0);

	// Trace Logger Options
	config->addOption("SDL.TraceLogSaveToFile", 0);
	config->addOption("SDL.TraceLogSaveFilePath", "");
	config->addOption("SDL.TraceLogPeriodicWindowUpdate", 1);
	config->addOption("SDL.TraceLogRegisterState", 1);
	config->addOption("SDL.TraceLogProcessorState", 1);
	config->addOption("SDL.TraceLogNewInstructions", 0);
	config->addOption("SDL.TraceLogNewData", 0);
	config->addOption("SDL.TraceLogFrameCount", 0);
	config->addOption("SDL.TraceLogCycleCount", 0);
	config->addOption("SDL.TraceLogInstructionCount", 0);
	config->addOption("SDL.TraceLogMessages", 1);
	config->addOption("SDL.TraceLogBreakpointHits", 1);
	config->addOption("SDL.TraceLogBankNumber", 0);
	config->addOption("SDL.TraceLogSymbolic", 0);
	config->addOption("SDL.TraceLogStackTabbing", 1);
	config->addOption("SDL.TraceLogLeftDisassembly", 1);
	
	// overwrite the config file?
	config->addOption("no-config", "SDL.NoConfig", 0);

	config->addOption("autoresume", "SDL.AutoResume", 0);
	config->addOption("SDL.FamilyKeyboardFont"  , "");
    
	// video playback
	config->addOption("playmov", "SDL.Movie", "");
	config->addOption("subtitles", "SDL.SubtitleDisplay", 1);
	config->addOption("movielength", "SDL.MovieLength", 0);

	config->addOption("SDL.SuggestReadOnlyReplay"  , 1 );
	config->addOption("SDL.PauseAfterMoviePlayback", 0 );
	config->addOption("SDL.CloseFinishedMovie"     , 0 );
	config->addOption("SDL.MovieBindSavestate"     , 1 );
	config->addOption("SDL.SubtitlesOnAVI"         , 0 );
	config->addOption("SDL.AutoMovieBackup"        , 0 );
	config->addOption("SDL.MovieFullSaveStateLoads", 0 );
	
	config->addOption("fourscore", "SDL.FourScore", 0);

	config->addOption("nofscursor", "SDL.NoFullscreenCursor", 1);
    
    #ifdef _S9XLUA_H
	// load lua script
	config->addOption("loadlua", "SDL.LuaScript", "");
    #endif
    
    #ifdef CREATE_AVI
	config->addOption("videolog",  "SDL.VideoLog",  "");
	config->addOption("mute", "SDL.MuteCapture", 0);
    #endif
    
    // auto load/save on gameload/close
	config->addOption("loadstate", "SDL.AutoLoadState", INVALID_STATE);
	config->addOption("savestate", "SDL.AutoSaveState", INVALID_STATE);

	config->addOption("SDL.StateRecorderEnable", false);
	config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
	config->addOption("SDL.StateRecorderTimingMode", 0);
	config->addOption("SDL.StateRecorderFramesBetweenSnaps", 60);
	config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
	config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
	config->addOption("SDL.StateRecorderCompressionLevel", 0);
	config->addOption("SDL.StateRecorderPauseOnLoad", 1);
	config->addOption("SDL.StateRecorderPauseDuration", 3);

	//TODO implement this
	config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);

	savPath = dir + "/sav";
	movPath = dir + "/movies";

	// prefixed with _ because they are internal (not cli options)
	config->addOption("_lastopenfile", "SDL.LastOpenFile", dir);
	config->addOption("_laststatefrom", "SDL.LastLoadStateFrom", savPath );
	config->addOption("_lastopennsf", "SDL.LastOpenNSF", dir);
	config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", savPath );
	config->addOption("_lastopenmovie", "SDL.LastOpenMovie", movPath);
	config->addOption("_lastloadlua", "SDL.LastLoadLua", "");
	config->addOption("_lastloadjs", "SDL.LastLoadJs", "");
	config->addOption("SDL.HelpFilePath", "");
	config->addOption("SDL.AviFilePath", "");
	config->addOption("SDL.WavFilePath", "");

	for (unsigned int i=0; i<10; i++)
	{
		char buf[128];
		snprintf(buf, sizeof(buf), "SDL.RecentRom%02u", i);

		config->addOption( buf, "");
	}

	for (unsigned int i=0; i<10; i++)
	{
		char buf[128];
		snprintf(buf, sizeof(buf), "SDL.RecentTasProject%02u", i);

		config->addOption( buf, "");
	}
	config->addOption("SDL.TasPianoRollFont", "");
	config->addOption("SDL.TasBookmarksFont", "");
	config->addOption("SDL.TasBranchesFont" , "");
	config->addOption("SDL.TasPianoRollGridColor", "#808080");

	config->addOption("SDL.TasAutoSaveEnabled"                         , tasCfg.autosaveEnabled );
	config->addOption("SDL.TasAutoSavePeriod"                          , tasCfg.autosavePeriod  );
	config->addOption("SDL.TasAutoSaveSilent"                          , tasCfg.autosaveSilent  );
	config->addOption("SDL.TasTooltipsEnabled"                         , tasCfg.tooltipsEnabled );
	config->addOption("SDL.TasCurrentPattern"                          , tasCfg.currentPattern  );
	config->addOption("SDL.TasFollowPlaybackCursor"                    , tasCfg.followPlaybackCursor  );
	config->addOption("SDL.TasTurboSeek"                               , tasCfg.turboSeek  );
	config->addOption("SDL.TasAutoRestoreLastPlaybackPosition"         , tasCfg.autoRestoreLastPlaybackPosition  );
	config->addOption("SDL.TasSuperImpose"                             , tasCfg.superimpose  );
	config->addOption("SDL.TasRecordingUsePattern"                     , tasCfg.recordingUsePattern  );
	config->addOption("SDL.TasEnableLuaAutoFunction"                   , tasCfg.enableLuaAutoFunction  );
	config->addOption("SDL.TasDisplayBranchesTree"                     , tasCfg.displayBranchesTree  );
	config->addOption("SDL.TasDisplayBranchScreenshots"                , tasCfg.displayBranchScreenshots  );
	config->addOption("SDL.TasDisplayBranchDescriptions"               , tasCfg.displayBranchDescriptions  );
	config->addOption("SDL.TasEnableHotChanges"                        , tasCfg.enableHotChanges  );
	config->addOption("SDL.TasFollowUndoContext"                       , tasCfg.followUndoContext  );
	config->addOption("SDL.TasFollowMarkerNoteContext"                 , tasCfg.followMarkerNoteContext  );
	config->addOption("SDL.TasGreenzoneCapacity"                       , tasCfg.greenzoneCapacity  );
	config->addOption("SDL.TasMaxUndoLevels"                           , tasCfg.maxUndoLevels  );
	config->addOption("SDL.TasEnableGreenzoning"                       , tasCfg.enableGreenzoning  );
	config->addOption("SDL.TasAutofirePatternSkipsLag"                 , tasCfg.autofirePatternSkipsLag  );
	config->addOption("SDL.TasAutoAdjustInputAccordingToLag"           , tasCfg.autoAdjustInputAccordingToLag  );
	config->addOption("SDL.TasDrawInputByDragging"                     , tasCfg.drawInputByDragging  );
	config->addOption("SDL.TasCombineConsecutiveRecordingsAndDraws"    , tasCfg.combineConsecutiveRecordingsAndDraws  );
	config->addOption("SDL.TasUse1PKeysForAllSingleRecordings"         , tasCfg.use1PKeysForAllSingleRecordings  );
	config->addOption("SDL.TasUseInputKeysForColumnSet"                , tasCfg.useInputKeysForColumnSet  );
	config->addOption("SDL.TasBindMarkersToInput"                      , tasCfg.bindMarkersToInput  );
	config->addOption("SDL.TasEmptyNewMarkerNotes"                     , tasCfg.emptyNewMarkerNotes  );
	config->addOption("SDL.TasOldControlSchemeForBranching"            , tasCfg.oldControlSchemeForBranching  );
	config->addOption("SDL.TasBranchesRestoreEntireMovie"              , tasCfg.branchesRestoreEntireMovie  );
	config->addOption("SDL.TasHUDInBranchScreenshots"                  , tasCfg.HUDInBranchScreenshots  );
	config->addOption("SDL.TasAutopauseAtTheEndOfMovie"                , tasCfg.autopauseAtTheEndOfMovie  );
	config->addOption("SDL.TasLastExportedInputType"                   , tasCfg.lastExportedInputType  );
	config->addOption("SDL.TasLastExportedSubtitlesStatus"             , tasCfg.lastExportedSubtitlesStatus  );
	config->addOption("SDL.TasProjectSavingOptions_SaveInBinary"       , tasCfg.projectSavingOptions_SaveInBinary  );
	config->addOption("SDL.TasProjectSavingOptions_SaveMarkers"        , tasCfg.projectSavingOptions_SaveMarkers  );
	config->addOption("SDL.TasProjectSavingOptions_SaveBookmarks"      , tasCfg.projectSavingOptions_SaveBookmarks  );
	config->addOption("SDL.TasProjectSavingOptions_SaveHistory"        , tasCfg.projectSavingOptions_SaveHistory  );
	config->addOption("SDL.TasProjectSavingOptions_SavePianoRoll"      , tasCfg.projectSavingOptions_SavePianoRoll  );
	config->addOption("SDL.TasProjectSavingOptions_SaveSelection"      , tasCfg.projectSavingOptions_SaveSelection  );
	config->addOption("SDL.TasProjectSavingOptions_GreenzoneSavingMode", tasCfg.projectSavingOptions_GreenzoneSavingMode  );
	config->addOption("SDL.TasSaveCompact_SaveInBinary"                , tasCfg.saveCompact_SaveInBinary  );
	config->addOption("SDL.TasSaveCompact_SaveMarkers"                 , tasCfg.saveCompact_SaveMarkers  );
	config->addOption("SDL.TasSaveCompact_SaveBookmarks"               , tasCfg.saveCompact_SaveBookmarks  );
	config->addOption("SDL.TasSaveCompact_SaveHistory"                 , tasCfg.saveCompact_SaveHistory  );
	config->addOption("SDL.TasSaveCompact_SavePianoRoll"               , tasCfg.saveCompact_SavePianoRoll  );
	config->addOption("SDL.TasSaveCompact_SaveSelection"               , tasCfg.saveCompact_SaveSelection  );
	config->addOption("SDL.TasSaveCompact_GreenzoneSavingMode"         , tasCfg.saveCompact_GreenzoneSavingMode  );
	config->addOption("SDL.TasLastAuthorName" , "");

	config->addOption("_useNativeFileDialog", "SDL.UseNativeFileDialog", false);
	config->addOption("_useNativeMenuBar"   , "SDL.UseNativeMenuBar", false);
	config->addOption("SDL.PauseOnMainMenuAccess", false);
	config->addOption("SDL.AutoHideMenuFullsreen", false);
	config->addOption("SDL.ContextMenuEnable", true);
	config->addOption("SDL.GuiStyle", "");
	config->addOption("SDL.QtStyleSheet", "");
	config->addOption("SDL.QPaletteFile", "");
	config->addOption("SDL.UseCustomQss", 0);
	config->addOption("SDL.UseCustomQPal", 0);

	config->addOption("_setSchedParam"      , "SDL.SetSchedParam" , 0);
	config->addOption("_emuSchedPolicy"     , "SDL.EmuSchedPolicy", 0);
	config->addOption("_emuSchedNice"       , "SDL.EmuSchedNice"  , 0);
	config->addOption("_emuSchedPrioRt"     , "SDL.EmuSchedPrioRt", 40);
	config->addOption("_guiSchedPolicy"     , "SDL.GuiSchedPolicy", 0);
	config->addOption("_guiSchedNice"       , "SDL.GuiSchedNice"  , 0);
	config->addOption("_guiSchedPrioRt"     , "SDL.GuiSchedPrioRt", 40);
	config->addOption("_emuTimingMech"      , "SDL.EmuTimingMech" , 0);
	config->addOption("SDL.OverClockEnable"     , 0);
	config->addOption("SDL.PostRenderScanlines" , 0);
	config->addOption("SDL.VBlankScanlines"     , 0);
	config->addOption("SDL.Skip7bitOverClocking", 1);

	// fcm -> fm2 conversion
	config->addOption("fcmconvert", "SDL.FCMConvert", "");
    
	// fm2 -> srt conversion
	config->addOption("ripsubs", "SDL.RipSubs", "");
	
	// enable new PPU core
	config->addOption("newppu", "SDL.NewPPU", 0);

	// PPU Viewer Preferences
	config->addOption("SDL.NT_TileFocusPolicy", 0);
	config->addOption("SDL.PPU_TileFocusPolicy", 0);
	config->addOption("SDL.OAM_TileFocusPolicy", 0);
	config->addOption("SDL.PPU_MaskUnused", 0);
	config->addOption("SDL.PPU_InvertMask", 0);
	config->addOption("SDL.PPU_View1_8x16", 0);
	config->addOption("SDL.PPU_View2_8x16", 0);
	config->addOption("SDL.PPU_ViewScanLine", 0);
	config->addOption("SDL.PPU_ViewRefreshFrames", 1);
	config->addOption("SDL.NT_TileSelColor", "#FFFFFF");
	config->addOption("SDL.NT_TileGridColor", "#FF0000");
	config->addOption("SDL.NT_AttrGridColor", "#0000FF");
	config->addOption("SDL.NT_ViewScanLine", 0);
	config->addOption("SDL.NT_DrawScrollLines", 1);
	config->addOption("SDL.NT_DrawTileGridLines", 1);
	config->addOption("SDL.NT_DrawAttrGridLines", 0);
	config->addOption("SDL.NT_DrawAttrbView", 0);
	config->addOption("SDL.NT_IgnoreHidePal", 0);
	config->addOption("SDL.NT_RefreshFrames", 1);
	config->addOption("SDL.PPU_TileSelColor0", "#FFFFFF");
	config->addOption("SDL.PPU_TileGridColor0", "#7F7F7F");
	config->addOption("SDL.PPU_TileSelColor1", "#FFFFFF");
	config->addOption("SDL.PPU_TileGridColor1", "#7F7F7F");
	config->addOption("SDL.PPU_TileShowGrid0", 1);
	config->addOption("SDL.PPU_TileShowGrid1", 1);
	config->addOption("SDL.OAM_TileShowGrid", 0);
	config->addOption("SDL.OAM_TileSelColor", "#FFFFFF");
	config->addOption("SDL.OAM_TileGridColor", "#7F7F7F");
	config->addOption("SDL.OAM_LocatorColor", "#7F7F7F");
	config->addOption("SDL.OAM_ShowPosHex", 0);

	// quit when a+b+select+start is pressed
	config->addOption("4buttonexit", "SDL.ABStartSelectExit", 0);

	// GamePad 0 - 3
	for(unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) 
	{
		char buf[64];
		snprintf(buf, sizeof(buf)-1, "SDL.Input.GamePad.%u.", i);
		prefix = buf;

		config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]);
		config->addOption(prefix + "DeviceGUID", "");
		config->addOption(prefix + "Profile"   , "");
	}
    
	// PowerPad 0 - 1
	for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) {
		char buf[64];
		snprintf(buf, sizeof(buf)-1, "SDL.Input.PowerPad.%u.", i);
		prefix = buf;

		config->addOption(prefix + "DeviceType", DefaultPowerPadDevice[i]);
		config->addOption(prefix + "DeviceNum",  0);
		for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) {
			config->addOption(prefix +PowerPadNames[j], DefaultPowerPad[i][j]);
		}
	}

	// QuizKing
	prefix = "SDL.Input.QuizKing.";
	config->addOption(prefix + "DeviceType", DefaultQuizKingDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) {
		config->addOption(prefix + QuizKingNames[j], DefaultQuizKing[j]);
	}

	// HyperShot
	prefix = "SDL.Input.HyperShot.";
	config->addOption(prefix + "DeviceType", DefaultHyperShotDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) {
		config->addOption(prefix + HyperShotNames[j], DefaultHyperShot[j]);
	}

	// Mahjong
	prefix = "SDL.Input.Mahjong.";
	config->addOption(prefix + "DeviceType", DefaultMahjongDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) {
		config->addOption(prefix + MahjongNames[j], DefaultMahjong[j]);
	}

	// TopRider
	prefix = "SDL.Input.TopRider.";
	config->addOption(prefix + "DeviceType", DefaultTopRiderDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) {
		config->addOption(prefix + TopRiderNames[j], DefaultTopRider[j]);
	}

	// FTrainer
	prefix = "SDL.Input.FTrainer.";
	config->addOption(prefix + "DeviceType", DefaultFTrainerDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) {
		config->addOption(prefix + FTrainerNames[j], DefaultFTrainer[j]);
	}

	// FamilyKeyBoard
	prefix = "SDL.Input.FamilyKeyBoard.";
	config->addOption(prefix + "DeviceType", DefaultFamilyKeyBoardDevice);
	config->addOption(prefix + "DeviceNum", 0);
	for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) {
		config->addOption(prefix + FamilyKeyBoardNames[j],
						DefaultFamilyKeyBoard[j]);
	}

	// for FAMICOM microphone in pad 2 pad 1 didn't have it
	// Takeshi no Chousenjou uses it for example.
	prefix = "SDL.Input.FamicomPad2.";
	config->addOption("rp2mic", prefix + "EnableMic", 0);

	// TODO: use a better data structure to store the hotkeys or something
	//			improve this code overall in the future to make it
	//			easier to maintain
	//const int Hotkeys[HK_MAX] = {
	//	SDLK_F1, // cheat menu
	//	SDLK_F2, // bind state
	//	SDLK_F3, // load lua
	//	SDLK_F4, // toggleBG
	//	SDLK_F5, // save state
	//	SDLK_F6, // fds select
	//	SDLK_F7, // load state
	//	SDLK_F8, // fds eject
	//	SDLK_F6, // VS insert coin
	//	SDLK_F8, // VS toggle dipswitch
	//	SDLK_PERIOD, // toggle frame display
	//	SDLK_F10, // toggle subtitle
	//	SDLK_F11, // reset
	//	SDLK_F12, // screenshot
	//	SDLK_PAUSE, // pause
	//	SDLK_MINUS, // speed++
	//	SDLK_EQUALS, // speed--
	//	SDLK_BACKSLASH, //frame advnace
	//	SDLK_TAB, // turbo
	//	SDLK_COMMA, // toggle input display
	//	SDLK_q, // toggle movie RW
	//	SDLK_QUOTE, // toggle mute capture
	//	0, // quit // edit 10/11/11 - don't map to escape, it causes ugly things to happen to sdl.  can be manually appended to config
	//	SDLK_DELETE, // frame advance lag skip
	//	SDLK_SLASH, // lag counter display
	//	SDLK_0, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5,
	//	SDLK_6, SDLK_7, SDLK_8, SDLK_9,
	//	SDLK_PAGEUP, // select state next
	//	SDLK_PAGEDOWN, // select state prev
	//	0, // Volume Down Internal 
	//	0, // Volume Up Internal 
	//	SDLK_SCROLLLOCK }; // FKB Enable Toggle


	//Hotkeys[ HK_OPEN_ROM ].init( "OpenROM", QKeySequence(QKeySequence::Open) );

	prefix = "SDL.Hotkeys.";

	for(int i=0; i < HK_MAX; i++)
	{
		const char *hotKeyName, *hotKeySeq;
		std::string nameText, keyText;

		getHotKeyConfig( i, &hotKeyName, &hotKeySeq );

		//printf("Hot Key: '%s' = '%s' \n", hotKeyName, hotKeySeq );

		//keyText.assign(" mod=");

		//snprintf( buf, sizeof(buf), "  key=%s", SDL_GetKeyName( Hotkeys[i] ) );

		if ( hotKeyName[0] != 0 )
		{
			nameText.assign( hotKeyName );
			keyText.assign( hotKeySeq );

			config->addOption(prefix + nameText, keyText);

			Hotkeys[i].setConfigName( hotKeyName );
		}
	}
	// All mouse devices
	config->addOption("SDL.OekaKids.0.DeviceType", "Mouse");
	config->addOption("SDL.OekaKids.0.DeviceNum", 0);

	config->addOption("SDL.Arkanoid.0.DeviceType", "Mouse");
	config->addOption("SDL.Arkanoid.0.DeviceNum", 0);

	config->addOption("SDL.Shadow.0.DeviceType", "Mouse");
	config->addOption("SDL.Shadow.0.DeviceNum", 0);

	config->addOption("SDL.Zapper.0.DeviceType", "Mouse");
	config->addOption("SDL.Zapper.0.DeviceNum", 0);

	return config;
}

void
UpdateEMUCore(Config *config)
{
	int ntsccol, ntsctint, ntschue, flag, region;
	int startNTSC, endNTSC, startPAL, endPAL;
	std::string cpalette;

	config->getOption("SDL.NTSCpalette", &ntsccol);
	config->getOption("SDL.Tint", &ntsctint);
	config->getOption("SDL.Hue", &ntschue);
	FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue);

	config->getOption("SDL.IntFrameRate"  , &useIntFrameRate);
	config->getOption("SDL.ForceGrayScale", &force_grayscale);
	config->getOption("SDL.DeempBitSwap"  , &paldeemphswap);
	config->getOption("SDL.PalNotch"      , &palnotch);
	config->getOption("SDL.PalSaturation" , &palsaturation);
	config->getOption("SDL.PalSharpness"  , &palsharpness);
	config->getOption("SDL.PalContrast"   , &palcontrast);
	config->getOption("SDL.PalBrightness" , &palbrightness);
	palupdate = 1;

	config->getOption("SDL.Palette", &cpalette);
	if(cpalette.size()) {
		LoadCPalette(cpalette);
	}

	config->getOption("SDL.NewPPU", &newppu);
	config->getOption("SDL.OverClockEnable"     , &overclock_enabled      );
	config->getOption("SDL.PostRenderScanlines" , &postrenderscanlines    );
	config->getOption("SDL.VBlankScanlines"     , &vblankscanlines        );
	config->getOption("SDL.Skip7bitOverClocking", &skip_7bit_overclocking );
	config->getOption("SDL.ShowGuiMessages"     , &vidGuiMsgEna           );
	config->getOption("SDL.FrameAdvanceDelay"   , &frameAdvance_Delay     );

	config->getOption("SDL.PAL", &region);
	FCEUI_SetRegion(region);

	config->getOption("SDL.GameGenie", &flag);
	FCEUI_SetGameGenie(flag ? 1 : 0);

	config->getOption("SDL.Sound.LowPass", &flag);
	FCEUI_SetLowPass(flag ? 1 : 0);

	config->getOption("SDL.DisableSpriteLimit", &flag);
	FCEUI_DisableSpriteLimitation(flag ? 1 : 0);

	config->getOption("SDL.ScanLineStartNTSC", &startNTSC);
	config->getOption("SDL.ScanLineEndNTSC", &endNTSC);
	config->getOption("SDL.ScanLineStartPAL", &startPAL);
	config->getOption("SDL.ScanLineEndPAL", &endPAL);

#if DOING_SCANLINE_CHECKS
	for(int i = 0; i < 2; x++) {
		if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0;
		if(erendlinev[x]<srendlinev[x] || erendlinev[x]>239) erendlinev[x]=239;
	}
#endif

	FCEUI_SetRenderedLines(startNTSC, endNTSC, startPAL, endPAL);
}

