diff --git a/CHANGES b/CHANGES index 221c201db..6beccae59 100644 --- a/CHANGES +++ b/CHANGES @@ -69,6 +69,7 @@ Misc: - Qt: Enable -b for Boot BIOS menu option (fixes mgba.io/i/2074) - Qt: Add tile range selection to tile viewer (closes mgba.io/i/2455) - Qt: Show warning if XQ audio is toggled while loaded (fixes mgba.io/i/2295) + - Qt: Add e-Card passing to the command line (closes mgba.io/i/2474) - Windows: Attach to console if present - Vita: Add bilinear filtering option (closes mgba.io/i/344) diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index 89ccae253..92d963008 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -125,6 +125,28 @@ ConfigController::ConfigController(QObject* parent) mCoreConfigSetDefaultIntValue(&m_config, "sgb.borders", 1); mCoreConfigSetDefaultIntValue(&m_config, "useCgbColors", 1); mCoreConfigMap(&m_config, &m_opts); + + mSubParserGraphicsInit(&m_subparsers[0], &m_graphicsOpts); + + m_subparsers[1].usage = "Frontend options:\n" + " --ecard FILENAME Scan an e-Reader card in the first loaded game\n" + " Can be paassed multiple times for multiple cards"; + m_subparsers[1].parse = nullptr; + m_subparsers[1].parseLong = [](struct mSubParser* parser, const char* option, const char* arg) { + if (option == QLatin1String("ecard")) { + QStringList* eCards = static_cast(parser->opts); + eCards->append(QString::fromUtf8(arg)); + return true; + } + return false; + }; + m_subparsers[1].apply = nullptr; + m_subparsers[1].extraOptions = nullptr; + m_subparsers[1].longOptions = (const mOption[]) { + { "ecard", true, '\0' }, + { 0 } + }; + m_subparsers[1].opts = &m_eCards; } ConfigController::~ConfigController() { @@ -140,7 +162,7 @@ bool ConfigController::parseArguments(int argc, char* argv[]) { if (m_parsed) { return false; } - mSubParserGraphicsInit(&m_subparsers[0], &m_graphicsOpts); + if (mArgumentsParse(&m_args, argc, argv, m_subparsers.data(), m_subparsers.size())) { mCoreConfigFreeOpts(&m_opts); mArgumentsApply(&m_args, m_subparsers.data(), m_subparsers.size(), &m_config); @@ -312,6 +334,10 @@ void ConfigController::usage(const char* arg0) const { ::usage(arg0, nullptr, nullptr, m_subparsers.data(), m_subparsers.size()); } +QStringList ConfigController::takeECardList() { + return QStringList(std::move(m_eCards)); +} + bool ConfigController::isPortable() { return mCoreConfigIsPortable(); } diff --git a/src/platform/qt/ConfigController.h b/src/platform/qt/ConfigController.h index 74afea99b..13a638f59 100644 --- a/src/platform/qt/ConfigController.h +++ b/src/platform/qt/ConfigController.h @@ -96,6 +96,8 @@ public: const mGraphicsOpts* graphicsOpts() const { return &m_graphicsOpts; } void usage(const char* arg0) const; + QStringList takeECardList(); + static const QString& configDir(); static bool isPortable(); @@ -117,8 +119,9 @@ private: mCoreOptions m_opts{}; mArguments m_args{}; mGraphicsOpts m_graphicsOpts{}; - std::array m_subparsers; + std::array m_subparsers; bool m_parsed = false; + QStringList m_eCards; QHash m_optionSet; std::unique_ptr m_settings; diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 94043d680..f4ff03d16 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -897,8 +897,31 @@ void CoreController::scanCard(const QString& path) { QImage image(path); if (image.isNull()) { QFile file(path); - file.open(QIODevice::ReadOnly); + if (!file.open(QIODevice::ReadOnly)) { + return; + } m_eReaderData = file.read(2912); + + file.seek(0); + QStringList lines; + QDir basedir(QFileInfo(path).dir()); + + while (true) { + QByteArray line = file.readLine().trimmed(); + if (line.isEmpty()) { + break; + } + QString filepath(QString::fromUtf8(line)); + if (filepath[0] == QChar('#')) { + continue; + } + if (QFileInfo(filepath).isRelative()) { + lines.append(basedir.filePath(filepath)); + } else { + lines.append(filepath); + } + } + scanCards(lines); } else if (image.size() == QSize(989, 44) || image.size() == QSize(639, 44)) { const uchar* bits = image.constBits(); size_t size; @@ -917,6 +940,11 @@ void CoreController::scanCard(const QString& path) { #endif } +void CoreController::scanCards(const QStringList& paths) { + for (const QString& path : paths) { + scanCard(path); + } +} void CoreController::importSharkport(const QString& path) { #ifdef M_CORE_GBA diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index ead578003..1dd61fec9 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -159,6 +159,7 @@ public slots: void loadSave(VFile*, bool temporary); void loadPatch(const QString&); void scanCard(const QString&); + void scanCards(const QStringList&); void replaceGame(const QString&); void yankPak(); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 3edac41c2..cfcb93599 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -925,8 +925,16 @@ void Window::gameStarted() { action->setActive(true); } } + interrupter.resume(); + m_actions.rebuildMenu(menuBar(), this, *m_shortcutController); +#ifdef M_CORE_GBA + if (m_controller->platform() == mPLATFORM_GBA) { + m_controller->scanCards(m_config->takeECardList()); + } +#endif + #ifdef USE_DISCORD_RPC DiscordCoordinator::gameStarted(m_controller); #endif