SDL_Libretro 0.1.0
SDL3-power libretro frontend.
Loading...
Searching...
No Matches
SDL_libretro_config.h
Go to the documentation of this file.
1
7#if defined(SDL_LIBRETRO_IMPLEMENTATION) && !defined(SDL_LIBRETRO_CONFIG_IMPL_ONCE)
8#define SDL_LIBRETRO_CONFIG_IMPL_ONCE
9
13static void SDL_Libretro_SanitizeSectionName(char* dst, size_t dstSize, const char* name) {
14 // Replace [], new lines, and spaces with _.
15 // This will make `Genesis Plus GX` match with `genesis_plus_gx`
16 SDL_strlcpy(dst, name, dstSize);
17 for (char* p = dst; *p; ++p) {
18 if (*p == '[' || *p == ']' || *p == '\n' || *p == '\r' || *p == ' ') {
19 *p = '_';
20 }
21 }
22}
23
39bool SDL_Libretro_InitConfigFile(SDL_Libretro* lr, const char* file) {
40 if (!lr || !file) return false;
41
42 // Clear our any existing config.
43 SDL_free(lr->iniFile);
44 lr->iniFile = NULL;
45 INI_Destroy(lr->ini);
46 lr->ini = NULL;
47
48 // Load the file. Only a missing file starts out empty: saving over one
49 // that failed to load would replace everything in it with defaults.
50 SDL_ini* ini = INI_Load(file);
51 if (!ini) {
52 if (SDL_GetPathInfo(file, NULL)) {
53 SDL_SetError("[SDL_Libretro] Failed to load config '%s', leaving it untouched: %s", file, SDL_GetError());
54 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", SDL_GetError());
55 return false;
56 }
57 ini = INI_Create();
58 if (!ini) return false;
59 }
60
61 // Capture the ini file path.
62 lr->iniFile = SDL_strdup(file);
63 if (!lr->iniFile) {
64 INI_Destroy(ini);
65 return false;
66 }
67 lr->ini = ini;
68
69 // Get all the configs.
70 if (INI_HasValue(ini, NULL, "volume"))
71 SDL_Libretro_SetVolume(lr, INI_GetFloat(ini, NULL, "volume", SDL_Libretro_GetVolume(lr)));
72 if (INI_HasValue(ini, NULL, "username"))
73 SDL_Libretro_SetUsername(lr, INI_GetString(ini, NULL, "username", SDL_Libretro_GetUsername(lr)));
74 if (INI_HasValue(ini, NULL, "audiolatency"))
75 SDL_Libretro_SetAudioLatency(lr, (unsigned)INI_GetInt(ini, NULL, "audiolatency", SDL_Libretro_GetAudioLatency(lr)));
76 if (INI_HasValue(ini, NULL, "fitmode"))
77 SDL_Libretro_SetFitMode(lr, (SDL_LibretroFitMode)INI_GetInt(ini, NULL, "fitmode", SDL_Libretro_GetFitMode(lr)));
78 if (INI_HasValue(ini, NULL, "scalemode"))
79 SDL_Libretro_SetScaleMode(lr, (SDL_ScaleMode)INI_GetInt(ini, NULL, "scalemode", (Sint64)SDL_Libretro_GetScaleMode(lr)));
80 if (INI_HasValue(ini, NULL, "savedirectory"))
81 SDL_Libretro_SetSaveDirectory(lr, INI_GetString(ini, NULL, "savedirectory", SDL_Libretro_GetSaveDirectory(lr)));
82 if (INI_HasValue(ini, NULL, "systemdirectory"))
83 SDL_Libretro_SetSystemDirectory(lr, INI_GetString(ini, NULL, "systemdirectory", SDL_Libretro_GetSystemDirectory(lr)));
84 if (INI_HasValue(ini, NULL, "coredirectory"))
85 SDL_Libretro_SetCoreDirectory(lr, INI_GetString(ini, NULL, "coredirectory", SDL_Libretro_GetCoreDirectory(lr)));
86 if (INI_HasValue(ini, NULL, "coreassetsdirectory"))
87 SDL_Libretro_SetCoreAssetsDirectory(lr, INI_GetString(ini, NULL, "coreassetsdirectory", SDL_Libretro_GetCoreAssetsDirectory(lr)));
88 if (INI_HasValue(ini, NULL, "rewindenabled") || INI_HasValue(ini, NULL, "rewindframes") || INI_HasValue(ini, NULL, "rewindinterval")) {
89 // Keep the current snapshot count and capture interval unless saved; 0 means the default.
90 bool enabled = INI_GetBoolean(ini, NULL, "rewindenabled", SDL_Libretro_GetRewindEnabled(lr));
91 Sint64 frames = INI_GetInt(ini, NULL, "rewindframes", (Sint64)lr->rewindCapacity);
92 Sint64 interval = INI_GetInt(ini, NULL, "rewindinterval", (Sint64)lr->rewindCaptureInterval);
93 unsigned bufferFrames = (frames > 0 && frames <= SDL_MAX_UINT32) ? (unsigned)frames : 0;
94 unsigned captureInterval = (interval > 0 && interval <= SDL_MAX_UINT32) ? (unsigned)interval : 0;
95 SDL_Libretro_SetRewindEnabled(lr, enabled, bufferFrames, captureInterval);
96 if (!enabled) {
97 // Disabling frees the buffers without storing the settings, so keep them for re-enabling later.
98 lr->rewindCapacity = bufferFrames;
99 lr->rewindCaptureInterval = captureInterval;
100 }
101 }
102 if (INI_HasValue(ini, NULL, "rewindmemorylimit"))
103 SDL_Libretro_SetRewindMemoryLimit(lr, (size_t)INI_GetInt(ini, NULL, "rewindmemorylimit", (Sint64)SDL_Libretro_GetRewindMemoryLimit(lr)));
104 if (INI_HasValue(ini, NULL, "mouseport"))
105 SDL_Libretro_SetMousePort(lr, (unsigned)INI_GetInt(ini, NULL, "mouseport", (Sint64)SDL_Libretro_GetMousePort(lr)));
106 if (INI_HasValue(ini, NULL, "language")) {
107 // -1 (or anything out of range) detects it from the system locale.
108 Sint64 language = INI_GetInt(ini, NULL, "language", (Sint64)lr->language);
109 SDL_Libretro_SetLanguage(lr, (language >= 0 && language < RETRO_LANGUAGE_LAST) ? (int)language : -1);
110 }
111 if (INI_HasValue(ini, NULL, "filebrowserdirectory"))
112 SDL_strlcpy(lr->fileBrowserStartDirectory, INI_GetString(ini, NULL, "filebrowserdirectory", ""), sizeof(lr->fileBrowserStartDirectory));
113
114 // Player 1 keyboard bindings, stored as SDL scancode names.
115 for (int button = 0; button < SDL_LIBRETRO_MAX_JOYPAD_BUTTONS; button++) {
116 if (!INI_HasValue(ini, "keyboard", SDL_Libretro_JoypadButtonNames[button])) {
117 continue;
118 }
119 SDL_Scancode scancode = SDL_GetScancodeFromName(INI_GetString(ini, "keyboard", SDL_Libretro_JoypadButtonNames[button], ""));
120 if (scancode != SDL_SCANCODE_UNKNOWN) {
121 SDL_Libretro_SetKeyboardMapping(lr, button, scancode);
122 }
123 }
124
125 // Per-port gamepad bindings ([gamepad1]..[gamepadN]), stored as SDL
126 // gamepad button names, with the analog-to-digital stick by mode name.
127 for (unsigned port = 0; port < SDL_LIBRETRO_MAX_USERS; port++) {
128 char section[16];
129 SDL_snprintf(section, sizeof(section), "gamepad%u", port + 1);
130 for (int button = 0; button < SDL_LIBRETRO_MAX_JOYPAD_BUTTONS; button++) {
131 if (!INI_HasValue(ini, section, SDL_Libretro_JoypadButtonNames[button])) {
132 continue;
133 }
134 SDL_GamepadButton pad = SDL_GetGamepadButtonFromString(INI_GetString(ini, section, SDL_Libretro_JoypadButtonNames[button], ""));
135 if (pad != SDL_GAMEPAD_BUTTON_INVALID) {
136 SDL_Libretro_SetGamepadMapping(lr, port, button, pad);
137 }
138 }
139
140 const char* analog = INI_GetString(ini, section, "AnalogToDigital", NULL);
141 if (analog != NULL) {
142 for (int mode = 0; mode < SDL_LIBRETRO_ANALOG_TO_DIGITAL_COUNT; mode++) {
143 if (SDL_strcasecmp(analog, SDL_Libretro_AnalogToDigitalNames[mode]) == 0) {
145 }
146 }
147 }
148 }
149
150 return true;
151}
152
168bool SDL_Libretro_InitConfig(SDL_Libretro* lr, const char* org, const char* app) {
169 if (!lr) return false;
170 if (!org || org[0] == '\0') org = "SDL_libretro";
171 if (!app || app[0] == '\0') app = "SDL_libretro";
172 char* prefPath = SDL_GetPrefPath(org, app);
173 if (!prefPath) return false;
174 char path[SDL_LIBRETRO_MAX_PATH];
175 SDL_snprintf(path, sizeof(path), "%s%s.cfg", prefPath, app);
176 SDL_free(prefPath);
177 return SDL_Libretro_InitConfigFile(lr, path);
178}
179
183static void SDL_Libretro_SetCoreConfigOption(void* userdata, const SDL_ini* ini, const char* section, const char* key, const char* value) {
184 (void)ini;
185 (void)section;
186 SDL_Libretro_SetOptionValue((SDL_Libretro*)userdata, key, value);
187}
188
192static bool SDL_Libretro_LoadCoreConfig(SDL_Libretro* lr) {
193 if (!lr || !lr->ini || !SDL_Libretro_IsCoreReady(lr)) return false;
194
195 // Set the library name as the section name.
196 char section[128];
197 SDL_Libretro_SanitizeSectionName(section, sizeof(section), lr->core.libraryName);
198
199 // Ensure there's a valid section name to enumerate.
200 if (section[0] == '\0') {
201 return false;
202 }
203 INI_EnumerateKeys(lr->ini, section, &SDL_Libretro_SetCoreConfigOption, (void*)lr);
204 return true;
205}
206
212static const char* SDL_Libretro_GetSavedCoreOption(const SDL_Libretro* lr, const char* key) {
213 if (!lr || !lr->ini || !key || lr->core.libraryName[0] == '\0') return NULL;
214 char section[128];
215 SDL_Libretro_SanitizeSectionName(section, sizeof(section), lr->core.libraryName);
216 if (section[0] == '\0') return NULL;
217 return INI_GetString(lr->ini, section, key, NULL);
218}
219
223static bool SDL_Libretro_SaveCoreConfig(SDL_Libretro* lr) {
224 if (!SDL_Libretro_IsCoreReady(lr) || !lr->ini) return false;
225 char section[128];
226 SDL_Libretro_SanitizeSectionName(section, sizeof(section), lr->core.libraryName);
227 if (section[0] == '\0') {
228 return false;
229 }
230 int count = SDL_Libretro_GetOptionCount(lr);
231 for (int i = 0; i < count; i++) {
233 if (!option) continue;
234 const char* val = option->value ? option->value : option->defaultValue;
235 // Save the value in the config even if it matches the default.
236 INI_SetString(lr->ini, section, option->key, val);
237 }
238 return true;
239}
240
244static bool SDL_Libretro_SaveConfig(SDL_Libretro* lr) {
245 if (!lr || !lr->ini || !lr->iniFile) return false;
246
247 // Save the core options if needed.
248 SDL_Libretro_SaveCoreConfig(lr);
249
250 INI_SetFloat(lr->ini, NULL, "volume", SDL_Libretro_GetVolume(lr));
251 INI_SetString(lr->ini, NULL, "username", SDL_Libretro_GetUsername(lr));
252 INI_SetInt(lr->ini, NULL, "audiolatency", (Sint64)SDL_Libretro_GetAudioLatency(lr));
253 INI_SetInt(lr->ini, NULL, "fitmode", (Sint64)SDL_Libretro_GetFitMode(lr));
254 INI_SetInt(lr->ini, NULL, "scalemode", (Sint64)SDL_Libretro_GetScaleMode(lr));
255 INI_SetString(lr->ini, NULL, "savedirectory", SDL_Libretro_GetSaveDirectory(lr));
256 INI_SetString(lr->ini, NULL, "systemdirectory", SDL_Libretro_GetSystemDirectory(lr));
257 INI_SetString(lr->ini, NULL, "coredirectory", SDL_Libretro_GetCoreDirectory(lr));
258 INI_SetString(lr->ini, NULL, "coreassetsdirectory", SDL_Libretro_GetCoreAssetsDirectory(lr));
259 INI_SetBoolean(lr->ini, NULL, "rewindenabled", SDL_Libretro_GetRewindEnabled(lr));
260 INI_SetInt(lr->ini, NULL, "rewindframes", (Sint64)lr->rewindCapacity);
261 INI_SetInt(lr->ini, NULL, "rewindinterval", (Sint64)lr->rewindCaptureInterval);
262 INI_SetInt(lr->ini, NULL, "rewindmemorylimit", (Sint64)SDL_Libretro_GetRewindMemoryLimit(lr));
263 INI_SetInt(lr->ini, NULL, "mouseport", (Sint64)SDL_Libretro_GetMousePort(lr));
264 // The raw override, so -1 keeps following the system locale.
265 INI_SetInt(lr->ini, NULL, "language", (Sint64)lr->language);
266 INI_SetString(lr->ini, NULL, "filebrowserdirectory", lr->fileBrowserStartDirectory);
267
268 for (int button = 0; button < SDL_LIBRETRO_MAX_JOYPAD_BUTTONS; button++) {
269 INI_SetString(lr->ini, "keyboard", SDL_Libretro_JoypadButtonNames[button], SDL_GetScancodeName(lr->keyboardPlayer1[button]));
270 }
271
272 // Per-port gamepad bindings ([gamepad1]..[gamepadN]).
273 for (unsigned port = 0; port < SDL_LIBRETRO_MAX_USERS; port++) {
274 char section[16];
275 SDL_snprintf(section, sizeof(section), "gamepad%u", port + 1);
276 for (int button = 0; button < SDL_LIBRETRO_MAX_JOYPAD_BUTTONS; button++) {
277 const char* padName = SDL_GetGamepadStringForButton(lr->gamepadButtons[port][button]);
278 INI_SetString(lr->ini, section, SDL_Libretro_JoypadButtonNames[button], padName != NULL ? padName : "");
279 }
280 INI_SetString(lr->ini, section, "AnalogToDigital", SDL_Libretro_AnalogToDigitalNames[lr->analogToDigital[port]]);
281 }
282
283 // Write through a temporary file, so a failed save can't truncate the config.
284 char tempPath[SDL_LIBRETRO_MAX_PATH];
285 SDL_IOStream* io = SDL_Libretro_OpenSaveFile(lr->iniFile, tempPath, sizeof(tempPath));
286 if (!io) return false;
287 return SDL_Libretro_CommitSaveFile(io, INI_Save_IO(lr->ini, io, false), tempPath, lr->iniFile);
288}
289
293static bool SDL_Libretro_CloseConfig(SDL_Libretro* lr) {
294 if (!lr) return false;
295 bool ok = SDL_Libretro_SaveConfig(lr);
296 SDL_free(lr->iniFile);
297 lr->iniFile = NULL;
298 INI_Destroy(lr->ini);
299 lr->ini = NULL;
300 return ok;
301}
302
303#endif
#define SDL_LIBRETRO_MAX_USERS
The number of controller ports (gamepads) the frontend tracks.
bool SDL_Libretro_IsCoreReady(const SDL_Libretro *lr)
Indicates whether a core is loaded.
bool SDL_Libretro_SetCoreAssetsDirectory(SDL_Libretro *lr, const char *path)
Sets where cores look for their assets, reported through RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY.
bool SDL_Libretro_SetSystemDirectory(SDL_Libretro *lr, const char *path)
Sets where cores look for system files (BIOS, firmware, etc).
bool SDL_Libretro_SetCoreDirectory(SDL_Libretro *lr, const char *path)
Sets the associated libretro core directory, where the default set of cores will be loaded from.
void SDL_Libretro_SetRewindMemoryLimit(SDL_Libretro *lr, size_t maxBytes)
Set the maximum number of bytes of encoded delta history to retain.
const char * SDL_Libretro_GetUsername(SDL_Libretro *lr)
Get the username reported to cores.
SDL_ScaleMode SDL_Libretro_GetScaleMode(const SDL_Libretro *lr)
Gets the texture scale mode used when the libretro frame is scaled.
SDL_LibretroFitMode SDL_Libretro_GetFitMode(const SDL_Libretro *lr)
Gets how the frame is fit into the destination rectangle when rendered.
SDL_LibretroFitMode
When rendering the libretro context, determine how to display within the destination.
bool SDL_Libretro_SetRewindEnabled(SDL_Libretro *lr, bool enabled, unsigned bufferFrames, unsigned captureInterval)
Enable or disable the rewind system.
bool SDL_Libretro_InitConfig(SDL_Libretro *lr, const char *org, const char *app)
Sets up the config file to be the default path, accoring to the organization and app name.
bool SDL_Libretro_InitConfigFile(SDL_Libretro *lr, const char *file)
Initializes the config system based on the given file.
bool SDL_Libretro_SetFitMode(SDL_Libretro *lr, SDL_LibretroFitMode mode)
Sets how the frame is fit into the destination rectangle when rendered.
const SDL_LibretroOption * SDL_Libretro_GetOptionByIndex(const SDL_Libretro *lr, unsigned index)
Retrieve a core option by its registration index.
void SDL_Libretro_SetVolume(SDL_Libretro *lr, float volume)
Set the audio volume when playing sounds.
const char * SDL_Libretro_GetCoreAssetsDirectory(SDL_Libretro *lr)
Get the core assets directory.
void SDL_Libretro_SetGamepadMapping(SDL_Libretro *lr, unsigned port, int retroButton, SDL_GamepadButton button)
Maps an SDL gamepad button to a RETRO_DEVICE_ID_JOYPAD_* button on the given controller port.
void SDL_Libretro_SetAudioLatency(SDL_Libretro *lr, unsigned latencyMs)
Set the desired minimum audio latency for the audio stream.
float SDL_Libretro_GetVolume(const SDL_Libretro *lr)
Get the audio volume.
void SDL_Libretro_SetMousePort(SDL_Libretro *lr, unsigned port)
Selects the one controller port that the mouse drives.
bool SDL_Libretro_GetRewindEnabled(const SDL_Libretro *lr)
Check whether the rewind system is enabled (independent of current direction).
const char * SDL_Libretro_GetSystemDirectory(SDL_Libretro *lr)
Get the system directory.
bool SDL_Libretro_SetOptionValue(SDL_Libretro *lr, const char *key, const char *value)
Set a core option's value; fails if the value isn't one the core declared.
bool SDL_Libretro_SetSaveDirectory(SDL_Libretro *lr, const char *path)
Sets where content will be saved.
size_t SDL_Libretro_GetRewindMemoryLimit(const SDL_Libretro *lr)
Get the current rewind memory budget in bytes (0 if unbounded).
unsigned SDL_Libretro_GetOptionCount(const SDL_Libretro *lr)
Get the number of core options that have been set.
bool SDL_Libretro_SetUsername(SDL_Libretro *lr, const char *username)
Sets the username reported to cores through RETRO_ENVIRONMENT_GET_USERNAME.
bool SDL_Libretro_SetScaleMode(SDL_Libretro *lr, SDL_ScaleMode mode)
Sets the texture scale mode used when the libretro frame is scaled.
unsigned SDL_Libretro_GetAudioLatency(const SDL_Libretro *lr)
Get the minimum audio latency for the audio stream.
void SDL_Libretro_SetAnalogToDigital(SDL_Libretro *lr, unsigned port, SDL_LibretroAnalogToDigital stick)
Selects which analog stick, if any, also registers D-Pad presses on the given controller port,...
const char * SDL_Libretro_GetCoreDirectory(SDL_Libretro *lr)
Get the core directory.
const char * SDL_Libretro_GetSaveDirectory(SDL_Libretro *lr)
Get the save directory.
SDL_LibretroAnalogToDigital
Which analog stick, if any, also registers D-Pad presses for a controller port.
unsigned SDL_Libretro_GetMousePort(const SDL_Libretro *lr)
Get the controller port that the mouse drives.
void SDL_Libretro_SetLanguage(SDL_Libretro *lr, int language)
Override the language reported to cores through RETRO_ENVIRONMENT_GET_LANGUAGE.
void SDL_Libretro_SetKeyboardMapping(SDL_Libretro *lr, int retroButton, SDL_Scancode scancode)
Maps a keyboard key to a RETRO_DEVICE_ID_JOYPAD_* button for Player 1 (controller port 0).
@ SDL_LIBRETRO_ANALOG_TO_DIGITAL_COUNT
The number of possible modes.
A core option and its current state.
const char * value
The current value.
const char * key
Unique identifier the core queries.
const char * defaultValue
The default value.