fceux/src/drivers/win/window.cpp

2000 lines
56 KiB
C++

/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// File description: Everything relevant for the main window should go here. This
// does not include functions relevant for dialog windows.
#include "../../input.h"
#include "window.h"
#include "main.h"
#include "state.h"
#include "sound.h"
#include "wave.h"
#include "input.h"
#include "video.h"
#include "input.h"
#include "fceu.h"
#include "memwatch.h"
#include "ppuview.h"
#include "debugger.h"
#include "cheat.h"
#include "debug.h"
#include "ntview.h"
#include "memview.h"
#include "tracer.h"
#include "cdlogger.h"
#include "throttle.h"
#include "monitor.h"
#include "tasedit.h"
#include "keyboard.h"
#include "joystick.h"
#include "oldmovie.h"
#include "movie.h"
#include "texthook.h"
#include "guiconfig.h"
#include "timing.h"
#include "palette.h"
#include "directories.h"
#include "gui.h"
#include "help.h"
#include "movie.h"
#include "fceulua.h"
#include "utils/xstring.h"
#include "file.h"
#include "mapinput.h"
#include <fstream>
using namespace std;
//********************************************************************************
//Globals
//********************************************************************************
//Handles---------------------------------------------
static HMENU fceumenu = 0; //Main menu.
HWND pwindow; //Client Area
static HMENU recentmenu; //Recent Menu
HMENU hfceuxcontext; //Handle to context menu
HMENU hfceuxcontextsub; //Handle to context sub menu
//Extern variables------------------------------------
extern bool movieSubtitles;
extern FCEUGI *GameInfo;
extern int EnableAutosave;
extern bool frameAdvanceLagSkip;
extern bool turbo;
extern int luaRunning;
extern bool movie_readonly;
// Extern functions
char *md5_asciistr(uint8 digest[16]);
void SetAutoFirePattern(int onframes, int offframes);
void SetAutoFireOffset(int offset);
void ShowNetplayConsole(void); //mbg merge 7/17/06 YECH had to add
void MapInput(void);
extern BOOL CALLBACK ReplayMetadataDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); //Metadata dialog
//AutoFire-----------------------------------------------
static int CheckedAutoFirePattern = MENU_AUTOFIRE_PATTERN_1;
static int CheckedAutoFireOffset = MENU_AUTOFIRE_OFFSET_1;
int GetCheckedAutoFirePattern();
int GetCheckedAutoFireOffset();
//Internal variables-------------------------------------
int pauseAfterPlayback = 0; //Flag for pausing emulator when movie is finished
static int winwidth, winheight;
static volatile int nofocus = 0;
static int tog = 0; //Toggle for Hide Menu
static bool loggingSound = false;
static LONG WindowXC=1<<30,WindowYC;
int MainWindow_wndx, MainWindow_wndy;
static uint32 mousex,mousey,mouseb;
static int vchanged = 0;
//Recent Menu Strings ------------------------------------
char *recent_files[] = { 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 };
const unsigned int MENU_FIRST_RECENT_FILE = 600;
const unsigned int MAX_NUMBER_OF_RECENT_FILES = sizeof(recent_files)/sizeof(*recent_files);
//Exported variables ------------------------------------
int EnableBackgroundInput = 0;
int ismaximized = 0;
//Subtitles/Comments
void InsertSubtitle(HWND main);
void InsertComment(HWND main);
//Help Menu subtopics
string moviehelp = "{695C964E-B83F-4A6E-9BA2-1A975387DB55}"; //Movie Recording
string gettingstartedhelp = "{C76AEBD9-1E27-4045-8A37-69E5A52D0F9A}";//Getting Started
//********************************************************************************
int GetCheckedAutoFirePattern()
{
//adelikat: sorry, I'm sure there is an easier way to accomplish this.
//This function allows the proper check to be displayed on the auto-fire pattern offset at start up when another autofire pattern is saved in config
if (AFon == 1 && AFoff == 2) return MENU_AUTOFIRE_PATTERN_2;
if (AFon == 1 && AFoff == 3) return MENU_AUTOFIRE_PATTERN_3;
if (AFon == 1 && AFoff == 4) return MENU_AUTOFIRE_PATTERN_4;
if (AFon == 1 && AFoff == 5) return MENU_AUTOFIRE_PATTERN_5;
if (AFon == 2 && AFoff == 1) return MENU_AUTOFIRE_PATTERN_6;
if (AFon == 2 && AFoff == 2) return MENU_AUTOFIRE_PATTERN_7;
if (AFon == 2 && AFoff == 3) return MENU_AUTOFIRE_PATTERN_8;
if (AFon == 2 && AFoff == 4) return MENU_AUTOFIRE_PATTERN_9;
if (AFon == 3 && AFoff == 1) return MENU_AUTOFIRE_PATTERN_10;
if (AFon == 3 && AFoff == 2) return MENU_AUTOFIRE_PATTERN_11;
if (AFon == 3 && AFoff == 3) return MENU_AUTOFIRE_PATTERN_12;
if (AFon == 4 && AFoff == 1) return MENU_AUTOFIRE_PATTERN_13;
if (AFon == 4 && AFoff == 2) return MENU_AUTOFIRE_PATTERN_14;
if (AFon == 5 && AFoff == 1) return MENU_AUTOFIRE_PATTERN_15;
return MENU_AUTOFIRE_PATTERN_1;
}
int GetCheckedAutoFireOffset()
{
if (AutoFireOffset == 1) return MENU_AUTOFIRE_OFFSET_2;
if (AutoFireOffset == 2) return MENU_AUTOFIRE_OFFSET_3;
if (AutoFireOffset == 3) return MENU_AUTOFIRE_OFFSET_4;
if (AutoFireOffset == 4) return MENU_AUTOFIRE_OFFSET_5;
if (AutoFireOffset == 5) return MENU_AUTOFIRE_OFFSET_6;
return MENU_AUTOFIRE_OFFSET_1;
}
// Internal functions
static void ConvertFCM(HWND hwndOwner)
{
std::string initdir = FCEU_GetPath(FCEUMKF_MOVIE);
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwndOwner;
ofn.lpstrFilter = "FCEU <2.0 Movie Files (*.fcm)\0*.fcm\0All files(*.*)\0*.*\0\0";
ofn.lpstrFile = new char[640*1024]; //640K should be enough for anyone
ofn.lpstrFile[0] = 0;
ofn.nMaxFile = 640*1024;
ofn.lpstrInitialDir = initdir.c_str();
ofn.Flags = OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
ofn.lpstrDefExt = "fcm";
ofn.lpstrTitle = "Select old movie(s) for conversion";
if(GetOpenFileName(&ofn))
{
std::vector<std::string> todo;
//build a list of movies to convert. this might be one, or it might be many, depending on what the user selected
if(ofn.nFileExtension==0)
{
//multiselect
std::string dir = ofn.lpstrFile;
char* cp = ofn.lpstrFile + dir.size() + 1;
while(*cp)
{
std::string fname = cp;
todo.push_back(dir + "/" + fname);
cp += fname.size() + 1;
}
}
else
{
todo.push_back(ofn.lpstrFile);
}
SetCursor(LoadCursor(0,IDC_WAIT));
//convert each movie
int okcount = 0;
for(uint32 i=0;i<todo.size();i++)
{
std::string infname = todo[i];
//produce output filename
std::string outname;
size_t dot = infname.find_last_of(".");
if(dot == std::string::npos)
outname = infname + ".fm2";
else
outname = infname.substr(0,dot) + ".fm2";
MovieData md;
EFCM_CONVERTRESULT result = convert_fcm(md, infname);
if(result==FCM_CONVERTRESULT_SUCCESS)
{
okcount++;
std::fstream* outf = FCEUD_UTF8_fstream(outname, "wb");
md.dump(outf,false);
delete outf;
} else {
std::string msg = "Failure converting " + infname + "\r\n\r\n" + EFCM_CONVERTRESULT_message(result);
MessageBox(hwndOwner,msg.c_str(),"Failure converting fcm", 0);
}
}
std::string okmsg = "Converted " + stditoa(okcount) + " movie(s). There were " + stditoa(todo.size()-okcount) + " failure(s).";
MessageBox(hwndOwner,okmsg.c_str(),"FCM Conversion results", 0);
}
delete[] ofn.lpstrFile;
}
void CalcWindowSize(RECT *al)
{
al->left = 0;
al->right = VNSWID * winsizemulx;
al->top = 0;
al->bottom = FSettings.TotalScanlines() * winsizemuly;
AdjustWindowRectEx(al,
GetWindowLong(hAppWnd, GWL_STYLE),
GetMenu(hAppWnd) != NULL,
GetWindowLong(hAppWnd, GWL_EXSTYLE)
);
al->right -= al->left;
al->left = 0;
al->bottom -= al->top;
al->top=0;
}
/// Updates the menu items that should only be enabled if a game is loaded.
/// @param enable Flag that indicates whether the menus should be enabled (1) or disabled (0).
void updateGameDependentMenus(unsigned int enable)
{
const int menu_ids[]= {
MENU_CLOSE_FILE,
MENU_RESET,
MENU_POWER,
MENU_INSERT_COIN,
MENU_SWITCH_DISK,
MENU_RECORD_AVI,
MENU_STOP_AVI,
MENU_RECORD_WAV,
MENU_STOP_WAV,
MENU_HIDE_MENU,
MENU_DEBUGGER,
MENU_PPUVIEWER,
MENU_NAMETABLEVIEWER,
MENU_HEXEDITOR,
MENU_TRACELOGGER,
MENU_CDLOGGER,
MENU_GAMEGENIEDECODER,
MENU_CHEATS,
ID_TOOLS_TEXTHOOKER
};
for (unsigned int i = 0; i < sizeof(menu_ids) / sizeof(*menu_ids); i++)
{
#ifndef _USE_SHARED_MEMORY_
if(simpled[x] == MENU_BASIC_BOT)
EnableMenuItem(fceumenu,menu_ids[i],MF_BYCOMMAND| MF_GRAYED);
else
#endif
EnableMenuItem(fceumenu, menu_ids[i], MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED));
}
}
//Updates menu items which need to be checked or unchecked.
void UpdateCheckedMenuItems()
{
bool spr, bg;
FCEUI_GetRenderPlanes(spr,bg);
static int *polo[] = { &genie, &pal_emulation, &status_icon};
static int polo2[]={ MENU_GAME_GENIE, MENU_PAL, MENU_SHOW_STATUS_ICON };
int x;
// Check or uncheck the necessary menu items
for(x = 0; x < sizeof(polo) / sizeof(*polo); x++)
{
CheckMenuItem(fceumenu, polo2[x], *polo[x] ? MF_CHECKED : MF_UNCHECKED);
}
//NES Menu
CheckMenuItem(fceumenu, ID_NES_PAUSE, EmulationPaused ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_NES_TURBO, turbo ? MF_CHECKED : MF_UNCHECKED);
//Config Menu
CheckMenuItem(fceumenu, MENU_PAUSEAFTERPLAYBACK, pauseAfterPlayback ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_RUN_IN_BACKGROUND, eoptions & EO_BGRUN ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_BACKGROUND_INPUT, EnableBackgroundInput ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_ENABLE_AUTOSAVE, EnableAutosave ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_DISPLAY_FA_LAGSKIP, frameAdvanceLagSkip?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_CONFIG_BINDSAVES, bindSavestate?MF_CHECKED : MF_UNCHECKED);
//Config - Display SubMenu
CheckMenuItem(fceumenu, MENU_DISPLAY_LAGCOUNTER, lagCounterDisplay?MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_DISPLAY_FRAMECOUNTER, frame_display ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_DISPLAY_MOVIESUBTITLES, movieSubtitles?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_DISPLAY_MOVIESUBTITLES_AVI, subtitlesOnAVI?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_DISPLAY_BG, bg?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_DISPLAY_OBJ, spr?MF_CHECKED:MF_UNCHECKED);
//Tools Menu
CheckMenuItem(fceumenu, MENU_ALTERNATE_AB, GetAutoFireDesynch() ? MF_CHECKED : MF_UNCHECKED);
//AutoFire Patterns
int AutoFirePatternIDs[] = {
MENU_AUTOFIRE_PATTERN_1,
MENU_AUTOFIRE_PATTERN_2,
MENU_AUTOFIRE_PATTERN_3,
MENU_AUTOFIRE_PATTERN_4,
MENU_AUTOFIRE_PATTERN_5,
MENU_AUTOFIRE_PATTERN_6,
MENU_AUTOFIRE_PATTERN_7,
MENU_AUTOFIRE_PATTERN_8,
MENU_AUTOFIRE_PATTERN_9,
MENU_AUTOFIRE_PATTERN_10,
MENU_AUTOFIRE_PATTERN_11,
MENU_AUTOFIRE_PATTERN_12,
MENU_AUTOFIRE_PATTERN_13,
MENU_AUTOFIRE_PATTERN_14,
MENU_AUTOFIRE_PATTERN_15,
0};
int AutoFireOffsetIDs[] = {
MENU_AUTOFIRE_OFFSET_1,
MENU_AUTOFIRE_OFFSET_2,
MENU_AUTOFIRE_OFFSET_3,
MENU_AUTOFIRE_OFFSET_4,
MENU_AUTOFIRE_OFFSET_5,
MENU_AUTOFIRE_OFFSET_6,
0};
x = 0;
CheckedAutoFirePattern = GetCheckedAutoFirePattern();
CheckedAutoFireOffset = GetCheckedAutoFireOffset();
while(AutoFirePatternIDs[x])
{
CheckMenuItem(fceumenu, AutoFirePatternIDs[x],
AutoFirePatternIDs[x] == CheckedAutoFirePattern ? MF_CHECKED : MF_UNCHECKED);
x++;
}
x = 0;
while(AutoFireOffsetIDs[x])
{
CheckMenuItem(fceumenu, AutoFireOffsetIDs[x],
AutoFireOffsetIDs[x] == CheckedAutoFireOffset ? MF_CHECKED : MF_UNCHECKED);
x++;
}
//Check input display
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_0, MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_1, MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_2, MF_UNCHECKED);
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_4, MF_UNCHECKED);
switch (input_display)
{
case 0: //Off
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_0, MF_CHECKED);
break;
case 1: //1 player
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_1, MF_CHECKED);
break;
case 2: //2 player
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_2, MF_CHECKED);
break;
//note: input display can actually have a 3 player display option but is skipped in the hotkey toggle so it is skipped here as well
case 4: //4 player
CheckMenuItem(fceumenu, MENU_INPUTDISPLAY_4, MF_CHECKED);
break;
default:
break;
}
}
/// Updates recent files / recent directories menu
/// @param menu Menu handle of the main window's menu
/// @param strs Strings to add to the menu
/// @param mitem Menu ID of the recent files / directory menu
/// @param baseid Menu ID of the first subitem
void UpdateRMenu(HMENU menu, char **strs, unsigned int mitem, unsigned int baseid)
{
// UpdateRMenu(recentmenu, recent_files, MENU_RECENT_FILES, MENU_FIRST_RECENT_FILE);
MENUITEMINFO moo;
int x;
moo.cbSize = sizeof(moo);
moo.fMask = MIIM_SUBMENU | MIIM_STATE;
GetMenuItemInfo(GetSubMenu(fceumenu, 0), mitem, FALSE, &moo);
moo.hSubMenu = menu;
moo.fState = strs[0] ? MFS_ENABLED : MFS_GRAYED;
SetMenuItemInfo(GetSubMenu(fceumenu, 0), mitem, FALSE, &moo);
// Remove all recent files submenus
for(x = 0; x < MAX_NUMBER_OF_RECENT_FILES; x++)
{
RemoveMenu(menu, baseid + x, MF_BYCOMMAND);
}
// Recreate the menus
for(x = MAX_NUMBER_OF_RECENT_FILES - 1; x >= 0; x--)
{
// Skip empty strings
if(!strs[x])
continue;
std::string tmp = strs[x];
std::string archiveName, fileName, fileToOpen;
FCEU_SplitArchiveFilename(tmp,archiveName,fileName,fileToOpen);
if(archiveName != "")
tmp = archiveName + " <" + fileName + ">";
//clamp this string to 128 chars
if(tmp.size()>128)
tmp = tmp.substr(0,128);
moo.cbSize = sizeof(moo);
moo.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
//// Fill in the menu text.
//if(strlen(strs[x]) < 128)
//{
// sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, strs[x]);
//}
//else
//{
// sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, strs[x] + strlen( strs[x] ) - 127);
//}
// Insert the menu item
moo.cch = tmp.size();
moo.fType = 0;
moo.wID = baseid + x;
moo.dwTypeData = (LPSTR)tmp.c_str();
InsertMenuItem(menu, 0, 1, &moo);
}
DrawMenuBar(hAppWnd);
}
/// Helper function to populate the recent directories and recent files arrays.
/// @param addString String to add to the array.
/// @param bufferArray Array where the string will be added.
/// @param arrayLen Length of the bufferArray.
/// @param menu Menu handle of the main menu.
/// @param menuItem
/// @param baseID
void UpdateRecentArray(const char* addString, char** bufferArray, unsigned int arrayLen, HMENU menu, unsigned int menuItem, unsigned int baseId)
{
// Try to find out if the filename is already in the recent files list.
for(unsigned int x = 0; x < arrayLen; x++)
{
if(bufferArray[x])
{
if(!strcmp(bufferArray[x], addString)) // Item is already in list.
{
// If the filename is in the file list don't add it again.
// Move it up in the list instead.
int y;
char *tmp;
// Save pointer.
tmp = bufferArray[x];
for(y = x; y; y--)
{
// Move items down.
bufferArray[y] = bufferArray[y - 1];
}
// Put item on top.
bufferArray[0] = tmp;
// Update the recent files menu
UpdateRMenu(menu, bufferArray, menuItem, baseId);
return;
}
}
}
// The filename wasn't found in the list. That means we need to add it.
// If there's no space left in the recent files list, get rid of the last
// item in the list.
if(bufferArray[arrayLen - 1])
{
free(bufferArray[arrayLen - 1]);
}
// Move the other items down.
for(unsigned int x = arrayLen - 1; x; x--)
{
bufferArray[x] = bufferArray[x - 1];
}
// Add the new item.
bufferArray[0] = (char*)malloc(strlen(addString) + 1); //mbg merge 7/17/06 added cast
strcpy(bufferArray[0], addString);
// Update the recent files menu
UpdateRMenu(menu, bufferArray, menuItem, baseId);
}
/// Add a filename to the recent files list.
/// @param filename Name of the file to add.
void AddRecentFile(const char *filename)
{
UpdateRecentArray(filename, recent_files, MAX_NUMBER_OF_RECENT_FILES, recentmenu, MENU_RECENT_FILES, MENU_FIRST_RECENT_FILE);
}
/// Hides the main menu.
///@param hide_menu Flag to turn the main menu on (0) or off (1)
void HideMenu(unsigned int hide_menu)
{
if(hide_menu)
{
SetMenu(hAppWnd, 0);
}
else
{
SetMenu(hAppWnd, fceumenu);
}
}
void HideFWindow(int h)
{
LONG desa;
if(h) /* Full-screen. */
{
RECT bo;
GetWindowRect(hAppWnd, &bo);
WindowXC = bo.left;
WindowYC = bo.top;
SetMenu(hAppWnd, 0);
desa=WS_POPUP | WS_CLIPSIBLINGS;
}
else
{
desa = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS;
HideMenu(tog);
/* Stupid DirectDraw bug(I think?) requires this. Need to investigate it. */
SetWindowPos(hAppWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE);
}
SetWindowLong(hAppWnd, GWL_STYLE ,desa | ( GetWindowLong(hAppWnd, GWL_STYLE) & WS_VISIBLE ));
SetWindowPos(hAppWnd, 0 ,0 ,0 ,0 ,0 ,SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
}
//Toggles the display status of the main menu.
void ToggleHideMenu(void)
{
if(!fullscreen && (GameInfo || tog))
{
tog ^= 1;
HideMenu(tog);
SetMainWindowStuff();
}
}
//Toggles the display status of the main menu.
//TODO: We could get rid of this one.
void FCEUD_HideMenuToggle(void)
{
ToggleHideMenu();
}
void CloseGame()
{
if (GameInfo)
{
FCEUI_CloseGame();
KillMemView();
updateGameDependentMenus(GameInfo != 0);
}
}
void ALoad(char *nameo, char* innerFilename)
{
if (GameInfo) FCEUI_CloseGame();
if(FCEUI_LoadGameVirtual(nameo, 1))
{
pal_emulation = FCEUI_GetCurrentVidSystem(0, 0);
UpdateCheckedMenuItems();
PushCurrentVideoSettings();
std::string recentFileName = nameo;
if(GameInfo->archiveFilename && GameInfo->archiveCount>1)
recentFileName = (std::string)GameInfo->archiveFilename + "|" + GameInfo->filename;
else
recentFileName = nameo;
AddRecentFile(recentFileName.c_str());
RefreshThrottleFPS();
if(eoptions & EO_HIDEMENU && !tog)
{
ToggleHideMenu();
}
if(eoptions & EO_FSAFTERLOAD)
{
SetFSVideoMode();
}
}
ParseGIInput(GameInfo);
updateGameDependentMenus(GameInfo != 0);
}
/// Shows an Open File dialog and opens the ROM if the user selects a ROM file.
/// @param hParent Handle of the main window
/// @param initialdir Directory that's pre-selected in the Open File dialog.
void LoadNewGamey(HWND hParent, const char *initialdir)
{
const char filter[] = "All usable files(*.nes,*.nsf,*.fds,*.unf,*.zip,*.rar,*.7z,*.gz)\0*.nes;*.nsf;*.fds;*.unf;*.zip;*.rar;*.7z;*.gz\0All non-compressed usable files(*.nes,*.nsf,*.fds,*.unf)\0*.nes;*.nsf;*.fds;*.unf\0All files (*.*)\0*.*\0";
char nameo[2048];
// Create the Open File dialog
OPENFILENAME ofn;
memset(&ofn,0,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.hInstance=fceu_hInstance;
ofn.lpstrTitle=FCEU_NAME" Open File...";
ofn.lpstrFilter=filter;
nameo[0]=0;
ofn.hwndOwner=hParent;
ofn.lpstrFile=nameo;
ofn.nMaxFile=256;
ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; //OFN_EXPLORER|OFN_ENABLETEMPLATE|OFN_ENABLEHOOK;
std::string stdinitdir =FCEU_GetPath(FCEUMKF_ROMS);
ofn.lpstrInitialDir = initialdir ? initialdir : stdinitdir.c_str();
// Show the Open File dialog
if(GetOpenFileName(&ofn))
{
ALoad(nameo);
}
}
void GetMouseData(uint32 (&md)[3])
{
if(FCEUMOV_Mode() == MOVIEMODE_PLAY)
{
return;
}
md[0] = mousex;
md[1] = mousey;
if(!fullscreen)
{
if(ismaximized)
{
RECT t;
GetClientRect(hAppWnd, &t);
md[0] = md[0] * VNSWID / (t.right ? t.right : 1);
md[1] = md[1] * FSettings.TotalScanlines() / (t.bottom ? t.bottom : 1);
}
else
{
md[0] /= winsizemulx;
md[1] /= winsizemuly;
}
md[0] += VNSCLIP;
}
md[1] += FSettings.FirstSLine;
md[2] = ((mouseb == MK_LBUTTON) ? 1 : 0) | (( mouseb == MK_RBUTTON ) ? 2 : 0);
}
//Message loop of the main window
LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
mouseb=wParam;
goto proco;
case WM_RBUTTONUP:
{
hfceuxcontext = LoadMenu(fceu_hInstance,"FCEUCONTEXTMENUS");
//If There is a movie loaded in read only
if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD) && movie_readonly)
hfceuxcontextsub = GetSubMenu(hfceuxcontext,0);
//If there is a movie loaded in read+write
else if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD) && !movie_readonly)
hfceuxcontextsub = GetSubMenu(hfceuxcontext,3);
//If there is a ROM loaded but no movie
else if (GameInfo)
hfceuxcontextsub = GetSubMenu(hfceuxcontext,1);
//Else no ROM
else
hfceuxcontextsub = GetSubMenu(hfceuxcontext,2);
TrackPopupMenu(hfceuxcontextsub,0,(MainWindow_wndx+mousex),(MainWindow_wndy+mousey),TPM_RIGHTBUTTON,hWnd,0);
}
case WM_MOVE:
{
RECT wrect;
GetWindowRect(hWnd,&wrect);
MainWindow_wndx = wrect.left;
MainWindow_wndy = wrect.top;
}
case WM_MOUSEMOVE:
{
mousex=LOWORD(lParam);
mousey=HIWORD(lParam);
}
goto proco;
case WM_ERASEBKGND:
if(xbsave)
return(0);
else
goto proco;
case WM_PAINT:
if(xbsave)
{
PAINTSTRUCT ps;
BeginPaint(hWnd,&ps);
FCEUD_BlitScreen(xbsave);
EndPaint(hWnd,&ps);
return(0);
}
goto proco;
case WM_SIZE:
if(!fullscreen && !changerecursive)
switch(wParam)
{
case SIZE_MAXIMIZED: ismaximized = 1;SetMainWindowStuff();break;
case SIZE_RESTORED: ismaximized = 0;SetMainWindowStuff();break;
}
break;
case WM_SIZING:
{
RECT *wrect=(RECT *)lParam;
RECT srect;
int h=wrect->bottom-wrect->top;
int w=wrect->right-wrect->left;
int how = 0;
if(wParam == WMSZ_BOTTOM || wParam == WMSZ_TOP)
how = 2;
else if(wParam == WMSZ_LEFT || wParam == WMSZ_RIGHT)
how = 1;
else if(wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT
|| wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
how = 3;
if(how & 1)
winsizemulx*= (double)w/winwidth;
if(how & 2)
winsizemuly*= (double)h/winheight;
if(how & 1) FixWXY(0);
else FixWXY(1);
CalcWindowSize(&srect);
winwidth=srect.right;
winheight=srect.bottom;
wrect->right = wrect->left + srect.right;
wrect->bottom = wrect->top + srect.bottom;
}
//sizchange=1;
//break;
goto proco;
case WM_DISPLAYCHANGE:
if(!fullscreen && !changerecursive)
vchanged=1;
goto proco;
case WM_DROPFILES:
{
UINT len;
char *ftmp;
len=DragQueryFile((HDROP)wParam,0,0,0)+1;
if((ftmp=(char*)malloc(len)))
{
DragQueryFile((HDROP)wParam,0,ftmp,len);
string fileDropped = ftmp;
//-------------------------------------------------------
//Check if Movie file
//-------------------------------------------------------
if (!(fileDropped.find(".fm2") == string::npos)) //ROM is already loaded and .fm2 in filename
{
if (GameInfo && !(fileDropped.find(".fm2") == string::npos)) //.fm2 is at the end of the filename so that must be the extension
FCEUI_LoadMovie(ftmp, 1, false, false); //We are convinced it is a movie file, attempt to load it
}
//-------------------------------------------------------
//If not a movie, Load it as a ROM file
//-------------------------------------------------------
else
{
ALoad(ftmp);
free(ftmp);
}
}
}
break;
case WM_COMMAND:
if(HIWORD(wParam) == 0 || HIWORD(wParam) == 1)
{
wParam &= 0xFFFF;
// A menu item from the recent files menu was clicked.
if(wParam >= MENU_FIRST_RECENT_FILE && wParam <= MENU_FIRST_RECENT_FILE + MAX_NUMBER_OF_RECENT_FILES - 1)
{
char*& fname = recent_files[wParam - MENU_FIRST_RECENT_FILE];
if(fname)
{
ALoad(fname);
}
}
switch(LOWORD(wParam))
{
//File Menu-------------------------------------------------------------
case FCEU_CONTEXT_OPENROM:
case MENU_OPEN_FILE:
LoadNewGamey(hWnd, 0);
break;
case FCEU_CONTEXT_CLOSEROM:
case MENU_CLOSE_FILE:
CloseGame();
break;
case MENU_SAVE_STATE: //Save state as
FCEUD_SaveStateAs();
break;
case MENU_LOAD_STATE: //Load state as
FCEUD_LoadStateFrom();
break;
//Movie submenu
case FCEUX_CONTEXT_RECORDMOVIE:
case MENU_RECORD_MOVIE:
FCEUD_MovieRecordTo();
break;
case FCEUX_CONTEXT_REPLAYMOVIE:
case MENU_REPLAY_MOVIE:
// Replay movie menu was selected
FCEUD_MovieReplayFrom();
break;
case FCEU_CONTEXT_STOPMOVIE:
case MENU_STOP_MOVIE:
FCEUI_StopMovie();
break;
case FCEU_CONTEXT_PLAYMOVIEFROMBEGINNING:
case ID_FILE_PLAYMOVIEFROMBEGINNING:
FCEUI_MoviePlayFromBeginning();
break;
//Record Avi/Wav submenu
case MENU_RECORD_AVI:
FCEUD_AviRecordTo();
break;
case MENU_STOP_AVI:
FCEUD_AviStop();
break;
case MENU_RECORD_WAV:
loggingSound = CreateSoundSave();
break;
case MENU_STOP_WAV:
CloseWave();
loggingSound = false;
break;
case FCEUX_CONTEXT_SCREENSHOT:
case ID_FILE_SCREENSHOT:
FCEUI_SaveSnapshot();
break;
//Lua submenu
case ID_FILE_RUNLUASCRIPT:
FCEUD_LuaRunFrom();
break;
case ID_FILE_STOPLUASCRIPT:
FCEU_LuaStop();
break;
case MENU_EXIT:
DoFCEUExit();
break;
//NES Menu--------------------------------------------------------------
case MENU_RESET:
FCEUI_ResetNES();
break;
case MENU_POWER:
FCEUI_PowerNES();
break;
case MENU_EJECT_DISK:
FCEUI_FDSInsert();
break;
case MENU_SWITCH_DISK:
FCEUI_FDSSelect();
break;
case MENU_INSERT_COIN:
FCEUI_VSUniCoin();
break;
//Emulation submenu
case ID_NES_PAUSE:
FCEUI_ToggleEmulationPause();
UpdateCheckedMenuItems();
break;
case ID_NES_TURBO:
FCEUD_TurboToggle();
break;
//Emulation speed submenu
case ID_NES_SPEEDUP:
FCEUD_SetEmulationSpeed(3);
break;
case ID_NES_SLOWDOWN:
FCEUD_SetEmulationSpeed(1);
break;
case ID_NES_SLOWESTSPEED:
FCEUD_SetEmulationSpeed(0);
break;
case ID_NES_NORMALSPEED:
FCEUD_SetEmulationSpeed(2);
break;
case ID_NES_FASTESTSPEED:
FCEUD_SetEmulationSpeed(4);
break;
//Config Menu-----------------------------------------------------------
case MENU_HIDE_MENU:
ToggleHideMenu();
break;
case MENU_PAUSEAFTERPLAYBACK:
pauseAfterPlayback = pauseAfterPlayback?0:1;
UpdateCheckedMenuItems();
break;
case MENU_RUN_IN_BACKGROUND:
eoptions ^= EO_BGRUN;
if((eoptions & EO_BGRUN) == 0)
{
EnableBackgroundInput = 0;
KeyboardSetBackgroundAccess(EnableBackgroundInput!=0);
JoystickSetBackgroundAccess(EnableBackgroundInput!=0);
}
UpdateCheckedMenuItems();
break;
case MENU_BACKGROUND_INPUT:
EnableBackgroundInput ^= 1;
eoptions |= EO_BGRUN * EnableBackgroundInput;
KeyboardSetBackgroundAccess(EnableBackgroundInput!=0);
JoystickSetBackgroundAccess(EnableBackgroundInput!=0);
UpdateCheckedMenuItems();
break;
case MENU_ENABLE_AUTOSAVE:
EnableAutosave ^= 1;
UpdateCheckedMenuItems();
break;
case MENU_DISPLAY_FA_LAGSKIP:
frameAdvanceLagSkip ^= 1;
UpdateCheckedMenuItems();
break;
case MENU_CONFIG_BINDSAVES:
bindSavestate ^= 1;
UpdateCheckedMenuItems();
//Display submenu
case MENU_SHOW_STATUS_ICON:
status_icon = !status_icon;
UpdateCheckedMenuItems();
break;
case MENU_INPUTDISPLAY_0: //Input display off
input_display = 0;
UpdateCheckedMenuItems();
break;
case MENU_INPUTDISPLAY_1: //Input display - 1 player
input_display = 1;
UpdateCheckedMenuItems();
break;
case MENU_INPUTDISPLAY_2: //Input display - 2 player
input_display = 2;
UpdateCheckedMenuItems();
break;
case MENU_INPUTDISPLAY_4: //Input display - 4 player
input_display = 4;
UpdateCheckedMenuItems();
break;
case MENU_DISPLAY_LAGCOUNTER:
lagCounterDisplay ^= 1;
UpdateCheckedMenuItems();
break;
case ID_DISPLAY_FRAMECOUNTER:
FCEUI_MovieToggleFrameDisplay();
UpdateCheckedMenuItems();
break;
case ID_DISPLAY_MOVIESUBTITLES:
movieSubtitles ^= 1;
if (movieSubtitles) FCEU_DispMessage("Movie subtitles on");
else FCEU_DispMessage("Movie subtitles off");
UpdateCheckedMenuItems();
break;
case ID_DISPLAY_MOVIESUBTITLES_AVI:
subtitlesOnAVI ^= 1;
UpdateCheckedMenuItems();
break;
case MENU_DISPLAY_BG:
case MENU_DISPLAY_OBJ:
{
bool spr, bg;
FCEUI_GetRenderPlanes(spr,bg);
if(LOWORD(wParam)==MENU_DISPLAY_BG)
bg = !bg;
else
spr = !spr;
FCEUI_SetRenderPlanes(spr,bg);
}
break;
case MENU_GAME_GENIE:
genie ^= 1;
FCEUI_SetGameGenie(genie!=0);
UpdateCheckedMenuItems();
break;
case MENU_PAL:
pal_emulation ^= 1;
FCEUI_SetVidSystem(pal_emulation);
RefreshThrottleFPS();
UpdateCheckedMenuItems();
PushCurrentVideoSettings();
break;
case MENU_DIRECTORIES:
ConfigDirectories();
break;
case MENU_GUI_OPTIONS:
ConfigGUI();
break;
case MENU_INPUT:
ConfigInput(hWnd);
break;
case MENU_NETWORK:
ShowNetplayConsole();
break;
case MENU_PALETTE:
ConfigPalette();
break;
case MENU_SOUND:
ConfigSound();
break;
case MENU_TIMING:
ConfigTiming();
break;
case MENU_VIDEO:
ConfigVideo();
break;
case MENU_HOTKEYS:
MapInput();
break;
//Tools Menu---------------------------------------------------------------
case MENU_CHEATS:
ConfigCheats(hWnd);
break;
case MENU_MEMORY_WATCH:
CreateMemWatch();
break;
case MENU_RAMFILTER:
DoByteMonitor();
break;
case ACCEL_CTRL_E:
case MENU_TASEDIT:
DoTasEdit();
break;
case MENU_CONVERT_MOVIE:
ConvertFCM(hWnd);
break;
//AutoFire Pattern submenu
case MENU_AUTOFIRE_PATTERN_1:
SetAutoFirePattern(1,1);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_2:
SetAutoFirePattern(1,2);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_3:
SetAutoFirePattern(1,3);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_4:
SetAutoFirePattern(1,4);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_5:
SetAutoFirePattern(1,5);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_6:
SetAutoFirePattern(2,1);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_7:
SetAutoFirePattern(2,2);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_8:
SetAutoFirePattern(2,3);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_9:
SetAutoFirePattern(2,4);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_10:
SetAutoFirePattern(3,1);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_11:
SetAutoFirePattern(3,2);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_12:
SetAutoFirePattern(3,3);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_13:
SetAutoFirePattern(4,1);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_14:
SetAutoFirePattern(4,2);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
case MENU_AUTOFIRE_PATTERN_15:
SetAutoFirePattern(5,1);
CheckedAutoFirePattern = wParam;
UpdateCheckedMenuItems();
break;
//Autofire Offset submenu
case MENU_AUTOFIRE_OFFSET_1:
case MENU_AUTOFIRE_OFFSET_2:
case MENU_AUTOFIRE_OFFSET_3:
case MENU_AUTOFIRE_OFFSET_4:
case MENU_AUTOFIRE_OFFSET_5:
case MENU_AUTOFIRE_OFFSET_6:
SetAutoFireOffset(wParam - MENU_AUTOFIRE_OFFSET_1);
CheckedAutoFireOffset = wParam;
UpdateCheckedMenuItems();
break;
case MENU_ALTERNATE_AB:
SetAutoFireDesynch(GetAutoFireDesynch()^1);
UpdateCheckedMenuItems();
break;
case ID_TOOLS_TEXTHOOKER:
DoTextHooker();
break;
//Debug Menu-------------------------------------------------------------
case MENU_DEBUGGER:
DoDebug(0);
break;
case MENU_PPUVIEWER:
DoPPUView();
break;
case MENU_NAMETABLEVIEWER:
DoNTView();
break;
case MENU_HEXEDITOR:
DoMemView();
break;
case MENU_TRACELOGGER:
DoTracer();
break;
case MENU_CDLOGGER:
DoCDLogger();
break;
case MENU_GAMEGENIEDECODER:
DoGGConv();
break;
//Help Menu--------------------------------------------------------------
case MENU_HELP:
OpenHelpWindow();
break;
case MENU_MSGLOG:
MakeLogWindow();
break;
case MENU_ABOUT:
ShowAboutBox();
break;
//Context Menus------------------------------------------------------
//View comments and subtitles
case FCEUX_CONTEXT_VIEWCOMMENTSSUBTITLES:
CreateDialog(fceu_hInstance, "IDD_REPLAY_METADATA", hWnd, ReplayMetadataDialogProc, (LPARAM)0);
//Load last auto-save
case FCEUX_CONTEXT_REWINDTOLASTAUTO:
FCEUI_Autosave();
break;
//Movie help
case FCEU_CONTEXT_MOVIEHELP:
OpenHelpWindow(moviehelp);
break;
//No Game
case FCEU_CONTEXT_FCEUHELP:
OpenHelpWindow(gettingstartedhelp);
break;
}
}
break;
case WM_SYSCOMMAND:
if(GameInfo && wParam == SC_SCREENSAVE && (goptions & GOO_DISABLESS))
return(0);
if(wParam==SC_KEYMENU)
{
if(GameInfo && InputType[2]==SIFC_FKB && cidisabled)
break;
if(lParam == VK_RETURN || fullscreen || tog) break;
}
goto proco;
case WM_SYSKEYDOWN:
if(GameInfo && InputType[2]==SIFC_FKB && cidisabled)
break; // Hopefully this won't break DInput...
if(fullscreen || tog)
{
if(wParam==VK_MENU)
break;
}
if(wParam == VK_RETURN)
{
if(!(lParam&(1<<30)))
{
UpdateCheckedMenuItems();
changerecursive=1;
if(!SetVideoMode(fullscreen^1))
SetVideoMode(fullscreen);
changerecursive=0;
}
break;
}
goto proco;
case WM_KEYDOWN:
if(GameInfo)
{
//Only disable command keys if a game is loaded(and the other conditions are right, of course).
if(InputType[2]==SIFC_FKB)
{
if(wParam==VK_SCROLL)
{
cidisabled^=1;
FCEUI_DispMessage("Family Keyboard %sabled.",cidisabled?"en":"dis");
}
if(cidisabled)
break; // Hopefully this won't break DInput...
}
}
goto proco;
case WM_CLOSE:
case WM_DESTROY:
case WM_QUIT:
DoFCEUExit();
break;
case WM_ACTIVATEAPP:
if((BOOL)wParam)
{
nofocus=0;
}
else
{
nofocus=1;
}
goto proco;
case WM_ENTERMENULOOP:
UpdateCheckedMenuItems();
UpdateMenuHotkeys();
EnableMenuItem(fceumenu,MENU_RESET,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_RESET)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_POWER,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_POWER)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_TASEDIT,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_TASEDIT)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_CLOSE_FILE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_CLOSEGAME)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_RECENT_FILES,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_OPENGAME)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_OPEN_FILE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_OPENGAME)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_RECORD_MOVIE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_RECORDMOVIE)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_REPLAY_MOVIE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_PLAYMOVIE)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_STOP_MOVIE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_STOPMOVIE)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,ID_FILE_PLAYMOVIEFROMBEGINNING,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_PLAYFROMBEGINNING)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_SAVE_STATE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_SAVESTATE)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_LOAD_STATE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_LOADSTATE)?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_STOP_AVI,MF_BYCOMMAND | (FCEUI_AviIsRecording()?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,MENU_STOP_WAV,MF_BYCOMMAND | (loggingSound?MF_ENABLED:MF_GRAYED));
EnableMenuItem(fceumenu,ID_FILE_STOPLUASCRIPT,MF_BYCOMMAND | (luaRunning?MF_ENABLED:MF_GRAYED));
default:
proco:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
void FixWXY(int pref)
{
if(eoptions&EO_FORCEASPECT)
{
/* First, make sure the ratio is valid, and if it's not, change
it so that it doesn't break everything.
*/
if(saspectw < 0.01) saspectw = 0.01;
if(saspecth < 0.01) saspecth = 0.01;
if((saspectw / saspecth) > 100) saspecth = saspectw;
if((saspecth / saspectw) > 100) saspectw = saspecth;
if((saspectw / saspecth) < 0.1) saspecth = saspectw;
if((saspecth / saspectw) > 0.1) saspectw = saspecth;
if(!pref)
{
winsizemuly = winsizemulx * 256 / FSettings.TotalScanlines() * 3 / 4 * saspectw / saspecth;
}
else
{
winsizemulx = winsizemuly * FSettings.TotalScanlines() / 256 * 4 / 3 * saspecth / saspectw;
}
}
if(winspecial)
{
int mult;
if(winspecial == 1 || winspecial == 2) mult = 2;
else mult = 3;
if(winsizemulx < mult)
{
if(eoptions&EO_FORCEASPECT)
winsizemuly *= mult / winsizemulx;
winsizemulx = mult;
}
if(winsizemuly < mult && mult < 3) //11/14/2008, adelikat: added && mult < 3 and extra code to meet mult >=3 conditions
{
if(eoptions&EO_FORCEASPECT)
winsizemulx *= mult / winsizemuly;
winsizemuly = mult;
}
else if (winsizemuly < mult&& mult >= 3) //11/14/2008, adelikat: This was probably a hacky solution. But when special scalar = 3 and aspect correction is on,
if(eoptions&EO_FORCEASPECT) //then x is corrected to a wider ratio (.5 of what this code seems to expect) so I added a special circumstance for these 2 situations
winsizemulx *= (mult+0.5) / winsizemuly; //And adjusted the special scaling by .5
winsizemuly = mult;
}
if(winsizemulx<0.1)
winsizemulx=0.1;
if(winsizemuly<0.1)
winsizemuly=0.1;
if(eoptions & EO_FORCEISCALE)
{
int x,y;
x = winsizemulx * 2;
y = winsizemuly * 2;
x = (x>>1) + (x&1);
y = (y>>1) + (y&1);
if(!x) x=1;
if(!y) y=1;
winsizemulx = x;
winsizemuly = y;
}
if(winsizemulx > 100) winsizemulx = 100;
if(winsizemuly > 100) winsizemuly = 100;
}
void UpdateFCEUWindow(void)
{
if(vchanged && !fullscreen && !changerecursive && !nofocus)
{
SetVideoMode(0);
vchanged = 0;
}
BlockingCheck();
if(!(eoptions & EO_BGRUN))
{
while(nofocus)
{
Sleep(75);
BlockingCheck();
}
}
}
//Destroys the main window
void ByebyeWindow()
{
SetMenu(hAppWnd, 0);
DestroyMenu(fceumenu);
DestroyWindow(hAppWnd);
}
/// reates the main window.
/// @return Flag that indicates failure (0) or success (1)
int CreateMainWindow()
{
WNDCLASSEX winclass;
RECT tmp;
// Create and register the window class
memset(&winclass, 0, sizeof(winclass));
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_SAVEBITS;
winclass.lpfnWndProc = AppWndProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = fceu_hInstance;
winclass.hIcon = LoadIcon(fceu_hInstance, "ICON_1");
winclass.hIconSm = LoadIcon(fceu_hInstance, "ICON_1");
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //mbg merge 7/17/06 added cast
winclass.lpszClassName = "FCEULTRA";
if(!RegisterClassEx(&winclass))
{
return FALSE;
}
AdjustWindowRectEx(&tmp, WS_OVERLAPPEDWINDOW, 1, 0);
fceumenu = LoadMenu(fceu_hInstance,"FCEUMENU");
recentmenu = CreateMenu();
// Update recent files menu
UpdateRMenu(recentmenu, recent_files, MENU_RECENT_FILES, MENU_FIRST_RECENT_FILE);
updateGameDependentMenus(0);
if (MainWindow_wndx==-32000) MainWindow_wndx=0; //Just in case
if (MainWindow_wndy==-32000) MainWindow_wndy=0;
hAppWnd = CreateWindowEx(
0,
"FCEULTRA",
FCEU_NAME_AND_VERSION,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS, /* Style */
MainWindow_wndx,
MainWindow_wndy,
256,
FSettings.TotalScanlines(), /* X,Y ; Width, Height */
NULL,
fceumenu,
fceu_hInstance,
NULL );
//CenterWindowOnScreen(hAppWnd);
DragAcceptFiles(hAppWnd, 1);
SetMainWindowStuff();
return 1;
}
void SetMainWindowStuff()
{
RECT tmp;
GetWindowRect(hAppWnd, &tmp);
if(ismaximized)
{
winwidth = tmp.right - tmp.left;
winheight = tmp.bottom - tmp.top;
ShowWindow(hAppWnd, SW_SHOWMAXIMIZED);
}
else
{
RECT srect;
if(WindowXC != ( 1 << 30 ))
{
/* Subtracting and adding for if(eoptions&EO_USERFORCE) below. */
tmp.bottom -= tmp.top;
tmp.bottom += WindowYC;
tmp.right -= tmp.left;
tmp.right += WindowXC;
tmp.left = WindowXC;
tmp.top = WindowYC;
WindowXC = 1 << 30;
}
CalcWindowSize(&srect);
SetWindowPos(
hAppWnd,
HWND_TOP,
tmp.left,
tmp.top,
srect.right,
srect.bottom,
SWP_SHOWWINDOW
);
winwidth = srect.right;
winheight = srect.bottom;
ShowWindow(hAppWnd, SW_SHOWNORMAL);
}
}
/// @return Flag that indicates failure (0) or success (1).
int GetClientAbsRect(LPRECT lpRect)
{
POINT point;
point.x = point.y = 0;
if(!ClientToScreen(hAppWnd, &point))
{
return 0;
}
lpRect->top = point.y;
lpRect->left = point.x;
if(ismaximized)
{
RECT al;
GetClientRect(hAppWnd, &al);
lpRect->right = point.x + al.right;
lpRect->bottom = point.y + al.bottom;
}
else
{
lpRect->right = point.x + VNSWID * winsizemulx;
lpRect->bottom = point.y + FSettings.TotalScanlines() * winsizemuly;
}
return 1;
}
//Shows an Open File menu and starts recording an AVI
void FCEUD_AviRecordTo(void)
{
OPENFILENAME ofn;
char szChoice[MAX_PATH];
string tempFilename, aviFilename;
std::string aviDirectory = FCEU_GetPath(21); //21 = FCEUMKF_AVI
if (aviDirectory.find_last_of("\\") != (aviDirectory.size()-1))
aviDirectory.append("\\"); //if directory override has no / then add one
//if we are playing a movie, construct the filename from the current movie.
if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD))
{
tempFilename = GetMfn(); //get movie filename
tempFilename.erase(0,1); //remove dot
}
//else construct it from the ROM name.
else
tempFilename = GetRomName();
aviFilename = aviDirectory + tempFilename; //concate avi directory and movie filename
strcpy(szChoice, aviFilename.c_str());
char* dot = strrchr(szChoice,'.');
if (dot) *dot='\0';
strcat(szChoice, ".avi");
// avi record file browser
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hAppWnd;
ofn.lpstrFilter = "AVI Files (*.avi)\0*.avi\0\0";
ofn.lpstrFile = szChoice;
ofn.lpstrDefExt = "avi";
ofn.lpstrTitle = "Save AVI as";
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if(GetSaveFileName(&ofn))
{
FCEUI_AviBegin(szChoice);
}
}
//Stop AVI recording
void FCEUD_AviStop(void)
{
FCEUI_AviEnd();
}
void FCEUD_CmdOpen(void)
{
LoadNewGamey(hAppWnd, 0);
}
bool FCEUD_PauseAfterPlayback()
{
return pauseAfterPlayback!=0;
}
INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
static int *success;
switch (msg) {
case WM_INITDIALOG:
{
// Nothing very useful to do
success = (int*)lParam;
return TRUE;
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
{
char filename[MAX_PATH];
GetDlgItemText(hDlg, 1096, filename, MAX_PATH);
if (FCEU_LoadLuaCode(filename)) {
*success = 1;
// For user's convenience, don't close dialog unless we're done.
// Users who make syntax errors and fix/reload will thank us.
EndDialog(hDlg, 1);
} else {
//MessageBox(hDlg, "Couldn't load script.", "Oops", MB_OK); // XXX better if errors are displayed by the Lua code.
*success = 0;
}
return TRUE;
}
case IDCANCEL:
{
EndDialog(hDlg, 0);
return TRUE;
}
case 1359:
{
OPENFILENAME ofn;
char szFileName[MAX_PATH];
szFileName[0] = '\0';
ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hDlg;
ofn.lpstrFilter = "Lua scripts\0*.lua\0All files\0*.*\0\0";
ofn.lpstrFile = szFileName;
ofn.lpstrDefExt = "lua";
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; // hide previously-ignored read-only checkbox (the real read-only box is in the open-movie dialog itself)
if(GetOpenFileName( &ofn ))
{
SetWindowText(GetDlgItem(hDlg, 1096), szFileName);
}
//SetCurrentDirectory(movieDirectory);
return TRUE;
}
}
}
//char message[1024];
// sprintf(message, "Unkonwn command %d,%d",msg,wParam);
//MessageBox(hDlg, message, TEXT("Range Error"), MB_OK);
// printf("Unknown entry %d,%d,%d\n",msg,wParam,lParam);
// All else, fall off
return FALSE;
}
void FCEUD_LuaRunFrom(void)
{
int success = 0;
//mbg 8/2/08 - i decided i didnt like this dialog box. so for now we are just going to run the script directly
//DialogBoxParam(fceu_hInstance, "IDD_LUA_ADD", hAppWnd, DlgLuaScriptDialog,(LPARAM) &success);
OPENFILENAME ofn;
char szFileName[MAX_PATH];
szFileName[0] = '\0';
ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hAppWnd;
ofn.lpstrFilter = "Lua scripts\0*.lua\0All files\0*.*\0\0";
ofn.lpstrFile = szFileName;
ofn.lpstrDefExt = "lua";
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; // hide previously-ignored read-only checkbox (the real read-only box is in the open-movie dialog itself)
std::string initdir = FCEU_GetPath(FCEUMKF_LUA);
ofn.lpstrInitialDir=initdir.c_str();
if(GetOpenFileName( &ofn ))
{
FCEU_LoadLuaCode(szFileName);
}
}
void ChangeMenuItemText(int menuitem, string text)
{
MENUITEMINFO moo;
moo.cbSize = sizeof(moo);
moo.fMask = MIIM_TYPE;
moo.cch = NULL;
GetMenuItemInfo(fceumenu, menuitem, FALSE, &moo);
moo.dwTypeData = (LPSTR)text.c_str();
SetMenuItemInfo(fceumenu, menuitem, FALSE, &moo);
}
void UpdateMenuHotkeys()
{
//Update all menu items that can be called rom a hotkey
string combo, combined;
//-------------------------------FILE---------------------------------------
//Open ROM
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_OPENROM]);
combined = "&Open ROM...\t" + combo;
ChangeMenuItemText(MENU_OPEN_FILE, combined);
//Close ROM
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_CLOSEROM]);
combined = "&Close\t" + combo;
ChangeMenuItemText(MENU_CLOSE_FILE, combined);
//Loadstate from
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_LOAD_STATE_FROM]);
combined = "Load State From...\t" + combo;
ChangeMenuItemText(MENU_LOAD_STATE, combined);
//Savestate as
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SAVE_STATE_AS]);
combined = "Save State As...\t" + combo;
ChangeMenuItemText(MENU_SAVE_STATE, combined);
//Record Movie
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_RECORD_TO]);
combined = "Record Movie...\t" + combo;
ChangeMenuItemText(MENU_RECORD_MOVIE, combined);
//Replay movie
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_REPLAY_FROM]);
combined = "Replay Movie...\t" + combo;
ChangeMenuItemText(MENU_REPLAY_MOVIE, combined);
//Stop movie
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_STOP]);
combined = "Stop Movie\t" + combo;
ChangeMenuItemText(MENU_STOP_MOVIE, combined);
//Play Movie from Beginning
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_PLAY_FROM_BEGINNING]);
combined = "Play from beginning\t" + combo;
ChangeMenuItemText(ID_FILE_PLAYMOVIEFROMBEGINNING, combined);
//Screenshot
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SCREENSHOT]);
combined = "Screenshot\t" + combo;
ChangeMenuItemText(ID_FILE_SCREENSHOT, combined);
//Record AVI
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_AVI_RECORD_AS]);
combined = "Record AVI...\t" + combo;
ChangeMenuItemText(MENU_RECORD_AVI, combined);
//Stop AVI
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_AVI_STOP]);
combined = "Stop AVI\t" + combo;
ChangeMenuItemText(MENU_STOP_AVI, combined);
//-------------------------------NES----------------------------------------
//Reset
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_RESET]);
combined = "&Reset\t" + combo;
ChangeMenuItemText(MENU_RESET, combined);
//Power
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_POWER]);
combined = "&Power\t" + combo;
ChangeMenuItemText(MENU_POWER, combined);
//Eject/Insert Disk
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_FDS_EJECT_INSERT]);
combined = "&Eject/Insert Disk\t" + combo;
ChangeMenuItemText(MENU_EJECT_DISK, combined);
//Switch Disk Side
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_FDS_SIDE_SELECT]);
combined = "&Switch Disk Side\t" + combo;
ChangeMenuItemText(MENU_SWITCH_DISK, combined);
//Insert Coin
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_VSUNI_COIN]);
combined = "&Insert Coin\t" + combo;
ChangeMenuItemText(MENU_INSERT_COIN, combined);
//Pause
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_PAUSE]);
combined = "Pause\t" + combo;
ChangeMenuItemText(ID_NES_PAUSE, combined);
//Frame Advance
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_FRAME_ADVANCE]);
combined = "Frame Advance\t" + combo;
ChangeMenuItemText(ID_NES_FRAMEADVANCE, combined);
//Turbo
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_TURBO_TOGGLE]);
combined = "Turbo\t" + combo;
ChangeMenuItemText(ID_NES_TURBO, combined);
//Speed Up
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_FASTER]);
combined = "Speed Up\t" + combo;
ChangeMenuItemText(ID_NES_SPEEDUP, combined);
//Slow Down
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_SLOWER]);
combined = "Slow Down\t" + combo;
ChangeMenuItemText(ID_NES_SLOWDOWN, combined);
//Slowest Speed
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_SLOWEST]);
combined = "Slowest Speeed\t" + combo;
ChangeMenuItemText(ID_NES_SLOWESTSPEED, combined);
//Normal Speed
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_NORMAL]);
combined = "Normal Speed\t" + combo;
ChangeMenuItemText(ID_NES_NORMALSPEED, combined);
//Fastest Speed
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SPEED_FASTEST]);
combined = "Fastest Speed\t" + combo;
ChangeMenuItemText(ID_NES_FASTESTSPEED, combined);
//-------------------------------Config-------------------------------------
//Hide Menu
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_HIDE_MENU_TOGGLE]);
combined = "Hide Menu\t" + combo;
ChangeMenuItemText(MENU_HIDE_MENU, combined);
//Frame Adv. skip lag
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_FRAMEADV_SKIPLAG]);
combined = "Frame Adv. - Skip Lag\t" + combo;
ChangeMenuItemText(MENU_DISPLAY_FA_LAGSKIP, combined);
//Movie Status Icon
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE]);
combined = "Movie Status Icon\t" + combo;
ChangeMenuItemText(MENU_SHOW_STATUS_ICON, combined);
//Lag Counter
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MISC_DISPLAY_LAGCOUNTER_TOGGLE]);
combined = "Lag Counter\t" + combo;
ChangeMenuItemText(MENU_DISPLAY_LAGCOUNTER, combined);
//Frame Counter
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE]);
combined = "Frame Counter\t" + combo;
ChangeMenuItemText(ID_DISPLAY_FRAMECOUNTER, combined);
//Movie Subtitles
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MISC_DISPLAY_MOVIESUBTITLES]);
combined = "Movie Subtitles\t" + combo;
ChangeMenuItemText(ID_DISPLAY_MOVIESUBTITLES, combined);
//Graphics: BG
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MISC_DISPLAY_BG_TOGGLE]);
combined = "Graphics: BG\t" + combo;
ChangeMenuItemText(MENU_DISPLAY_BG, combined);
//Graphics: OBJ
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_MISC_DISPLAY_OBJ_TOGGLE]);
combined = "Graphics: OBJ\t" + combo;
ChangeMenuItemText(MENU_DISPLAY_OBJ, combined);
//-------------------------------Tools--------------------------------------
//Open Cheats
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENCHEATS]);
combined = "&Cheats...\t" + combo;
ChangeMenuItemText(MENU_CHEATS, combined);
//Open Memory Watch
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENMEMORYWATCH]);
combined = "&Memory Watch...\t" + combo;
ChangeMenuItemText(MENU_MEMORY_WATCH, combined);
//-------------------------------Debug--------------------------------------
//Open Debugger
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENDEBUGGER]);
combined = "Debugger...\t" + combo;
ChangeMenuItemText(MENU_DEBUGGER, combined);
//Open PPU Viewer
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENPPU]);
combined = "PPU Viewer...\t" + combo;
ChangeMenuItemText(MENU_PPUVIEWER, combined);
//Open Hex editor
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENHEX]);
combined = "Hex Editor...\t" + combo;
ChangeMenuItemText(MENU_HEXEDITOR, combined);
//Open Trace Logger
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENTRACELOGGER]);
combined = "Trace Logger...\t" + combo;
ChangeMenuItemText(MENU_TRACELOGGER, combined);
//Open Code/Data Logger
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_TOOL_OPENCDLOGGER]);
combined = "Code/Data Logger...\t" + combo;
ChangeMenuItemText(MENU_CDLOGGER, combined);
}