This commit is contained in:
Viačasłaŭ 2025-06-26 15:55:21 +00:00 committed by GitHub
commit d33d26e2d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 157 additions and 27 deletions

View File

@ -32,6 +32,15 @@
#include "configuration.h" #include "configuration.h"
enum accessibility_narrator_synthesizer
{
ACCESSIBILITY_NARRATOR_SYNTHESIZER_NATIVE = 0,
ACCESSIBILITY_NARRATOR_SYNTHESIZER_SPEACH_DISPATCHER,
ACCESSIBILITY_NARRATOR_SYNTHESIZER_ESPEAK,
ACCESSIBILITY_NARRATOR_SYNTHESIZER_LAST
};
typedef struct typedef struct
{ {
int ai_service_auto; int ai_service_auto;

View File

@ -180,6 +180,8 @@
#define DEFAULT_ACCESSIBILITY_ENABLE false #define DEFAULT_ACCESSIBILITY_ENABLE false
#define DEFAULT_ACCESSIBILITY_NARRATOR_SYNTHESIZER 0
#define DEFAULT_ACCESSIBILITY_NARRATOR_SPEECH_SPEED 5 #define DEFAULT_ACCESSIBILITY_NARRATOR_SPEECH_SPEED 5
#define DEFAULT_DRIVER_SWITCH_ENABLE true #define DEFAULT_DRIVER_SWITCH_ENABLE true

View File

@ -2621,6 +2621,7 @@ static struct config_uint_setting *populate_settings_uint(
SETTING_UINT("cheevos_appearance_anchor", &settings->uints.cheevos_appearance_anchor, true, DEFAULT_CHEEVOS_APPEARANCE_ANCHOR, false); SETTING_UINT("cheevos_appearance_anchor", &settings->uints.cheevos_appearance_anchor, true, DEFAULT_CHEEVOS_APPEARANCE_ANCHOR, false);
SETTING_UINT("cheevos_visibility_summary", &settings->uints.cheevos_visibility_summary, true, DEFAULT_CHEEVOS_VISIBILITY_SUMMARY, false); SETTING_UINT("cheevos_visibility_summary", &settings->uints.cheevos_visibility_summary, true, DEFAULT_CHEEVOS_VISIBILITY_SUMMARY, false);
#endif #endif
SETTING_UINT("accessibility_narrator_synthesizer", &settings->uints.accessibility_narrator_synthesizer, true, DEFAULT_ACCESSIBILITY_NARRATOR_SYNTHESIZER, false);
SETTING_UINT("accessibility_narrator_speech_speed", &settings->uints.accessibility_narrator_speech_speed, true, DEFAULT_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, false); SETTING_UINT("accessibility_narrator_speech_speed", &settings->uints.accessibility_narrator_speech_speed, true, DEFAULT_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, false);
SETTING_UINT("ai_service_mode", &settings->uints.ai_service_mode, true, DEFAULT_AI_SERVICE_MODE, false); SETTING_UINT("ai_service_mode", &settings->uints.ai_service_mode, true, DEFAULT_AI_SERVICE_MODE, false);
SETTING_UINT("ai_service_target_lang", &settings->uints.ai_service_target_lang, true, 0, false); SETTING_UINT("ai_service_target_lang", &settings->uints.ai_service_target_lang, true, 0, false);

View File

@ -279,6 +279,7 @@ typedef struct settings
#endif #endif
/* Accessibility */ /* Accessibility */
unsigned accessibility_narrator_synthesizer;
unsigned accessibility_narrator_speech_speed; unsigned accessibility_narrator_speech_speed;
unsigned menu_timedate_style; unsigned menu_timedate_style;

View File

@ -51,6 +51,10 @@
#include <signal.h> #include <signal.h>
#include <pthread.h> #include <pthread.h>
#if (defined(__linux__) || defined(__HAIKU__) || defined(__unix__)) && !defined(ANDROID)
#include "accessibility.h"
#endif
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "../../config.h" #include "../../config.h"
#endif #endif
@ -2899,7 +2903,8 @@ static const char* accessibility_unix_language_code(const char* language)
string_is_equal(language, "ta") || string_is_equal(language, "ta") ||
string_is_equal(language, "te") || string_is_equal(language, "te") ||
string_is_equal(language, "ur") || string_is_equal(language, "ur") ||
string_is_equal(language, "cy") string_is_equal(language, "cy") ||
string_is_equal(language, "ca")
) )
return language; return language;
else if ( else if (
@ -2908,19 +2913,16 @@ static const char* accessibility_unix_language_code(const char* language)
) )
return "nb"; return "nb";
else if (string_is_equal(language, "en_gb")) else if (string_is_equal(language, "en_gb"))
return "en-gb"; return "en-GB";
else if ( else if (string_is_equal(language, "ca_ES@valencia"))
string_is_equal(language, "ca") || return "ca-VA";
string_is_equal(language, "ca_ES@valencia")
)
return "ca";
else if ( else if (
string_is_equal(language, "pt_pt") || string_is_equal(language, "pt_pt") ||
string_is_equal(language, "pt") string_is_equal(language, "pt")
) )
return "pt"; return "pt";
else if (string_is_equal(language, "pt_bt")) else if (string_is_equal(language, "pt_bt"))
return "pt-br"; return "pt-BR";
else if ( else if (
string_is_equal(language, "zh") || string_is_equal(language, "zh") ||
string_is_equal(language, "zh_cn") || string_is_equal(language, "zh_cn") ||
@ -2938,27 +2940,69 @@ static const char* accessibility_unix_language_code(const char* language)
static bool accessibility_speak_unix(int speed, static bool accessibility_speak_unix(int speed,
const char* speak_text, int priority) const char* speak_text, int priority)
{ {
unsigned synthesizer;
int pid; int pid;
const char* language = accessibility_unix_language_code(get_user_language_iso639_1(true)); const char* language = accessibility_unix_language_code(get_user_language_iso639_1(true));
char* voice_out = (char*)malloc(3 + strlen(language)); char* voice_out = (char*)malloc(3 + strlen(language));
char* speed_out = (char*)malloc(3 + 3); char* speed_out = (char*)malloc(3 + 3);
const char* speeds[10] = {"80", "100", "125", "150", "170", "210", "260", "310", "380", "450"}; const char* speeds[10] = {"80", "100", "125", "150", "170", "210", "260", "310", "380", "450"};
char* executable = (char*)malloc(16);
settings_t *settings = config_get_ptr();
synthesizer = settings->uints.accessibility_narrator_synthesizer;
switch (synthesizer)
{
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_SPEACH_DISPATCHER:
{
strlcpy(executable, "spd-say", 8);
speeds[0] = "-99";
speeds[1] = "-75";
speeds[2] = "-50";
speeds[3] = "-25";
speeds[4] = "0";
speeds[5] = "20";
speeds[6] = "40";
speeds[7] = "60";
speeds[8] = "80";
speeds[9] = "100";
voice_out[0] = '-';
voice_out[1] = 'l';
voice_out[2] = '\0';
strlcat(voice_out, language, sizeof(voice_out));
speed_out[0] = '-';
speed_out[1] = 'r';
speed_out[2] = '\0';
strlcat(speed_out, speeds[speed-1], sizeof(speed_out));
break;
}
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_ESPEAK:
default:
{
strlcpy(executable, "espeak", 7);
voice_out[0] = '-';
voice_out[1] = 'v';
voice_out[2] = '\0';
strlcat(voice_out, language, sizeof(voice_out));
speed_out[0] = '-';
speed_out[1] = 's';
speed_out[2] = '\0';
strlcat(speed_out, speeds[speed-1], sizeof(speed_out));
break;
}
}
if (speed < 1) if (speed < 1)
speed = 1; speed = 1;
else if (speed > 10) else if (speed > 10)
speed = 10; speed = 10;
voice_out[0] = '-';
voice_out[1] = 'v';
voice_out[2] = '\0';
strlcat(voice_out, language, 3 + strlen(language));
speed_out[0] = '-';
speed_out[1] = 's';
speed_out[2] = '\0';
strlcat(speed_out, speeds[speed-1], 6);
if (priority < 10 && speak_pid > 0) if (priority < 10 && speak_pid > 0)
{ {
/* check if old pid is running */ /* check if old pid is running */
@ -2968,7 +3012,7 @@ static bool accessibility_speak_unix(int speed,
if (speak_pid > 0) if (speak_pid > 0)
{ {
/* Kill the running espeak */ /* Kill the running TTS Engine */
kill(speak_pid, SIGTERM); kill(speak_pid, SIGTERM);
speak_pid = 0; speak_pid = 0;
} }
@ -2978,19 +3022,20 @@ static bool accessibility_speak_unix(int speed,
{ {
case 0: case 0:
{ {
/* child process: replace process with the espeak command */ /* child process: replace process with the TTS command */
char* cmd[] = { (char*) "espeak", NULL, NULL, NULL, NULL }; char* cmd[] = { NULL, NULL, NULL, NULL, NULL };
cmd[0] = executable;
cmd[1] = voice_out; cmd[1] = voice_out;
cmd[2] = speed_out; cmd[2] = speed_out;
cmd[3] = (char*)speak_text; cmd[3] = (char*)speak_text;
execvp("espeak", cmd); execvp(executable, cmd);
RARCH_WARN("Could not execute espeak.\n"); RARCH_WARN("Could not execute TTS Engine.\n");
/* Prevent interfere with the parent process */ /* Prevent interfere with the parent process */
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
case -1: case -1:
RARCH_ERR("Could not fork for espeak.\n"); RARCH_ERR("Could not fork for the TTS process.\n");
default: default:
{ {
/* parent process */ /* parent process */
@ -3007,6 +3052,8 @@ end:
free(voice_out); free(voice_out);
if (speed_out) if (speed_out)
free(speed_out); free(speed_out);
if (executable)
free(executable);
return true; return true;
} }
#endif #endif

View File

@ -6580,6 +6580,10 @@ MSG_HASH(
MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED, MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED,
"accessibility_enabled" "accessibility_enabled"
) )
MSG_HASH(
MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
"accessibility_narrator_synthesizer"
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED,
"accessibility_narrator_speech_speed" "accessibility_narrator_speech_speed"

View File

@ -7235,6 +7235,14 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_ACCESSIBILITY_ENABLED, MENU_ENUM_SUBLABEL_ACCESSIBILITY_ENABLED,
"Enable Text-to-Speech to aid in menu navigation." "Enable Text-to-Speech to aid in menu navigation."
) )
MSG_HASH(
MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
"Text-to-Speech synthesizer"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
"The engine of the Text-to-Speech synthesis."
)
MSG_HASH( MSG_HASH(
MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_NARRATOR_SPEECH_SPEED,
"Text-to-Speech Speed" "Text-to-Speech Speed"

View File

@ -231,6 +231,7 @@ DEFAULT_SUBLABEL_MACRO(menu_action_sublabel_setting_audio_mixer_stream_volume,
MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME) MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME)
#endif #endif
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accessibility_enabled, MENU_ENUM_SUBLABEL_ACCESSIBILITY_ENABLED) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accessibility_enabled, MENU_ENUM_SUBLABEL_ACCESSIBILITY_ENABLED)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accessibility_narrator_synthesizer, MENU_ENUM_SUBLABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accessibility_narrator_speech_speed, MENU_ENUM_SUBLABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_accessibility_narrator_speech_speed, MENU_ENUM_SUBLABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_load_config, MENU_ENUM_SUBLABEL_CONFIGURATIONS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_load_config, MENU_ENUM_SUBLABEL_CONFIGURATIONS)
@ -5342,6 +5343,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED: case MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accessibility_enabled); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accessibility_enabled);
break; break;
case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accessibility_narrator_synthesizer);
break;
case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED: case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accessibility_narrator_speech_speed); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_accessibility_narrator_speech_speed);
break; break;

View File

@ -8296,6 +8296,7 @@ unsigned menu_displaylist_build_list(
bool accessibility_enable = settings->bools.accessibility_enable; bool accessibility_enable = settings->bools.accessibility_enable;
menu_displaylist_build_info_selective_t build_list[] = { menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, PARSE_ONLY_UINT, false }, {MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_AI_SERVICE_SETTINGS, PARSE_ACTION, true }, {MENU_ENUM_LABEL_AI_SERVICE_SETTINGS, PARSE_ACTION, true },
}; };
@ -8304,6 +8305,9 @@ unsigned menu_displaylist_build_list(
{ {
switch (build_list[i].enum_idx) switch (build_list[i].enum_idx)
{ {
#if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER:
#endif
case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED: case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED:
if (accessibility_enable) if (accessibility_enable)
build_list[i].checked = true; build_list[i].checked = true;

View File

@ -31,6 +31,12 @@
#include <compat/strl.h> #include <compat/strl.h>
#ifdef HAVE_ACCESSIBILITY
#if (defined(__linux__) || defined(__HAIKU__) || defined(__unix__)) && !defined(ANDROID)
#include "accessibility.h"
#endif
#endif
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "../config.h" #include "../config.h"
#endif #endif
@ -3175,6 +3181,29 @@ static size_t setting_get_string_representation_uint_keyboard_gamepad_mapping_ty
} }
#endif #endif
#ifdef HAVE_ACCESSIBILITY
#if (defined(__linux__) || defined(__HAIKU__) || defined(__unix__)) && !defined(ANDROID)
static size_t setting_get_string_representation_uint_accessibility_narrator_synthesizer(
rarch_setting_t *setting, char *s, size_t len)
{
if (!setting)
return 0;
switch(*setting->value.target.unsigned_integer)
{
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_NATIVE:
return strlcpy(s, "native", len);
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_SPEACH_DISPATCHER:
return strlcpy(s, "Speech Dispatcher", len);
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_ESPEAK:
return strlcpy(s, "eSpeak", len);
case ACCESSIBILITY_NARRATOR_SYNTHESIZER_LAST:
return 0;
}
return 0;
}
#endif
#endif
#ifdef HAVE_TRANSLATE #ifdef HAVE_TRANSLATE
static size_t setting_get_string_representation_uint_ai_service_mode( static size_t setting_get_string_representation_uint_ai_service_mode(
rarch_setting_t *setting, char *s, size_t len) rarch_setting_t *setting, char *s, size_t len)
@ -20542,6 +20571,26 @@ static bool setting_append_list(
(*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh; (*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh;
(*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh; (*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh;
#ifdef HAVE_ACCESSIBILITY
#if (defined(__linux__) || defined(__HAIKU__) || defined(__unix__)) && !defined(ANDROID)
CONFIG_UINT(
list, list_info,
&settings->uints.accessibility_narrator_synthesizer,
MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
MENU_ENUM_LABEL_VALUE_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
DEFAULT_ACCESSIBILITY_NARRATOR_SYNTHESIZER,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_uint_accessibility_narrator_synthesizer;
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
menu_settings_list_current_add_range(list, list_info, ACCESSIBILITY_NARRATOR_SYNTHESIZER_NATIVE, (ACCESSIBILITY_NARRATOR_SYNTHESIZER_LAST - 1), 1, true, true);
#endif
#endif
CONFIG_UINT( CONFIG_UINT(
list, list_info, list, list_info,
&settings->uints.accessibility_narrator_speech_speed, &settings->uints.accessibility_narrator_speech_speed,

View File

@ -2945,6 +2945,7 @@ enum msg_hash_enums
MENU_LABEL(INPUT_HAPTIC_FEEDBACK_SETTINGS), MENU_LABEL(INPUT_HAPTIC_FEEDBACK_SETTINGS),
MENU_LABEL(ACCESSIBILITY_SETTINGS), MENU_LABEL(ACCESSIBILITY_SETTINGS),
MENU_LABEL(ACCESSIBILITY_ENABLED), MENU_LABEL(ACCESSIBILITY_ENABLED),
MENU_LABEL(ACCESSIBILITY_NARRATOR_SYNTHESIZER),
MENU_LABEL(ACCESSIBILITY_NARRATOR_SPEECH_SPEED), MENU_LABEL(ACCESSIBILITY_NARRATOR_SPEECH_SPEED),
MENU_LABEL(AI_SERVICE_SETTINGS), MENU_LABEL(AI_SERVICE_SETTINGS),
MENU_LABEL(AI_SERVICE_MODE), MENU_LABEL(AI_SERVICE_MODE),