diff --git a/src/commandlineutility.cpp b/src/commandlineutility.cpp index d9c5c2a8d..bf5874728 100644 --- a/src/commandlineutility.cpp +++ b/src/commandlineutility.cpp @@ -22,11 +22,12 @@ #include "eventhandlerfactory.h" #include "messagehandler.h" -#include #include #include #include +#include + QStringList CommandLineUtility::eventGeneratorsList = EventHandlerFactory::buildEventGeneratorList(); CommandLineUtility::CommandLineUtility(QObject *parent) @@ -38,7 +39,6 @@ CommandLineUtility::CommandLineUtility(QObject *parent) hideTrayIcon = false; profileLocation = ""; controllerNumber = 0; - encounteredError = false; hiddenRequest = false; unloadProfile = false; startSetNumber = 0; @@ -55,23 +55,84 @@ CommandLineUtility::CommandLineUtility(QObject *parent) eventGenerator = EventHandlerFactory::fallBackIdentifier(); } -void CommandLineUtility::parseArguments(QCommandLineParser *parser) +void CommandLineUtility::parseArguments(const QApplication &parsed_app) { + QCommandLineParser parser; + parser.setApplicationDescription( + QCoreApplication::translate("antimicrox", "Graphical program used to map keyboard buttons and mouse controls to " + "a " + "gamepad. Useful for playing games with no gamepad support.")); + parser.addHelpOption(); + parser.addVersionOption(); + + parser.addOptions({ + // A boolean option with a single name (-p) + {"tray", QCoreApplication::translate("main", "Launch program in system tray only.")}, + // A boolean option with multiple names (-f, --force) + {"no-tray", QCoreApplication::translate("main", "Launch program with the tray menu disabled")}, + // An option with a value + {"hidden", QCoreApplication::translate("main", "Launch program without the main window displayed")}, + {"profile", + QCoreApplication::translate("main", "Launch program with the configuration file selected as " + "the default for " + "selected controllers. Defaults to all controllers"), + QCoreApplication::translate("main", "location")}, + {"profile-controller", + QCoreApplication::translate("main", "Apply configuration file to a specific controller. Value " + "can be a controller index, name, or GUID"), + QCoreApplication::translate("main", "value")}, + {"unload", QCoreApplication::translate("main", "Unload currently enabled profile(s)"), + QCoreApplication::translate("main", "value(s)")}, + {"startSet", + QCoreApplication::translate("main", "Start joysticks on a specific set. Value can be a " + "controller index, name, or GUID"), + QCoreApplication::translate("main", "number value")}, + {{"daemon", "d"}, QCoreApplication::translate("main", "Launch program as a daemon. Use only on Linux.")}, + {"log-level", QCoreApplication::translate("main", "Enable logging. Levels (from the least strict): warn,info,debug"), + QCoreApplication::translate("main", "log-type")}, + {"log-file", QCoreApplication::translate("main", "Choose a file for logs writing"), + QCoreApplication::translate("main", "filename")}, + {"eventgen", + QCoreApplication::translate("main", "Choose between using XTest support and uinput support " + "for event generation. Use only if you have " + "enabled xtest and uinput options on Linux or vmulti on " + "Windows. Default: xtest."), + QCoreApplication::translate("main", "event-generation-type"), "xtest"}, // default + {{"list", "l"}, + QCoreApplication::translate("main", "Print information about joysticks detected by SDL. Use " + "only if you have sdl " + "library. You can check your controller index, name or " + "even GUID.")}, + // {"display", + // QCoreApplication::translate("main", "Use specified display for + // X11 calls")}, + // {"next", + // QCoreApplication::translate("main", "Advance profile loading set + // options")}, + // {"map", + // QCoreApplication::translate("main", "Open game controller + // mapping window of selected controller. Value can be + // a controller index or GUID."), + // QCoreApplication::translate("main", "value")}, + }); + + parser.process(parsed_app); + qInstallMessageHandler(MessageHandler::myMessageOutput); int i = 0; - while ((i < parser->optionNames().count()) && !encounteredError) + while ((i < parser.optionNames().count())) { - if (parser->isSet("tray")) + if (parser.isSet("tray")) { qDebug() << "tray is set"; launchInTray = true; hideTrayIcon = false; - } else if (parser->isSet("no-tray")) + } else if (parser.isSet("no-tray")) { qDebug() << "no-tray is set"; @@ -80,88 +141,88 @@ void CommandLineUtility::parseArguments(QCommandLineParser *parser) launchInTray = false; } - if (parser->isSet("profile")) + if (parser.isSet("profile")) { parseArgsProfile(parser); } - if (parser->isSet("profile-controller")) + if (parser.isSet("profile-controller")) { parseArgsPrControle(parser); } - if (parser->isSet("hidden")) + if (parser.isSet("hidden")) { hiddenRequest = true; } - if (parser->isSet("unload")) + if (parser.isSet("unload")) { parseArgsUnload(parser); } - if (parser->isSet("startSet")) + if (parser.isSet("startSet")) { parseArgsStartSet(parser); } - if (parser->isSet("next")) + if (parser.isSet("next")) { currentListsIndex++; ControllerOptionsInfo tempInfo; controllerOptionsList.append(tempInfo); } - if (parser->isSet("list")) + if (parser.isSet("list")) { listControllers = true; } - if (parser->isSet("map")) + if (parser.isSet("map")) { parseArgsMap(parser); } - if (parser->isSet("daemon")) + if (parser.isSet("daemon")) { daemonMode = true; } #ifdef WITH_X11 - if (parser->isSet("display")) + if (parser.isSet("display")) { - if (!parser->value("display").isEmpty()) + if (!parser.value("display").isEmpty()) { - displayString = parser->value("display"); + displayString = parser.value("display"); } else { - setErrorMessage(QObject::tr("No display string was specified.")); + throw std::runtime_error(QObject::tr("No display string was specified.").toStdString()); } } #endif #if (defined(WITH_UINPUT) && defined(WITH_XTEST)) - if (parser->isSet("eventgen")) + if (parser.isSet("eventgen")) { - QString eventGenText = parser->value("eventgen"); + QString eventGenText = parser.value("eventgen"); if (!eventGenText.isEmpty() && !eventGeneratorsList.contains(eventGenText)) { eventGenerator = ""; - setErrorMessage(QObject::tr("An invalid event generator was specified.")); + throw std::runtime_error(QObject::tr("An invalid event generator was specified.").toStdString()); } else if (!eventGenText.isEmpty() && eventGeneratorsList.contains(eventGenText)) { eventGenerator = eventGenText; } else { - setErrorMessage(QObject::tr("No event generator string was specified.")); + throw std::runtime_error(QObject::tr("No event generator string was specified.").toStdString()); } } #endif - if (parser->isSet("log-level")) + if (parser.isSet("log-level")) { - QString logLevelText = parser->value("log-level"); + QString logLevelText = parser.value("log-level"); if (logLevelText == "debug") currentLogLevel = Logger::LOG_DEBUG; @@ -171,16 +232,20 @@ void CommandLineUtility::parseArguments(QCommandLineParser *parser) currentLogLevel = Logger::LOG_WARNING; else if (logLevelText == "error") currentLogLevel = Logger::LOG_ERROR; + else + { + throw std::runtime_error((QObject::tr("Unknown log level: ") + logLevelText).toStdString()); + } } - if (parser->isSet("log-file")) + if (parser.isSet("log-file")) { - if (!parser->value("log-file").isEmpty()) + if (!parser.value("log-file").isEmpty()) { - currentLogFile = parser->value("log-file"); + currentLogFile = parser.value("log-file"); } else { - setErrorMessage(QObject::tr("No log file specified.")); + throw std::runtime_error(QObject::tr("No log file specified.").toStdString()); } } @@ -188,13 +253,14 @@ void CommandLineUtility::parseArguments(QCommandLineParser *parser) } } -void CommandLineUtility::parseArgsProfile(QCommandLineParser *parser) +void CommandLineUtility::parseArgsProfile(const QCommandLineParser &parser) { - QFileInfo profileFileInfo(parser->value("profile")); + QFileInfo profileFileInfo(parser.value("profile")); if (profileFileInfo.exists() && (profileFileInfo.suffix() != "amgp") && (profileFileInfo.suffix() != "xml")) { - setErrorMessage(QObject::tr("Profile location %1 is not an XML file.").arg(parser->value("profile"))); + throw std::runtime_error( + QObject::tr("Profile location %1 is not an XML file.").arg(parser.value("profile")).toStdString()); } else if (profileFileInfo.exists() && ((profileFileInfo.suffix() == "amgp") || (profileFileInfo.suffix() == "xml"))) { QString tempProfileLocation = profileFileInfo.absoluteFilePath(); @@ -203,14 +269,15 @@ void CommandLineUtility::parseArgsProfile(QCommandLineParser *parser) controllerOptionsList.replace(currentListsIndex, tempInfo); } else { - setErrorMessage(QObject::tr("Profile location %1 does not exist.").arg(parser->value("profile"))); + throw std::runtime_error( + QObject::tr("Profile location %1 does not exist.").arg(parser.value("profile")).toStdString()); } } -void CommandLineUtility::parseArgsPrControle(QCommandLineParser *parser) +void CommandLineUtility::parseArgsPrControle(const QCommandLineParser &parser) { bool validNumber = false; - int tempNumber = parser->value("profile-controller").toInt(&validNumber); + int tempNumber = parser.value("profile-controller").toInt(&validNumber); if (validNumber) { @@ -220,28 +287,28 @@ void CommandLineUtility::parseArgsPrControle(QCommandLineParser *parser) ControllerOptionsInfo tempInfo = getControllerOptionsList().at(currentListsIndex); tempInfo.setControllerNumber(tempNumber); controllerOptionsList.replace(currentListsIndex, tempInfo); - } else if (!parser->value("profile-controller").isEmpty()) + } else if (!parser.value("profile-controller").isEmpty()) { if (controllerIDString.isEmpty()) - controllerIDString = parser->value("profile-controller"); + controllerIDString = parser.value("profile-controller"); ControllerOptionsInfo tempInfo = getControllerOptionsList().at(currentListsIndex); - tempInfo.setControllerID(parser->value("profile-controller")); + tempInfo.setControllerID(parser.value("profile-controller")); controllerOptionsList.replace(currentListsIndex, tempInfo); } else { - setErrorMessage(QObject::tr("Controller identifier is not a valid value.")); + throw std::runtime_error(QObject::tr("Controller identifier is not a valid value.").toStdString()); } } -void CommandLineUtility::parseArgsUnload(QCommandLineParser *parser) +void CommandLineUtility::parseArgsUnload(const QCommandLineParser &parser) { ControllerOptionsInfo gameControllerOptionInfo = getControllerOptionsList().at(currentListsIndex); gameControllerOptionInfo.setProfileLocation(""); gameControllerOptionInfo.setUnloadRequest(true); controllerOptionsList.replace(currentListsIndex, gameControllerOptionInfo); - QStringList parserVals = QStringList() << parser->values("unload"); + QStringList parserVals = QStringList() << parser.values("unload"); QListIterator profileForUnload(parserVals); QString unloadedProfText = QString(); @@ -269,7 +336,7 @@ void CommandLineUtility::parseArgsUnload(QCommandLineParser *parser) controllerOptionsList.replace(currentListsIndex, gameControllerOptionInfo); } else { - setErrorMessage(QObject::tr("Controller identifier is not a valid value.")); + throw std::runtime_error(QObject::tr("Controller identifier is not a valid value.").toStdString()); } } else { @@ -278,9 +345,9 @@ void CommandLineUtility::parseArgsUnload(QCommandLineParser *parser) } } -void CommandLineUtility::parseArgsStartSet(QCommandLineParser *parser) +void CommandLineUtility::parseArgsStartSet(const QCommandLineParser &parser) { - QStringList parserValues = QStringList() << parser->values("startSet"); + QStringList parserValues = QStringList() << parser.values("startSet"); QListIterator profileForStartset(parserValues); QString startSetText = QString(); @@ -299,7 +366,7 @@ void CommandLineUtility::parseArgsStartSet(QCommandLineParser *parser) controllerOptionsList.replace(currentListsIndex, tempInfo); } else if (validNumber) { - setErrorMessage(QObject::tr("An invalid set number '%1' was specified.").arg(tempNumber)); + throw std::runtime_error(QObject::tr("An invalid set number '%1' was specified.").arg(tempNumber).toStdString()); } if (profileForStartset.hasNext()) @@ -320,18 +387,19 @@ void CommandLineUtility::parseArgsStartSet(QCommandLineParser *parser) controllerOptionsList.replace(currentListsIndex, tempInfo); } else { - setErrorMessage(QObject::tr("Controller identifier '%s'' is not a valid value.").arg(startSetText)); + throw std::runtime_error( + QObject::tr("Controller identifier '%s'' is not a valid value.").arg(startSetText).toStdString()); } } } else { - setErrorMessage(QObject::tr("No set number was specified.")); + throw std::runtime_error(QObject::tr("No set number was specified.").toStdString()); } } -void CommandLineUtility::parseArgsMap(QCommandLineParser *parser) +void CommandLineUtility::parseArgsMap(const QCommandLineParser &parser) { - QString mapOptionText = parser->value("map"); + QString mapOptionText = parser.value("map"); if (!mapOptionText.isEmpty()) { @@ -349,11 +417,11 @@ void CommandLineUtility::parseArgsMap(QCommandLineParser *parser) mappingController = true; } else { - setErrorMessage(QObject::tr("Controller identifier is not a valid value.")); + throw std::runtime_error(QObject::tr("Controller identifier is not a valid value.").toStdString()); } } else { - setErrorMessage(QObject::tr("No controller was specified.")); + throw std::runtime_error(QObject::tr("No controller was specified.").toStdString()); } } @@ -399,13 +467,6 @@ int CommandLineUtility::getControllerNumber() return controllerNumber; } -bool CommandLineUtility::hasError() -{ - qInstallMessageHandler(MessageHandler::myMessageOutput); - - return encounteredError; -} - bool CommandLineUtility::isHiddenRequested() { qInstallMessageHandler(MessageHandler::myMessageOutput); @@ -498,22 +559,6 @@ QString CommandLineUtility::getCurrentLogFile() return currentLogFile; } -QString CommandLineUtility::getErrorText() -{ - - qInstallMessageHandler(MessageHandler::myMessageOutput); - - return errorText; -} - -void CommandLineUtility::setErrorMessage(QString temp) -{ - qInstallMessageHandler(MessageHandler::myMessageOutput); - - errorText = temp; - encounteredError = true; -} - QList const &CommandLineUtility::getControllerOptionsList() { qInstallMessageHandler(MessageHandler::myMessageOutput); diff --git a/src/commandlineutility.h b/src/commandlineutility.h index 755a4abfe..c1d5328f5 100644 --- a/src/commandlineutility.h +++ b/src/commandlineutility.h @@ -1,6 +1,7 @@ /* antimicrox Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * Copyright (C) 2020 Jagoda Górska + * Copyright (C) 2021 Paweł Kotiuk * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +22,8 @@ class QCommandLineParser; +#include + #include "logger.h" class ControllerOptionsInfo @@ -83,7 +86,13 @@ class CommandLineUtility : public QObject public: explicit CommandLineUtility(QObject *parent = nullptr); - void parseArguments(QCommandLineParser *parser); + /** + * @brief load and parse arguments from commandline + * + * @param parsed_app + * @exception std::runtime_error - in case of problems with parsing like unknown flag, wrong value etc + */ + void parseArguments(const QApplication &parsed_app); bool isLaunchInTrayEnabled(); bool isTrayHidden(); @@ -95,7 +104,6 @@ class CommandLineUtility : public QObject bool shouldListControllers(); bool shouldMapController(); bool hasProfileInOptions(); - bool hasError(); int getControllerNumber(); int getStartSetNumber(); @@ -105,7 +113,6 @@ class CommandLineUtility : public QObject QString getProfileLocation(); QString getEventGenerator(); QString getCurrentLogFile(); - QString getErrorText(); QList *getJoyStartSetNumberList(); QList const &getControllerOptionsList(); @@ -116,12 +123,9 @@ class CommandLineUtility : public QObject Logger::LogLevel getCurrentLogLevel(); protected: - void setErrorMessage(QString temp); - private: bool launchInTray; bool hideTrayIcon; - bool encounteredError; bool hiddenRequest; bool unloadProfile; bool daemonMode; @@ -136,7 +140,6 @@ class CommandLineUtility : public QObject QString controllerIDString; QString displayString; QString eventGenerator; - QString errorText; QString currentLogFile; Logger::LogLevel currentLogLevel; @@ -145,11 +148,11 @@ class CommandLineUtility : public QObject static QStringList eventGeneratorsList; - void parseArgsProfile(QCommandLineParser *parser); - void parseArgsPrControle(QCommandLineParser *parser); - void parseArgsUnload(QCommandLineParser *parser); - void parseArgsStartSet(QCommandLineParser *parser); - void parseArgsMap(QCommandLineParser *parser); + void parseArgsProfile(const QCommandLineParser &parser); + void parseArgsPrControle(const QCommandLineParser &parser); + void parseArgsUnload(const QCommandLineParser &parser); + void parseArgsStartSet(const QCommandLineParser &parser); + void parseArgsMap(const QCommandLineParser &parser); }; #endif // COMMANDLINEPARSER_H diff --git a/src/main.cpp b/src/main.cpp index 333fcf2ca..d721e3e62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,6 @@ #include "messagehandler.h" #include -#include #include #include #include @@ -52,6 +51,9 @@ #include #include +#include +#include + #ifdef Q_OS_UNIX #include #include @@ -184,119 +186,17 @@ int main(int argc, char *argv[]) QTextStream outstream(stdout); QTextStream errorstream(stderr); - QCommandLineParser parser; - parser.setApplicationDescription( - QCoreApplication::translate("antimicrox", "Graphical program used to map keyboard buttons and mouse controls to " - "a " - "gamepad. Useful for playing games with no gamepad support.")); - parser.addHelpOption(); - parser.addVersionOption(); - -#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) - parser.addOptions({ - // A boolean option with a single name (-p) - {"tray", QCoreApplication::translate("main", "Launch program in system tray only.")}, - // A boolean option with multiple names (-f, --force) - {"no-tray", QCoreApplication::translate("main", "Launch program with the tray menu disabled")}, - // An option with a value - {"hidden", QCoreApplication::translate("main", "Launch program without the main window displayed")}, - {"profile", - QCoreApplication::translate("main", "Launch program with the configuration file selected as " - "the default for " - "selected controllers. Defaults to all controllers"), - QCoreApplication::translate("main", "location")}, - {"profile-controller", - QCoreApplication::translate("main", "Apply configuration file to a specific controller. Value " - "can be a controller index, name, or GUID"), - QCoreApplication::translate("main", "value")}, - {"unload", QCoreApplication::translate("main", "Unload currently enabled profile(s)"), - QCoreApplication::translate("main", "value(s)")}, - {"startSet", - QCoreApplication::translate("main", "Start joysticks on a specific set. Value can be a " - "controller index, name, or GUID"), - QCoreApplication::translate("main", "number value")}, - {{"daemon", "d"}, QCoreApplication::translate("main", "Launch program as a daemon. Use only on Linux.")}, - {"log-level", QCoreApplication::translate("main", "Enable logging. Levels (from the least strict): warn,info,debug"), - QCoreApplication::translate("main", "log-type")}, - {"log-file", QCoreApplication::translate("main", "Choose a file for logs writing"), - QCoreApplication::translate("main", "filename")}, - {"eventgen", - QCoreApplication::translate("main", "Choose between using XTest support and uinput support " - "for event generation. Use only if you have " - "enabled xtest and uinput options on Linux or vmulti on " - "Windows. Default: xtest."), - QCoreApplication::translate("main", "event-generation-type"), "xtest"}, // default - {{"list", "l"}, - QCoreApplication::translate("main", "Print information about joysticks detected by SDL. Use " - "only if you have sdl " - "library. You can check your controller index, name or " - "even GUID.")}, - // {"display", - // QCoreApplication::translate("main", "Use specified display for - // X11 calls")}, - // {"next", - // QCoreApplication::translate("main", "Advance profile loading set - // options")}, - // {"map", - // QCoreApplication::translate("main", "Open game controller - // mapping window of selected controller. Value can be - // a controller index or GUID."), - // QCoreApplication::translate("main", "value")}, - }); - -#else - parser.addOption(QCommandLineOption("tray", QObject::trUtf8("Launch program in system tray only."))); - parser.addOption(QCommandLineOption("no-tray", QObject::trUtf8("Launch program with the tray menu disabled"))); - parser.addOption(QCommandLineOption("hidden", QObject::trUtf8("Launch program without the main window displayed"))); - - parser.addOption(QCommandLineOption("profile", - QObject::trUtf8("Launch program with the configuration file selected as the " - "default " - "for selected controllers. Defaults to all controllers"), - QObject::trUtf8("location"))); - - parser.addOption(QCommandLineOption("profile-controller", - QObject::trUtf8("Apply configuration file to a specific controller. " - "Value can be a controller index, name, or GUID"), - QObject::trUtf8("value"))); - - parser.addOption( - QCommandLineOption("unload", QObject::trUtf8("Unload currently enabled profile(s)"), QObject::trUtf8("value(s)"))); - - parser.addOption(QCommandLineOption("startSet", - QObject::trUtf8("Start joysticks on a specific set. Value can be a " - "controller index, name, or GUID"), - QObject::trUtf8("number value"))); - - parser.addOption(QCommandLineOption(QStringList() << "daemon" - << "d", - QObject::trUtf8("Launch program as a daemon. Use only on Linux."))); - - parser.addOption(QCommandLineOption("log-level", QObject::trUtf8("Enable logging"), QObject::trUtf8("log-type"))); - - parser.addOption( - QCommandLineOption("log-file", QObject::trUtf8("Choose a file for logs writing"), QObject::trUtf8("filename"))); - - parser.addOption(QCommandLineOption("eventgen", - QObject::trUtf8("Choose between using XTest support and uinput support " - "for event generation. Use only if you have " - "enabled xtest and uinput options on Linux or vmulti " - "on Windows. Default: xtest."), - QObject::trUtf8("event-generation-type"), "xtest")); - - parser.addOption(QCommandLineOption(QStringList() << "list" - << "l", - QObject::trUtf8("Print information about joysticks detected by SDL. " - "Use only if you have sdl " - "library. You can check your controller index, name or " - "even GUID."))); - -#endif - - parser.process(antimicrox); - CommandLineUtility cmdutility; - cmdutility.parseArguments(&parser); + + try + { + cmdutility.parseArguments(antimicrox); + } catch (const std::runtime_error &e) + { + std::cerr << e.what() << '\n'; + std::cerr << "Closing\n"; + return -1; + } Logger appLogger(&outstream, &errorstream); @@ -384,10 +284,10 @@ int main(int argc, char *argv[]) mainWindow.fillButtons(); mainWindow.alterConfigFromSettings(); - if (!cmdutility.hasError() && (cmdutility.hasProfile() || cmdutility.hasProfileInOptions())) + if (cmdutility.hasProfile() || cmdutility.hasProfileInOptions()) { mainWindow.saveAppConfig(); - } else if (!cmdutility.hasError() && cmdutility.isUnloadRequested()) + } else if (cmdutility.isUnloadRequested()) { mainWindow.saveAppConfig(); }