add lua console, and add/replace print, tostring, addressof, and copytable.

This commit is contained in:
gocha 2009-10-19 03:01:26 +00:00
parent 972e87ca32
commit 25cdffc734
8 changed files with 657 additions and 162 deletions

View File

@ -0,0 +1,207 @@
#include <windows.h>
#include <stdio.h>
#include "main.h"
#include "resource.h"
#include "../../fceulua.h"
extern HWND hAppWnd;
HWND LuaConsoleHWnd = NULL;
void PrintToWindowConsole(int hDlgAsInt, const char* str)
{
HWND hDlg = (HWND)hDlgAsInt;
HWND hConsole = GetDlgItem(hDlg, IDC_LUACONSOLE);
int length = GetWindowTextLength(hConsole);
if(length >= 250000)
{
// discard first half of text if it's getting too long
SendMessage(hConsole, EM_SETSEL, 0, length/2);
SendMessage(hConsole, EM_REPLACESEL, false, (LPARAM)"");
length = GetWindowTextLength(hConsole);
}
SendMessage(hConsole, EM_SETSEL, length, length);
//LuaPerWindowInfo& info = LuaWindowInfo[hDlg];
{
SendMessage(hConsole, EM_REPLACESEL, false, (LPARAM)str);
}
}
void WinLuaOnStart(int hDlgAsInt)
{
HWND hDlg = (HWND)hDlgAsInt;
//LuaPerWindowInfo& info = LuaWindowInfo[hDlg];
//info.started = true;
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_LUABROWSE), false); // disable browse while running because it misbehaves if clicked in a frameadvance loop
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_LUASTOP), true);
SetWindowText(GetDlgItem(hDlg, IDC_BUTTON_LUARUN), "Restart");
SetWindowText(GetDlgItem(hDlg, IDC_LUACONSOLE), ""); // clear the console
// Show_Genesis_Screen(HWnd); // otherwise we might never show the first thing the script draws
}
void WinLuaOnStop(int hDlgAsInt)
{
HWND hDlg = (HWND)hDlgAsInt;
//LuaPerWindowInfo& info = LuaWindowInfo[hDlg];
HWND prevWindow = GetActiveWindow();
SetActiveWindow(hDlg); // bring to front among other script/secondary windows, since a stopped script will have some message for the user that would be easier to miss otherwise
if(prevWindow == hAppWnd) SetActiveWindow(prevWindow);
//info.started = false;
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_LUABROWSE), true);
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_LUASTOP), false);
SetWindowText(GetDlgItem(hDlg, IDC_BUTTON_LUARUN), "Run");
// if(statusOK)
// Show_Genesis_Screen(MainWindow->getHWnd()); // otherwise we might never show the last thing the script draws
//if(info.closeOnStop)
// PostMessage(hDlg, WM_CLOSE, 0, 0);
}
INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
RECT r;
RECT r2;
int dx1, dy1, dx2, dy2;
switch (msg) {
case WM_INITDIALOG:
{
// disable resizing
LONG wndStyle = GetWindowLong(hDlg, GWL_STYLE);
wndStyle &= ~WS_THICKFRAME;
SetWindowLong(hDlg, GWL_STYLE, wndStyle);
// remove the 30000 character limit from the console control
SendMessage(GetDlgItem(hDlg, IDC_LUACONSOLE),EM_LIMITTEXT,0,0);
GetWindowRect(hAppWnd, &r);
dx1 = (r.right - r.left) / 2;
dy1 = (r.bottom - r.top) / 2;
GetWindowRect(hDlg, &r2);
dx2 = (r2.right - r2.left) / 2;
dy2 = (r2.bottom - r2.top) / 2;
int windowIndex = 0;//std::find(LuaScriptHWnds.begin(), LuaScriptHWnds.end(), hDlg) - LuaScriptHWnds.begin();
int staggerOffset = windowIndex * 24;
r.left += staggerOffset;
r.right += staggerOffset;
r.top += staggerOffset;
r.bottom += staggerOffset;
// push it away from the main window if we can
const int width = (r.right-r.left);
const int width2 = (r2.right-r2.left);
if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN))
{
r.right += width;
r.left += width;
}
else if((int)r.left - (int)width2 > 0)
{
r.right -= width2;
r.left -= width2;
}
SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
DragAcceptFiles(hDlg, true);
SetDlgItemText(hDlg, IDC_EDIT_LUAPATH, FCEU_GetLuaScriptName());
return true;
} break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL: {
EndDialog(hDlg, true); // goto case WM_CLOSE;
} break;
case IDC_BUTTON_LUARUN:
{
char filename[MAX_PATH];
GetDlgItemText(hDlg, IDC_EDIT_LUAPATH, filename, MAX_PATH);
FCEU_LoadLuaCode(filename);
} break;
case IDC_BUTTON_LUASTOP:
{
FCEU_LuaStop();
} break;
case IDC_BUTTON_LUAEDIT:
{
char Str_Tmp [1024]; // shadow added because the global one is unreliable
SendDlgItemMessage(hDlg,IDC_EDIT_LUAPATH,WM_GETTEXT,(WPARAM)512,(LPARAM)Str_Tmp);
// tell the OS to open the file with its associated editor,
// without blocking on it or leaving a command window open.
ShellExecute(NULL, "edit", Str_Tmp, NULL, NULL, SW_SHOWNORMAL);
} break;
case IDC_BUTTON_LUABROWSE:
{
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 (*.lua)\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 ))
{
SetWindowText(GetDlgItem(hDlg, IDC_EDIT_LUAPATH), szFileName);
}
return true;
} break;
case IDC_EDIT_LUAPATH:
{
char filename[MAX_PATH];
GetDlgItemText(hDlg, IDC_EDIT_LUAPATH, filename, MAX_PATH);
FILE* file = fopen(filename, "rb");
EnableWindow(GetDlgItem(hDlg, IDOK), file != NULL);
if(file)
fclose(file);
} break;
}
break;
case WM_CLOSE: {
FCEU_LuaStop();
DragAcceptFiles(hDlg, FALSE);
LuaConsoleHWnd = NULL;
} break;
case WM_DROPFILES: {
HDROP hDrop;
//UINT fileNo;
UINT fileCount;
char filename[MAX_PATH];
hDrop = (HDROP)wParam;
fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
if (fileCount > 0) {
DragQueryFile(hDrop, 0, filename, sizeof(filename));
SetWindowText(GetDlgItem(hDlg, IDC_EDIT_LUAPATH), filename);
}
DragFinish(hDrop);
return true;
} break;
}
return false;
}

