mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 07:35:38 +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 "VolumeControl.h"
|
||||
#include "Window.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
FileData::FileData(
|
||||
|
@ -452,18 +453,84 @@ void FileData::launchGame(Window* window)
|
|||
else
|
||||
command = mEnvData->mLaunchCommand;
|
||||
|
||||
std::string commandRaw = command;
|
||||
|
||||
const std::string rom = Utils::FileSystem::getEscapedPath(getPath());
|
||||
const std::string basename = Utils::FileSystem::getStem(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, "%BASENAME%", basename);
|
||||
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;
|
||||
int exitCode = runSystemCommand(command);
|
||||
Scripting::fireEvent("game-start", rom, basename);
|
||||
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) {
|
||||
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;
|
||||
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();
|
||||
fullname = system.child("fullname").text().get();
|
||||
|
|
|
@ -312,8 +312,8 @@ int VolumeControl::getVolume() const
|
|||
float floatVolume = 0.0f; // 0-1
|
||||
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK) {
|
||||
volume = (int)Math::round(floatVolume * 100.0f);
|
||||
LOG(LogInfo) << " getting volume as " << volume <<
|
||||
" ( from float " << floatVolume << ")";
|
||||
LOG(LogInfo) << "System audio volume is " << volume <<
|
||||
" (floating point value " << floatVolume << ")";
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "VolumeControl::getVolume() - Failed to get master volume!";
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//
|
||||
|
||||
#include "Platform.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#if defined(__linux__) || defined(_WIN64)
|
||||
#include <SDL2/SDL_events.h>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#else
|
||||
|
@ -42,16 +44,89 @@ int runPoweroffCommand()
|
|||
|
||||
int runSystemCommand(const std::string& cmd_utf8)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
#ifdef _WIN64
|
||||
// On Windows we use _wsystem to support non-ASCII paths
|
||||
// which requires converting from UTF8 to a wstring.
|
||||
typedef std::codecvt_utf8<wchar_t> convert_type;
|
||||
std::wstring_convert<convert_type, wchar_t> converter;
|
||||
std::wstring wchar_str = converter.from_bytes(cmd_utf8);
|
||||
// which requires converting from UTF-8 to a wstring.
|
||||
std::wstring wchar_str = Utils::String::charToWideChar(cmd_utf8);
|
||||
return _wsystem(wchar_str.c_str());
|
||||
#else
|
||||
#else
|
||||
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;
|
||||
|
|
|
@ -21,8 +21,14 @@ enum QuitMode {
|
|||
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);
|
||||
// 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);
|
||||
void processQuitMode();
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Utils
|
|||
std::string getCWDPath();
|
||||
void setExePath(const std::string& _path);
|
||||
std::string getExePath();
|
||||
std::string getProgramDataPath ();
|
||||
std::string getProgramDataPath();
|
||||
std::string getPreferredPath(const std::string& _path);
|
||||
std::string getGenericPath(const std::string& _path);
|
||||
std::string getEscapedPath(const std::string& _path);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "utils/StringUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace Utils
|
||||
|
@ -185,6 +187,22 @@ namespace Utils
|
|||
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)
|
||||
{
|
||||
return (_string.find(_start) == 0);
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace Utils
|
|||
std::string trim(const std::string& _string);
|
||||
std::string replace(const std::string& _string, const std::string& _replace,
|
||||
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 endsWith(const std::string& _string, const std::string& _end);
|
||||
std::string removeParenthesis(const std::string& _string);
|
||||
|
|
Loading…
Reference in a new issue