From 083e0a12e9fec932428a1ab9980c2298697a7cd6 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Wed, 24 Mar 2021 20:13:33 +0100 Subject: [PATCH] Improved launching of Steam games by keeping ES-DE running in the background. --- es-app/src/FileData.cpp | 24 ++++++++++++++----- es-app/src/views/ViewController.cpp | 35 ++++++++++----------------- es-core/src/Platform.cpp | 37 +++++++++++++++++++---------- es-core/src/Platform.h | 4 ++-- es-core/src/Window.cpp | 2 +- 5 files changed, 58 insertions(+), 44 deletions(-) diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index dbe74b671..adbb88889 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -954,9 +954,16 @@ void FileData::launchGame(Window* window) LOG(LogInfo) << command; #if defined(_WIN64) - returnValue = launchEmulatorWindows(Utils::String::stringToWideString(command)); + if (mSystem->hasPlatformId(PlatformIds::VALVE_STEAM) || + Settings::getInstance()->getBool("RunInBackground")) + returnValue = launchGameWindows(Utils::String::stringToWideString(command), true); + else + returnValue = launchGameWindows(Utils::String::stringToWideString(command), false); #else - returnValue = launchEmulatorUnix(command); + if (mSystem->hasPlatformId(PlatformIds::VALVE_STEAM)) + returnValue = launchGameUnix(command, true); + else + returnValue = launchGameUnix(command, false); #endif // Notify the user in case of a failed game launch using a popup window. @@ -972,16 +979,21 @@ void FileData::launchGame(Window* window) // Stop showing the game launch notification. window->stopInfoPopup(); #if defined(_WIN64) - // This code is only needed for Windows, where we may need to keep ES running while - // the game/emulator is in use. It's basically used to pause any playing game video - // and to keep the screensaver from activating. - if (Settings::getInstance()->getBool("RunInBackground")) + // If starting a Steam game or if the "RunInBackground" setting has been enabled, + // then keep ES-DE running while the game is launched. This pauses any video and keeps + // the screensaver from getting activated. + if (mSystem->hasPlatformId(PlatformIds::VALVE_STEAM) || + Settings::getInstance()->getBool("RunInBackground")) window->setLaunchedGame(); else // Normalize deltaTime so that the screensaver does not start immediately // when returning from the game. window->normalizeNextUpdate(); #else + // If starting a Steam game, then keep ES-DE running while the game is launched. + // This pauses any video and keeps the screensaver from getting activated. + if (mSystem->hasPlatformId(PlatformIds::VALVE_STEAM)) + window->setLaunchedGame(); // Normalize deltaTime so that the screensaver does not start immediately // when returning from the game. window->normalizeNextUpdate(); diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index ab79fac78..4081e0f63 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -762,18 +762,13 @@ bool ViewController::input(InputConfig* config, Input input) if (mLockInput) return true; - #if defined(_WIN64) - // This code is only needed for Windows, where we may need to keep ES running while - // the game/emulator is in use. It's basically used to pause any playing game video - // and to keep the screensaver from activating. - if (Settings::getInstance()->getBool("RunInBackground")) { - // If we have previously launched a game and there is now input registered, it means - // the user is back in ES, so unset the flag to indicate that a game has been launched - // and update all the GUI components to reflect this. - if (mWindow->getGameLaunchedState()) - mWindow->unsetLaunchedGame(); - } - #endif + // For Steam games or if enabling the "RunInBackground" setting on Windows, ES-DE will + // run in the background while a game is launched. If we're in this state and then + // register some input, it means that the user is back in ES-DE. Therefore unset the game + // launch flag and update all the GUI components. This will re-enable the video player + // and let the screensaver start on schedule again. + if (mWindow->getGameLaunchedState()) + mWindow->unsetLaunchedGame(); // Open the main menu. if (!(UIModeController::getInstance()->isUIModeKid() && @@ -930,16 +925,12 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme) } } - #if defined(_WIN64) - // This code is only needed for Windows, where we may need to keep ES running while - // the game/emulator is in use. It's basically used to pause any playing game video - // and to keep the screensaver from activating. - if (Settings::getInstance()->getBool("RunInBackground")) { - // If a game has been launched, then update all the GUI components to reflect this. - if (mWindow->getGameLaunchedState()) - mWindow->setLaunchedGame(); - } - #endif + // For Steam games or if enabling the "RunInBackground" setting on Windows, ES-DE will + // run in the background while a game is launched. If this flag has been set, then update + // all the GUI components. This will disable the video player and prevent the screensaver + // from starting on schedule. + if (mWindow->getGameLaunchedState()) + mWindow->setLaunchedGame(); // Redisplay the current view. if (mCurrentView) diff --git a/es-core/src/Platform.cpp b/es-core/src/Platform.cpp index 90134a0a9..658f1bf98 100644 --- a/es-core/src/Platform.cpp +++ b/es-core/src/Platform.cpp @@ -71,10 +71,19 @@ int runSystemCommand(const std::wstring& cmd_utf16) #endif } -int launchEmulatorUnix(const std::string& cmd_utf8) +int launchGameUnix(const std::string& cmd_utf8, bool runInBackground) { #if defined(__unix__) || defined (__APPLE__) - std::string command = std::string(cmd_utf8) + " 2>&1"; + std::string command = std::string(cmd_utf8) + " 2>&1 &"; + + // Launching games while keeping ES-DE running in the background is very crude as for + // instance no output from the command is captured and no real error handling is + // implemented. It should therefore only be used when absolutely necessary. + if (runInBackground) { + LOG(LogDebug) << "Platform::launchGameUnix(): Launching game while keeping ES-DE " + "running in the background, no command output will be written to the log file"; + return system(command.c_str()); + } FILE* commandPipe; std::array buffer; @@ -101,15 +110,15 @@ int launchEmulatorUnix(const std::string& cmd_utf8) } if (returnValue) { - LOG(LogError) << "launchEmulatorUnix - return value " << + LOG(LogError) << "launchGameUnix - return value " << std::to_string(returnValue) + ":"; if (commandOutput.size()) LOG(LogError) << commandOutput; else - LOG(LogError) << "No error output provided by emulator."; + LOG(LogError) << "No error output provided by game or emulator"; } else if (commandOutput.size()) { - LOG(LogDebug) << "Platform::launchEmulatorUnix():"; + LOG(LogDebug) << "Platform::launchGameUnix():"; LOG(LogDebug) << "Output from launched game:\n" << commandOutput; } @@ -120,7 +129,7 @@ int launchEmulatorUnix(const std::string& cmd_utf8) #endif } -int launchEmulatorWindows(const std::wstring& cmd_utf16) +int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground) { #if defined(_WIN64) STARTUPINFOW si {}; @@ -142,12 +151,14 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16) &si, // Pointer to the STARTUPINFOW structure. &pi); // Pointer to the PROCESS_INFORMATION structure. - // Unfortunately suspending ES and resuming when the emulator process has exited - // doesn't work reliably on Windows, so we may need to keep ES running in the - // background while the game is launched. I'm not sure if there is a workaround - // for this, but on some Windows installations it seems to work fine so we'll let - // the user choose via a menu option. - if (!Settings::getInstance()->getBool("RunInBackground")) { + // Unfortunately suspending ES-DE and resuming when the game/emulator process has exited + // doesn't work reliably on Windows, so we may need to keep ES-DE running in the background + // while the game is launched. I'm not sure if there is a workaround for this, but on most + // Windows installations it seems to work fine so we'll let the user choose via a menu option. + // Possibly the issue is specific to Windows 8. + // Running in the background is also required for Steam games as ES-DE would otherwise + // wait forever for Steam to exit unless it was already running when the game was launched. + if (!runInBackground) { // Wait for the child process to exit. WaitForSingleObject(pi.hThread, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE); @@ -174,7 +185,7 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16) } } - LOG(LogError) << "launchEmulatorWindows - system error code " << + LOG(LogError) << "launchGameWindows - system error code " << errorCode << ": " << errorMessage; } diff --git a/es-core/src/Platform.h b/es-core/src/Platform.h index 9cb862f3c..580016e24 100644 --- a/es-core/src/Platform.h +++ b/es-core/src/Platform.h @@ -26,8 +26,8 @@ int runSystemCommand(const std::string& cmd_utf8); // Windows specific UTF-16/wstring function. (FOR FUTURE USE) int runSystemCommand(const std::wstring& cmd_utf16); -int launchEmulatorUnix(const std::string& cmd_utf8); -int launchEmulatorWindows(const std::wstring& cmd_utf16); +int launchGameUnix(const std::string& cmd_utf8, bool runInBackground); +int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground); unsigned int getTaskbarState(); void hideTaskbar(); diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index d01eaac7c..0e29e27d0 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -648,7 +648,7 @@ void Window::setLaunchedGame() void Window::unsetLaunchedGame() { - // Tell the GUI components that the user is back in ES again. + // Tell the GUI components that the user is back in ES-DE again. for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) (*it)->onGameLaunchedDeactivate();