View File

@ -8,6 +8,7 @@
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@ -74,9 +75,8 @@ BEGIN
POPUP "&Lua"
BEGIN
MENUITEM "&Recent", MENU_LUA_RECENT
MENUITEM "Run &Lua Script...", ID_FILE_RUNLUASCRIPT
MENUITEM "&Stop Lua Script", ID_FILE_STOPLUASCRIPT
MENUITEM "&Reload Lua Script", ID_FILE_LUA_RELOADLUASCRIPT
MENUITEM "&New Lua Script Window...", ID_FILE_OPENLUAWINDOW
MENUITEM "&Close All Script Windows", ID_FILE_CLOSELUAWINDOWS
END
MENUITEM "&Screenshot", ID_FILE_SCREENSHOT
MENUITEM SEPARATOR
@ -1446,15 +1446,19 @@ BEGIN
LTEXT "(Hex)",IDC_STATIC,226,34,19,8
END
IDD_LUA_ADD DIALOGEX 0, 0, 186, 66
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Load Lua Script..."
IDD_LUA DIALOGEX 0, 0, 270, 150
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Lua Script"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Load && Run",1,70,44,50,14
PUSHBUTTON "Cancel",2,129,44,50,14
EDITTEXT 1096,7,7,116,14,ES_AUTOHSCROLL | ES_READONLY,WS_EX_NOPARENTNOTIFY
PUSHBUTTON "Browse...",1359,129,7,50,14
PUSHBUTTON "Browse...",IDC_BUTTON_LUABROWSE,7,31,48,16
PUSHBUTTON "Run",IDC_BUTTON_LUARUN,213,31,50,16
PUSHBUTTON "Stop",IDC_BUTTON_LUASTOP,160,31,50,16
EDITTEXT IDC_EDIT_LUAPATH,7,16,256,14,ES_AUTOHSCROLL
EDITTEXT IDC_LUACONSOLE,7,61,256,81,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY
LTEXT "Output Console",IDC_STATIC,7,51,51,8
LTEXT "Script File",IDC_STATIC,7,7,32,8
PUSHBUTTON "Edit",IDC_BUTTON_LUAEDIT,58,31,46,16
END
VIDEOCONFIG DIALOGEX 65520, 76, 384, 296
@ -1787,14 +1791,6 @@ BEGIN
BOTTOMMARGIN, 171
END
"IDD_LUA_ADD", DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 59
END
"VIDEOCONFIG", DIALOG
BEGIN
LEFTMARGIN, 10
@ -1927,6 +1923,7 @@ IDB_TE_ARROW BITMAP "res/te_arrow.bmp"
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -153,6 +153,7 @@
#define IDD_EDITWATCH 156
#define IDD_PROMPT 157
#define IDR_RWACCELERATOR 158
#define IDD_LUA 159
#define MENU_RESET 200
#define BUTTON_ROMS 200
#define TXT_PAD1 200
@ -456,6 +457,12 @@
#define IDC_PROMPT_TEXT 1245
#define IDC_PROMPT_TEXT2 1246
#define IDC_PROMPT_EDIT 1247
#define IDC_BUTTON_LUABROWSE 1248
#define IDC_BUTTON_LUARUN 1249
#define IDC_BUTTON_LUASTOP 1250
#define IDC_EDIT_LUAPATH 1251
#define IDC_LUACONSOLE 1252
#define IDC_BUTTON_LUAEDIT 1253
#define MENU_NETWORK 40040
#define MENU_PALETTE 40041
#define MENU_SOUND 40042
@ -605,8 +612,8 @@
#define ID_MEMWVIEW_FILE_CLOSE 40217
#define ID_FILE_CLOSE40218 40218
#define MENU_BASIC_BOT2 40220
#define ID_FILE_RUNLUASCRIPT 40229
#define ID_FILE_STOPLUASCRIPT 40230
#define ID_FILE_OPENLUAWINDOW 40229
#define ID_FILE_CLOSELUAWINDOWS 40230
#define ID_CONFIG_DISPLAY 40231
#define ID_DISPLAY_INPUTDISPLAY 40232
#define ID_DISPLAY_LAGCOUNTER 40233
@ -764,9 +771,9 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 159
#define _APS_NEXT_RESOURCE_VALUE 160
#define _APS_NEXT_COMMAND_VALUE 40401
#define _APS_NEXT_CONTROL_VALUE 1248
#define _APS_NEXT_CONTROL_VALUE 1254
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -77,7 +77,7 @@ using namespace std;
//----Context Menu - Some dynamically added menu items
#define FCEUX_CONTEXT_UNHIDEMENU 60000
#define FCEUX_CONTEXT_LOADLASTLUA 60001
#define FCEUX_CONTEXT_STOPLUA 60002
#define FCEUX_CONTEXT_CLOSELUAWINDOWS 60002
//********************************************************************************
//Globals
@ -99,7 +99,6 @@ extern FCEUGI *GameInfo;
extern int EnableAutosave;
extern bool frameAdvanceLagSkip;
extern bool turbo;
extern int luaRunning;
extern bool movie_readonly;
extern bool AutoSS; //flag for whether an auto-save has been made
extern int newppu;
@ -143,6 +142,10 @@ 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);
//Lua Console --------------------------------------------
extern HWND LuaConsoleHWnd;
extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
//Recent Lua Menu ----------------------------------------
char *recent_lua[] = {0,0,0,0,0};
const unsigned int LUA_FIRST_RECENT_FILE = 50000;
@ -371,6 +374,7 @@ void UpdateCheckedMenuItems()
}
//File Maneu
CheckMenuItem(fceumenu, ID_FILE_MOVIE_TOGGLEREAD, movie_readonly ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_FILE_OPENLUAWINDOW, LuaConsoleHWnd ? MF_CHECKED : MF_UNCHECKED);
//NES Menu
CheckMenuItem(fceumenu, ID_NES_PAUSE, EmulationPaused ? MF_CHECKED : MF_UNCHECKED);
@ -507,7 +511,7 @@ void UpdateContextMenuItems(HMENU context, int whichContext)
EnableMenuItem(context,FCEUX_CONTEXT_RECENTROM1,MF_BYCOMMAND | MF_GRAYED);
//Add Lua separator if either lua condition is true (yeah, a little ugly but it works)
if (recent_lua[0] || luaRunning)
if (recent_lua[0] || FCEU_LuaRunning())
InsertMenu(context, 0xFFFF, MF_SEPARATOR, 0, "");
//If a recent lua file exists, add Load Last Lua
@ -515,8 +519,8 @@ void UpdateContextMenuItems(HMENU context, int whichContext)
InsertMenu(context, 0xFFFF, MF_BYCOMMAND, FCEUX_CONTEXT_LOADLASTLUA, "Load last Lua");
//If lua is loaded, add a stop lua item
if (luaRunning)
InsertMenu(context, 0xFFFF, MF_BYCOMMAND, FCEUX_CONTEXT_STOPLUA, "Stop Lua script");
if (FCEU_LuaRunning())
InsertMenu(context, 0xFFFF, MF_BYCOMMAND, FCEUX_CONTEXT_CLOSELUAWINDOWS, "Close All Script Windows");
//If menu is hidden, add an Unhide menu option
if (tog)
@ -1500,15 +1504,31 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
break;
//Lua submenu
case ID_FILE_RUNLUASCRIPT:
FCEUD_LuaRunFrom();
case ID_FILE_OPENLUAWINDOW:
if(!LuaConsoleHWnd)
LuaConsoleHWnd = CreateDialog(fceu_hInstance, MAKEINTRESOURCE(IDD_LUA), hWnd, (DLGPROC) DlgLuaScriptDialog);
else
SetForegroundWindow(LuaConsoleHWnd);
break;
case FCEUX_CONTEXT_STOPLUA:
case ID_FILE_STOPLUASCRIPT:
FCEU_LuaStop();
case FCEUX_CONTEXT_CLOSELUAWINDOWS:
case ID_FILE_CLOSELUAWINDOWS:
if(LuaConsoleHWnd)
PostMessage(LuaConsoleHWnd, WM_CLOSE, 0, 0);
break;
case ID_FILE_LUA_RELOADLUASCRIPT:
FCEU_ReloadLuaCode();
//Recent Lua 1
case FCEUX_CONTEXT_LOADLASTLUA:
if(recent_lua[0])
{
if (!FCEU_LoadLuaCode(recent_lua[0]))
{
int result = MessageBox(hWnd,"Remove from list?", "Could Not Open Recent File", MB_YESNO);
if (result == IDYES)
{
RemoveRecentItem(0, recent_lua, MAX_NUMBER_OF_LUA_RECENT_FILES);
UpdateLuaRMenu(recentluamenu, recent_lua, MENU_LUA_RECENT, LUA_FIRST_RECENT_FILE);
}
}
}
break;
case MENU_EXIT:
@ -1864,22 +1884,6 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
}
break;
//Recent Lua 1
case FCEUX_CONTEXT_LOADLASTLUA:
if(recent_lua[0])
{
if (!FCEU_LoadLuaCode(recent_lua[0]))
{
int result = MessageBox(hWnd,"Remove from list?", "Could Not Open Recent File", MB_YESNO);
if (result == IDYES)
{
RemoveRecentItem(0, recent_lua, MAX_NUMBER_OF_LUA_RECENT_FILES);
UpdateLuaRMenu(recentluamenu, recent_lua, MENU_LUA_RECENT, LUA_FIRST_RECENT_FILE);
}
}
}
break;
//Recent Movie 1
case FCEUX_CONTEXT_LOADLASTMOVIE:
if(recent_movie[0])
@ -2052,7 +2056,7 @@ adelikat: Outsourced this to a remappable hotkey
EnableMenuItem(fceumenu,MENU_VIEWSAVESLOTS,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_VIEWSLOTS)?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));
EnableMenuItem(fceumenu,ID_FILE_CLOSELUAWINDOWS,MF_BYCOMMAND | (LuaConsoleHWnd?MF_ENABLED:MF_GRAYED));
CheckMenuItem(fceumenu, ID_NEWPPU, newppu ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(fceumenu, ID_OLDPPU, !newppu ? MF_CHECKED : MF_UNCHECKED);
@ -2376,102 +2380,6 @@ 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 (*.lua)\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 ))
{
AddRecentLuaFile(szFileName);
FCEU_LoadLuaCode(szFileName);
}
}
void ChangeContextMenuItemText(int menuitem, string text, HMENU menu)
{
MENUITEMINFO moo;
@ -2585,11 +2493,6 @@ void UpdateMenuHotkeys()
combined = "&Stop AVI\t" + combo;
ChangeMenuItemText(MENU_STOP_AVI, combined);
//Reload Lua Script
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_SCRIPT_RELOAD]);
combined = "&Reload Lua Script\t" + combo;
ChangeMenuItemText(ID_FILE_LUA_RELOADLUASCRIPT, combined);
//-------------------------------NES----------------------------------------
//Reset
combo = GetKeyComboName(FCEUD_CommandMapping[EMUCMD_RESET]);

