mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-21 05:09:46 -06:00
CLI 2.0: Electric Boogaloo (#1546)
* CLI: begin QT reimplementation * Add first batch of parameters * ROM loading (no archives yet) * --fullscreen * --boot (non-functional???) * fix --boot * archives! * Add disclaimer that a.zip|b.nds is kind of fucky * remove shit7 debugging * Apply requested changes
This commit is contained in:
135
src/frontend/qt_sdl/CLI.cpp
Normal file
135
src/frontend/qt_sdl/CLI.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS 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 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "CLI.h"
|
||||||
|
|
||||||
|
namespace CLI
|
||||||
|
{
|
||||||
|
|
||||||
|
CommandLineOptions* ManageArgs(QApplication& melon)
|
||||||
|
{
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.addHelpOption();
|
||||||
|
|
||||||
|
parser.addPositionalArgument("nds", "Nintendo DS ROM (or an archive file which contains it) to load into Slot-1");
|
||||||
|
parser.addPositionalArgument("gba", "GBA ROM (or an archive file which contains it) to load into Slot-2");
|
||||||
|
|
||||||
|
parser.addOption(QCommandLineOption({"b", "boot"}, "Whether to boot firmware on startup. Defaults to \"auto\" (boot if NDS rom given)", "auto/always/never", "auto"));
|
||||||
|
parser.addOption(QCommandLineOption({"f", "fullscreen"}, "Start melonDS in fullscreen mode"));
|
||||||
|
|
||||||
|
#ifdef ARCHIVE_SUPPORT_ENABLED
|
||||||
|
parser.addOption(QCommandLineOption({"a", "archive-file"}, "Specify file to load inside an archive given (NDS)", "rom"));
|
||||||
|
parser.addOption(QCommandLineOption({"A", "archive-file-gba"}, "Specify file to load inside an archive given (GBA)", "rom"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
parser.process(melon);
|
||||||
|
|
||||||
|
CommandLineOptions* options = new CommandLineOptions;
|
||||||
|
|
||||||
|
options->fullscreen = parser.isSet("fullscreen");
|
||||||
|
|
||||||
|
QStringList posargs = parser.positionalArguments();
|
||||||
|
switch (posargs.size())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
printf("Too many positional arguments; ignoring 3 onwards\n");
|
||||||
|
case 2:
|
||||||
|
options->gbaRomPath = QStringList(posargs[1]);
|
||||||
|
case 1:
|
||||||
|
options->dsRomPath = QStringList(posargs[0]);
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString bootMode = parser.value("boot");
|
||||||
|
if (bootMode == "auto")
|
||||||
|
{
|
||||||
|
options->boot = posargs.size() > 0;
|
||||||
|
}
|
||||||
|
else if (bootMode == "always")
|
||||||
|
{
|
||||||
|
options->boot = true;
|
||||||
|
}
|
||||||
|
else if (bootMode == "never")
|
||||||
|
{
|
||||||
|
options->boot = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: -b/--boot only accepts auto/always/never as arguments\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARCHIVE_SUPPORT_ENABLED
|
||||||
|
if (parser.isSet("archive-file"))
|
||||||
|
{
|
||||||
|
if (options->dsRomPath.isEmpty())
|
||||||
|
{
|
||||||
|
options->errorsToDisplay += "Option -a/--archive-file given, but no archive specified!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
options->dsRomPath += parser.value("archive-file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!options->dsRomPath.isEmpty())
|
||||||
|
{
|
||||||
|
//TODO-CLI: try to automatically find ROM
|
||||||
|
QStringList paths = options->dsRomPath[0].split("|");
|
||||||
|
if (paths.size() >= 2)
|
||||||
|
{
|
||||||
|
printf("Warning: use the a.zip|b.nds format at your own risk!\n");
|
||||||
|
options->dsRomPath = paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.isSet("archive-file-gba"))
|
||||||
|
{
|
||||||
|
if (options->gbaRomPath.isEmpty())
|
||||||
|
{
|
||||||
|
options->errorsToDisplay += "Option -A/--archive-file-gba given, but no archive specified!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
options->gbaRomPath += parser.value("archive-file-gba");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!options->gbaRomPath.isEmpty())
|
||||||
|
{
|
||||||
|
//TODO-CLI: try to automatically find ROM
|
||||||
|
QStringList paths = options->gbaRomPath[0].split("|");
|
||||||
|
if (paths.size() >= 2)
|
||||||
|
{
|
||||||
|
printf("Warning: use the a.zip|b.gba format at your own risk!\n");
|
||||||
|
options->gbaRomPath = paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
src/frontend/qt_sdl/CLI.h
Normal file
41
src/frontend/qt_sdl/CLI.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021-2022 melonDS team
|
||||||
|
|
||||||
|
This file is part of melonDS.
|
||||||
|
|
||||||
|
melonDS 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 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLI_H
|
||||||
|
#define CLI_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace CLI {
|
||||||
|
|
||||||
|
struct CommandLineOptions
|
||||||
|
{
|
||||||
|
QStringList errorsToDisplay = {};
|
||||||
|
|
||||||
|
QStringList dsRomPath;
|
||||||
|
QStringList gbaRomPath;
|
||||||
|
bool fullscreen;
|
||||||
|
bool boot;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CommandLineOptions* ManageArgs(QApplication& melon);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -49,6 +49,9 @@ set(SOURCES_QT_SDL
|
|||||||
../duckstation/gl/context.cpp
|
../duckstation/gl/context.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
||||||
|
|
||||||
|
CLI.h
|
||||||
|
CLI.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -503,6 +503,7 @@ bool LoadROM(QStringList filepath, bool reset)
|
|||||||
if (len > 0x40000000)
|
if (len > 0x40000000)
|
||||||
{
|
{
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
delete[] filedata;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +529,7 @@ bool LoadROM(QStringList filepath, bool reset)
|
|||||||
{
|
{
|
||||||
// file inside archive
|
// file inside archive
|
||||||
|
|
||||||
u32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
|
s32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
|
||||||
if (lenread < 0) return false;
|
if (lenread < 0) return false;
|
||||||
if (!filedata) return false;
|
if (!filedata) return false;
|
||||||
if (lenread != filelen)
|
if (lenread != filelen)
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QCommandLineParser>
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
@ -94,6 +95,8 @@
|
|||||||
#include "ArchiveUtil.h"
|
#include "ArchiveUtil.h"
|
||||||
#include "CameraManager.h"
|
#include "CameraManager.h"
|
||||||
|
|
||||||
|
#include "CLI.h"
|
||||||
|
|
||||||
// TODO: uniform variable spelling
|
// TODO: uniform variable spelling
|
||||||
|
|
||||||
bool RunningSomething;
|
bool RunningSomething;
|
||||||
@ -2126,7 +2129,7 @@ bool MainWindow::verifySetup()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::preloadROMs(QString filename, QString gbafilename)
|
bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot)
|
||||||
{
|
{
|
||||||
if (!verifySetup())
|
if (!verifySetup())
|
||||||
{
|
{
|
||||||
@ -2134,9 +2137,8 @@ bool MainWindow::preloadROMs(QString filename, QString gbafilename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool gbaloaded = false;
|
bool gbaloaded = false;
|
||||||
if (!gbafilename.isEmpty())
|
if (!gbafile.isEmpty())
|
||||||
{
|
{
|
||||||
QStringList gbafile = gbafilename.split('|');
|
|
||||||
if (!ROMManager::LoadGBAROM(gbafile))
|
if (!ROMManager::LoadGBAROM(gbafile))
|
||||||
{
|
{
|
||||||
// TODO: better error reporting?
|
// TODO: better error reporting?
|
||||||
@ -2147,20 +2149,33 @@ bool MainWindow::preloadROMs(QString filename, QString gbafilename)
|
|||||||
gbaloaded = true;
|
gbaloaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList file = filename.split('|');
|
bool ndsloaded = false;
|
||||||
|
if (!file.isEmpty())
|
||||||
|
{
|
||||||
if (!ROMManager::LoadROM(file, true))
|
if (!ROMManager::LoadROM(file, true))
|
||||||
{
|
{
|
||||||
// TODO: better error reporting?
|
// TODO: better error reporting?
|
||||||
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
recentFileList.removeAll(file.join("|"));
|
||||||
recentFileList.removeAll(filename);
|
recentFileList.prepend(file.join("|"));
|
||||||
recentFileList.prepend(filename);
|
|
||||||
updateRecentFilesMenu();
|
updateRecentFilesMenu();
|
||||||
|
ndsloaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot)
|
||||||
|
{
|
||||||
|
if (ndsloaded)
|
||||||
|
{
|
||||||
NDS::Start();
|
NDS::Start();
|
||||||
emuThread->emuRun();
|
emuThread->emuRun();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onBootFirmware();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateCartInserted(false);
|
updateCartInserted(false);
|
||||||
|
|
||||||
@ -3115,8 +3130,7 @@ void MainWindow::onTitleUpdate(QString title)
|
|||||||
setWindowTitle(title);
|
setWindowTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onFullscreenToggled()
|
void ToggleFullscreen(MainWindow* mainWindow) {
|
||||||
{
|
|
||||||
if (!mainWindow->isFullScreen())
|
if (!mainWindow->isFullScreen())
|
||||||
{
|
{
|
||||||
mainWindow->showFullScreen();
|
mainWindow->showFullScreen();
|
||||||
@ -3130,6 +3144,11 @@ void MainWindow::onFullscreenToggled()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onFullscreenToggled()
|
||||||
|
{
|
||||||
|
ToggleFullscreen(this);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onEmuStart()
|
void MainWindow::onEmuStart()
|
||||||
{
|
{
|
||||||
for (int i = 1; i < 9; i++)
|
for (int i = 1; i < 9; i++)
|
||||||
@ -3217,7 +3236,7 @@ bool MelonApplication::event(QEvent *event)
|
|||||||
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent*>(event);
|
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent*>(event);
|
||||||
|
|
||||||
emuThread->emuPause();
|
emuThread->emuPause();
|
||||||
if (!mainWindow->preloadROMs(openEvent->file(), ""))
|
if (!mainWindow->preloadROMs(openEvent->file().split("|"), {}, true))
|
||||||
emuThread->emuUnpause();
|
emuThread->emuUnpause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3233,10 +3252,16 @@ int main(int argc, char** argv)
|
|||||||
printf("melonDS " MELONDS_VERSION "\n");
|
printf("melonDS " MELONDS_VERSION "\n");
|
||||||
printf(MELONDS_URL "\n");
|
printf(MELONDS_URL "\n");
|
||||||
|
|
||||||
|
// easter egg - not worth checking other cases for something so dumb
|
||||||
|
if (argc != 0 && (!strcasecmp(argv[0], "derpDS") || !strcasecmp(argv[0], "./derpDS")))
|
||||||
|
printf("did you just call me a derp???\n");
|
||||||
|
|
||||||
Platform::Init(argc, argv);
|
Platform::Init(argc, argv);
|
||||||
|
|
||||||
MelonApplication melon(argc, argv);
|
MelonApplication melon(argc, argv);
|
||||||
|
|
||||||
|
CLI::CommandLineOptions* options = CLI::ManageArgs(melon);
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
|
// http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||||
|
|
||||||
@ -3339,6 +3364,8 @@ int main(int argc, char** argv)
|
|||||||
Input::OpenJoystick();
|
Input::OpenJoystick();
|
||||||
|
|
||||||
mainWindow = new MainWindow();
|
mainWindow = new MainWindow();
|
||||||
|
if (options->fullscreen)
|
||||||
|
ToggleFullscreen(mainWindow);
|
||||||
|
|
||||||
emuThread = new EmuThread();
|
emuThread = new EmuThread();
|
||||||
emuThread->start();
|
emuThread->start();
|
||||||
@ -3348,14 +3375,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged);
|
QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged);
|
||||||
|
|
||||||
if (argc > 1)
|
mainWindow->preloadROMs(options->dsRomPath, options->gbaRomPath, options->boot);
|
||||||
{
|
|
||||||
QString file = argv[1];
|
|
||||||
QString gbafile = "";
|
|
||||||
if (argc > 2) gbafile = argv[2];
|
|
||||||
|
|
||||||
mainWindow->preloadROMs(file, gbafile);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = melon.exec();
|
int ret = melon.exec();
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ public:
|
|||||||
bool hasOGL;
|
bool hasOGL;
|
||||||
GL::Context* getOGLContext();
|
GL::Context* getOGLContext();
|
||||||
|
|
||||||
bool preloadROMs(QString filename, QString gbafilename);
|
bool preloadROMs(QStringList file, QStringList gbafile, bool boot);
|
||||||
|
|
||||||
void onAppStateChanged(Qt::ApplicationState state);
|
void onAppStateChanged(Qt::ApplicationState state);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user