diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index 8cb5fcf..ffa12c1 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -14,7 +14,8 @@ SOURCES += src/main.cpp\ src/tabcontrollers/audiomanager/AudioManagerDummy.cpp \ src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp \ src/openvr/openvr_init.cpp \ - src/openvr/ivrinput.cpp + src/openvr/ivrinput.cpp \ + src/utils/setup.cpp HEADERS += src/overlaycontroller.h \ src/tabcontrollers/AudioTabController.h \ diff --git a/src/utils/setup.cpp b/src/utils/setup.cpp new file mode 100644 index 0000000..5fd879d --- /dev/null +++ b/src/utils/setup.cpp @@ -0,0 +1,299 @@ +#include "setup.h" + +// The default Qt message handler prints to stdout on X11 and to the debugger on +// Windows. That is borderline useless for us, therefore we create our own +// message handler. +void mainQtMessageHandler( QtMsgType type, + const QMessageLogContext& context, + const QString& msg ) +{ + QByteArray localMsg = msg.toLocal8Bit(); + switch ( type ) + { + case QtDebugMsg: + LOG( DEBUG ) << localMsg.constData() << " (" << context.file << ":" + << context.line << ")"; + break; + case QtInfoMsg: + LOG( INFO ) << localMsg.constData() << " (" << context.file << ":" + << context.line << ")"; + break; + case QtWarningMsg: + LOG( WARNING ) << localMsg.constData() << " (" << context.file << ":" + << context.line << ")"; + break; + case QtCriticalMsg: + LOG( ERROR ) << localMsg.constData() << " (" << context.file << ":" + << context.line << ")"; + break; + case QtFatalMsg: + LOG( FATAL ) << localMsg.constData() << " (" << context.file << ":" + << context.line << ")"; + break; + } +} + +namespace argument +{ +CommandLineOptions returnCommandLineParser( const MyQApplication& application ) +{ + QCommandLineParser parser; + + parser.setApplicationDescription( + "Advanced Settings overlay for SteamVR." ); + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption desktopMode( k_desktopMode, k_desktopModeDescription ); + parser.addOption( desktopMode ); + + QCommandLineOption forceNoSound( k_forceNoSound, + k_forceNoSoundDescription ); + parser.addOption( forceNoSound ); + + QCommandLineOption forceNoManifest( k_forceNoManifest, + k_forceNoManifestDescription ); + parser.addOption( forceNoManifest ); + + QCommandLineOption forceInstallManifest( + k_forceInstallManifest, k_forceInstallManifestDescription ); + parser.addOption( forceInstallManifest ); + + QCommandLineOption forceRemoveManifest( k_forceRemoveManifest, + k_forceRemoveManifestDescription ); + parser.addOption( forceRemoveManifest ); + + parser.process( application ); + + const bool desktopModeEnabled = parser.isSet( desktopMode ); + LOG_IF( desktopModeEnabled, INFO ) << "Desktop mode enabled."; + + const bool forceNoSoundEnabled = parser.isSet( forceNoSound ); + LOG_IF( forceNoSoundEnabled, INFO ) << "Sound effects disabled."; + + const bool forceNoManifestEnabled = parser.isSet( forceNoManifest ); + LOG_IF( forceNoManifestEnabled, INFO ) + << "Running without applications manifest."; + + const bool forceInstallManifestEnabled + = parser.isSet( forceInstallManifest ); + LOG_IF( forceInstallManifestEnabled, INFO ) + << "Forcing install of applications manifest."; + + const bool forceRemoveManifestEnabled = parser.isSet( forceRemoveManifest ); + LOG_IF( forceRemoveManifestEnabled, INFO ) + << "Forcing removal of applications manifest."; + + const CommandLineOptions commandLineArgs{ desktopModeEnabled, + forceNoSoundEnabled, + forceNoManifestEnabled, + forceInstallManifestEnabled, + forceRemoveManifestEnabled }; + + LOG( INFO ) << "Command line arguments processed."; + + return commandLineArgs; +} +} // namespace argument + +namespace manifest +{ +// Enables autostart of OpenVR Advanced Settings. +void enableApplicationAutostart() +{ + const auto app_error = vr::VRApplications()->SetApplicationAutoLaunch( + advsettings::OverlayController::applicationKey, true ); + if ( app_error != vr::VRApplicationError_None ) + { + throw std::runtime_error( + std::string( "Could not set auto start: " ) + + std::string( + vr::VRApplications()->GetApplicationsErrorNameFromEnum( + app_error ) ) ); + } +} + +// Installs the application manifest. If a manifest with the same application +// key is already installed, nothing will happen. +// OpenVR must be initialized before calling this function. +void installApplicationManifest( const QString manifestPath ) +{ + if ( vr::VRApplications()->IsApplicationInstalled( + advsettings::OverlayController::applicationKey ) ) + { + // We don't want to disrupt applications that are already installed. + return; + } + + const auto app_error = vr::VRApplications()->AddApplicationManifest( + QDir::toNativeSeparators( manifestPath ).toStdString().c_str() ); + if ( app_error != vr::VRApplicationError_None ) + { + throw std::runtime_error( + std::string( "Could not add application manifest: " ) + + std::string( + vr::VRApplications()->GetApplicationsErrorNameFromEnum( + app_error ) ) ); + } +} + +// Removes the application manifest. +void removeApplicationManifest( const QString manifestPath ) +{ + if ( !QFile::exists( manifestPath ) ) + { + throw std::runtime_error( + std::string( "Could not find application manifest: " ) + + manifestPath.toStdString() ); + } + + if ( vr::VRApplications()->IsApplicationInstalled( + advsettings::OverlayController::applicationKey ) ) + { + vr::VRApplications()->RemoveApplicationManifest( + QDir::toNativeSeparators( manifestPath ).toStdString().c_str() ); + } +} + +// Removes and then installs the application manifest. +void reinstallApplicationManifest( const QString manifestPath ) +{ + if ( !QFile::exists( manifestPath ) ) + { + throw std::runtime_error( + std::string( "Could not find application manifest: " ) + + manifestPath.toStdString() ); + } + + if ( vr::VRApplications()->IsApplicationInstalled( + advsettings::OverlayController::applicationKey ) ) + { + // String size was arbitrarily chosen by original author. + constexpr auto kStringSize = 1024; + char oldApplicationWorkingDir[kStringSize] = { 0 }; + auto app_error = vr::VRApplicationError_None; + vr::VRApplications()->GetApplicationPropertyString( + advsettings::OverlayController::applicationKey, + vr::VRApplicationProperty_WorkingDirectory_String, + oldApplicationWorkingDir, + kStringSize, + &app_error ); + + if ( app_error != vr::VRApplicationError_None ) + { + throw std::runtime_error( + "Could not find working directory of already " + "installed application: " + + std::string( + vr::VRApplications()->GetApplicationsErrorNameFromEnum( + app_error ) ) ); + } + + const auto oldManifestPath + = QDir::cleanPath( QDir( oldApplicationWorkingDir ) + .absoluteFilePath( kVRManifestName ) ); + + removeApplicationManifest( manifestPath ); + } + + installApplicationManifest( manifestPath ); +} + +// Initializes OpenVR and calls the relevant manifest functions. +// The .vrmanifest is used by SteamVR however the exact functiontionality is not +// documented in the official documentation. +// The manifest is installed upon using the NSIS installer for windows (this +// program is called with "--force-install-manifest" by the installer) and every +// time the program is launched without both "--desktop-mode" and +// "--force-no-manifest". The OpenVR initialization is necessary for both +// removing and installing manifests. +[[noreturn]] void handleManifests( const bool installManifest, + const bool removeManifest ) +{ + openvr_init::initializeOpenVR( + openvr_init::OpenVrInitializationType::Utility ); + + int exit_code = ReturnErrorCode::SUCCESS; + try + { + const auto manifestPath + = QDir::cleanPath( QDir( QCoreApplication::applicationDirPath() ) + .absoluteFilePath( kVRManifestName ) ); + + if ( installManifest ) + { + reinstallApplicationManifest( manifestPath ); + enableApplicationAutostart(); + LOG( INFO ) << "Manifest reinstalled."; + } + else if ( removeManifest ) + { + removeApplicationManifest( manifestPath ); + LOG( INFO ) << "Manifest removed."; + } + } + catch ( std::exception& e ) + { + exit_code = ReturnErrorCode::GENERAL_FAILURE; + LOG( ERROR ) << e.what(); + } + + vr::VR_Shutdown(); + exit( exit_code ); +} +} // namespace manifest + +void setUpLogging() +{ + el::Loggers::addFlag( el::LoggingFlag::DisableApplicationAbortOnFatalLog ); + + el::Configurations conf; + conf.setToDefault(); + + using el::ConfigurationType; + using el::Level; + + conf.set( Level::Global, + ConfigurationType::Format, + "[%level] %datetime{%Y-%M-%d %H:%m:%s}: %msg" ); + conf.set( + Level::Global, ConfigurationType::Filename, "AdvancedSettings.log" ); + + constexpr auto confEnabled = "true"; + conf.set( Level::Global, ConfigurationType::Enabled, confEnabled ); + conf.set( Level::Global, ConfigurationType::ToFile, confEnabled ); + conf.set( Level::Global, ConfigurationType::ToStandardOutput, confEnabled ); + + constexpr auto TwoMegabytesInBytes = "2097152"; + conf.set( + Level::Global, ConfigurationType::MaxLogFileSize, TwoMegabytesInBytes ); + + constexpr auto confDisabled = "false"; + conf.set( Level::Trace, ConfigurationType::Enabled, confDisabled ); + conf.set( Level::Debug, ConfigurationType::Enabled, confDisabled ); + + // This places the log file in + // Roaming/AppData/matzman666/OpenVRAdvancedSettings/AdvancedSettings.log. + // The log file placement has been broken since at least git tag "v2.7". + // It was being placed in the working dir of the executable. + // The change hasn't been documented anywhere, so it is likely that it was + // unintentional. This fixes the probable regression until a new path is + // decided on. + constexpr auto appDataFolders = "/matzman666/OpenVRAdvancedSettings"; + const QString logFilePath = QDir( QStandardPaths::writableLocation( + QStandardPaths::AppDataLocation ) + + appDataFolders ) + .absoluteFilePath( "AdvancedSettings.log" ); + conf.set( el::Level::Global, + el::ConfigurationType::Filename, + QDir::toNativeSeparators( logFilePath ).toStdString() ); + + conf.setRemainingToDefault(); + + el::Loggers::reconfigureAllLoggers( conf ); + + LOG( INFO ) << "Application started (Version " + << advsettings::OverlayController::applicationVersionString + << ")"; + LOG( INFO ) << "Log File: " << logFilePath; +} diff --git a/src/utils/setup.h b/src/utils/setup.h index 99b518b..451fdc4 100644 --- a/src/utils/setup.h +++ b/src/utils/setup.h @@ -61,38 +61,9 @@ public: } }; -// The default Qt message handler prints to stdout on X11 and to the debugger on -// Windows. That is borderline useless for us, therefore we create our own -// message handler. void mainQtMessageHandler( QtMsgType type, const QMessageLogContext& context, - const QString& msg ) -{ - QByteArray localMsg = msg.toLocal8Bit(); - switch ( type ) - { - case QtDebugMsg: - LOG( DEBUG ) << localMsg.constData() << " (" << context.file << ":" - << context.line << ")"; - break; - case QtInfoMsg: - LOG( INFO ) << localMsg.constData() << " (" << context.file << ":" - << context.line << ")"; - break; - case QtWarningMsg: - LOG( WARNING ) << localMsg.constData() << " (" << context.file << ":" - << context.line << ")"; - break; - case QtCriticalMsg: - LOG( ERROR ) << localMsg.constData() << " (" << context.file << ":" - << context.line << ")"; - break; - case QtFatalMsg: - LOG( FATAL ) << localMsg.constData() << " (" << context.file << ":" - << context.line << ")"; - break; - } -} + const QString& msg ); namespace argument { @@ -117,65 +88,8 @@ constexpr auto k_forceRemoveManifest = "force-remove-manifest"; constexpr auto k_forceRemoveManifestDescription = "Forces removing the applications manifest. Application will exit early."; -CommandLineOptions returnCommandLineParser( const MyQApplication& application ) -{ - QCommandLineParser parser; +CommandLineOptions returnCommandLineParser( const MyQApplication& application ); - parser.setApplicationDescription( - "Advanced Settings overlay for SteamVR." ); - parser.addHelpOption(); - parser.addVersionOption(); - - QCommandLineOption desktopMode( k_desktopMode, k_desktopModeDescription ); - parser.addOption( desktopMode ); - - QCommandLineOption forceNoSound( k_forceNoSound, - k_forceNoSoundDescription ); - parser.addOption( forceNoSound ); - - QCommandLineOption forceNoManifest( k_forceNoManifest, - k_forceNoManifestDescription ); - parser.addOption( forceNoManifest ); - - QCommandLineOption forceInstallManifest( - k_forceInstallManifest, k_forceInstallManifestDescription ); - parser.addOption( forceInstallManifest ); - - QCommandLineOption forceRemoveManifest( k_forceRemoveManifest, - k_forceRemoveManifestDescription ); - parser.addOption( forceRemoveManifest ); - - parser.process( application ); - - const bool desktopModeEnabled = parser.isSet( desktopMode ); - LOG_IF( desktopModeEnabled, INFO ) << "Desktop mode enabled."; - - const bool forceNoSoundEnabled = parser.isSet( forceNoSound ); - LOG_IF( forceNoSoundEnabled, INFO ) << "Sound effects disabled."; - - const bool forceNoManifestEnabled = parser.isSet( forceNoManifest ); - LOG_IF( forceNoManifestEnabled, INFO ) - << "Running without applications manifest."; - - const bool forceInstallManifestEnabled - = parser.isSet( forceInstallManifest ); - LOG_IF( forceInstallManifestEnabled, INFO ) - << "Forcing install of applications manifest."; - - const bool forceRemoveManifestEnabled = parser.isSet( forceRemoveManifest ); - LOG_IF( forceRemoveManifestEnabled, INFO ) - << "Forcing removal of applications manifest."; - - const CommandLineOptions commandLineArgs{ desktopModeEnabled, - forceNoSoundEnabled, - forceNoManifestEnabled, - forceInstallManifestEnabled, - forceRemoveManifestEnabled }; - - LOG( INFO ) << "Command line arguments processed."; - - return commandLineArgs; -} } // namespace argument namespace manifest @@ -183,202 +97,13 @@ namespace manifest // File name of the manifest. Is placed in the same directory as the binary. constexpr auto kVRManifestName = "manifest.vrmanifest"; -// Enables autostart of OpenVR Advanced Settings. -void enableApplicationAutostart() -{ - const auto app_error = vr::VRApplications()->SetApplicationAutoLaunch( - advsettings::OverlayController::applicationKey, true ); - if ( app_error != vr::VRApplicationError_None ) - { - throw std::runtime_error( - std::string( "Could not set auto start: " ) - + std::string( - vr::VRApplications()->GetApplicationsErrorNameFromEnum( - app_error ) ) ); - } -} - -// Installs the application manifest. If a manifest with the same application -// key is already installed, nothing will happen. -// OpenVR must be initialized before calling this function. -void installApplicationManifest( const QString manifestPath ) -{ - if ( vr::VRApplications()->IsApplicationInstalled( - advsettings::OverlayController::applicationKey ) ) - { - // We don't want to disrupt applications that are already installed. - return; - } - - const auto app_error = vr::VRApplications()->AddApplicationManifest( - QDir::toNativeSeparators( manifestPath ).toStdString().c_str() ); - if ( app_error != vr::VRApplicationError_None ) - { - throw std::runtime_error( - std::string( "Could not add application manifest: " ) - + std::string( - vr::VRApplications()->GetApplicationsErrorNameFromEnum( - app_error ) ) ); - } -} - -// Removes the application manifest. -void removeApplicationManifest( const QString manifestPath ) -{ - if ( !QFile::exists( manifestPath ) ) - { - throw std::runtime_error( - std::string( "Could not find application manifest: " ) - + manifestPath.toStdString() ); - } - - if ( vr::VRApplications()->IsApplicationInstalled( - advsettings::OverlayController::applicationKey ) ) - { - vr::VRApplications()->RemoveApplicationManifest( - QDir::toNativeSeparators( manifestPath ).toStdString().c_str() ); - } -} - -// Removes and then installs the application manifest. -void reinstallApplicationManifest( const QString manifestPath ) -{ - if ( !QFile::exists( manifestPath ) ) - { - throw std::runtime_error( - std::string( "Could not find application manifest: " ) - + manifestPath.toStdString() ); - } - - if ( vr::VRApplications()->IsApplicationInstalled( - advsettings::OverlayController::applicationKey ) ) - { - // String size was arbitrarily chosen by original author. - constexpr auto kStringSize = 1024; - char oldApplicationWorkingDir[kStringSize] = { 0 }; - auto app_error = vr::VRApplicationError_None; - vr::VRApplications()->GetApplicationPropertyString( - advsettings::OverlayController::applicationKey, - vr::VRApplicationProperty_WorkingDirectory_String, - oldApplicationWorkingDir, - kStringSize, - &app_error ); - - if ( app_error != vr::VRApplicationError_None ) - { - throw std::runtime_error( - "Could not find working directory of already " - "installed application: " - + std::string( - vr::VRApplications()->GetApplicationsErrorNameFromEnum( - app_error ) ) ); - } - - const auto oldManifestPath - = QDir::cleanPath( QDir( oldApplicationWorkingDir ) - .absoluteFilePath( kVRManifestName ) ); - - removeApplicationManifest( manifestPath ); - } - - installApplicationManifest( manifestPath ); -} - -// Initializes OpenVR and calls the relevant manifest functions. -// The .vrmanifest is used by SteamVR however the exact functiontionality is not -// documented in the official documentation. -// The manifest is installed upon using the NSIS installer for windows (this -// program is called with "--force-install-manifest" by the installer) and every -// time the program is launched without both "--desktop-mode" and -// "--force-no-manifest". The OpenVR initialization is necessary for both -// removing and installing manifests. +void enableApplicationAutostart(); +void installApplicationManifest( const QString manifestPath ); +void removeApplicationManifest( const QString manifestPath ); +void reinstallApplicationManifest( const QString manifestPath ); [[noreturn]] void handleManifests( const bool installManifest, - const bool removeManifest ) -{ - openvr_init::initializeOpenVR( - openvr_init::OpenVrInitializationType::Utility ); + const bool removeManifest ); - int exit_code = ReturnErrorCode::SUCCESS; - try - { - const auto manifestPath - = QDir::cleanPath( QDir( QCoreApplication::applicationDirPath() ) - .absoluteFilePath( kVRManifestName ) ); - - if ( installManifest ) - { - reinstallApplicationManifest( manifestPath ); - enableApplicationAutostart(); - LOG( INFO ) << "Manifest reinstalled."; - } - else if ( removeManifest ) - { - removeApplicationManifest( manifestPath ); - LOG( INFO ) << "Manifest removed."; - } - } - catch ( std::exception& e ) - { - exit_code = ReturnErrorCode::GENERAL_FAILURE; - LOG( ERROR ) << e.what(); - } - - vr::VR_Shutdown(); - exit( exit_code ); -} } // namespace manifest -void setUpLogging() -{ - el::Loggers::addFlag( el::LoggingFlag::DisableApplicationAbortOnFatalLog ); - - el::Configurations conf; - conf.setToDefault(); - - using el::ConfigurationType; - using el::Level; - - conf.set( Level::Global, - ConfigurationType::Format, - "[%level] %datetime{%Y-%M-%d %H:%m:%s}: %msg" ); - conf.set( - Level::Global, ConfigurationType::Filename, "AdvancedSettings.log" ); - - constexpr auto confEnabled = "true"; - conf.set( Level::Global, ConfigurationType::Enabled, confEnabled ); - conf.set( Level::Global, ConfigurationType::ToFile, confEnabled ); - conf.set( Level::Global, ConfigurationType::ToStandardOutput, confEnabled ); - - constexpr auto TwoMegabytesInBytes = "2097152"; - conf.set( - Level::Global, ConfigurationType::MaxLogFileSize, TwoMegabytesInBytes ); - - constexpr auto confDisabled = "false"; - conf.set( Level::Trace, ConfigurationType::Enabled, confDisabled ); - conf.set( Level::Debug, ConfigurationType::Enabled, confDisabled ); - - // This places the log file in - // Roaming/AppData/matzman666/OpenVRAdvancedSettings/AdvancedSettings.log. - // The log file placement has been broken since at least git tag "v2.7". - // It was being placed in the working dir of the executable. - // The change hasn't been documented anywhere, so it is likely that it was - // unintentional. This fixes the probable regression until a new path is - // decided on. - constexpr auto appDataFolders = "/matzman666/OpenVRAdvancedSettings"; - const QString logFilePath = QDir( QStandardPaths::writableLocation( - QStandardPaths::AppDataLocation ) - + appDataFolders ) - .absoluteFilePath( "AdvancedSettings.log" ); - conf.set( el::Level::Global, - el::ConfigurationType::Filename, - QDir::toNativeSeparators( logFilePath ).toStdString() ); - - conf.setRemainingToDefault(); - - el::Loggers::reconfigureAllLoggers( conf ); - - LOG( INFO ) << "Application started (Version " - << advsettings::OverlayController::applicationVersionString - << ")"; - LOG( INFO ) << "Log File: " << logFilePath; -} +void setUpLogging();