View File

@ -40,6 +40,8 @@ int FCEU_LuaRerecordCountSkip();
void FCEU_LuaGui(uint8 *XBuf);
void FCEU_LuaUpdatePalette();
char* FCEU_GetLuaScriptName();
// And some interesting REVERSE declarations!
char *FCEU_GetFreezeFilename(int slot);

View File

@ -93,6 +93,18 @@ struct LuaSaveState {
}
};
static void(*info_print)(int uid, const char* str);
static void(*info_onstart)(int uid);
static void(*info_onstop)(int uid);
static int info_uid;
#ifdef WIN32
extern HWND LuaConsoleHWnd;
extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
extern void PrintToWindowConsole(int hDlgAsInt, const char* str);
extern void WinLuaOnStart(int hDlgAsInt);
extern void WinLuaOnStop(int hDlgAsInt);
#endif
static lua_State *L;
// Are we running any code right now?
@ -148,6 +160,14 @@ static const char *button_mappings[] = {
"A", "B", "select", "start", "up", "down", "left", "right"
};
#ifdef _MSC_VER
#define snprintf _snprintf
#define vscprintf _vscprintf
#else
#define stricmp strcasecmp
#define strnicmp strncasecmp
#endif
static const char* luaCallIDStrings [] =
{
"CALL_BEFOREEMULATION",
@ -172,6 +192,9 @@ static const char* luaMemHookTypeStrings [] =
//make sure we have the right number of strings
CTASSERT(sizeof(luaMemHookTypeStrings)/sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT)
static char* rawToCString(lua_State* L, int idx=0);
static const char* toCString(lua_State* L, int idx=0);
/**
* Resets emulator speed / pause states after script exit.
*/
@ -435,6 +458,320 @@ static int memory_readbyterange(lua_State *L) {
return 1;
}
static inline bool isalphaorunderscore(char c)
{
return isalpha(c) || c == '_';
}
static std::vector<const void*> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is found, print something like table:parent)
static std::vector<const void*> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table that contains that something (when cycle is found, print the inner result without using __tostring)
#define APPENDPRINT { int _n = snprintf(ptr, remaining,
#define END ); if(_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } }
static void toCStringConverter(lua_State* L, int i, char*& ptr, int& remaining)
{
if(remaining <= 0)
return;
const char* str = ptr; // for debugging
// if there is a __tostring metamethod then call it
int usedMeta = luaL_callmeta(L, i, "__tostring");
if(usedMeta)
{
std::vector<const void*>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L,i));
if(foundCycleIter != s_metacallStack.end())
{
lua_pop(L, 1);
usedMeta = false;
}
else
{
s_metacallStack.push_back(lua_topointer(L,i));
i = lua_gettop(L);
}
}
switch(lua_type(L, i))
{
case LUA_TNONE: break;
case LUA_TNIL: APPENDPRINT "nil" END break;
case LUA_TBOOLEAN: APPENDPRINT lua_toboolean(L,i) ? "true" : "false" END break;
case LUA_TSTRING: APPENDPRINT "%s",lua_tostring(L,i) END break;
case LUA_TNUMBER: APPENDPRINT "%.12Lg",lua_tonumber(L,i) END break;
case LUA_TFUNCTION:
/*if((L->base + i-1)->value.gc->cl.c.isC)
{
//lua_CFunction func = lua_tocfunction(L, i);
//std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func);
//if(iter == s_cFuncInfoMap.end())
goto defcase;
//APPENDPRINT "function(%s)", iter->second END
}
else
{
APPENDPRINT "function(" END
Proto* p = (L->base + i-1)->value.gc->cl.l.p;
int numParams = p->numparams + (p->is_vararg?1:0);
for (int n=0; n<p->numparams; n++)
{
APPENDPRINT "%s", getstr(p->locvars[n].varname) END
if(n != numParams-1)
APPENDPRINT "," END
}
if(p->is_vararg)
APPENDPRINT "..." END
APPENDPRINT ")" END
}*/
goto defcase;
break;
defcase:default: APPENDPRINT "%s:%p",luaL_typename(L,i),lua_topointer(L,i) END break;
case LUA_TTABLE:
{
// first make sure there's enough stack space
if(!lua_checkstack(L, 4))
{
// note that even if lua_checkstack never returns false,
// that doesn't mean we didn't need to call it,
// because calling it retrieves stack space past LUA_MINSTACK
goto defcase;
}
std::vector<const void*>::const_iterator foundCycleIter = std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L,i));
if(foundCycleIter != s_tableAddressStack.end())
{
int parentNum = s_tableAddressStack.end() - foundCycleIter;
if(parentNum > 1)
APPENDPRINT "%s:parent^%d",luaL_typename(L,i),parentNum END
else
APPENDPRINT "%s:parent",luaL_typename(L,i) END
}
else
{
s_tableAddressStack.push_back(lua_topointer(L,i));
struct Scope { ~Scope(){ s_tableAddressStack.pop_back(); } } scope;
APPENDPRINT "{" END
lua_pushnil(L); // first key
int keyIndex = lua_gettop(L);
int valueIndex = keyIndex + 1;
bool first = true;
bool skipKey = true; // true if we're still in the "array part" of the table
lua_Number arrayIndex = (lua_Number)0;
while(lua_next(L, i))
{
if(first)
first = false;
else
APPENDPRINT ", " END
if(skipKey)
{
arrayIndex += (lua_Number)1;
bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex);
}
if(!skipKey)
{
bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex)));
if(invalidLuaIdentifier)
if(keyIsString)
APPENDPRINT "['" END
else
APPENDPRINT "[" END
toCStringConverter(L, keyIndex, ptr, remaining); // key
if(invalidLuaIdentifier)
if(keyIsString)
APPENDPRINT "']=" END
else
APPENDPRINT "]=" END
else
APPENDPRINT "=" END
}
bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
if(valueIsString)
APPENDPRINT "'" END
toCStringConverter(L, valueIndex, ptr, remaining); // value
if(valueIsString)
APPENDPRINT "'" END
lua_pop(L, 1);
if(remaining <= 0)
{
lua_settop(L, keyIndex-1); // stack might not be clean yet if we're breaking early
break;
}
}
APPENDPRINT "}" END
}
} break;
}
if(usedMeta)
{
s_metacallStack.pop_back();
lua_pop(L, 1);
}
}
static const int s_tempStrMaxLen = 64 * 1024;
static char s_tempStr [s_tempStrMaxLen];
static char* rawToCString(lua_State* L, int idx)
{
int a = idx>0 ? idx : 1;
int n = idx>0 ? idx : lua_gettop(L);
char* ptr = s_tempStr;
*ptr = 0;
int remaining = s_tempStrMaxLen;
for(int i = a; i <= n; i++)
{
toCStringConverter(L, i, ptr, remaining);
if(i != n)
APPENDPRINT " " END
}
if(remaining < 3)
{
while(remaining < 6)
remaining++, ptr--;
APPENDPRINT "..." END
}
APPENDPRINT "\r\n" END
// the trailing newline is so print() can avoid having to do wasteful things to print its newline
// (string copying would be wasteful and calling info.print() twice can be extremely slow)
// at the cost of functions that don't want the newline needing to trim off the last two characters
// (which is a very fast operation and thus acceptable in this case)
return s_tempStr;
}
#undef APPENDPRINT
#undef END
// replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function prototypes)
// can be called directly from lua via tostring(), assuming tostring hasn't been reassigned
static int tostring(lua_State *L)
{
char* str = rawToCString(L);
str[strlen(str)-2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's task)
lua_pushstring(L, str);
return 1;
}
// like rawToCString, but will check if the global Lua function tostring()
// has been replaced with a custom function, and call that instead if so
static const char* toCString(lua_State* L, int idx)
{
int a = idx>0 ? idx : 1;
int n = idx>0 ? idx : lua_gettop(L);
lua_getglobal(L, "tostring");
lua_CFunction cf = lua_tocfunction(L,-1);
if(cf == tostring) // optimization: if using our own C tostring function, we can bypass the call through Lua and all the string object allocation that would entail
{
lua_pop(L,1);
return rawToCString(L, idx);
}
else // if the user overrided the tostring function, we have to actually call it and store the temporarily allocated string it returns
{
lua_pushstring(L, "");
for (int i=a; i<=n; i++) {
lua_pushvalue(L, -2); // function to be called
lua_pushvalue(L, i); // value to print
lua_call(L, 1, 1);
if(lua_tostring(L, -1) == NULL)
luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
lua_pushstring(L, (i<n) ? " " : "\r\n");
lua_concat(L, 3);
}
const char* str = lua_tostring(L, -1);
strncpy(s_tempStr, str, s_tempStrMaxLen);
s_tempStr[s_tempStrMaxLen-1] = 0;
lua_pop(L, 2);
return s_tempStr;
}
}
// replacement for luaB_print() that goes to the appropriate textbox instead of stdout
static int print(lua_State *L)
{
const char* str = toCString(L);
int uid = info_uid;//luaStateToUIDMap[L->l_G->mainthread];
//LuaContextInfo& info = GetCurrentInfo();
if(info_print)
info_print(uid, str);
else
puts(str);
//worry(L, 100);
return 0;
}
// provides an easy way to copy a table from Lua
// (simple assignment only makes an alias, but sometimes an independent table is desired)
// currently this function only performs a shallow copy,
// but I think it should be changed to do a deep copy (possibly of configurable depth?)
// that maintains the internal table reference structure
static int copytable(lua_State *L)
{
int origIndex = 1; // we only care about the first argument
int origType = lua_type(L, origIndex);
if(origType == LUA_TNIL)
{
lua_pushnil(L);
return 1;
}
if(origType != LUA_TTABLE)
{
luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
lua_pushnil(L);
return 1;
}
lua_createtable(L, lua_objlen(L,1), 0);
int copyIndex = lua_gettop(L);
lua_pushnil(L); // first key
int keyIndex = lua_gettop(L);
int valueIndex = keyIndex + 1;
while(lua_next(L, origIndex))
{
lua_pushvalue(L, keyIndex);
lua_pushvalue(L, valueIndex);
lua_rawset(L, copyIndex); // copytable[key] = value
lua_pop(L, 1);
}
// copy the reference to the metatable as well, if any
if(lua_getmetatable(L, origIndex))
lua_setmetatable(L, copyIndex);
return 1; // return the new table
}
// because print traditionally shows the address of tables,
// and the print function I provide instead shows the contents of tables,
// I also provide this function
// (otherwise there would be no way to see a table's address, AFAICT)
static int addressof(lua_State *L)
{
const void* ptr = lua_topointer(L,-1);
lua_pushinteger(L, (lua_Integer)ptr);
return 1;
}
struct registerPointerMap
{
const char* registerName;
@ -875,7 +1212,7 @@ static int memory_registerexec(lua_State *L)
//adelikat: table pulled from GENS. credz nitsuja!
#ifdef _WIN32
#ifdef WIN32
const char* s_keyToName[256] =
{
NULL,
@ -989,7 +1326,7 @@ const char* s_keyToName[256] =
static int input_get(lua_State *L) {
lua_newtable(L);
#ifdef _WIN32
#ifdef WIN32
// keyboard and mouse button status
{
extern int EnableBackgroundInput;
@ -2967,7 +3304,7 @@ bool luabitop_validate(lua_State *L) // originally named as luaopen_bit
if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */
const char *msg = "compiled with incompatible luaconf.h";
#ifdef LUA_NUMBER_DOUBLE
#ifdef _WIN32
#ifdef WIN32
if (b == (UBits)1610612736L)
msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
#endif
@ -3144,6 +3481,7 @@ static const struct luaL_reg emulib [] = {
{"registerexit", emu_registerexit},
{"readonly", movie_getreadonly},
{"setreadonly", movie_setreadonly},
{"print", print}, // sure, why not
{NULL,NULL}
};
@ -3324,7 +3662,7 @@ void FCEU_LuaFrameBoundary() {
#endif
} else {
FCEU_LuaStop();
FCEU_LuaOnStop();
FCEU_DispMessage("Script died of natural causes.\n");
}
@ -3383,6 +3721,12 @@ int FCEU_LoadLuaCode(const char *filename) {
luaL_register(L, "bit", bit_funcs); // LuaBitOp library
lua_settop(L, 0); // clean the stack, because each call to luaL_register leaves a table on top
// register a few utility functions outside of libraries (in the global namespace)
lua_register(L, "print", print);
lua_register(L, "tostring", tostring);
lua_register(L, "addressof", addressof);
lua_register(L, "copytable", copytable);
// old bit operation functions
lua_register(L, "AND", bit_band);
lua_register(L, "OR", bit_bor);
@ -3446,6 +3790,21 @@ int FCEU_LoadLuaCode(const char *filename) {
// Set up our protection hook to be executed once every 10,000 bytecode instructions.
//lua_sethook(thread, FCEU_LuaHookFunction, LUA_MASKCOUNT, 10000);
#ifdef WIN32
info_print = PrintToWindowConsole;
info_onstart = WinLuaOnStart;
info_onstop = WinLuaOnStop;
if(!LuaConsoleHWnd)
LuaConsoleHWnd = CreateDialog(fceu_hInstance, MAKEINTRESOURCE(IDD_LUA), hAppWnd, (DLGPROC) DlgLuaScriptDialog);
info_uid = (int)LuaConsoleHWnd;
#else
info_print = NULL;
info_onstart = NULL;
info_onstop = NULL;
#endif
if (info_onstart)
info_onstart(info_uid);
// We're done.
return 1;
}
@ -3486,6 +3845,9 @@ void FCEU_LuaStop() {
CoInitialize(0);
#endif
if (info_onstop)
info_onstop(info_uid);
//lua_gc(L,LUA_GCCOLLECT,0);
@ -3499,7 +3861,8 @@ void FCEU_LuaStop() {
*
*/
int FCEU_LuaRunning() {
return L && luaRunning;
// FIXME: return false when no callback functions are registered.
return (int) (L != NULL); // should return true if callback functions are active.
}
@ -3542,6 +3905,7 @@ uint8 FCEU_LuaReadJoypad(int which, uint8 joyl) {
* This function will not return true if a script is not running.
*/
int FCEU_LuaRerecordCountSkip() {
// FIXME: return true if (there are any active callback functions && skipRerecords)
return L && luaRunning && skipRerecords;
}
@ -3554,7 +3918,7 @@ int FCEU_LuaRerecordCountSkip() {
*/
void FCEU_LuaGui(uint8 *XBuf) {
if (!L || !luaRunning)
if (!L/* || !luaRunning*/)
return;
// First, check if we're being called by anybody
@ -3623,3 +3987,10 @@ void FCEU_LuaGui(uint8 *XBuf) {
return;
}
lua_State* FCEU_GetLuaState() {
return L;
}
char* FCEU_GetLuaScriptName() {
return luaScriptName;
}

View File

@ -1076,6 +1076,10 @@
RelativePath="..\src\drivers\win\log.h"
>
</File>
<File
RelativePath="..\src\drivers\win\luaconsole.cpp"
>
</File>
<File
RelativePath="..\src\drivers\win\main.cpp"
>

View File

@ -1075,6 +1075,10 @@
RelativePath="..\src\drivers\win\log.h"
>
</File>
<File
RelativePath="..\src\drivers\win\luaconsole.cpp"
>
</File>
<File
RelativePath="..\src\drivers\win\main.cpp"
>