From 7c07c0d5cfd22c79924f24d823ff9f1670002da4 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Mon, 22 Nov 2021 20:03:05 +0100 Subject: [PATCH] Added a 'winregistryvalue' find rule and a %RUNINBACKGROUND% variable. --- es-app/src/FileData.cpp | 102 +++++++++++++++++++++++++++++++------- es-app/src/SystemData.cpp | 6 ++- es-app/src/SystemData.h | 1 + 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 4d1424a57..2aaf71135 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -818,10 +818,24 @@ void FileData::launchGame(Window* window) const std::string baseName = Utils::FileSystem::getStem(getPath()); const std::string romRaw = Utils::FileSystem::getPreferredPath(getPath()); const std::string esPath = Utils::FileSystem::getExePath(); + bool runInBackground = false; -#if defined(_WIN64) - bool hideWindow = false; -#endif + // In addition to the global RunInBackground setting it's possible to define this flag + // per launch command in es_systems.xml. + size_t inBackgroundPos = command.find("%RUNINBACKGROUND%"); + + if (inBackgroundPos != std::string::npos) { + runInBackground = true; + command = Utils::String::replace(command, "%RUNINBACKGROUND%", ""); + // Trim any leading whitespaces as they could cause the script execution to fail. + command.erase(command.begin(), std::find_if(command.begin(), command.end(), [](char c) { + return !std::isspace(static_cast(c)); + })); + } + + // The global setting always applies. + if (Settings::getInstance()->getBool("RunInBackground")) + runInBackground = true; std::string coreEntry; std::string coreName; @@ -831,10 +845,14 @@ void FileData::launchGame(Window* window) std::vector emulatorCorePaths; #if defined(_WIN64) + bool hideWindow = false; + // If the %HIDEWINDOW% variable is defined, we pass a flag to launchGameWindows() to // hide the window. This is intended primarily for hiding console windows when launching // scripts (used for example by Steam games and source ports). - if (command.substr(0, 12) == "%HIDEWINDOW%") { + size_t hideWindowPos = command.find("%HIDEWINDOW%"); + + if (hideWindowPos != std::string::npos) { hideWindow = true; command = Utils::String::replace(command, "%HIDEWINDOW%", ""); // Trim any leading whitespaces as they could cause the script execution to fail. @@ -1059,10 +1077,9 @@ void FileData::launchGame(Window* window) // from the game. #if defined(_WIN64) - if (!(Settings::getInstance()->getBool("LaunchWorkaround") || - ViewController::get()->runInBackground(mSystem))) + if (!(Settings::getInstance()->getBool("LaunchWorkaround") || runInBackground)) #else - if (!ViewController::get()->runInBackground(mSystem)) + if (!runInBackground) #endif Renderer::swapBuffers(); @@ -1077,10 +1094,10 @@ void FileData::launchGame(Window* window) // Possibly keep ES-DE running in the background while the game is launched. #if defined(_WIN64) - returnValue = launchGameWindows(Utils::String::stringToWideString(command), - ViewController::get()->runInBackground(mSystem), hideWindow); + returnValue = + launchGameWindows(Utils::String::stringToWideString(command), runInBackground, hideWindow); #else - returnValue = launchGameUnix(command, ViewController::get()->runInBackground(mSystem)); + returnValue = launchGameUnix(command, runInBackground); #endif // Notify the user in case of a failed game launch using a popup window. if (returnValue != 0) { @@ -1095,10 +1112,10 @@ void FileData::launchGame(Window* window) // Stop showing the game launch notification. window->stopInfoPopup(); #if defined(_WIN64) - // For some game systems or if the "RunInBackground" setting has been enabled, keep - // ES-DE running while the game is launched. This pauses any video and keeps the - // screensaver from getting activated. - if (ViewController::get()->runInBackground(mSystem)) + // If the RunInBackground setting has been enabled or if the %RUNINBACKGROUND% variable has + // been set for the specific launch command, then block the video player, stop scrolling + // game names and descriptions and keep the screensaver from getting activated. + if (runInBackground) window->setLaunchedGame(); else // Normalize deltaTime so that the screensaver does not start immediately @@ -1106,8 +1123,9 @@ void FileData::launchGame(Window* window) window->normalizeNextUpdate(); #else // For some game systems we need to keep ES-DE running while the game is launched. - // This pauses any video and keeps the screensaver from getting activated. - if (ViewController::get()->runInBackground(mSystem)) + // This blocks the video player, stops the scrolling of game names and descriptions and + // keeps the screensaver from getting activated. + if (runInBackground) window->setLaunchedGame(); // Normalize deltaTime so that the screensaver does not start immediately // when returning from the game. @@ -1119,7 +1137,7 @@ void FileData::launchGame(Window* window) // Unless we're running in the background while the game is launched, re-enable the text // scrolling that was disabled in ViewController. - if (!ViewController::get()->runInBackground(mSystem)) + if (!runInBackground) window->setAllowTextScrolling(true); // Update number of times the game has been launched. @@ -1159,6 +1177,7 @@ const std::string FileData::findEmulatorPath(std::string& command) #if defined(_WIN64) std::vector emulatorWinRegistryPaths; + std::vector emulatorWinRegistryValues; #endif std::vector emulatorSystemPaths; std::vector emulatorStaticPaths; @@ -1175,6 +1194,8 @@ const std::string FileData::findEmulatorPath(std::string& command) #if defined(_WIN64) emulatorWinRegistryPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryPaths; + emulatorWinRegistryValues = + SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryValues; #endif emulatorSystemPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].systemPaths; emulatorStaticPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].staticPaths; @@ -1206,7 +1227,7 @@ const std::string FileData::findEmulatorPath(std::string& command) KEY_QUERY_VALUE, ®istryKey); } - // If the key exists, then try to retrieve the value. + // If the key exists, then try to retrieve its default value. if (keyStatus == ERROR_SUCCESS) { pathStatus = RegGetValue(registryKey, nullptr, nullptr, RRF_RT_REG_SZ, nullptr, ®istryPath, &pathSize); @@ -1228,6 +1249,51 @@ const std::string FileData::findEmulatorPath(std::string& command) } RegCloseKey(registryKey); } + + for (std::string value : emulatorWinRegistryValues) { + // Search for the defined value in the Windows Registry. + std::string registryValueKey = + Utils::String::replace(Utils::FileSystem::getParent(value), "/", "\\"); + std::string registryValue = Utils::FileSystem::getFileName(value); + + HKEY registryKey; + LSTATUS keyStatus = -1; + LSTATUS pathStatus = -1; + char path[1024]{}; + DWORD pathSize = 1024; + + // First look in HKEY_CURRENT_USER. + keyStatus = RegOpenKeyEx(HKEY_CURRENT_USER, registryValueKey.c_str(), 0, KEY_QUERY_VALUE, + ®istryKey); + + // If not found, then try in HKEY_LOCAL_MACHINE. + if (keyStatus != ERROR_SUCCESS) { + keyStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryValueKey.c_str(), 0, + KEY_QUERY_VALUE, ®istryKey); + } + + // If the key exists, then try to retrieve the defined value. + if (keyStatus == ERROR_SUCCESS) { + pathStatus = + RegGetValue(registryKey, nullptr, reinterpret_cast(registryValue.c_str()), + RRF_RT_REG_SZ, nullptr, &path, &pathSize); + } + else { + RegCloseKey(registryKey); + continue; + } + + // That a value was found does not guarantee that the emulator binary actually exists, + // so check for that as well. + if (pathStatus == ERROR_SUCCESS) { + if (Utils::FileSystem::isRegularFile(path) || Utils::FileSystem::isSymlink(path)) { + command.replace(0, endPos + 1, path); + RegCloseKey(registryKey); + return path; + } + } + RegCloseKey(registryKey); + } #endif for (std::string path : emulatorSystemPaths) { diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index 954f8993a..04a2e198c 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -112,8 +112,8 @@ void FindRules::loadFindRules() continue; } #if defined(_WIN64) - if (ruleType != "winregistrypath" && ruleType != "systempath" && - ruleType != "staticpath") { + if (ruleType != "winregistrypath" && ruleType != "winregistryvalue" && + ruleType != "systempath" && ruleType != "staticpath") { #else if (ruleType != "systempath" && ruleType != "staticpath") { #endif @@ -131,6 +131,8 @@ void FindRules::loadFindRules() #if defined(_WIN64) else if (ruleType == "winregistrypath") emulatorRules.winRegistryPaths.push_back(entryValue); + else if (ruleType == "winregistryvalue") + emulatorRules.winRegistryValues.push_back(entryValue); #endif } } diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index 312cee3a8..f40ac14bc 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -42,6 +42,7 @@ private: struct EmulatorRules { #if defined(_WIN64) std::vector winRegistryPaths; + std::vector winRegistryValues; #endif std::vector systemPaths; std::vector staticPaths;