Qt JS script engine interface in work.
This commit is contained in:
parent
8e7e5e8c05
commit
198cdafbf8
|
@ -186,6 +186,10 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
gameTimer->setTimerType( Qt::PreciseTimer );
|
||||
gameTimer->start( 8 ); // 120hz
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QtScriptManager::create(nullptr);
|
||||
#endif
|
||||
|
||||
emulatorThread->start();
|
||||
|
||||
g_config->getOption( "SDL.SetSchedParam", &opt );
|
||||
|
@ -272,9 +276,6 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
// Create AVI Recording Disk Thread
|
||||
aviDiskThread = new AviRecordDiskThread_t(this);
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QtScriptManager::create(this);
|
||||
#endif
|
||||
scrHandlerConnected = false;
|
||||
}
|
||||
|
||||
|
@ -316,6 +317,9 @@ consoleWin_t::~consoleWin_t(void)
|
|||
|
||||
closeGamePadConfWindow();
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QtScriptManager::destroy();
|
||||
#endif
|
||||
// The closeApp function call stops all threads.
|
||||
// Calling quit on threads should not happen here.
|
||||
//printf("Thread Finished: %i \n", emulatorThread->isFinished() );
|
||||
|
|
|
@ -167,10 +167,29 @@ void EmuScriptObject::speedMode(const QString& mode)
|
|||
FCEUD_SetEmulationSpeed(speed);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::registerBefore(const QJSValue& func)
|
||||
{
|
||||
script->registerBefore(func);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::registerAfter(const QJSValue& func)
|
||||
{
|
||||
script->registerAfter(func);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::registerStop(const QJSValue& func)
|
||||
{
|
||||
script->registerStop(func);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool EmuScriptObject::loadRom(const QString& romPath)
|
||||
{
|
||||
int ret = LoadGame(romPath.toLocal8Bit().constData());
|
||||
int ret = 0;
|
||||
|
||||
if (!romPath.isEmpty())
|
||||
{
|
||||
ret = LoadGame(romPath.toLocal8Bit().constData());
|
||||
}
|
||||
return ret != 0;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
|
@ -193,7 +212,7 @@ QtScriptInstance::QtScriptInstance(QObject* parent)
|
|||
dialog = win;
|
||||
emu->setDialog(dialog);
|
||||
}
|
||||
engine = new QJSEngine(this);
|
||||
engine = new QJSEngine(nullptr);
|
||||
|
||||
emu->setEngine(engine);
|
||||
|
||||
|
@ -223,7 +242,14 @@ void QtScriptInstance::resetEngine()
|
|||
engine->deleteLater();
|
||||
engine = nullptr;
|
||||
}
|
||||
engine = new QJSEngine(this);
|
||||
engine = new QJSEngine(nullptr);
|
||||
|
||||
if (ui_rootWidget != nullptr)
|
||||
{
|
||||
ui_rootWidget->hide();
|
||||
ui_rootWidget->deleteLater();
|
||||
ui_rootWidget = nullptr;
|
||||
}
|
||||
|
||||
configEngine();
|
||||
}
|
||||
|
@ -240,8 +266,7 @@ int QtScriptInstance::configEngine()
|
|||
|
||||
engine->globalObject().setProperty("gui", guiObject);
|
||||
|
||||
QtScriptManager::getInstance()->removeFrameFinishedConnection(this);
|
||||
|
||||
onFrameBeginCallback = QJSValue();
|
||||
onFrameFinishCallback = QJSValue();
|
||||
onScriptStopCallback = QJSValue();
|
||||
|
||||
|
@ -276,13 +301,10 @@ int QtScriptInstance::loadScriptFile( QString filepath )
|
|||
running = true;
|
||||
//printf("Script Evaluation Success!\n");
|
||||
}
|
||||
onFrameFinishCallback = engine->globalObject().property("onFrameFinish");
|
||||
onScriptStopCallback = engine->globalObject().property("onScriptStop");
|
||||
//onFrameBeginCallback = engine->globalObject().property("onFrameBegin");
|
||||
//onFrameFinishCallback = engine->globalObject().property("onFrameFinish");
|
||||
//onScriptStopCallback = engine->globalObject().property("onScriptStop");
|
||||
|
||||
if (onFrameFinishCallback.isCallable())
|
||||
{
|
||||
QtScriptManager::getInstance()->addFrameFinishedConnection(this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
|
@ -313,24 +335,40 @@ void QtScriptInstance::loadUI(const QString& uiFilePath)
|
|||
QFile uiFile(uiFilePath);
|
||||
QUiLoader uiLoader;
|
||||
|
||||
QWidget* rootWidget = uiLoader.load(&uiFile, dialog);
|
||||
ui_rootWidget = uiLoader.load(&uiFile, dialog);
|
||||
|
||||
if (rootWidget == nullptr)
|
||||
if (ui_rootWidget == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QJSValue uiObject = engine->newQObject(rootWidget);
|
||||
|
||||
QJSValue uiObject = engine->newQObject(ui_rootWidget);
|
||||
|
||||
engine->globalObject().setProperty("ui", uiObject);
|
||||
|
||||
loadObjectChildren( uiObject, rootWidget);
|
||||
loadObjectChildren( uiObject, ui_rootWidget);
|
||||
|
||||
rootWidget->show();
|
||||
ui_rootWidget->show();
|
||||
#else
|
||||
throwError(QJSValue::GenericError, "Error: Application was not linked against Qt UI Tools");
|
||||
#endif
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::registerBefore(const QJSValue& func)
|
||||
{
|
||||
onFrameBeginCallback = func;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::registerAfter(const QJSValue& func)
|
||||
{
|
||||
onFrameFinishCallback = func;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::registerStop(const QJSValue& func)
|
||||
{
|
||||
onScriptStopCallback = func;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::print(const QString& msg)
|
||||
{
|
||||
if (dialog)
|
||||
|
@ -416,6 +454,14 @@ void QtScriptInstance::stopRunning()
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::onFrameBegin()
|
||||
{
|
||||
if (running && onFrameBeginCallback.isCallable())
|
||||
{
|
||||
onFrameBeginCallback.call();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::onFrameFinish()
|
||||
{
|
||||
if (running && onFrameFinishCallback.isCallable())
|
||||
|
@ -499,6 +545,14 @@ QtScriptManager* QtScriptManager::create(QObject* parent)
|
|||
return mgr;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::destroy(void)
|
||||
{
|
||||
if (_instance != nullptr)
|
||||
{
|
||||
delete _instance;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::addScriptInstance(QtScriptInstance* script)
|
||||
{
|
||||
scriptList.push_back(script);
|
||||
|
@ -519,45 +573,22 @@ void QtScriptManager::removeScriptInstance(QtScriptInstance* script)
|
|||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
removeFrameFinishedConnection(script);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::addFrameFinishedConnection(QtScriptInstance* script)
|
||||
void QtScriptManager::frameBeginUpdate()
|
||||
{
|
||||
if (frameFinishConnectList.size() == 0)
|
||||
FCEU_WRAPPER_LOCK();
|
||||
for (auto script : scriptList)
|
||||
{
|
||||
connect(consoleWindow->emulatorThread, SIGNAL(frameFinished(void)), this, SLOT(frameFinishedUpdate(void)), Qt::BlockingQueuedConnection);
|
||||
}
|
||||
frameFinishConnectList.push_back(script);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::removeFrameFinishedConnection(QtScriptInstance* script)
|
||||
{
|
||||
auto it = frameFinishConnectList.begin();
|
||||
|
||||
while (it != frameFinishConnectList.end())
|
||||
{
|
||||
if (*it == script)
|
||||
{
|
||||
it = frameFinishConnectList.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
if (frameFinishConnectList.size() == 0)
|
||||
{
|
||||
consoleWindow->emulatorThread->disconnect( SIGNAL(frameFinished(void)), this, SLOT(frameFinishedUpdate(void)));
|
||||
script->onFrameBegin();
|
||||
}
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::frameFinishedUpdate()
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
for (auto script : frameFinishConnectList)
|
||||
for (auto script : scriptList)
|
||||
{
|
||||
script->onFrameFinish();
|
||||
}
|
||||
|
@ -649,6 +680,8 @@ QScriptDialog_t::QScriptDialog_t(QWidget *parent)
|
|||
|
||||
setLayout(mainLayout);
|
||||
|
||||
emuThreadText.reserve(4096);
|
||||
|
||||
//winList.push_back(this);
|
||||
|
||||
periodicTimer = new QTimer(this);
|
||||
|
@ -694,13 +727,15 @@ void QScriptDialog_t::closeWindow(void)
|
|||
//----------------------------------------------------
|
||||
void QScriptDialog_t::updatePeriodic(void)
|
||||
{
|
||||
// TODO
|
||||
//printf("Update JS\n");
|
||||
//if (updateJSDisplay)
|
||||
//{
|
||||
// updateJSWindows();
|
||||
// updateJSDisplay = false;
|
||||
//}
|
||||
FCEU_WRAPPER_LOCK();
|
||||
if (!emuThreadText.isEmpty())
|
||||
{
|
||||
jsOutput->insertPlainText(emuThreadText);
|
||||
emuThreadText.clear();
|
||||
}
|
||||
refreshState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::openJSKillMessageBox(void)
|
||||
|
@ -863,10 +898,12 @@ void QScriptDialog_t::openScriptFile(void)
|
|||
//----------------------------------------------------
|
||||
void QScriptDialog_t::startScript(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
scriptInstance->resetEngine();
|
||||
if (scriptInstance->loadScriptFile(scriptPath->text()))
|
||||
{
|
||||
// Script parsing error
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
return;
|
||||
}
|
||||
// TODO add option to pass options to script main.
|
||||
|
@ -880,12 +917,16 @@ void QScriptDialog_t::startScript(void)
|
|||
scriptInstance->call("main", argList);
|
||||
|
||||
refreshState();
|
||||
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::stopScript(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
scriptInstance->stopRunning();
|
||||
refreshState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::refreshState(void)
|
||||
|
@ -904,7 +945,14 @@ void QScriptDialog_t::refreshState(void)
|
|||
//----------------------------------------------------
|
||||
void QScriptDialog_t::logOutput(const QString& text)
|
||||
{
|
||||
jsOutput->insertPlainText(text);
|
||||
if (QThread::currentThread() == consoleWindow->emulatorThread)
|
||||
{
|
||||
emuThreadText.append(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
jsOutput->insertPlainText(text);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
#endif // __FCEU_QSCRIPT_ENABLE__
|
||||
|
|
|
@ -55,6 +55,9 @@ public slots:
|
|||
Q_INVOKABLE bool lagged();
|
||||
Q_INVOKABLE void setlagflag(bool flag);
|
||||
Q_INVOKABLE bool emulating();
|
||||
Q_INVOKABLE void registerBefore(const QJSValue& func);
|
||||
Q_INVOKABLE void registerAfter(const QJSValue& func);
|
||||
Q_INVOKABLE void registerStop(const QJSValue& func);
|
||||
Q_INVOKABLE void message(const QString& msg);
|
||||
Q_INVOKABLE void speedMode(const QString& mode);
|
||||
Q_INVOKABLE bool loadRom(const QString& romPath);
|
||||
|
@ -76,6 +79,7 @@ public:
|
|||
void stopRunning();
|
||||
|
||||
int call(const QString& funcName, const QJSValueList& args = QJSValueList());
|
||||
void onFrameBegin();
|
||||
void onFrameFinish();
|
||||
|
||||
int throwError(QJSValue::ErrorType errorType, const QString &message = QString());
|
||||
|
@ -90,6 +94,8 @@ private:
|
|||
QJSEngine* engine = nullptr;
|
||||
QScriptDialog_t* dialog = nullptr;
|
||||
EmuScriptObject* emu = nullptr;
|
||||
QWidget* ui_rootWidget = nullptr;
|
||||
QJSValue onFrameBeginCallback;
|
||||
QJSValue onFrameFinishCallback;
|
||||
QJSValue onScriptStopCallback;
|
||||
bool running = false;
|
||||
|
@ -98,6 +104,9 @@ public slots:
|
|||
Q_INVOKABLE void print(const QString& msg);
|
||||
Q_INVOKABLE void loadUI(const QString& uiFilePath);
|
||||
Q_INVOKABLE QString openFileBrowser(const QString& initialPath = QString());
|
||||
Q_INVOKABLE void registerBefore(const QJSValue& func);
|
||||
Q_INVOKABLE void registerAfter(const QJSValue& func);
|
||||
Q_INVOKABLE void registerStop(const QJSValue& func);
|
||||
};
|
||||
|
||||
class QtScriptManager : public QObject
|
||||
|
@ -110,21 +119,19 @@ public:
|
|||
|
||||
static QtScriptManager* getInstance(){ return _instance; }
|
||||
static QtScriptManager* create(QObject* parent = nullptr);
|
||||
static void destroy();
|
||||
|
||||
int numScriptsLoaded(void){ return scriptList.size(); }
|
||||
void addScriptInstance(QtScriptInstance* script);
|
||||
void removeScriptInstance(QtScriptInstance* script);
|
||||
void addFrameFinishedConnection(QtScriptInstance* script);
|
||||
void removeFrameFinishedConnection(QtScriptInstance* script);
|
||||
private:
|
||||
static QtScriptManager* _instance;
|
||||
|
||||
QList<QtScriptInstance*> scriptList;
|
||||
QList<QtScriptInstance*> frameFinishConnectList;
|
||||
FCEU::timeStampRecord lastFrameUpdate;
|
||||
|
||||
int frameFinishedConnectCount = 0;
|
||||
|
||||
public slots:
|
||||
void frameBeginUpdate();
|
||||
void frameFinishedUpdate();
|
||||
};
|
||||
|
||||
|
@ -151,6 +158,7 @@ protected:
|
|||
QPushButton *startButton;
|
||||
QTextEdit *jsOutput;
|
||||
QtScriptInstance *scriptInstance;
|
||||
QString emuThreadText;
|
||||
|
||||
private:
|
||||
public slots:
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Qt/CheatsConf.h"
|
||||
#include "Qt/SymbolicDebug.h"
|
||||
#include "Qt/CodeDataLogger.h"
|
||||
#include "Qt/QtScriptManager.h"
|
||||
#include "Qt/ConsoleDebugger.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
|
@ -1477,17 +1478,32 @@ int fceuWrapperUpdate( void )
|
|||
|
||||
if ( GameInfo )
|
||||
{
|
||||
auto* qscriptMgr = QtScriptManager::getInstance();
|
||||
|
||||
bool scriptsLoaded = (qscriptMgr != nullptr) && (qscriptMgr->numScriptsLoaded() > 0);
|
||||
|
||||
if (scriptsLoaded)
|
||||
{
|
||||
qscriptMgr->frameBeginUpdate();
|
||||
}
|
||||
|
||||
DoFun(frameskip, periodic_saves);
|
||||
|
||||
if (scriptsLoaded)
|
||||
{
|
||||
qscriptMgr->frameFinishedUpdate();
|
||||
}
|
||||
|
||||
hexEditorUpdateMemoryValues();
|
||||
|
||||
fceuWrapperUnLock();
|
||||
|
||||
emulatorHasMutex = 0;
|
||||
|
||||
if ( consoleWindow )
|
||||
{
|
||||
consoleWindow->emulatorThread->signalFrameFinished();
|
||||
}
|
||||
emulatorHasMutex = 0;
|
||||
|
||||
#ifdef __FCEU_PROFILER_ENABLE__
|
||||
FCEU_profiler_log_thread_activity();
|
||||
|
|
Loading…
Reference in New Issue