Add quit and daemon quit commands

Add default keys CTRL+q to post a "quit" command and listen for the
command in the Game::respond function. When the SHIFT key is also
pressed on Linux, run a system command that stops the daemon configured
at "daemon service name". This is made for arcade cabinet builds which
have a daemon service managing the game.
This commit is contained in:
Cocktail Frank 2025-02-26 16:04:12 -05:00
parent c82b163349
commit 0594d42fe5
4 changed files with 73 additions and 5 deletions

View File

@ -29,7 +29,8 @@ void Configuration::set_defaults()
{"down", "down"},
{"left", "left"},
{"fullscreen", {"ALT", "enter"}},
{"reset", {"CTRL", "r"}}
{"reset", {"CTRL", "r"}},
{"quit", {"CTRL", "q"}}
};
config["input"] = {
{"suppress any key on mods", true},
@ -43,7 +44,7 @@ void Configuration::set_defaults()
{"max framerate", -1},
{"vsync", false},
{"sdl delay", 6},
{"title", "play your next game at dank.game 🪐💫💫💫📦"},
{"title", "🚬 dank🦄game 🚬"},
{"debug", false},
{"show cursor", false},
{"render-test-spacing", 2},
@ -104,13 +105,14 @@ void Configuration::set_defaults()
config["configuration"] = {
{"auto refresh", false},
{"auto refresh interval", 5.0},
{"android config path", "config_android.json"},
{"wasm config path", "config_wasm.json"},
{"search path", {"config.json", "config"}}
};
config["storage"] = {
{"preferences file", "storage/preferences.json"}
};
config["system"] = {
{"daemon service name", ""}
};
}
nlohmann::json& Configuration::operator[](const std::string& key)

View File

@ -656,6 +656,63 @@ std::shared_ptr<TTF_Font> sb::Game::font(
void Game::respond(SDL_Event& event)
{
/* Game will quit after current frame */
if (_delegate.compare(event, "quit"))
{
flag_to_end();
#if defined(__LINUX__)
/* If the shift button is being held and the game is configured to have a systemd service file path, add a
* system call to stop the service. This prevents the service from automatically relaunching the game after
* it quits. */
std::string daemon_name { configuration()("system", "daemon service name") };
if (!daemon_name.empty() && SDL_GetModState() & KMOD_SHIFT)
{
/* Make sure the service name has no special characters. This prevents system commands from being inserted
* through the configuration. */
std::string invalid_characters { " ~`!@#$%^;\"'<>,.?{}[]|\\&*()+=" };
if (strcspn(daemon_name.c_str(), invalid_characters.c_str()) == daemon_name.size())
{
/* Check if a command processor exists */
if (std::system(nullptr) > 0)
{
/* Build systemctl command */
std::ostringstream command;
command << "systemctl --user stop " << daemon_name;
/* To run successfully, this requires a systemd service to be running. */
int status = std::system(command.str().c_str());
sb::Log::Multi() << "Stopping systemd service " << daemon_name << sb::Log::end;
if (WIFEXITED(status) == 0)
{
if (WIFSIGNALED(status) == 0)
{
if (WIFSTOPPED(status) > 0)
{
sb::Log::Multi() << "Daemon stopped with signal " << WTERMSIG(status) << sb::Log::end;
}
}
else
{
sb::Log::Multi() << "Daemon terminated with signal " << WTERMSIG(status) << sb::Log::end;
}
}
else
{
sb::Log::Multi() << "Daemon exit status is " << WEXITSTATUS(status) << sb::Log::end;
}
}
}
else
{
sb::Log::Multi() << "Daemon name " << daemon_name << " contains invalid characters." << sb::Log::end;
}
}
}
#endif
/* Controls for the recorder object */
if (configuration()("recording", "enabled"))
{
if (_delegate.compare(event, "screenshot"))

View File

@ -20,6 +20,12 @@
#include <functional>
#include <optional>
/* Needed to make system calls and check exit status of Linux processes */
#if defined(__LINUX__)
#include <sys/wait.h>
#include <string.h>
#endif
#include "SDL.h"
#include "SDL_mixer.h"
#include "SDL_ttf.h"

View File

@ -106,7 +106,10 @@ void Input::respond(SDL_Event &event)
{
for (KeyCombination& combination : key_map)
{
if (sym == combination.key && (!combination.ctrl || ctrl) && (!combination.shift || shift) && (!combination.alt || alt))
if (sym == combination.key &&
(!combination.ctrl || ctrl) &&
(!combination.shift || shift) &&
(!combination.alt || alt))
{
sb::Delegate::post(combination.command, cancel);
if (!sb::contains(system_any_key_ignore, combination.command) && !found_command &&