From 446763b232e5bfd1f4a86981dcdcee471998d0ab Mon Sep 17 00:00:00 2001 From: harry Date: Sun, 11 Feb 2024 14:56:58 -0500 Subject: [PATCH] Added JS joypad object functionality. --- src/drivers/Qt/QtScriptManager.cpp | 109 ++++++++++++++++++++++++++++- src/drivers/Qt/QtScriptManager.h | 70 ++++++++++++++++++ 2 files changed, 178 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/QtScriptManager.cpp b/src/drivers/Qt/QtScriptManager.cpp index f296a502..d15ea21f 100644 --- a/src/drivers/Qt/QtScriptManager.cpp +++ b/src/drivers/Qt/QtScriptManager.cpp @@ -71,6 +71,8 @@ // File Base Name from Core extern char FileBase[]; +extern uint8 joy[4]; +extern uint32 GetGamepadPressedImmediate(); static thread_local FCEU::JSEngine* currentEngine = nullptr; @@ -96,6 +98,56 @@ ColorScriptObject::~ColorScriptObject() //printf("ColorScriptObject %p Destructor: %i\n", this, numInstances); } //---------------------------------------------------- +//---- Joypad Object +//---------------------------------------------------- +int JoypadScriptObject::numInstances = 0; + +JoypadScriptObject::JoypadScriptObject(int playerIdx) + : QObject() +{ + numInstances++; + //printf("JoypadScriptObject %p Constructor: %i\n", this, numInstances); + + moveToThread(QApplication::instance()->thread()); + + player = playerIdx; +} +//---------------------------------------------------- +JoypadScriptObject::~JoypadScriptObject() +{ + numInstances--; + //printf("JoypadScriptObject %p Destructor: %i\n", this, numInstances); +} +//---------------------------------------------------- +void JoypadScriptObject::readData() +{ + uint8_t buttons = joy[player]; + + a = (buttons & 0x01) ? true : false; + b = (buttons & 0x02) ? true : false; + select = (buttons & 0x04) ? true : false; + start = (buttons & 0x08) ? true : false; + up = (buttons & 0x10) ? true : false; + down = (buttons & 0x20) ? true : false; + left = (buttons & 0x40) ? true : false; + right = (buttons & 0x80) ? true : false; +} +//---------------------------------------------------- +void JoypadScriptObject::readDataPhy() +{ + uint32_t gpData = GetGamepadPressedImmediate(); + uint8_t buttons = gpData >> (player * 8); + + a = (buttons & 0x01) ? true : false; + b = (buttons & 0x02) ? true : false; + select = (buttons & 0x04) ? true : false; + start = (buttons & 0x08) ? true : false; + up = (buttons & 0x10) ? true : false; + down = (buttons & 0x20) ? true : false; + left = (buttons & 0x40) ? true : false; + right = (buttons & 0x80) ? true : false; +} +//---------------------------------------------------- //---- EMU State Object //---------------------------------------------------- int EmuStateScriptObject::numInstances = 0; @@ -784,6 +836,50 @@ void PpuScriptObject::writeByte(int address, int value) } } //---------------------------------------------------- +//---- Input Script Object +//---------------------------------------------------- +//---------------------------------------------------- +InputScriptObject::InputScriptObject(QObject* parent) + : QObject(parent) +{ + script = qobject_cast(parent); + engine = script->getEngine(); + + for (int i=0; inewQObject( joypad[i].qObj ); + +//#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +// QJSEngine::setObjectOwnership( joypad[i].qObj, QJSEngine::CppScriptOwnership); +//#endif + } +} +//---------------------------------------------------- +InputScriptObject::~InputScriptObject() +{ +} +//---------------------------------------------------- +QJSValue InputScriptObject::readJoypad(int player, bool immediate) +{ + if ( (player < 0) || (player >= MAX_NUM_JOYPADS) ) + { + QString msg = "Error: Joypad player index (" + QString::number(player) + ") is out of bounds!\n"; + engine->throwError(QJSValue::RangeError, msg); + player = 0; + } + if (immediate) + { + joypad[player].qObj->readDataPhy(); + } + else + { + joypad[player].qObj->readData(); + } + return joypad[player].jsObj; +} +//---------------------------------------------------- //---- Memory Script Object //---------------------------------------------------- //---------------------------------------------------- @@ -1317,6 +1413,11 @@ void QtScriptInstance::shutdownEngine() delete mem; mem = nullptr; } + if (input != nullptr) + { + delete input; + input = nullptr; + } if (ui_rootWidget != nullptr) { @@ -1343,6 +1444,7 @@ int QtScriptInstance::initEngine() rom = new JS::RomScriptObject(this); ppu = new JS::PpuScriptObject(this); mem = new JS::MemoryScriptObject(this); + input = new JS::InputScriptObject(this); emu->setDialog(dialog); rom->setDialog(dialog); @@ -1374,6 +1476,11 @@ int QtScriptInstance::initEngine() engine->globalObject().setProperty("memory", memObject); + // input + QJSValue inputObject = engine->newQObject(input); + + engine->globalObject().setProperty("input", inputObject); + // gui QJSValue guiObject = engine->newQObject(this); @@ -1778,7 +1885,7 @@ QtScriptManager::QtScriptManager(QObject* parent) : QObject(parent) { _instance = this; - monitorThread = new ScriptMonitorThread_t(); + monitorThread = new ScriptMonitorThread_t(this); monitorThread->start(); periodicUpdateTimer = new QTimer(this); diff --git a/src/drivers/Qt/QtScriptManager.h b/src/drivers/Qt/QtScriptManager.h index 7b3e48d0..a9dd3ae9 100644 --- a/src/drivers/Qt/QtScriptManager.h +++ b/src/drivers/Qt/QtScriptManager.h @@ -105,6 +105,49 @@ public slots: Q_INVOKABLE void setPalette(int p){ _palette = p; } }; +class JoypadScriptObject: public QObject +{ + Q_OBJECT + Q_PROPERTY(bool up READ getUp) + Q_PROPERTY(bool down READ getDown) + Q_PROPERTY(bool left READ getLeft) + Q_PROPERTY(bool right READ getRight) + Q_PROPERTY(bool select READ getSelect) + Q_PROPERTY(bool start READ getStart) + Q_PROPERTY(bool a READ getA) + Q_PROPERTY(bool b READ getB) + Q_PROPERTY(int player READ getPlayer) +public: + JoypadScriptObject(int playerIdx); + ~JoypadScriptObject(); + + void readData(); + void readDataPhy(); + +private: + bool up = false; + bool down = false; + bool left = false; + bool right = false; + bool select = false; + bool start = false; + bool a = false; + bool b = false; + int player = 0; + static int numInstances; + +public slots: + Q_INVOKABLE bool getUp(){ return up; } + Q_INVOKABLE bool getDown(){ return down; } + Q_INVOKABLE bool getLeft(){ return left; } + Q_INVOKABLE bool getRight(){ return right; } + Q_INVOKABLE bool getSelect(){ return select; } + Q_INVOKABLE bool getStart(){ return start; } + Q_INVOKABLE bool getA(){ return a; } + Q_INVOKABLE bool getB(){ return b; } + Q_INVOKABLE int getPlayer(){ return player; } +}; + class EmuStateScriptObject: public QObject { Q_OBJECT @@ -299,6 +342,32 @@ public slots: Q_INVOKABLE void writeByte(int address, int value); }; +class InputScriptObject: public QObject +{ + Q_OBJECT +public: + InputScriptObject(QObject* parent = nullptr); + ~InputScriptObject(); + + void setEngine(FCEU::JSEngine* _engine){ engine = _engine; } + void setDialog(QScriptDialog_t* _dialog){ dialog = _dialog; } + + static constexpr int MAX_NUM_JOYPADS = 4; +private: + FCEU::JSEngine* engine = nullptr; + QScriptDialog_t* dialog = nullptr; + QtScriptInstance* script = nullptr; + + struct + { + JoypadScriptObject* qObj; + QJSValue jsObj; + } joypad[MAX_NUM_JOYPADS]; + +public slots: + Q_INVOKABLE QJSValue readJoypad(int player, bool immediate = false); +}; + } // JS class ScriptExecutionState @@ -369,6 +438,7 @@ private: JS::RomScriptObject* rom = nullptr; JS::PpuScriptObject* ppu = nullptr; JS::MemoryScriptObject* mem = nullptr; + JS::InputScriptObject* input = nullptr; QWidget* ui_rootWidget = nullptr; QJSValue *onFrameBeginCallback = nullptr; QJSValue *onFrameFinishCallback = nullptr;