RetroArch/menu/cbs/menu_cbs_ok.c

9792 lines
371 KiB
C
Raw Normal View History

/* RetroArch - A frontend for libretro.
2017-01-22 13:40:32 +01:00
* Copyright (C) 2011-2017 - Daniel De Matteis
2019-02-22 16:31:54 -05:00
* Copyright (C) 2016-2019 - Brad Parker
* Copyright (C) 2016-2019 - Andrés Suárez
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
2016-09-01 18:01:41 +02:00
#include <compat/strl.h>
#include <array/rbuf.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#include <streams/file_stream.h>
#include <lists/string_list.h>
#ifdef HAVE_NETWORKING
#include <net/net_http.h>
#endif
2016-09-08 05:39:08 +02:00
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#include <vfs/vfs_implementation.h>
#ifdef HAVE_CDROM
#include <vfs/vfs_implementation_cdrom.h>
#endif
2018-12-24 15:06:21 -05:00
#ifdef HAVE_DISCORD
2020-05-20 15:27:27 +02:00
#include "../../network/discord.h"
2018-12-24 15:06:21 -05:00
#endif
#include "../../config.def.h"
#include "../../driver.h"
#include "../../file_path_special.h"
2015-12-06 17:55:27 +01:00
#include "../menu_driver.h"
2015-06-26 15:28:01 +02:00
#include "../menu_cbs.h"
#include "../menu_entries.h"
#include "../menu_setting.h"
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
#include "../menu_shader.h"
#endif
#include "../menu_input.h"
2016-09-06 06:11:44 +02:00
#include "../../core.h"
2016-09-01 18:01:41 +02:00
#include "../../configuration.h"
#include "../../core_info.h"
#include "../../audio/audio_driver.h"
2021-11-10 02:34:04 +01:00
#include "../../record/record_driver.h"
2016-02-05 19:00:30 +01:00
#include "../../frontend/frontend_driver.h"
2015-12-06 22:48:57 +01:00
#include "../../defaults.h"
#include "../../core_option_manager.h"
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
#include "../../cheat_manager.h"
2020-06-30 19:35:41 +02:00
#endif
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2019-01-31 19:41:51 +01:00
#include "../../tasks/task_audio_mixer.h"
2019-07-11 11:51:06 +02:00
#endif
2019-01-20 03:16:58 +01:00
#include "../../tasks/task_content.h"
#include "../../tasks/task_file_transfer.h"
#include "../../tasks/tasks_internal.h"
#include "../../input/input_remapping.h"
2016-09-17 13:40:25 +02:00
#include "../../paths.h"
#include "../../playlist.h"
2016-03-21 19:23:45 +01:00
#include "../../retroarch.h"
2022-10-10 08:59:27 +02:00
#include "../../runloop.h"
2016-09-01 18:01:41 +02:00
#include "../../verbosity.h"
2016-03-23 21:40:41 +07:00
#include "../../lakka.h"
#ifdef HAVE_BLUETOOTH
2020-06-17 14:56:44 +03:00
#include "../../bluetooth/bluetooth_driver.h"
#endif
#include "../../gfx/video_display_server.h"
2019-11-29 17:13:35 +00:00
#include "../../manual_content_scan.h"
2016-09-29 21:07:10 +02:00
#ifdef HAVE_NETWORKING
#include "../../network/netplay/netplay.h"
#ifdef HAVE_WIFI
#include "../../network/wifi_driver.h"
#endif
#endif
#ifdef __WINRT__
#include "../../uwp/uwp_func.h"
#endif
2024-04-29 21:30:15 -04:00
#ifdef IOS
#include "../../ui/drivers/cocoa/apple_platform.h"
#endif
#if defined(ANDROID)
#include "../../file_path_special.h"
#include "../../play_feature_delivery/play_feature_delivery.h"
#endif
#if defined(HAVE_LIBNX)
#include "../../switch_performance_profiles.h"
#endif
#ifdef HAVE_MIST
#include "../../steam/steam.h"
#endif
enum
{
ACTION_OK_LOAD_PRESET = 0,
ACTION_OK_LOAD_SHADER_PASS,
2018-09-26 23:50:29 +02:00
ACTION_OK_LOAD_STREAM_CONFIGFILE,
ACTION_OK_LOAD_RECORD_CONFIGFILE,
ACTION_OK_LOAD_REMAPPING_FILE,
ACTION_OK_LOAD_OVERRIDE_FILE,
ACTION_OK_LOAD_CHEAT_FILE,
ACTION_OK_SUBSYSTEM_ADD,
ACTION_OK_LOAD_CONFIG_FILE,
ACTION_OK_LOAD_CORE,
ACTION_OK_LOAD_WALLPAPER,
ACTION_OK_SET_PATH,
ACTION_OK_SET_PATH_AUDIO_FILTER,
ACTION_OK_SET_PATH_VIDEO_FILTER,
ACTION_OK_SET_PATH_OVERLAY,
ACTION_OK_SET_PATH_OSK_OVERLAY,
ACTION_OK_SET_PATH_VIDEO_FONT,
ACTION_OK_SET_DIRECTORY,
ACTION_OK_SHOW_WIMP,
ACTION_OK_LOAD_CHEAT_FILE_APPEND,
ACTION_OK_LOAD_RGUI_MENU_THEME_PRESET,
ACTION_OK_SET_MANUAL_CONTENT_SCAN_DAT_FILE
};
2017-09-11 03:01:33 +02:00
enum
{
ACTION_OK_REMAP_FILE_SAVE_AS = 0,
ACTION_OK_REMAP_FILE_SAVE_CORE,
ACTION_OK_REMAP_FILE_SAVE_CONTENT_DIR,
2017-09-11 03:01:33 +02:00
ACTION_OK_REMAP_FILE_SAVE_GAME,
ACTION_OK_REMAP_FILE_REMOVE_CORE,
ACTION_OK_REMAP_FILE_REMOVE_CONTENT_DIR,
2017-09-11 03:01:33 +02:00
ACTION_OK_REMAP_FILE_REMOVE_GAME
};
#ifndef BIND_ACTION_OK
2020-03-28 01:59:15 +01:00
#define BIND_ACTION_OK(cbs, name) (cbs)->action_ok = (name)
#endif
2020-05-29 10:37:01 +02:00
#ifdef HAVE_NETWORKING
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#endif
2020-06-07 02:41:48 +02:00
#define ACTION_OK_DL_LBL(a, b) \
2020-05-29 10:37:01 +02:00
info.directory_ptr = idx; \
info.type = type; \
info_path = path; \
info_label = msg_hash_to_str(a); \
info.enum_idx = a; \
dl_type = b;
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_SET(funcname, _id, _flush) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return generic_action_ok(path, label, type, idx, entry_idx, _id, _flush); \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_DIALOG_START(funcname, _label, _idx, _cb) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label_setting, unsigned type, size_t idx, size_t entry_idx) \
{ \
menu_input_ctx_line_t line; \
line.label = _label; \
line.label_setting = label_setting; \
line.type = type; \
line.idx = (_idx); \
line.cb = _cb; \
if (!menu_input_dialog_start(&line)) \
return -1; \
return 0; \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_START_BUILTIN_CORE(funcname, _id) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
content_ctx_info_t content_info; \
content_info.argc = 0; \
content_info.argv = NULL; \
content_info.args = NULL; \
content_info.environ_get = NULL; \
if (!task_push_start_builtin_core(&content_info, _id, NULL, NULL)) \
return -1; \
return 0; \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_LIST(funcname, _id) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return generic_action_ok_network(path, label, type, idx, entry_idx, _id); \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_DOWNLOAD(funcname, _id) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return action_ok_download_generic(path, label, NULL, type, idx, entry_idx,_id); \
}
#define STATIC_DEFAULT_ACTION_OK_CMD_FUNC(func_name, cmd) \
static int (func_name)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
2020-05-29 10:37:01 +02:00
{ \
return generic_action_ok_command(cmd); \
}
#define STATIC_DEFAULT_ACTION_OK_FUNC(func_name, lbl) \
static int (func_name)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return generic_action_ok_displaylist_push(path, NULL, label, type, idx, entry_idx, lbl); \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_FUNC(func_name, lbl) \
2020-05-29 10:37:01 +02:00
int (func_name)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return generic_action_ok_displaylist_push(path, NULL, label, type, idx, entry_idx, lbl); \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_DL_PUSH(funcname, _fbid, _id, _path) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
settings_t *settings = config_get_ptr(); \
(void)settings; \
filebrowser_set_type(_fbid); \
return generic_action_ok_displaylist_push(path, _path, label, type, idx, entry_idx, _id); \
}
2020-06-07 02:41:48 +02:00
#define DEFAULT_ACTION_OK_HELP(funcname, _id, _id2) \
2020-05-29 10:37:01 +02:00
static int (funcname)(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) \
{ \
return generic_action_ok_help(path, label, type, idx, entry_idx, _id, _id2); \
}
2018-01-15 21:44:34 +01:00
static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl)
2018-01-12 04:18:53 +01:00
{
switch (lbl)
{
case ACTION_OK_DL_REMAPPINGS_PORT_LIST:
return MENU_ENUM_LABEL_DEFERRED_REMAPPINGS_PORT_LIST;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PARAMETER:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PARAMETER;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PRESET_PARAMETER:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PRESET_PARAMETER;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES;
case ACTION_OK_DL_DROPDOWN_BOX_LIST:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SPECIAL:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_AUDIO_DEVICE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_AUDIO_DEVICE;
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE;
#endif
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE;
2019-11-29 17:13:35 +00:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME;
2020-01-14 12:28:10 +00:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_DISK_INDEX:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_DISK_INDEX;
2021-02-04 17:06:19 +02:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE;
2020-07-23 17:19:41 +01:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_RESERVED_DEVICE:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_RESERVED_DEVICE;
#ifdef ANDROID
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD;
#endif
#ifdef HAVE_NETWORKING
case ACTION_OK_DL_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER;
#endif
case ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_ACCOUNTS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_LIST;
case ACTION_OK_DL_ACHIEVEMENTS_HARDCORE_PAUSE_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_INPUT_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_SETTINGS_LIST;
case ACTION_OK_DL_INPUT_MENU_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_MENU_SETTINGS_LIST;
2021-03-25 18:45:31 +02:00
case ACTION_OK_DL_INPUT_TURBO_FIRE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_TURBO_FIRE_SETTINGS_LIST;
case ACTION_OK_DL_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST;
case ACTION_OK_DL_LATENCY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_LATENCY_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_DRIVER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_DRIVER_SETTINGS_LIST;
case ACTION_OK_DL_CORE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_SETTINGS_LIST;
2020-05-28 17:48:18 +01:00
case ACTION_OK_DL_CORE_INFORMATION_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST;
#ifdef HAVE_MIST
case ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_STEAM_LIST;
#endif
case ACTION_OK_DL_CORE_RESTORE_BACKUP_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_RESTORE_BACKUP_LIST;
case ACTION_OK_DL_CORE_DELETE_BACKUP_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_DELETE_BACKUP_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_VIDEO_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST;
2019-12-19 19:39:02 +01:00
case ACTION_OK_DL_VIDEO_SYNCHRONIZATION_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_SYNCHRONIZATION_SETTINGS_LIST;
case ACTION_OK_DL_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST;
case ACTION_OK_DL_VIDEO_WINDOWED_MODE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_WINDOWED_MODE_SETTINGS_LIST;
case ACTION_OK_DL_VIDEO_SCALING_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_SCALING_SETTINGS_LIST;
Add HDR support for D3D12 (rebased PR from MajorPainTheCactus) (#12917) * Add HDR support * Attempt to fix Mingw build and Metal builds * (D3D12) Fix relative header includes * Add missing hdr_sm5.hlsl.h * (d3d12_common.c) Some C89 build fixes * Fix MSVC build * - Attempt to fix build on mingw/msys unix with dirty hack - Fix shader compilation of hdr_sm5.hlsl.h on MSVC/Visual Studio - the define was seen as an error and was causing the first pipeline to error out - Make sure we manually set handle of backBuffer to NULL * Moving the release of the texture above the freeing of desc.srv_heap and desc.rtv_heap solves the hard crashes on teardown/setup in RA - it was crashing hard in d3d12_release_texture before * Add HAVE_D3D12_HDR ifdef - needs to be disabled for WinRT for now because of several things that are Windows desktop-specific right now (GetWindowRect) * Add dirty GUID hack - should work for both mingw/msys on Windows/Linux as well as MSVC/Visual Studio (hopefully) * Change HAVE_D3D12_HDR to HAVE_DXGI_HDR * Move away from camelcase named variables * Fix RARCH_ERR logs - they need a newline at the end * d3d12_check_display_hdr_support - make it return a bool on return and set d3d12->hdr.support and d3d12->hdr.enable outside of the function * (DXGI) Remove D3D12 dependencies from dxgi_check_display_hdr_support and move it to dxgi_common.c instead * (DXGI) move d3d12_swapchain_color_space over to dxgi_common.c and rename it dxgi_swapchain_color_space * (DXGI) move d3d12_set_hdr_metadata to dxgi_common.c and rename it dxgi_set_hdr_metadata * (DXGI) dxgi_check_display_hdr_support - better error handling? * Fix typo * Remove video_force_resolution * (D3D12) Address TODO/FIXME * (D3D12) Backport https://github.com/libretro/RetroArch/pull/12916/commits/c1b6c0bff2aa33cde035b43cb31ac7e78ff2a07a - Fixed resource transition for present when HDR is off Fixed cel shader displaying all black as blending was enabled when the hdr shader was being applied - turned off blending during this shader * Move d3d12_hdr_uniform_t to dxgi_common.h and rename it dxgi_hdr_uniform_t * (D3D11) Add HDR support * Add TODO/FIXME notes * Cache hdr_enable in video_frame_info_t * Update comment
2021-09-03 06:15:25 +02:00
case ACTION_OK_DL_VIDEO_HDR_SETTINGS_LIST:
2023-08-16 03:22:02 +02:00
return MENU_ENUM_LABEL_DEFERRED_VIDEO_HDR_SETTINGS_LIST;
2019-12-19 19:15:57 +01:00
case ACTION_OK_DL_VIDEO_OUTPUT_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_OUTPUT_SETTINGS_LIST;
case ACTION_OK_DL_CRT_SWITCHRES_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CRT_SWITCHRES_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST;
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST;
case ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST;
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST;
2019-08-24 18:18:24 +02:00
case ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_FRAME_TIME_COUNTER_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_REWIND_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST;
case ACTION_OK_DL_CHEAT_DETAILS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CHEAT_DETAILS_SETTINGS_LIST;
case ACTION_OK_DL_CHEAT_SEARCH_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CHEAT_SEARCH_SETTINGS_LIST;
2018-01-12 04:18:53 +01:00
case ACTION_OK_DL_ONSCREEN_DISPLAY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ONSCREEN_DISPLAY_SETTINGS_LIST;
case ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST;
2020-07-16 16:30:38 +01:00
case ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_ONSCREEN_OVERLAY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST;
case ACTION_OK_DL_OSK_OVERLAY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_OSK_OVERLAY_SETTINGS_LIST;
case ACTION_OK_DL_OVERLAY_LIGHTGUN_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_OVERLAY_LIGHTGUN_SETTINGS_LIST;
case ACTION_OK_DL_OVERLAY_MOUSE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_OVERLAY_MOUSE_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_MENU_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST;
2022-08-17 08:23:07 +02:00
#ifdef _3DS
case ACTION_OK_DL_MENU_BOTTOM_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MENU_BOTTOM_SETTINGS_LIST;
#endif
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_MENU_VIEWS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MENU_VIEWS_SETTINGS_LIST;
case ACTION_OK_DL_SETTINGS_VIEWS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_SETTINGS_VIEWS_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_QUICK_MENU_VIEWS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_QUICK_MENU_VIEWS_SETTINGS_LIST;
case ACTION_OK_DL_QUICK_MENU_OVERRIDE_OPTIONS_LIST:
return MENU_ENUM_LABEL_DEFERRED_QUICK_MENU_OVERRIDE_OPTIONS;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_USER_INTERFACE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_USER_INTERFACE_SETTINGS_LIST;
2019-08-21 20:43:32 +02:00
case ACTION_OK_DL_AI_SERVICE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AI_SERVICE_SETTINGS_LIST;
case ACTION_OK_DL_ACCESSIBILITY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCESSIBILITY_SETTINGS_LIST;
2018-06-19 06:23:38 +02:00
case ACTION_OK_DL_POWER_MANAGEMENT_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_POWER_MANAGEMENT_SETTINGS_LIST;
case ACTION_OK_DL_CPU_PERFPOWER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CPU_PERFPOWER_LIST;
case ACTION_OK_DL_CPU_POLICY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CPU_POLICY_ENTRY;
2019-01-27 11:22:16 -05:00
case ACTION_OK_DL_MENU_SOUNDS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MENU_SOUNDS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_MENU_FILE_BROWSER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MENU_FILE_BROWSER_SETTINGS_LIST;
case ACTION_OK_DL_RETRO_ACHIEVEMENTS_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_RETRO_ACHIEVEMENTS_SETTINGS_LIST;
case ACTION_OK_DL_CHEEVOS_APPEARANCE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CHEEVOS_APPEARANCE_SETTINGS_LIST;
case ACTION_OK_DL_CHEEVOS_VISIBILITY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_CHEEVOS_VISIBILITY_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_UPDATER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_UPDATER_SETTINGS_LIST;
2019-12-30 03:01:52 +01:00
case ACTION_OK_DL_NETWORK_HOSTING_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETWORK_HOSTING_SETTINGS_LIST;
case ACTION_OK_DL_NETPLAY_KICK_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETPLAY_KICK_LIST;
2022-07-07 11:08:46 -03:00
case ACTION_OK_DL_NETPLAY_BAN_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETPLAY_BAN_LIST;
case ACTION_OK_DL_NETPLAY_LOBBY_FILTERS_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETPLAY_LOBBY_FILTERS_LIST;
case ACTION_OK_DL_SUBSYSTEM_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_SUBSYSTEM_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_NETWORK_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETWORK_SETTINGS_LIST;
2020-06-17 14:56:44 +03:00
case ACTION_OK_DL_BLUETOOTH_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_BLUETOOTH_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_WIFI_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_WIFI_SETTINGS_LIST;
case ACTION_OK_DL_WIFI_NETWORKS_LIST:
return MENU_ENUM_LABEL_DEFERRED_WIFI_NETWORKS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_NETPLAY:
return MENU_ENUM_LABEL_DEFERRED_NETPLAY;
case ACTION_OK_DL_NETPLAY_LAN_SCAN_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_NETPLAY_LAN_SCAN_SETTINGS_LIST;
case ACTION_OK_DL_LAKKA_SERVICES_LIST:
return MENU_ENUM_LABEL_DEFERRED_LAKKA_SERVICES_LIST;
#ifdef HAVE_LAKKA_SWITCH
case ACTION_OK_DL_LAKKA_SWITCH_OPTIONS_LIST:
return MENU_ENUM_LABEL_DEFERRED_LAKKA_SWITCH_OPTIONS_LIST;
#endif
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_USER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST;
case ACTION_OK_DL_DIRECTORY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST;
case ACTION_OK_DL_PRIVACY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST;
2018-06-04 07:48:08 +02:00
case ACTION_OK_DL_MIDI_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_AUDIO_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST;
case ACTION_OK_DL_AUDIO_OUTPUT_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AUDIO_OUTPUT_SETTINGS_LIST;
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
case ACTION_OK_DL_MICROPHONE_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MICROPHONE_SETTINGS_LIST;
#endif
case ACTION_OK_DL_AUDIO_SYNCHRONIZATION_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AUDIO_SYNCHRONIZATION_SETTINGS_LIST;
case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AUDIO_MIXER_SETTINGS_LIST;
case ACTION_OK_DL_INPUT_RETROPAD_BINDS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_RETROPAD_BINDS_LIST;
2018-01-12 04:42:44 +01:00
case ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST:
return MENU_ENUM_LABEL_DEFERRED_INPUT_HOTKEY_BINDS_LIST;
2018-01-12 04:51:15 +01:00
case ACTION_OK_DL_RECORDING_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_RECORDING_SETTINGS_LIST;
case ACTION_OK_DL_PLAYLIST_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_PLAYLIST_SETTINGS_LIST;
case ACTION_OK_DL_PLAYLIST_MANAGER_LIST:
return MENU_ENUM_LABEL_DEFERRED_PLAYLIST_MANAGER_LIST;
case ACTION_OK_DL_PLAYLIST_MANAGER_SETTINGS:
return MENU_ENUM_LABEL_DEFERRED_PLAYLIST_MANAGER_SETTINGS;
2018-01-12 04:51:15 +01:00
case ACTION_OK_DL_ACCOUNTS_CHEEVOS_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_CHEEVOS_LIST;
2018-09-26 23:00:00 +02:00
case ACTION_OK_DL_ACCOUNTS_TWITCH_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_TWITCH_LIST;
2020-12-19 15:14:14 +03:00
case ACTION_OK_DL_ACCOUNTS_FACEBOOK_LIST:
2023-08-16 03:22:02 +02:00
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_FACEBOOK_LIST;
case ACTION_OK_DL_DUMP_DISC_LIST:
return MENU_ENUM_LABEL_DEFERRED_DUMP_DISC_LIST;
#ifdef HAVE_LAKKA
case ACTION_OK_DL_EJECT_DISC:
return MENU_ENUM_LABEL_DEFERRED_EJECT_DISC;
#endif
2019-07-05 19:55:04 +02:00
case ACTION_OK_DL_LOAD_DISC_LIST:
return MENU_ENUM_LABEL_DEFERRED_LOAD_DISC_LIST;
2018-09-26 23:00:00 +02:00
case ACTION_OK_DL_ACCOUNTS_YOUTUBE_LIST:
return MENU_ENUM_LABEL_DEFERRED_ACCOUNTS_YOUTUBE_LIST;
2018-01-12 04:51:15 +01:00
case ACTION_OK_DL_PLAYLIST_COLLECTION:
return MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST;
case ACTION_OK_DL_FAVORITES_LIST:
return MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST;
case ACTION_OK_DL_BROWSE_URL_LIST:
return MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_LIST;
2018-01-12 05:27:09 +01:00
case ACTION_OK_DL_MUSIC_LIST:
return MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST;
case ACTION_OK_DL_IMAGES_LIST:
return MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST;
2019-07-11 06:34:27 +02:00
case ACTION_OK_DL_CDROM_INFO_DETAIL_LIST:
return MENU_ENUM_LABEL_DEFERRED_CDROM_INFO_LIST;
2019-08-24 01:44:50 +02:00
case ACTION_OK_DL_SHADER_PRESET_SAVE:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_SHADER_PRESET_SAVE_LIST;
case ACTION_OK_DL_SHADER_PRESET_REMOVE:
return MENU_ENUM_LABEL_DEFERRED_VIDEO_SHADER_PRESET_REMOVE_LIST;
2019-11-29 17:13:35 +00:00
case ACTION_OK_DL_MANUAL_CONTENT_SCAN_LIST:
return MENU_ENUM_LABEL_DEFERRED_MANUAL_CONTENT_SCAN_LIST;
2020-06-11 14:12:20 +01:00
case ACTION_OK_DL_CORE_MANAGER_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_LIST;
#ifdef HAVE_MIST
case ACTION_OK_DL_STEAM_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_STEAM_SETTINGS_LIST;
case ACTION_OK_DL_CORE_MANAGER_STEAM_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_MANAGER_STEAM_LIST;
#endif
case ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST:
return MENU_ENUM_LABEL_DEFERRED_CORE_OPTION_OVERRIDE_LIST;
case ACTION_OK_DL_REMAP_FILE_MANAGER_LIST:
return MENU_ENUM_LABEL_DEFERRED_REMAP_FILE_MANAGER_LIST;
case ACTION_OK_DL_ADD_TO_PLAYLIST:
return MENU_ENUM_LABEL_DEFERRED_ADD_TO_PLAYLIST_LIST;
2018-01-12 04:18:53 +01:00
default:
break;
}
2018-01-15 21:44:34 +01:00
return MSG_UNKNOWN;
2018-01-12 04:18:53 +01:00
}
static void action_ok_get_file_browser_start_path(
const char *current_path, const char *default_path,
2024-12-25 19:06:04 +01:00
char *s, size_t len, bool set_pending)
{
const char *pending_selection = NULL;
bool current_path_valid = false;
2024-12-25 19:06:04 +01:00
if (!s || (len < 1))
return;
/* Parse current path */
if (!string_is_empty(current_path))
{
/* Start path is the parent directory of
* the current path */
2024-12-25 19:06:04 +01:00
fill_pathname_parent_dir(s, current_path, len);
/* 'Pending selection' is the basename of
* the current path - either a file name
* or a directory name */
pending_selection = path_basename(current_path);
/* Check if current path is valid */
2024-12-25 19:06:04 +01:00
if ( path_is_directory(s)
2023-07-15 15:14:26 +02:00
&& !string_is_empty(pending_selection))
current_path_valid = true;
}
/* If current path is invalid, use default path */
if (!current_path_valid)
{
2024-12-24 05:10:09 +01:00
if ( string_is_empty(default_path)
|| !path_is_directory(default_path))
{
2024-12-25 19:06:04 +01:00
s[0] = '\0';
return;
}
2024-12-25 19:06:04 +01:00
strlcpy(s, default_path, len);
return;
}
/* Current path is valid - set pending selection,
* if required */
else if (set_pending)
menu_driver_set_pending_selection(pending_selection);
}
static void menu_driver_set_last_start_content(struct menu_state *menu_st, const char *start_content_path)
{
char archive_path[PATH_MAX_LENGTH];
menu_handle_t *menu = menu_st->driver_data;
settings_t *settings = config_get_ptr();
bool use_last = settings->bools.use_last_start_directory;
const char *archive_delim = NULL;
const char *file_name = NULL;
if (!menu)
return;
/* Reset existing cache */
menu->last_start_content.directory[0] = '\0';
menu->last_start_content.file_name[0] = '\0';
/* If 'use_last_start_directory' is disabled or
* path is empty, do nothing */
if (!use_last ||
string_is_empty(start_content_path))
return;
/* Cache directory */
fill_pathname_parent_dir(menu->last_start_content.directory,
start_content_path, sizeof(menu->last_start_content.directory));
/* Cache file name */
if ((archive_delim = path_get_archive_delim(start_content_path)))
{
/* If path references a file inside an
* archive, must extract the string segment
* before the archive delimiter (i.e. path of
* 'parent' archive file) */
size_t _len = (size_t)(1 + archive_delim - start_content_path);
if (_len >= PATH_MAX_LENGTH)
_len = PATH_MAX_LENGTH;
strlcpy(archive_path, start_content_path, _len * sizeof(char));
file_name = path_basename(archive_path);
}
else
file_name = path_basename_nocompression(start_content_path);
if (!string_is_empty(file_name))
strlcpy(menu->last_start_content.file_name, file_name,
sizeof(menu->last_start_content.file_name));
}
static const char *menu_driver_get_last_start_file_name(void)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
settings_t *settings = config_get_ptr();
bool use_last = settings->bools.use_last_start_directory;
/* Return NULL if there is no last 'file name' */
2023-08-16 03:22:02 +02:00
if ( !menu
|| !use_last
|| string_is_empty(menu->last_start_content.file_name))
return NULL;
return menu->last_start_content.file_name;
}
static const char *menu_driver_get_last_start_directory(void)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
settings_t *settings = config_get_ptr();
bool use_last = settings->bools.use_last_start_directory;
const char *default_directory = settings->paths.directory_menu_content;
/* Also treat content launched from CLI as last start content */
if ( menu
&& use_last
&& string_is_empty(menu->last_start_content.file_name)
&& !string_is_empty(path_get(RARCH_PATH_CONTENT)))
menu_driver_set_last_start_content(menu_st, path_get(RARCH_PATH_CONTENT));
/* Return default directory if there is no
* last directory or it's invalid */
if ( !menu
|| !use_last
|| string_is_empty(menu->last_start_content.directory)
|| !path_is_directory(menu->last_start_content.directory))
return default_directory;
return menu->last_start_content.directory;
}
2023-07-17 22:32:13 +03:00
int generic_action_ok_displaylist_push(
const char *path, const char *new_path,
const char *label, unsigned type,
size_t idx, size_t entry_idx,
2015-09-04 13:08:15 +02:00
unsigned action_type)
{
2019-04-20 19:51:08 +02:00
menu_displaylist_info_t info;
2016-10-08 19:44:03 +02:00
char tmp[PATH_MAX_LENGTH];
char parent_dir[DIR_MAX_LENGTH];
2016-07-08 20:47:17 +02:00
enum menu_displaylist_ctl_state dl_type = DISPLAYLIST_NONE;
const char *menu_label = NULL;
const char *menu_path = NULL;
const char *content_path = NULL;
const char *info_label = NULL;
const char *info_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_dialog_t *p_dialog = &menu_st->dialog_st;
menu_handle_t *menu = menu_st->driver_data;
menu_list_t *menu_list = menu_st->entries.list;
settings_t *settings = config_get_ptr();
const char *menu_ident = (menu_st->driver_ctx && menu_st->driver_ctx->ident) ? menu_st->driver_ctx->ident : NULL;
file_list_t *menu_stack = MENU_LIST_GET(menu_list, 0);
2020-02-19 22:06:21 +01:00
#ifdef HAVE_AUDIOMIXER
bool audio_enable_menu = settings->bools.audio_enable_menu;
bool audio_enable_menu_ok = settings->bools.audio_enable_menu_ok;
#endif
2020-02-21 03:28:23 +01:00
const char *dir_menu_content = settings->paths.directory_menu_content;
const char *dir_libretro = settings->paths.directory_libretro;
2021-11-10 02:34:04 +01:00
recording_state_t *recording_st = recording_state_get_ptr();
2016-02-10 21:15:23 +01:00
if (!menu || string_is_equal(menu_ident, "null"))
{
menu_displaylist_info_free(&info);
return -1;
}
2019-08-16 15:17:02 +02:00
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2020-02-19 22:06:21 +01:00
if (audio_enable_menu && audio_enable_menu_ok)
2019-01-27 11:22:16 -05:00
audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_OK);
2019-07-11 11:51:06 +02:00
#endif
2019-01-27 11:22:16 -05:00
2017-09-10 22:38:03 +02:00
menu_displaylist_info_init(&info);
2017-09-11 00:23:04 +02:00
info.list = menu_stack;
tmp[0] = parent_dir[0] = '\0';
2016-10-08 19:44:03 +02:00
menu_entries_get_last_stack(&menu_path, &menu_label, NULL, NULL, NULL);
2015-09-04 13:08:15 +02:00
switch (action_type)
{
2016-12-27 00:02:09 +01:00
case ACTION_OK_DL_BROWSE_URL_START:
info.type = type;
info.directory_ptr = idx;
2017-09-11 00:23:04 +02:00
info_path = NULL;
2016-12-27 00:02:09 +01:00
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_BROWSE_URL_START;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_VIDEO_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = label;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_EXPLORE_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = label;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_EXPLORE_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_EXPLORE_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
2022-02-22 18:23:48 +00:00
case ACTION_OK_DL_CONTENTLESS_CORES_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = label;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_CONTENTLESS_CORES_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CONTENTLESS_CORES_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_REMAPPINGS_PORT_LIST:
info.type = type;
info.directory_ptr = idx;
info.path = strdup(label);
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_REMAPPINGS_PORT_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_REMAPPINGS_PORT_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SPECIAL:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_SPECIAL;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PARAMETER:
info.type = (unsigned)(MENU_SETTINGS_SHADER_PARAMETER_0 + idx);
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PARAMETER);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PARAMETER;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PRESET_PARAMETER:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PRESET_PARAMETER);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_PRESET_PARAMETER;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_RESOLUTION;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE;
dl_type = DISPLAYLIST_GENERIC;
break;
2019-11-29 17:13:35 +00:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME;
dl_type = DISPLAYLIST_GENERIC;
break;
2020-01-14 12:28:10 +00:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_DISK_INDEX:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_DISK_INDEX);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_DISK_INDEX;
dl_type = DISPLAYLIST_GENERIC;
break;
2021-02-04 17:06:19 +02:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_RESERVED_DEVICE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_RESERVED_DEVICE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_RESERVED_DEVICE;
dl_type = DISPLAYLIST_GENERIC;
break;
#ifdef ANDROID
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD;
dl_type = DISPLAYLIST_GENERIC;
break;
#endif
2020-07-23 17:19:41 +01:00
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_AUDIO_DEVICE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_AUDIO_DEVICE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_AUDIO_DEVICE;
dl_type = DISPLAYLIST_GENERIC;
break;
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
case ACTION_OK_DL_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MICROPHONE_DEVICE;
dl_type = DISPLAYLIST_GENERIC;
break;
#endif
#ifdef HAVE_NETWORKING
case ACTION_OK_DL_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER;
dl_type = DISPLAYLIST_GENERIC;
break;
#endif
case ACTION_OK_DL_USER_BINDS_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = label;
info_label = msg_hash_to_str(
2016-06-16 12:56:10 +02:00
MENU_ENUM_LABEL_DEFERRED_USER_BINDS_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_USER_BINDS_LIST;
2021-02-04 17:06:19 +02:00
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_MUSIC:
if (!string_is_empty(path))
strlcpy(menu->scratch_buf, path, sizeof(menu->scratch_buf));
if (!string_is_empty(menu_path))
strlcpy(menu->scratch2_buf, menu_path, sizeof(menu->scratch2_buf));
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_MUSIC);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_MUSIC;
info_path = path;
info.type = type;
info.directory_ptr = idx;
dl_type = DISPLAYLIST_GENERIC;
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_OPEN_ARCHIVE_DETECT_CORE:
if (menu)
{
#if IOS
fill_pathname_expand_special(tmp, menu->scratch2_buf, sizeof(tmp));
menu_path = tmp;
#else
2015-12-10 14:00:28 +01:00
menu_path = menu->scratch2_buf;
#endif
2015-09-04 13:08:15 +02:00
content_path = menu->scratch_buf;
}
if (content_path)
2024-04-29 21:30:15 -04:00
{
if (path_is_absolute(content_path))
strlcpy(menu->detect_content_path, content_path, sizeof(menu->detect_content_path));
else
fill_pathname_join_special(menu->detect_content_path,
menu_path, content_path,
sizeof(menu->detect_content_path));
}
2015-09-04 13:08:15 +02:00
info_label = msg_hash_to_str(
2016-06-18 18:45:11 +02:00
MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE;
info_path = path;
info.type = type;
info.directory_ptr = idx;
2021-02-04 17:06:19 +02:00
dl_type = DISPLAYLIST_GENERIC;
2016-06-18 18:45:11 +02:00
break;
case ACTION_OK_DL_OPEN_ARCHIVE:
if (menu)
2015-09-04 13:08:15 +02:00
{
2016-06-18 18:45:11 +02:00
menu_path = menu->scratch2_buf;
content_path = menu->scratch_buf;
2015-09-04 13:08:15 +02:00
}
2016-06-18 18:45:11 +02:00
if (content_path)
fill_pathname_join_special(menu->detect_content_path,
menu_path, content_path,
sizeof(menu->detect_content_path));
2016-06-18 18:45:11 +02:00
info_label = msg_hash_to_str(
2016-06-18 18:45:11 +02:00
MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN;
2015-09-07 00:38:23 +02:00
info_path = path;
2015-09-04 13:08:15 +02:00
info.type = type;
info.directory_ptr = idx;
2021-02-04 17:06:19 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_HELP:
2016-09-04 22:58:54 +02:00
info_label = label;
2015-09-04 13:08:15 +02:00
dl_type = DISPLAYLIST_HELP;
p_dialog->current_type = (enum menu_dialog_type)type;
p_dialog->pending_push = true;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_RPL_ENTRY:
strlcpy(menu->deferred_path, label, sizeof(menu->deferred_path));
info_label = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS;
info.directory_ptr = idx;
2020-07-31 15:13:43 +01:00
menu->rpl_entry_selection_ptr = (unsigned)entry_idx;
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_AUDIO_DSP_PLUGIN:
filebrowser_clear_type();
2015-09-04 13:08:15 +02:00
info.directory_ptr = idx;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
settings->paths.path_audio_dsp_plugin,
settings->paths.directory_audio_filter,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
break;
case ACTION_OK_DL_VIDEO_FILTER:
filebrowser_clear_type();
info.directory_ptr = idx;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_FILTER);
info.enum_idx = MENU_ENUM_LABEL_VIDEO_FILTER;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
settings->paths.path_softfilter_plugin,
settings->paths.directory_video_filter,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
break;
case ACTION_OK_DL_OVERLAY_PRESET:
filebrowser_clear_type();
info.directory_ptr = idx;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_OVERLAY_PRESET);
info.enum_idx = MENU_ENUM_LABEL_OVERLAY_PRESET;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
settings->paths.path_overlay,
settings->paths.directory_overlay,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
break;
case ACTION_OK_DL_OSK_OVERLAY_PRESET:
filebrowser_clear_type();
info.directory_ptr = idx;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_OSK_OVERLAY_PRESET);
info.enum_idx = MENU_ENUM_LABEL_OSK_OVERLAY_PRESET;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
settings->paths.path_osk_overlay,
settings->paths.directory_osk_overlay,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
break;
case ACTION_OK_DL_VIDEO_FONT:
filebrowser_set_type(FILEBROWSER_SELECT_VIDEO_FONT);
info.directory_ptr = idx;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_FONT_PATH);
info.enum_idx = MENU_ENUM_LABEL_VIDEO_FONT_PATH;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
settings->paths.path_font,
settings->paths.directory_assets,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_SHADER_PARAMETERS:
info.type = MENU_SETTING_ACTION;
info.directory_ptr = idx;
2016-06-17 23:47:23 +02:00
info_label = label;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_GENERIC:
if (path)
strlcpy(menu->deferred_path, path,
sizeof(menu->deferred_path));
info.type = type;
info.directory_ptr = idx;
2016-06-17 23:47:23 +02:00
info_label = label;
2021-02-04 17:06:19 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_FILE_BROWSER_SELECT_FILE:
if (path)
strlcpy(menu->deferred_path, path,
sizeof(menu->deferred_path));
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
break;
case ACTION_OK_DL_FILE_BROWSER_SELECT_DIR:
if (path)
strlcpy(menu->deferred_path, path,
sizeof(menu->deferred_path));
info.type = type;
info.directory_ptr = idx;
info_label = label;
info_path = new_path;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_DIR;
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_PUSH_DEFAULT:
info.type = type;
info.directory_ptr = idx;
info_path = label;
2016-06-17 23:47:23 +02:00
info_label = label;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_SHADER_PASS:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
const char *shader_file_name = NULL;
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
menu_driver_get_last_shader_pass_path(&info_path, &shader_file_name);
menu_driver_set_pending_selection(shader_file_name);
}
#endif
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_SHADER_PRESET:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
const char *shader_file_name = NULL;
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
menu_driver_get_last_shader_preset_path(&info_path, &shader_file_name);
menu_driver_set_pending_selection(shader_file_name);
}
#endif
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_SHADER_PRESET_PREPEND:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
const char *shader_file_name = NULL;
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
menu_driver_get_last_shader_preset_path(&info_path, &shader_file_name);
menu_driver_set_pending_selection(shader_file_name);
}
#endif
break;
case ACTION_OK_DL_SHADER_PRESET_APPEND:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
const char *shader_file_name = NULL;
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
menu_driver_get_last_shader_preset_path(&info_path, &shader_file_name);
menu_driver_set_pending_selection(shader_file_name);
}
#endif
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CONTENT_LIST:
2016-06-20 15:50:37 +02:00
info.type = FILE_TYPE_DIRECTORY;
2015-09-04 13:08:15 +02:00
info.directory_ptr = idx;
2016-07-09 18:12:35 +02:00
info_path = new_path;
2015-09-07 00:38:23 +02:00
info_label = label;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
/* If this is the 'Start Directory' content
* list, use last selected directory/file */
2023-07-15 15:14:26 +02:00
if ( (type == MENU_SETTING_ACTION_FAVORITES_DIR)
&& settings->bools.use_last_start_directory)
{
info_path = menu_driver_get_last_start_directory();
menu_driver_set_pending_selection(
menu_driver_get_last_start_file_name());
}
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_SCAN_DIR_LIST:
filebrowser_set_type(FILEBROWSER_SCAN_DIR);
info.type = FILE_TYPE_DIRECTORY;
info.directory_ptr = idx;
info_path = new_path;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SCAN_DIR;
break;
2019-11-29 17:13:35 +00:00
case ACTION_OK_DL_MANUAL_SCAN_DIR_LIST:
filebrowser_set_type(FILEBROWSER_MANUAL_SCAN_DIR);
info.type = FILE_TYPE_DIRECTORY;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_DIR;
action_ok_get_file_browser_start_path(
manual_content_scan_get_content_dir_ptr(),
new_path, parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
2019-11-29 17:13:35 +00:00
break;
case ACTION_OK_DL_MANUAL_CONTENT_SCAN_DAT_FILE:
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
action_ok_get_file_browser_start_path(
manual_content_scan_get_dat_file_path_ptr(),
dir_menu_content, parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_REMAP_FILE:
2020-08-14 12:57:58 +03:00
{
struct retro_system_info *sysinfo = &runloop_state_get_ptr()->system.info;
const char *core_name = sysinfo ? sysinfo->library_name : NULL;
2020-08-14 12:57:58 +03:00
2023-08-16 03:22:02 +02:00
if ( !string_is_empty(core_name)
2023-07-15 15:14:26 +02:00
&& !string_is_empty(settings->paths.directory_input_remapping))
2020-08-14 12:57:58 +03:00
{
fill_pathname_join_special(tmp,
2020-08-14 12:57:58 +03:00
settings->paths.directory_input_remapping, core_name, sizeof(tmp));
if (!path_is_directory(tmp))
tmp[0] = '\0';
}
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_path = !string_is_empty(tmp) ? tmp : settings->paths.directory_input_remapping;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_OVERRIDE_FILE:
{
struct retro_system_info *sysinfo = &runloop_state_get_ptr()->system.info;
const char *core_name = sysinfo ? sysinfo->library_name : NULL;
if (!string_is_empty(core_name))
{
fill_pathname_join_special(tmp,
settings->paths.directory_menu_config,
core_name, sizeof(tmp));
if (!path_is_directory(tmp))
tmp[0] = '\0';
}
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_path = !string_is_empty(tmp) ? tmp : settings->paths.directory_menu_config;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
break;
2018-09-26 23:50:29 +02:00
case ACTION_OK_DL_STREAM_CONFIGFILE:
2018-10-13 16:06:43 -05:00
{
info.type = type;
info.directory_ptr = idx;
2021-11-10 02:34:04 +01:00
info_path = recording_st->config_dir;
2018-10-13 16:06:43 -05:00
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
2018-09-26 23:50:29 +02:00
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_RECORD_CONFIGFILE:
filebrowser_clear_type();
{
info.type = type;
info.directory_ptr = idx;
2021-11-10 02:34:04 +01:00
info_path = recording_st->config_dir;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_DISK_IMAGE_APPEND_LIST:
{
filebrowser_clear_type();
fill_pathname_basedir(tmp,
path_get(RARCH_PATH_CONTENT), sizeof(tmp));
info.type = type;
info.directory_ptr = idx;
2020-02-21 03:28:23 +01:00
info_path = !string_is_empty(tmp) ? tmp : dir_menu_content;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
/* Focus on current content entry */
2022-06-18 08:54:14 +03:00
{
char path_content[PATH_MAX_LENGTH];
strlcpy(path_content, path_get(RARCH_PATH_CONTENT), sizeof(path_content));
/* Remove archive browsed file from the path */
{
char *delim = (char*)strchr(path_content, '#');
if (delim)
*delim = '\0';
2022-06-18 08:54:14 +03:00
}
menu_driver_set_pending_selection(path_basename(path_content));
}
}
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_SUBSYSTEM_ADD_LIST:
{
filebrowser_clear_type();
2018-12-16 11:39:38 -05:00
if (content_get_subsystem_rom_id() > 0)
strlcpy(tmp, content_get_subsystem_rom(content_get_subsystem_rom_id() - 1), sizeof(tmp));
2018-12-16 11:39:38 -05:00
else
strlcpy(tmp, path_get(RARCH_PATH_CONTENT), sizeof(tmp));
2020-08-04 03:05:20 +02:00
path_basedir(tmp);
if (content_get_subsystem() != (int)type - MENU_SETTINGS_SUBSYSTEM_ADD)
content_clear_subsystem();
content_set_subsystem(type - MENU_SETTINGS_SUBSYSTEM_ADD);
filebrowser_set_type(FILEBROWSER_SELECT_FILE_SUBSYSTEM);
info.type = type;
info.directory_ptr = idx;
2020-02-21 03:28:23 +01:00
info_path = !string_is_empty(tmp) ? tmp : dir_menu_content;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
break;
2018-02-10 20:23:24 -05:00
case ACTION_OK_DL_SUBSYSTEM_LOAD:
2018-02-11 10:00:08 -05:00
{
content_ctx_info_t content_info = {0};
filebrowser_clear_type();
2021-10-15 14:43:25 +02:00
task_push_load_subsystem_with_core(
2018-02-11 10:00:08 -05:00
NULL, &content_info,
CORE_TYPE_PLAIN, NULL, NULL);
}
2018-02-10 20:23:24 -05:00
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CHEAT_FILE:
case ACTION_OK_DL_CHEAT_FILE_APPEND:
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_path = settings->paths.path_cheat_database;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
2020-06-30 19:35:41 +02:00
#endif
break;
case ACTION_OK_DL_RGUI_MENU_THEME_PRESET:
{
char rgui_assets_dir[DIR_MAX_LENGTH];
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
fill_pathname_join_special(rgui_assets_dir,
settings->paths.directory_assets, "rgui",
sizeof(rgui_assets_dir));
action_ok_get_file_browser_start_path(
settings->paths.path_rgui_theme_preset,
rgui_assets_dir,
parent_dir, sizeof(parent_dir), true);
info_path = parent_dir;
}
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CORE_LIST:
filebrowser_clear_type();
2015-09-04 13:08:15 +02:00
info.type = type;
info.directory_ptr = idx;
2020-02-21 03:28:23 +01:00
info_path = dir_libretro;
2015-09-07 00:38:23 +02:00
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_CORE;
2015-09-04 13:08:15 +02:00
break;
2018-12-06 15:54:25 -05:00
case ACTION_OK_DL_SIDELOAD_CORE_LIST:
filebrowser_clear_type();
info.type = type;
info.directory_ptr = idx;
info_path = settings->paths.directory_core_assets;
info_label = label;
2020-01-09 14:13:21 +00:00
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
2018-12-06 15:54:25 -05:00
break;
2022-04-06 01:58:48 +03:00
case ACTION_OK_DL_SAVESTATE_LIST:
2021-08-06 15:32:51 +01:00
case ACTION_OK_DL_CORE_OPTIONS_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = label;
dl_type = DISPLAYLIST_GENERIC;
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CONTENT_COLLECTION_LIST:
info.type = type;
info.directory_ptr = idx;
2017-04-29 00:39:29 +02:00
info_path = settings->paths.directory_playlist;
2015-09-07 00:38:23 +02:00
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_COLLECTION;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_RDB_ENTRY:
filebrowser_clear_type();
2016-01-25 18:18:00 +01:00
fill_pathname_join_delim(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL),
2015-09-07 00:32:01 +02:00
path, '|', sizeof(tmp));
2015-09-04 13:08:15 +02:00
2015-09-07 00:32:01 +02:00
info.directory_ptr = idx;
2015-09-07 00:38:23 +02:00
info_path = label;
info_label = tmp;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_RDB_ENTRY_SUBMENU:
info.directory_ptr = idx;
2015-09-07 00:38:23 +02:00
info_label = label;
info_path = path;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_CONFIGURATIONS_LIST:
2015-09-04 13:08:15 +02:00
info.type = type;
info.directory_ptr = idx;
2017-04-29 00:39:29 +02:00
if (string_is_empty(settings->paths.directory_menu_config))
2015-09-07 00:38:23 +02:00
info_path = label;
else
2017-04-29 00:39:29 +02:00
info_path = settings->paths.directory_menu_config;
2021-02-04 17:06:19 +02:00
info_label = label;
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH_DETECT_CORE:
2016-06-18 18:45:11 +02:00
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
2016-06-18 18:45:11 +02:00
MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION_DETECT_CORE);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION_DETECT_CORE;
if (!string_is_empty(path))
strlcpy(menu->scratch_buf, path, sizeof(menu->scratch_buf));
if (!string_is_empty(menu_path))
strlcpy(menu->scratch2_buf, menu_path, sizeof(menu->scratch2_buf));
2016-07-10 02:26:20 +02:00
dl_type = DISPLAYLIST_GENERIC;
2016-06-18 18:45:11 +02:00
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH:
info.type = type;
info.directory_ptr = idx;
2015-09-07 00:38:23 +02:00
info_path = path;
info_label = msg_hash_to_str(
2016-06-18 18:45:11 +02:00
MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_ARCHIVE_ACTION;
2015-09-04 13:08:15 +02:00
if (!string_is_empty(path))
strlcpy(menu->scratch_buf, path, sizeof(menu->scratch_buf));
if (!string_is_empty(menu_path))
strlcpy(menu->scratch2_buf, menu_path, sizeof(menu->scratch2_buf));
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
2015-10-25 08:31:55 +01:00
case ACTION_OK_DL_PARENT_DIRECTORY_PUSH:
2017-09-18 16:35:31 +02:00
parent_dir[0] = '\0';
2017-09-11 03:04:55 +02:00
2017-09-18 16:35:31 +02:00
if (path && menu_path)
{
#if IOS
fill_pathname_expand_special(parent_dir, menu_path, sizeof(parent_dir));
fill_pathname_join_special(tmp,
parent_dir, path, sizeof(tmp));
#else
fill_pathname_join_special(tmp,
2017-09-18 16:35:31 +02:00
menu_path, path, sizeof(tmp));
#endif
}
2015-10-25 08:31:55 +01:00
2017-09-18 16:35:31 +02:00
fill_pathname_parent_dir(parent_dir,
tmp, sizeof(parent_dir));
fill_pathname_parent_dir(parent_dir,
parent_dir, sizeof(parent_dir));
2017-09-11 00:23:04 +02:00
#if IOS
fill_pathname_abbreviate_special(tmp, parent_dir, sizeof(tmp));
strlcpy(parent_dir, tmp, sizeof(parent_dir));
#endif
2017-09-18 16:35:31 +02:00
info.type = type;
info.directory_ptr = idx;
info_path = parent_dir;
info_label = menu_label;
dl_type = DISPLAYLIST_GENERIC;
2015-10-25 08:31:55 +01:00
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_DIRECTORY_PUSH:
if (!string_is_empty(path))
{
if (!string_is_empty(menu_path))
fill_pathname_join_special(
tmp, menu_path, path, sizeof(tmp));
else
strlcpy(tmp, path, sizeof(tmp));
}
2017-09-11 00:23:04 +02:00
info.type = type;
info.directory_ptr = idx;
info_path = tmp;
info_label = menu_label;
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_DATABASE_MANAGER_LIST:
2017-09-11 00:23:04 +02:00
{
char lpl_basename[NAME_MAX_LENGTH];
2023-08-16 03:22:02 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
2017-09-11 00:23:04 +02:00
filebrowser_clear_type();
fill_pathname_join_special(tmp,
2017-09-11 00:23:04 +02:00
settings->paths.path_content_database,
path, sizeof(tmp));
fill_pathname(lpl_basename, path_basename(path), "",
sizeof(lpl_basename));
gfx_thumbnail_set_system(menu_st->thumbnail_path_data, lpl_basename,
playlist_get_cached());
2017-09-11 00:23:04 +02:00
info.directory_ptr = idx;
info_path = tmp;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DATABASE_MANAGER_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DATABASE_MANAGER_LIST;
dl_type = DISPLAYLIST_GENERIC;
2017-09-11 00:23:04 +02:00
}
2015-09-04 13:08:15 +02:00
break;
/* Pending clear */
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CORE_UPDATER_LIST:
info.type = type;
info.directory_ptr = idx;
2015-09-07 00:38:23 +02:00
info_path = path;
info_label = msg_hash_to_str(
2016-06-16 12:56:10 +02:00
MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST;
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_PENDING_CLEAR;
2015-09-04 13:08:15 +02:00
break;
#if 0
/* Thumbnailpack removal */
case ACTION_OK_DL_THUMBNAILS_UPDATER_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
2016-06-16 12:56:10 +02:00
MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST;
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_PENDING_CLEAR;
break;
#endif
case ACTION_OK_DL_PL_THUMBNAILS_UPDATER_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_PL_THUMBNAILS_UPDATER_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_PL_THUMBNAILS_UPDATER_LIST;
dl_type = DISPLAYLIST_PENDING_CLEAR;
break;
2016-06-21 00:46:55 +02:00
case ACTION_OK_DL_CORE_CONTENT_DIRS_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST;
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_PENDING_CLEAR;
2016-06-21 00:46:55 +02:00
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_CORE_CONTENT_LIST:
info.type = type;
info.directory_ptr = idx;
2015-09-07 00:38:23 +02:00
info_path = path;
info_label = msg_hash_to_str(
2016-06-16 12:56:10 +02:00
MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_LIST;
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_PENDING_CLEAR;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_LAKKA_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_LAKKA_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_LAKKA_LIST;
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_PENDING_CLEAR;
break;
case ACTION_OK_DL_CORE_CONTENT_DIRS_SUBDIR_LIST:
fill_pathname_join_delim(tmp, path, label, ';',
sizeof(tmp));
info.type = type;
info.directory_ptr = idx;
info_path = tmp;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_SUBDIR_LIST;
dl_type = DISPLAYLIST_GENERIC;
break;
case ACTION_OK_DL_CORE_SYSTEM_FILES_LIST:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_CORE_SYSTEM_FILES_LIST);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_SYSTEM_FILES_LIST;
dl_type = DISPLAYLIST_PENDING_CLEAR;
break;
2015-09-04 13:08:15 +02:00
case ACTION_OK_DL_DEFERRED_CORE_LIST:
info.directory_ptr = idx;
2020-02-21 03:28:23 +01:00
info_path = dir_libretro;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_LIST);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_LIST;
2016-10-08 15:05:31 +02:00
dl_type = DISPLAYLIST_GENERIC;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_DEFERRED_CORE_LIST_SET:
2023-07-17 22:32:13 +03:00
info.directory_ptr = idx;
info_path = dir_libretro;
info_label = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET;
dl_type = DISPLAYLIST_GENERIC;
/* Required for writing to correct playlist entry */
menu->scratchpad.unsigned_var = (unsigned)type;
2015-09-04 13:08:15 +02:00
break;
case ACTION_OK_DL_CHEAT_DETAILS_SETTINGS_LIST:
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
{
2020-06-30 19:35:41 +02:00
rarch_setting_t *setting = NULL;
cheat_manager_copy_idx_to_working(type-MENU_SETTINGS_CHEAT_BEGIN);
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_IDX);
if (setting)
setting->max = cheat_manager_get_size()-1;
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_VALUE);
if (setting)
setting->max = cheat_manager_get_state_search_size(cheat_manager_state.working_cheat.memory_search_size);
2020-06-30 19:35:41 +02:00
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_RUMBLE_VALUE);
if (setting)
setting->max = cheat_manager_get_state_search_size(cheat_manager_state.working_cheat.memory_search_size);
2020-06-30 19:35:41 +02:00
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_ADDRESS_BIT_POSITION);
if (setting)
{
int max_bit_position = cheat_manager_state.working_cheat.memory_search_size<3 ? 7 : 0;
setting->max = max_bit_position;
}
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_ADDRESS);
if (setting)
cheat_manager_state.browse_address = *setting->value.target.unsigned_integer;
ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC);
}
2020-06-30 19:35:41 +02:00
#endif
2020-02-21 03:28:23 +01:00
break;
case ACTION_OK_DL_CHEAT_SEARCH_SETTINGS_LIST:
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
{
rarch_setting_t *setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT);
if (setting)
setting->max = cheat_manager_get_state_search_size(cheat_manager_state.search_bit_size);
2020-06-30 19:35:41 +02:00
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS);
if (setting)
setting->max = cheat_manager_get_state_search_size(cheat_manager_state.search_bit_size);
2020-06-30 19:35:41 +02:00
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS);
if (setting)
setting->max = cheat_manager_get_state_search_size(cheat_manager_state.search_bit_size);
2020-06-30 19:35:41 +02:00
ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC);
}
#endif
2020-02-21 03:28:23 +01:00
break;
case ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST:
{
unsigned player_no = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_BEGIN;
2020-06-07 02:41:48 +02:00
ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC);
info.type = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_BEGIN + player_no;
}
break;
case ACTION_OK_DL_ACCOUNTS_LIST:
case ACTION_OK_DL_ACHIEVEMENTS_HARDCORE_PAUSE_LIST:
case ACTION_OK_DL_INPUT_SETTINGS_LIST:
case ACTION_OK_DL_INPUT_MENU_SETTINGS_LIST:
2021-03-25 18:45:31 +02:00
case ACTION_OK_DL_INPUT_TURBO_FIRE_SETTINGS_LIST:
case ACTION_OK_DL_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST:
case ACTION_OK_DL_LATENCY_SETTINGS_LIST:
2016-06-16 21:40:13 +02:00
case ACTION_OK_DL_DRIVER_SETTINGS_LIST:
2016-06-18 22:17:39 +02:00
case ACTION_OK_DL_CORE_SETTINGS_LIST:
2020-05-28 17:48:18 +01:00
case ACTION_OK_DL_CORE_INFORMATION_LIST:
#ifdef HAVE_MIST
case ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST:
#endif
case ACTION_OK_DL_VIDEO_SETTINGS_LIST:
Add HDR support for D3D12 (rebased PR from MajorPainTheCactus) (#12917) * Add HDR support * Attempt to fix Mingw build and Metal builds * (D3D12) Fix relative header includes * Add missing hdr_sm5.hlsl.h * (d3d12_common.c) Some C89 build fixes * Fix MSVC build * - Attempt to fix build on mingw/msys unix with dirty hack - Fix shader compilation of hdr_sm5.hlsl.h on MSVC/Visual Studio - the define was seen as an error and was causing the first pipeline to error out - Make sure we manually set handle of backBuffer to NULL * Moving the release of the texture above the freeing of desc.srv_heap and desc.rtv_heap solves the hard crashes on teardown/setup in RA - it was crashing hard in d3d12_release_texture before * Add HAVE_D3D12_HDR ifdef - needs to be disabled for WinRT for now because of several things that are Windows desktop-specific right now (GetWindowRect) * Add dirty GUID hack - should work for both mingw/msys on Windows/Linux as well as MSVC/Visual Studio (hopefully) * Change HAVE_D3D12_HDR to HAVE_DXGI_HDR * Move away from camelcase named variables * Fix RARCH_ERR logs - they need a newline at the end * d3d12_check_display_hdr_support - make it return a bool on return and set d3d12->hdr.support and d3d12->hdr.enable outside of the function * (DXGI) Remove D3D12 dependencies from dxgi_check_display_hdr_support and move it to dxgi_common.c instead * (DXGI) move d3d12_swapchain_color_space over to dxgi_common.c and rename it dxgi_swapchain_color_space * (DXGI) move d3d12_set_hdr_metadata to dxgi_common.c and rename it dxgi_set_hdr_metadata * (DXGI) dxgi_check_display_hdr_support - better error handling? * Fix typo * Remove video_force_resolution * (D3D12) Address TODO/FIXME * (D3D12) Backport https://github.com/libretro/RetroArch/pull/12916/commits/c1b6c0bff2aa33cde035b43cb31ac7e78ff2a07a - Fixed resource transition for present when HDR is off Fixed cel shader displaying all black as blending was enabled when the hdr shader was being applied - turned off blending during this shader * Move d3d12_hdr_uniform_t to dxgi_common.h and rename it dxgi_hdr_uniform_t * (D3D11) Add HDR support * Add TODO/FIXME notes * Cache hdr_enable in video_frame_info_t * Update comment
2021-09-03 06:15:25 +02:00
case ACTION_OK_DL_VIDEO_HDR_SETTINGS_LIST:
2019-12-19 19:39:02 +01:00
case ACTION_OK_DL_VIDEO_SYNCHRONIZATION_SETTINGS_LIST:
case ACTION_OK_DL_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST:
case ACTION_OK_DL_VIDEO_WINDOWED_MODE_SETTINGS_LIST:
case ACTION_OK_DL_VIDEO_SCALING_SETTINGS_LIST:
2019-12-19 19:15:57 +01:00
case ACTION_OK_DL_VIDEO_OUTPUT_SETTINGS_LIST:
case ACTION_OK_DL_CRT_SWITCHRES_SETTINGS_LIST:
case ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST:
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
case ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST:
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
2019-08-24 18:18:24 +02:00
case ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST:
case ACTION_OK_DL_REWIND_SETTINGS_LIST:
case ACTION_OK_DL_ONSCREEN_DISPLAY_SETTINGS_LIST:
2016-11-23 14:28:15 +01:00
case ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST:
2020-07-16 16:30:38 +01:00
case ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST:
case ACTION_OK_DL_ONSCREEN_OVERLAY_SETTINGS_LIST:
case ACTION_OK_DL_OSK_OVERLAY_SETTINGS_LIST:
case ACTION_OK_DL_OVERLAY_LIGHTGUN_SETTINGS_LIST:
case ACTION_OK_DL_OVERLAY_MOUSE_SETTINGS_LIST:
2016-07-02 20:40:27 +02:00
case ACTION_OK_DL_MENU_SETTINGS_LIST:
2022-08-17 08:23:07 +02:00
#ifdef _3DS
case ACTION_OK_DL_MENU_BOTTOM_SETTINGS_LIST:
#endif
2017-06-20 02:04:23 +02:00
case ACTION_OK_DL_MENU_VIEWS_SETTINGS_LIST:
case ACTION_OK_DL_SETTINGS_VIEWS_SETTINGS_LIST:
case ACTION_OK_DL_QUICK_MENU_VIEWS_SETTINGS_LIST:
case ACTION_OK_DL_QUICK_MENU_OVERRIDE_OPTIONS_LIST:
2016-07-02 20:40:27 +02:00
case ACTION_OK_DL_USER_INTERFACE_SETTINGS_LIST:
2019-08-21 20:43:32 +02:00
case ACTION_OK_DL_AI_SERVICE_SETTINGS_LIST:
case ACTION_OK_DL_ACCESSIBILITY_SETTINGS_LIST:
2018-06-19 06:23:38 +02:00
case ACTION_OK_DL_POWER_MANAGEMENT_SETTINGS_LIST:
case ACTION_OK_DL_CPU_PERFPOWER_SETTINGS_LIST:
case ACTION_OK_DL_CPU_POLICY_SETTINGS_LIST:
2019-01-27 11:22:16 -05:00
case ACTION_OK_DL_MENU_SOUNDS_LIST:
2016-07-02 20:40:27 +02:00
case ACTION_OK_DL_MENU_FILE_BROWSER_SETTINGS_LIST:
case ACTION_OK_DL_RETRO_ACHIEVEMENTS_SETTINGS_LIST:
case ACTION_OK_DL_CHEEVOS_APPEARANCE_SETTINGS_LIST:
case ACTION_OK_DL_CHEEVOS_VISIBILITY_SETTINGS_LIST:
2016-07-02 20:40:27 +02:00
case ACTION_OK_DL_UPDATER_SETTINGS_LIST:
case ACTION_OK_DL_NETWORK_SETTINGS_LIST:
2019-12-30 03:01:52 +01:00
case ACTION_OK_DL_NETWORK_HOSTING_SETTINGS_LIST:
case ACTION_OK_DL_NETPLAY_KICK_LIST:
2022-07-07 11:08:46 -03:00
case ACTION_OK_DL_NETPLAY_BAN_LIST:
case ACTION_OK_DL_NETPLAY_LOBBY_FILTERS_LIST:
case ACTION_OK_DL_SUBSYSTEM_SETTINGS_LIST:
2020-06-17 14:56:44 +03:00
case ACTION_OK_DL_BLUETOOTH_SETTINGS_LIST:
2016-09-21 21:58:43 +02:00
case ACTION_OK_DL_WIFI_SETTINGS_LIST:
case ACTION_OK_DL_WIFI_NETWORKS_LIST:
2017-06-08 00:19:43 +02:00
case ACTION_OK_DL_NETPLAY:
2016-12-02 22:40:26 -05:00
case ACTION_OK_DL_NETPLAY_LAN_SCAN_SETTINGS_LIST:
case ACTION_OK_DL_LAKKA_SERVICES_LIST:
#ifdef HAVE_LAKKA_SWITCH
case ACTION_OK_DL_LAKKA_SWITCH_OPTIONS_LIST:
#endif
2016-07-02 20:40:27 +02:00
case ACTION_OK_DL_USER_SETTINGS_LIST:
case ACTION_OK_DL_DIRECTORY_SETTINGS_LIST:
case ACTION_OK_DL_PRIVACY_SETTINGS_LIST:
2018-06-04 07:48:08 +02:00
case ACTION_OK_DL_MIDI_SETTINGS_LIST:
case ACTION_OK_DL_AUDIO_SETTINGS_LIST:
case ACTION_OK_DL_AUDIO_SYNCHRONIZATION_SETTINGS_LIST:
case ACTION_OK_DL_AUDIO_OUTPUT_SETTINGS_LIST:
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
case ACTION_OK_DL_MICROPHONE_SETTINGS_LIST:
#endif
case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST:
case ACTION_OK_DL_INPUT_RETROPAD_BINDS_LIST:
case ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST:
2016-10-08 15:05:31 +02:00
case ACTION_OK_DL_RECORDING_SETTINGS_LIST:
2015-10-25 10:25:07 +01:00
case ACTION_OK_DL_PLAYLIST_SETTINGS_LIST:
case ACTION_OK_DL_PLAYLIST_MANAGER_LIST:
case ACTION_OK_DL_PLAYLIST_MANAGER_SETTINGS:
2015-10-17 15:58:59 +02:00
case ACTION_OK_DL_ACCOUNTS_CHEEVOS_LIST:
2018-09-26 23:00:00 +02:00
case ACTION_OK_DL_ACCOUNTS_YOUTUBE_LIST:
case ACTION_OK_DL_ACCOUNTS_TWITCH_LIST:
2023-08-16 03:22:02 +02:00
case ACTION_OK_DL_ACCOUNTS_FACEBOOK_LIST:
2018-01-12 04:51:15 +01:00
case ACTION_OK_DL_PLAYLIST_COLLECTION:
case ACTION_OK_DL_FAVORITES_LIST:
case ACTION_OK_DL_BROWSE_URL_LIST:
2018-01-12 05:27:09 +01:00
case ACTION_OK_DL_MUSIC_LIST:
case ACTION_OK_DL_IMAGES_LIST:
2019-07-05 19:55:04 +02:00
case ACTION_OK_DL_LOAD_DISC_LIST:
case ACTION_OK_DL_DUMP_DISC_LIST:
#ifdef HAVE_LAKKA
case ACTION_OK_DL_EJECT_DISC:
#endif
2019-08-24 01:44:50 +02:00
case ACTION_OK_DL_SHADER_PRESET_REMOVE:
case ACTION_OK_DL_SHADER_PRESET_SAVE:
2019-07-11 06:34:27 +02:00
case ACTION_OK_DL_CDROM_INFO_LIST:
2019-11-29 17:13:35 +00:00
case ACTION_OK_DL_MANUAL_CONTENT_SCAN_LIST:
2020-06-11 14:12:20 +01:00
case ACTION_OK_DL_CORE_MANAGER_LIST:
#ifdef HAVE_MIST
case ACTION_OK_DL_STEAM_SETTINGS_LIST:
case ACTION_OK_DL_CORE_MANAGER_STEAM_LIST:
#endif
case ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST:
case ACTION_OK_DL_REMAP_FILE_MANAGER_LIST:
case ACTION_OK_DL_ADD_TO_PLAYLIST:
2020-06-07 02:41:48 +02:00
ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC);
break;
2019-07-11 06:34:27 +02:00
case ACTION_OK_DL_CDROM_INFO_DETAIL_LIST:
case ACTION_OK_DL_CORE_RESTORE_BACKUP_LIST:
case ACTION_OK_DL_CORE_DELETE_BACKUP_LIST:
2020-06-07 02:41:48 +02:00
ACTION_OK_DL_LBL(action_ok_dl_to_enum(action_type), DISPLAYLIST_GENERIC);
info_path = label;
2015-10-17 15:58:59 +02:00
break;
case ACTION_OK_DL_CONTENT_SETTINGS:
info.list = MENU_LIST_GET_SELECTION(menu_list, 0);
info_path = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS);
info_label = msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_SETTINGS);
2016-06-17 23:47:23 +02:00
info.enum_idx = MENU_ENUM_LABEL_CONTENT_SETTINGS;
menu_entries_append(menu_stack, info_path, info_label,
2016-06-15 14:59:49 +02:00
MENU_ENUM_LABEL_CONTENT_SETTINGS,
0, 0, 0, NULL);
2016-07-08 20:47:17 +02:00
dl_type = DISPLAYLIST_CONTENT_SETTINGS;
break;
2015-09-04 13:08:15 +02:00
}
2015-09-07 00:32:01 +02:00
if (info_label)
2017-09-28 02:45:03 +02:00
info.label = strdup(info_label);
2015-09-07 00:38:23 +02:00
if (info_path)
2017-09-28 03:06:54 +02:00
info.path = strdup(info_path);
2015-09-04 13:08:15 +02:00
if (menu_displaylist_ctl(dl_type, &info, settings))
2017-09-11 00:23:04 +02:00
{
2017-05-26 20:12:52 +02:00
if (menu_displaylist_process(&info))
2017-09-11 00:23:04 +02:00
{
menu_displaylist_info_free(&info);
2016-02-24 23:19:53 +01:00
return 0;
2017-09-11 00:23:04 +02:00
}
}
2017-09-11 00:23:04 +02:00
menu_displaylist_info_free(&info);
return -1;
2015-09-04 13:08:15 +02:00
}
/**
* menu_content_find_first_core:
* @core_info : Core info list handle.
* @dir : Directory. Gets joined with @path.
* @path : Path. Gets joined with @dir.
* @menu_label : Label identifier of menu setting.
* @s : Deferred core path. Will be filled in
* by function.
* @len : Size of @s.
*
* Gets deferred core.
*
* Returns: false if there are multiple deferred cores and a
* selection needs to be made from a list, otherwise
* returns true and fills in @s with path to core.
**/
static bool menu_content_find_first_core(menu_content_ctx_defer_info_t *def_info,
bool load_content_with_current_core,
char *new_core_path, size_t len)
{
const core_info_t *info = NULL;
size_t supported = 0;
core_info_list_t *core_info = (core_info_list_t*)def_info->data;
const char *default_info_dir = def_info->dir;
if (!string_is_empty(default_info_dir))
{
const char *default_info_path = def_info->path;
size_t default_info_length = def_info->len;
if (!string_is_empty(default_info_path))
fill_pathname_join_special(def_info->s,
default_info_dir, default_info_path,
default_info_length);
#ifdef HAVE_COMPRESSION
if (path_is_compressed_file(default_info_dir))
{
size_t _len = strlen(default_info_dir);
/* In case of a compressed archive, we have to join with a hash */
/* We are going to write at the position of dir: */
def_info->s[_len] = '#';
}
#endif
}
if (core_info)
core_info_list_get_supported_cores(core_info,
def_info->s, &info,
&supported);
/* We started the menu with 'Load Content', we are
* going to use the current core to load this. */
if (load_content_with_current_core)
{
core_info_get_current_core((core_info_t**)&info);
if (info)
supported = 1;
}
/* There are multiple deferred cores and a
* selection needs to be made from a list, return 0. */
if (supported != 1)
return false;
if (info)
strlcpy(new_core_path, info->path, len);
return true;
}
#ifdef HAVE_LIBRETRODB
void handle_dbscan_finished(retro_task_t *task,
void *task_data, void *user_data, const char *err);
#endif
2023-05-09 04:58:06 +02:00
static int file_load_with_detect_core_wrapper(
enum msg_hash_enums enum_label_idx,
size_t idx, size_t entry_idx,
2016-01-25 05:58:45 +01:00
const char *path, const char *label,
unsigned type, bool is_carchive)
{
2016-06-03 04:59:12 +02:00
int ret = 0;
2023-05-09 04:58:06 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2017-09-12 05:08:56 +02:00
{
menu_content_ctx_defer_info_t def_info;
#if IOS
char tmp_path[PATH_MAX_LENGTH];
#endif
char menu_path_new[PATH_MAX_LENGTH];
char new_core_path[PATH_MAX_LENGTH];
const char *menu_path = NULL;
const char *menu_label = NULL;
core_info_list_t *list = NULL;
2017-09-12 05:08:56 +02:00
new_core_path[0] = menu_path_new[0] = '\0';
menu_entries_get_last_stack(&menu_path, &menu_label, NULL, NULL, NULL);
#if IOS
if (menu_path)
{
fill_pathname_expand_special(tmp_path, menu_path, sizeof(tmp_path));
menu_path = tmp_path;
}
#endif
2017-09-12 05:08:56 +02:00
if (!string_is_empty(menu_path))
strlcpy(menu_path_new, menu_path, sizeof(menu_path_new));
2015-12-11 13:51:17 +01:00
2017-09-12 05:08:56 +02:00
if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE)))
2024-04-29 21:30:15 -04:00
{
if (path_is_absolute(menu->scratch_buf))
strlcpy(menu_path_new, menu->scratch_buf, sizeof(menu_path_new));
else
{
#if IOS
fill_pathname_join_special(tmp_path,
menu->scratch2_buf, menu->scratch_buf, sizeof(tmp_path));
fill_pathname_expand_special(menu_path_new, tmp_path, sizeof(menu_path_new));
#else
2024-04-29 21:30:15 -04:00
fill_pathname_join_special(menu_path_new,
menu->scratch2_buf, menu->scratch_buf, sizeof(menu_path_new));
#endif
}
2024-04-29 21:30:15 -04:00
}
2017-09-12 05:08:56 +02:00
else if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN)))
2024-04-29 21:30:15 -04:00
{
if (path_is_absolute(menu->scratch_buf))
strlcpy(menu_path_new, menu->scratch_buf, sizeof(menu_path_new));
else
fill_pathname_join_special(menu_path_new,
menu->scratch2_buf, menu->scratch_buf, sizeof(menu_path_new));
}
2017-09-12 05:08:56 +02:00
core_info_get_list(&list);
/* If loading a directory, use only path */
if (path == NULL && !string_is_empty(menu_path_new))
{
strlcpy(menu->deferred_path, menu_path_new,
sizeof(menu->deferred_path));
strlcpy(menu->detect_content_path, menu_path_new,
sizeof(menu->detect_content_path));
path = menu->detect_content_path;
menu_path_new[0] = '\0';
}
2017-09-12 05:08:56 +02:00
def_info.data = list;
def_info.dir = menu_path_new;
def_info.path = path;
def_info.menu_label = menu_label;
def_info.s = menu->deferred_path;
def_info.len = sizeof(menu->deferred_path);
2017-09-11 06:31:44 +02:00
2017-09-12 05:08:56 +02:00
if (menu_content_find_first_core(&def_info, false, new_core_path,
sizeof(new_core_path)))
2017-09-12 05:08:56 +02:00
ret = -1;
2015-06-07 23:26:29 +02:00
if ( !is_carchive
&& !string_is_empty(path)
2017-09-12 05:08:56 +02:00
&& !string_is_empty(menu_path_new))
fill_pathname_join_special(menu->detect_content_path,
2017-09-12 05:08:56 +02:00
menu_path_new, path,
sizeof(menu->detect_content_path));
2017-04-27 01:23:04 +02:00
2023-07-17 22:32:13 +03:00
/* Return to idx 0 */
2017-09-12 05:08:56 +02:00
if (enum_label_idx == MENU_ENUM_LABEL_COLLECTION)
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
NULL, menu->rpl_entry_selection_ptr,
0, entry_idx,
ACTION_OK_DL_DEFERRED_CORE_LIST_SET);
2017-09-12 05:08:56 +02:00
switch (ret)
{
case -1:
{
content_ctx_info_t content_info;
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
if (!task_push_load_content_with_new_core_from_menu(
new_core_path, def_info.s,
&content_info,
CORE_TYPE_PLAIN,
NULL, NULL))
return -1;
2023-05-09 04:58:06 +02:00
menu_driver_set_last_start_content(menu_st, def_info.s);
2017-09-12 05:08:56 +02:00
2017-09-18 15:57:05 +02:00
ret = 0;
break;
2017-09-12 05:08:56 +02:00
}
case 0:
2023-07-17 22:32:13 +03:00
ret = generic_action_ok_displaylist_push(
path, NULL,
label, type,
idx, entry_idx,
ACTION_OK_DL_DEFERRED_CORE_LIST);
2017-09-18 15:57:05 +02:00
break;
2017-09-12 05:08:56 +02:00
default:
break;
}
}
return ret;
}
static int action_ok_file_load_with_detect_core_carchive(
const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
fill_pathname_join_delim(menu->detect_content_path,
menu->detect_content_path, path,
'#', sizeof(menu->detect_content_path));
type = 0;
2016-01-25 05:58:45 +01:00
label = NULL;
return file_load_with_detect_core_wrapper(
MSG_UNKNOWN, idx, entry_idx,
path, label, type, true);
}
static int action_ok_file_load_with_detect_core(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
2015-06-08 18:35:14 +02:00
{
bool is_dir = (entry_idx == FILE_TYPE_USE_DIRECTORY
&& string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_USE_THIS_DIRECTORY)));
if (is_dir)
path = NULL;
2016-01-25 05:58:45 +01:00
type = 0;
label = NULL;
2017-08-13 07:14:10 +02:00
return file_load_with_detect_core_wrapper(
MSG_UNKNOWN, idx, entry_idx,
path, label, type, false);
}
static int action_ok_file_load_with_detect_core_collection(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
type = 0;
label = NULL;
return file_load_with_detect_core_wrapper(
MENU_ENUM_LABEL_COLLECTION,
idx, entry_idx,
path, label, type, false);
}
2017-08-11 02:51:09 +02:00
static int set_path_generic(const char *label, const char *action_path)
{
2017-08-15 05:30:57 +02:00
rarch_setting_t *setting = menu_setting_find(label);
2017-08-11 02:51:09 +02:00
if (setting)
{
if (setting->value.target.string)
strlcpy(setting->value.target.string, action_path, setting->size);
if (setting->change_handler)
setting->change_handler(setting);
return menu_setting_generic(setting, 0, false);
2017-08-11 02:51:09 +02:00
}
return 0;
}
int generic_action_ok_command(enum event_command cmd)
2017-11-26 06:35:53 +01:00
{
2019-07-12 16:31:16 +02:00
#ifdef HAVE_AUDIOMIXER
2020-02-19 22:06:21 +01:00
settings_t *settings = config_get_ptr();
bool audio_enable_menu = settings->bools.audio_enable_menu;
bool audio_enable_menu_ok = settings->bools.audio_enable_menu_ok;
2019-01-27 11:22:16 -05:00
2020-02-19 22:06:21 +01:00
if (audio_enable_menu && audio_enable_menu_ok)
2019-01-27 11:22:16 -05:00
audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_OK);
2019-07-11 11:51:06 +02:00
#endif
2019-01-27 11:22:16 -05:00
2017-11-26 06:35:53 +01:00
if (!command_event(cmd, NULL))
return -1;
2017-11-26 06:35:53 +01:00
return 0;
}
static int generic_action_ok(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
unsigned id, enum msg_hash_enums flush_id)
{
#if IOS
char tmp_path[PATH_MAX_LENGTH];
#endif
char action_path[PATH_MAX_LENGTH];
unsigned flush_type = 0;
int ret = 0;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
const char *menu_path = NULL;
const char *menu_label = NULL;
const char *flush_char = NULL;
2023-05-09 05:21:59 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
settings_t *settings = config_get_ptr();
2019-07-12 16:31:16 +02:00
#ifdef HAVE_AUDIOMIXER
2020-02-19 22:06:21 +01:00
bool audio_enable_menu = settings->bools.audio_enable_menu;
bool audio_enable_menu_ok = settings->bools.audio_enable_menu_ok;
if (audio_enable_menu && audio_enable_menu_ok)
2019-01-27 11:22:16 -05:00
audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_OK);
2019-07-11 11:51:06 +02:00
#endif
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
menu_entries_get_last_stack(&menu_path,
&menu_label, NULL, &enum_idx, NULL);
#if IOS
fill_pathname_expand_special(tmp_path, menu_path, sizeof(tmp_path));
menu_path = tmp_path;
#endif
if (!string_is_empty(path))
fill_pathname_join_special(action_path,
menu_path, path, sizeof(action_path));
else
strlcpy(action_path, menu_path, sizeof(action_path));
switch (id)
{
case ACTION_OK_LOAD_WALLPAPER:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST);
if (filestream_exists(action_path))
{
configuration_set_string(settings,
settings->paths.path_menu_wallpaper,
action_path);
task_push_image_load(action_path,
video_driver_supports_rgba(), 0,
menu_display_handle_wallpaper_upload, NULL);
}
break;
case ACTION_OK_LOAD_CORE:
{
2017-04-27 01:23:04 +02:00
content_ctx_info_t content_info;
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
flush_type = MENU_SETTINGS;
2017-02-21 16:53:02 +01:00
if (!task_push_load_new_core(
action_path, NULL,
&content_info,
CORE_TYPE_PLAIN,
NULL, NULL))
{
#ifndef HAVE_DYNAMIC
ret = -1;
#endif
}
}
break;
case ACTION_OK_LOAD_CONFIG_FILE:
#ifdef HAVE_CONFIGFILE
{
2020-02-19 22:06:21 +01:00
bool config_save_on_exit = settings->bools.config_save_on_exit;
2017-01-24 18:08:26 +01:00
flush_type = MENU_SETTINGS;
disp_get_ptr()->flags |= GFX_DISP_FLAG_MSG_FORCE;
2017-01-24 18:08:26 +01:00
2020-02-19 22:06:21 +01:00
if (config_replace(config_save_on_exit, action_path))
2017-01-24 18:08:26 +01:00
{
2021-09-21 21:10:38 +02:00
bool pending_push = false;
menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
2017-01-24 18:08:26 +01:00
ret = -1;
}
}
#endif
break;
case ACTION_OK_LOAD_PRESET:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
2017-01-09 03:53:55 +01:00
struct video_shader *shader = menu_shader_get();
flush_char = msg_hash_to_str(flush_id);
/* Cache selected shader parent directory/file name */
menu_driver_set_last_shader_preset_path(action_path);
/* Check whether this a load or append action */
if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PREPEND)) ||
string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_APPEND)))
2023-08-16 03:22:02 +02:00
menu_shader_manager_append_preset(shader, action_path,
string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PREPEND)));
else
menu_shader_manager_set_preset(shader,
menu_driver_get_last_shader_preset_type(),
action_path,
true);
}
#endif
break;
case ACTION_OK_LOAD_SHADER_PASS:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
2018-02-27 05:07:17 +01:00
struct video_shader *shader = menu_shader_get();
struct video_shader_pass *shader_pass = shader ? &shader->pass[menu->scratchpad.unsigned_var] : NULL;
2018-02-27 05:07:17 +01:00
flush_char = msg_hash_to_str((enum msg_hash_enums)flush_id);
2018-03-19 06:58:36 +01:00
if (shader_pass)
{
/* Cache selected shader parent directory/file name */
menu_driver_set_last_shader_pass_path(action_path);
2018-03-19 06:58:36 +01:00
strlcpy(
shader_pass->source.path,
action_path,
sizeof(shader_pass->source.path));
video_shader_resolve_parameters(shader);
shader->flags |= SHDR_FLAG_MODIFIED;
2018-03-19 06:58:36 +01:00
}
}
#endif
break;
2018-09-26 23:50:29 +02:00
case ACTION_OK_LOAD_STREAM_CONFIGFILE:
2023-05-09 05:21:59 +02:00
flush_char = msg_hash_to_str(flush_id);
if (settings)
2018-09-26 23:50:29 +02:00
{
2023-05-09 05:21:59 +02:00
configuration_set_string(settings,
settings->paths.path_stream_config, action_path);
2018-09-26 23:50:29 +02:00
}
break;
case ACTION_OK_LOAD_RECORD_CONFIGFILE:
2023-05-09 05:21:59 +02:00
flush_char = msg_hash_to_str(flush_id);
if (settings)
{
2023-05-09 05:21:59 +02:00
configuration_set_string(settings,
settings->paths.path_record_config, action_path);
}
break;
case ACTION_OK_LOAD_REMAPPING_FILE:
#ifdef HAVE_CONFIGFILE
{
2020-08-14 12:57:58 +03:00
retro_ctx_controller_info_t pad;
2024-09-09 15:27:52 +02:00
config_file_t *conf = NULL;
2020-08-14 12:57:58 +03:00
flush_char = msg_hash_to_str(flush_id);
2024-09-09 15:27:52 +02:00
if ((conf = config_file_new_from_path_to_string(action_path)))
{
2024-09-09 15:27:52 +02:00
char conf_key[64];
2020-08-14 12:57:58 +03:00
if (input_remapping_load_file(conf, action_path))
{
2024-09-09 15:27:52 +02:00
unsigned port;
size_t _len = strlcpy(conf_key, "input_libretro_device_p", sizeof(conf_key));
2020-08-14 12:57:58 +03:00
for (port = 0; port < MAX_USERS; port++)
{
2024-09-09 15:27:52 +02:00
unsigned current_device;
int conf_val = 0;
snprintf(conf_key + _len, sizeof(conf_key) - _len, "%u", port + 1);
2020-08-14 12:57:58 +03:00
if (!config_get_int(conf, conf_key, &conf_val))
continue;
current_device = input_config_get_device(port);
input_config_set_device(port, current_device);
pad.port = port;
pad.device = current_device;
2020-08-14 12:57:58 +03:00
core_set_controller_port_device(&pad);
}
}
config_file_free(conf);
conf = NULL;
}
}
#endif
break;
case ACTION_OK_LOAD_OVERRIDE_FILE:
#ifdef HAVE_CONFIGFILE
flush_char = msg_hash_to_str(flush_id);
config_unload_override();
if (!config_load_override_file(action_path))
return -1;
#endif
break;
case ACTION_OK_LOAD_CHEAT_FILE:
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
flush_char = msg_hash_to_str(flush_id);
cheat_manager_state_free();
if (!cheat_manager_load(action_path,false))
return -1;
2020-06-30 19:35:41 +02:00
#endif
break;
case ACTION_OK_LOAD_CHEAT_FILE_APPEND:
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
flush_char = msg_hash_to_str(flush_id);
if (!cheat_manager_load(action_path,true))
return -1;
2020-06-30 19:35:41 +02:00
#endif
break;
case ACTION_OK_LOAD_RGUI_MENU_THEME_PRESET:
2023-05-09 05:21:59 +02:00
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MENU_SETTINGS_LIST);
if (settings)
{
2023-05-09 05:21:59 +02:00
configuration_set_string(settings,
settings->paths.path_rgui_theme_preset, action_path);
}
break;
case ACTION_OK_SUBSYSTEM_ADD:
flush_type = MENU_SETTINGS;
content_add_subsystem(action_path);
break;
case ACTION_OK_SET_DIRECTORY:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST);
#ifdef HAVE_COCOATOUCH
2023-08-16 03:22:02 +02:00
/* For iOS, set the path using realpath because the
* path name can start with /private and this ensures
2020-08-19 06:53:09 +02:00
* the path starts with it.
*
2023-08-16 03:22:02 +02:00
* This will allow the path to be properly substituted
2020-08-19 06:53:09 +02:00
* when fill_pathname_expand_special
* is called.
*/
{
char real_action_path[PATH_MAX_LENGTH];
real_action_path[0] = '\0';
realpath(action_path, real_action_path);
strlcpy(action_path, real_action_path, sizeof(action_path));
}
#endif
ret = set_path_generic(menu->filebrowser_label, action_path);
break;
case ACTION_OK_SET_PATH_VIDEO_FILTER:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST);
2018-01-18 06:15:39 +01:00
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_PATH_AUDIO_FILTER:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST);
2018-01-18 06:15:39 +01:00
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_PATH_OVERLAY:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST);
retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_OVERLAY_PRESET, NULL);
2018-01-18 06:15:39 +01:00
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_PATH_OSK_OVERLAY:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_OSK_OVERLAY_SETTINGS_LIST);
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_PATH_VIDEO_FONT:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST);
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_MANUAL_CONTENT_SCAN_DAT_FILE:
flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MANUAL_CONTENT_SCAN_LIST);
ret = set_path_generic(menu_label, action_path);
break;
case ACTION_OK_SET_PATH:
flush_type = MENU_SETTINGS;
2018-01-18 06:15:39 +01:00
ret = set_path_generic(menu_label, action_path);
break;
default:
flush_char = msg_hash_to_str(flush_id);
break;
}
menu_entries_flush_stack(flush_char, flush_type);
return ret;
}
static int default_action_ok_load_content_with_core_from_menu(const char *_path, unsigned _type)
2017-11-26 07:29:19 +01:00
{
content_ctx_info_t content_info;
struct menu_state *menu_st = menu_state_get_ptr();
2017-11-26 07:29:19 +01:00
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2021-10-15 14:43:25 +02:00
if (!task_push_load_content_with_core(
2018-01-18 06:15:39 +01:00
_path, &content_info,
(enum rarch_core_type)_type, NULL, NULL))
2017-11-26 07:29:19 +01:00
return -1;
2023-05-09 04:58:06 +02:00
menu_driver_set_last_start_content(menu_st, _path);
2017-11-26 07:29:19 +01:00
return 0;
}
static int default_action_ok_load_content_from_playlist_from_menu(const char *_path,
2018-01-18 06:15:39 +01:00
const char *path, const char *entry_label)
2017-11-26 07:35:06 +01:00
{
content_ctx_info_t content_info;
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
if (!task_push_load_content_from_playlist_from_menu(
_path, path, entry_label,
&content_info,
NULL, NULL))
return -1;
return 0;
}
2020-10-01 15:54:11 +01:00
DEFAULT_ACTION_OK_SET(action_ok_set_path_audiofilter, ACTION_OK_SET_PATH_AUDIO_FILTER, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_set_path_videofilter, ACTION_OK_SET_PATH_VIDEO_FILTER, MSG_UNKNOWN)
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_SET(action_ok_set_path_overlay, ACTION_OK_SET_PATH_OVERLAY, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_set_path_osk_overlay, ACTION_OK_SET_PATH_OSK_OVERLAY, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_set_path_video_font, ACTION_OK_SET_PATH_VIDEO_FONT, MSG_UNKNOWN)
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_SET(action_ok_set_path, ACTION_OK_SET_PATH, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_load_core, ACTION_OK_LOAD_CORE, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_config_load, ACTION_OK_LOAD_CONFIG_FILE, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_subsystem_add, ACTION_OK_SUBSYSTEM_ADD, MSG_UNKNOWN)
DEFAULT_ACTION_OK_SET(action_ok_cheat_file_load, ACTION_OK_LOAD_CHEAT_FILE, MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS)
DEFAULT_ACTION_OK_SET(action_ok_cheat_file_load_append, ACTION_OK_LOAD_CHEAT_FILE_APPEND, MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS)
DEFAULT_ACTION_OK_SET(action_ok_record_configfile_load, ACTION_OK_LOAD_RECORD_CONFIGFILE, MENU_ENUM_LABEL_RECORDING_SETTINGS)
DEFAULT_ACTION_OK_SET(action_ok_stream_configfile_load, ACTION_OK_LOAD_STREAM_CONFIGFILE, MENU_ENUM_LABEL_RECORDING_SETTINGS)
DEFAULT_ACTION_OK_SET(action_ok_remap_file_load, ACTION_OK_LOAD_REMAPPING_FILE, MENU_ENUM_LABEL_DEFERRED_REMAP_FILE_MANAGER_LIST)
DEFAULT_ACTION_OK_SET(action_ok_override_file_load, ACTION_OK_LOAD_OVERRIDE_FILE, MENU_ENUM_LABEL_DEFERRED_QUICK_MENU_OVERRIDE_OPTIONS)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
DEFAULT_ACTION_OK_SET(action_ok_shader_preset_load, ACTION_OK_LOAD_PRESET, MENU_ENUM_LABEL_SHADER_OPTIONS)
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_SET(action_ok_shader_pass_load, ACTION_OK_LOAD_SHADER_PASS, MENU_ENUM_LABEL_SHADER_OPTIONS)
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_SET(action_ok_rgui_menu_theme_preset_load, ACTION_OK_LOAD_RGUI_MENU_THEME_PRESET, MENU_ENUM_LABEL_MENU_SETTINGS)
DEFAULT_ACTION_OK_SET(action_ok_set_manual_content_scan_dat_file, ACTION_OK_SET_MANUAL_CONTENT_SCAN_DAT_FILE, MENU_ENUM_LABEL_DEFERRED_MANUAL_CONTENT_SCAN_LIST)
static int action_ok_file_load(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char menu_path_new[PATH_MAX_LENGTH];
char full_path_new[PATH_MAX_LENGTH];
const char *menu_label = NULL;
const char *menu_path = NULL;
rarch_setting_t *setting = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
menu_list_t *menu_list = menu_st->entries.list;
file_list_t *menu_stack = MENU_LIST_GET(menu_list, 0);
2018-02-17 12:23:15 +01:00
if (filebrowser_get_type() == FILEBROWSER_SELECT_FILE_SUBSYSTEM)
{
/* TODO/FIXME - this path is triggered when we try to load a
2018-02-17 12:23:15 +01:00
* file from an archive while inside the load subsystem
* action */
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
fill_pathname_join_special(menu_path_new,
menu->scratch2_buf, menu->scratch_buf,
sizeof(menu_path_new));
2018-02-17 12:23:15 +01:00
switch (type)
{
case FILE_TYPE_IN_CARCHIVE:
fill_pathname_join_delim(full_path_new, menu_path_new, path,
2024-12-25 19:06:04 +01:00
'#', sizeof(full_path_new));
2018-02-17 12:23:15 +01:00
break;
default:
fill_pathname_join_special(full_path_new, menu_path_new, path,
2018-02-17 12:23:15 +01:00
sizeof(full_path_new));
break;
}
content_add_subsystem(full_path_new);
menu_entries_flush_stack(NULL, MENU_SETTINGS);
return 0;
}
if (menu_stack && menu_stack->size)
{
menu_path = menu_stack->list[menu_stack->size - 1].path;
menu_label = menu_stack->list[menu_stack->size - 1].label;
}
2017-10-04 06:53:47 +02:00
if (!string_is_empty(menu_label))
setting = menu_setting_find(menu_label);
2020-06-30 07:04:55 +02:00
if (setting && setting->type == ST_PATH)
return action_ok_set_path(path, label, type, idx, entry_idx);
2017-10-04 06:53:47 +02:00
if (!string_is_empty(menu_path))
strlcpy(menu_path_new, menu_path, sizeof(menu_path_new));
2017-10-04 06:53:47 +02:00
if (!string_is_empty(menu_label))
{
if (
string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE)) ||
string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN))
)
{
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
fill_pathname_join_special(menu_path_new,
menu->scratch2_buf, menu->scratch_buf,
sizeof(menu_path_new));
}
}
switch (type)
{
case FILE_TYPE_IN_CARCHIVE:
fill_pathname_join_delim(full_path_new, menu_path_new, path,
'#',sizeof(full_path_new));
break;
default:
fill_pathname_join_special(full_path_new, menu_path_new, path,
sizeof(full_path_new));
break;
}
2017-11-26 07:29:19 +01:00
return default_action_ok_load_content_with_core_from_menu(full_path_new,
CORE_TYPE_PLAIN);
2015-06-08 18:35:14 +02:00
}
static bool playlist_entry_path_is_valid(const char *entry_path)
{
char *archive_delim = NULL;
char *file_path = NULL;
if (string_is_empty(entry_path))
return false;
file_path = strdup(entry_path);
/* We need to check whether the file referenced by the
* entry path actually exists. If it is a normal file,
* we can do this directly. If the path contains an
* archive delimiter, then we have to trim everything
* after the archive extension
* > Note: Have to do a nasty cast here, since
* path_get_archive_delim() returns a const char *
* (this cast is safe, though, and is done in many
* places throughout the codebase...) */
if ((archive_delim = (char *)path_get_archive_delim(file_path)))
{
*archive_delim = '\0';
if (string_is_empty(file_path))
goto error;
}
/* Path is 'sanitised' - can now check if it exists */
if (!path_is_valid(file_path))
goto error;
/* File is valid */
free(file_path);
file_path = NULL;
return true;
error:
free(file_path);
file_path = NULL;
return false;
}
static int action_ok_playlist_entry_collection(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_config_t playlist_config;
char content_path[PATH_MAX_LENGTH];
char content_label[NAME_MAX_LENGTH];
char core_path[PATH_MAX_LENGTH];
size_t selection_ptr = entry_idx;
bool playlist_initialized = false;
playlist_t *playlist = NULL;
playlist_t *tmp_playlist = NULL;
const struct playlist_entry *entry = NULL;
core_info_t* core_info = NULL;
bool core_is_builtin = false;
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
settings_t *settings = config_get_ptr();
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool playlist_sort_alphabetical = settings->bools.playlist_sort_alphabetical;
const char *path_content_history = settings->paths.path_content_history;
const char *path_content_image_history = settings->paths.path_content_image_history;
const char *path_content_music_history = settings->paths.path_content_music_history;
const char *path_content_video_history = settings->paths.path_content_video_history;
2017-04-27 01:23:04 +02:00
2020-06-26 15:39:03 +01:00
playlist_config.capacity = COLLECTION_SIZE;
playlist_config.old_format = settings->bools.playlist_use_old_format;
playlist_config.compress = settings->bools.playlist_compression;
playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL);
2020-06-26 15:39:03 +01:00
content_path[0] = '\0';
content_label[0] = '\0';
core_path[0] = '\0';
2019-08-16 15:17:02 +02:00
if (!menu)
goto error;
/* Get playlist */
if (!(tmp_playlist = playlist_get_cached()))
{
enum playlist_sort_mode current_sort_mode;
/* If playlist is not cached, have to load
* it here
* > Since the menu will always sort playlists
* based on current user config, have to do
* the same here - otherwise entry_idx may
* go out of sync... */
bool is_content_history = string_is_equal(menu->db_playlist_file, path_content_history)
|| string_is_equal(menu->db_playlist_file, path_content_image_history)
|| string_is_equal(menu->db_playlist_file, path_content_music_history)
|| string_is_equal(menu->db_playlist_file, path_content_video_history);
2020-06-26 15:39:03 +01:00
playlist_config_set_path(&playlist_config, menu->db_playlist_file);
if (!(tmp_playlist = playlist_init(&playlist_config)))
goto error;
2019-04-11 19:45:28 -04:00
current_sort_mode = playlist_get_sort_mode(tmp_playlist);
if ( !is_content_history
&& ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT))
|| (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL)))
playlist_qsort(tmp_playlist);
playlist_initialized = true;
}
playlist = tmp_playlist;
/* Get playlist entry */
playlist_get_index(playlist, selection_ptr, &entry);
if (!entry)
goto error;
2019-04-11 18:18:37 -05:00
/* Cache entry path */
if (!string_is_empty(entry->path))
2019-04-11 18:18:37 -05:00
{
strlcpy(content_path, entry->path, sizeof(content_path));
playlist_resolve_path(PLAYLIST_LOAD, false, content_path, sizeof(content_path));
2019-04-11 18:18:37 -05:00
}
runloop_st->entry_state_slot = entry->entry_slot;
/* Cache entry label */
if (!string_is_empty(entry->label))
strlcpy(content_label, entry->label, sizeof(content_label));
/* Get core path */
if (!playlist_entry_has_core(entry))
{
struct playlist_entry update_entry = {0};
/* Entry core is not set - attempt to use
* playlist default */
core_info = playlist_get_default_core_info(playlist);
/* If default core is not set, prompt user
* to select one */
if (!core_info)
{
/* TODO: figure out if this should refer to the inner or outer content_path */
int ret = action_ok_file_load_with_detect_core_collection(content_path,
label, type, selection_ptr, entry_idx);
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
return ret;
}
/* Update playlist entry */
strlcpy(core_path, core_info->path, sizeof(core_path));
playlist_resolve_path(PLAYLIST_SAVE, true, core_path, sizeof(core_path));
update_entry.core_path = core_path;
update_entry.core_name = core_info->display_name;
command_playlist_update_write(
playlist,
selection_ptr,
2020-06-26 15:39:03 +01:00
&update_entry);
/* Cache core path */
strlcpy(core_path, core_info->path, sizeof(core_path));
}
2016-07-09 22:15:24 +02:00
else
{
/* Entry does have a core assignment
* > If core is 'built-in' (imageviewer, etc.),
* then copy the path without modification
* > If this is a standard core, ensure
* it has a corresponding core info entry */
2020-06-25 14:38:06 +02:00
if (string_ends_with_size(entry->core_path, "builtin",
strlen(entry->core_path),
STRLEN_CONST("builtin")))
{
strlcpy(core_path, entry->core_path, sizeof(core_path));
core_is_builtin = true;
}
else
{
[iOS] New iOS 13 project to support Swift; Custom keyboard and touch mouse support (#13435) * Support for Swift, added emulator keyboard * fixed toggle key handling using magic number hack for now * fixed keyboard transparency slider for now with suboptimal fix; add gesture recognizer to hide/show keyboard * Support CocoaView extensions in Swift; move keyboard delegate impl and setup to swift extension * moved keyboard view model creation out of EmulatorKeyboard * implement key pressed delegate in swift extension * added input method for directly sending RETROK_* codes to support a touchscreen keyboard; assign keyboard model delegates; updated keyboard layout (added F1-F12 keys); change shift, control and alt keys to be modifiers * enable focus mode when custom keyboard is shown; enable/disable overlay when custom keyboard is toggled * Specify -DHAVE_OPENGLES2 instead of -DHAVE_OPENGLES3 since glsym_es3.h does not compile in iOS 14.5 Fix tvOS build using compiler flags * Create new project for iOS 13 deploy target; add check for deploy target to conditionally compile for new iOS 13 specific feature (custom keyboard) * force disable core info caching for iOS, use opengl es2 for debug * Add flag for iOS custom keyboard - 3-finger swipe up to show, 3-finger swipe down to hide * use OpenGLES2 instead; using ES3 results in compile time errors on iOS 14.5 * code cleanup * Updated references to -DDONT_WANT_ARM_ASM_OPTIMIZATIONS flag * Add JIT support for non-jailbroken devices * iOS: Add support for touch mouse handler * Added a HAVE_IOS_TOUCHMOUSE preprocessor macro so that it builds under the iOS11_Metal xcode project * Changed click-and-drag behavior to double tap hold and drag * Visual improvements to the emulator keyboard: updated colors, improved key-press effect
2022-02-21 21:21:34 -10:00
#ifndef IOS
core_info = playlist_entry_get_core_info(entry);
if (core_info && !string_is_empty(core_info->path))
strlcpy(core_path, core_info->path, sizeof(core_path));
else
/* Core path is invalid - just copy what we have
* and hope for the best... */
2022-11-17 19:07:54 +01:00
#endif
{
strlcpy(core_path, entry->core_path, sizeof(core_path));
playlist_resolve_path(PLAYLIST_LOAD, true, core_path, sizeof(core_path));
}
}
2016-12-15 12:18:26 +01:00
}
/* Ensure core path is valid */
2022-11-17 19:07:54 +01:00
if ( string_is_empty(core_path)
|| (!core_is_builtin && !path_is_valid(core_path)))
goto error;
/* Subsystem codepath */
if (!string_is_empty(entry->subsystem_ident))
{
content_ctx_info_t content_info = {0};
size_t i;
task_push_load_new_core(core_path, NULL,
&content_info, CORE_TYPE_PLAIN, NULL, NULL);
content_clear_subsystem();
if (!content_set_subsystem_by_name(entry->subsystem_ident))
{
RARCH_LOG("[playlist] subsystem not found in implementation\n");
goto error;
}
for (i = 0; i < entry->subsystem_roms->size; i++)
content_add_subsystem(entry->subsystem_roms->elems[i].data);
2015-05-26 04:27:21 +02:00
2021-10-15 14:43:25 +02:00
task_push_load_subsystem_with_core(
NULL, &content_info,
CORE_TYPE_PLAIN, NULL, NULL);
/* TODO: update playlist entry? move to first position I guess? */
if (playlist_initialized && tmp_playlist)
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
}
return 1;
}
/* Ensure entry path is valid */
if (!playlist_entry_path_is_valid(content_path))
goto error;
/* Free temporary playlist, if required */
if (playlist_initialized && tmp_playlist)
2016-12-15 12:18:26 +01:00
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
2016-12-15 12:18:26 +01:00
}
/* Note: Have to use cached entry label, since entry
* may be free()'d by above playlist_free() - but need
* to pass NULL explicitly if label is empty */
2017-12-06 14:25:41 +01:00
return default_action_ok_load_content_from_playlist_from_menu(
core_path, content_path, string_is_empty(content_label) ? NULL : content_label);
error:
runloop_msg_queue_push(
"File could not be loaded from playlist.\n",
STRLEN_CONST("File could not be loaded from playlist.\n"),
1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
if (playlist_initialized && tmp_playlist)
2016-12-15 12:18:26 +01:00
{
playlist_free(tmp_playlist);
tmp_playlist = NULL;
playlist = NULL;
2016-12-15 12:18:26 +01:00
}
return -1;
}
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2018-04-30 15:04:29 +02:00
static int action_ok_mixer_stream_action_play(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-05-09 05:21:59 +02:00
unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_BEGIN;
2018-04-30 15:04:29 +02:00
enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id);
2023-05-09 05:21:59 +02:00
if (state == AUDIO_STREAM_STATE_STOPPED)
audio_driver_mixer_play_stream(stream_id);
2018-04-30 15:04:29 +02:00
return 0;
}
static int action_ok_mixer_stream_action_play_looped(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-05-09 05:21:59 +02:00
unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN;
2018-04-30 15:04:29 +02:00
enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id);
2023-05-09 05:21:59 +02:00
if (state == AUDIO_STREAM_STATE_STOPPED)
audio_driver_mixer_play_stream_looped(stream_id);
return 0;
}
static int action_ok_mixer_stream_action_play_sequential(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN;
enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id);
2023-05-09 05:21:59 +02:00
if (state == AUDIO_STREAM_STATE_STOPPED)
audio_driver_mixer_play_stream_sequential(stream_id);
2018-04-30 15:04:29 +02:00
return 0;
}
static int action_ok_mixer_stream_action_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_BEGIN;
enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id);
switch (state)
{
case AUDIO_STREAM_STATE_PLAYING:
case AUDIO_STREAM_STATE_PLAYING_LOOPED:
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
case AUDIO_STREAM_STATE_STOPPED:
audio_driver_mixer_remove_stream(stream_id);
break;
case AUDIO_STREAM_STATE_NONE:
break;
}
return 0;
}
static int action_ok_mixer_stream_action_stop(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-05-09 05:21:59 +02:00
unsigned stream_id = type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_STOP_BEGIN;
enum audio_mixer_state state = audio_driver_mixer_get_stream_state(stream_id);
switch (state)
{
case AUDIO_STREAM_STATE_PLAYING:
case AUDIO_STREAM_STATE_PLAYING_LOOPED:
case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
audio_driver_mixer_stop_stream(stream_id);
break;
case AUDIO_STREAM_STATE_STOPPED:
case AUDIO_STREAM_STATE_NONE:
break;
}
return 0;
}
2019-07-11 11:51:06 +02:00
#endif
2019-07-05 19:55:04 +02:00
static int action_ok_load_cdrom(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-07-09 11:17:10 -04:00
#ifdef HAVE_CDROM
struct retro_system_info *sysinfo;
if (!cdrom_drive_has_media(label[0]))
{
const char *_msg = msg_hash_to_str(MSG_NO_DISC_INSERTED);
2019-07-10 20:56:23 -04:00
RARCH_LOG("[CDROM]: No media is inserted or drive is not ready.\n");
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return -1;
}
sysinfo = &runloop_state_get_ptr()->system.info;
2019-07-09 11:17:10 -04:00
if (sysinfo && !string_is_empty(sysinfo->library_name))
2019-07-09 11:17:10 -04:00
{
2024-12-25 19:06:04 +01:00
char cdrom_path[256];
2019-07-09 11:17:10 -04:00
cdrom_device_fillpath(cdrom_path, sizeof(cdrom_path), label[0], 0, true);
2019-07-10 20:56:23 -04:00
RARCH_LOG("[CDROM]: Loading disc from path: %s\n", cdrom_path);
2019-07-09 11:17:10 -04:00
path_clear(RARCH_PATH_CONTENT);
2024-12-25 19:06:04 +01:00
if (!string_is_empty(cdrom_path))
path_set(RARCH_PATH_CONTENT, cdrom_path);
2019-07-09 11:17:10 -04:00
#if defined(HAVE_DYNAMIC)
{
content_ctx_info_t content_info;
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2021-10-15 14:43:25 +02:00
task_push_load_content_with_core(cdrom_path, &content_info, CORE_TYPE_PLAIN, NULL, NULL);
2019-07-09 11:17:10 -04:00
}
#else
frontend_driver_set_fork(FRONTEND_FORK_CORE_WITH_ARGS);
#endif
}
else
{
const char *_msg = msg_hash_to_str(MSG_LOAD_CORE_FIRST);
2019-07-10 20:56:23 -04:00
RARCH_LOG("[CDROM]: Cannot load disc without a core.\n");
2019-07-09 11:17:10 -04:00
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return -1;
2019-07-09 11:17:10 -04:00
}
#endif
2019-07-05 19:55:04 +02:00
return 0;
}
2019-07-03 22:28:12 +02:00
static int action_ok_dump_cdrom(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-07-08 15:32:12 -04:00
if (string_is_empty(label))
return -1;
#ifdef HAVE_CDROM
if (!cdrom_drive_has_media(label[0]))
{
const char *_msg = msg_hash_to_str(MSG_NO_DISC_INSERTED);
2019-07-10 20:56:23 -04:00
RARCH_LOG("[CDROM]: No media is inserted or drive is not ready.\n");
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true,
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return -1;
}
2019-07-08 15:32:12 -04:00
task_push_cdrom_dump(label);
#endif
2019-07-03 22:28:12 +02:00
return 0;
}
#ifdef HAVE_LAKKA
static int action_ok_eject_disc(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifdef HAVE_CDROM
system("nohup eject 2>&1 >/dev/null & exit");
#endif /* HAVE_CDROM */
return 0;
}
#endif /* HAVE_LAKKA */
static int action_ok_lookup_setting(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return menu_setting_set(type, MENU_ACTION_OK, false);
}
2015-09-02 18:38:45 +02:00
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
static int action_ok_audio_add_to_mixer(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
playlist_t *tmp_playlist = playlist_get_cached();
const struct playlist_entry *entry = NULL;
if (!tmp_playlist)
return -1;
playlist_get_index(tmp_playlist, entry_idx, &entry);
if (filestream_exists(entry->path))
task_push_audio_mixer_load(entry->path,
NULL, NULL, false,
AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC,
0
);
return 0;
}
static int action_ok_audio_add_to_mixer_and_play(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
playlist_t *tmp_playlist = playlist_get_cached();
const struct playlist_entry *entry = NULL;
if (!tmp_playlist)
return -1;
playlist_get_index(tmp_playlist, entry_idx, &entry);
if (filestream_exists(entry->path))
task_push_audio_mixer_load_and_play(entry->path,
NULL, NULL, false,
AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC,
0);
return 0;
}
static int action_ok_audio_add_to_mixer_and_collection(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char combined_path[PATH_MAX_LENGTH];
2020-06-26 15:39:03 +01:00
struct playlist_entry entry = {0};
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2018-05-02 21:09:53 +02:00
fill_pathname_join_special(combined_path, menu->scratch2_buf,
2018-05-02 21:09:53 +02:00
menu->scratch_buf, sizeof(combined_path));
2023-08-16 03:22:02 +02:00
/* The push function reads our entry as const,
so these casts are safe */
entry.path = combined_path;
entry.core_path = (char*)"builtin";
entry.core_name = (char*)"musicplayer";
2020-06-26 15:39:03 +01:00
command_playlist_push_write(g_defaults.music_history, &entry);
2018-05-02 21:09:53 +02:00
if (filestream_exists(combined_path))
task_push_audio_mixer_load(combined_path,
NULL, NULL, false,
AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC,
0);
2018-05-02 21:09:53 +02:00
return 0;
}
static int action_ok_audio_add_to_mixer_and_collection_and_play(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char combined_path[PATH_MAX_LENGTH];
2020-06-26 15:39:03 +01:00
struct playlist_entry entry = {0};
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2018-05-02 21:09:53 +02:00
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
fill_pathname_join_special(combined_path, menu->scratch2_buf,
menu->scratch_buf, sizeof(combined_path));
/* the push function reads our entry as const, so these casts are safe */
2022-11-17 19:07:54 +01:00
entry.path = combined_path;
entry.core_path = (char*)"builtin";
entry.core_name = (char*)"musicplayer";
2020-06-26 15:39:03 +01:00
command_playlist_push_write(g_defaults.music_history, &entry);
if (filestream_exists(combined_path))
task_push_audio_mixer_load_and_play(combined_path,
NULL, NULL, false,
AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC,
0);
return 0;
}
2019-07-11 11:51:06 +02:00
#endif
static int action_ok_menu_wallpaper(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
filebrowser_set_type(FILEBROWSER_SELECT_IMAGE);
return action_ok_lookup_setting(path, label, type, idx, entry_idx);
}
2015-09-04 23:11:04 +02:00
static int action_ok_menu_wallpaper_load(const char *path,
2015-09-04 22:48:20 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
filebrowser_clear_type();
2017-04-28 21:03:04 +02:00
settings->uints.menu_xmb_shader_pipeline = XMB_SHADER_PIPELINE_WALLPAPER;
return generic_action_ok(path, label, type, idx, entry_idx,
ACTION_OK_LOAD_WALLPAPER, MSG_UNKNOWN);
2015-09-04 22:48:20 +02:00
}
int generic_action_ok_help(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
2016-09-15 16:07:20 +02:00
enum msg_hash_enums id, enum menu_dialog_type id2)
{
const char *lbl = msg_hash_to_str(id);
2016-02-10 21:15:23 +01:00
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
lbl, id2,
idx, entry_idx,
ACTION_OK_DL_HELP);
}
#ifdef HAVE_BLUETOOTH
2020-06-17 14:56:44 +03:00
static int action_ok_bluetooth(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
2021-02-03 10:39:29 +01:00
driver_bluetooth_connect_device((unsigned)idx);
2020-06-17 14:56:44 +03:00
return 0;
}
#endif
2020-06-17 14:56:44 +03:00
2020-12-09 22:03:23 +01:00
#ifdef HAVE_NETWORKING
#ifdef HAVE_WIFI
2016-09-23 13:16:27 +02:00
static void menu_input_wifi_cb(void *userdata, const char *passphrase)
{
struct menu_state *menu_st = menu_state_get_ptr();
unsigned idx = menu_st->input_dialog_kb_idx;
2022-11-17 19:07:54 +01:00
wifi_network_scan_t *scan = driver_wifi_get_ssids();
wifi_network_info_t *netinfo = &scan->net_list[idx];
2023-07-15 15:14:26 +02:00
if ( (idx < RBUF_LEN(scan->net_list))
&& passphrase)
{
/* Need to fill in the passphrase that we got from the user! */
strlcpy(netinfo->passphrase, passphrase, sizeof(netinfo->passphrase));
task_push_wifi_connect(NULL, netinfo);
}
2016-09-23 13:16:27 +02:00
menu_input_dialog_end();
}
static int action_ok_wifi(const char *path, const char *label_setting,
unsigned type, size_t idx, size_t entry_idx)
{
2022-11-17 19:07:54 +01:00
menu_input_ctx_line_t line;
wifi_network_scan_t* scan = driver_wifi_get_ssids();
if (idx >= RBUF_LEN(scan->net_list))
return -1;
/* No need to ask for a password, should be stored */
if (scan->net_list[idx].saved_password)
task_push_wifi_connect(NULL, &scan->net_list[idx]);
else
{
/* Show password input dialog */
line.label = "Passphrase";
line.label_setting = label_setting;
line.type = type;
line.idx = (unsigned)idx;
line.cb = menu_input_wifi_cb;
if (!menu_input_dialog_start(&line))
return -1;
}
2022-11-17 19:07:54 +01:00
return 0;
}
#endif
2020-12-09 22:03:23 +01:00
#endif
2016-09-23 13:16:27 +02:00
2017-08-14 20:07:43 +02:00
static void menu_input_st_string_cb_rename_entry(void *userdata,
const char *str)
{
if (str && *str)
{
const char *label = menu_input_dialog_get_buffer();
if (!string_is_empty(label))
{
2024-12-25 19:06:04 +01:00
struct playlist_entry entry = {0};
struct menu_state *menu_st = menu_state_get_ptr();
unsigned idx = menu_st->input_dialog_kb_idx;
2020-02-19 22:06:21 +01:00
/* the update function reads our entry as const,
* so these casts are safe */
entry.label = (char*)label;
command_playlist_update_write(NULL, idx, &entry);
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
}
2017-08-14 20:07:43 +02:00
}
menu_input_dialog_end();
}
static void menu_input_st_string_cb_disable_kiosk_mode(void *userdata,
const char *str)
{
if (str && *str)
{
2020-02-19 22:06:21 +01:00
const char *label = menu_input_dialog_get_buffer();
settings_t *settings = config_get_ptr();
2023-08-16 03:22:02 +02:00
const char *path_kiosk_mode_password =
2020-02-19 22:06:21 +01:00
settings->paths.kiosk_mode_password;
2020-02-19 22:06:21 +01:00
if (string_is_equal(label, path_kiosk_mode_password))
{
const char *_msg = msg_hash_to_str(MSG_INPUT_KIOSK_MODE_PASSWORD_OK);
settings->bools.kiosk_mode_enable = false;
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
else
{
const char *_msg = msg_hash_to_str(MSG_INPUT_KIOSK_MODE_PASSWORD_NOK);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
menu_input_dialog_end();
}
static void menu_input_st_string_cb_enable_settings(void *userdata,
const char *str)
{
if (str && *str)
{
2023-08-16 03:22:02 +02:00
const char *label =
2020-02-19 22:06:21 +01:00
menu_input_dialog_get_buffer();
settings_t *settings = config_get_ptr();
const char *menu_content_show_settings_password = settings->paths.menu_content_show_settings_password;
2020-02-19 22:06:21 +01:00
if (string_is_equal(label, menu_content_show_settings_password))
{
const char *_msg = msg_hash_to_str(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_OK);
settings->bools.menu_content_show_settings = true;
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
else
{
const char *_msg = msg_hash_to_str(MSG_INPUT_ENABLE_SETTINGS_PASSWORD_NOK);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
menu_input_dialog_end();
}
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
2020-12-09 22:03:23 +01:00
static int action_ok_shader_pass(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2020-12-09 22:03:23 +01:00
if (!menu)
return -1;
2020-12-09 22:03:23 +01:00
menu->scratchpad.unsigned_var = type - MENU_SETTINGS_SHADER_PASS_0;
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
label, type,
idx, entry_idx,
ACTION_OK_DL_SHADER_PASS);
2020-12-09 22:03:23 +01:00
}
2016-07-01 05:42:53 +02:00
static void menu_input_st_string_cb_save_preset(void *userdata,
const char *str)
{
if (!string_is_empty(str))
{
2020-02-19 22:06:21 +01:00
rarch_setting_t *setting = NULL;
bool ret = false;
2023-08-16 03:22:02 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
const char *label = menu_st->input_dialog_kb_label;
2020-02-19 22:06:21 +01:00
settings_t *settings = config_get_ptr();
const char *dir_video_shader = settings->paths.directory_video_shader;
const char *dir_menu_config = settings->paths.directory_menu_config;
if (!string_is_empty(label))
setting = menu_setting_find(label);
if (setting)
{
if (setting->value.target.string)
strlcpy(setting->value.target.string, str, setting->size);
if (setting->change_handler)
setting->change_handler(setting);
menu_setting_generic(setting, 0, false);
}
else if (!string_is_empty(label))
2020-02-19 22:06:21 +01:00
ret = menu_shader_manager_save_preset(
menu_shader_get(),
str,
2020-02-19 22:06:21 +01:00
dir_video_shader,
dir_menu_config,
true);
2016-07-27 18:31:49 -05:00
if (ret)
{
const char *_msg = msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
2016-07-27 18:31:49 -05:00
else
{
const char *_msg = msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
}
menu_input_dialog_end();
}
2017-11-26 06:03:34 +01:00
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_DIALOG_START(action_ok_shader_preset_save_as,
2017-11-26 06:12:51 +01:00
msg_hash_to_str(MSG_INPUT_PRESET_FILENAME),
(unsigned)idx,
menu_input_st_string_cb_save_preset)
2017-11-26 06:03:34 +01:00
enum
{
2019-08-17 20:05:20 +02:00
ACTION_OK_SHADER_PRESET_SAVE_GLOBAL = 0,
ACTION_OK_SHADER_PRESET_SAVE_CORE,
ACTION_OK_SHADER_PRESET_SAVE_PARENT,
ACTION_OK_SHADER_PRESET_SAVE_GAME
};
2019-08-24 01:44:50 +02:00
enum
{
ACTION_OK_SHADER_PRESET_REMOVE_GLOBAL = 0,
ACTION_OK_SHADER_PRESET_REMOVE_CORE,
ACTION_OK_SHADER_PRESET_REMOVE_PARENT,
ACTION_OK_SHADER_PRESET_REMOVE_GAME
};
static int generic_action_ok_shader_preset_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
unsigned action_type)
{
enum auto_shader_type preset_type;
2020-02-21 03:28:23 +01:00
settings_t *settings = config_get_ptr();
const char *dir_video_shader = settings->paths.directory_video_shader;
const char *dir_menu_config = settings->paths.directory_menu_config;
2019-08-24 01:44:50 +02:00
switch (action_type)
{
case ACTION_OK_SHADER_PRESET_REMOVE_GLOBAL:
preset_type = SHADER_PRESET_GLOBAL;
break;
case ACTION_OK_SHADER_PRESET_REMOVE_CORE:
preset_type = SHADER_PRESET_CORE;
break;
case ACTION_OK_SHADER_PRESET_REMOVE_PARENT:
preset_type = SHADER_PRESET_PARENT;
break;
case ACTION_OK_SHADER_PRESET_REMOVE_GAME:
preset_type = SHADER_PRESET_GAME;
break;
default:
return 0;
}
if (menu_shader_manager_remove_auto_preset(preset_type,
2020-02-21 03:28:23 +01:00
dir_video_shader, dir_menu_config))
{
2023-05-11 01:58:30 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
const char *_msg = msg_hash_to_str(MSG_SHADER_PRESET_REMOVED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2023-05-11 01:58:30 +02:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
}
2019-08-24 01:44:50 +02:00
else
{
const char *_msg = msg_hash_to_str(MSG_ERROR_REMOVING_SHADER_PRESET);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
2019-08-24 01:44:50 +02:00
return 0;
}
static int generic_action_ok_shader_preset_save(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
unsigned action_type)
{
enum auto_shader_type preset_type;
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
const char *dir_video_shader = settings->paths.directory_video_shader;
const char *dir_menu_config = settings->paths.directory_menu_config;
switch (action_type)
{
2019-08-17 20:05:20 +02:00
case ACTION_OK_SHADER_PRESET_SAVE_GLOBAL:
preset_type = SHADER_PRESET_GLOBAL;
2019-08-17 20:05:20 +02:00
break;
case ACTION_OK_SHADER_PRESET_SAVE_CORE:
preset_type = SHADER_PRESET_CORE;
break;
case ACTION_OK_SHADER_PRESET_SAVE_PARENT:
preset_type = SHADER_PRESET_PARENT;
break;
case ACTION_OK_SHADER_PRESET_SAVE_GAME:
preset_type = SHADER_PRESET_GAME;
break;
default:
return 0;
}
/* Save Auto Preset and have it immediately reapply the preset
2023-08-16 03:22:02 +02:00
* TODO: This seems necessary so that the loaded shader gains a link to the file saved
* But this is slow and seems like a redundant way to do this
* It seems like it would be better to just set the path and shader_preset_loaded
* on the current shader */
if (menu_shader_manager_save_auto_preset(menu_shader_get(), preset_type,
2020-02-19 22:06:21 +01:00
dir_video_shader, dir_menu_config,
true))
{
const char *_msg = msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
else
{
const char *_msg = msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
return 0;
}
2019-08-17 20:05:20 +02:00
static int action_ok_shader_preset_save_global(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_save(path, label, type,
2019-08-17 20:05:20 +02:00
idx, entry_idx, ACTION_OK_SHADER_PRESET_SAVE_GLOBAL);
}
2019-08-17 20:05:20 +02:00
static int action_ok_shader_preset_save_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_save(path, label, type,
2019-08-17 20:05:20 +02:00
idx, entry_idx, ACTION_OK_SHADER_PRESET_SAVE_CORE);
}
static int action_ok_shader_preset_save_parent(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_save(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_SAVE_PARENT);
}
2019-08-17 20:05:20 +02:00
static int action_ok_shader_preset_save_game(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_save(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_SAVE_GAME);
}
2019-08-24 01:44:50 +02:00
static int action_ok_shader_preset_remove_global(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_remove(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_REMOVE_GLOBAL);
}
static int action_ok_shader_preset_remove_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_remove(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_REMOVE_CORE);
}
static int action_ok_shader_preset_remove_parent(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_remove(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_REMOVE_PARENT);
}
static int action_ok_shader_preset_remove_game(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_shader_preset_remove(path, label, type,
idx, entry_idx, ACTION_OK_SHADER_PRESET_REMOVE_GAME);
}
#endif
2020-10-01 15:54:11 +01:00
static int action_ok_video_filter_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
settings_t *settings = config_get_ptr();
2020-10-01 15:54:11 +01:00
if (!settings)
return -1;
2020-10-01 15:54:11 +01:00
if (!string_is_empty(settings->paths.path_softfilter_plugin))
{
/* Unload video filter */
settings->paths.path_softfilter_plugin[0] = '\0';
command_event(CMD_EVENT_REINIT, NULL);
/* Refresh menu */
2024-12-25 19:06:04 +01:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
2020-10-01 15:54:11 +01:00
}
return 0;
}
2020-10-19 11:30:28 +01:00
static int action_ok_audio_dsp_plugin_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
settings_t *settings = config_get_ptr();
2020-10-19 11:30:28 +01:00
if (!settings)
return -1;
2020-10-19 11:30:28 +01:00
if (!string_is_empty(settings->paths.path_audio_dsp_plugin))
{
/* Unload DSP plugin filter */
2020-10-19 11:30:28 +01:00
settings->paths.path_audio_dsp_plugin[0] = '\0';
command_event(CMD_EVENT_DSP_FILTER_INIT, NULL);
/* Refresh menu */
2024-12-25 19:06:04 +01:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
2020-10-19 11:30:28 +01:00
}
return 0;
}
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
static void menu_input_st_string_cb_cheat_file_save_as(
void *userdata, const char *str)
{
if (str && *str)
{
rarch_setting_t *setting = NULL;
2023-08-16 03:22:02 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
const char *label = menu_st->input_dialog_kb_label;
2020-06-30 19:35:41 +02:00
settings_t *settings = config_get_ptr();
const char *path_cheat_database = settings->paths.path_cheat_database;
if (!string_is_empty(label))
setting = menu_setting_find(label);
if (setting)
{
if (setting->value.target.string)
strlcpy(setting->value.target.string, str, setting->size);
if (setting->change_handler)
setting->change_handler(setting);
2020-06-30 19:35:41 +02:00
menu_setting_generic(setting, 0, false);
}
else if (!string_is_empty(label))
cheat_manager_save(str, path_cheat_database,
false);
}
menu_input_dialog_end();
}
#endif
DEFAULT_ACTION_DIALOG_START(action_ok_enable_settings,
msg_hash_to_str(MSG_INPUT_ENABLE_SETTINGS_PASSWORD),
(unsigned)entry_idx,
menu_input_st_string_cb_enable_settings)
#ifdef HAVE_CHEATS
DEFAULT_ACTION_DIALOG_START(action_ok_cheat_file_save_as,
msg_hash_to_str(MSG_INPUT_CHEAT_FILENAME),
(unsigned)idx,
menu_input_st_string_cb_cheat_file_save_as)
#endif
DEFAULT_ACTION_DIALOG_START(action_ok_disable_kiosk_mode,
msg_hash_to_str(MSG_INPUT_KIOSK_MODE_PASSWORD),
(unsigned)entry_idx,
menu_input_st_string_cb_disable_kiosk_mode)
DEFAULT_ACTION_DIALOG_START(action_ok_rename_entry,
msg_hash_to_str(MSG_INPUT_RENAME_ENTRY),
(unsigned)entry_idx,
menu_input_st_string_cb_rename_entry)
static int generic_action_ok_remap_file_operation(const char *path,
2015-09-04 21:59:04 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx,
unsigned action_type)
{
#ifdef HAVE_CONFIGFILE
char remap_file_path[PATH_MAX_LENGTH];
char remap_path[PATH_MAX_LENGTH];
struct menu_state *menu_st = menu_state_get_ptr();
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
const char *core_name = sys_info ? sys_info->info.library_name : NULL;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
bool has_content = !string_is_empty(rarch_path_basename);
settings_t *settings = config_get_ptr();
const char *directory_input_remapping = settings->paths.directory_input_remapping;
unsigned joypad_port = settings->uints.input_joypad_index[0];
const char *input_device_name = input_config_get_device_display_name(joypad_port);
const char *input_device_dir = NULL;
bool sort_remaps_by_controller = settings->bools.input_remap_sort_by_controller_enable;
size_t _len = 0;
remap_file_path[0] = '\0';
2016-10-08 19:47:26 +02:00
/* Cannot perform remap file operation if we
* have no core */
if (string_is_empty(core_name))
return -1;
2024-10-02 03:36:33 +03:00
if ( sort_remaps_by_controller
2024-12-25 19:06:04 +01:00
&& (input_device_name != NULL)
&& !string_is_empty(input_device_name))
{
/* Ensure directory does not contain special chars */
input_device_dir = sanitize_path_part(input_device_name, strlen(input_device_name));
2024-10-02 03:36:33 +03:00
/* Allocate memory for the new path */
/* Build the new path with the controller name */
_len = strlcpy(remap_path, core_name, sizeof(remap_path));
_len += strlcpy(remap_path + _len, PATH_DEFAULT_SLASH(), sizeof(remap_path) - _len);
_len += strlcpy(remap_path + _len, input_device_dir, sizeof(remap_path) - _len);
2024-10-02 03:36:33 +03:00
/* Deallocate as we no longer this */
free((char*)input_device_dir);
input_device_dir = NULL;
}
else /* We're not using controller path, just use core name */
strlcpy(remap_path, core_name, sizeof(remap_path));
2015-09-04 21:59:04 +02:00
switch (action_type)
{
case ACTION_OK_REMAP_FILE_SAVE_AS:
fill_pathname_join_special_ext(remap_file_path,
directory_input_remapping, remap_path,
path,
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file_path));
break;
2015-09-04 21:59:04 +02:00
case ACTION_OK_REMAP_FILE_SAVE_CORE:
2017-08-05 00:37:26 -05:00
case ACTION_OK_REMAP_FILE_REMOVE_CORE:
fill_pathname_join_special_ext(remap_file_path,
directory_input_remapping, remap_path,
core_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file_path));
2015-09-04 21:59:04 +02:00
break;
case ACTION_OK_REMAP_FILE_SAVE_GAME:
2017-08-05 00:37:26 -05:00
case ACTION_OK_REMAP_FILE_REMOVE_GAME:
if (has_content)
fill_pathname_join_special_ext(remap_file_path,
directory_input_remapping, remap_path,
path_basename(rarch_path_basename),
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file_path));
2015-09-04 21:59:04 +02:00
break;
case ACTION_OK_REMAP_FILE_SAVE_CONTENT_DIR:
case ACTION_OK_REMAP_FILE_REMOVE_CONTENT_DIR:
if (has_content)
{
char content_dir_name[DIR_MAX_LENGTH];
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
fill_pathname_join_special_ext(remap_file_path,
directory_input_remapping, remap_path,
content_dir_name,
FILE_PATH_REMAP_EXTENSION,
sizeof(remap_file_path));
}
break;
2015-09-04 21:59:04 +02:00
}
2015-04-07 22:51:31 -05:00
2017-08-05 00:37:26 -05:00
if (action_type < ACTION_OK_REMAP_FILE_REMOVE_CORE)
{
const char *_msg;
2023-07-15 15:14:26 +02:00
if ( !string_is_empty(remap_file_path)
&& input_remapping_save_file(remap_file_path))
2017-08-05 00:37:26 -05:00
{
switch (action_type)
{
case ACTION_OK_REMAP_FILE_SAVE_CORE:
retroarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL);
break;
case ACTION_OK_REMAP_FILE_SAVE_GAME:
retroarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL);
break;
case ACTION_OK_REMAP_FILE_SAVE_CONTENT_DIR:
retroarch_ctl(RARCH_CTL_SET_REMAPS_CONTENT_DIR_ACTIVE, NULL);
break;
}
2017-08-05 00:37:26 -05:00
_msg = msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* TODO/FIXME - localize */
RARCH_LOG("[Remap]: File saved successfully: \"%s\".\n",remap_file_path);
2017-08-05 00:37:26 -05:00
}
else
{
_msg = msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* TODO/FIXME - localize */
RARCH_ERR("[Remap]: File save unsuccessful: \"%s\".\n",remap_file_path);
}
2017-08-05 00:37:26 -05:00
}
2015-04-07 22:40:42 -05:00
else
2017-08-05 00:37:26 -05:00
{
2023-05-09 05:21:59 +02:00
if ( !string_is_empty(remap_file_path)
&& (filestream_delete(remap_file_path) == 0))
2017-08-05 00:37:26 -05:00
{
const char *_msg;
2022-10-10 08:59:27 +02:00
uint32_t flags = runloop_get_flags();
switch (action_type)
2017-09-11 22:49:39 -05:00
{
case ACTION_OK_REMAP_FILE_REMOVE_CORE:
2022-10-10 08:59:27 +02:00
if (flags & RUNLOOP_FLAG_REMAPS_CORE_ACTIVE)
input_remapping_deinit(false);
break;
case ACTION_OK_REMAP_FILE_REMOVE_GAME:
2022-10-10 08:59:27 +02:00
if (flags & RUNLOOP_FLAG_REMAPS_GAME_ACTIVE)
input_remapping_deinit(false);
break;
case ACTION_OK_REMAP_FILE_REMOVE_CONTENT_DIR:
2022-10-10 08:59:27 +02:00
if (flags & RUNLOOP_FLAG_REMAPS_CONTENT_DIR_ACTIVE)
input_remapping_deinit(false);
break;
}
_msg = msg_hash_to_str(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* After removing a remap file, attempt to
* load any remaining remap file with the
* next highest priority */
config_load_remap(directory_input_remapping, sys_info);
2017-08-05 00:37:26 -05:00
}
else
{
const char *_msg = msg_hash_to_str(MSG_ERROR_REMOVING_REMAP_FILE);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
2017-08-05 00:37:26 -05:00
}
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
#endif
return 0;
}
static void menu_input_st_string_cb_remap_file_save_as(
void *userdata, const char *str)
{
#ifdef HAVE_CONFIGFILE
if (str && *str)
{
rarch_setting_t *setting = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
const char *label = menu_st->input_dialog_kb_label;
if (!string_is_empty(label))
setting = menu_setting_find(label);
if (setting)
{
if (setting->value.target.string)
strlcpy(setting->value.target.string, str, setting->size);
if (setting->change_handler)
setting->change_handler(setting);
menu_setting_generic(setting, 0, false);
}
else if (!string_is_empty(label))
generic_action_ok_remap_file_operation(str, label, 0,
0, 0, ACTION_OK_REMAP_FILE_SAVE_AS);
}
menu_input_dialog_end();
#endif
}
DEFAULT_ACTION_DIALOG_START(action_ok_remap_file_save_as,
msg_hash_to_str(MSG_INPUT_REMAP_FILENAME),
(unsigned)idx,
menu_input_st_string_cb_remap_file_save_as)
static int action_ok_remap_file_save_core(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
2015-09-04 21:59:04 +02:00
idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_CORE);
}
2015-04-07 22:51:31 -05:00
static int action_ok_remap_file_save_content_dir(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_CONTENT_DIR);
}
static int action_ok_remap_file_save_game(const char *path,
2015-09-04 21:59:04 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
2015-09-04 21:59:04 +02:00
idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_GAME);
}
static int action_ok_remap_file_remove_core(const char *path,
2017-08-05 00:37:26 -05:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
2017-08-05 00:37:26 -05:00
idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_CORE);
}
static int action_ok_remap_file_remove_content_dir(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_CONTENT_DIR);
}
static int action_ok_remap_file_remove_game(const char *path,
2017-08-05 00:37:26 -05:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_remap_file_operation(path, label, type,
2017-08-05 00:37:26 -05:00
idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_GAME);
}
static int action_ok_remap_file_reset(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *_msg = msg_hash_to_str(MSG_REMAP_FILE_RESET);
input_remapping_set_defaults(false);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return 0;
}
static int action_ok_remap_file_flush(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-12-25 19:06:04 +01:00
char msg[128];
runloop_state_t *runloop_st = runloop_state_get_ptr();
const char *path_remapfile = runloop_st->name.remapfile;
const char *remapfile = NULL;
bool success = false;
msg[0] = '\0';
/* Check if a remap file is active */
if (!string_is_empty(path_remapfile))
{
/* Update existing remap file */
success = input_remapping_save_file(path_remapfile);
/* Get remap file name for display purposes */
remapfile = path_basename_nocompression(path_remapfile);
}
if (string_is_empty(remapfile))
remapfile = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN);
/* Log result */
if (success)
{
/* TODO/FIXME - localize */
RARCH_LOG(
"[Remaps]: Saved input remapping options to \"%s\".\n",
path_remapfile ? path_remapfile : "UNKNOWN");
_len = snprintf(msg, sizeof(msg), "%s \"%s\"",
msg_hash_to_str(MSG_REMAP_FILE_FLUSHED),
remapfile);
}
else
{
/* TODO/FIXME - localize */
RARCH_LOG(
"[Remaps]: Failed to save input remapping options to \"%s\".\n",
path_remapfile ? path_remapfile : "UNKNOWN");
_len = snprintf(msg, sizeof(msg), "%s \"%s\"",
msg_hash_to_str(MSG_REMAP_FILE_FLUSH_FAILED),
remapfile);
}
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return 0;
}
static void menu_input_st_string_cb_override_file_save_as(
void *userdata, const char *str)
{
#ifdef HAVE_CONFIGFILE
if (str && *str)
{
rarch_setting_t *setting = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
const char *label = menu_st->input_dialog_kb_label;
const char *msg_str = NULL;
int ret = false;
if (!string_is_empty(label))
setting = menu_setting_find(label);
if (setting)
{
if (setting->value.target.string)
strlcpy(setting->value.target.string, str, setting->size);
if (setting->change_handler)
setting->change_handler(setting);
menu_setting_generic(setting, 0, false);
}
else if (!string_is_empty(label))
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
ret = config_save_overrides(OVERRIDE_AS, &runloop_st->system, false, str);
}
switch (ret)
{
case 1:
msg_str = msg_hash_to_str(MSG_OVERRIDES_SAVED_SUCCESSFULLY);
break;
case -1:
msg_str = msg_hash_to_str(MSG_OVERRIDES_NOT_SAVED);
break;
default:
case 0:
msg_str = msg_hash_to_str(MSG_OVERRIDES_ERROR_SAVING);
break;
}
runloop_msg_queue_push(msg_str, strlen(msg_str), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
menu_input_dialog_end();
#endif
}
DEFAULT_ACTION_DIALOG_START(action_ok_override_file_save_as,
msg_hash_to_str(MSG_INPUT_OVERRIDE_FILENAME),
(unsigned)idx,
menu_input_st_string_cb_override_file_save_as)
static int action_ok_override_unload(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifdef HAVE_CONFIGFILE
2023-05-09 05:21:59 +02:00
if (config_unload_override())
{
const char *_msg = msg_hash_to_str(MSG_OVERRIDES_UNLOADED_SUCCESSFULLY);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
#endif
return 0;
}
int action_ok_path_use_directory(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
filebrowser_clear_type();
return generic_action_ok(NULL, label, type, idx, entry_idx,
ACTION_OK_SET_DIRECTORY, MSG_UNKNOWN);
}
2015-11-24 01:12:50 +01:00
#ifdef HAVE_LIBRETRODB
static int action_ok_scan_file(const char *path,
2015-07-04 02:07:18 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return action_scan_file(path, label, type, idx);
}
static int action_ok_path_scan_directory(const char *path,
2015-07-04 01:51:41 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return action_scan_directory(NULL, label, type, idx);
}
2015-11-24 01:12:50 +01:00
#endif
2015-07-04 01:51:41 +02:00
2019-11-29 17:13:35 +00:00
static int action_ok_path_manual_scan_directory(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char content_dir[DIR_MAX_LENGTH];
2019-11-29 17:13:35 +00:00
const char *flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MANUAL_CONTENT_SCAN_LIST);
unsigned flush_type = 0;
const char *menu_path = NULL;
content_dir[0] = '\0';
2019-11-29 17:13:35 +00:00
/* 'Reset' file browser */
filebrowser_clear_type();
/* Get user-selected scan directory */
menu_entries_get_last_stack(&menu_path,
NULL, NULL, NULL, NULL);
if (!string_is_empty(menu_path))
strlcpy(content_dir, menu_path, sizeof(content_dir));
#ifdef HAVE_COCOATOUCH
{
/* For iOS, set the path using realpath because the path name
* can start with /private and this ensures the path starts with it.
* This will allow the path to be properly substituted when
* fill_pathname_expand_special() is called. */
char tmp_dir[DIR_MAX_LENGTH];
2024-04-19 10:12:13 -04:00
tmp_dir[0] = '\0';
fill_pathname_expand_special(tmp_dir, content_dir, sizeof(content_dir));
realpath(tmp_dir, content_dir);
2019-11-29 17:13:35 +00:00
}
#endif
/* Update manual content scan settings */
manual_content_scan_set_menu_content_dir(content_dir);
/* Return to 'manual content scan' menu */
menu_entries_flush_stack(flush_char, flush_type);
return 0;
}
static int action_ok_core_deferred_set(const char *new_core_path,
2018-03-22 19:46:02 -04:00
const char *content_label, unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
char msg[128];
char resolved_core_path[PATH_MAX_LENGTH];
struct menu_state *menu_st = menu_state_get_ptr();
struct playlist_entry entry = {0};
size_t selection = menu_st->selection_ptr;
menu_handle_t *menu = menu_st->driver_data;
core_info_t *core_info = NULL;
const char *core_display_name = NULL;
2022-11-17 19:07:54 +01:00
if ( !menu
|| string_is_empty(new_core_path))
return -1;
/* Get core display name */
if (core_info_find(new_core_path, &core_info))
core_display_name = core_info->display_name;
if (string_is_empty(core_display_name))
core_display_name = path_basename_nocompression(new_core_path);
/* Get 'real' core path */
2020-01-14 12:28:10 +00:00
strlcpy(resolved_core_path, new_core_path, sizeof(resolved_core_path));
playlist_resolve_path(PLAYLIST_SAVE, true, resolved_core_path, sizeof(resolved_core_path));
/* the update function reads our entry
* as const, so these casts are safe */
entry.core_path = (char*)resolved_core_path;
entry.core_name = (char*)core_display_name;
command_playlist_update_write(
NULL,
menu->scratchpad.unsigned_var,
2020-06-26 15:39:03 +01:00
&entry);
/* Provide visual feedback */
_len = strlcpy(msg, msg_hash_to_str(MSG_SET_CORE_ASSOCIATION), sizeof(msg));
_len += strlcpy(msg + _len, core_display_name, sizeof(msg) - _len);
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
menu_entries_pop_stack(&selection, 0, 1);
menu_st->selection_ptr = selection;
2020-01-14 12:28:10 +00:00
return 0;
}
static int action_ok_deferred_list_stub(const char *path,
2016-06-20 19:54:04 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return 0;
}
#if defined(HAVE_LIBNX)
2018-10-06 14:52:44 +02:00
static int action_ok_set_switch_cpu_profile(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-12-25 19:06:04 +01:00
size_t _len;
2018-10-06 14:52:44 +02:00
char command[PATH_MAX_LENGTH] = {0};
2024-12-25 19:06:04 +01:00
unsigned profile_clock = SWITCH_CPU_SPEEDS_VALUES[entry_idx];
settings_t *settings = config_get_ptr();
2020-02-19 20:57:02 +01:00
settings->uints.libnx_overclock = entry_idx;
if (hosversionBefore(8, 0, 0))
pcvSetClockRate(PcvModule_CpuBus, (u32)profile_clock);
else
{
ClkrstSession session = {0};
clkrstOpenSession(&session, PcvModuleId_CpuBus, 3);
clkrstSetClockRate(&session, profile_clock);
clkrstCloseSession(&session);
}
/* TODO/FIXME - localize */
_len = strlcpy(command, "Current clock set to", sizeof(command));
_len += snprintf(command + _len, sizeof(command) - _len, "%i", profile_clock);
runloop_msg_queue_push(command, _len, 1, 90, true, NULL,
2020-02-21 03:28:23 +01:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2018-10-06 14:52:44 +02:00
return -1;
2018-10-06 14:52:44 +02:00
}
#endif
static int action_ok_load_core_deferred(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2017-04-27 01:23:04 +02:00
content_ctx_info_t content_info;
2023-05-09 04:58:06 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2017-04-27 01:23:04 +02:00
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2017-02-21 18:36:38 +01:00
if (!task_push_load_content_with_new_core_from_menu(
path, menu->deferred_path,
&content_info,
CORE_TYPE_PLAIN,
NULL, NULL))
return -1;
2023-05-09 04:58:06 +02:00
menu_driver_set_last_start_content(menu_st, path);
return 0;
}
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_START_BUILTIN_CORE(action_ok_start_net_retropad_core, CORE_TYPE_NETRETROPAD)
DEFAULT_ACTION_OK_START_BUILTIN_CORE(action_ok_start_video_processor_core, CORE_TYPE_VIDEO_PROCESSOR)
2017-05-28 18:33:44 +02:00
2018-06-20 04:50:58 +02:00
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
static int action_ok_file_load_ffmpeg(const char *path,
2016-06-20 19:54:04 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char new_path[PATH_MAX_LENGTH];
const char *menu_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_list_t *menu_list = menu_st->entries.list;
file_list_t *menu_stack = MENU_LIST_GET(menu_list, 0);
2017-11-26 07:29:19 +01:00
if (menu_stack && menu_stack->size)
menu_path = menu_stack->list[menu_stack->size - 1].path;
if (string_is_empty(menu_path))
return -1;
fill_pathname_join_special(new_path, menu_path, path,
sizeof(new_path));
2017-02-21 18:36:38 +01:00
2018-06-20 04:50:58 +02:00
/* TODO/FIXME - should become runtime optional */
#ifdef HAVE_MPV
2020-02-21 03:28:23 +01:00
return default_action_ok_load_content_with_core_from_menu(
new_path, CORE_TYPE_MPV);
2018-06-20 04:50:58 +02:00
#else
2020-02-21 03:28:23 +01:00
return default_action_ok_load_content_with_core_from_menu(
new_path, CORE_TYPE_FFMPEG);
2018-06-20 04:50:58 +02:00
#endif
}
2017-05-28 18:33:44 +02:00
#endif
static int action_ok_audio_run(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char combined_path[PATH_MAX_LENGTH];
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
fill_pathname_join_special(combined_path, menu->scratch2_buf,
menu->scratch_buf, sizeof(combined_path));
2018-06-20 04:50:58 +02:00
/* TODO/FIXME - should become runtime optional */
#ifdef HAVE_MPV
2020-02-21 03:28:23 +01:00
return default_action_ok_load_content_with_core_from_menu(
combined_path, CORE_TYPE_MPV);
2018-06-20 04:50:58 +02:00
#else
2020-02-21 03:28:23 +01:00
return default_action_ok_load_content_with_core_from_menu(
combined_path, CORE_TYPE_FFMPEG);
2018-06-20 04:50:58 +02:00
#endif
}
int action_ok_core_option_dropdown_list(const char *path,
2018-09-23 18:36:48 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-12-25 19:06:04 +01:00
size_t _len;
2024-09-09 22:18:23 +02:00
char option_path_str[64];
char option_lbl_str[64];
2020-07-24 15:31:50 +01:00
core_option_manager_t *coreopts = NULL;
struct core_option *option = NULL;
const char *value_label_0 = NULL;
const char *value_label_1 = NULL;
2022-11-17 19:07:54 +01:00
size_t option_index = type - MENU_SETTINGS_CORE_OPTION_START;
2020-07-24 15:31:50 +01:00
2022-11-17 19:07:54 +01:00
option_lbl_str[0] = '\0';
2021-08-06 15:32:51 +01:00
2020-07-24 15:31:50 +01:00
/* Boolean options are toggled directly,
* without the use of a drop-down list */
/* > Get current option index */
if (type < MENU_SETTINGS_CORE_OPTION_START)
goto push_dropdown_list;
/* > Get core options struct */
if (!retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts) ||
2020-07-24 15:31:50 +01:00
(option_index >= coreopts->size))
goto push_dropdown_list;
/* > Get current option, and check whether
* it has exactly 2 values (i.e. on/off) */
option = (struct core_option*)&coreopts->opts[option_index];
2022-11-17 19:07:54 +01:00
if ( (!option)
|| (option->vals->size != 2)
|| ((option->index != 0)
&& (option->index != 1))
)
2020-07-24 15:31:50 +01:00
goto push_dropdown_list;
/* > Check whether option values correspond
* to a boolean toggle */
value_label_0 = option->val_labels->elems[0].data;
value_label_1 = option->val_labels->elems[1].data;
2022-11-17 19:07:54 +01:00
if ( string_is_empty(value_label_0)
|| string_is_empty(value_label_1)
2022-12-25 19:17:16 +02:00
|| !( ( string_is_equal(value_label_0, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))
2024-09-09 22:18:23 +02:00
&& string_is_equal(value_label_1, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
2022-12-25 19:17:16 +02:00
|| ( string_is_equal(value_label_0, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
2024-09-09 22:18:23 +02:00
&& string_is_equal(value_label_1, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON)))))
2020-07-24 15:31:50 +01:00
goto push_dropdown_list;
/* > Update value and return */
core_option_manager_set_val(coreopts, option_index,
(option->index == 0) ? 1 : 0, true);
2020-07-24 15:31:50 +01:00
return 0;
push_dropdown_list:
/* If this option is not a boolean toggle,
* push drop-down list */
2024-12-25 19:06:04 +01:00
_len = strlcpy(option_path_str, "core_option_",
sizeof(option_path_str));
snprintf(option_path_str + _len,
sizeof(option_path_str) - _len,
"%d", (int)option_index);
2020-07-24 15:31:50 +01:00
snprintf(option_lbl_str, sizeof(option_lbl_str),
"%d", type);
2018-09-23 18:36:48 +02:00
2020-07-24 15:31:50 +01:00
/* TODO/FIXME: This should be refactored to make
* use of a core-option-specific drop-down list,
* rather than hijacking the generic one... */
2018-09-23 18:36:48 +02:00
generic_action_ok_displaylist_push(
2020-07-24 15:31:50 +01:00
option_path_str, NULL,
2023-07-17 22:32:13 +03:00
option_lbl_str, 0,
idx, 0,
2018-09-23 18:36:48 +02:00
ACTION_OK_DL_DROPDOWN_BOX_LIST);
2020-07-24 15:31:50 +01:00
2018-09-23 18:36:48 +02:00
return 0;
}
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
static int action_ok_cheat_reload_cheats(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
2020-02-19 22:06:21 +01:00
settings_t *settings = config_get_ptr();
const char *path_cheat_database = settings->paths.path_cheat_database;
cheat_manager_realloc(0, CHEAT_HANDLER_TYPE_EMU);
cheat_manager_load_game_specific_cheats(
2020-02-19 22:06:21 +01:00
path_cheat_database);
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
2020-02-21 03:28:23 +01:00
return 0;
}
2020-06-30 19:35:41 +02:00
#endif
static int action_ok_start_recording(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
streaming_set_state(false);
command_event(CMD_EVENT_RECORD_INIT, NULL);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
static int action_ok_start_streaming(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
streaming_set_state(true);
command_event(CMD_EVENT_RECORD_INIT, NULL);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
static int action_ok_stop_recording(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
command_event(CMD_EVENT_RECORD_DEINIT, NULL);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
static int action_ok_stop_streaming(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
command_event(CMD_EVENT_RECORD_DEINIT, NULL);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
static int action_ok_cheat_add_top(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2018-07-28 22:11:56 +02:00
int i;
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
struct item_cheat tmp;
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
2018-07-28 22:11:56 +02:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
2020-02-21 03:28:23 +01:00
memcpy(&tmp, &cheat_manager_state.cheats[cheat_manager_state.size-1],
sizeof(struct item_cheat));
tmp.idx = 0;
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.size-2; i >=0; i--)
{
2018-07-29 19:04:53 +02:00
memcpy(&cheat_manager_state.cheats[i+1],
2018-09-23 12:49:05 +02:00
&cheat_manager_state.cheats[i], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i+1].idx++;
}
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[0], &tmp, sizeof(struct item_cheat));
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_TOP_SUCCESS), sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
2020-02-21 03:28:23 +01:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_add_bottom(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
2018-07-29 19:04:53 +02:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
_len = strlcpy(msg,
2018-07-29 19:04:53 +02:00
msg_hash_to_str(MSG_CHEAT_ADD_BOTTOM_SUCCESS), sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
2020-02-21 03:28:23 +01:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_delete_all(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
struct menu_state *menu_st = menu_state_get_ptr();
2020-02-21 03:28:23 +01:00
cheat_manager_state.delete_state = 0;
cheat_manager_realloc(0, CHEAT_HANDLER_TYPE_EMU);
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_DELETE_ALL_SUCCESS),
sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
2020-02-21 03:28:23 +01:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_add_new_after(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2018-07-28 22:11:56 +02:00
int i;
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
2018-07-28 22:11:56 +02:00
struct item_cheat tmp;
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
2020-02-21 03:28:23 +01:00
memcpy(&tmp, &cheat_manager_state.cheats[cheat_manager_state.size-1],
sizeof(struct item_cheat));
tmp.idx = cheat_manager_state.working_cheat.idx+1;
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.size-2; i >= (int)(cheat_manager_state.working_cheat.idx+1); i--)
{
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[i+1], &cheat_manager_state.cheats[i], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i+1].idx++;
}
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx+1], &tmp, sizeof(struct item_cheat));
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_AFTER_SUCCESS),
sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_add_new_before(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2018-07-28 22:11:56 +02:00
int i;
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
2020-02-21 03:28:23 +01:00
struct item_cheat tmp;
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_EMU);
2018-09-23 12:49:05 +02:00
memcpy(&tmp, &cheat_manager_state.cheats[cheat_manager_state.size-1], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
tmp.idx = cheat_manager_state.working_cheat.idx;
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.size-2; i >=(int)tmp.idx; i--)
{
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[i+1], &cheat_manager_state.cheats[i], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i+1].idx++;
}
2018-07-29 19:04:53 +02:00
memcpy(&cheat_manager_state.cheats[tmp.idx],
2018-09-23 12:49:05 +02:00
&tmp, sizeof(struct item_cheat));
2018-07-29 19:04:53 +02:00
memcpy(&cheat_manager_state.working_cheat,
2018-09-23 12:49:05 +02:00
&tmp, sizeof(struct item_cheat));
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_ADD_BEFORE_SUCCESS), sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_copy_before(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2018-07-28 22:11:56 +02:00
int i;
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
struct item_cheat tmp;
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO);
2018-09-23 12:49:05 +02:00
memcpy(&tmp, &cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
tmp.idx = cheat_manager_state.working_cheat.idx;
2018-09-23 12:10:33 +02:00
if (tmp.code)
2018-09-23 12:49:05 +02:00
tmp.code = strdup(tmp.code);
2018-09-23 12:10:33 +02:00
if (tmp.desc)
2018-09-23 12:49:05 +02:00
tmp.desc = strdup(tmp.desc);
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.size-2; i >=(int)tmp.idx; i--)
{
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[i+1], &cheat_manager_state.cheats[i], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i+1].idx++;
}
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[tmp.idx], &tmp, sizeof(struct item_cheat));
memcpy(&cheat_manager_state.working_cheat, &tmp, sizeof(struct item_cheat));
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_COPY_BEFORE_SUCCESS), sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_copy_after(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2018-07-28 22:11:56 +02:00
int i;
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
struct item_cheat tmp;
struct menu_state *menu_st = menu_state_get_ptr();
unsigned int new_size = cheat_manager_get_size() + 1;
2018-07-28 22:11:56 +02:00
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO);
2018-09-23 12:49:05 +02:00
memcpy(&tmp, &cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
tmp.idx = cheat_manager_state.working_cheat.idx+1;
2018-09-23 12:10:33 +02:00
if (tmp.code)
2018-09-23 12:49:05 +02:00
tmp.code = strdup(tmp.code);
2018-09-23 12:10:33 +02:00
if (tmp.desc)
2018-09-23 12:49:05 +02:00
tmp.desc = strdup(tmp.desc);
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.size-2; i >= (int)(cheat_manager_state.working_cheat.idx+1); i--)
{
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[i+1], &cheat_manager_state.cheats[i], sizeof(struct item_cheat));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i+1].idx++;
}
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx+1], &tmp, sizeof(struct item_cheat ));
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_COPY_AFTER_SUCCESS),
sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2020-02-21 03:28:23 +01:00
return 0;
}
static int action_ok_cheat_delete(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
size_t new_selection_ptr = 0;
struct menu_state *menu_st = menu_state_get_ptr();
2023-05-11 05:22:17 +02:00
size_t selection = menu_st->selection_ptr;
unsigned int new_size = cheat_manager_get_size() - 1;
2018-09-23 12:10:33 +02:00
if (new_size >0)
{
2018-07-28 22:11:56 +02:00
unsigned i;
2020-03-26 14:57:02 +01:00
2018-09-23 12:10:33 +02:00
if (cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].code)
2018-09-23 12:49:05 +02:00
free(cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].code);
2018-09-23 12:10:33 +02:00
if (cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].desc)
2018-09-23 12:49:05 +02:00
free(cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].desc);
2020-03-26 14:57:02 +01:00
2020-02-21 03:28:23 +01:00
for (i = cheat_manager_state.working_cheat.idx; i <cheat_manager_state.size-1; i++)
{
2018-09-23 12:49:05 +02:00
memcpy(&cheat_manager_state.cheats[i], &cheat_manager_state.cheats[i+1], sizeof(struct item_cheat ));
2020-02-21 03:28:23 +01:00
cheat_manager_state.cheats[i].idx--;
}
2020-03-26 14:57:02 +01:00
cheat_manager_state.cheats[cheat_manager_state.size-1].code = NULL;
cheat_manager_state.cheats[cheat_manager_state.size-1].desc = NULL;
cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].desc = NULL;
cheat_manager_state.cheats[cheat_manager_state.working_cheat.idx].code = NULL;
}
cheat_manager_realloc(new_size, CHEAT_HANDLER_TYPE_RETRO);
_len = strlcpy(msg, msg_hash_to_str(MSG_CHEAT_DELETE_SUCCESS), sizeof(msg));
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
new_selection_ptr = menu_st->selection_ptr;
menu_entries_pop_stack(&new_selection_ptr, 0, 1);
menu_st->selection_ptr = new_selection_ptr;
2023-05-11 05:22:17 +02:00
if (menu_st->driver_ctx)
{
if (menu_st->driver_ctx->update_savestate_thumbnail_path)
menu_st->driver_ctx->update_savestate_thumbnail_path(
menu_st->userdata, (unsigned)selection);
if (menu_st->driver_ctx->update_savestate_thumbnail_image)
menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata);
}
return 0;
}
2020-06-30 19:35:41 +02:00
#endif
static int action_ok_file_load_imageviewer(const char *path,
2015-06-28 17:21:32 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2016-10-26 06:23:05 +02:00
char fullpath[PATH_MAX_LENGTH];
2016-06-20 19:54:04 +02:00
const char *menu_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_list_t *menu_list = menu_st->entries.list;
file_list_t *menu_stack = MENU_LIST_GET(menu_list, 0);
2017-10-01 17:20:01 +02:00
if (menu_stack && menu_stack->size)
menu_path = menu_stack->list[menu_stack->size - 1].path;
2016-10-26 06:23:05 +02:00
2017-10-04 06:53:47 +02:00
if (!string_is_empty(menu_path))
fill_pathname_join_special(fullpath, menu_path, path,
sizeof(fullpath));
else
fullpath[0] = '\0';
2017-02-21 18:36:38 +01:00
2017-11-26 07:29:19 +01:00
return default_action_ok_load_content_with_core_from_menu(fullpath, CORE_TYPE_IMAGEVIEWER);
2015-06-28 17:21:32 +02:00
}
static int action_ok_file_load_current_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
return default_action_ok_load_content_with_core_from_menu(
menu->detect_content_path, CORE_TYPE_PLAIN);
}
static int action_ok_file_load_detect_core(const char *path,
2016-06-20 19:54:04 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2017-04-27 01:23:04 +02:00
content_ctx_info_t content_info;
2023-05-09 04:58:06 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2017-04-27 01:23:04 +02:00
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2017-02-21 18:36:38 +01:00
if (!task_push_load_content_with_new_core_from_menu(
path, menu->detect_content_path,
&content_info,
CORE_TYPE_PLAIN,
NULL, NULL))
return -1;
2023-05-09 04:58:06 +02:00
menu_driver_set_last_start_content(menu_st, menu->detect_content_path);
return 0;
2016-06-20 19:54:04 +02:00
}
static int action_ok_load_state(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-21 03:28:23 +01:00
bool resume = settings->bools.menu_savestate_resume;
2016-05-09 20:51:53 +02:00
if (generic_action_ok_command(CMD_EVENT_LOAD_STATE) == -1)
return -1;
if (resume)
return generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
static int action_ok_save_state(const char *path,
2016-06-04 14:34:06 -05:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-21 03:28:23 +01:00
bool resume = settings->bools.menu_savestate_resume;
2016-06-04 14:34:06 -05:00
if (generic_action_ok_command(CMD_EVENT_SAVE_STATE) == -1)
return -1;
if (resume)
return generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
2016-06-04 14:34:06 -05:00
}
static int action_ok_play_replay(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
bool resume = settings->bools.menu_savestate_resume;
if (generic_action_ok_command(CMD_EVENT_PLAY_REPLAY) == -1)
return -1;
if (resume)
return generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
static int action_ok_record_replay(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
bool resume = settings->bools.menu_savestate_resume;
if (generic_action_ok_command(CMD_EVENT_RECORD_REPLAY) == -1)
return -1;
if (resume)
return generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
static int action_ok_halt_replay(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
bool resume = settings->bools.menu_savestate_resume;
if (generic_action_ok_command(CMD_EVENT_HALT_REPLAY) == -1)
return -1;
if (resume)
return generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
static int action_ok_close_submenu(const char* path,
const char* label, unsigned type, size_t idx, size_t entry_idx)
{
return action_cancel_pop_default(path, label, type, idx);
}
2018-05-14 01:44:08 +02:00
static int action_ok_cheevos_toggle_hardcore_mode(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
generic_action_ok_command(CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE);
action_cancel_pop_default(path, label, type, idx);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
static int action_ok_undo_load_state(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
if (generic_action_ok_command(CMD_EVENT_UNDO_LOAD_STATE) == -1)
return -1;
return generic_action_ok_command(CMD_EVENT_RESUME);
}
static int action_ok_undo_save_state(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2016-06-04 14:34:06 -05:00
if (generic_action_ok_command(CMD_EVENT_UNDO_SAVE_STATE) == -1)
return -1;
2016-05-09 20:51:53 +02:00
return generic_action_ok_command(CMD_EVENT_RESUME);
}
2016-02-03 15:50:51 +01:00
#ifdef HAVE_NETWORKING
2016-10-30 03:27:43 +01:00
2016-05-11 21:22:45 +02:00
#ifdef HAVE_ZLIB
static void cb_decompressed(retro_task_t *task,
void *task_data, void *user_data, const char *err)
2016-02-03 15:50:51 +01:00
{
decompress_task_data_t *dec = (decompress_task_data_t*)task_data;
2016-02-03 15:50:51 +01:00
if (dec && !err)
2016-02-03 15:50:51 +01:00
{
2020-05-10 05:05:43 +02:00
unsigned enum_idx = (unsigned)(uintptr_t)user_data;
2016-06-29 17:07:18 +02:00
2020-05-10 05:05:43 +02:00
switch (enum_idx)
{
2020-05-10 05:05:43 +02:00
case MENU_ENUM_LABEL_CB_UPDATE_ASSETS:
case MENU_ENUM_LABEL_CB_UPDATE_AUTOCONFIG_PROFILES:
generic_action_ok_command(CMD_EVENT_REINIT);
break;
default:
break;
}
2016-02-03 15:50:51 +01:00
}
if (err)
RARCH_ERR("%s", err);
if (dec)
{
if (filestream_exists(dec->source_file))
filestream_delete(dec->source_file);
2016-02-03 15:50:51 +01:00
free(dec->source_file);
free(dec);
}
}
2016-05-11 21:22:45 +02:00
#endif
2016-02-03 15:50:51 +01:00
static int action_ok_core_updater_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
/* Get cached core updater list, initialising
* it if required */
2020-08-29 19:27:16 +02:00
core_updater_list_t *core_list = core_updater_list_get_cached();
if (!core_list)
{
core_updater_list_init_cached();
if (!(core_list = core_updater_list_get_cached()))
return -1;
}
#if defined(ANDROID)
if (play_feature_delivery_enabled())
{
2020-08-29 19:27:16 +02:00
settings_t *settings = config_get_ptr();
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_libretro_info = settings->paths.path_libretro_info;
/* Core downloads are handled via play
* feature delivery
* > Core list can be populated directly
* using the play feature delivery
* interface */
struct string_list *available_cores =
2020-08-29 19:27:16 +02:00
play_feature_delivery_available_cores();
bool success = false;
if (!available_cores)
return -1;
core_updater_list_reset(core_list);
success = core_updater_list_parse_pfd_data(
core_list,
path_dir_libretro,
path_libretro_info,
available_cores);
string_list_free(available_cores);
if (!success)
return -1;
/* Ensure network is initialised */
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
}
else
#endif
{
/* Initial setup... */
struct menu_state *menu_st = menu_state_get_ptr();
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NONBLOCKING_REFRESH;
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push core list update task */
task_push_get_core_updater_list(core_list, false, true);
}
return generic_action_ok_displaylist_push(
2023-07-17 22:32:13 +03:00
path, NULL,
label, type,
idx, entry_idx,
ACTION_OK_DL_CORE_UPDATER_LIST);
}
static void cb_net_generic_subdir(retro_task_t *task,
void *task_data, void *user_data, const char *err)
{
if (user_data)
free(user_data);
}
static void cb_net_generic(retro_task_t *task,
void *task_data, void *user_data, const char *err)
{
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
file_transfer_t *state = (file_transfer_t*)user_data;
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
if (!menu)
goto finish;
if (menu->core_buf)
free(menu->core_buf);
menu->core_buf = NULL;
menu->core_len = 0;
if (!data || err || !data->data)
goto finish;
menu->core_buf = (char*)malloc((data->len+1) * sizeof(char));
if (!menu->core_buf)
goto finish;
if (!string_is_empty(data->data))
memcpy(menu->core_buf, data->data, data->len * sizeof(char));
menu->core_buf[data->len] = '\0';
menu->core_len = data->len;
finish:
menu_st->flags &= ~MENU_ST_FLAG_ENTRIES_NONBLOCKING_REFRESH;
2023-08-16 03:22:02 +02:00
if ( !err
&& !string_ends_with_size(state->path,
FILE_PATH_INDEX_DIRS_URL,
strlen(state->path),
STRLEN_CONST(FILE_PATH_INDEX_DIRS_URL)
))
{
char parent_dir_encoded[DIR_MAX_LENGTH];
2024-12-24 05:10:09 +01:00
file_transfer_t *transf = (file_transfer_t*)malloc(sizeof(*transf));
parent_dir_encoded[0] = '\0';
2024-12-24 05:10:09 +01:00
transf->enum_idx = MSG_UNKNOWN;
2024-12-24 05:10:09 +01:00
fill_pathname_parent_dir(transf->path,
state->path, sizeof(transf->path));
strlcat(transf->path, FILE_PATH_INDEX_DIRS_URL,
sizeof(transf->path));
2024-12-24 05:10:09 +01:00
net_http_urlencode_full(parent_dir_encoded, transf->path,
sizeof(parent_dir_encoded));
task_push_http_transfer_file(parent_dir_encoded, true,
"index_dirs", cb_net_generic_subdir, transf);
}
if (state)
free(state);
}
static int generic_action_ok_network(const char *path,
2016-06-21 04:09:13 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx,
enum msg_hash_enums enum_idx)
{
2016-10-08 19:47:26 +02:00
char url_path[PATH_MAX_LENGTH];
char url_path_encoded[PATH_MAX_LENGTH];
2020-02-19 22:06:21 +01:00
unsigned type_id2 = 0;
file_transfer_t *transf = NULL;
const char *url_label = NULL;
retro_task_callback_t callback = NULL;
bool suppress_msg = false;
settings_t *settings = config_get_ptr();
struct menu_state *menu_st = menu_state_get_ptr();
2020-02-19 22:06:21 +01:00
const char *network_buildbot_assets_url =
settings->paths.network_buildbot_assets_url;
2016-06-21 04:09:13 +02:00
url_path[0] = '\0';
url_path_encoded[0] = '\0';
2016-10-08 19:47:26 +02:00
2016-06-21 04:09:13 +02:00
switch (enum_idx)
{
case MENU_ENUM_LABEL_CB_CORE_CONTENT_DIRS_LIST:
2020-02-19 22:06:21 +01:00
if (string_is_empty(network_buildbot_assets_url))
return -1;
fill_pathname_join_special(url_path,
2020-02-19 22:06:21 +01:00
network_buildbot_assets_url,
2020-08-22 13:04:52 +02:00
"cores/" FILE_PATH_INDEX_DIRS_URL,
sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_CORE_CONTENT_DIRS_LIST;
callback = cb_net_generic;
2016-07-12 05:22:24 +02:00
suppress_msg = true;
2016-06-21 04:09:13 +02:00
break;
case MENU_ENUM_LABEL_CB_CORE_CONTENT_LIST:
fill_pathname_join_special(url_path, path,
2020-08-22 13:04:52 +02:00
FILE_PATH_INDEX_URL, sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_CORE_CONTENT_LIST;
callback = cb_net_generic;
2016-07-12 05:22:24 +02:00
suppress_msg = true;
2016-06-21 04:09:13 +02:00
break;
case MENU_ENUM_LABEL_CB_CORE_SYSTEM_FILES_LIST:
if (string_is_empty(network_buildbot_assets_url))
return -1;
fill_pathname_join_special(url_path,
network_buildbot_assets_url,
"system/" FILE_PATH_INDEX_URL,
sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_CORE_SYSTEM_FILES_LIST;
callback = cb_net_generic;
suppress_msg = true;
break;
#if 0
/* Thumbnailpack removal */
2016-06-21 04:09:13 +02:00
case MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_LIST:
fill_pathname_join_special(url_path,
2020-08-22 13:04:52 +02:00
FILE_PATH_CORE_THUMBNAILPACKS_URL,
FILE_PATH_INDEX_URL, sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_THUMBNAILS_UPDATER_LIST;
callback = cb_net_generic;
2016-06-21 04:09:13 +02:00
break;
#endif
2016-06-21 04:09:13 +02:00
#ifdef HAVE_LAKKA
case MENU_ENUM_LABEL_CB_LAKKA_LIST:
/* TODO unhardcode this path */
fill_pathname_join_special(url_path,
2020-08-22 01:06:10 +02:00
FILE_PATH_LAKKA_URL,
LAKKA_PROJECT, sizeof(url_path));
fill_pathname_join_special(url_path, url_path,
2020-08-22 13:04:52 +02:00
FILE_PATH_INDEX_URL,
2016-06-21 04:09:13 +02:00
sizeof(url_path));
url_label = msg_hash_to_str(enum_idx);
type_id2 = ACTION_OK_DL_LAKKA_LIST;
callback = cb_net_generic;
2016-06-21 04:09:13 +02:00
break;
#endif
default:
break;
}
2023-05-21 17:49:34 +03:00
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NONBLOCKING_REFRESH;
2017-11-26 06:35:53 +01:00
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
2016-06-21 04:09:13 +02:00
transf = (file_transfer_t*)calloc(1, sizeof(*transf));
2016-07-11 19:33:07 +02:00
strlcpy(transf->path, url_path, sizeof(transf->path));
net_http_urlencode_full(url_path_encoded, url_path, sizeof(url_path_encoded));
2020-01-17 19:48:40 -07:00
task_push_http_transfer_file(url_path_encoded, suppress_msg, url_label, callback, transf);
2016-06-21 04:09:13 +02:00
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
label, type,
idx, entry_idx,
type_id2);
2016-06-21 04:09:13 +02:00
}
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_LIST(action_ok_core_content_list, MENU_ENUM_LABEL_CB_CORE_CONTENT_LIST)
DEFAULT_ACTION_OK_LIST(action_ok_core_content_dirs_list, MENU_ENUM_LABEL_CB_CORE_CONTENT_DIRS_LIST)
DEFAULT_ACTION_OK_LIST(action_ok_core_system_files_list, MENU_ENUM_LABEL_CB_CORE_SYSTEM_FILES_LIST)
#if 0
/* Thumbnailpack removal */
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_LIST(action_ok_thumbnails_updater_list, MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_LIST)
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_LIST(action_ok_lakka_list, MENU_ENUM_LABEL_CB_LAKKA_LIST)
2016-06-21 04:09:13 +02:00
static void cb_generic_dir_download(retro_task_t *task,
void *task_data,
2016-06-21 04:09:13 +02:00
void *user_data, const char *err)
{
file_transfer_t *transf = (file_transfer_t*)user_data;
2017-01-03 12:00:45 -05:00
if (transf)
{
generic_action_ok_network(transf->path, transf->path, 0, 0, 0,
MENU_ENUM_LABEL_CB_CORE_CONTENT_LIST);
2017-01-03 12:00:45 -05:00
free(transf);
}
2016-06-21 04:09:13 +02:00
}
/* expects http_transfer_t*, file_transfer_t* */
void cb_generic_download(retro_task_t *task,
void *task_data,
2016-02-03 15:50:51 +01:00
void *user_data, const char *err)
{
2016-10-08 19:47:26 +02:00
char output_path[PATH_MAX_LENGTH];
char buf[PATH_MAX_LENGTH];
2017-12-29 13:00:24 +01:00
#if defined(HAVE_COMPRESSION) && defined(HAVE_ZLIB)
bool extract = true;
#endif
2016-02-03 15:50:51 +01:00
const char *dir_path = NULL;
2020-02-19 20:57:02 +01:00
file_transfer_t *transf = (file_transfer_t*)user_data;
2016-02-03 15:50:51 +01:00
settings_t *settings = config_get_ptr();
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
if (!data || !data->data || !transf)
2016-02-03 15:50:51 +01:00
goto finish;
2016-10-08 19:47:26 +02:00
output_path[0] = '\0';
2024-10-02 03:36:33 +03:00
/* we have to determine dir_path at the time of writing or else
2016-02-03 15:50:51 +01:00
* we'd run into races when the user changes the setting during an
* http transfer. */
switch (transf->enum_idx)
2016-02-03 15:50:51 +01:00
{
case MENU_ENUM_LABEL_CB_CORE_THUMBNAILS_DOWNLOAD:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.directory_thumbnails;
break;
case MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.directory_core_assets;
2017-12-29 13:00:24 +01:00
#if defined(HAVE_COMPRESSION) && defined(HAVE_ZLIB)
2020-03-02 20:10:24 +01:00
extract = settings->bools.network_buildbot_auto_extract_archive;
2017-12-29 13:00:24 +01:00
#endif
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_CORE_SYSTEM_FILES_DOWNLOAD:
dir_path = settings->paths.directory_system;
break;
case MENU_ENUM_LABEL_CB_UPDATE_CORE_INFO_FILES:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.path_libretro_info;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_ASSETS:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.directory_assets;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_AUTOCONFIG_PROFILES:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.directory_autoconfig;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_DATABASES:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.path_content_database;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_OVERLAYS:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.directory_overlay;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_CHEATS:
2017-04-29 00:39:29 +02:00
dir_path = settings->paths.path_cheat_database;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_CG:
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL:
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
2016-12-14 16:33:54 +01:00
{
static char shaderdir[DIR_MAX_LENGTH] = {0};
2020-02-19 22:06:21 +01:00
const char *dirname = NULL;
const char *dir_video_shader = settings->paths.directory_video_shader;
2016-12-14 16:33:54 +01:00
2020-02-19 22:06:21 +01:00
switch (transf->enum_idx)
{
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_CG:
dirname = "shaders_cg";
break;
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL:
dirname = "shaders_glsl";
break;
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG:
dirname = "shaders_slang";
break;
default:
break;
}
2016-12-14 16:33:54 +01:00
fill_pathname_join_special(shaderdir, dir_video_shader,
2020-02-19 22:06:21 +01:00
dirname, sizeof(shaderdir));
2016-12-14 16:33:54 +01:00
2023-08-16 03:22:02 +02:00
if ( !path_is_directory(shaderdir)
2023-07-15 15:14:26 +02:00
&& !path_mkdir(shaderdir))
2016-02-03 15:50:51 +01:00
goto finish;
2016-12-14 16:33:54 +01:00
dir_path = shaderdir;
}
#endif
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD:
2016-03-23 21:40:41 +07:00
dir_path = LAKKA_UPDATE_DIR;
2016-02-03 15:50:51 +01:00
break;
case MENU_ENUM_LABEL_CB_DISCORD_AVATAR:
2020-08-19 06:53:09 +02:00
fill_pathname_application_special(buf, sizeof(buf),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS);
dir_path = buf;
break;
2016-02-03 15:50:51 +01:00
default:
RARCH_WARN("Unknown transfer type '%s' bailing out.\n",
msg_hash_to_str(transf->enum_idx));
2016-02-03 15:50:51 +01:00
break;
}
2016-06-29 12:13:40 +02:00
if (!string_is_empty(dir_path))
fill_pathname_join_special(output_path, dir_path,
2016-06-29 12:13:40 +02:00
transf->path, sizeof(output_path));
2016-02-03 15:50:51 +01:00
/* Make sure the directory exists
* This function is horrible. It mutates the original path
* so after operating we'll have to set the path to the intended
* location again...
*/
path_basedir_wrapper(output_path);
2016-06-29 12:13:40 +02:00
2016-02-03 15:50:51 +01:00
if (!path_mkdir(output_path))
{
2016-07-01 05:42:53 +02:00
err = msg_hash_to_str(MSG_FAILED_TO_CREATE_THE_DIRECTORY);
2016-02-03 15:50:51 +01:00
goto finish;
}
if (!string_is_empty(dir_path))
fill_pathname_join_special(output_path, dir_path,
transf->path, sizeof(output_path));
2016-02-03 15:50:51 +01:00
#ifdef HAVE_COMPRESSION
if (path_is_compressed_file(output_path))
{
2016-05-27 18:14:47 +02:00
if (task_check_decompress(output_path))
{
err = msg_hash_to_str(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS);
goto finish;
}
}
#endif
2016-03-24 04:09:25 +01:00
if (!filestream_write_file(output_path, data->data, data->len))
2016-02-03 15:50:51 +01:00
{
err = "Write failed.";
goto finish;
}
2016-10-30 03:27:43 +01:00
#if defined(HAVE_COMPRESSION) && defined(HAVE_ZLIB)
if (!extract)
2016-02-03 15:50:51 +01:00
goto finish;
if (path_is_compressed_file(output_path))
2016-02-03 15:50:51 +01:00
{
retro_task_t *decompress_task = NULL;
void *frontend_userdata = task->frontend_userdata;
task->frontend_userdata = NULL;
decompress_task = (retro_task_t*)task_push_decompress(
output_path, dir_path,
NULL, NULL, NULL,
2020-05-10 05:05:43 +02:00
cb_decompressed,
(void*)(uintptr_t)transf->enum_idx,
frontend_userdata, false);
if (!decompress_task)
{
err = msg_hash_to_str(MSG_DECOMPRESSION_FAILED);
goto finish;
}
2016-02-03 15:50:51 +01:00
}
#endif
finish:
if (err)
{
RARCH_ERR("[Updater]: Download of \"%s\" failed: %s\n",
(transf ? transf->path : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN)), err);
2016-02-03 15:50:51 +01:00
}
else
{
RARCH_LOG("[Updater]: Download \"%s\".\n",
(transf ? transf->path : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN)));
2018-12-24 15:06:21 -05:00
#ifdef HAVE_DISCORD
if (transf && transf->enum_idx == MENU_ENUM_LABEL_CB_DISCORD_AVATAR)
discord_avatar_set_ready(true);
2018-12-24 15:06:21 -05:00
#endif
}
2016-02-03 15:50:51 +01:00
if (transf)
free(transf);
}
static int action_ok_download_generic(const char *path,
const char *label, const char *menu_label,
unsigned type, size_t idx, size_t entry_idx,
enum msg_hash_enums enum_idx)
2015-06-24 15:56:49 +02:00
{
2016-10-08 19:47:26 +02:00
char s[PATH_MAX_LENGTH];
char s2[PATH_MAX_LENGTH];
2016-10-08 19:47:26 +02:00
char s3[PATH_MAX_LENGTH];
2020-02-19 20:57:02 +01:00
file_transfer_t *transf = NULL;
bool suppress_msg = false;
2016-06-21 04:09:13 +02:00
retro_task_callback_t cb = cb_generic_download;
2020-02-19 22:06:21 +01:00
settings_t *settings = config_get_ptr();
const char *network_buildbot_assets_url =
settings->paths.network_buildbot_assets_url;
const char *network_buildbot_url = settings->paths.network_buildbot_url;
s3[0] = '\0';
2016-10-08 19:47:26 +02:00
fill_pathname_join_special(s,
2020-02-19 22:06:21 +01:00
network_buildbot_assets_url,
2015-06-24 17:34:07 +02:00
"frontend", sizeof(s));
2016-06-18 18:23:09 +02:00
switch (enum_idx)
{
2016-06-21 01:40:55 +02:00
case MENU_ENUM_LABEL_CB_DOWNLOAD_URL:
suppress_msg = true;
fill_pathname_join_special(s, label,
2016-06-21 01:40:55 +02:00
path, sizeof(s));
2016-06-27 21:15:26 +02:00
path = s;
cb = cb_generic_dir_download;
2016-06-21 04:09:13 +02:00
break;
2016-06-18 18:23:09 +02:00
case MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD:
{
2024-06-15 15:04:05 +02:00
char *tok, *save;
char *menu_label_cpy = strdup(menu_label);
if ((tok = strtok_r(menu_label_cpy, ";", &save)))
strlcpy(s, tok, sizeof(s));
free(menu_label_cpy);
}
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_CORE_SYSTEM_FILES_DOWNLOAD:
fill_pathname_join_special(s,
network_buildbot_assets_url,
"system", sizeof(s));
break;
2016-06-18 18:23:09 +02:00
case MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD:
#ifdef HAVE_LAKKA
2016-06-18 18:23:09 +02:00
/* TODO unhardcode this path*/
fill_pathname_join_special(s, FILE_PATH_LAKKA_URL,
LAKKA_PROJECT, sizeof(s));
#endif
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_ASSETS:
2019-09-18 18:12:57 +02:00
path = "assets.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_AUTOCONFIG_PROFILES:
2019-09-18 18:12:57 +02:00
path = "autoconfig.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_CORE_INFO_FILES:
2019-09-18 18:12:57 +02:00
path = "info.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_CHEATS:
2019-09-18 18:12:57 +02:00
path = "cheats.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_OVERLAYS:
2019-09-18 18:12:57 +02:00
path = "overlays.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_DATABASES:
2019-09-18 18:12:57 +02:00
path = "database-rdb.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL:
2019-09-18 18:12:57 +02:00
path = "shaders_glsl.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG:
2019-09-18 18:12:57 +02:00
path = "shaders_slang.zip";
break;
2016-06-18 18:23:09 +02:00
case MENU_ENUM_LABEL_CB_UPDATE_SHADERS_CG:
2019-09-18 18:12:57 +02:00
path = "shaders_cg.zip";
2016-06-18 18:23:09 +02:00
break;
case MENU_ENUM_LABEL_CB_CORE_THUMBNAILS_DOWNLOAD:
strlcpy(s, "http://thumbnailpacks.libretro.com", sizeof(s));
2016-06-18 18:23:09 +02:00
break;
default:
2020-02-19 22:06:21 +01:00
strlcpy(s, network_buildbot_url, sizeof(s));
2016-06-18 18:23:09 +02:00
break;
}
2015-06-24 17:34:07 +02:00
fill_pathname_join_special(s2, s, path, sizeof(s2));
transf = (file_transfer_t*)calloc(1, sizeof(*transf));
transf->enum_idx = enum_idx;
2015-11-23 11:13:26 -03:00
strlcpy(transf->path, path, sizeof(transf->path));
2015-06-24 16:17:29 +02:00
2019-02-20 13:50:49 -05:00
if (string_is_equal(path, s))
net_http_urlencode_full(s3, s, sizeof(s3));
2019-02-20 13:50:49 -05:00
else
net_http_urlencode_full(s3, s2, sizeof(s3));
2020-02-19 22:06:21 +01:00
task_push_http_transfer_file(s3, suppress_msg,
msg_hash_to_str(enum_idx), cb, transf);
2015-06-24 15:56:49 +02:00
return 0;
}
static int action_ok_core_content_download(const char *path,
2015-07-04 04:01:35 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *menu_path = NULL;
const char *menu_label = NULL;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
2020-02-19 22:06:21 +01:00
menu_entries_get_last_stack(&menu_path, &menu_label,
NULL, &enum_idx, NULL);
return action_ok_download_generic(path, label,
2016-07-01 05:17:04 +02:00
menu_path, type, idx, entry_idx,
2016-06-18 18:23:09 +02:00
MENU_ENUM_LABEL_CB_CORE_CONTENT_DOWNLOAD);
2015-07-04 04:01:35 +02:00
}
static int action_ok_core_updater_download(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_updater_list_t *core_list = core_updater_list_get_cached();
settings_t *settings = config_get_ptr();
bool auto_backup = settings->bools.core_updater_auto_backup;
unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_dir_core_assets = settings->paths.directory_core_assets;
if (!core_list)
return -1;
#if defined(ANDROID)
/* Play Store builds install cores via
* the play feature delivery interface */
if (play_feature_delivery_enabled())
task_push_play_feature_delivery_core_install(
core_list, path, false);
else
#endif
task_push_core_updater_download(
core_list, path, 0, false,
auto_backup, (size_t)auto_backup_history_size,
path_dir_libretro, path_dir_core_assets);
return 0;
}
static int action_ok_update_installed_cores(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
bool auto_backup = settings->bools.core_updater_auto_backup;
unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_dir_core_assets = settings->paths.directory_core_assets;
/* Ensure networking is initialised */
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push update task */
task_push_update_installed_cores(
auto_backup, auto_backup_history_size,
path_dir_libretro, path_dir_core_assets);
return 0;
}
#if defined(ANDROID)
static int action_ok_switch_installed_cores_pfd(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
const char *path_dir_libretro = settings->paths.directory_libretro;
const char *path_libretro_info = settings->paths.path_libretro_info;
/* Ensure networking is initialised */
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
/* Push core switch/update task */
task_push_play_feature_delivery_switch_installed_cores(
path_dir_libretro, path_libretro_info);
return 0;
}
#endif
#endif
2020-01-09 14:13:21 +00:00
static int action_ok_sideload_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-02-19 22:06:21 +01:00
const char *menu_path = NULL;
bool core_loaded = false;
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2020-02-19 22:06:21 +01:00
settings_t *settings = config_get_ptr();
const char *dir_libretro = settings->paths.directory_libretro;
2020-01-09 14:13:21 +00:00
2024-12-25 19:06:04 +01:00
if (string_is_empty(path) || !menu)
return -1;
2020-01-09 14:13:21 +00:00
/* Get path of source (core 'backup') file */
2020-01-09 14:13:21 +00:00
menu_entries_get_last_stack(
&menu_path, NULL, NULL, NULL, NULL);
if (!string_is_empty(menu_path))
2024-12-25 19:06:04 +01:00
{
char backup_path[PATH_MAX_LENGTH];
fill_pathname_join_special(
2024-12-25 19:06:04 +01:00
backup_path, menu_path, path, sizeof(backup_path));
task_push_core_restore(backup_path, dir_libretro, &core_loaded);
}
2020-01-09 14:13:21 +00:00
else
2024-12-25 19:06:04 +01:00
task_push_core_restore(path, dir_libretro, &core_loaded);
2020-01-09 14:13:21 +00:00
/* Flush stack
* > Since the 'sideload core' option is present
* in several locations, can't flush to a predefined
* level - just go to the top */
menu_entries_flush_stack(NULL, 0);
return 0;
2020-01-09 14:13:21 +00:00
}
#ifdef HAVE_NETWORKING
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_core_system_files_download, MENU_ENUM_LABEL_CB_CORE_SYSTEM_FILES_DOWNLOAD)
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_core_content_thumbnails, MENU_ENUM_LABEL_CB_CORE_THUMBNAILS_DOWNLOAD)
#if 0
/* Thumbnailpack removal */
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_thumbnails_updater_download, MENU_ENUM_LABEL_CB_THUMBNAILS_UPDATER_DOWNLOAD)
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_download_url, MENU_ENUM_LABEL_CB_DOWNLOAD_URL)
#ifdef HAVE_LAKKA
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_lakka_download, MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD)
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_assets, MENU_ENUM_LABEL_CB_UPDATE_ASSETS)
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_core_info_files, MENU_ENUM_LABEL_CB_UPDATE_CORE_INFO_FILES)
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_overlays, MENU_ENUM_LABEL_CB_UPDATE_OVERLAYS)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_shaders_cg, MENU_ENUM_LABEL_CB_UPDATE_SHADERS_CG)
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_shaders_glsl, MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL)
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_shaders_slang, MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG)
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_databases, MENU_ENUM_LABEL_CB_UPDATE_DATABASES)
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
#ifdef HAVE_NETWORKING
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_cheats, MENU_ENUM_LABEL_CB_UPDATE_CHEATS)
2020-06-30 19:35:41 +02:00
#endif
#endif
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_DOWNLOAD(action_ok_update_autoconfig_profiles, MENU_ENUM_LABEL_CB_UPDATE_AUTOCONFIG_PROFILES)
#endif
2015-09-03 23:38:07 +02:00
static int action_ok_game_specific_core_options_create(const char *path,
2016-01-26 02:21:03 +01:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
core_options_create_override(true);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return 0;
}
static int action_ok_folder_specific_core_options_create(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
core_options_create_override(false);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return 0;
}
static int action_ok_game_specific_core_options_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
core_options_remove_override(true);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return 0;
}
static int action_ok_folder_specific_core_options_remove(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
core_options_remove_override(false);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
2015-11-15 22:09:39 -05:00
return 0;
}
static int action_ok_core_options_reset(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_options_reset();
return 0;
}
static int action_ok_core_options_flush(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_options_flush();
return 0;
}
int action_ok_close_content(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx)
{
int ret;
struct menu_state *menu_st = menu_state_get_ptr();
/* Reset navigation pointer
* > If we are returning to the quick menu, want
* the active entry to be 'Run' (first item in
* menu list) */
menu_st->selection_ptr = 0;
/* Check if we need to quit */
if (should_quit_on_close())
return generic_action_ok_command(CMD_EVENT_QUIT);
/* Otherwise, unload core */
ret = generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
2022-02-22 18:23:48 +00:00
/* If close content was selected via any means other than
* 'Playlist > Quick Menu', have to flush the menu stack
* (otherwise users will be presented with an empty
* 'No items' quick menu, requiring needless backwards
* navigation) */
if (type == MENU_SETTING_ACTION_CLOSE)
{
2022-02-22 18:23:48 +00:00
const char *parent_label = NULL;
const char *flush_target = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU);
2022-02-22 18:23:48 +00:00
file_list_t *list = NULL;
if (menu_st->entries.list)
list = MENU_LIST_GET(menu_st->entries.list, 0);
2022-02-22 18:23:48 +00:00
if (list && (list->size > 1))
{
parent_label = list->list[list->size - 2].label;
2022-02-22 18:23:48 +00:00
if ( string_is_equal(parent_label, msg_hash_to_str(MENU_ENUM_LABEL_CONTENTLESS_CORES_TAB))
|| string_is_equal(parent_label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONTENTLESS_CORES_LIST)))
2022-02-22 18:23:48 +00:00
flush_target = parent_label;
}
menu_entries_flush_stack(flush_target, 0);
/* An annoyance - some menu drivers (Ozone...) set
* MENU_ST_FLAG_PREVENT_POPULATE in awkward places,
* which can cause breakage here when flushing
* the menu stack. We therefore have to unset
* MENU_ST_FLAG_PREVENT_POPULATE */
menu_st->flags &= ~MENU_ST_FLAG_PREVENT_POPULATE;
}
return ret;
}
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_cheat_apply_changes, CMD_EVENT_CHEATS_APPLY)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_quit, CMD_EVENT_QUIT)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_save_new_config, CMD_EVENT_MENU_SAVE_CONFIG)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_resume_content, CMD_EVENT_RESUME)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_restart_content, CMD_EVENT_RESET)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_screenshot, CMD_EVENT_TAKE_SCREENSHOT)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_shader_apply_changes, CMD_EVENT_SHADERS_APPLY_CHANGES)
#endif
STATIC_DEFAULT_ACTION_OK_CMD_FUNC(action_ok_show_wimp, CMD_EVENT_UI_COMPANION_TOGGLE)
static int action_ok_set_core_association(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
/* TODO/FIXME - menu->rpl_entry_selection_ptr - find
2023-07-17 22:32:13 +03:00
* a way so that we can remove this temporary state
* required for playlist entry write */
return generic_action_ok_displaylist_push(
path, NULL,
NULL, menu->rpl_entry_selection_ptr,
idx, entry_idx,
ACTION_OK_DL_DEFERRED_CORE_LIST_SET);
}
static int action_ok_reset_core_association(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-08-26 15:17:37 +01:00
size_t playlist_index;
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2020-08-26 15:17:37 +01:00
playlist_index = (size_t)menu->rpl_entry_selection_ptr;
if (!command_event(CMD_EVENT_RESET_CORE_ASSOCIATION,
2020-08-26 15:17:37 +01:00
(void *)&playlist_index))
return -1;
return 0;
}
2019-03-05 13:04:43 +00:00
/* This function is called when selecting 'add to favorites'
* while viewing the quick menu (i.e. content is running) */
static int action_ok_add_to_favorites(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-03-05 13:04:43 +00:00
const char *content_path = path_get(RARCH_PATH_CONTENT);
int ret = 0;
/* Error checking
* > If content path is empty, cannot do anything... */
if (!string_is_empty(content_path))
{
union string_list_elem_attr attr;
char core_name[NAME_MAX_LENGTH];
char content_label[NAME_MAX_LENGTH];
char core_path[PATH_MAX_LENGTH];
runloop_state_t *runloop_st = runloop_state_get_ptr();
struct retro_system_info *sysinfo = &runloop_st->system.info;
struct string_list *str_list = NULL;
const char *crc32 = NULL;
const char *db_name = NULL;
2019-03-05 13:04:43 +00:00
2020-08-19 06:53:09 +02:00
core_path[0] = '\0';
core_name[0] = '\0';
2019-03-05 13:04:43 +00:00
/* Create string list container for playlist parameters */
2020-08-19 06:53:09 +02:00
attr.i = 0;
if (!(str_list = string_list_new()))
2019-03-05 13:04:43 +00:00
return 0;
/* Determine playlist parameters */
/* > content_label */
2021-11-09 06:03:00 +01:00
if (!string_is_empty(runloop_st->name.label))
strlcpy(content_label, runloop_st->name.label,
sizeof(content_label));
else
content_label[0] = '\0';
2019-03-05 13:04:43 +00:00
2020-06-08 16:02:06 +02:00
/* Label is empty - use file name instead */
if (string_is_empty(content_label))
fill_pathname(content_label,
path_basename(content_path), "",
sizeof(content_label));
2019-03-05 13:04:43 +00:00
/* > core_path + core_name */
if (sysinfo)
2019-03-05 13:04:43 +00:00
{
if (!string_is_empty(path_get(RARCH_PATH_CORE)))
{
core_info_t *core_info = NULL;
2019-03-05 13:04:43 +00:00
/* >> core_path */
strlcpy(core_path, path_get(RARCH_PATH_CORE),
sizeof(core_path));
2019-03-05 13:04:43 +00:00
/* >> core_name
* (always use display name, if available) */
if (core_info_find(core_path, &core_info))
if (!string_is_empty(core_info->display_name))
strlcpy(core_name, core_info->display_name,
2020-06-08 16:02:06 +02:00
sizeof(core_name));
2019-03-05 13:04:43 +00:00
}
/* >> core_name (continued) */
2023-07-15 15:14:26 +02:00
if ( string_is_empty(core_name)
&& !string_is_empty(sysinfo->library_name))
strlcpy(core_name, sysinfo->library_name, sizeof(core_name));
2019-03-05 13:04:43 +00:00
}
if (string_is_empty(core_path) || string_is_empty(core_name))
{
strlcpy(core_path, FILE_PATH_DETECT, sizeof(core_path));
strlcpy(core_name, FILE_PATH_DETECT, sizeof(core_name));
2019-03-05 13:04:43 +00:00
}
/* > crc32 + db_name */
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (menu)
{
2019-08-16 15:17:02 +02:00
playlist_t *playlist_curr = playlist_get_cached();
2020-06-08 16:02:06 +02:00
if (playlist_index_is_valid(playlist_curr,
menu->rpl_entry_selection_ptr,
content_path, core_path))
2019-08-16 15:17:02 +02:00
{
2020-06-08 16:02:06 +02:00
playlist_get_crc32(playlist_curr,
menu->rpl_entry_selection_ptr, &crc32);
playlist_get_db_name(playlist_curr,
menu->rpl_entry_selection_ptr, &db_name);
2019-08-16 15:17:02 +02:00
}
}
}
2019-03-05 13:04:43 +00:00
/* Copy playlist parameters into string list
* [0]: content_path
* [1]: content_label
* [2]: core_path
* [3]: core_name
* [4]: crc32
* [5]: db_name */
2019-03-05 13:04:43 +00:00
string_list_append(str_list, content_path, attr);
string_list_append(str_list, content_label, attr);
string_list_append(str_list, core_path, attr);
string_list_append(str_list, core_name, attr);
2023-08-16 03:22:02 +02:00
string_list_append(str_list, !string_is_empty(crc32)
2020-06-08 16:02:06 +02:00
? crc32 : "", attr);
2023-08-16 03:22:02 +02:00
string_list_append(str_list, !string_is_empty(db_name)
2020-06-08 16:02:06 +02:00
? db_name : "", attr);
2019-03-05 13:04:43 +00:00
/* Trigger 'ADD_TO_FAVORITES' event */
if (!command_event(CMD_EVENT_ADD_TO_FAVORITES, (void*)str_list))
ret = -1;
2019-03-05 13:04:43 +00:00
/* Clean up */
string_list_free(str_list);
str_list = NULL;
}
return ret;
}
static int action_ok_add_entry_to_playlist(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
playlist_t *playlist_curr = playlist_get_cached();
const struct playlist_entry *entry = NULL;
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
int ret = 0;
if (!playlist_curr)
return 0;
if (!menu)
return -1;
if(!label)
return 0;
2024-12-25 19:06:04 +01:00
/*
*
* path = menu entry select. use this to identify the menu item to add the content to
* entry->path = The file path of the currently selected content
* [INFO] [playlist] = Add to Favorites
* [INFO] [content_path] = C:\roms\Arcade - Mame 2003 Plus\aburner2.zip
*/
/* Read current playlist parameters */
playlist_get_index(playlist_curr, menu->rpl_entry_selection_ptr, &entry);
/* Error checking
* > If content path is empty, cannot do anything... */
if (!string_is_empty(entry->path))
{
union string_list_elem_attr attr;
char core_display_name[NAME_MAX_LENGTH];
char core_name[NAME_MAX_LENGTH];
char core_path[PATH_MAX_LENGTH];
struct string_list *str_list = NULL;
core_display_name[0] = '\0';
core_path[0] = '\0';
core_name[0] = '\0';
/* Create string list container for playlist parameters */
attr.i = 0;
if (!(str_list = string_list_new()))
return 0;
/* Copy playlist parameters into string list
* [0]: content_path
* [1]: content_label
* [2]: core_path
* [3]: core_name
* [4]: crc32
* [5]: db_name
* [6]: playlist*/
/* > content_path */
string_list_append(str_list, entry->path, attr);
/* > content_label */
if (!string_is_empty(entry->label))
string_list_append(str_list, entry->label, attr);
else
{
/* Label is empty - use file name instead */
char fallback_content_label[PATH_MAX_LENGTH];
fallback_content_label[0] = '\0';
fill_pathname(fallback_content_label,
path_basename(entry->path), "",
sizeof(fallback_content_label));
string_list_append(str_list, fallback_content_label, attr);
}
/* Replace "DETECT" with default_core_path + name if available */
if ( !string_is_empty(entry->core_path)
&& !string_is_empty(entry->core_name))
{
if ( string_is_equal(entry->core_path, FILE_PATH_DETECT)
&& string_is_equal(entry->core_name, FILE_PATH_DETECT))
{
const char *default_core_path = playlist_get_default_core_path(playlist_curr);
const char *default_core_name = playlist_get_default_core_name(playlist_curr);
if ( !string_is_empty(default_core_path)
&& !string_is_empty(default_core_name))
{
strlcpy(core_path, default_core_path, sizeof(core_path));
strlcpy(core_name, default_core_name, sizeof(core_name));
}
}
else
{
strlcpy(core_path, entry->core_path, sizeof(core_path));
strlcpy(core_name, entry->core_name, sizeof(core_name));
}
}
/* > core_path + core_name */
if ( !string_is_empty(core_path)
&& !string_is_empty(core_name))
{
core_info_t *core_info = NULL;
/* >> core_path */
string_list_append(str_list, core_path, attr);
/* >> core_name
* (always use display name, if available) */
if (core_info_find(core_path, &core_info))
if (!string_is_empty(core_info->display_name))
strlcpy(core_display_name, core_info->display_name, sizeof(core_display_name));
if (!string_is_empty(core_display_name))
string_list_append(str_list, core_display_name, attr);
else
string_list_append(str_list, core_name, attr);
}
else
{
string_list_append(str_list, FILE_PATH_DETECT, attr);
string_list_append(str_list, FILE_PATH_DETECT, attr);
}
/* crc32 */
string_list_append(str_list, !string_is_empty(entry->crc32) ? entry->crc32 : "", attr);
/* db_name */
string_list_append(str_list, !string_is_empty(entry->db_name) ? entry->db_name : "", attr);
/* db_name */
string_list_append(str_list, label, attr);
/* Trigger 'ADD_TO_FAVORITES' event */
if (!command_event(CMD_EVENT_ADD_TO_PLAYLIST, (void*)str_list))
ret = -1;
/* Clean up */
string_list_free(str_list);
str_list = NULL;
}
return ret;
}
static void action_input_add_entry_to_new_playlist(void *userdata, const char *line)
{
char path[PATH_MAX_LENGTH];
settings_t *settings = config_get_ptr();
size_t _len = 0;
menu_input_dialog_end();
if(!line)
return;
/* Create path for new file */
_len = fill_pathname_join_special(path, settings->paths.directory_playlist, line, sizeof(path));
strlcpy(path + _len, ".lpl", sizeof(path) - _len);
action_ok_add_entry_to_playlist(NULL, path, 0, 0, 0);
}
static int action_ok_add_entry_to_new_playlist(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_input_ctx_line_t line;
line.label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CREATE_NEW_PLAYLIST);
line.label_setting = NULL;
line.type = 0;
line.idx = 0;
line.cb = action_input_add_entry_to_new_playlist;
menu_input_dialog_start(&line);
return 0;
}
2019-03-05 13:04:43 +00:00
/* This function is called when selecting 'add to favorites'
* while viewing a playlist entry */
static int action_ok_add_to_favorites_playlist(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-08-16 15:17:02 +02:00
playlist_t *playlist_curr = playlist_get_cached();
const struct playlist_entry *entry = NULL;
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
int ret = 0;
if (!playlist_curr)
return 0;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2019-03-05 13:04:43 +00:00
/* Read current playlist parameters */
playlist_get_index(playlist_curr, menu->rpl_entry_selection_ptr, &entry);
2019-03-05 13:04:43 +00:00
/* Error checking
* > If content path is empty, cannot do anything... */
if (!string_is_empty(entry->path))
2019-03-05 13:04:43 +00:00
{
union string_list_elem_attr attr;
char core_display_name[NAME_MAX_LENGTH];
char core_name[NAME_MAX_LENGTH];
char core_path[PATH_MAX_LENGTH];
struct string_list *str_list = NULL;
2019-03-05 13:04:43 +00:00
core_display_name[0] = '\0';
core_path[0] = '\0';
core_name[0] = '\0';
2019-03-05 13:04:43 +00:00
/* Create string list container for playlist parameters */
2020-06-08 16:02:06 +02:00
attr.i = 0;
if (!(str_list = string_list_new()))
2019-03-05 13:04:43 +00:00
return 0;
/* Copy playlist parameters into string list
* [0]: content_path
* [1]: content_label
* [2]: core_path
* [3]: core_name
* [4]: crc32
* [5]: db_name */
2019-03-05 13:04:43 +00:00
/* > content_path */
string_list_append(str_list, entry->path, attr);
2015-09-04 00:27:55 +02:00
2019-03-05 13:04:43 +00:00
/* > content_label */
if (!string_is_empty(entry->label))
string_list_append(str_list, entry->label, attr);
2019-03-05 13:04:43 +00:00
else
{
/* Label is empty - use file name instead */
char fallback_content_label[PATH_MAX_LENGTH];
fallback_content_label[0] = '\0';
fill_pathname(fallback_content_label,
path_basename(entry->path), "",
sizeof(fallback_content_label));
2019-03-05 13:04:43 +00:00
string_list_append(str_list, fallback_content_label, attr);
}
/* Replace "DETECT" with default_core_path + name if available */
2023-08-16 03:22:02 +02:00
if ( !string_is_empty(entry->core_path)
2023-07-15 15:14:26 +02:00
&& !string_is_empty(entry->core_name))
{
2023-07-15 15:14:26 +02:00
if ( string_is_equal(entry->core_path, FILE_PATH_DETECT)
&& string_is_equal(entry->core_name, FILE_PATH_DETECT))
{
const char *default_core_path = playlist_get_default_core_path(playlist_curr);
const char *default_core_name = playlist_get_default_core_name(playlist_curr);
2023-08-16 03:22:02 +02:00
if ( !string_is_empty(default_core_path)
2023-07-15 15:14:26 +02:00
&& !string_is_empty(default_core_name))
{
strlcpy(core_path, default_core_path, sizeof(core_path));
strlcpy(core_name, default_core_name, sizeof(core_name));
}
}
else
{
strlcpy(core_path, entry->core_path, sizeof(core_path));
strlcpy(core_name, entry->core_name, sizeof(core_name));
}
}
/* > core_path + core_name */
2023-08-16 03:22:02 +02:00
if ( !string_is_empty(core_path)
2023-07-15 15:14:26 +02:00
&& !string_is_empty(core_name))
2019-03-05 13:04:43 +00:00
{
core_info_t *core_info = NULL;
2019-03-05 13:04:43 +00:00
/* >> core_path */
string_list_append(str_list, core_path, attr);
2019-03-05 13:04:43 +00:00
/* >> core_name
* (always use display name, if available) */
if (core_info_find(core_path, &core_info))
if (!string_is_empty(core_info->display_name))
strlcpy(core_display_name, core_info->display_name, sizeof(core_display_name));
2019-03-05 13:04:43 +00:00
if (!string_is_empty(core_display_name))
string_list_append(str_list, core_display_name, attr);
else
string_list_append(str_list, core_name, attr);
2019-03-05 13:04:43 +00:00
}
else
{
string_list_append(str_list, FILE_PATH_DETECT, attr);
string_list_append(str_list, FILE_PATH_DETECT, attr);
2019-03-05 13:04:43 +00:00
}
/* crc32 */
string_list_append(str_list, !string_is_empty(entry->crc32) ? entry->crc32 : "", attr);
/* db_name */
string_list_append(str_list, !string_is_empty(entry->db_name) ? entry->db_name : "", attr);
2019-03-05 13:04:43 +00:00
/* Trigger 'ADD_TO_FAVORITES' event */
if (!command_event(CMD_EVENT_ADD_TO_FAVORITES, (void*)str_list))
ret = -1;
2019-03-05 13:04:43 +00:00
/* Clean up */
string_list_free(str_list);
str_list = NULL;
}
return ret;
}
2017-08-14 20:07:43 +02:00
static int action_ok_delete_entry(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2016-08-29 17:09:45 +02:00
size_t new_selection_ptr;
char *conf_path = NULL;
char *def_conf_path = NULL;
char *def_conf_music_path = NULL;
2018-06-20 04:50:58 +02:00
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
char *def_conf_video_path = NULL;
#endif
#ifdef HAVE_IMAGEVIEWER
char *def_conf_img_path = NULL;
#endif
char *def_conf_fav_path = NULL;
playlist_t *playlist = playlist_get_cached();
struct menu_state *menu_st= menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2017-08-14 02:49:55 +02:00
conf_path = playlist_get_conf_path(playlist);
def_conf_path = playlist_get_conf_path(g_defaults.content_history);
def_conf_music_path = playlist_get_conf_path(g_defaults.music_history);
2018-06-20 04:50:58 +02:00
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
2017-08-14 02:49:55 +02:00
def_conf_video_path = playlist_get_conf_path(g_defaults.video_history);
#endif
#ifdef HAVE_IMAGEVIEWER
def_conf_img_path = playlist_get_conf_path(g_defaults.image_history);
#endif
def_conf_fav_path = playlist_get_conf_path(g_defaults.content_favorites);
2017-08-14 02:49:55 +02:00
if (string_is_equal(conf_path, def_conf_path))
playlist = g_defaults.content_history;
else if (string_is_equal(conf_path, def_conf_music_path))
playlist = g_defaults.music_history;
2018-06-20 04:50:58 +02:00
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
else if (string_is_equal(conf_path, def_conf_video_path))
playlist = g_defaults.video_history;
2016-08-29 02:39:02 +02:00
#endif
#ifdef HAVE_IMAGEVIEWER
else if (string_is_equal(conf_path, def_conf_img_path))
playlist = g_defaults.image_history;
2016-08-29 02:39:02 +02:00
#endif
else if (string_is_equal(conf_path, def_conf_fav_path))
playlist = g_defaults.content_favorites;
2016-08-29 02:39:02 +02:00
2017-11-25 23:39:31 +01:00
if (playlist)
{
playlist_delete_index(playlist, menu->rpl_entry_selection_ptr);
2020-06-26 15:39:03 +01:00
playlist_write_file(playlist);
#if TARGET_OS_TV
update_topshelf();
#endif
2017-11-25 23:39:31 +01:00
}
new_selection_ptr = menu_st->selection_ptr;
menu_entries_pop_stack(&new_selection_ptr, 0, 1);
menu_st->selection_ptr = new_selection_ptr;
/* Thumbnail must be refreshed */
if (menu_st->driver_ctx && menu_st->driver_ctx->refresh_thumbnail_image)
menu_st->driver_ctx->refresh_thumbnail_image(
menu_st->userdata, (unsigned)new_selection_ptr);
return 0;
}
static int action_ok_rdb_entry_submenu(const char *path,
2015-09-04 00:44:09 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-06-15 19:12:15 +02:00
char *tok, *save;
char new_str[PATH_MAX_LENGTH];
2016-10-08 19:44:03 +02:00
char new_label[PATH_MAX_LENGTH];
size_t _len = 0;
2024-06-15 19:12:15 +02:00
char *label_cpy = NULL;
2015-09-04 00:44:09 +02:00
if (!label)
return -1;
2015-09-04 00:44:09 +02:00
2024-06-15 19:12:15 +02:00
new_label[0] = '\0';
label_cpy = strdup(label);
2015-09-04 00:44:09 +02:00
/* element 0: label */
2024-06-15 19:12:15 +02:00
if ((tok = strtok_r(label_cpy, "|", &save)))
fill_pathname_join_delim(new_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CURSOR_MANAGER_LIST),
tok, '_', sizeof(new_label));
/* element 1: value */
2024-06-15 19:12:15 +02:00
if ((tok = strtok_r(NULL, "|", &save)))
_len += strlcpy(new_str + _len, tok, sizeof(new_str) - _len);
/* element 2: database path */
2024-06-15 19:12:15 +02:00
if ((tok = strtok_r(NULL, "|", &save)))
{
_len += strlcpy(new_str + _len, "|", sizeof(new_str) - _len);
_len += strlcpy(new_str + _len, tok, sizeof(new_str) - _len);
}
2024-06-15 19:12:15 +02:00
free(label_cpy);
return generic_action_ok_displaylist_push(
new_str, NULL,
2023-07-17 22:32:13 +03:00
new_label, type,
idx, entry_idx,
2015-09-04 00:44:09 +02:00
ACTION_OK_DL_RDB_ENTRY_SUBMENU);
}
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_browse_url_start, ACTION_OK_DL_BROWSE_URL_START)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_favorites, ACTION_OK_DL_FAVORITES_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_images, ACTION_OK_DL_IMAGES_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cdrom_info_list, ACTION_OK_DL_CDROM_INFO_DETAIL_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_video, ACTION_OK_DL_VIDEO_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_music, ACTION_OK_DL_MUSIC_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_explore, ACTION_OK_DL_EXPLORE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_goto_contentless_cores, ACTION_OK_DL_CONTENTLESS_CORES_LIST)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_preset_save, ACTION_OK_DL_SHADER_PRESET_SAVE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_preset_remove, ACTION_OK_DL_SHADER_PRESET_REMOVE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_parameters, ACTION_OK_DL_SHADER_PARAMETERS)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_parent_directory_push, ACTION_OK_DL_PARENT_DIRECTORY_PUSH)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_directory_push, ACTION_OK_DL_DIRECTORY_PUSH)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_configurations_list, ACTION_OK_DL_CONFIGURATIONS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_saving_list, ACTION_OK_DL_SAVING_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cloud_sync_list, ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_list, ACTION_OK_DL_NETWORK_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_hosting_list, ACTION_OK_DL_NETWORK_HOSTING_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_kick_list, ACTION_OK_DL_NETPLAY_KICK_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_ban_list, ACTION_OK_DL_NETPLAY_BAN_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_lobby_filters_list, ACTION_OK_DL_NETPLAY_LOBBY_FILTERS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_subsystem_list, ACTION_OK_DL_SUBSYSTEM_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_database_manager_list, ACTION_OK_DL_DATABASE_MANAGER_LIST)
#ifdef HAVE_BLUETOOTH
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_bluetooth_list, ACTION_OK_DL_BLUETOOTH_SETTINGS_LIST)
#endif
2020-12-09 22:03:23 +01:00
#ifdef HAVE_NETWORKING
#ifdef HAVE_WIFI
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_wifi_list, ACTION_OK_DL_WIFI_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_wifi_networks_list, ACTION_OK_DL_WIFI_NETWORKS_LIST)
2020-12-09 22:03:23 +01:00
#endif
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_compressed_archive_push, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_compressed_archive_push_detect_core, ACTION_OK_DL_COMPRESSED_ARCHIVE_PUSH_DETECT_CORE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_logging_list, ACTION_OK_DL_LOGGING_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_frame_throttle_list, ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_frame_time_counter_list, ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_rewind_list, ACTION_OK_DL_REWIND_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheat, ACTION_OK_DL_CHEAT_DETAILS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheat_start_or_cont, ACTION_OK_DL_CHEAT_SEARCH_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_onscreen_display_list, ACTION_OK_DL_ONSCREEN_DISPLAY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_onscreen_notifications_list, ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_onscreen_notifications_views_list, ACTION_OK_DL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_onscreen_overlay_list, ACTION_OK_DL_ONSCREEN_OVERLAY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_overlay_lightgun_settings_list, ACTION_OK_DL_OVERLAY_LIGHTGUN_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_overlay_mouse_settings_list, ACTION_OK_DL_OVERLAY_MOUSE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_osk_overlay_list, ACTION_OK_DL_OSK_OVERLAY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_menu_list, ACTION_OK_DL_MENU_SETTINGS_LIST)
2022-08-17 08:23:07 +02:00
#ifdef _3DS
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_menu_bottom_list, ACTION_OK_DL_MENU_BOTTOM_SETTINGS_LIST)
2022-08-17 08:23:07 +02:00
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_quick_menu_override_options, ACTION_OK_DL_QUICK_MENU_OVERRIDE_OPTIONS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_menu_views_list, ACTION_OK_DL_MENU_VIEWS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_settings_views_list, ACTION_OK_DL_SETTINGS_VIEWS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_quick_menu_views_list, ACTION_OK_DL_QUICK_MENU_VIEWS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_power_management_list, ACTION_OK_DL_POWER_MANAGEMENT_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cpu_perfpower_list, ACTION_OK_DL_CPU_PERFPOWER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cpu_policy_entry, ACTION_OK_DL_CPU_POLICY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_menu_sounds_list, ACTION_OK_DL_MENU_SOUNDS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_user_interface_list, ACTION_OK_DL_USER_INTERFACE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_menu_file_browser_list, ACTION_OK_DL_MENU_FILE_BROWSER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_retro_achievements_list, ACTION_OK_DL_RETRO_ACHIEVEMENTS_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheevos_appearance_list, ACTION_OK_DL_CHEEVOS_APPEARANCE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheevos_visibility_list, ACTION_OK_DL_CHEEVOS_VISIBILITY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_updater_list, ACTION_OK_DL_UPDATER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_lakka_services, ACTION_OK_DL_LAKKA_SERVICES_LIST)
#ifdef HAVE_LAKKA_SWITCH
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_lakka_switch_options, ACTION_OK_DL_LAKKA_SWITCH_OPTIONS_LIST)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_user_list, ACTION_OK_DL_USER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_sublist, ACTION_OK_DL_NETPLAY)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_directory_list, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_privacy_list, ACTION_OK_DL_PRIVACY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_midi_list, ACTION_OK_DL_MIDI_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_rdb_entry, ACTION_OK_DL_RDB_ENTRY)
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_mixer_stream_actions, ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST)
2019-07-11 11:51:06 +02:00
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_browse_url_list, ACTION_OK_DL_BROWSE_URL_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_core_list, ACTION_OK_DL_CORE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_sideload_core_list, ACTION_OK_DL_SIDELOAD_CORE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheat_file, ACTION_OK_DL_CHEAT_FILE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cheat_file_append, ACTION_OK_DL_CHEAT_FILE_APPEND)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_playlist_collection, ACTION_OK_DL_PLAYLIST_COLLECTION)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_disk_image_append_list, ACTION_OK_DL_DISK_IMAGE_APPEND_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_subsystem_add_list, ACTION_OK_DL_SUBSYSTEM_ADD_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_subsystem_add_load, ACTION_OK_DL_SUBSYSTEM_LOAD)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_record_configfile, ACTION_OK_DL_RECORD_CONFIGFILE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_stream_configfile, ACTION_OK_DL_STREAM_CONFIGFILE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_remap_file, ACTION_OK_DL_REMAP_FILE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_override_file, ACTION_OK_DL_OVERRIDE_FILE)
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_preset, ACTION_OK_DL_SHADER_PRESET)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_preset_prepend, ACTION_OK_DL_SHADER_PRESET_PREPEND)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_shader_preset_append, ACTION_OK_DL_SHADER_PRESET_APPEND)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_generic_list, ACTION_OK_DL_GENERIC)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_audio_dsp_plugin, ACTION_OK_DL_AUDIO_DSP_PLUGIN)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_video_filter, ACTION_OK_DL_VIDEO_FILTER)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_overlay_preset, ACTION_OK_DL_OVERLAY_PRESET)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_osk_overlay_preset, ACTION_OK_DL_OSK_OVERLAY_PRESET)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_video_font, ACTION_OK_DL_VIDEO_FONT)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_rpl_entry, ACTION_OK_DL_RPL_ENTRY)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_open_archive_detect_core, ACTION_OK_DL_OPEN_ARCHIVE_DETECT_CORE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_file_load_music, ACTION_OK_DL_MUSIC)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accounts_list, ACTION_OK_DL_ACCOUNTS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_driver_settings_list, ACTION_OK_DL_DRIVER_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_crt_switchres_settings_list, ACTION_OK_DL_CRT_SWITCHRES_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_settings_list, ACTION_OK_DL_VIDEO_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_fullscreen_mode_settings_list, ACTION_OK_DL_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_synchronization_settings_list, ACTION_OK_DL_VIDEO_SYNCHRONIZATION_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_windowed_mode_settings_list, ACTION_OK_DL_VIDEO_WINDOWED_MODE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_scaling_settings_list, ACTION_OK_DL_VIDEO_SCALING_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_hdr_settings_list, ACTION_OK_DL_VIDEO_HDR_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_video_output_settings_list, ACTION_OK_DL_VIDEO_OUTPUT_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_configuration_settings_list, ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_settings_list, ACTION_OK_DL_CORE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_restore_backup_list, ACTION_OK_DL_CORE_RESTORE_BACKUP_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_delete_backup_list, ACTION_OK_DL_CORE_DELETE_BACKUP_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_audio_settings_list, ACTION_OK_DL_AUDIO_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_audio_output_settings_list, ACTION_OK_DL_AUDIO_OUTPUT_SETTINGS_LIST)
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_microphone_settings_list, ACTION_OK_DL_MICROPHONE_SETTINGS_LIST)
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_audio_synchronization_settings_list, ACTION_OK_DL_AUDIO_SYNCHRONIZATION_SETTINGS_LIST)
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_audio_mixer_settings_list, ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST)
2019-07-11 11:51:06 +02:00
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_ai_service_settings_list, ACTION_OK_DL_AI_SERVICE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accessibility_settings_list, ACTION_OK_DL_ACCESSIBILITY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_settings_list, ACTION_OK_DL_INPUT_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_menu_settings_list, ACTION_OK_DL_INPUT_MENU_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_turbo_fire_settings_list, ACTION_OK_DL_INPUT_TURBO_FIRE_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_haptic_feedback_settings_list, ACTION_OK_DL_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_latency_settings_list, ACTION_OK_DL_LATENCY_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_recording_settings_list, ACTION_OK_DL_RECORDING_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_playlist_settings_list, ACTION_OK_DL_PLAYLIST_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_playlist_manager_list, ACTION_OK_DL_PLAYLIST_MANAGER_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_retropad_binds_list, ACTION_OK_DL_INPUT_RETROPAD_BINDS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_input_hotkey_binds_list, ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_user_binds_list, ACTION_OK_DL_USER_BINDS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accounts_cheevos_list, ACTION_OK_DL_ACCOUNTS_CHEEVOS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accounts_youtube_list, ACTION_OK_DL_ACCOUNTS_YOUTUBE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accounts_twitch_list, ACTION_OK_DL_ACCOUNTS_TWITCH_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_accounts_facebook_list, ACTION_OK_DL_ACCOUNTS_FACEBOOK_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_dump_disc_list, ACTION_OK_DL_DUMP_DISC_LIST)
#ifdef HAVE_LAKKA
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_eject_disc, ACTION_OK_DL_EJECT_DISC)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_load_disc_list, ACTION_OK_DL_LOAD_DISC_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_open_archive, ACTION_OK_DL_OPEN_ARCHIVE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_rgui_menu_theme_preset, ACTION_OK_DL_RGUI_MENU_THEME_PRESET)
#ifdef HAVE_NETWORKING
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_pl_thumbnails_updater_list, ACTION_OK_DL_PL_THUMBNAILS_UPDATER_LIST)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_manual_content_scan_list, ACTION_OK_DL_MANUAL_CONTENT_SCAN_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_manual_content_scan_dat_file, ACTION_OK_DL_MANUAL_CONTENT_SCAN_DAT_FILE)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_manager_list, ACTION_OK_DL_CORE_MANAGER_LIST)
#ifdef HAVE_MIST
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_steam_settings_list, ACTION_OK_DL_STEAM_SETTINGS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_manager_steam_list, ACTION_OK_DL_CORE_MANAGER_STEAM_LIST)
#endif
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_option_override_list, ACTION_OK_DL_CORE_OPTION_OVERRIDE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_remap_file_manager_list, ACTION_OK_DL_REMAP_FILE_MANAGER_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_savestate_list, ACTION_OK_DL_SAVESTATE_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_core_options_list, ACTION_OK_DL_CORE_OPTIONS_LIST)
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_push_add_to_playlist_list, ACTION_OK_DL_ADD_TO_PLAYLIST)
DEFAULT_ACTION_OK_FUNC(action_ok_push_playlist_manager_settings, ACTION_OK_DL_PLAYLIST_MANAGER_SETTINGS)
#ifdef HAVE_CHEEVOS
DEFAULT_ACTION_OK_FUNC(action_ok_push_achievements_hardcore_pause_list, ACTION_OK_DL_ACHIEVEMENTS_HARDCORE_PAUSE_LIST)
#endif
DEFAULT_ACTION_OK_FUNC(action_ok_push_core_information_list, ACTION_OK_DL_CORE_INFORMATION_LIST)
#ifdef HAVE_MIST
DEFAULT_ACTION_OK_FUNC(action_ok_push_core_information_steam_list, ACTION_OK_DL_CORE_INFORMATION_STEAM_LIST)
#endif
2016-12-27 00:02:09 +01:00
static int action_ok_open_uwp_permission_settings(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifdef __WINRT__
uwp_open_broadfilesystemaccess_settings();
#endif
return 0;
}
static int action_ok_open_picker(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-04-29 21:30:15 -04:00
#if TARGET_OS_IOS
ios_show_file_sheet();
return 0;
#else
char *new_path = NULL;
2023-07-17 22:32:13 +03:00
int ret = generic_action_ok_displaylist_push(
path, new_path,
msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), MENU_SETTING_ACTION_FAVORITES_DIR,
idx, entry_idx,
ACTION_OK_DL_CONTENT_LIST);
free(new_path);
return ret;
2024-04-29 21:30:15 -04:00
#endif
}
2020-12-09 22:03:23 +01:00
#ifdef HAVE_NETWORKING
#ifdef HAVE_WIFI
static void wifi_menu_refresh_callback(retro_task_t *task,
void *task_data,
void *user_data, const char *error)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
}
static int action_ok_wifi_disconnect(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
task_push_wifi_disconnect(wifi_menu_refresh_callback);
return true;
}
#endif
2022-06-17 17:38:56 -03:00
static int action_ok_netplay_connect_room(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
2017-01-19 23:44:10 -05:00
{
2022-06-17 17:38:56 -03:00
char hostname[512];
struct netplay_room *room;
net_driver_state_t *net_st = networking_state_get_ptr();
unsigned room_index = type - MENU_SETTINGS_NETPLAY_ROOMS_START;
if (room_index >= (unsigned)net_st->room_count)
return -1;
2021-11-05 18:07:41 +01:00
2022-06-17 17:38:56 -03:00
room = &net_st->room_list[room_index];
2022-06-17 17:38:56 -03:00
if (room->host_method == NETPLAY_HOST_METHOD_MITM)
snprintf(hostname, sizeof(hostname), "%s|%d|%s",
room->mitm_address, room->mitm_port, room->mitm_session);
else
2022-06-17 17:38:56 -03:00
snprintf(hostname, sizeof(hostname), "%s|%d", room->address, room->port);
2017-01-22 21:19:39 +01:00
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE, NULL))
{
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
command_event(CMD_EVENT_NETPLAY_INIT_DIRECT, (void*)hostname);
menu_input_dialog_end();
retroarch_menu_running_finished(false);
}
else
task_push_netplay_crc_scan(room->gamecrc, room->gamename,
room->subsystem_name, room->corename, hostname);
2017-01-19 23:44:10 -05:00
return 0;
}
2022-06-17 17:38:56 -03:00
static void netplay_refresh_rooms_cb(retro_task_t *task, void *task_data,
void *user_data, const char *error)
{
2022-06-17 17:38:56 -03:00
char *room_data = NULL;
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
const char *path = NULL;
const char *label = NULL;
unsigned menu_type = 0;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
2022-06-17 17:38:56 -03:00
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
net_driver_state_t *net_st = networking_state_get_ptr();
struct menu_state *menu_st = menu_state_get_ptr();
2022-06-17 17:38:56 -03:00
free(net_st->room_list);
net_st->room_list = NULL;
net_st->room_count = 0;
menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL);
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
/* Don't push the results if we left the netplay menu */
2023-07-15 15:14:26 +02:00
if ( !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB))
&& !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
return;
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
if (error)
{
2022-06-17 17:38:56 -03:00
RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), error);
goto done;
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
}
if (!data || !data->data || !data->len || data->status != 200)
{
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
RARCH_ERR("%s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED));
2022-06-17 17:38:56 -03:00
goto done;
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
}
2022-06-17 17:38:56 -03:00
room_data = (char*)malloc(data->len + 1);
if (!room_data)
goto done;
memcpy(room_data, data->data, data->len);
room_data[data->len] = '\0';
2017-01-19 00:52:53 -05:00
2022-06-17 17:38:56 -03:00
if (!string_is_empty(room_data))
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
{
2022-06-17 17:38:56 -03:00
int room_count;
netplay_rooms_parse(room_data, strlen(room_data));
2017-01-19 00:52:53 -05:00
if ((room_count = netplay_rooms_get_count()) > 0)
2022-06-17 17:38:56 -03:00
{
net_st->room_list = (struct netplay_room*)calloc(room_count,
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
sizeof(*net_st->room_list));
2022-06-17 17:38:56 -03:00
if (net_st->room_list)
{
int i;
net_st->room_count = room_count;
for (i = 0; i < room_count; i++)
memcpy(&net_st->room_list[i], netplay_room_get(i),
sizeof(*net_st->room_list));
}
}
netplay_rooms_free();
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
}
2022-06-17 17:38:56 -03:00
free(room_data);
done:
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
}
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
static int action_ok_push_netplay_refresh_rooms(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2022-06-17 17:38:56 -03:00
task_push_http_transfer(FILE_PATH_LOBBY_LIBRETRO_URL "list", true, NULL,
netplay_refresh_rooms_cb, NULL);
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
return 0;
}
2017-02-27 19:00:43 -05:00
#ifdef HAVE_NETPLAYDISCOVERY
static void netplay_refresh_lan_cb(const void *data)
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
{
2022-06-17 17:38:56 -03:00
int i;
const char *path = NULL;
const char *label = NULL;
unsigned menu_type = 0;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
const struct netplay_host_list *hosts =
(const struct netplay_host_list*)data;
net_driver_state_t *net_st = networking_state_get_ptr();
struct menu_state *menu_st = menu_state_get_ptr();
2022-06-17 17:38:56 -03:00
free(net_st->room_list);
net_st->room_list = NULL;
net_st->room_count = 0;
2017-01-22 21:19:39 +01:00
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL);
2017-01-19 00:52:53 -05:00
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
/* Don't push the results if we left the netplay menu */
2023-07-15 15:14:26 +02:00
if ( !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB))
&& !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
return;
2022-06-17 17:38:56 -03:00
if (!hosts || !hosts->size)
goto done;
net_st->room_list =
(struct netplay_room*)calloc(hosts->size, sizeof(*net_st->room_list));
if (!net_st->room_list)
goto done;
net_st->room_count = (int)hosts->size;
2022-06-17 17:38:56 -03:00
for (i = 0; i < net_st->room_count; i++)
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
{
2022-06-17 17:38:56 -03:00
struct netplay_host *host = &hosts->hosts[i];
struct netplay_room *room = &net_st->room_list[i];
room->gamecrc = host->content_crc;
room->port = host->port;
strlcpy(room->nickname, host->nick, sizeof(room->nickname));
strlcpy(room->frontend, host->frontend, sizeof(room->frontend));
strlcpy(room->corename, host->core, sizeof(room->corename));
strlcpy(room->coreversion, host->core_version,
sizeof(room->coreversion));
strlcpy(room->retroarch_version, host->retroarch_version,
sizeof(room->retroarch_version));
strlcpy(room->gamename, host->content, sizeof(room->gamename));
strlcpy(room->subsystem_name, host->subsystem_name,
sizeof(room->subsystem_name));
strlcpy(room->address, host->address, sizeof(room->address));
room->has_password = host->has_password;
room->has_spectate_password = host->has_spectate_password;
room->connectable = true;
room->is_retroarch = true;
room->lan = true;
2017-01-19 00:52:53 -05:00
}
2022-06-17 17:38:56 -03:00
done:
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
2017-01-19 00:52:53 -05:00
}
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
static int action_ok_push_netplay_refresh_lan(const char *path,
2017-01-19 00:52:53 -05:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
task_push_netplay_lan_scan(netplay_refresh_lan_cb, 800);
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
2017-01-19 00:52:53 -05:00
return 0;
}
2017-01-22 21:19:39 +01:00
#endif
static int action_ok_push_netplay_kick(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
netplay_client_info_t client;
client.id = (int)strtol(label, NULL, 10);
strlcpy(client.name, path, sizeof(client.name));
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_KICK_CLIENT, &client))
_len = snprintf(msg, sizeof(msg),
msg_hash_to_str(MSG_NETPLAY_KICKED_CLIENT_S), client.name);
else
_len = snprintf(msg, sizeof(msg),
msg_hash_to_str(MSG_NETPLAY_FAILED_TO_KICK_CLIENT_S), client.name);
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2022-07-07 11:08:46 -03:00
static int action_ok_push_netplay_ban(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
2022-07-07 11:08:46 -03:00
netplay_client_info_t client;
client.id = (int)strtol(label, NULL, 10);
strlcpy(client.name, path, sizeof(client.name));
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_BAN_CLIENT, &client))
_len = snprintf(msg, sizeof(msg),
2022-07-07 11:08:46 -03:00
msg_hash_to_str(MSG_NETPLAY_BANNED_CLIENT_S), client.name);
else
_len = snprintf(msg, sizeof(msg),
2022-07-07 11:08:46 -03:00
msg_hash_to_str(MSG_NETPLAY_FAILED_TO_BAN_CLIENT_S), client.name);
runloop_msg_queue_push(msg, _len, 1, 180, true, NULL,
2022-07-07 11:08:46 -03:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
#endif
2017-01-19 00:52:53 -05:00
DEFAULT_ACTION_OK_DL_PUSH(action_ok_content_collection_list, FILEBROWSER_SELECT_COLLECTION, ACTION_OK_DL_CONTENT_COLLECTION_LIST, NULL)
DEFAULT_ACTION_OK_DL_PUSH(action_ok_push_content_list, FILEBROWSER_SELECT_FILE, ACTION_OK_DL_CONTENT_LIST, settings->paths.directory_menu_content)
DEFAULT_ACTION_OK_DL_PUSH(action_ok_push_scan_file, FILEBROWSER_SCAN_FILE, ACTION_OK_DL_CONTENT_LIST, settings->paths.directory_menu_content)
static int action_ok_scan_directory_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
const char *dir_menu_content = settings->paths.directory_menu_content;
filebrowser_clear_type();
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, dir_menu_content,
label, type,
idx, entry_idx,
ACTION_OK_DL_SCAN_DIR_LIST);
}
static int action_ok_push_random_dir(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, path,
msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), type,
idx, entry_idx,
ACTION_OK_DL_CONTENT_LIST);
}
static int action_ok_push_downloads_dir(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2016-07-09 18:12:35 +02:00
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
const char *dir_core_assets = settings->paths.directory_core_assets;
filebrowser_set_type(FILEBROWSER_SELECT_FILE);
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, dir_core_assets,
msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), type,
idx, entry_idx,
ACTION_OK_DL_CONTENT_LIST);
}
int action_ok_push_filebrowser_list_dir_select(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-12-22 05:21:25 +01:00
menu_entry_t entry;
2024-12-24 05:10:09 +01:00
#if IOS
char tmp[PATH_MAX_LENGTH];
#endif
char current_value[PATH_MAX_LENGTH];
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
/* Start browsing from current directory */
2024-12-22 05:21:25 +01:00
MENU_ENTRY_INITIALIZE(entry);
entry.flags |= MENU_ENTRY_FLAG_VALUE_ENABLED;
menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true);
strlcpy(current_value, entry.value, sizeof(current_value));
#if IOS
fill_pathname_expand_special(tmp, current_value, sizeof(tmp));
if (!path_is_directory(tmp))
current_value[0] = '\0';
#else
if (!path_is_directory(current_value))
current_value[0] = '\0';
#endif
2017-05-19 02:39:33 +02:00
filebrowser_set_type(FILEBROWSER_SELECT_DIR);
strlcpy(menu->filebrowser_label, label, sizeof(menu->filebrowser_label));
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, current_value,
label, type,
idx, entry_idx,
ACTION_OK_DL_FILE_BROWSER_SELECT_DIR);
}
int action_ok_push_filebrowser_list_file_select(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_state_get_ptr()->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
filebrowser_set_type(FILEBROWSER_SELECT_FILE);
strlcpy(menu->filebrowser_label, label, sizeof(menu->filebrowser_label));
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
label, type,
idx, entry_idx,
ACTION_OK_DL_FILE_BROWSER_SELECT_DIR);
}
2019-11-29 17:13:35 +00:00
int action_ok_push_manual_content_scan_dir_select(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
const char *dir_menu_content = settings->paths.directory_menu_content;
2019-11-29 17:13:35 +00:00
filebrowser_clear_type();
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, dir_menu_content,
label, type,
idx, entry_idx,
ACTION_OK_DL_MANUAL_SCAN_DIR_LIST);
2019-11-29 17:13:35 +00:00
}
/* TODO/FIXME */
2020-02-19 22:06:21 +01:00
static int action_ok_push_dropdown_setting_core_options_item_special(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_option_manager_t *coreopts = NULL;
int core_option_idx = (int)atoi(label);
retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
if (!coreopts)
return -1;
core_option_manager_set_val(coreopts,
core_option_idx, idx, false);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2019-12-02 21:05:04 +01:00
static int action_ok_push_dropdown_setting_core_options_item(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-12-02 21:05:04 +01:00
core_option_manager_t *coreopts = NULL;
int core_option_idx = (int)atoi(label);
retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
2019-12-02 21:05:04 +01:00
if (!coreopts)
return -1;
core_option_manager_set_val(coreopts,
core_option_idx, idx, false);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
/* TODO/FIXME */
static int action_ok_push_dropdown_setting_uint_item_special(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned value;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(label);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
value = (unsigned)(idx + setting->offset_by);
if (!string_is_empty(path))
{
unsigned path_value = atoi(path);
if (path_value != value)
value = path_value;
}
*setting->value.target.unsigned_integer = value;
if (setting->change_handler)
setting->change_handler(setting);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2019-12-02 21:05:04 +01:00
static int generic_action_ok_dropdown_setting(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
2018-09-23 17:13:45 +02:00
{
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(label);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
2020-06-30 05:21:47 +02:00
switch (setting->type)
2019-12-02 21:05:04 +01:00
{
case ST_INT:
*setting->value.target.integer = (int32_t)(idx + setting->offset_by);
break;
case ST_UINT:
{
unsigned value = (unsigned)(idx + setting->offset_by);
*setting->value.target.unsigned_integer = value;
}
break;
case ST_FLOAT:
{
float val = (float)atof(path);
*setting->value.target.fraction = (float)val;
}
break;
case ST_STRING_OPTIONS:
if (setting->get_string_representation)
{
char *tok, *save;
unsigned tok_idx = 0;
char *setting_values_cpy = strdup(setting->values);
for (tok = strtok_r(setting_values_cpy, "|", &save); tok != NULL;
tok = strtok_r(NULL, "|", &save), tok_idx++)
{
if (idx == tok_idx)
{
strlcpy(setting->value.target.string, tok,
setting->size);
break;
}
}
free(setting_values_cpy);
break;
}
/* fallthrough */
case ST_STRING:
2019-12-02 21:05:04 +01:00
case ST_PATH:
case ST_DIR:
strlcpy(setting->value.target.string, path,
setting->size);
break;
default:
break;
}
if (setting->change_handler)
setting->change_handler(setting);
2018-09-23 17:13:45 +02:00
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
static int action_ok_push_dropdown_item(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return 0;
}
2019-04-14 07:08:35 +02:00
int action_cb_push_dropdown_item_resolution(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char *save = NULL;
char *tok = NULL;
unsigned width = 0;
unsigned height = 0;
float refreshrate = 0.0f;
char *str = path ? strdup(path) : NULL;
if (!str)
return -1;
if ((tok = strtok_r(str, "x", &save)))
width = (unsigned)strtoul(tok, NULL, 0);
if ((tok = strtok_r(NULL, " ", &save)))
height = (unsigned)strtoul(tok, NULL, 0);
if ((tok = strtok_r(NULL, "(", &save)))
refreshrate = (float)strtod(tok, NULL);
free(str);
if (video_display_server_set_resolution(width, height,
floor(refreshrate), refreshrate, 0, 0, 0, 0))
{
settings_t *settings = config_get_ptr();
2021-08-21 20:05:44 +02:00
#ifdef _MSC_VER
float num = refreshrate / 60.0f;
unsigned refresh_mod = num > 0 ? (unsigned)(floorf(num + 0.5f)) : (unsigned)(ceilf(num - 0.5f));
#else
unsigned refresh_mod = (unsigned)lroundf((float)(refreshrate / 60.0f));
2021-08-21 20:05:44 +02:00
#endif
2021-08-21 18:20:15 +03:00
float refresh_exact = refreshrate;
/* 59 Hz is an inaccurate representation of the real value (59.94).
* In case at this point we only have the integer to work with,
2021-08-21 18:20:15 +03:00
* the exact float needs to be calculated for 'video_refresh_rate' */
if (refreshrate == (60.0f * refresh_mod) - 1)
refresh_exact = 59.94f * refresh_mod;
video_monitor_set_refresh_rate(refresh_exact);
settings->uints.video_fullscreen_x = width;
settings->uints.video_fullscreen_y = height;
action_cancel_pop_default(NULL, NULL, 0, 0);
2019-04-14 07:08:35 +02:00
}
return 0;
}
static int action_ok_push_dropdown_item_video_shader_num_pass(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
struct video_shader *shader = menu_shader_get();
if (!shader)
return -1;
shader->passes = (unsigned)idx;
video_shader_resolve_parameters(shader);
shader->flags |= SHDR_FLAG_MODIFIED;
return action_cancel_pop_default(NULL, NULL, 0, 0);
#else
return 0;
#endif
}
static int action_ok_push_dropdown_item_video_shader_param_generic(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx,
size_t setting_offset)
{
2019-12-24 03:15:51 +01:00
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
video_shader_ctx_t shader_info;
2021-02-03 10:39:29 +01:00
unsigned offset = (unsigned)setting_offset;
float val = atof(path);
struct video_shader *shader = menu_shader_get();
struct video_shader_parameter *param_menu = NULL;
struct video_shader_parameter *param_prev = NULL;
video_shader_driver_get_current_shader(&shader_info);
2020-10-02 21:39:46 +02:00
param_prev = &shader_info.data->parameters[entry_idx - offset];
if (shader)
param_menu = &shader->parameters [entry_idx - offset];
if (!param_prev || !param_menu)
return -1;
param_prev->current = val;
param_menu->current = param_prev->current;
shader->flags |= SHDR_FLAG_MODIFIED;
return action_cancel_pop_default(NULL, NULL, 0, 0);
2019-12-24 03:15:51 +01:00
#else
return 0;
#endif
}
static int action_ok_push_dropdown_item_video_shader_param(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-10-02 21:39:46 +02:00
return action_ok_push_dropdown_item_video_shader_param_generic(
path, label, type,
idx, entry_idx, MENU_SETTINGS_SHADER_PARAMETER_0);
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_video_shader_preset_param(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-10-02 21:39:46 +02:00
return action_ok_push_dropdown_item_video_shader_param_generic(
path, label, type,
idx, entry_idx, MENU_SETTINGS_SHADER_PRESET_PARAMETER_0);
}
2019-04-14 07:08:35 +02:00
static int action_ok_push_dropdown_item_resolution(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
/* TODO/FIXME - menu drivers like XMB don't rescale
* automatically */
2019-04-14 07:08:35 +02:00
if (action_cb_push_dropdown_item_resolution(path,
label, type, idx, entry_idx) == 1)
return -1;
return 0;
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_playlist_default_core(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
core_info_list_t *core_info_list = NULL;
playlist_t *playlist = playlist_get_cached();
const char* core_name = path;
/* Get core list */
core_info_get_list(&core_info_list);
if (!core_info_list || !playlist)
return -1;
/* Handle N/A or empty path input */
2024-12-25 19:06:04 +01:00
if ( string_is_empty(core_name)
|| string_is_equal(core_name, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)))
{
playlist_set_default_core_path(playlist, FILE_PATH_DETECT);
playlist_set_default_core_name(playlist, FILE_PATH_DETECT);
}
else
{
size_t i;
/* Loop through cores until we find a match */
for (i = 0; i < core_info_list->count; i++)
{
core_info_t *core_info = core_info_get(core_info_list, i);
if (core_info)
{
const char *core_info_display_name = core_info->display_name;
const char *core_info_path = core_info->path;
if (string_is_equal(core_name, core_info_display_name))
{
/* Update playlist */
playlist_set_default_core_path(playlist, core_info_path);
playlist_set_default_core_name(playlist, core_info_display_name);
goto end;
}
}
}
/* if we couldn't find a match, add this fallback... */
playlist_set_default_core_path(playlist, FILE_PATH_DETECT);
playlist_set_default_core_name(playlist, FILE_PATH_DETECT);
}
end:
/* In all cases, update file on disk */
2020-06-26 15:39:03 +01:00
playlist_write_file(playlist);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-02-19 22:06:21 +01:00
static int action_ok_push_dropdown_item_playlist_label_display_mode(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_t *playlist = playlist_get_cached();
2020-10-02 21:39:46 +02:00
playlist_set_label_display_mode(playlist,
(enum playlist_label_display_mode)idx);
/* In all cases, update file on disk */
2020-06-26 15:39:03 +01:00
playlist_write_file(playlist);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-10-02 21:39:46 +02:00
static int generic_set_thumbnail_mode(
enum playlist_thumbnail_id thumbnail_id, size_t idx)
{
2020-06-26 15:39:03 +01:00
playlist_t *playlist = playlist_get_cached();
if (!playlist)
return -1;
2020-02-19 22:06:21 +01:00
playlist_set_thumbnail_mode(playlist, thumbnail_id,
(enum playlist_thumbnail_mode)idx);
2020-06-26 15:39:03 +01:00
playlist_write_file(playlist);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_playlist_right_thumbnail_mode(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_set_thumbnail_mode(PLAYLIST_THUMBNAIL_RIGHT, idx);
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_playlist_left_thumbnail_mode(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_set_thumbnail_mode(PLAYLIST_THUMBNAIL_LEFT, idx);
}
static int action_ok_push_dropdown_item_playlist_sort_mode(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_t *playlist = playlist_get_cached();
playlist_set_sort_mode(playlist, (enum playlist_sort_mode)idx);
2020-06-26 15:39:03 +01:00
playlist_write_file(playlist);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_manual_content_scan_system_name(
const char *path,
2019-11-29 17:13:35 +00:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char* system_name = path;
enum manual_content_scan_system_name_type system_name_type =
MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE;
/* Get system name type (i.e. check if setting is
* 'use content directory' or 'use custom') */
2020-02-21 03:28:23 +01:00
switch (idx)
{
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR:
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM:
2020-02-21 05:00:08 +01:00
system_name_type = (enum manual_content_scan_system_name_type)idx;
2020-02-21 03:28:23 +01:00
break;
default:
break;
}
2019-11-29 17:13:35 +00:00
/* Set system name */
manual_content_scan_set_menu_system_name(
system_name_type, system_name);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-02-21 03:28:23 +01:00
static int action_ok_push_dropdown_item_manual_content_scan_core_name(
const char *path,
2019-11-29 17:13:35 +00:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char* core_name = path;
enum manual_content_scan_core_type core_type =
MANUAL_CONTENT_SCAN_CORE_SET;
/* Get core type (i.e. check if setting is
* DETECT/Unspecified) */
if (idx == (size_t)MANUAL_CONTENT_SCAN_CORE_DETECT)
core_type = MANUAL_CONTENT_SCAN_CORE_DETECT;
/* Set core name */
manual_content_scan_set_menu_core_name(
core_type, core_name);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-01-14 12:28:10 +00:00
static int action_ok_push_dropdown_item_disk_index(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
unsigned disk_index = (unsigned)idx;
2020-01-14 12:28:10 +00:00
command_event(CMD_EVENT_DISK_INDEX, &disk_index);
/* When choosing a disk, menu selection should
* automatically be reset to the 'insert disk'
* option */
menu_entries_pop_stack(NULL, 0, 1);
menu_st->selection_ptr = 0;
2020-01-14 12:28:10 +00:00
return 0;
}
static int action_ok_push_dropdown_item_audio_device(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
enum msg_hash_enums enum_idx;
rarch_setting_t *setting;
2024-12-24 05:10:09 +01:00
const char *menu_path = NULL;
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
strlcpy(setting->value.target.string, label, setting->size);
command_event(CMD_EVENT_AUDIO_REINIT, NULL);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
static int action_ok_push_dropdown_item_microphone_device(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *menu_path = NULL;
enum msg_hash_enums enum_idx;
rarch_setting_t *setting;
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
strlcpy(setting->value.target.string, label, setting->size);
command_event(CMD_EVENT_MICROPHONE_REINIT, NULL);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#endif
2021-02-04 17:06:19 +02:00
static int action_ok_push_dropdown_item_input_device_type(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
rarch_setting_t *setting;
enum msg_hash_enums enum_idx;
2021-02-04 17:06:19 +02:00
retro_ctx_controller_info_t pad;
unsigned port = 0;
unsigned device = 0;
const char *menu_path = NULL;
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
2021-02-05 18:15:10 +02:00
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
2021-02-04 17:06:19 +02:00
if (!setting)
return -1;
2021-02-04 17:06:19 +02:00
port = setting->index_offset;
device = atoi(label);
input_config_set_device(port, device);
pad.port = port;
pad.device = device;
core_set_controller_port_device(&pad);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
static int action_ok_push_dropdown_item_input_select_reserved_device(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned user;
const char *no_device;
const char *reserved_device_name;
enum msg_hash_enums enum_idx;
rarch_setting_t *setting = NULL;
settings_t *settings = config_get_ptr();
const char *menu_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
user = enum_idx - MENU_ENUM_LABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME;
if (!setting)
return -1;
reserved_device_name = path;
no_device = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
if (string_is_equal(reserved_device_name, no_device))
settings->arrays.input_reserved_devices[user][0] = '\0';
else
{
int i;
for (i = 0; i < MAX_INPUT_DEVICES; i++)
{
const char* device_name = input_config_get_device_display_name(i)
? input_config_get_device_display_name(i)
: input_config_get_device_name(i);
if (string_is_equal(device_name, reserved_device_name))
{
uint16_t vendor_id = input_config_get_device_vid(i);
uint16_t product_id = input_config_get_device_pid(i);
snprintf(settings->arrays.input_reserved_devices[user],
sizeof(settings->arrays.input_reserved_devices[user]),
"%04x:%04x %s",
vendor_id, product_id, reserved_device_name);
break;
}
}
}
settings->flags |= SETTINGS_FLG_MODIFIED;
command_event(CMD_EVENT_REINIT, NULL);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#ifdef ANDROID
static int action_ok_push_dropdown_item_input_select_physical_keyboard(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char* keyboard;
const char *no_keyboard;
const char *keyboard_name;
enum msg_hash_enums enum_idx;
rarch_setting_t *setting = NULL;
settings_t *settings = config_get_ptr();
const char *menu_path = NULL;
2023-05-10 21:59:50 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
keyboard_name = path;
no_keyboard = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
if (string_is_equal(keyboard_name, no_keyboard))
settings->arrays.input_android_physical_keyboard[0] = '\0';
else
{
int i;
for (i = 0; i < MAX_INPUT_DEVICES; i++)
{
const char* device_name = input_config_get_device_name(i);
if (string_is_equal(device_name, keyboard_name))
{
uint16_t vendor_id = input_config_get_device_vid(i);
uint16_t product_id = input_config_get_device_pid(i);
snprintf(settings->arrays.input_android_physical_keyboard,
sizeof(settings->arrays.input_android_physical_keyboard),
"%04x:%04x %s",
vendor_id, product_id, keyboard_name);
break;
}
}
/*
* if we did not find the selected device, do nothing, the user has chosen to keep
* the previous configuration, which is to use a device that is either not plugged right
* now or already working as the physical keyboard.
*/
}
settings->flags |= SETTINGS_FLG_MODIFIED;
command_event(CMD_EVENT_REINIT, NULL);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#endif
2020-07-23 17:19:41 +01:00
static int action_ok_push_dropdown_item_input_description(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned remap_idx = (unsigned)entry_idx;
unsigned entry_type = string_to_unsigned(label);
settings_t *settings = config_get_ptr();
unsigned user_idx;
unsigned btn_idx;
2023-07-15 15:14:26 +02:00
if ( !settings
|| (entry_type < MENU_SETTINGS_INPUT_DESC_BEGIN)
|| ((remap_idx >= RARCH_CUSTOM_BIND_LIST_END)
&& (remap_idx != RARCH_UNMAPPED)))
return -1;
2020-07-23 17:19:41 +01:00
/* Determine user/button indices */
2023-08-16 03:22:02 +02:00
user_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_BEGIN)
2020-10-02 21:39:46 +02:00
/ (RARCH_FIRST_CUSTOM_BIND + 8);
2023-08-16 03:22:02 +02:00
btn_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_BEGIN)
2020-10-02 21:39:46 +02:00
- (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
2020-07-23 17:19:41 +01:00
if ((user_idx >= MAX_USERS) || (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
return -1;
2020-07-23 17:19:41 +01:00
/* Assign new mapping */
settings->uints.input_remap_ids[user_idx][btn_idx] = remap_idx;
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2020-10-02 21:39:46 +02:00
static int action_ok_push_dropdown_item_input_description_kbd(
const char *path,
2020-07-23 17:19:41 +01:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
unsigned key_id = (unsigned)entry_idx;
unsigned entry_type = string_to_unsigned(label);
settings_t *settings = config_get_ptr();
unsigned user_idx;
unsigned btn_idx;
if ( (!settings)
|| (entry_type < MENU_SETTINGS_INPUT_DESC_KBD_BEGIN)
|| (key_id >= (RARCH_MAX_KEYS + MENU_SETTINGS_INPUT_DESC_KBD_BEGIN)))
return -1;
2020-07-23 17:19:41 +01:00
/* Determine user/button indices */
2023-08-16 03:22:02 +02:00
user_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN)
/ RARCH_ANALOG_BIND_LIST_END;
2023-08-16 03:22:02 +02:00
btn_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN)
- RARCH_ANALOG_BIND_LIST_END * user_idx;
2020-07-23 17:19:41 +01:00
if ((user_idx >= MAX_USERS) || (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
return -1;
2020-07-23 17:19:41 +01:00
/* Assign new mapping */
settings->uints.input_keymapper_ids[user_idx][btn_idx] = key_id;
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#ifdef HAVE_NETWORKING
static int action_ok_push_dropdown_item_netplay_mitm_server(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *menu_path = NULL;
enum msg_hash_enums enum_idx;
rarch_setting_t *setting;
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
2024-12-24 05:10:09 +01:00
strlcpy(setting->value.target.string, label, setting->size);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#endif
static int action_ok_push_default(const char *path,
2015-09-03 23:14:50 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
filebrowser_clear_type();
2023-07-17 22:32:13 +03:00
return generic_action_ok_displaylist_push(
path, NULL,
label, type,
idx, entry_idx,
ACTION_OK_DL_PUSH_DEFAULT);
2015-09-03 23:14:50 +02:00
}
static int action_ok_start_core(const char *path,
2016-01-24 01:51:05 +01:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2017-04-27 01:23:04 +02:00
content_ctx_info_t content_info;
2023-05-12 01:00:08 +02:00
struct menu_state *menu_st = menu_state_get_ptr();
2017-04-27 01:23:04 +02:00
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2022-02-22 18:23:48 +00:00
/* We are going to push a new menu; ensure
* that the current one is cached for animation
* purposes */
2023-05-12 01:00:08 +02:00
if (menu_st->driver_ctx && menu_st->driver_ctx->list_cache)
menu_st->driver_ctx->list_cache(menu_st->userdata,
MENU_LIST_PLAIN, MENU_ACTION_NOOP);
2022-02-22 18:23:48 +00:00
2017-11-26 18:33:05 -05:00
path_clear(RARCH_PATH_BASENAME);
2017-02-21 16:50:39 +01:00
if (!task_push_start_current_core(&content_info))
return -1;
return 0;
}
2016-05-27 19:18:46 +02:00
2022-02-22 18:23:48 +00:00
static int action_ok_contentless_core_run(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = path;
struct menu_state *menu_st = menu_state_get_ptr();
2022-02-22 18:23:48 +00:00
/* TODO/FIXME: If this function succeeds, the
* quick menu will be pushed on the subsequent
* frame via the RARCH_MENU_CTL_SET_PENDING_QUICK_MENU
* command. The way this is implemented 'breaks' the
* menu stack record, so when leaving the quick
* menu via a 'cancel' operation, the last selected
* menu index is lost. We therefore have to cache
* the current selection here, and reapply it manually
* when building the contentless cores list... */
size_t selection = menu_st->selection_ptr;
uint32_t flags = runloop_get_flags();
2022-02-22 18:23:48 +00:00
if (string_is_empty(core_path))
return -1;
2022-02-22 18:23:48 +00:00
/* If core is already running, open quick menu */
2022-10-10 08:59:27 +02:00
if ( retroarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path)
&& (flags & RUNLOOP_FLAG_CORE_RUNNING))
2022-02-22 18:23:48 +00:00
{
bool flush_menu = false;
2022-02-22 18:23:48 +00:00
menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, &flush_menu);
menu_st->contentless_core_ptr = selection;
menu_st->selection_ptr = 0;
2022-02-22 18:23:48 +00:00
return 0;
}
/* Cache current menu selection *before* attempting
* to start the core, to ensure consistent menu
* navigation (i.e. running a core will in general
* cause a redraw of the menu, so must record current
* position even if the operation fails) */
menu_st->contentless_core_ptr = selection;
2022-02-22 18:23:48 +00:00
/* Load and start core */
path_clear(RARCH_PATH_BASENAME);
if (!task_push_load_contentless_core_from_menu(core_path))
{
if (retroarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path))
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
return -1;
}
return 0;
}
static int action_ok_load_archive(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *menu_path = NULL;
const char *content_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2016-02-10 21:15:23 +01:00
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
2016-02-10 21:15:23 +01:00
menu_path = menu->scratch2_buf;
content_path = menu->scratch_buf;
fill_pathname_join_special(menu->detect_content_path,
menu_path, content_path,
sizeof(menu->detect_content_path));
2017-11-26 06:35:53 +01:00
generic_action_ok_command(CMD_EVENT_LOAD_CORE);
2017-11-26 07:29:19 +01:00
return default_action_ok_load_content_with_core_from_menu(
menu->detect_content_path,
2017-11-26 07:29:19 +01:00
CORE_TYPE_PLAIN);
}
static int action_ok_load_archive_detect_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
char new_core_path[PATH_MAX_LENGTH];
menu_content_ctx_defer_info_t def_info;
int ret = 0;
core_info_list_t *list = NULL;
const char *menu_path = NULL;
const char *content_path = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
2019-08-16 15:17:02 +02:00
if (!menu)
return -1;
menu_path = menu->scratch2_buf;
content_path = menu->scratch_buf;
2016-02-10 21:15:23 +01:00
#if IOS
char tmp_path[PATH_MAX_LENGTH];
fill_pathname_expand_special(tmp_path, menu_path, sizeof(tmp_path));
menu_path = tmp_path;
#endif
2016-05-09 18:11:17 +02:00
core_info_get_list(&list);
2015-12-11 13:51:17 +01:00
def_info.data = list;
def_info.dir = menu_path;
def_info.path = content_path;
def_info.menu_label = label;
def_info.s = menu->deferred_path;
def_info.len = sizeof(menu->deferred_path);
new_core_path[0] = '\0';
2018-02-04 19:05:43 +01:00
2016-07-01 05:17:04 +02:00
if (menu_content_find_first_core(&def_info, false,
new_core_path, sizeof(new_core_path)))
ret = -1;
2024-04-29 21:30:15 -04:00
if (path_is_absolute(content_path))
strlcpy(menu->detect_content_path, content_path, sizeof(menu->detect_content_path));
else
fill_pathname_join_special(
menu->detect_content_path, menu_path, content_path,
sizeof(menu->detect_content_path));
switch (ret)
{
case -1:
{
2017-04-27 01:23:04 +02:00
content_ctx_info_t content_info;
content_info.argc = 0;
content_info.argv = NULL;
content_info.args = NULL;
content_info.environ_get = NULL;
2018-02-04 19:05:43 +01:00
ret = 0;
2017-02-21 18:36:38 +01:00
if (!task_push_load_content_with_new_core_from_menu(
new_core_path, def_info.s,
&content_info,
CORE_TYPE_PLAIN,
NULL, NULL))
2018-02-04 19:05:43 +01:00
ret = -1;
else
2023-05-09 04:58:06 +02:00
menu_driver_set_last_start_content(menu_st, def_info.s);
}
2017-09-09 22:10:19 +02:00
break;
case 0:
idx = menu_st->selection_ptr;
2023-07-17 22:32:13 +03:00
ret = generic_action_ok_displaylist_push(
path, NULL,
2017-08-13 00:55:47 +02:00
label, type,
2023-07-17 22:32:13 +03:00
idx, entry_idx,
ACTION_OK_DL_DEFERRED_CORE_LIST);
2017-09-09 22:10:19 +02:00
break;
2015-09-07 02:46:47 +02:00
default:
break;
}
return ret;
}
2020-06-07 02:41:48 +02:00
DEFAULT_ACTION_OK_HELP(action_ok_help_audio_video_troubleshooting, MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING, MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING)
DEFAULT_ACTION_OK_HELP(action_ok_help, MENU_ENUM_LABEL_HELP, MENU_DIALOG_WELCOME)
DEFAULT_ACTION_OK_HELP(action_ok_help_controls, MENU_ENUM_LABEL_HELP_CONTROLS, MENU_DIALOG_HELP_CONTROLS)
DEFAULT_ACTION_OK_HELP(action_ok_help_what_is_a_core, MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE, MENU_DIALOG_HELP_WHAT_IS_A_CORE)
DEFAULT_ACTION_OK_HELP(action_ok_help_scanning_content, MENU_ENUM_LABEL_HELP_SCANNING_CONTENT, MENU_DIALOG_HELP_SCANNING_CONTENT)
DEFAULT_ACTION_OK_HELP(action_ok_help_change_virtual_gamepad, MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD, MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD)
DEFAULT_ACTION_OK_HELP(action_ok_help_load_content, MENU_ENUM_LABEL_HELP_LOADING_CONTENT, MENU_DIALOG_HELP_LOADING_CONTENT)
static int generic_dropdown_box_list(size_t idx, unsigned lbl)
{
generic_action_ok_displaylist_push(
2023-07-17 22:32:13 +03:00
NULL, NULL,
NULL, 0,
idx, 0,
lbl);
return 0;
}
static int action_ok_video_resolution(const char *path,
2015-06-10 23:11:40 +02:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#if defined(GEKKO) || defined(PS2) || defined(__PS3__)
2015-09-05 17:17:26 +02:00
unsigned width = 0;
unsigned height = 0;
char desc[64] = {0};
2015-09-05 17:17:26 +02:00
if (video_driver_get_video_output_size(&width, &height, desc, sizeof(desc)))
2015-07-06 00:29:51 -05:00
{
size_t _len;
char msg[128];
2016-10-08 19:47:26 +02:00
msg[0] = '\0';
#if defined(_WIN32) || defined(__PS3__)
2017-11-26 06:35:53 +01:00
generic_action_ok_command(CMD_EVENT_REINIT);
#endif
video_driver_set_video_mode(width, height, true);
#ifdef GEKKO
if (width == 0 || height == 0)
_len = snprintf(msg, sizeof(msg),
msg_hash_to_str(MSG_SCREEN_RESOLUTION_APPLYING_DEFAULT));
else
#endif
{
if (!string_is_empty(desc))
_len = snprintf(msg, sizeof(msg),
2023-08-16 03:22:02 +02:00
msg_hash_to_str(MSG_SCREEN_RESOLUTION_APPLYING_DESC),
width, height, desc);
else
_len = snprintf(msg, sizeof(msg),
2023-08-16 03:22:02 +02:00
msg_hash_to_str(MSG_SCREEN_RESOLUTION_APPLYING_NO_DESC),
width, height);
}
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
2020-10-02 21:39:46 +02:00
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2015-07-06 00:29:51 -05:00
}
return 0;
#else
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_RESOLUTION);
#endif
}
static int action_ok_playlist_default_core(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_DEFAULT_CORE);
}
static int action_ok_playlist_label_display_mode(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE);
}
static int action_ok_playlist_right_thumbnail_mode(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE);
}
static int action_ok_playlist_left_thumbnail_mode(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE);
}
static int action_ok_playlist_sort_mode(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE);
}
static int action_ok_remappings_port_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
generic_action_ok_displaylist_push(
2023-07-17 22:32:13 +03:00
path, NULL,
label, 0,
idx, 0,
ACTION_OK_DL_REMAPPINGS_PORT_LIST);
return 0;
}
static int action_ok_shader_parameter_dropdown_box_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PARAMETER);
}
2020-10-02 21:39:46 +02:00
static int action_ok_shader_preset_parameter_dropdown_box_list(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_SHADER_PRESET_PARAMETER);
}
2019-11-29 17:13:35 +00:00
static int action_ok_manual_content_scan_system_name(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
2019-11-29 17:13:35 +00:00
ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME);
}
static int action_ok_manual_content_scan_core_name(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
2019-11-29 17:13:35 +00:00
ACTION_OK_DL_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME);
}
2020-10-02 21:39:46 +02:00
static int action_ok_video_shader_num_passes_dropdown_box_list(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-08-16 03:22:02 +02:00
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_VIDEO_SHADER_NUM_PASSES);
}
2020-01-14 12:28:10 +00:00
static int action_ok_disk_index_dropdown_box_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_dropdown_box_list(idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_DISK_INDEX);
}
2020-07-23 17:19:41 +01:00
static int action_ok_input_description_dropdown_box_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_displaylist_push(
2023-07-17 22:32:13 +03:00
path, NULL,
label, type,
idx, entry_idx,
2020-07-23 17:19:41 +01:00
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION);
}
2020-10-02 21:39:46 +02:00
static int action_ok_input_description_kbd_dropdown_box_list(
const char *path,
2020-07-23 17:19:41 +01:00
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
return generic_action_ok_displaylist_push(
2023-07-17 22:32:13 +03:00
path, NULL,
label, type,
idx, entry_idx,
2020-07-23 17:19:41 +01:00
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD);
}
2020-01-14 12:28:10 +00:00
static int action_ok_disk_cycle_tray_status(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
bool disk_ejected = false;
bool print_log = false;
struct menu_state *menu_st = menu_state_get_ptr();
2021-09-21 19:08:26 +02:00
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
2020-01-14 12:28:10 +00:00
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
#ifdef HAVE_AUDIOMIXER
bool audio_enable_menu = settings->bools.audio_enable_menu;
bool audio_enable_menu_ok = settings->bools.audio_enable_menu_ok;
#endif
bool menu_insert_disk_resume = settings->bools.menu_insert_disk_resume;
2020-01-14 12:28:10 +00:00
if (!settings)
return -1;
2020-01-14 12:28:10 +00:00
#ifdef HAVE_AUDIOMIXER
2020-02-19 22:06:21 +01:00
if (audio_enable_menu && audio_enable_menu_ok)
2020-01-14 12:28:10 +00:00
audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_OK);
#endif
/* Get disk eject state *before* toggling drive status */
if (sys_info)
disk_ejected = disk_control_get_eject_state(&sys_info->disk_control);
2020-01-14 12:28:10 +00:00
/* Only want to display a notification if we are
* going to resume content immediately after
* inserting a disk (i.e. if quick menu remains
* open, there is sufficient visual feedback
* without a notification) */
2020-02-19 22:06:21 +01:00
print_log = menu_insert_disk_resume && disk_ejected;
2020-01-14 12:28:10 +00:00
if (!command_event(CMD_EVENT_DISK_EJECT_TOGGLE, &print_log))
return -1;
2020-01-14 12:28:10 +00:00
/* If we reach this point, then tray toggle
* was successful */
disk_ejected = !disk_ejected;
/* If disk is now ejected, menu selection should
* automatically increment to the 'current disk
* index' option */
if (disk_ejected)
menu_st->selection_ptr = 1;
2020-01-14 12:28:10 +00:00
/* If disk is now inserted and user has enabled
* 'menu_insert_disk_resume', resume running content */
2020-02-19 22:06:21 +01:00
if (!disk_ejected && menu_insert_disk_resume)
2020-01-14 12:28:10 +00:00
generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
static int action_ok_disk_image_append(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2021-09-21 19:08:26 +02:00
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
const char *menu_path = NULL;
settings_t *settings = config_get_ptr();
#ifdef HAVE_AUDIOMIXER
bool audio_enable_menu = settings->bools.audio_enable_menu;
bool audio_enable_menu_ok = settings->bools.audio_enable_menu_ok;
#endif
bool menu_insert_disk_resume = settings->bools.menu_insert_disk_resume;
if (!menu)
return -1;
#ifdef HAVE_AUDIOMIXER
if (audio_enable_menu && audio_enable_menu_ok)
audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_OK);
#endif
/* Get file path of new disk image */
menu_entries_get_last_stack(&menu_path,
NULL, NULL, NULL, NULL);
if (!string_is_empty(menu_path))
{
2024-12-24 05:10:09 +01:00
char image_path[PATH_MAX_LENGTH];
bool is_dir = (entry_idx == FILE_TYPE_USE_DIRECTORY
&& string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_USE_THIS_DIRECTORY)));
if (is_dir)
{
size_t past_slash;
strlcpy(image_path, menu_path, sizeof(image_path));
past_slash = fill_pathname_slash(image_path, sizeof(image_path));
2024-12-24 05:10:09 +01:00
if (past_slash > 1)
image_path[past_slash - 1] = '\0';
}
else if (!string_is_empty(path))
fill_pathname_join_special(image_path,
menu_path, path, sizeof(image_path));
else
strlcpy(image_path, menu_path, sizeof(image_path));
2024-12-24 05:10:09 +01:00
/* Append image */
command_event(CMD_EVENT_DISK_APPEND_IMAGE, image_path);
}
/* In all cases, return to the disk options menu */
menu_entries_flush_stack(msg_hash_to_str(MENU_ENUM_LABEL_DISK_OPTIONS), 0);
/* > If disk tray is open, reset menu selection to
* the 'insert disk' option
* > If disk try is closed and user has enabled
* 'menu_insert_disk_resume', resume running content */
if (sys_info && disk_control_get_eject_state(&sys_info->disk_control))
menu_st->selection_ptr = 0;
else if (menu_insert_disk_resume)
generic_action_ok_command(CMD_EVENT_RESUME);
return 0;
}
2019-11-29 17:13:35 +00:00
static int action_ok_manual_content_scan_start(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_config_t playlist_config;
settings_t *settings = config_get_ptr();
const char *directory_playlist = settings->paths.directory_playlist;
/* Note: playlist_config.path will set by the
* task itself */
playlist_config.capacity = COLLECTION_SIZE;
playlist_config.old_format = settings->bools.playlist_use_old_format;
playlist_config.compress = settings->bools.playlist_compression;
playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
playlist_config_set_base_content_directory(&playlist_config,
settings->bools.playlist_portable_paths ?
settings->paths.directory_menu_content : NULL);
2020-06-26 15:39:03 +01:00
task_push_manual_content_scan(&playlist_config, directory_playlist);
2019-11-29 17:13:35 +00:00
return 0;
}
#ifdef HAVE_NETWORKING
static int action_ok_netplay_enable_host(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2019-03-09 17:48:03 -05:00
if (command_event(CMD_EVENT_NETPLAY_ENABLE_HOST, NULL))
2017-08-13 00:55:47 +02:00
return generic_action_ok_command(CMD_EVENT_RESUME);
2017-08-13 00:55:47 +02:00
return -1;
}
static void action_ok_netplay_enable_client_hostname_cb(void *userdata,
const char *line)
{
if (!string_is_empty(line))
{
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE, NULL))
{
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
command_event(CMD_EVENT_NETPLAY_INIT_DIRECT, (void*)line);
menu_input_dialog_end();
retroarch_menu_running_finished(false);
}
else if (!task_push_netplay_content_reload(line))
{
#ifdef HAVE_DYNAMIC
const char *_msg = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED);
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, (void*)line);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 480, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
#else
const char *_msg = msg_hash_to_str(MSG_NETPLAY_NEED_CONTENT_LOADED);
runloop_msg_queue_push(_msg, strlen(_msg), 1, 480, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
#endif
menu_input_dialog_end();
}
else
{
menu_input_dialog_end();
retroarch_menu_running_finished(false);
}
}
else
menu_input_dialog_end();
}
static int action_ok_netplay_enable_client(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
const char *netplay_server = settings->paths.netplay_server;
if (!string_is_empty(netplay_server))
{
2020-02-19 22:06:21 +01:00
action_ok_netplay_enable_client_hostname_cb(NULL, netplay_server);
2017-08-13 00:55:47 +02:00
return 0;
}
else
{
menu_input_ctx_line_t hostname = {0};
hostname.label =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS);
hostname.label_setting = "no_setting";
hostname.cb = action_ok_netplay_enable_client_hostname_cb;
if (menu_input_dialog_start(&hostname))
return 0;
}
2017-08-13 00:55:47 +02:00
return -1;
}
static int action_ok_netplay_disconnect(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
command_event(CMD_EVENT_NETPLAY_DISCONNECT, NULL);
return generic_action_ok_command(CMD_EVENT_RESUME);
}
#endif
static int action_ok_core_create_backup(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = label;
settings_t *settings = config_get_ptr();
unsigned auto_backup_history_size = settings->uints.core_updater_auto_backup_history_size;
const char *dir_core_assets = settings->paths.directory_core_assets;
if (string_is_empty(core_path))
return -1;
task_push_core_backup(core_path, NULL, 0, CORE_BACKUP_MODE_MANUAL,
(size_t)auto_backup_history_size, dir_core_assets, false);
return 0;
}
static int action_ok_core_restore_backup(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *backup_path = label;
bool core_loaded = false;
settings_t *settings = config_get_ptr();
const char *dir_libretro = settings->paths.directory_libretro;
if (string_is_empty(backup_path))
return -1;
/* If core to be restored is currently loaded, the task
* will unload it
* > In this case, must flush the menu stack
* (otherwise user will be faced with 'no information
* available' when popping the stack - this would be
* confusing/ugly) */
2023-07-15 15:14:26 +02:00
if ( task_push_core_restore(backup_path, dir_libretro, &core_loaded)
&& core_loaded)
menu_entries_flush_stack(NULL, 0);
return 0;
}
static int action_ok_core_delete_backup(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
const char *backup_path = label;
if (string_is_empty(backup_path))
return -1;
/* Delete backup file (if it exists) */
if (path_is_valid(backup_path))
filestream_delete(backup_path);
/* Refresh menu */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return 0;
}
/* Do not declare this static - it is also used
* in menu_cbs_left.c and menu_cbs_right.c */
int action_ok_core_lock(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
const char *core_path = path;
bool lock = false;
int ret = 0;
if (string_is_empty(core_path))
return -1;
/* Simply toggle current lock status */
lock = !core_info_get_core_lock(core_path, true);
if (!core_info_set_core_lock(core_path, lock))
{
size_t _len;
const char *core_name = NULL;
core_info_t *core_info = NULL;
char msg[128];
/* Need to fetch core name for error message */
/* If core is found, use display name */
if (
core_info_find(core_path, &core_info)
&& core_info->display_name)
core_name = core_info->display_name;
/* If not, use core file name */
else
core_name = path_basename_nocompression(core_path);
/* Build error message */
_len = strlcpy(msg,
2023-07-15 15:14:26 +02:00
msg_hash_to_str(lock
? MSG_CORE_LOCK_FAILED : MSG_CORE_UNLOCK_FAILED),
sizeof(msg));
if (!string_is_empty(core_name))
_len += strlcpy(msg + _len, core_name, sizeof(msg) - _len);
/* Generate log + notification */
RARCH_ERR("%s\n", msg);
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
ret = -1;
}
/* Whenever lock status is changed, menu must be
* refreshed - do this even in the event of an error,
* since we don't want to leave the menu in an
* undefined state */
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
return ret;
}
/* Do not declare this static - it is also used
* in menu_cbs_left.c and menu_cbs_right.c */
int action_ok_core_set_standalone_exempt(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = path;
bool exempt = false;
if (string_is_empty(core_path))
return -1;
/* Simply toggle current 'exempt' status */
exempt = !core_info_get_core_standalone_exempt(core_path);
if (!core_info_set_core_standalone_exempt(core_path, exempt))
{
size_t _len;
const char *core_name = NULL;
core_info_t *core_info = NULL;
char msg[128];
/* Need to fetch core name for error message */
/* If core is found, use display name */
if (
core_info_find(core_path, &core_info)
&& core_info->display_name)
core_name = core_info->display_name;
/* If not, use core file name */
else
core_name = path_basename_nocompression(core_path);
/* Build error message */
_len = strlcpy(msg,
msg_hash_to_str(exempt ?
MSG_CORE_SET_STANDALONE_EXEMPT_FAILED :
MSG_CORE_UNSET_STANDALONE_EXEMPT_FAILED),
sizeof(msg));
if (!string_is_empty(core_name))
_len += strlcpy(msg + _len, core_name, sizeof(msg) - _len);
/* Generate log + notification */
RARCH_ERR("%s\n", msg);
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
2024-09-09 22:18:23 +02:00
return -1;
}
2024-09-09 22:18:23 +02:00
return 0;
}
static int action_ok_core_delete(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
const char *core_path = label;
2017-11-26 07:17:31 +01:00
2020-05-28 17:48:18 +01:00
if (string_is_empty(core_path))
return -1;
/* Check whether core is locked */
if (core_info_get_core_lock(core_path, true))
{
size_t _len;
const char *core_name = NULL;
core_info_t *core_info = NULL;
char msg[128];
/* Need to fetch core name for notification */
/* If core is found, use display name */
2023-08-16 03:22:02 +02:00
if (
core_info_find(core_path, &core_info)
&& core_info->display_name)
core_name = core_info->display_name;
/* If not, use core file name */
else
core_name = path_basename_nocompression(core_path);
/* Build notification message */
_len = strlcpy(msg, msg_hash_to_str(MSG_CORE_DELETE_DISABLED), sizeof(msg));
if (!string_is_empty(core_name))
_len += strlcpy(msg + _len, core_name, sizeof(msg) - _len);
runloop_msg_queue_push(msg, _len, 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* We do not consider this an 'error' - we are
* merely telling the user that this operation
* is not currently supported */
return 0;
}
2020-05-28 17:48:18 +01:00
/* Check if core to be deleted is currently
* loaded - if so, unload it */
if (retroarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)core_path))
2020-05-28 17:48:18 +01:00
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
2020-05-28 17:48:18 +01:00
/* Delete core file */
#if defined(ANDROID)
/* If this is a Play Store build and the
* core is currently installed via
* play feature delivery, must delete
* the core via the play feature delivery
* interface */
if (play_feature_delivery_enabled())
{
size_t _len;
const char *core_filename = path_basename_nocompression(core_path);
char backup_core_path[PATH_MAX_LENGTH];
if (play_feature_delivery_core_installed(core_filename))
play_feature_delivery_delete(core_filename);
else
filestream_delete(core_path);
/* When installing cores via play feature
* delivery, there is a low probability of
* backup core files being left behind if
* something interrupts the install process
* (i.e. a crash or user exit while the
* install task is running). To prevent the
* accumulation of mess, additionally check
* for and remove any such backups when deleting
* a core */
_len = strlcpy(backup_core_path, core_path,
sizeof(backup_core_path));
strlcpy(backup_core_path + _len, FILE_PATH_BACKUP_EXTENSION,
sizeof(backup_core_path) - _len);
if ( !string_is_empty(backup_core_path)
&& path_is_valid(backup_core_path))
filestream_delete(backup_core_path);
}
else
#endif
filestream_delete(core_path);
2020-05-28 17:48:18 +01:00
/* Reload core info files */
command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
2022-02-22 18:23:48 +00:00
/* Force reload of contentless cores icons */
menu_contentless_cores_free();
2020-05-28 17:48:18 +01:00
/* Return to higher level menu */
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
2019-09-29 10:46:09 -04:00
static int action_ok_delete_playlist(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2023-05-06 22:10:55 +02:00
playlist_t *playlist = playlist_get_cached();
struct menu_state *menu_st = menu_state_get_ptr();
2019-09-29 10:46:09 -04:00
if (!playlist)
return -1;
path = playlist_get_conf_path(playlist);
filestream_delete(path);
2023-05-06 22:10:55 +02:00
if (menu_st->driver_ctx->environ_cb)
menu_st->driver_ctx->environ_cb(MENU_ENVIRON_RESET_HORIZONTAL_LIST,
NULL, menu_st->userdata);
2019-09-29 10:46:09 -04:00
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#ifdef HAVE_NETWORKING
static int action_ok_pl_content_thumbnails(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
2020-02-19 22:06:21 +01:00
if (settings)
{
2020-06-26 15:39:03 +01:00
const char *path_dir_playlist = settings->paths.directory_playlist;
2020-02-19 22:06:21 +01:00
if (!string_is_empty(path_dir_playlist))
{
2024-09-09 22:18:23 +02:00
playlist_config_t playlist_config;
2020-06-26 15:39:03 +01:00
char playlist_path[PATH_MAX_LENGTH];
2024-09-09 22:18:23 +02:00
const char *path_dir_thumbnails = settings->paths.directory_thumbnails;
playlist_config.capacity = COLLECTION_SIZE;
playlist_config.old_format = settings->bools.playlist_use_old_format;
playlist_config.compress = settings->bools.playlist_compression;
playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
fill_pathname_join_special(
2020-06-26 15:39:03 +01:00
playlist_path, path_dir_playlist, label,
2020-02-19 22:06:21 +01:00
sizeof(playlist_path));
2020-06-26 15:39:03 +01:00
playlist_config_set_path(&playlist_config, playlist_path);
2020-06-26 15:39:03 +01:00
task_push_pl_thumbnail_download(path, &playlist_config,
2020-02-19 22:06:21 +01:00
path_dir_thumbnails);
2020-06-26 15:39:03 +01:00
2020-02-19 22:06:21 +01:00
return 0;
}
}
return -1;
}
static int action_ok_pl_entry_content_thumbnails(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
playlist_t *playlist = playlist_get_cached();
menu_handle_t *menu = menu_st->driver_data;
if (!playlist || !menu)
return -1;
task_push_pl_entry_thumbnail_download(
menu_st->thumbnail_path_data->system,
playlist, menu->rpl_entry_selection_ptr,
true, false);
return 0;
}
#endif
static int action_ok_playlist_reset_cores(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_t *playlist = playlist_get_cached();
playlist_config_t *playlist_config = NULL;
if (!playlist)
return -1;
2020-06-26 15:39:03 +01:00
playlist_config = playlist_get_config(playlist);
2020-06-26 15:39:03 +01:00
if (!playlist_config || string_is_empty(playlist_config->path))
return -1;
2020-06-26 15:39:03 +01:00
task_push_pl_manager_reset_cores(playlist_config);
return 0;
}
static int action_ok_playlist_clean(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2020-06-26 15:39:03 +01:00
playlist_t *playlist = playlist_get_cached();
playlist_config_t *playlist_config = NULL;
if (!playlist)
return -1;
2020-06-26 15:39:03 +01:00
playlist_config = playlist_get_config(playlist);
2020-06-26 15:39:03 +01:00
if (!playlist_config || string_is_empty(playlist_config->path))
return -1;
2020-06-26 15:39:03 +01:00
task_push_pl_manager_clean_playlist(playlist_config);
return 0;
}
static int action_ok_playlist_refresh(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
2024-09-09 22:18:23 +02:00
enum manual_content_scan_playlist_refresh_status stat;
playlist_config_t *playlist_config = NULL;
playlist_t *playlist = playlist_get_cached();
settings_t *settings = config_get_ptr();
if (!playlist || !settings)
return -1;
playlist_config = playlist_get_config(playlist);
if (!playlist_config || string_is_empty(playlist_config->path))
return -1;
2024-09-09 22:18:23 +02:00
stat = manual_content_scan_set_menu_from_playlist(playlist,
settings->paths.path_content_database,
2024-09-09 22:18:23 +02:00
settings->bools.show_hidden_files);
if (stat != MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_OK)
{
size_t _len;
2024-09-09 22:18:23 +02:00
char msg[128];
char system_name[256];
const char *msg_prefix = NULL;
const char *msg_subject = NULL;
const char *log_text = NULL;
2024-09-09 22:18:23 +02:00
switch (stat)
{
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_INVALID_CONTENT_DIR:
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_INVALID_CONTENT_DIR);
msg_subject = playlist_get_scan_content_dir(playlist);
log_text = "[Playlist Refresh]: Invalid content directory: %s\n";
break;
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_INVALID_SYSTEM_NAME:
{
2024-09-09 22:18:23 +02:00
const char *playlist_file = NULL;
if ((playlist_file = path_basename(playlist_config->path)))
fill_pathname(system_name, playlist_file, "",
sizeof(system_name));
2024-09-09 22:18:23 +02:00
else
system_name[0] = '\0';
2024-09-09 22:18:23 +02:00
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_INVALID_SYSTEM_NAME);
msg_subject = system_name;
log_text = "[Playlist Refresh]: Invalid system name: %s\n";
}
break;
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_INVALID_CORE:
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_INVALID_CORE);
msg_subject = playlist_get_default_core_name(playlist);
log_text = "[Playlist Refresh]: Invalid core name: %s\n";
break;
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_INVALID_DAT_FILE:
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_INVALID_DAT_FILE);
msg_subject = playlist_get_scan_dat_file_path(playlist);
log_text = "[Playlist Refresh]: Invalid arcade dat file: %s\n";
break;
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_DAT_FILE_TOO_LARGE:
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_DAT_FILE_TOO_LARGE);
msg_subject = playlist_get_scan_dat_file_path(playlist);
log_text = "[Playlist Refresh]: Arcade dat file too large: %s\n";
break;
case MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_MISSING_CONFIG:
default:
msg_prefix = msg_hash_to_str(MSG_PLAYLIST_MANAGER_REFRESH_MISSING_CONFIG);
msg_subject = path_basename(playlist_config->path);
log_text = "[Playlist Refresh]: No scan record found: %s\n";
break;
}
/* Log errors in the event of an invalid
* scan record */
if (string_is_empty(msg_subject))
msg_subject = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
_len = fill_pathname_join_special(msg, msg_prefix, msg_subject, sizeof(msg));
RARCH_ERR(log_text, msg_subject);
runloop_msg_queue_push(msg, _len, 1, 150, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
/* Even though this is a failure condition, we
2024-09-09 22:18:23 +02:00
* let it fall-through to 0 here to suppress
* any refreshing of the menu (this can appear
* ugly, depending on the active menu driver...) */
}
else
{
/* Perform manual scan
* > Since we are refreshing the playlist,
* additionally ensure that all pertinent
* 'playlist_config' parameters are synchronised
* with the current settings struct */
playlist_config->capacity = COLLECTION_SIZE;
playlist_config->old_format = settings->bools.playlist_use_old_format;
playlist_config->compress = settings->bools.playlist_compression;
playlist_config->fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
playlist_config_set_base_content_directory(playlist_config,
settings->bools.playlist_portable_paths ?
settings->paths.directory_menu_content : NULL);
task_push_manual_content_scan(playlist_config,
settings->paths.directory_playlist);
}
return 0;
}
#ifdef HAVE_MIST
static int action_ok_core_steam_install(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
steam_core_dlc_list_t *core_dlc_list = NULL;
steam_core_dlc_t *core_dlc = NULL;
if (MIST_IS_ERROR(steam_get_core_dlcs(&core_dlc_list, true))) return 0;
core_dlc = steam_get_core_dlc_by_name(core_dlc_list, label);
if (core_dlc == NULL) return 0;
steam_install_core_dlc(core_dlc);
return 0;
}
static int action_ok_core_steam_uninstall(
const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
steam_core_dlc_list_t *core_dlc_list = NULL;
steam_core_dlc_t *core_dlc = NULL;
if (MIST_IS_ERROR(steam_get_core_dlcs(&core_dlc_list, true))) return 0;
core_dlc = steam_get_core_dlc_by_name(core_dlc_list, label);
if (core_dlc == NULL) return 0;
steam_uninstall_core_dlc(core_dlc);
return 0;
}
#endif
2016-07-01 19:01:25 +02:00
static int is_rdb_entry(enum msg_hash_enums enum_idx)
{
2016-07-01 19:01:25 +02:00
switch (enum_idx)
{
2016-07-01 19:01:25 +02:00
case MENU_ENUM_LABEL_RDB_ENTRY_PUBLISHER:
case MENU_ENUM_LABEL_RDB_ENTRY_DEVELOPER:
case MENU_ENUM_LABEL_RDB_ENTRY_ORIGIN:
case MENU_ENUM_LABEL_RDB_ENTRY_FRANCHISE:
case MENU_ENUM_LABEL_RDB_ENTRY_ENHANCEMENT_HW:
case MENU_ENUM_LABEL_RDB_ENTRY_ESRB_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_BBFC_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_ELSPA_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_PEGI_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_CERO_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_EDGE_MAGAZINE_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_EDGE_MAGAZINE_ISSUE:
case MENU_ENUM_LABEL_RDB_ENTRY_FAMITSU_MAGAZINE_RATING:
case MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_MONTH:
case MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_YEAR:
case MENU_ENUM_LABEL_RDB_ENTRY_MAX_USERS:
break;
default:
return -1;
}
return 0;
}
static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs,
2020-03-27 18:35:10 +01:00
const char *label)
{
2016-07-01 20:18:51 +02:00
if (cbs->enum_idx != MSG_UNKNOWN)
{
2017-08-13 00:39:11 +02:00
const char *str = msg_hash_to_str(cbs->enum_idx);
2016-07-01 20:18:51 +02:00
2019-12-02 06:10:32 +01:00
if (str)
2016-07-01 20:18:51 +02:00
{
2019-12-02 06:10:32 +01:00
if (is_rdb_entry(cbs->enum_idx) == 0)
{
BIND_ACTION_OK(cbs, action_ok_rdb_entry_submenu);
return 0;
}
2016-12-14 16:33:54 +01:00
2020-06-25 14:38:06 +02:00
if (string_ends_with_size(str, "input_binds_list",
strlen(str),
STRLEN_CONST("input_binds_list")))
2017-08-13 00:39:11 +02:00
{
2019-12-02 06:10:32 +01:00
unsigned i;
unsigned first_char = atoi(&str[0]);
2016-12-14 16:33:54 +01:00
2019-12-02 06:10:32 +01:00
for (i = 0; i < MAX_USERS; i++)
{
if (first_char != ((i+1)))
continue;
BIND_ACTION_OK(cbs, action_ok_push_user_binds_list);
return 0;
}
2017-08-13 00:39:11 +02:00
}
2016-07-01 20:18:51 +02:00
}
}
if (menu_setting_get_browser_selection_type(cbs->setting) == ST_DIR)
2015-06-07 18:14:48 +02:00
{
BIND_ACTION_OK(cbs, action_ok_push_filebrowser_list_dir_select);
2015-06-07 18:14:48 +02:00
return 0;
}
if (cbs->enum_idx != MSG_UNKNOWN)
{
2020-03-26 16:44:16 +01:00
unsigned i;
typedef struct temp_ok_list
{
2020-03-26 16:44:16 +01:00
enum msg_hash_enums type;
int (*cb)(const char *path, const char *label, unsigned type,
size_t idx, size_t entry_idx);
} temp_ok_list_t;
temp_ok_list_t ok_list[] = {
{MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING, action_ok_start_recording},
{MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING, action_ok_start_streaming},
{MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING, action_ok_stop_recording},
{MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING, action_ok_stop_streaming},
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CHEAT_START_OR_CONT, action_ok_cheat_start_or_cont},
{MENU_ENUM_LABEL_CHEAT_ADD_NEW_TOP, action_ok_cheat_add_top},
{MENU_ENUM_LABEL_CHEAT_RELOAD_CHEATS, action_ok_cheat_reload_cheats},
{MENU_ENUM_LABEL_CHEAT_ADD_NEW_BOTTOM, action_ok_cheat_add_bottom},
{MENU_ENUM_LABEL_CHEAT_DELETE_ALL, action_ok_cheat_delete_all},
{MENU_ENUM_LABEL_CHEAT_ADD_NEW_AFTER, action_ok_cheat_add_new_after},
{MENU_ENUM_LABEL_CHEAT_ADD_NEW_BEFORE, action_ok_cheat_add_new_before},
{MENU_ENUM_LABEL_CHEAT_COPY_AFTER, action_ok_cheat_copy_after},
{MENU_ENUM_LABEL_CHEAT_COPY_BEFORE, action_ok_cheat_copy_before},
{MENU_ENUM_LABEL_CHEAT_DELETE, action_ok_cheat_delete},
2020-06-30 19:35:41 +02:00
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_RUN_MUSIC, action_ok_audio_run},
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION, action_ok_audio_add_to_mixer_and_collection},
{MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY,action_ok_audio_add_to_mixer_and_collection_and_play},
{MENU_ENUM_LABEL_ADD_TO_MIXER, action_ok_audio_add_to_mixer},
{MENU_ENUM_LABEL_ADD_TO_MIXER_AND_PLAY, action_ok_audio_add_to_mixer_and_play},
2015-09-04 20:11:46 +02:00
#endif
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_VIDEO_SHADER_PASS, action_ok_shader_pass},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET, action_ok_shader_preset},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PREPEND, action_ok_shader_preset_prepend},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_APPEND, action_ok_shader_preset_append},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_VIDEO_SHADER_PARAMETERS, action_ok_shader_parameters},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PARAMETERS, action_ok_shader_parameters},
{MENU_ENUM_LABEL_SHADER_APPLY_CHANGES, action_ok_shader_apply_changes},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE, action_ok_shader_preset_remove},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE, action_ok_shader_preset_save},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS, action_ok_shader_preset_save_as},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GLOBAL, action_ok_shader_preset_save_global},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE, action_ok_shader_preset_save_core},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT, action_ok_shader_preset_save_parent},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GAME, action_ok_shader_preset_save_game},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GLOBAL, action_ok_shader_preset_remove_global},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_CORE, action_ok_shader_preset_remove_core},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_PARENT, action_ok_shader_preset_remove_parent},
{MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GAME, action_ok_shader_preset_remove_game},
#ifdef HAVE_NETWORKING
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS, action_ok_update_shaders_glsl},
{MENU_ENUM_LABEL_UPDATE_CG_SHADERS, action_ok_update_shaders_cg},
{MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS, action_ok_update_shaders_slang},
#endif
#endif
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS, action_ok_push_audio_mixer_settings_list},
2018-10-06 14:52:44 +02:00
#endif
2017-01-22 21:27:36 +01:00
#ifdef HAVE_NETWORKING
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT, action_ok_core_content_list},
{MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS, action_ok_core_content_dirs_list},
{MENU_ENUM_LABEL_DOWNLOAD_CORE_SYSTEM_FILES, action_ok_core_system_files_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CORE_UPDATER_LIST, action_ok_core_updater_list},
{MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES, action_ok_update_installed_cores},
#if defined(ANDROID)
{MENU_ENUM_LABEL_SWITCH_INSTALLED_CORES_PFD, action_ok_switch_installed_cores_pfd},
#endif
#if 0
/* Thumbnailpack removal */
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST, action_ok_thumbnails_updater_list},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST, action_ok_pl_thumbnails_updater_list},
{MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, action_ok_pl_entry_content_thumbnails},
{MENU_ENUM_LABEL_UPDATE_LAKKA, action_ok_lakka_list},
{MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS, action_ok_push_netplay_refresh_rooms},
Netplay Stuff (#13375) * Netplay Stuff ## PROTOCOL FALLBACK In order to support older clients a protocol fallback system was introduced. The host will no longer send its header automatically after a TCP connection is established, instead, it awaits for the client to send his before determining which protocol this connection is going to operate on. Netplay has now two protocols, a low protocol and a high protocol; the low protocol is the minimum protocol it supports, while the high protocol is the highest protocol it can operate on. To fully support older clients, a hack was necessary: sending the high protocol in the unused client's header salt field, while keeping the protocol field to the low protocol. Without this hack we would only be able to support older clients if a newer client was the host. Any future system can make use of this system by checking connection->netplay_protocol, which is available for both the client and host. ## NETPLAY CHAT Starting with protocol 6, netplay chat is available through the new NETPLAY_CMD_PLAYER_CHAT command. Limitations of the command code, which causes a disconnection on unknown commands, makes this system not possible on protocol 5. Protocol 5 connections can neither send nor receive chat, but other netplay operations are unaffected. Clients send chat as a string to the server, and it's the server's sole responsability to relay chat messages. As of now, sending chat uses RetroArch's input menu, while the display of on-screen chat uses a widget overlay and RetroArch's notifications as a fallback. If a new overlay and/or input system is desired, no backwards compatibility changes need to be made. Only clients in playing mode (as opposed to spectating mode) can send and receive chat. ## SETTINGS SHARING Some settings are better used when both host and clients share the same configuration. As of protocol 6, the following settings will be shared from host to clients (without altering a client's configuration file): input latency frames and allow pausing. ## NETPLAY TUNNEL/MITM With the current MITM system being defunct (at least as of 1.9.X), a new system was in order to solve most if not all of the problems with the current system. This new system uses a tunneling approach, which is similar to most VPN and tunneling services around. Tunnel commands: RATS[unique id] (RetroArch Tunnel Session) - 16 bytes -> When this command is sent with a zeroed unique id, the tunnel server interprets this as a netplay host wanting to create a new session, in this case, the same command is returned to the host, but now with its unique session id. When a client needs to connect to a host, this command is sent with the unique session id of the host, causing the tunnel server to send a RATL command to the host. RATL[unique id] (RetroArch Tunnel Link) - 16 bytes -> The tunnel server sends this command to the host when a client wants to connect to the host. Once the host receives this command, it establishes a new connection to the tunnel server, sending this command together with the client's unique id through this new connection, causing the tunnel server to link this connection to the connection of the client. RATP (RetroArch Tunnel Ping) - 4 bytes -> The tunnel server sends this command to verify that the host, whom the session belongs to, is still around. The host replies with the same command. A session is closed if the tunnel server can not verify that the host is alive. Operations: Host -> Instead of listening and accepting connections, it connects to the tunnel server, requests a new session and then monitor this connection for new linking requests. Once a request is received, it establishes a new connection to the tunnel server for linking with a client. The tunnel server's address and port are obtained by querying the lobby server. The host will publish its session id together with the rest of its info to the lobby server. Client -> It connects to the tunnel server and then sends the session id of the host it wants to connect to. A host's session id is obtained from the json data sent by the lobby server. Improvements (from current MITM system): No longer a risk of TCP port exhaustion; we only use one port now at the tunnel server. Very little cpu usage. About 95% net I/O bound now. Future backwards compatible with any and all changes to netplay as it no longer runs any netplay logic at MITM servers. No longer operates the host in client mode, which was a source of many of the current problems. Cleaner and more maintainable system and code. Notable functions: netplay_mitm_query -> Grabs the tunnel's address and port from the lobby server. init_tcp_socket -> Handles the creation and operation mode of the TCP socket based on whether it's host, host+MITM or client. handle_mitm_connection -> Creates and completes linking connections and replies to ping commands (only 1 of each per call to not affect performance). ## MISC Ping Limiter: If a client's estimated latency to the server is higher than this value, connection will be dropped just before finishing the netplay handshake. Ping Counter: A ping counter (similar to the FPS one) can be shown in the bottom right corner of the screen, if you are connected to a host. LAN Discovery: Refactored and moved to its own "Refresh Netplay LAN List" button. ## FIXES Many minor fixes to the current netplay implementation are also included. * Remove NETPLAY_TEST_BUILD
2021-12-19 12:58:01 -03:00
#ifdef HAVE_NETPLAYDISCOVERY
{MENU_ENUM_LABEL_NETPLAY_REFRESH_LAN, action_ok_push_netplay_refresh_lan},
#endif
2019-08-24 01:44:50 +02:00
#endif
#if defined(HAVE_LIBNX)
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_SWITCH_CPU_PROFILE, action_ok_push_default},
#endif
{MENU_ENUM_LABEL_MENU_WALLPAPER, action_ok_menu_wallpaper},
{MENU_ENUM_LABEL_VIDEO_FONT_PATH, action_ok_video_font},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_GOTO_FAVORITES, action_ok_goto_favorites},
{MENU_ENUM_LABEL_GOTO_MUSIC, action_ok_goto_music},
{MENU_ENUM_LABEL_GOTO_IMAGES, action_ok_goto_images},
{MENU_ENUM_LABEL_GOTO_VIDEO, action_ok_goto_video},
{MENU_ENUM_LABEL_GOTO_EXPLORE, action_ok_goto_explore},
2022-02-22 18:23:48 +00:00
{MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES, action_ok_goto_contentless_cores},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_BROWSE_START, action_ok_browse_url_start},
{MENU_ENUM_LABEL_FILE_BROWSER_CORE, action_ok_load_core},
{MENU_ENUM_LABEL_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION,action_ok_core_deferred_set},
2023-08-16 03:22:02 +02:00
{MENU_ENUM_LABEL_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION_CURRENT_CORE,action_ok_core_deferred_set},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_START_CORE, action_ok_start_core},
{MENU_ENUM_LABEL_START_NET_RETROPAD, action_ok_start_net_retropad_core},
{MENU_ENUM_LABEL_START_VIDEO_PROCESSOR, action_ok_start_video_processor_core},
{MENU_ENUM_LABEL_OPEN_ARCHIVE_DETECT_CORE, action_ok_open_archive_detect_core},
{MENU_ENUM_LABEL_OPEN_ARCHIVE, action_ok_open_archive},
{MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE, action_ok_load_archive_detect_core},
{MENU_ENUM_LABEL_LOAD_ARCHIVE, action_ok_load_archive},
2023-08-16 03:22:02 +02:00
{MENU_ENUM_LABEL_CUSTOM_BIND_ALL, action_ok_lookup_setting},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_SAVE_STATE, action_ok_save_state},
{MENU_ENUM_LABEL_LOAD_STATE, action_ok_load_state},
{MENU_ENUM_LABEL_UNDO_LOAD_STATE, action_ok_undo_load_state},
{MENU_ENUM_LABEL_UNDO_SAVE_STATE, action_ok_undo_save_state},
{MENU_ENUM_LABEL_RECORD_REPLAY, action_ok_record_replay},
{MENU_ENUM_LABEL_PLAY_REPLAY, action_ok_play_replay},
{MENU_ENUM_LABEL_HALT_REPLAY, action_ok_halt_replay},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_RESUME_CONTENT, action_ok_resume_content},
{MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST, action_ok_add_to_favorites_playlist},
{MENU_ENUM_LABEL_ADD_ENTRY_TO_PLAYLIST, action_ok_add_entry_to_playlist},
{MENU_ENUM_LABEL_CREATE_NEW_PLAYLIST, action_ok_add_entry_to_new_playlist},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_SET_CORE_ASSOCIATION, action_ok_set_core_association},
{MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION, action_ok_reset_core_association},
{MENU_ENUM_LABEL_ADD_TO_FAVORITES, action_ok_add_to_favorites},
{MENU_ENUM_LABEL_ADD_TO_PLAYLIST, action_ok_push_add_to_playlist_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_RESTART_CONTENT, action_ok_restart_content},
{MENU_ENUM_LABEL_TAKE_SCREENSHOT, action_ok_screenshot},
{MENU_ENUM_LABEL_RENAME_ENTRY, action_ok_rename_entry},
{MENU_ENUM_LABEL_DELETE_ENTRY, action_ok_delete_entry},
{MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE, action_ok_disable_kiosk_mode},
{MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, action_ok_enable_settings},
{MENU_ENUM_LABEL_SHOW_WIMP, action_ok_show_wimp},
{MENU_ENUM_LABEL_QUIT_RETROARCH, action_ok_quit},
{MENU_ENUM_LABEL_CLOSE_CONTENT, action_ok_close_content},
{MENU_ENUM_LABEL_SAVE_NEW_CONFIG, action_ok_save_new_config},
{MENU_ENUM_LABEL_HELP, action_ok_help},
{MENU_ENUM_LABEL_HELP_CONTROLS, action_ok_help_controls},
{MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE, action_ok_help_what_is_a_core},
{MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD, action_ok_help_change_virtual_gamepad},
{MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING, action_ok_help_audio_video_troubleshooting},
{MENU_ENUM_LABEL_HELP_SCANNING_CONTENT, action_ok_help_scanning_content},
{MENU_ENUM_LABEL_HELP_LOADING_CONTENT, action_ok_help_load_content},
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CHEAT_FILE_LOAD, action_ok_cheat_file},
{MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND, action_ok_cheat_file_append},
#ifdef HAVE_NETWORKING
2020-06-30 19:35:41 +02:00
{MENU_ENUM_LABEL_UPDATE_CHEATS, action_ok_update_cheats},
#endif
2020-06-30 19:35:41 +02:00
{MENU_ENUM_LABEL_CHEAT_ADD_MATCHES, cheat_manager_add_matches},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN, action_ok_audio_dsp_plugin},
{MENU_ENUM_LABEL_VIDEO_FILTER, action_ok_video_filter},
{MENU_ENUM_LABEL_OVERLAY_PRESET, action_ok_overlay_preset},
{MENU_ENUM_LABEL_OSK_OVERLAY_PRESET, action_ok_osk_overlay_preset},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_RECORD_CONFIG, action_ok_record_configfile},
{MENU_ENUM_LABEL_STREAM_CONFIG, action_ok_stream_configfile},
#ifdef HAVE_RGUI
{MENU_ENUM_LABEL_RGUI_MENU_THEME_PRESET, action_ok_rgui_menu_theme_preset},
#endif
{MENU_ENUM_LABEL_ACCOUNTS_LIST, action_ok_push_accounts_list},
{MENU_ENUM_LABEL_ACCESSIBILITY_SETTINGS, action_ok_push_accessibility_settings_list},
{MENU_ENUM_LABEL_AI_SERVICE_SETTINGS, action_ok_push_ai_service_settings_list},
{MENU_ENUM_LABEL_INPUT_SETTINGS, action_ok_push_input_settings_list},
{MENU_ENUM_LABEL_INPUT_MENU_SETTINGS, action_ok_push_input_menu_settings_list},
2021-03-25 18:45:31 +02:00
{MENU_ENUM_LABEL_INPUT_TURBO_FIRE_SETTINGS, action_ok_push_input_turbo_fire_settings_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_INPUT_HAPTIC_FEEDBACK_SETTINGS, action_ok_push_input_haptic_feedback_settings_list},
{MENU_ENUM_LABEL_DRIVER_SETTINGS, action_ok_push_driver_settings_list},
{MENU_ENUM_LABEL_VIDEO_SETTINGS, action_ok_push_video_settings_list},
{MENU_ENUM_LABEL_VIDEO_SYNCHRONIZATION_SETTINGS, action_ok_push_video_synchronization_settings_list},
{MENU_ENUM_LABEL_VIDEO_FULLSCREEN_MODE_SETTINGS, action_ok_push_video_fullscreen_mode_settings_list},
{MENU_ENUM_LABEL_VIDEO_WINDOWED_MODE_SETTINGS, action_ok_push_video_windowed_mode_settings_list},
{MENU_ENUM_LABEL_VIDEO_SCALING_SETTINGS, action_ok_push_video_scaling_settings_list},
Add HDR support for D3D12 (rebased PR from MajorPainTheCactus) (#12917) * Add HDR support * Attempt to fix Mingw build and Metal builds * (D3D12) Fix relative header includes * Add missing hdr_sm5.hlsl.h * (d3d12_common.c) Some C89 build fixes * Fix MSVC build * - Attempt to fix build on mingw/msys unix with dirty hack - Fix shader compilation of hdr_sm5.hlsl.h on MSVC/Visual Studio - the define was seen as an error and was causing the first pipeline to error out - Make sure we manually set handle of backBuffer to NULL * Moving the release of the texture above the freeing of desc.srv_heap and desc.rtv_heap solves the hard crashes on teardown/setup in RA - it was crashing hard in d3d12_release_texture before * Add HAVE_D3D12_HDR ifdef - needs to be disabled for WinRT for now because of several things that are Windows desktop-specific right now (GetWindowRect) * Add dirty GUID hack - should work for both mingw/msys on Windows/Linux as well as MSVC/Visual Studio (hopefully) * Change HAVE_D3D12_HDR to HAVE_DXGI_HDR * Move away from camelcase named variables * Fix RARCH_ERR logs - they need a newline at the end * d3d12_check_display_hdr_support - make it return a bool on return and set d3d12->hdr.support and d3d12->hdr.enable outside of the function * (DXGI) Remove D3D12 dependencies from dxgi_check_display_hdr_support and move it to dxgi_common.c instead * (DXGI) move d3d12_swapchain_color_space over to dxgi_common.c and rename it dxgi_swapchain_color_space * (DXGI) move d3d12_set_hdr_metadata to dxgi_common.c and rename it dxgi_set_hdr_metadata * (DXGI) dxgi_check_display_hdr_support - better error handling? * Fix typo * Remove video_force_resolution * (D3D12) Address TODO/FIXME * (D3D12) Backport https://github.com/libretro/RetroArch/pull/12916/commits/c1b6c0bff2aa33cde035b43cb31ac7e78ff2a07a - Fixed resource transition for present when HDR is off Fixed cel shader displaying all black as blending was enabled when the hdr shader was being applied - turned off blending during this shader * Move d3d12_hdr_uniform_t to dxgi_common.h and rename it dxgi_hdr_uniform_t * (D3D11) Add HDR support * Add TODO/FIXME notes * Cache hdr_enable in video_frame_info_t * Update comment
2021-09-03 06:15:25 +02:00
{MENU_ENUM_LABEL_VIDEO_HDR_SETTINGS, action_ok_push_video_hdr_settings_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_VIDEO_OUTPUT_SETTINGS, action_ok_push_video_output_settings_list},
{MENU_ENUM_LABEL_CRT_SWITCHRES_SETTINGS, action_ok_push_crt_switchres_settings_list},
{MENU_ENUM_LABEL_AUDIO_SETTINGS, action_ok_push_audio_settings_list},
{MENU_ENUM_LABEL_AUDIO_SYNCHRONIZATION_SETTINGS, action_ok_push_audio_synchronization_settings_list},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DIR, action_ok_push_manual_content_scan_dir_select},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME, action_ok_manual_content_scan_system_name},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME, action_ok_manual_content_scan_core_name},
{MENU_ENUM_LABEL_VIDEO_SHADER_NUM_PASSES, action_ok_video_shader_num_passes_dropdown_box_list},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE, action_ok_manual_content_scan_dat_file},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_START, action_ok_manual_content_scan_start},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, action_ok_playlist_label_display_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE,action_ok_playlist_right_thumbnail_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE,action_ok_playlist_left_thumbnail_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_SORT_MODE, action_ok_playlist_sort_mode},
#ifdef HAVE_NETWORKING
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES, action_ok_update_core_info_files},
{MENU_ENUM_LABEL_UPDATE_OVERLAYS, action_ok_update_overlays},
{MENU_ENUM_LABEL_UPDATE_DATABASES, action_ok_update_databases},
{MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES, action_ok_update_autoconfig_profiles},
{MENU_ENUM_LABEL_UPDATE_ASSETS, action_ok_update_assets},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST, action_ok_netplay_enable_host},
{MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT, action_ok_netplay_enable_client},
{MENU_ENUM_LABEL_NETPLAY_DISCONNECT, action_ok_netplay_disconnect},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CORE_DELETE, action_ok_core_delete},
{MENU_ENUM_LABEL_CORE_CREATE_BACKUP, action_ok_core_create_backup},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_DELETE_PLAYLIST, action_ok_delete_playlist},
{MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU, action_ok_push_default},
{MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE, action_ok_cheevos_toggle_hardcore_mode},
{MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL, action_ok_close_submenu},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_ACHIEVEMENT_RESUME, action_ok_cheevos_toggle_hardcore_mode},
{MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL, action_ok_close_submenu },
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST, action_ok_push_manual_content_scan_list},
{MENU_ENUM_LABEL_AUDIO_OUTPUT_SETTINGS, action_ok_push_audio_output_settings_list},
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
{MENU_ENUM_LABEL_MICROPHONE_SETTINGS, action_ok_push_microphone_settings_list},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_LATENCY_SETTINGS, action_ok_push_latency_settings_list},
{MENU_ENUM_LABEL_CORE_SETTINGS, action_ok_push_core_settings_list},
2020-05-28 17:48:18 +01:00
{MENU_ENUM_LABEL_CORE_INFORMATION, action_ok_push_core_information_list},
2020-06-11 14:12:20 +01:00
{MENU_ENUM_LABEL_CORE_MANAGER_ENTRY, action_ok_push_core_information_list},
#ifdef HAVE_MIST
{MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY, action_ok_push_core_information_steam_list},
#endif
{MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST, action_ok_push_core_restore_backup_list},
{MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST, action_ok_push_core_delete_backup_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CONFIGURATION_SETTINGS, action_ok_push_configuration_settings_list},
{MENU_ENUM_LABEL_PLAYLIST_SETTINGS, action_ok_push_playlist_settings_list},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_LIST, action_ok_push_playlist_manager_list},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS, action_ok_push_playlist_manager_settings},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES, action_ok_playlist_reset_cores},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST, action_ok_playlist_clean},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST, action_ok_playlist_refresh},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_RECORDING_SETTINGS, action_ok_push_recording_settings_list},
{MENU_ENUM_LABEL_INPUT_RETROPAD_BINDS, action_ok_push_input_retropad_binds_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_INPUT_HOTKEY_BINDS, action_ok_push_input_hotkey_binds_list},
{MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, action_ok_push_accounts_cheevos_list},
{MENU_ENUM_LABEL_ACCOUNTS_YOUTUBE, action_ok_push_accounts_youtube_list},
{MENU_ENUM_LABEL_ACCOUNTS_TWITCH, action_ok_push_accounts_twitch_list},
2020-12-19 15:14:14 +03:00
{MENU_ENUM_LABEL_ACCOUNTS_FACEBOOK, action_ok_push_accounts_facebook_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_DUMP_DISC, action_ok_push_dump_disc_list},
#ifdef HAVE_LAKKA
{MENU_ENUM_LABEL_EJECT_DISC, action_ok_push_eject_disc},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_LOAD_DISC, action_ok_push_load_disc_list},
{MENU_ENUM_LABEL_SHADER_OPTIONS, action_ok_push_default},
2022-04-06 01:58:48 +03:00
{MENU_ENUM_LABEL_SAVESTATE_LIST, action_ok_push_savestate_list},
2021-08-06 15:32:51 +01:00
{MENU_ENUM_LABEL_CORE_OPTIONS, action_ok_push_core_options_list},
{MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_LIST, action_ok_push_core_option_override_list},
{MENU_ENUM_LABEL_REMAP_FILE_MANAGER_LIST, action_ok_push_remap_file_manager_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS, action_ok_push_default},
{MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS, action_ok_push_default},
{MENU_ENUM_LABEL_DISC_INFORMATION, action_ok_push_default},
{MENU_ENUM_LABEL_SYSTEM_INFORMATION, action_ok_push_default},
{MENU_ENUM_LABEL_NETWORK_INFORMATION, action_ok_push_default},
{MENU_ENUM_LABEL_ACHIEVEMENT_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_ACHIEVEMENT_LIST_HARDCORE, action_ok_push_default},
{MENU_ENUM_LABEL_DISK_OPTIONS, action_ok_push_default},
{MENU_ENUM_LABEL_SETTINGS, action_ok_push_default},
{MENU_ENUM_LABEL_FRONTEND_COUNTERS, action_ok_push_default},
{MENU_ENUM_LABEL_CORE_COUNTERS, action_ok_push_default},
{MENU_ENUM_LABEL_MANAGEMENT, action_ok_push_default},
{MENU_ENUM_LABEL_ONLINE_UPDATER, action_ok_push_default},
{MENU_ENUM_LABEL_NETPLAY, action_ok_push_default},
{MENU_ENUM_LABEL_LOAD_CONTENT_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_ADD_CONTENT_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_CONFIGURATIONS_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_HELP_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_INFORMATION_LIST, action_ok_push_default},
{MENU_ENUM_LABEL_INFORMATION, action_ok_push_default},
{MENU_ENUM_LABEL_CONTENT_SETTINGS, action_ok_push_default},
{MENU_ENUM_LABEL_LOAD_CONTENT_SPECIAL, action_ok_push_filebrowser_list_file_select},
{MENU_ENUM_LABEL_SCAN_DIRECTORY, action_ok_scan_directory_list},
{MENU_ENUM_LABEL_SCAN_FILE, action_ok_push_scan_file},
{MENU_ENUM_LABEL_FAVORITES, action_ok_push_content_list},
{MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, action_ok_push_random_dir},
{MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, action_ok_push_downloads_dir},
{MENU_ENUM_LABEL_DETECT_CORE_LIST_OK, action_ok_file_load_detect_core},
{MENU_ENUM_LABEL_DETECT_CORE_LIST_OK_CURRENT_CORE, action_ok_file_load_current_core},
{MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, action_ok_push_generic_list},
{MENU_ENUM_LABEL_DATABASE_MANAGER_LIST, action_ok_push_generic_list},
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES, action_ok_cheat_apply_changes},
{MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS, action_ok_cheat_file_save_as},
2020-06-30 19:35:41 +02:00
#endif
{MENU_ENUM_LABEL_REMAP_FILE_LOAD, action_ok_remap_file},
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_AS, action_ok_remap_file_save_as},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE, action_ok_remap_file_save_core},
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR, action_ok_remap_file_save_content_dir},
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, action_ok_remap_file_save_game},
{MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE, action_ok_remap_file_remove_core},
{MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CONTENT_DIR, action_ok_remap_file_remove_content_dir},
{MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME, action_ok_remap_file_remove_game},
{MENU_ENUM_LABEL_REMAP_FILE_RESET, action_ok_remap_file_reset},
{MENU_ENUM_LABEL_REMAP_FILE_FLUSH, action_ok_remap_file_flush},
{MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD, action_ok_override_file},
{MENU_ENUM_LABEL_OVERRIDE_FILE_SAVE_AS, action_ok_override_file_save_as},
{MENU_ENUM_LABEL_OVERRIDE_UNLOAD, action_ok_override_unload},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_PLAYLISTS_TAB, action_ok_content_collection_list},
{MENU_ENUM_LABEL_BROWSE_URL_LIST, action_ok_browse_url_list},
{MENU_ENUM_LABEL_CORE_LIST, action_ok_core_list},
{MENU_ENUM_LABEL_SIDELOAD_CORE_LIST, action_ok_sideload_core_list},
{MENU_ENUM_LABEL_DISK_IMAGE_APPEND, action_ok_disk_image_append_list},
{MENU_ENUM_LABEL_SUBSYSTEM_ADD, action_ok_subsystem_add_list},
{MENU_ENUM_LABEL_SUBSYSTEM_LOAD, action_ok_subsystem_add_load},
{MENU_ENUM_LABEL_CONFIGURATIONS, action_ok_configurations_list},
{MENU_ENUM_LABEL_SAVING_SETTINGS, action_ok_saving_list},
{MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS, action_ok_cloud_sync_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_LOGGING_SETTINGS, action_ok_logging_list},
{MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS, action_ok_frame_throttle_list},
{MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, action_ok_frame_time_counter_list},
{MENU_ENUM_LABEL_REWIND_SETTINGS, action_ok_rewind_list},
{MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS, action_ok_onscreen_display_list},
{MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, action_ok_onscreen_notifications_list},
{MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS,action_ok_onscreen_notifications_views_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS, action_ok_onscreen_overlay_list},
{MENU_ENUM_LABEL_OVERLAY_LIGHTGUN_SETTINGS, action_ok_overlay_lightgun_settings_list},
{MENU_ENUM_LABEL_OVERLAY_MOUSE_SETTINGS, action_ok_overlay_mouse_settings_list},
{MENU_ENUM_LABEL_OSK_OVERLAY_SETTINGS, action_ok_osk_overlay_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_MENU_SETTINGS, action_ok_menu_list},
2022-08-17 08:23:07 +02:00
#ifdef _3DS
{MENU_ENUM_LABEL_MENU_BOTTOM_SETTINGS, action_ok_menu_bottom_list},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_MENU_VIEWS_SETTINGS, action_ok_menu_views_list},
{MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS, action_ok_quick_menu_override_options},
{MENU_ENUM_LABEL_SETTINGS_VIEWS_SETTINGS, action_ok_settings_views_list},
{MENU_ENUM_LABEL_QUICK_MENU_VIEWS_SETTINGS, action_ok_quick_menu_views_list},
{MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS, action_ok_user_interface_list},
{MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS, action_ok_power_management_list},
{MENU_ENUM_LABEL_CPU_PERFPOWER, action_ok_cpu_perfpower_list},
{MENU_ENUM_LABEL_CPU_POLICY_ENTRY, action_ok_cpu_policy_entry},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_MENU_SOUNDS, action_ok_menu_sounds_list},
{MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, action_ok_menu_file_browser_list},
{MENU_ENUM_LABEL_FILE_BROWSER_OPEN_UWP_PERMISSIONS, action_ok_open_uwp_permission_settings},
{MENU_ENUM_LABEL_FILE_BROWSER_OPEN_PICKER, action_ok_open_picker},
{MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS, action_ok_retro_achievements_list},
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_SETTINGS, action_ok_cheevos_appearance_list},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_SETTINGS, action_ok_cheevos_visibility_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_UPDATER_SETTINGS, action_ok_updater_list},
#ifdef HAVE_BLUETOOTH
2020-06-17 14:56:44 +03:00
{MENU_ENUM_LABEL_BLUETOOTH_SETTINGS, action_ok_bluetooth_list},
#endif
2020-12-09 22:03:23 +01:00
#ifdef HAVE_NETWORKING
#ifdef HAVE_WIFI
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_WIFI_SETTINGS, action_ok_wifi_list},
{MENU_ENUM_LABEL_WIFI_NETWORK_SCAN, action_ok_wifi_networks_list},
{MENU_ENUM_LABEL_WIFI_DISCONNECT, action_ok_wifi_disconnect},
#endif
{MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM, action_ok_netplay_connect_room},
2020-12-09 22:03:23 +01:00
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_NETWORK_HOSTING_SETTINGS, action_ok_network_hosting_list},
{MENU_ENUM_LABEL_NETPLAY_KICK, action_ok_netplay_kick_list},
2022-07-07 11:08:46 -03:00
{MENU_ENUM_LABEL_NETPLAY_BAN, action_ok_netplay_ban_list},
{MENU_ENUM_LABEL_NETPLAY_LOBBY_FILTERS, action_ok_netplay_lobby_filters_list},
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_SUBSYSTEM_SETTINGS, action_ok_subsystem_list},
{MENU_ENUM_LABEL_NETWORK_SETTINGS, action_ok_network_list},
{MENU_ENUM_LABEL_LAKKA_SERVICES, action_ok_lakka_services},
#ifdef HAVE_LAKKA_SWITCH
{MENU_ENUM_LABEL_LAKKA_SWITCH_OPTIONS, action_ok_lakka_switch_options},
#endif
2020-03-26 16:44:16 +01:00
{MENU_ENUM_LABEL_NETPLAY_SETTINGS, action_ok_netplay_sublist},
{MENU_ENUM_LABEL_USER_SETTINGS, action_ok_user_list},
{MENU_ENUM_LABEL_DIRECTORY_SETTINGS, action_ok_directory_list},
{MENU_ENUM_LABEL_PRIVACY_SETTINGS, action_ok_privacy_list},
{MENU_ENUM_LABEL_MIDI_SETTINGS, action_ok_midi_list},
{MENU_ENUM_LABEL_SCREEN_RESOLUTION, action_ok_video_resolution},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE, action_ok_playlist_default_core},
2020-06-11 14:12:20 +01:00
{MENU_ENUM_LABEL_CORE_MANAGER_LIST, action_ok_push_core_manager_list},
#ifdef HAVE_MIST
{MENU_ENUM_LABEL_STEAM_SETTINGS, action_ok_steam_settings_list},
{MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, action_ok_push_core_manager_steam_list},
{MENU_ENUM_LABEL_CORE_STEAM_INSTALL, action_ok_core_steam_install},
{MENU_ENUM_LABEL_CORE_STEAM_UNINSTALL, action_ok_core_steam_uninstall},
#endif
{MENU_ENUM_LABEL_EXPLORE_TAB, action_ok_push_default},
2022-02-22 18:23:48 +00:00
{MENU_ENUM_LABEL_CONTENTLESS_CORES_TAB, action_ok_push_default},
2020-03-26 16:44:16 +01:00
};
for (i = 0; i < ARRAY_SIZE(ok_list); i++)
{
if (cbs->enum_idx == ok_list[i].type)
{
BIND_ACTION_OK(cbs, ok_list[i].cb);
return 0;
}
}
}
else
{
2020-03-27 18:35:10 +01:00
unsigned i;
typedef struct temp_ok_list
{
2020-03-27 18:35:10 +01:00
enum msg_hash_enums type;
int (*cb)(const char *path, const char *label, unsigned type,
size_t idx, size_t entry_idx);
} temp_ok_list_t;
temp_ok_list_t ok_list[] = {
{MENU_ENUM_LABEL_OPEN_ARCHIVE_DETECT_CORE, action_ok_open_archive_detect_core},
{MENU_ENUM_LABEL_OPEN_ARCHIVE, action_ok_open_archive},
{MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE, action_ok_load_archive_detect_core},
{MENU_ENUM_LABEL_LOAD_ARCHIVE, action_ok_load_archive},
{MENU_ENUM_LABEL_CHEAT_FILE_LOAD, action_ok_cheat_file},
{MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND, action_ok_cheat_file_append},
{MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN, action_ok_audio_dsp_plugin},
{MENU_ENUM_LABEL_VIDEO_FILTER, action_ok_video_filter},
{MENU_ENUM_LABEL_OVERLAY_PRESET, action_ok_overlay_preset},
{MENU_ENUM_LABEL_OSK_OVERLAY_PRESET, action_ok_osk_overlay_preset},
2020-03-27 18:35:10 +01:00
{MENU_ENUM_LABEL_REMAP_FILE_LOAD, action_ok_remap_file},
{MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD, action_ok_override_file},
2020-03-27 18:35:10 +01:00
{MENU_ENUM_LABEL_RECORD_CONFIG, action_ok_record_configfile},
{MENU_ENUM_LABEL_STREAM_CONFIG, action_ok_stream_configfile},
{MENU_ENUM_LABEL_RGUI_MENU_THEME_PRESET, action_ok_rgui_menu_theme_preset},
{MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, action_ok_push_accounts_cheevos_list},
{MENU_ENUM_LABEL_FAVORITES, action_ok_push_content_list},
{MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, action_ok_push_downloads_dir},
{MENU_ENUM_LABEL_DETECT_CORE_LIST_OK, action_ok_file_load_detect_core},
2020-06-30 19:35:41 +02:00
#ifdef HAVE_CHEATS
2020-03-27 18:35:10 +01:00
{MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES, action_ok_cheat_apply_changes},
{MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS, action_ok_cheat_file_save_as},
2020-06-30 19:35:41 +02:00
#endif
2020-03-27 18:35:10 +01:00
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE, action_ok_remap_file_save_core},
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR, action_ok_remap_file_save_content_dir},
{MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, action_ok_remap_file_save_game},
{MENU_ENUM_LABEL_DISK_IMAGE_APPEND, action_ok_disk_image_append_list},
{MENU_ENUM_LABEL_SUBSYSTEM_ADD, action_ok_subsystem_add_list},
{MENU_ENUM_LABEL_SCREEN_RESOLUTION, action_ok_video_resolution},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE, action_ok_playlist_default_core},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, action_ok_playlist_label_display_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE,action_ok_playlist_right_thumbnail_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE,action_ok_playlist_left_thumbnail_mode},
{MENU_ENUM_LABEL_PLAYLIST_MANAGER_SORT_MODE, action_ok_playlist_sort_mode},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME, action_ok_manual_content_scan_system_name},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME, action_ok_manual_content_scan_core_name},
{MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE, action_ok_manual_content_scan_dat_file},
2020-03-27 18:35:10 +01:00
};
for (i = 0; i < ARRAY_SIZE(ok_list); i++)
{
if (string_is_equal(label, msg_hash_to_str(ok_list[i].type)))
{
BIND_ACTION_OK(cbs, ok_list[i].cb);
return 0;
}
}
}
2020-03-27 18:35:10 +01:00
return -1;
2015-06-05 11:48:25 +02:00
}
static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
2020-03-27 19:05:54 +01:00
const char *label, const char *menu_label, unsigned type)
2015-06-05 11:48:25 +02:00
{
2019-07-03 22:28:12 +02:00
if (type == MENU_SET_CDROM_LIST)
{
BIND_ACTION_OK(cbs, action_ok_dump_cdrom);
}
#ifdef HAVE_LAKKA
else if (type == MENU_SET_EJECT_DISC)
{
BIND_ACTION_OK(cbs, action_ok_eject_disc);
}
#endif
2019-07-11 06:34:27 +02:00
else if (type == MENU_SET_CDROM_INFO)
{
BIND_ACTION_OK(cbs, action_ok_cdrom_info_list);
}
2019-07-05 19:55:04 +02:00
else if (type == MENU_SET_LOAD_CDROM_LIST)
{
BIND_ACTION_OK(cbs, action_ok_load_cdrom);
}
2019-07-03 22:28:12 +02:00
else if (type == MENU_SETTINGS_CUSTOM_BIND_KEYBOARD ||
2015-06-07 17:16:21 +02:00
type == MENU_SETTINGS_CUSTOM_BIND)
{
BIND_ACTION_OK(cbs, action_ok_lookup_setting);
}
2019-07-11 11:51:06 +02:00
#ifdef HAVE_AUDIOMIXER
2018-04-30 15:04:29 +02:00
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_play);
}
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_play_looped);
}
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_play_sequential);
}
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_remove);
}
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_STOP_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_STOP_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_action_stop);
}
else if (type >= MENU_SETTINGS_AUDIO_MIXER_STREAM_BEGIN
&& type <= MENU_SETTINGS_AUDIO_MIXER_STREAM_END)
{
BIND_ACTION_OK(cbs, action_ok_mixer_stream_actions);
}
2019-07-11 11:51:06 +02:00
#endif
else if (type >= MENU_SETTINGS_REMAPPING_PORT_BEGIN
&& type <= MENU_SETTINGS_REMAPPING_PORT_END)
{
BIND_ACTION_OK(cbs, action_ok_remappings_port_list);
}
2015-06-07 17:16:21 +02:00
else if (type >= MENU_SETTINGS_SHADER_PARAMETER_0
&& type <= MENU_SETTINGS_SHADER_PARAMETER_LAST)
{
BIND_ACTION_OK(cbs, action_ok_shader_parameter_dropdown_box_list);
}
2015-06-07 17:16:21 +02:00
else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0
&& type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST)
{
BIND_ACTION_OK(cbs, action_ok_shader_preset_parameter_dropdown_box_list);
}
2015-06-07 17:16:21 +02:00
else if (type >= MENU_SETTINGS_CHEAT_BEGIN
&& type <= MENU_SETTINGS_CHEAT_END)
{
BIND_ACTION_OK(cbs, action_ok_cheat);
}
2023-07-15 15:14:26 +02:00
else if ( (type >= MENU_SETTINGS_CORE_OPTION_START)
&& (type < MENU_SETTINGS_CHEEVOS_START))
2018-09-23 18:36:48 +02:00
{
BIND_ACTION_OK(cbs, action_ok_core_option_dropdown_list);
}
2023-07-15 15:14:26 +02:00
else if ( (type >= MENU_SETTINGS_INPUT_DESC_BEGIN)
&& (type <= MENU_SETTINGS_INPUT_DESC_END))
2020-07-23 17:19:41 +01:00
{
BIND_ACTION_OK(cbs, action_ok_input_description_dropdown_box_list);
}
2023-07-15 15:14:26 +02:00
else if ( (type >= MENU_SETTINGS_INPUT_DESC_KBD_BEGIN)
&& (type <= MENU_SETTINGS_INPUT_DESC_KBD_END))
2020-07-23 17:19:41 +01:00
{
BIND_ACTION_OK(cbs, action_ok_input_description_kbd_dropdown_box_list);
}
2015-06-07 17:16:21 +02:00
else
{
2015-06-07 17:16:21 +02:00
switch (type)
{
2018-09-23 18:36:48 +02:00
case MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_setting_core_options_item);
break;
2019-12-02 21:08:21 +01:00
case MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM_SPECIAL:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_setting_core_options_item_special);
2018-09-23 17:13:45 +02:00
break;
2019-12-02 21:08:21 +01:00
case MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM:
case MENU_SETTING_DROPDOWN_SETTING_INT_ITEM:
case MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM:
case MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM:
case MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM_SPECIAL:
case MENU_SETTING_DROPDOWN_SETTING_INT_ITEM_SPECIAL:
case MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM_SPECIAL:
BIND_ACTION_OK(cbs, generic_action_ok_dropdown_setting);
break;
case MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM_SPECIAL:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_setting_uint_item_special);
break;
case MENU_SETTING_DROPDOWN_ITEM:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item);
break;
case MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_PARAM:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_video_shader_param);
break;
case MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_PRESET_PARAM:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_video_shader_preset_param);
break;
case MENU_SETTING_DROPDOWN_ITEM_RESOLUTION:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_resolution);
break;
case MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_NUM_PASS:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_video_shader_num_pass);
break;
case MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_DEFAULT_CORE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_playlist_default_core);
break;
case MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_LABEL_DISPLAY_MODE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_playlist_label_display_mode);
break;
case MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_RIGHT_THUMBNAIL_MODE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_playlist_right_thumbnail_mode);
break;
case MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_LEFT_THUMBNAIL_MODE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_playlist_left_thumbnail_mode);
break;
case MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_SORT_MODE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_playlist_sort_mode);
break;
2019-11-29 17:13:35 +00:00
case MENU_SETTING_DROPDOWN_ITEM_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_manual_content_scan_system_name);
break;
case MENU_SETTING_DROPDOWN_ITEM_MANUAL_CONTENT_SCAN_CORE_NAME:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_manual_content_scan_core_name);
break;
2020-01-14 12:28:10 +00:00
case MENU_SETTING_DROPDOWN_ITEM_DISK_INDEX:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_disk_index);
break;
2021-02-04 17:06:19 +02:00
case MENU_SETTING_DROPDOWN_ITEM_INPUT_DEVICE_TYPE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_device_type);
break;
case MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_RESERVED_DEVICE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_select_reserved_device);
break;
#ifdef ANDROID
case MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_PHYSICAL_KEYBOARD:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_select_physical_keyboard);
break;
#endif
2020-07-23 17:19:41 +01:00
case MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_description);
break;
case MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION_KBD:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_description_kbd);
break;
case MENU_SETTING_DROPDOWN_ITEM_AUDIO_DEVICE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_audio_device);
break;
Add microphone support via a new driver (#14731) * Some slight fixes * Update libretro.h * Log calls to RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE * Finish proof-of-concept for mic support - It works, but doesn't support floating-point audio yet - It may need to be resampled, too * Add macros that aren't available in SDL 2 * Comment out a variable definition for now - For C89 compliance * Add some comments for clarity * Let ALSA tolerate a null new_rate * Partial ALSA microphone support - Not yet tested - Mic is created and destroyed - Mic can also be paused or unpaused - Mic is paused or unpaused with the rest of the driver - Microphone is not yet read * Install error logging in the ALSA driver - It defers to RARCH_ERR * Free the ALSA microphone in alsa_free * Fix an indent * First draft of alsa_read_microphone * Deinitialize SDL Audio in sdl_audio_free * Save and restore the ALSA error logger - You should always practice safe global state * Add newlines to some RARCH_ERRs * Add some logging * Check for the mic being active via settings instead of via flags * Adjusted a log entry to be less misleading - A frequency of 0Hz looks weird to the uninformed - In reality, it means the driver used the requested frequency * Fix an incorrect format string * Tidy up logging in alsa.c * Rename audio_enable_microphone to audio_enable_input * Rename microphone_device to audio_input_device * Add audio_input_latency and audio_input_block_frames settings * Add all mic-related settings to the options menu * Adjust logging for alsa.c - Log the ALSA library version - Add errno details * Refer to the microphone in logs by name * Use %u instead of %d for some log items * Add input_samples_buf * Remove an inaccurate comment * Change type of input_samples_buf * Clean up audio_driver_flush_microphone_input * Comment convert_float_to_s16 - It helped me understand what it's doing - Turns out it'll work just fine on mono audio * Don't use the resampler for mic input * Fix crash in the ALSA driver when reading from a mic * Update some logging messages * ALSA support now works for mics * Reuse some common functions in alsa.c * Add alsa_thread_microphone_t * Refactor alsa.c - Introduce alsa_init_pcm to init any PCM that we're using - Vastly simplifies the implementation of alsa_init and alsa_init_microphone - Will be used for the read-based versions next * Make ALSA logging a little more consistent * Clean up the mic with alsa_free_microphone if alsa_init_microphone fails * Remove an unused function * Move some cleanup in alsa.c to a common function * First crack at mic support for alsathread - Refactor some duplicate code into functions - Use functions introduced in alsa.c - Create and destroy the mic * Slight cleanups for clarity * Implement alsa_thread_set/get_microphone_state * More work on alsathread - No more crashing, but the mic just returns silence * Slight cleanups for clarity * Add alsa_set_mic_enabled_internal - For setting the state of a microphone while considering its current state * Use alsa_set_mic_enabled_internal * Log a little more info * Log when the audio driver is started/stopped * Move base microphone driver code into a new directory - Add microphone_driver.c to Makefile.common - Rename functions as needed * Initialize and deinitialize the microphone driver * Implement sdl_microphone.c * Un-const an argument - In case the driver context needs to do any locking * Revise comments for microphone_driver.h * Remove an unimplemented function * Remove some functions from the mic driver * Remove mic functions from audio_thread_wrapper * Remove mic functions from sdl_audio * Fix microphone_null * Split the mic code for the alsa audio drivers into microphone drivers * Fix an extra struct member * Add a setting for the mic driver * Add a command to reinitialize the microphone driver * Rename mic-related settings * Add DRIVER_MICROPHONE_MASK to DRIVERS_CMD_ALL * Rename audio_enable_input to microphone_enable * Remove some labels from qt_options * Search for microphone_driver within find_driver_nonempty * Clean up some mic driver code * Pending mics now return silence * Adjust some logging and comments * Some cleanup in the microphone driver * Invert a flag check - Oops * Fix a log message * Fix the wrong flags being checked * Slight refactor of wasapi_init_device - Add a data_flow parameter - Declare it in a header - In preparation for WASAPI mic support * Add some WASAPI macros for _IAudioCaptureClient * Move some common WASAPI functions to audio/common/wasapi.c - They'll be used by the mic and the audio drivers * Add wasapi_log_hr * Generalize mmdevice_list_new to look for capture devices, too * Fix a function declaration * Move driver-specific device_list_new functions into their respective files * Clean up some declarations * First draft of wasapi microphone driver * Add wasapi_microphone_device_list_free * Change function parameter names to be consistent with microphone_driver * Partially implement wasapi_microphone_read - Mostly copied from the audio driver so far - It doesn't compile yet - But it'll be beautiful when I'm done with it * Refactor the mic driver's functions - Rename get_mic_active to mic_alive - Split set_mic_active into start_mic and stop_mic - Refactor the SDL mic driver accordingly * Edit some WASAPI functions for logging and clarity * Implement more of the WASAPI mic driver * Rename write_event to read_event * Pass the WASAPI driver context to the various read functions * Mostly implement the read function for the WASAPI mic driver * Fix a crash in microphone_driver - Forgot to move the position of the name of null_driver * Reduce some logging in wasapi common functions - Only log the chosen audio client format, not all attempted ones * Add some macro wrappers for IAudioClient methods * Update mic driver configuration - Make the mic driver configurable in the menu - Add config items for WASAPI-related options similar to the audio driver * Fix a menu entry scrolling through audio devices instead of mic devices * Add some utility functions * Expose the new utility functions in wasapi.h * Add extra logging in the WASAPI common functions * Add sharemode_name * Use _IAudioClient_Initialize macro in some places * Pass channels to wasapi_init_client - Remember, mics are in mono * Use _IAudioClient_Initialize macro some more * Forgot to pass channels in some places * Add some utility functions * Forgot an #include * Add wasapi_select_device_format * Simplify the format selection logic in wasapi_init_client_sh * Unset the microphone in wasapi_microphone_close_mic - Ought to prevent a potential segfault * Simplify some logging * Fix incorrect value being passed to _IAudioCaptureClient_ReleaseBuffer * Remove some unneeded logging * Add some values to hresult_name * Polish up wasapi_select_device_format - Test for formats manually when Windows can't - Add some debug logging - Check for channels * Compute the fields of WAVEFORMATEXTENSIBLE correctly - As per the doc's stated requirements * Simplify logic for WASAPI client creation * Fix a potential hang in wasapi_microphone_read_shared_buffered * Stop the microphone if the driver is stopped * Don't name the microphone event * Ensure that wasapi_init_client reports the correct format and rate * Implement exclusive microphone read access for WASAPI * Add _IAudioCaptureClient_GetNextPacketSize macro * Organize cases in hresult_name * Clear some extra fields if wasapi_set_format is setting a Pcm format * Adjust some logs * Adjust some logs * Remove unneeded local vars * Add a log * Update wasapi.c * Update wasapi.c * Fix shared-mode mic support in WASAPI producing broken input - Turns out it had nothing to do with shared mode * Reuse a common function - Remove wasapi_microphone_read_shared_buffered - Rename wasapi_microphone_read_exclusive to wasapi_microphone_read_buffered * Remove some code I was using for test purposes * Clarify some language * Double the default shared-mode mic buffer length * Split getting a device's name into a separate function, then use it * Fix the ALSA mic drivers - To comply with changes I previously made to the mic driver interface * Remove unused synchronization primitives from the SDL microphone driver * Add sdl_microphone_mic_use_float * Document audio_driver_state_flags - I needed to understand these to see if similar flags were required for the mic driver * Remove an unused function in wasapi.c * Add and document flags in microphone_driver.h * Remove driver-specific mic start/stop functions - The mic driver itself doesn't do much processing - That honor goes to individual mics * Remove some unused fields in microphone_driver.h * Add CMD_EVENT_MICROPHONE_STOP/START * Remove unused functions from microphone_null * Change how the mic driver state is referenced in some places * Simplify the SDL microphone driver - The driver backend no longer keeps a reference to the mic (the frontend does that) - Remove functions that are no longer needed - Don't track paused state, just query the mic itself * Simplify the WASAPI microphone driver - Don't track the driver running state or the microphone handle, the frontend does that now - Remove support for unbuffered input (hunterk suggested that it wasn't necessary) * Make microphone_wasapi_sh_buffer_length a uint, not an int - It won't be negative anymore - 0 now represents the default value * Make the microphone frontend more robust - Improve documentation for how various functions should be implemented - Closes all microphones before freeing the driver (so backends don't have to) - Tracks the enabled state of each microphone, so backends don't have to (but they still can) * Stop the mic driver in core_unload_game * Ensure mic support is compatible with the revised menu code * Move alsa.h into audio/common * Remove RETRO_ENVIRONMENT_GET_MICROPHONE_ENABLED - It was never really needed * Refactor the ALSA microphone driver - Move common ALSA functions to audio/common/alsa.c - Replace alsa_set_mic_enabled_internal with alsa_start/stop_pcm - Don't track the microphone handle in the ALSA driver context - Remove unneeded fields * Move some common alsathread code into audio/common/alsathread.c * Change return type of mic_driver_open_mic_internal to bool * First crack at resampling mic input * Remove an extraneous check - I think something distracted me when I was writing this line * Add stereo/mono conversion functions * Make alsa_start_pcm and alsa_stop_pcm more robust - They now return success if the stream is already running and stopped, respectively * Revise some mic-related comments in libretro.h * First crack at resampling mic input * Simplify an expression * Simplify an expression * Fix a log tag * Allow mic resampler to be configured separately from audio resampler * Add some comments * Set the source ratio to something sensible * Stop deadlock in `alsathread` mic driver * Allow mics to be initialized even when core is loaded from CLI - When loading content from CLI, the drivers are initialized a little differently - That threw off the mic initialization code * Rename the functions in retro_microphone_interface * Revise some mic-related comments in libretro.h * Update retro_microphone_interface - Add get_mic_rate - Add a parameter to open_mic - The modifications don't do anything yet * Use parameter objects in the microphone handle * Replace get_mic_rate with get_params * Add a microphone interface version * Remove part of a comment * Set the effective params in mic_driver_microphone_handle_init * Drop a stray newline * Change where the mic interface is zeroed - I was accidentally throwing out the version that the core was asking for * Reduce logspam for wasapi_set_nonblock_state - Now it only logs when the sync mode is changed * Change DEFAULT_WASAPI_SH_BUFFER_LENGTH to 0 - -16 is no longer a valid value * Set the new_rate in wasapi_init * Change description of microphone sample rate in the settings * First attempt at resampling configured mic input * Forgot a section * Fix some input samples being skipped * Rename a variable for clarity * Add microphone.outgoing_samples * Update the mic driver - Processed samples are now buffered - The resampler is skipped if the ratio is (very close to) 1 * Remove part of a comment * Update some comments in audio_resampler.h * Slightly refactor the SDL microphone driver - Move SDL_AudioSpec to a field of sdl_microphone_handle_t - Allow SDL to change the requested format and sample rate - Request floating-point input - Implement sdl_microphone_mic_use_float * Fix a non-C89-compliant declaration * Add new files to griffin.c * Remove a C++-style comment * Add two more files to griffin.c * Remove some unneeded declarations in microphone_driver.h * Remove a stray comma in configuration.c - For C89 compliance * Fix compilation on some platforms * Change some function signatures * Make the ALSA drivers always set the audio rate * Fix the alsathread mic driver * Make state_manager_frame_is_reversed return false if HAVE_REWIND isn't defined * Mute the microphone if the core is running in fast-forward, slow-mo, or rewind * Clarify a comment * Clarify a comment * Add a comment * Don't allocate memory for slowmo samples in the mic driver - We're not supporting slowmo for mics, so it's not needed * Fix a { * Add my name to AUTHORS.h * Add driver_lifetime_flags - For drivers that have special setup/teardown needs * Ensure that resetting the mic driver maintains active mic handles - Prevents fullscreen toggle from stopping all mic input * Update CHANGES.md * Move some default microphone settings to a new part of the config file * Ensure that RetroArch can use the audio format that Windows suggests * Remove references to mic support in the SDL audio driver * Remove unused WASAPI functions * Return failure if RetroArch couldn't select a WASAPI format * Ensure that Windows uses the WASAPI mic driver by default * Treat disabled mic support as a warning, not an error * Clarify some WASAPI-related microphone settings * Remove some unused variables * Add or revise microphone-related comments * Rearrange doc comments for microphone types in libretro.h * Remove a space * Remove some unused flags * Remove ALSA error logger - It was never used anyway * Remove unneeded microphone-related arguments * Document a parameter * Remove a logging call * Add a constant for the microphone's shared buffer length for WASAPI * Fix stylistic inconsistencies * Make mic_driver_get_sample_size a macro instead of a function * Move the microphone implementation to the audio directory * Make microphone support optional (but enabled by default) * Fix the griffin build
2023-06-06 15:55:06 -04:00
#ifdef HAVE_MICROPHONE
case MENU_SETTING_DROPDOWN_ITEM_MICROPHONE_DEVICE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_microphone_device);
break;
#endif
#ifdef HAVE_NETWORKING
case MENU_SETTING_DROPDOWN_ITEM_NETPLAY_MITM_SERVER:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_netplay_mitm_server);
break;
#endif
2015-06-25 09:15:34 +02:00
case MENU_SETTING_ACTION_CORE_DISK_OPTIONS:
BIND_ACTION_OK(cbs, action_ok_push_default);
2015-06-25 09:15:34 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_PLAYLIST_ENTRY:
BIND_ACTION_OK(cbs, action_ok_playlist_entry_collection);
2015-06-07 17:16:21 +02:00
break;
#if defined(HAVE_LIBNX)
2018-10-06 14:52:44 +02:00
case MENU_SET_SWITCH_CPU_PROFILE:
BIND_ACTION_OK(cbs, action_ok_set_switch_cpu_profile);
break;
#endif
2016-06-20 15:50:37 +02:00
case FILE_TYPE_RPL_ENTRY:
BIND_ACTION_OK(cbs, action_ok_rpl_entry);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_PLAYLIST_COLLECTION:
BIND_ACTION_OK(cbs, action_ok_playlist_collection);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_CONTENTLIST_ENTRY:
BIND_ACTION_OK(cbs, action_ok_push_generic_list);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_CHEAT:
2020-06-08 16:02:06 +02:00
if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND)))
{
BIND_ACTION_OK(cbs, action_ok_cheat_file_load_append);
}
else
{
BIND_ACTION_OK(cbs, action_ok_cheat_file_load);
}
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_RECORD_CONFIG:
BIND_ACTION_OK(cbs, action_ok_record_configfile_load);
2015-06-07 17:16:21 +02:00
break;
2018-09-26 23:50:29 +02:00
case FILE_TYPE_STREAM_CONFIG:
BIND_ACTION_OK(cbs, action_ok_stream_configfile_load);
break;
case FILE_TYPE_RGUI_THEME_PRESET:
BIND_ACTION_OK(cbs, action_ok_rgui_menu_theme_preset_load);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_REMAP:
BIND_ACTION_OK(cbs, action_ok_remap_file_load);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_SHADER_PRESET:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
/* TODO/FIXME - handle scan case */
BIND_ACTION_OK(cbs, action_ok_shader_preset_load);
#endif
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_SHADER:
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
/* TODO/FIXME - handle scan case */
BIND_ACTION_OK(cbs, action_ok_shader_pass_load);
#endif
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_IMAGE:
/* TODO/FIXME - handle scan case */
BIND_ACTION_OK(cbs, action_ok_menu_wallpaper_load);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_USE_DIRECTORY:
BIND_ACTION_OK(cbs, action_ok_path_use_directory);
2015-06-07 17:16:21 +02:00
break;
2015-11-24 01:12:50 +01:00
#ifdef HAVE_LIBRETRODB
2016-06-20 15:50:37 +02:00
case FILE_TYPE_SCAN_DIRECTORY:
BIND_ACTION_OK(cbs, action_ok_path_scan_directory);
2015-07-04 01:51:41 +02:00
break;
2015-11-24 01:12:50 +01:00
#endif
2019-11-29 17:13:35 +00:00
case FILE_TYPE_MANUAL_SCAN_DIRECTORY:
BIND_ACTION_OK(cbs, action_ok_path_manual_scan_directory);
break;
case FILE_TYPE_MANUAL_SCAN_DAT:
BIND_ACTION_OK(cbs, action_ok_set_manual_content_scan_dat_file);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_CONFIG:
if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD)))
{
BIND_ACTION_OK(cbs, action_ok_override_file_load);
break;
}
BIND_ACTION_OK(cbs, action_ok_config_load);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_PARENT_DIRECTORY:
2015-10-25 08:31:55 +01:00
BIND_ACTION_OK(cbs, action_ok_parent_directory_push);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DIRECTORY:
if (cbs->enum_idx != MSG_UNKNOWN
2020-06-08 16:02:06 +02:00
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DISK_IMAGE_APPEND))
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_SUBSYSTEM_ADD))
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_FONT_PATH))
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_XMB_FONT))
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN))
|| string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_FILTER)))
BIND_ACTION_OK(cbs, action_ok_directory_push);
else
BIND_ACTION_OK(cbs, action_ok_push_random_dir);
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_CARCHIVE:
2017-08-17 18:53:55 +02:00
if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE)
2015-07-04 01:51:41 +02:00
{
#ifdef HAVE_LIBRETRODB
2017-08-17 18:53:55 +02:00
BIND_ACTION_OK(cbs, action_ok_scan_file);
#endif
2017-08-17 18:53:55 +02:00
}
else
{
2020-06-08 16:02:06 +02:00
if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES)))
{
2020-02-23 10:20:14 +01:00
BIND_ACTION_OK(cbs, action_ok_compressed_archive_push_detect_core);
}
else
{
BIND_ACTION_OK(cbs, action_ok_compressed_archive_push);
}
2015-07-04 01:51:41 +02:00
}
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_CORE:
2016-06-27 21:34:05 +02:00
if (cbs->enum_idx != MSG_UNKNOWN)
2015-06-07 17:16:21 +02:00
{
2016-06-18 19:07:51 +02:00
switch (cbs->enum_idx)
{
case MENU_ENUM_LABEL_CORE_UPDATER_LIST:
BIND_ACTION_OK(cbs, action_ok_deferred_list_stub);
break;
case MSG_UNKNOWN:
2016-06-18 19:07:51 +02:00
default:
break;
}
}
else
2018-02-06 21:55:49 +01:00
{
2020-06-08 16:02:06 +02:00
if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_LIST)))
{
2020-03-27 19:05:54 +01:00
BIND_ACTION_OK(cbs, action_ok_load_core_deferred);
}
2020-06-08 16:02:06 +02:00
else if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_LIST_SET)))
2020-03-27 19:05:54 +01:00
{
BIND_ACTION_OK(cbs, action_ok_core_deferred_set);
}
2020-06-08 16:02:06 +02:00
else if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_CORE_LIST)))
2020-03-27 19:05:54 +01:00
{
BIND_ACTION_OK(cbs, action_ok_load_core);
}
2015-06-07 17:16:21 +02:00
}
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_CORE_CONTENT:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_core_content_download);
#endif
break;
case FILE_TYPE_DOWNLOAD_CORE_SYSTEM_FILES:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_core_system_files_download);
#endif
2015-07-04 04:01:35 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_THUMBNAIL_CONTENT:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_core_content_thumbnails);
#endif
break;
case FILE_TYPE_DOWNLOAD_PL_THUMBNAIL_CONTENT:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_pl_content_thumbnails);
#endif
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_CORE:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_core_updater_download);
#endif
2015-06-07 17:16:21 +02:00
break;
2020-01-09 14:13:21 +00:00
case FILE_TYPE_SIDELOAD_CORE:
BIND_ACTION_OK(cbs, action_ok_sideload_core);
break;
2016-06-21 01:40:55 +02:00
case FILE_TYPE_DOWNLOAD_URL:
#ifdef HAVE_NETWORKING
2016-06-21 01:40:55 +02:00
BIND_ACTION_OK(cbs, action_ok_download_url);
#endif
2016-06-21 01:40:55 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_THUMBNAIL:
#if 0
/* Thumbnailpack removal */
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_thumbnails_updater_download);
#endif
#endif
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_LAKKA:
#if defined(HAVE_NETWORKING) && defined(HAVE_LAKKA)
BIND_ACTION_OK(cbs, action_ok_lakka_download);
#endif
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_DOWNLOAD_CORE_INFO:
2015-06-07 17:16:21 +02:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_RDB:
2020-06-08 16:02:06 +02:00
if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DATABASE_MANAGER_LIST)))
{
2020-03-27 19:05:54 +01:00
BIND_ACTION_OK(cbs, action_ok_deferred_list_stub);
}
2020-06-08 16:02:06 +02:00
else if (string_is_equal(menu_label,
msg_hash_to_str(MENU_ENUM_LABEL_DATABASE_MANAGER_LIST)))
2020-03-27 19:05:54 +01:00
{
BIND_ACTION_OK(cbs, action_ok_database_manager_list);
}
/* TODO/FIXME - refactor this */
else if (string_is_equal(menu_label, "Horizontal Menu"))
{
BIND_ACTION_OK(cbs, action_ok_database_manager_list);
2015-06-07 17:16:21 +02:00
}
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_RDB_ENTRY:
BIND_ACTION_OK(cbs, action_ok_rdb_entry);
2015-06-07 17:16:21 +02:00
break;
2020-06-17 14:56:44 +03:00
case MENU_BLUETOOTH:
#ifdef HAVE_BLUETOOTH
2020-06-17 14:56:44 +03:00
BIND_ACTION_OK(cbs, action_ok_bluetooth);
#endif
2020-06-17 14:56:44 +03:00
break;
2016-09-22 16:44:51 +02:00
case MENU_WIFI:
2020-12-09 22:03:23 +01:00
#ifdef HAVE_NETWORKING
#ifdef HAVE_WIFI
2016-09-22 16:44:51 +02:00
BIND_ACTION_OK(cbs, action_ok_wifi);
#endif
#endif
break;
case MENU_NETPLAY_KICK:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_push_netplay_kick);
2022-07-07 11:08:46 -03:00
#endif
break;
case MENU_NETPLAY_BAN:
#ifdef HAVE_NETWORKING
BIND_ACTION_OK(cbs, action_ok_push_netplay_ban);
#endif
2016-12-02 22:40:26 -05:00
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_VIDEOFILTER:
BIND_ACTION_OK(cbs, action_ok_set_path_videofilter);
break;
case FILE_TYPE_FONT:
BIND_ACTION_OK(cbs, action_ok_set_path);
2015-06-07 17:16:21 +02:00
break;
case FILE_TYPE_VIDEO_FONT:
BIND_ACTION_OK(cbs, action_ok_set_path_video_font);
break;
case FILE_TYPE_OVERLAY:
BIND_ACTION_OK(cbs, action_ok_set_path_overlay);
break;
case FILE_TYPE_OSK_OVERLAY:
BIND_ACTION_OK(cbs, action_ok_set_path_osk_overlay);
break;
case FILE_TYPE_AUDIOFILTER:
BIND_ACTION_OK(cbs, action_ok_set_path_audiofilter);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_IN_CARCHIVE:
case FILE_TYPE_PLAIN:
2017-08-17 18:53:55 +02:00
if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE)
2015-06-07 17:16:21 +02:00
{
2015-11-24 01:18:00 +01:00
#ifdef HAVE_LIBRETRODB
2017-08-17 18:53:55 +02:00
BIND_ACTION_OK(cbs, action_ok_scan_file);
2015-11-24 01:12:50 +01:00
#endif
2017-08-17 18:53:55 +02:00
}
else if (cbs->enum_idx != MSG_UNKNOWN)
{
switch (cbs->enum_idx)
{
case MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST:
2016-12-13 01:06:28 +01:00
case MENU_ENUM_LABEL_FAVORITES:
case MENU_ENUM_LABEL_DEFERRED_ARCHIVE_OPEN_DETECT_CORE:
#ifdef HAVE_COMPRESSION
if (type == FILE_TYPE_IN_CARCHIVE)
{
BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core_carchive);
}
else
#endif
{
BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core);
}
break;
case MENU_ENUM_LABEL_DISK_IMAGE_APPEND:
BIND_ACTION_OK(cbs, action_ok_disk_image_append);
break;
case MENU_ENUM_LABEL_SUBSYSTEM_ADD:
BIND_ACTION_OK(cbs, action_ok_subsystem_add);
break;
default:
BIND_ACTION_OK(cbs, action_ok_file_load);
break;
}
}
else
{
2020-03-27 19:05:54 +01:00
if (
string_is_equal(menu_label, "deferred_archive_open_detect_core") ||
string_is_equal(menu_label, "downloaded_file_detect_core_list") ||
string_is_equal(menu_label, "favorites")
)
2018-02-07 22:28:44 +01:00
{
#ifdef HAVE_COMPRESSION
2020-03-27 19:05:54 +01:00
if (type == FILE_TYPE_IN_CARCHIVE)
{
BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core_carchive);
}
else
2018-02-07 22:28:44 +01:00
#endif
2020-03-27 19:05:54 +01:00
{
BIND_ACTION_OK(cbs, action_ok_file_load_with_detect_core);
}
}
else if (string_is_equal(menu_label, "disk_image_append"))
{
BIND_ACTION_OK(cbs, action_ok_disk_image_append);
}
else if (string_is_equal(menu_label, "subsystem_add"))
{
BIND_ACTION_OK(cbs, action_ok_subsystem_add);
}
else
{
BIND_ACTION_OK(cbs, action_ok_file_load);
}
2015-06-07 17:16:21 +02:00
}
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_MOVIE:
2018-06-20 04:50:58 +02:00
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
/* TODO/FIXME - handle scan case */
BIND_ACTION_OK(cbs, action_ok_file_load_ffmpeg);
#endif
break;
case FILE_TYPE_MUSIC:
BIND_ACTION_OK(cbs, action_ok_file_load_music);
break;
2016-06-20 15:50:37 +02:00
case FILE_TYPE_IMAGEVIEWER:
/* TODO/FIXME - handle scan case */
BIND_ACTION_OK(cbs, action_ok_file_load_imageviewer);
2015-06-28 17:21:32 +02:00
break;
case FILE_TYPE_DIRECT_LOAD:
BIND_ACTION_OK(cbs, action_ok_file_load);
break;
2015-06-07 17:16:21 +02:00
case MENU_SETTINGS:
case MENU_SETTING_GROUP:
case MENU_SETTING_SUBGROUP:
BIND_ACTION_OK(cbs, action_ok_push_default);
2015-06-07 17:16:21 +02:00
break;
case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_CYCLE_TRAY_STATUS:
BIND_ACTION_OK(cbs, action_ok_disk_cycle_tray_status);
2015-06-07 17:16:21 +02:00
break;
2020-01-14 12:28:10 +00:00
case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX:
BIND_ACTION_OK(cbs, action_ok_disk_index_dropdown_box_list);
break;
case MENU_SETTING_ACTION_GAME_SPECIFIC_CORE_OPTIONS_CREATE:
BIND_ACTION_OK(cbs, action_ok_game_specific_core_options_create);
break;
case MENU_SETTING_ACTION_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE:
BIND_ACTION_OK(cbs, action_ok_folder_specific_core_options_create);
break;
case MENU_SETTING_ACTION_GAME_SPECIFIC_CORE_OPTIONS_REMOVE:
BIND_ACTION_OK(cbs, action_ok_game_specific_core_options_remove);
break;
case MENU_SETTING_ACTION_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE:
BIND_ACTION_OK(cbs, action_ok_folder_specific_core_options_remove);
2015-11-15 22:09:39 -05:00
break;
case MENU_SETTING_ACTION_CORE_OPTIONS_RESET:
BIND_ACTION_OK(cbs, action_ok_core_options_reset);
break;
case MENU_SETTING_ACTION_CORE_OPTIONS_FLUSH:
BIND_ACTION_OK(cbs, action_ok_core_options_flush);
break;
case MENU_SETTING_ITEM_CORE_RESTORE_BACKUP:
BIND_ACTION_OK(cbs, action_ok_core_restore_backup);
break;
case MENU_SETTING_ITEM_CORE_DELETE_BACKUP:
BIND_ACTION_OK(cbs, action_ok_core_delete_backup);
break;
case MENU_SETTING_ACTION_CORE_LOCK:
BIND_ACTION_OK(cbs, action_ok_core_lock);
break;
case MENU_SETTING_ACTION_CORE_SET_STANDALONE_EXEMPT:
BIND_ACTION_OK(cbs, action_ok_core_set_standalone_exempt);
break;
2020-10-01 15:54:11 +01:00
case MENU_SETTING_ACTION_VIDEO_FILTER_REMOVE:
BIND_ACTION_OK(cbs, action_ok_video_filter_remove);
break;
2020-10-19 11:30:28 +01:00
case MENU_SETTING_ACTION_AUDIO_DSP_PLUGIN_REMOVE:
BIND_ACTION_OK(cbs, action_ok_audio_dsp_plugin_remove);
break;
2022-02-22 18:23:48 +00:00
case MENU_SETTING_ACTION_CONTENTLESS_CORE_RUN:
BIND_ACTION_OK(cbs, action_ok_contentless_core_run);
break;
2015-06-07 17:16:21 +02:00
default:
return -1;
}
2015-06-05 11:48:25 +02:00
}
return 0;
}
int menu_cbs_init_bind_ok(menu_file_list_cbs_t *cbs,
2023-07-15 09:10:16 +02:00
const char *path,
const char *label, size_t lbl_len,
unsigned type, size_t idx,
const char *menu_label, size_t menu_lbl_len)
2015-06-05 11:48:25 +02:00
{
2015-06-07 18:36:10 +02:00
if (!cbs)
return -1;
2015-06-05 11:48:25 +02:00
BIND_ACTION_OK(cbs, action_ok_lookup_setting);
2015-06-05 11:48:25 +02:00
2020-03-27 18:35:10 +01:00
if (menu_cbs_init_bind_ok_compare_label(cbs, label) == 0)
2015-06-07 18:36:10 +02:00
return 0;
2015-06-05 11:48:25 +02:00
2020-02-23 09:22:30 +01:00
if (menu_cbs_init_bind_ok_compare_type(cbs, label,
2020-03-27 19:05:54 +01:00
menu_label, type) == 0)
2015-06-07 18:36:10 +02:00
return 0;
return -1;
}