mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-29 09:35:39 +00:00
Added proper emulator launch function for Windows and added logic for the new %EMUPATH% variable.
This commit is contained in:
parent
76aa239855
commit
2bea3021c3
|
@ -22,6 +22,7 @@
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "VolumeControl.h"
|
#include "VolumeControl.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
FileData::FileData(
|
FileData::FileData(
|
||||||
|
@ -452,18 +453,84 @@ void FileData::launchGame(Window* window)
|
||||||
else
|
else
|
||||||
command = mEnvData->mLaunchCommand;
|
command = mEnvData->mLaunchCommand;
|
||||||
|
|
||||||
|
std::string commandRaw = command;
|
||||||
|
|
||||||
const std::string rom = Utils::FileSystem::getEscapedPath(getPath());
|
const std::string rom = Utils::FileSystem::getEscapedPath(getPath());
|
||||||
const std::string basename = Utils::FileSystem::getStem(getPath());
|
const std::string basename = Utils::FileSystem::getStem(getPath());
|
||||||
const std::string rom_raw = Utils::FileSystem::getPreferredPath(getPath());
|
const std::string rom_raw = Utils::FileSystem::getPreferredPath(getPath());
|
||||||
|
const std::string emupath = Utils::FileSystem::getExePath();
|
||||||
|
|
||||||
command = Utils::String::replace(command, "%ROM%", rom);
|
command = Utils::String::replace(command, "%ROM%", rom);
|
||||||
command = Utils::String::replace(command, "%BASENAME%", basename);
|
command = Utils::String::replace(command, "%BASENAME%", basename);
|
||||||
command = Utils::String::replace(command, "%ROM_RAW%", rom_raw);
|
command = Utils::String::replace(command, "%ROM_RAW%", rom_raw);
|
||||||
|
|
||||||
Scripting::fireEvent("game-start", rom, basename);
|
#ifdef _WIN64
|
||||||
|
std::wstring commandWide = Utils::String::charToWideChar(command);
|
||||||
|
#endif
|
||||||
|
|
||||||
LOG(LogInfo) << " " << command;
|
Scripting::fireEvent("game-start", rom, basename);
|
||||||
int exitCode = runSystemCommand(command);
|
int exitCode = 0;
|
||||||
|
|
||||||
|
if (command.find("%EMUPATH%") != std::string::npos) {
|
||||||
|
// Extract the emulator executable from the launch command string. This could either be
|
||||||
|
// just the program name, assuming the binary is in the PATH variable of the operating
|
||||||
|
// system, or it could be an absolute path to the emulator. (In the latter case, if
|
||||||
|
// there is a space in the the path, it needs to be enclosed by quotation marks in
|
||||||
|
// es_systems.cfg.)
|
||||||
|
std::string emuExecutable;
|
||||||
|
|
||||||
|
// If the first character is a quotation mark, then we need to extract up to the
|
||||||
|
// next quotation mark, otherwise we'll extract up to the first space character.
|
||||||
|
if (command.front() == '\"') {
|
||||||
|
std::string emuTemp = command.substr(1, std::string::npos);
|
||||||
|
emuExecutable = emuTemp.substr(0, emuTemp.find('"'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
emuExecutable = command.substr(0, command.find(' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Windows, we need to handle UTF-16 encoding.
|
||||||
|
#ifdef _WIN64
|
||||||
|
std::wstring emuExecutableWide;
|
||||||
|
std::wstring emuPathWide;
|
||||||
|
|
||||||
|
emuExecutableWide = Utils::String::charToWideChar(emuExecutable);
|
||||||
|
|
||||||
|
// Search for the emulator using the PATH environmental variable.
|
||||||
|
DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
std::vector<wchar_t> pathBuffer(static_cast<size_t>(size) + 1 );
|
||||||
|
wchar_t* fileName = nullptr;
|
||||||
|
|
||||||
|
SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", size + 1 ,
|
||||||
|
pathBuffer.data(), &fileName);
|
||||||
|
std::wstring pathString = pathBuffer.data();
|
||||||
|
|
||||||
|
if (pathString.length()) {
|
||||||
|
emuPathWide = pathString.substr(0, pathString.size() -
|
||||||
|
std::wstring(fileName).size());
|
||||||
|
emuPathWide.pop_back();
|
||||||
|
auto stringPos = commandWide.find(L"%EMUPATH%");
|
||||||
|
commandWide = commandWide.replace(stringPos, 9, emuPathWide);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// TODO for Unix.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(LogInfo) << "Raw emulator launch command:";
|
||||||
|
LOG(LogInfo) << commandRaw;
|
||||||
|
LOG(LogInfo) << "Expanded emulator launch command:";
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
LOG(LogInfo) << Utils::String::wideCharToChar(commandWide);
|
||||||
|
exitCode = launchEmulatorWindows(commandWide);
|
||||||
|
#else
|
||||||
|
LOG(LogInfo) << command;
|
||||||
|
exitCode = launchEmulatorUnix(command);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
LOG(LogWarning) << "...launch terminated with nonzero exit code " << exitCode << "!";
|
LOG(LogWarning) << "...launch terminated with nonzero exit code " << exitCode << "!";
|
||||||
|
|
|
@ -235,7 +235,11 @@ bool SystemData::loadConfig()
|
||||||
|
|
||||||
for (pugi::xml_node system = systemList.child("system"); system;
|
for (pugi::xml_node system = systemList.child("system"); system;
|
||||||
system = system.next_sibling("system")) {
|
system = system.next_sibling("system")) {
|
||||||
std::string name, fullname, path, cmd, themeFolder;
|
std::string name;
|
||||||
|
std::string fullname;
|
||||||
|
std::string path;
|
||||||
|
std::string cmd;
|
||||||
|
std::string themeFolder;
|
||||||
|
|
||||||
name = system.child("name").text().get();
|
name = system.child("name").text().get();
|
||||||
fullname = system.child("fullname").text().get();
|
fullname = system.child("fullname").text().get();
|
||||||
|
|
|
@ -312,8 +312,8 @@ int VolumeControl::getVolume() const
|
||||||
float floatVolume = 0.0f; // 0-1
|
float floatVolume = 0.0f; // 0-1
|
||||||
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK) {
|
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK) {
|
||||||
volume = (int)Math::round(floatVolume * 100.0f);
|
volume = (int)Math::round(floatVolume * 100.0f);
|
||||||
LOG(LogInfo) << " getting volume as " << volume <<
|
LOG(LogInfo) << "System audio volume is " << volume <<
|
||||||
" ( from float " << floatVolume << ")";
|
" (floating point value " << floatVolume << ")";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) << "VolumeControl::getVolume() - Failed to get master volume!";
|
LOG(LogError) << "VolumeControl::getVolume() - Failed to get master volume!";
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
#if defined(__linux__) || defined(_WIN64)
|
#if defined(__linux__) || defined(_WIN64)
|
||||||
#include <SDL2/SDL_events.h>
|
#include <SDL2/SDL_events.h>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
#include <windows.h>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#else
|
#else
|
||||||
|
@ -42,16 +44,89 @@ int runPoweroffCommand()
|
||||||
|
|
||||||
int runSystemCommand(const std::string& cmd_utf8)
|
int runSystemCommand(const std::string& cmd_utf8)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// On Windows we use _wsystem to support non-ASCII paths
|
// On Windows we use _wsystem to support non-ASCII paths
|
||||||
// which requires converting from UTF8 to a wstring.
|
// which requires converting from UTF-8 to a wstring.
|
||||||
typedef std::codecvt_utf8<wchar_t> convert_type;
|
std::wstring wchar_str = Utils::String::charToWideChar(cmd_utf8);
|
||||||
std::wstring_convert<convert_type, wchar_t> converter;
|
|
||||||
std::wstring wchar_str = converter.from_bytes(cmd_utf8);
|
|
||||||
return _wsystem(wchar_str.c_str());
|
return _wsystem(wchar_str.c_str());
|
||||||
#else
|
#else
|
||||||
return system(cmd_utf8.c_str());
|
return system(cmd_utf8.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int runSystemCommand(const std::wstring& cmd_utf16)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
return _wsystem(cmd_utf16.c_str());
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int launchEmulatorUnix(const std::string& cmd_utf8)
|
||||||
|
{
|
||||||
|
#ifdef __unix__
|
||||||
|
return system(cmd_utf8.c_str());
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int launchEmulatorWindows(const std::wstring& cmd_utf16)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
STARTUPINFOW si {};
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
bool processReturnValue = true;
|
||||||
|
DWORD errorCode = 0;
|
||||||
|
|
||||||
|
processReturnValue = CreateProcessW(
|
||||||
|
nullptr, // No application name (use command line).
|
||||||
|
(wchar_t*) cmd_utf16.c_str(), // Command line.
|
||||||
|
nullptr, // Process attributes.
|
||||||
|
nullptr, // Thread attributes.
|
||||||
|
FALSE, // Handles inheritance.
|
||||||
|
0, // Creation flags.
|
||||||
|
nullptr, // Use parent's environment block.
|
||||||
|
nullptr, // Use parent's starting directory.
|
||||||
|
&si, // Pointer to the STARTUPINFOW structure.
|
||||||
|
&pi ); // Pointer to the PROCESS_INFORMATION structure.
|
||||||
|
|
||||||
|
// Wait for the child process to exit.
|
||||||
|
WaitForSingleObject(pi.hThread, INFINITE);
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
|
||||||
|
// If the return value is false, then something failed.
|
||||||
|
if (!processReturnValue) {
|
||||||
|
LPWSTR pBuffer = nullptr;
|
||||||
|
|
||||||
|
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||||
|
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPWSTR)&pBuffer, 0, nullptr);
|
||||||
|
|
||||||
|
errorCode = GetLastError();
|
||||||
|
|
||||||
|
std::string errorMessage = Utils::String::wideCharToChar(pBuffer);
|
||||||
|
// Remove trailing newline from the error message.
|
||||||
|
if (errorMessage.back() == '\n');
|
||||||
|
errorMessage.pop_back();
|
||||||
|
if (errorMessage.back() == '\r');
|
||||||
|
errorMessage.pop_back();
|
||||||
|
|
||||||
|
LOG(LogError) << "Error - launchEmulatorWindows - system error code " <<
|
||||||
|
errorCode << ": " << errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close process and thread handles.
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
|
return errorCode;
|
||||||
|
#else // _WIN64
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QuitMode quitMode = QuitMode::QUIT;
|
QuitMode quitMode = QuitMode::QUIT;
|
||||||
|
|
|
@ -21,8 +21,14 @@ enum QuitMode {
|
||||||
POWEROFF = 2
|
POWEROFF = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run UTF-8 encoded in the shell (requires wstring conversion on Windows).
|
// Uses UTF-8 for Unix and does a UTF-16/wstring conversion for Windows.
|
||||||
int runSystemCommand(const std::string& cmd_utf8);
|
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 quitES(QuitMode mode = QuitMode::QUIT);
|
int quitES(QuitMode mode = QuitMode::QUIT);
|
||||||
void processQuitMode();
|
void processQuitMode();
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Utils
|
||||||
std::string getCWDPath();
|
std::string getCWDPath();
|
||||||
void setExePath(const std::string& _path);
|
void setExePath(const std::string& _path);
|
||||||
std::string getExePath();
|
std::string getExePath();
|
||||||
std::string getProgramDataPath ();
|
std::string getProgramDataPath();
|
||||||
std::string getPreferredPath(const std::string& _path);
|
std::string getPreferredPath(const std::string& _path);
|
||||||
std::string getGenericPath(const std::string& _path);
|
std::string getGenericPath(const std::string& _path);
|
||||||
std::string getEscapedPath(const std::string& _path);
|
std::string getEscapedPath(const std::string& _path);
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
|
@ -185,6 +187,22 @@ namespace Utils
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring charToWideChar(const std::string& _string)
|
||||||
|
{
|
||||||
|
typedef std::codecvt_utf8<wchar_t> convert_type;
|
||||||
|
std::wstring_convert<convert_type, wchar_t> stringConverter;
|
||||||
|
|
||||||
|
return stringConverter.from_bytes(_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string wideCharToChar(const std::wstring& _string)
|
||||||
|
{
|
||||||
|
typedef std::codecvt_utf8<wchar_t> convert_type;
|
||||||
|
std::wstring_convert<convert_type, wchar_t> stringConverter;
|
||||||
|
|
||||||
|
return stringConverter.to_bytes(_string);
|
||||||
|
}
|
||||||
|
|
||||||
bool startsWith(const std::string& _string, const std::string& _start)
|
bool startsWith(const std::string& _string, const std::string& _start)
|
||||||
{
|
{
|
||||||
return (_string.find(_start) == 0);
|
return (_string.find(_start) == 0);
|
||||||
|
|
|
@ -28,6 +28,8 @@ namespace Utils
|
||||||
std::string trim(const std::string& _string);
|
std::string trim(const std::string& _string);
|
||||||
std::string replace(const std::string& _string, const std::string& _replace,
|
std::string replace(const std::string& _string, const std::string& _replace,
|
||||||
const std::string& _with);
|
const std::string& _with);
|
||||||
|
std::wstring charToWideChar(const std::string& _string);
|
||||||
|
std::string wideCharToChar(const std::wstring& _string);
|
||||||
bool startsWith(const std::string& _string, const std::string& _start);
|
bool startsWith(const std::string& _string, const std::string& _start);
|
||||||
bool endsWith(const std::string& _string, const std::string& _end);
|
bool endsWith(const std::string& _string, const std::string& _end);
|
||||||
std::string removeParenthesis(const std::string& _string);
|
std::string removeParenthesis(const std::string& _string);
|
||||||
|
|
Loading…
Reference in a new issue