diff --git a/README.md b/README.md index 8023927..6d1d22a 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ The "\_about\_" assigns corresponding text file for displaying _About_ message, The "\_keyboard__\_" string will modify alternative overlay keyboard on Input Dialog (accesed with MODIFY button). +The "\_TTS_voice\_" string assigns voice type used by TTS engine e.g. "\_TTS_voice\_"=en" for English (check for available voices on your device `/usr/share/espeak-data/voices`) + ### Dictionary To view the full list of string messages available to translate in source see: [dictionary.txt](https://github.com/MiyooCFW/gmenu2x/blob/master/dictionary.txt) diff --git a/assets/translations/Chinese(CN) b/assets/translations/Chinese(CN) index d0fbf37..08bd537 100644 --- a/assets/translations/Chinese(CN) +++ b/assets/translations/Chinese(CN) @@ -10,6 +10,7 @@ Alt= Appearance & skin settings=外观设置 apps=软件 Are you sure?=是否确定? +at= Audio volume=全局音量 Automatic load backdrops from skin pack=自动从主题包加载程序背景壁纸 Autostart=自动启动 @@ -69,6 +70,7 @@ Displays last launched program's output=显示最后运行的程序输出日志 Done processing.= Edit=编辑 emus=模拟器 +Entering Text Dialog editor, press B to exit= Exit=退出 Explorer=文件管理器 favorites= @@ -93,7 +95,9 @@ Hint: Hold 'X' to change Date & Time=提示:长按X更改日期和时间 Hint: Hold 'Y' to restart GMenu2X=提示:长按Y重启GMenu2X Hint: Press 'Y' now quickly to disable AutoStart= Hint: Press 'Y' now quickly to reset gmenu2x.cfg=提示:此时快速按下Y重置gmenu2x.cfg配置文件 +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings=提示:可以在设置中设置软件或游戏自动启动 +Hint: You can skip reading a message, by pressing START= Hints=提示 Home path=默认路径 How to scale wallpaper, backdrops and game art=设置壁纸,程序背景和预览图缩放方式 @@ -153,6 +157,7 @@ Power=关机 Poweroff or reboot the device?=请选择关机还是重启? Poweroff=关机 Preview mode=预览图模式 +Processing output.= Reboot=重启 Rebooting= Remember selection=记住选择 @@ -166,6 +171,7 @@ Reset link's icon back to default=恢复图标为默认设置 Reset settings=恢复默认设置 Reset=重置 Restart= +RGBA values are = Run last app on restart=重启后运行最后的程序 Running.. Please wait..= Save changes?=保存更改? @@ -224,7 +230,9 @@ Space=空格 Suspend timeout=闲置锁屏时间 SW Clock=系统时间 TEfix method=屏幕撕裂修正方式 +Terminal output as follows= Terminal= +Text To Speak= Text viewer= The section this link belongs to=该软件链接属于分组 the settings. Continue?= @@ -234,6 +242,7 @@ This section is empty=分组为空 Title font size=标题文字大小 Title=标题 Top/Section Bar=标题栏颜色 +Typed= Umount external media device= Umount= Uninstall IPK=卸载IPK程序 @@ -245,7 +254,9 @@ Unset link's selector box art path=取消设置缩略图路径 Unset link's selector directory=取消设置模拟器程序目录 Unset link's selector file filters=取消设置ROM文件后缀过滤 Use file browser selector=使用文件浏览 +Use TTS engine to read menu out loud= Wallpaper=壁纸 +Welcome to GMenu= Yes=是 Zip content= _about_= @@ -258,3 +269,4 @@ _keyboard_t2_l3_= _keyboard_t3_l1_= _keyboard_t3_l2_= _keyboard_t3_l3_= +_TTS_voice_=zh diff --git a/assets/translations/Polish b/assets/translations/Polish index 11f4dc4..5322cba 100644 --- a/assets/translations/Polish +++ b/assets/translations/Polish @@ -10,6 +10,7 @@ Alt= Appearance & skin settings=Wygląd i ustawienie skórki apps=apki Are you sure?=Jesteś pewien? +at= Audio volume=Głośność Automatic load backdrops from skin pack=Automatycznie ładuj plany tła z paczki skórki Autostart=Autostart @@ -69,6 +70,7 @@ Displays last launched program's output=Pokazuje dziennik z ostatnio uruchomione Done processing.=Skończono przetwarzanie. Edit=Edytuj emus=emusy +Entering Text Dialog editor, press B to exit= Exit=Wyjdź Explorer=Eksplorator favorites=ulubione @@ -93,7 +95,9 @@ Hint: Hold 'X' to change Date & Time=Tip: Przytrzymaj 'X' do zmiany Daty i Czasu Hint: Hold 'Y' to restart GMenu2X=Tip: Przytrzymaj 'Y' aby zrestartować GMenu2X Hint: Press 'Y' now quickly to disable AutoStart=Tip: Naciśnij 'Y' teraz szybko \n aby dezaktywować AutoStart Hint: Press 'Y' now quickly to reset gmenu2x.cfg=Tip: Naciśnij 'Y' teraz szybko \n aby zresetować gmenu2x.cfg +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings=Tip: Możesz AutoStartować każdą grę/apkę!?\nZobacz ustawienia +Hint: You can skip reading a message, by pressing START= Hints=Wskazówki Home path=Ścieżka domowa How to scale wallpaper, backdrops and game art=Jak skalować tapetę, tło i okładki @@ -153,6 +157,7 @@ Power=Zasilanie Poweroff or reboot the device?=Wyłączyć czy zresetować urządzenie? Poweroff=Wyłącz Preview mode=Tryb podglądu +Processing output.= Reboot=Restart Rebooting=Restartuje Remember selection=Zapamiętaj wybór @@ -166,6 +171,7 @@ Reset link's icon back to default=Zresetuj ikony skrótów do domyślnych Reset settings=Zresetuj ustawienia Reset=Zresetuj Restart=Restartuj +RGBA values are = Run last app on restart=Uruchom ostatnią aplikacje po restarcie Running.. Please wait..=Uruchamiam.. Proszę czekać.. Save changes?=Zapisać zmiany? @@ -224,7 +230,9 @@ Space=Spacja Suspend timeout=Czas do uśpienia SW Clock=SW Zegar TEfix method=metoda TEfix +Terminal output as follows= Terminal=Terminal +Text To Speak= Text viewer=Przeglądarka tekstu The section this link belongs to=Sekcja do której należy ten skrót the settings. Continue?=ustawienia. Kontynuować? @@ -234,6 +242,7 @@ This section is empty=Ta sekcja jest pusta Title font size=Wielkość czcionki tytułowej Title=Tytuł Top/Section Bar=Pasek sekcji/górny +Typed= Umount external media device=Wysuń zewnętrzny nośnik danych Umount=Wysuń Uninstall IPK=Odinstaluj IPK @@ -245,7 +254,9 @@ Unset link's selector box art path=Wyzeruj ścieżkę okładki selektora skrótu Unset link's selector directory=Wyzeruj katalog selektora skrótu Unset link's selector file filters=Wyzeruj filtry selektora pliku skrótu Use file browser selector=Użyj selektora przeglądarki plików +Use TTS engine to read menu out loud= Wallpaper=Tapeta +Welcome to GMenu= Yes=Tak Zip content=Zawartość zip'a _about_=_about_pl @@ -258,3 +269,4 @@ _keyboard_t2_l3_=ŻŹĆVBŃM<>?_+\n!@# _keyboard_t3_l1_= _keyboard_t3_l2_= _keyboard_t3_l3_= +_TTS_voice_=pl diff --git a/assets/translations/Portuguese(Brazil) b/assets/translations/Portuguese(Brazil) index dac1b85..0d8d0c8 100644 --- a/assets/translations/Portuguese(Brazil) +++ b/assets/translations/Portuguese(Brazil) @@ -10,6 +10,7 @@ Alt= Appearance & skin settings=Configurações de aparência e configurações de skins apps=aplicativos Are you sure?=Tem certeza? +at= Audio volume=Volume do Áudio Automatic load backdrops from skin pack=Carregar pacote de plano de fundo do pacote de skins Autostart=Início automático @@ -69,6 +70,7 @@ Displays last launched program's output=Mostra a saída do último programa exec Done processing.=Processamento finalizado. Edit=Editar emus=emus +Entering Text Dialog editor, press B to exit= Exit=Sair Explorer=Explorador favorites=favoritos @@ -93,7 +95,9 @@ Hint: Hold 'X' to change Date & Time=Dica: segure 'X' para alterar a data e a ho Hint: Hold 'Y' to restart GMenu2X=Dica: segure 'Y' para reiniciar o GMenu2X Hint: Press 'Y' now quickly to disable AutoStart= Hint: Press 'Y' now quickly to reset gmenu2x.cfg=Dica: pressione 'Y' agora rapidamente para redefinir gmenu2x.cfg +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings=Dica: você pode iniciar automaticamente qualquer jogo/aplicativo!? Ver configurações +Hint: You can skip reading a message, by pressing START= Hints=Dicas Home path=Caminho inicial How to scale wallpaper, backdrops and game art=Como dimensionar papéis de parede, planos de fundos e arte do jogo @@ -153,6 +157,7 @@ Power=Ligar/Desligar Poweroff or reboot the device?=Desligar ou reiniciar o dispositivo? Poweroff=Desligar Preview mode=Modo de pré-visualização +Processing output.= Reboot=Reiniciar Rebooting=Reiniciando Remember selection=Lembrar seleção @@ -166,6 +171,7 @@ Reset link's icon back to default=Redefinir o ícone do link de volta ao padrão Reset settings=Redefinir configurações Reset=Reiniciar Restart= +RGBA values are = Run last app on restart=Execute o último aplicativo ao reiniciar Running.. Please wait..=Executando.. Por favor, aguarde.. Save changes?=Salvar alterações? @@ -224,7 +230,9 @@ Space=Espaço Suspend timeout=Suspender tempo limite SW Clock=Relógio de Software TEfix method=Método TEfix +Terminal output as follows= Terminal=Terminal +Text To Speak= Text viewer=Visualizador de texto The section this link belongs to=Seção a qual pertence este link the settings. Continue?= @@ -234,6 +242,7 @@ This section is empty=Esta seção está vazia Title font size=Tamanho da fonte do título Title=Título Top/Section Bar=Barra superior/seção +Typed= Umount external media device= Umount= Uninstall IPK=Desinstalar IPK @@ -245,7 +254,9 @@ Unset link's selector box art path=Desmarcar caminho da arte da caixa seletora d Unset link's selector directory=Desativar diretório seletor de link Unset link's selector file filters=Desativar filtros de arquivo seletor de link Use file browser selector=Use o seletor do navegador de arquivos +Use TTS engine to read menu out loud= Wallpaper=Papel de parede +Welcome to GMenu= Yes=Sim Zip content=Conteúdo Zip _about_= @@ -258,3 +269,4 @@ _keyboard_t2_l3_= _keyboard_t3_l1_= _keyboard_t3_l2_= _keyboard_t3_l3_= +_TTS_voice_=pt-br diff --git a/assets/translations/Russian b/assets/translations/Russian index 7c1c08e..7b8877b 100644 --- a/assets/translations/Russian +++ b/assets/translations/Russian @@ -10,6 +10,7 @@ Alt=Р/Л Appearance & skin settings=Настройка темы и внешнего вида apps=приложения Are you sure?=Уверены? +at= Audio volume=Громкость звука Automatic load backdrops from skin pack=Автозагрузка задников из набора темы Autostart=Автозапуск @@ -69,6 +70,7 @@ Displays last launched program's output=Сообщения последнего Done processing.=Выполнение завершено. Edit=Изменить emus=эмуляторы +Entering Text Dialog editor, press B to exit= Exit=Выход Explorer=Обозреватель favorites=избранное @@ -93,7 +95,9 @@ Hint: Hold 'X' to change Date & Time=Совет: Для изменения да Hint: Hold 'Y' to restart GMenu2X=Совет: Для перезапуска GMenu2X держите «Y» Hint: Press 'Y' now quickly to disable AutoStart=Совет: Отключить автозапуск? Быстро нажмите «Y» Hint: Press 'Y' now quickly to reset gmenu2x.cfg=Совет: Для сброса gmenu2x.cfg быстро нажмите «Y» +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings=Совет: Автозапуск игр/приложений?! В настройках! +Hint: You can skip reading a message, by pressing START= Hints=Советы Home path=Домашний каталог How to scale wallpaper, backdrops and game art=Как масштабировать обои, фоны и изображения @@ -153,6 +157,7 @@ Power=Питание Poweroff or reboot the device?=Выключить или перезагрузить устройство? Poweroff=Выключить Preview mode=Режим предпросмотра +Processing output.= Reboot=Перезагрузить Rebooting=Перезагрузка Remember selection=Запоминать выбор @@ -166,6 +171,7 @@ Reset link's icon back to default=Сбросить назначенные зна Reset settings=Сброс настроек Reset=Сброс Restart=Перезапуск +RGBA values are = Run last app on restart=Запуск последнего приложения при перезагрузке Running.. Please wait..=Идёт выполнение.. Ждите.. Save changes?=Сохранить изменения? @@ -224,7 +230,9 @@ Space=⎵ Suspend timeout=Тайм-аут сна SW Clock=Программные часы TEfix method=Коррекция разрыва кадра +Terminal output as follows= Terminal=Терминал +Text To Speak= Text viewer=Просмотрщик текстов The section this link belongs to=Раздел, к которому относится этот ярлык the settings. Continue?=настройки. Продолжить? @@ -234,6 +242,7 @@ This section is empty=Этот раздел пуст Title font size=Размер шрифта заголовка Title=Заголовок Top/Section Bar=Панель разделов/верхняя +Typed= Umount external media device=Извлечь внешний носитель данных Umount=Извлечь Uninstall IPK=Удалить IPK @@ -245,7 +254,9 @@ Unset link's selector box art path=Сбросить пути к миниатюр Unset link's selector directory=Сбросить назначенные каталоги ярлыков Unset link's selector file filters=Сбросить файловые фильтры ярлыков Use file browser selector=Использовать обозреватель в роли селектора +Use TTS engine to read menu out loud= Wallpaper=Обои +Welcome to GMenu= Yes=Да Zip content=Содержимое архива _about_=_about_ru @@ -258,3 +269,4 @@ _keyboard_t2_l3_=ЯЧСМИТЬБЮЁ:;\n/?! _keyboard_t3_l1_=*·×÷+-/\&<=>| _keyboard_t3_l2_=()[]{}@#$¤%^~ _keyboard_t3_l3_=_«»"'`.,:;!?§ +_TTS_voice_=ru diff --git a/dictionary.txt b/dictionary.txt index 4462133..3b849a9 100644 --- a/dictionary.txt +++ b/dictionary.txt @@ -90,6 +90,7 @@ Displays last launched program's output= Done processing.= Done= Edit= +Entering Text Dialog editor, press B to exit= Error loading meta-data= Executable= Exit= @@ -121,7 +122,9 @@ Hint: Hold 'X' to change Date & Time= Hint: Hold 'Y' to restart GMenu2X= Hint: Press 'Y' now quickly to disable AutoStart= Hint: Press 'Y' now quickly to reset gmenu2x.cfg= +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings= +Hint: You can skip reading a message, by pressing START= Hints= Home Path= Home directory= @@ -194,6 +197,8 @@ Poweroff or reboot the device?= Poweroff the device?= Poweroff= Preview mode= +Processing output.= +RGBA values are = Reboot= Rebooting= Remember selection= @@ -287,7 +292,9 @@ THIS CAN'T BE UNDONE= TV mode= TV-out connected. Enable?= Telnet on boot= +Terminal output as follows= Terminal= +Text To Speak= Text viewer= The section this link belongs to= This directory is empty= @@ -296,6 +303,7 @@ Title font size= Title= Top/Section Bar= Turn off= +Typed= USB Enabled (Nand)= USB Enabled (Root)= USB Enabled (SD)= @@ -322,12 +330,15 @@ Unsupported platform= Update OPK links= Uptime: = Use Ginge= +Use TTS engine to read menu out loud= Use file browser selector= Wallpaper= +Welcome to GMenu= Y: Show manual= Yes= You should disable Usb Networking to do this.= Zip content= +_TTS_voice_= _about_= _keyboard_t1_l1_= _keyboard_t1_l2_= @@ -338,4 +349,5 @@ _keyboard_t2_l3_= _keyboard_t3_l1_= _keyboard_t3_l2_= _keyboard_t3_l3_= +at= the settings. Continue?= diff --git a/src/browsedialog.cpp b/src/browsedialog.cpp index 40dfaa7..ad298c6 100644 --- a/src/browsedialog.cpp +++ b/src/browsedialog.cpp @@ -13,7 +13,8 @@ uint32_t hideAlphaNum(uint32_t interval, void *param) { SDL_RemoveTimer(alphanum_timer); alphanum_timer = NULL; InputManager::wakeUp(0, (void*)false); return 0; -}; +} + BrowseDialog::BrowseDialog(GMenu2X *gmenu2x, const string &title, const string &description, const string &icon): Dialog(gmenu2x, title, description, icon) { @@ -111,6 +112,8 @@ bool BrowseDialog::exec() { gmenu2x->s->write(gmenu2x->font, getFileName(i), gmenu2x->listRect.x + 21, iY + rowHeight/2, VAlignMiddle); } + gmenu2x->allyTTS(getFileName(selected).c_str(), FAST_GAP_TTS, FAST_SPEED_TTS, 0); + if (gmenu2x->confStr["previewMode"] != "Backdrop") { Surface anim = new Surface(gmenu2x->s); if (preview.empty() || preview == "#") { // hide preview diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 9ebd174..3a9b6f8 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -96,6 +96,14 @@ int TEFIX_MAX = -1; const char *CARD_ROOT = getenv("HOME"); +int SLOW_GAP_TTS = 5; +int SLOW_SPEED_TTS = 140; +int MEDIUM_GAP_TTS = 3; +int MEDIUM_SPEED_TTS = 150; +int FAST_GAP_TTS = 0; //default for espeak +int FAST_SPEED_TTS = 175; //default for espeak +string VOICE_TTS = "en"; //default for espeak + #if defined(TARGET_RETROFW) #include "platform/retrofw.h" #elif defined(TARGET_RG350) @@ -117,6 +125,10 @@ const char *CARD_ROOT = getenv("HOME"); #ifndef DEFAULT_TEFIX #define DEFAULT_TEFIX -1 #endif +#ifndef TTS_ENGINE +#define TTS_ENGINE ":" +#endif + #include "menu.h" @@ -199,6 +211,56 @@ GMenu2X::~GMenu2X() { delete titlefont; } +void GMenu2X::allyTTS(const char* text) { + if (!confInt["enableTTS"]) return; + char tmp_chr[256]; + const char* voice; + + voice = VOICE_TTS.c_str(); + + system("killall " TTS_ENGINE); + snprintf(tmp_chr, sizeof(tmp_chr), TTS_ENGINE " \'%s\' -v%s &", text, voice); + system(tmp_chr); +} + +void GMenu2X::allyTTS(const char* file, int gap, int speed) { + if (!confInt["enableTTS"]) return; + char tmp_chr[256]; + const char* voice; + + voice = VOICE_TTS.c_str(); + + system("killall " TTS_ENGINE); + snprintf(tmp_chr, sizeof(tmp_chr), TTS_ENGINE " -f%s -g%i -s%i -v%s &", file, gap, speed, voice); + system(tmp_chr); +} + +void GMenu2X::allyTTS(const char* text, int gap, int speed, bool wait) { + if (!confInt["enableTTS"]) return; + char tmp_chr[256]; + const char* voice; + //static char rm_tmp_chr[256]; + + //if (strcmp(text, rm_tmp_chr) == 0) return; + //snprintf(rm_tmp_chr, sizeof(rm_tmp_chr), "%s", text); + + voice = VOICE_TTS.c_str(); + + //freopen("/dev/null", "w", stdout); // nulify stdout + + if (confInt["enableTTS"]) system("killall " TTS_ENGINE); + snprintf(tmp_chr, sizeof(tmp_chr), TTS_ENGINE " \"%s\" -g%i -s%i -v%s &", text, gap, speed, voice); + system(tmp_chr); + if (wait) while (system("pgrep " TTS_ENGINE) == 0) { + sleep(0.1); + input.update(false); + if (input[SETTINGS]) system("killall " TTS_ENGINE); + } + + //fflush(stdout); + //freopen("/dev/tty", "w", stdout); // activate stdout +} + void GMenu2X::quit() { s->flip(); s->flip(); s->flip(); // flush buffers @@ -211,6 +273,8 @@ void GMenu2X::quit() { //#endif writeConfig(); + system("killall " TTS_ENGINE); + s->free(); font->free(); @@ -296,7 +360,24 @@ void GMenu2X::main(bool autoStart) { // Hint messages //while (true) { if (confInt["showHints"] == 1) { - if (confStr["lastCommand"] == "" || confStr["lastDirectory"] == "") { + if (confInt["enableTTS"] == 1 && (confStr["lastCommand"] == "" || confStr["lastDirectory"] == "")) { + switch (randomInt) { + case 0: case 1: case 2: { + string readHint = tr["Hint: To read a selected value or Link's description press X"]; + allyTTS(readHint.c_str(), FAST_GAP_TTS, FAST_SPEED_TTS, 1); + break; + } + case 3: case 4: case 5: { + string readHint = tr["Hint: You can skip reading a message, by pressing START"]; + allyTTS(readHint.c_str(), FAST_GAP_TTS, FAST_SPEED_TTS, 1); + break; + } + default: { + allyTTS(tr["Loading"].c_str(), FAST_GAP_TTS, FAST_SPEED_TTS, 1); + break; + } + } + } else if (confStr["lastCommand"] == "" || confStr["lastDirectory"] == "") { switch (randomInt) { case 0: { MessageBox mb(this, tr["Loading."]+"\n"+tr["Hint: Press 'Y' now quickly\nto reset gmenu2x.cfg"]); @@ -395,6 +476,9 @@ void GMenu2X::main(bool autoStart) { } } + string readMenu = tr["Welcome to GMenu"]; + allyTTS(readMenu.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + menu = new Menu(this); initMenu(); @@ -516,6 +600,7 @@ bool GMenu2X::inputCommonActions(bool &inputAction) { wasActive = SETTINGS; input.update(); + if (confInt["enableTTS"]) system("killall " TTS_ENGINE); if (SDL_GetTicks() - button_hold > 1000 && !actionPerformed) { wasActive = 0; @@ -774,6 +859,7 @@ void GMenu2X::settings() { sd.addSetting(new MenuSettingBool(this, tr["Autostart"], tr["Run last app on restart"], &confInt["saveAutoStart"])); sd.addSetting(new MenuSettingBool(this, tr["Hints"], tr["Show \"Hint\" messages"], &confInt["showHints"])); sd.addSetting(new MenuSettingBool(this, tr["Output logs"], tr["Logs the link's output to read with Log Viewer"], &confInt["outputLogs"])); + sd.addSetting(new MenuSettingBool(this, tr["Text To Speak"], tr["Use TTS engine to read menu out loud"], &confInt["enableTTS"])); sd.addSetting(new MenuSettingMultiString(this, tr["Reset settings"], tr["Choose settings to reset back to defaults"], &tmp, &opFactory, 0, MakeDelegate(this, &GMenu2X::resetSettings))); if (sd.exec() && sd.edited() && sd.save) { @@ -951,6 +1037,7 @@ void GMenu2X::readConfig() { // Defaults *** Sync with default values in writeConfig confInt["saveSelection"] = 1; confInt["dialogAutoStart"] = 1; + confInt["enableTTS"] = 0; confInt["showHints"] = 1; confStr["datetime"] = xstr(__BUILDTIME__); confInt["skinBackdrops"] = 1; @@ -992,7 +1079,12 @@ void GMenu2X::readConfig() { cfg.close(); } - if (!confStr["lang"].empty()) tr.setLang(confStr["lang"]); + if (!confStr["lang"].empty()) { + tr.setLang(confStr["lang"]); + string voiceTTS = tr["_TTS_voice_"]; + INFO("voice is set to %s",voiceTTS.c_str()); + if (voiceTTS != "_TTS_voice_" && !voiceTTS.empty()) VOICE_TTS = voiceTTS; + } if (!confStr["wallpaper"].empty() && !file_exists(confStr["wallpaper"])) confStr["wallpaper"] = ""; if (confStr["skin"].empty() || !dir_exists("skins/" + confStr["skin"])) confStr["skin"] = "Default"; @@ -1464,6 +1556,7 @@ void GMenu2X::about() { #endif // td.appendText(temp); td.appendFile(tr["_about_"] + ".txt"); + allyTTS((tr["_about_"] + ".txt").c_str(), FAST_GAP_TTS, FAST_SPEED_TTS); td.exec(); } @@ -1473,6 +1566,7 @@ void GMenu2X::viewLog() { TextDialog td(this, tr["Log Viewer"], tr["Last launched program's output"], "skin:icons/ebook.png"); td.appendFile(exe_path() + "/log.txt"); + allyTTS((exe_path() + "/log.txt").c_str(), FAST_GAP_TTS, FAST_SPEED_TTS); td.exec(); MessageBox mb(this, tr["Delete the log file?"], "skin:icons/ebook.png"); @@ -1578,6 +1672,7 @@ void GMenu2X::showManual() { return; } + allyTTS(linkManual.c_str(), FAST_GAP_TTS, FAST_SPEED_TTS); td.exec(); } @@ -1604,6 +1699,7 @@ void GMenu2X::explorer() { } else if (ext == ".txt" || ext == ".conf" || ext == ".me" || ext == ".md" || ext == ".xml" || ext == ".log" || ext == ".ini") { TextDialog td(this, tr["Text viewer"], bd.getFile(bd.selected), "skin:icons/ebook.png"); td.appendFile(bd.getFilePath(bd.selected)); + allyTTS(bd.getFilePath(bd.selected).c_str(), FAST_GAP_TTS, FAST_SPEED_TTS); td.exec(); #if defined(IPK_SUPPORT) } else if (ext == ".ipk" && file_exists("/usr/bin/opkg")) { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 5b1bae2..aaee15e 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -105,6 +105,14 @@ extern int LAYOUT_VERSION_MAX; extern int TEFIX; extern int TEFIX_MAX; +extern int SLOW_GAP_TTS; +extern int SLOW_SPEED_TTS; +extern int MEDIUM_GAP_TTS; +extern int MEDIUM_SPEED_TTS; +extern int FAST_GAP_TTS; +extern int FAST_SPEED_TTS; +extern string VOICE_TTS; + typedef FastDelegate0<> MenuAction; typedef unordered_map > ConfStrHash; typedef unordered_map > ConfIntHash; @@ -212,6 +220,10 @@ class GMenu2X { void renameSection(); void deleteSection(); + void allyTTS(const char* text); + void allyTTS(const char* file, int gap, int speed); + void allyTTS(const char* text, int gap, int speed, bool wait); + string setBackground(Surface *bg, string wallpaper); int drawButton(Button *btn, int x = 5, int y = -8); diff --git a/src/inputdialog.cpp b/src/inputdialog.cpp index 4165981..498205c 100644 --- a/src/inputdialog.cpp +++ b/src/inputdialog.cpp @@ -126,6 +126,9 @@ void InputDialog::setKeyboard(int kb) { } bool InputDialog::exec() { + string readWarning = gmenu2x->tr["Entering Text Dialog editor, press B to exit"]; + gmenu2x->allyTTS(readWarning.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 1); + Surface *bg = new Surface(gmenu2x->s); SDL_Rect box = {gmenu2x->listRect.x + 2, 0, gmenu2x->listRect.w - 4, gmenu2x->font->getHeight() + 4}; @@ -138,6 +141,8 @@ bool InputDialog::exec() { gmenu2x->s->box(gmenu2x->bottomBarRect, gmenu2x->skinConfColors[COLOR_BOTTOM_BAR_BG]); + string readValue = ""; + string readTyped = gmenu2x->tr["Typed"] + " "; string altBtn = "x"; string altChar = gmenu2x->tr["Alt"]; string spaceChar = gmenu2x->tr["Space"]; @@ -208,10 +213,19 @@ bool InputDialog::exec() { gmenu2x->s->flip(); bool inputAction = gmenu2x->input.update(); - if (gmenu2x->inputCommonActions(inputAction)) continue; + + if (!allyRead) { + readValue = currKey(); + gmenu2x->allyTTS(readValue.c_str()); + allyRead = true; + } + + if (gmenu2x->inputCommonActions(inputAction)) { + continue; + } if (gmenu2x->input[CANCEL] || gmenu2x->input[MENU]) return false; - else if (gmenu2x->input[SETTINGS]) { + else if (gmenu2x->input[SETTINGS]) { string inputss; string::size_type position_newl_all = input.find("\n"); @@ -249,6 +263,22 @@ bool InputDialog::exec() { else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) changeKeysCustom(); else if (gmenu2x->input[SECTION_PREV]) backspace(); else if (gmenu2x->input[SECTION_NEXT]) space(); + + if ( + gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[UP] || gmenu2x->input[DOWN] || gmenu2x->input[MANUAL] + || gmenu2x->input.hatEvent(DLEFT) == DLEFT || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT || gmenu2x->input.hatEvent(DUP) == DUP || gmenu2x->input.hatEvent(DDOWN) == DDOWN + ) { + allyRead = false; + } else if (gmenu2x->input[SECTION_NEXT]) { + readValue = readTyped + gmenu2x->tr["Space"]; + gmenu2x->allyTTS(readValue.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + } else if (gmenu2x->input[SECTION_PREV]) { + readValue = readTyped + gmenu2x->tr["Backspace"]; + gmenu2x->allyTTS(readValue.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + } else if (gmenu2x->input[CONFIRM]) { + readValue = readTyped + currKey(); + gmenu2x->allyTTS(readValue.c_str()); + } } } @@ -261,15 +291,21 @@ void InputDialog::space() { input += " "; } -void InputDialog::confirm() { +string InputDialog::currKey() { bool utf8; int xc=0; for (uint32_t x = 0; x < kb->at(selRow).length(); x++) { utf8 = gmenu2x->font->utf8Code(kb->at(selRow)[x]); - if (xc == selCol) input += kb->at(selRow).substr(x, utf8 ? 2 : 1); + if (xc == selCol) + return kb->at(selRow).substr(x, utf8 ? 2 : 1); if (utf8) x++; xc++; } + return ""; +} + +void InputDialog::confirm() { + input += currKey(); } void InputDialog::changeKeys() { diff --git a/src/inputdialog.h b/src/inputdialog.h index 2693e9d..cd99fc0 100644 --- a/src/inputdialog.h +++ b/src/inputdialog.h @@ -74,6 +74,9 @@ class InputDialog { IconButton *btnBackspaceX, *btnBackspaceL, *btnSpace, *btnConfirm, *btnChangeKeys; string input; + string currKey(); + bool allyRead = false; + void backspace(); void space(); void confirm(); diff --git a/src/menu.cpp b/src/menu.cpp index c6a95f2..ba160fe 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -922,10 +922,16 @@ void Menu::exec() { selLink()->run(); } - else if (gmenu2x->input[CANCEL]) continue; - else if (gmenu2x->input[SETTINGS] && !(gmenu2x->actionPerformed)) gmenu2x->settings(); - else if (gmenu2x->input[MENU]) gmenu2x->contextMenu(); - + else if (gmenu2x->input[CANCEL]) { + continue; + } else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) { + if (selLinkApp() != NULL || selLink() != NULL) gmenu2x->allyTTS(iconDescription.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + continue; + } else if (gmenu2x->input[SETTINGS] && !(gmenu2x->actionPerformed)) { + gmenu2x->settings(); + } else if (gmenu2x->input[MENU]) { + gmenu2x->contextMenu(); + } // LINK NAVIGATION else if ((gmenu2x->input[LEFT] || gmenu2x->input.hatEvent(DLEFT) == DLEFT) && linkCols == 1 && linkRows > 1) pageUp(); else if ((gmenu2x->input[RIGHT] || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT) && linkCols == 1 && linkRows > 1) pageDown(); @@ -962,13 +968,28 @@ void Menu::exec() { // } // } + iconTitle = ""; iconDescription = ""; if (selLinkApp() != NULL) { + iconTitle = selLinkApp()->getTitle(); iconDescription = selLinkApp()->getDescription(); } else if (selLink() != NULL) { + iconTitle = selLink()->getTitle(); iconDescription = selLink()->getDescription(); } + if ( + gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[UP] || gmenu2x->input[DOWN] || gmenu2x->input[MANUAL] + || gmenu2x->input.hatEvent(DLEFT) == DLEFT || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT || gmenu2x->input.hatEvent(DUP) == DUP || gmenu2x->input.hatEvent(DDOWN) == DDOWN + || gmenu2x->input[MANUAL] || gmenu2x->input[MODIFIER] + ) allyRead = false; + + readSection = gmenu2x->tr["Section"] + " " + gmenu2x->tr[selSectionName()] + " " + gmenu2x->tr["at"] + " " + iconTitle; + if (!allyRead) { + gmenu2x->allyTTS(readSection.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + allyRead = true; + } + if ( !iconDescription.empty() && (gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[UP] || gmenu2x->input[DOWN] || gmenu2x->input[SECTION_PREV] || gmenu2x->input[SECTION_NEXT] @@ -978,11 +999,18 @@ void Menu::exec() { SDL_RemoveTimer(iconChangedTimer); iconChangedTimer = NULL; iconChangedTimer = SDL_AddTimer(1000, gmenu2x->input.wakeUp, (void*)false); } + if ( + !iconTitle.empty() && + (gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[UP] || gmenu2x->input[DOWN]) + ) { + gmenu2x->allyTTS(iconTitle.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + } if (gmenu2x->skinConfInt["sectionLabel"] && (gmenu2x->input[SECTION_PREV] || gmenu2x->input[SECTION_NEXT])) { section_changed = SDL_GetTicks(); SDL_RemoveTimer(sectionChangedTimer); sectionChangedTimer = NULL; sectionChangedTimer = SDL_AddTimer(2000, gmenu2x->input.wakeUp, (void*)false); + gmenu2x->allyTTS(readSection.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } } } diff --git a/src/menu.h b/src/menu.h index 107bf60..122c248 100644 --- a/src/menu.h +++ b/src/menu.h @@ -40,6 +40,7 @@ Handles the menu structure class Menu { private: GMenu2X *gmenu2x; + int iSection, iLink; int32_t iFirstDispSection, iFirstDispRow; vector sections; @@ -54,6 +55,9 @@ class Menu { int8_t brightnessIcon = 5; string iconDescription = ""; + string iconTitle = ""; + + string readSection = ""; SDL_TimerID sectionChangedTimer, iconChangedTimer; @@ -90,6 +94,7 @@ class Menu { bool addSection(const string §ionName); void deleteSelectedLink(); void deleteSelectedSection(); + bool allyRead = false; void loadIcons(); bool linkChangeSection(uint32_t linkIndex, uint32_t oldSectionIndex, uint32_t newSectionIndex); diff --git a/src/menusetting.h b/src/menusetting.h index de16ada..7c9f2f7 100644 --- a/src/menusetting.h +++ b/src/menusetting.h @@ -44,6 +44,7 @@ class MenuSetting { virtual void drawSelected(int y); virtual bool edited() = 0; + const std::string &getTitle() { return title; }; const std::string &getDescription() { return description; } }; diff --git a/src/menusettingbool.cpp b/src/menusettingbool.cpp index 162c43e..3d7cf6b 100644 --- a/src/menusettingbool.cpp +++ b/src/menusettingbool.cpp @@ -25,7 +25,7 @@ MenuSettingBool::MenuSettingBool(GMenu2X *gmenu2x, const string &title, const st MenuSetting(gmenu2x, title, description), _ivalue(value) { _value = NULL; originalValue = *value != 0; - setValue(this->value()); + setValue(this->value(), 0); initButton(); } @@ -33,7 +33,7 @@ MenuSettingBool::MenuSettingBool(GMenu2X *gmenu2x, const string &title, const st MenuSetting(gmenu2x, title, description), _value(value) { _ivalue = NULL; originalValue = *value; - setValue(this->value()); + setValue(this->value(), 0); initButton(); } @@ -61,23 +61,29 @@ uint32_t MenuSettingBool::manageInput() { if (gmenu2x->input[LEFT] || gmenu2x->input[RIGHT] || gmenu2x->input[CONFIRM] || gmenu2x->input.hatEvent(DLEFT) == DLEFT || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT) toggle(); + else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); return 0; // SD_NO_ACTION } void MenuSettingBool::toggle() { - setValue(!value()); + setValue(!value(), 1); +} + +void MenuSettingBool::current() { + setValue(value(), 1); } void MenuSettingBool::setValue(int value) { setValue(value != 0); } -void MenuSettingBool::setValue(bool value) { +void MenuSettingBool::setValue(bool value, bool readValue) { if (_value == NULL) *_ivalue = value; else *_value = value; strvalue = value ? "ON" : "OFF"; + if (readValue) gmenu2x->allyTTS(strvalue.c_str(), SLOW_GAP_TTS, SLOW_SPEED_TTS, 0); } bool MenuSettingBool::value() { diff --git a/src/menusettingbool.h b/src/menusettingbool.h index 2869615..843f7ca 100644 --- a/src/menusettingbool.h +++ b/src/menusettingbool.h @@ -44,8 +44,9 @@ class MenuSettingBool : public MenuSetting { virtual bool edited(); void setValue(int value); - void setValue(bool value); + void setValue(bool value, bool readValue); bool value(); + void current(); }; #endif diff --git a/src/menusettingdatetime.cpp b/src/menusettingdatetime.cpp index e567276..e6651b3 100644 --- a/src/menusettingdatetime.cpp +++ b/src/menusettingdatetime.cpp @@ -86,6 +86,7 @@ uint32_t MenuSettingDateTime::manageInput() { if (gmenu2x->input[SETTINGS]) return 0; if (gmenu2x->input[INC] || gmenu2x->input[UP] || gmenu2x->input.hatEvent(DUP) == DUP) inc(); else if (gmenu2x->input[DEC] || gmenu2x->input[DOWN] || gmenu2x->input.hatEvent(DDOWN) == DDOWN) dec(); + else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); else if (gmenu2x->input[LEFT] || gmenu2x->input.hatEvent(DLEFT) == DLEFT) leftComponent(); else if (gmenu2x->input[RIGHT] || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT) rightComponent(); else if (gmenu2x->input[CONFIRM] || gmenu2x->input[CANCEL]) { @@ -96,6 +97,8 @@ uint32_t MenuSettingDateTime::manageInput() { buttonBox.add(btn); } return -1; + } else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) { + current(); } else if (gmenu2x->input[CONFIRM]) { editing = true; @@ -119,6 +122,10 @@ void MenuSettingDateTime::inc() { setSelPart(getSelPart() + 1); } +void MenuSettingDateTime::current() { + setSelPart(getSelPart()); +} + void MenuSettingDateTime::leftComponent() { selPart = constrain(selPart - 1, 0, 4); } @@ -180,6 +187,7 @@ void MenuSettingDateTime::setSelPart(uint16_t i) { } *_value = year + "-" + month + "-" + day + " " + hour + ":" + minute; + gmenu2x->allyTTS(value().c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } string MenuSettingDateTime::value() { diff --git a/src/menusettingdatetime.h b/src/menusettingdatetime.h index 932ae23..8b15a49 100644 --- a/src/menusettingdatetime.h +++ b/src/menusettingdatetime.h @@ -36,6 +36,7 @@ class MenuSettingDateTime : public MenuSetting { void dec(); void inc(); + void current(); void leftComponent(); void rightComponent(); diff --git a/src/menusettingint.cpp b/src/menusettingint.cpp index 4887289..49d33bd 100644 --- a/src/menusettingint.cpp +++ b/src/menusettingint.cpp @@ -30,7 +30,7 @@ using fastdelegate::MakeDelegate; MenuSettingInt::MenuSettingInt(GMenu2X *gmenu2x, const string &title, const string &description, int *value, int def, int min, int max, int delta): MenuSetting(gmenu2x, title, description), _value(value), def(def), min(min), max(max), delta(delta), off(false) { originalValue = *value; - setValue(evalIntConf(value, def, min, max)); + setValue(evalIntConf(value, def, min, max), 0); //Delegates // ButtonAction actionInc = MakeDelegate(this, &MenuSettingInt::inc); @@ -63,21 +63,27 @@ void MenuSettingInt::draw(int y) { uint32_t MenuSettingInt::manageInput() { if (gmenu2x->input[LEFT] || gmenu2x->input.hatEvent(DLEFT) == DLEFT) dec(); else if (gmenu2x->input[RIGHT] || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT) inc(); - else if (gmenu2x->input[DEC]) setValue(value() - 10 * delta); - else if (gmenu2x->input[INC]) setValue(value() + 10 * delta); - else if (gmenu2x->input[MENU]) setDefault(); + else if (gmenu2x->input[DEC]) setValue(value() - 10 * delta, 1); + else if (gmenu2x->input[INC]) setValue(value() + 10 * delta, 1); + else if (gmenu2x->input[MENU]) setDefault(); + else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); + return 0; // SD_NO_ACTION } void MenuSettingInt::inc() { - setValue(value() + delta); + setValue(value() + delta, 1); } void MenuSettingInt::dec() { - setValue(value() - delta); + setValue(value() - delta, 1); +} + +void MenuSettingInt::current() { + setValue(*_value, 1); } -void MenuSettingInt::setValue(int value) { +void MenuSettingInt::setValue(int value, bool readValue) { if (off && *_value < value && value <= offValue) *_value = offValue + 1; else if (off && *_value > value && value <= offValue) @@ -92,10 +98,11 @@ void MenuSettingInt::setValue(int value) { ss << *_value; strvalue = ""; ss >> strvalue; + if (readValue) gmenu2x->allyTTS(strvalue.c_str(), SLOW_GAP_TTS, SLOW_SPEED_TTS, 0); } void MenuSettingInt::setDefault() { - setValue(def); + setValue(def, 1); } int MenuSettingInt::value() { @@ -110,4 +117,4 @@ MenuSettingInt *MenuSettingInt::setOff(int value) { off = true; offValue = constrain(value,min,max); return this; -} \ No newline at end of file +} diff --git a/src/menusettingint.h b/src/menusettingint.h index 194231b..3224f25 100644 --- a/src/menusettingint.h +++ b/src/menusettingint.h @@ -30,9 +30,9 @@ class MenuSettingInt : public MenuSetting { int def, min, max, delta; bool off=false; int offValue; - void inc(); void dec(); + void current(); public: MenuSettingInt(GMenu2X *gmenu2x, const std::string &title, const std::string &description, int *value, int def, int min, int max, int delta=1); @@ -42,7 +42,7 @@ class MenuSettingInt : public MenuSetting { virtual void draw(int); virtual bool edited(); - virtual void setValue(int value); + virtual void setValue(int value, bool readValue); virtual void setDefault(); int value(); diff --git a/src/menusettingmultiint.cpp b/src/menusettingmultiint.cpp index 446cfbb..0bf5d20 100644 --- a/src/menusettingmultiint.cpp +++ b/src/menusettingmultiint.cpp @@ -41,7 +41,7 @@ MenuSettingMultiInt::MenuSettingMultiInt(GMenu2X *gmenu2x, const string &title, this->min = min; this->max = max; - setValue(evalIntConf(choices[selection], def, min, max)); + setValue(evalIntConf(choices[selection], def, min, max), 0); //Delegates ButtonAction actionInc = MakeDelegate(this, &MenuSettingMultiInt::inc); @@ -71,6 +71,7 @@ uint32_t MenuSettingMultiInt::manageInput() { if ( gmenu2x->input[DEC] ) dec2x(); if ( gmenu2x->input[INC] ) inc2x(); if ( gmenu2x->input[MENU] ) setDefault(); + if ( gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); return 0; // SD_NO_ACTION } @@ -89,48 +90,53 @@ int MenuSettingMultiInt::reverseLookup(int value) { void MenuSettingMultiInt::inc() { if (selection < selection_max && choices[selection + 1] <= max) { selection = selection + 1; - setValue(choices[selection]); + setValue(choices[selection], 1); } } void MenuSettingMultiInt::inc2x() { if (selection < selection_max && ((choices[selection + 1] < max) || (choices[selection + 2] == max))) { selection = selection + 2; - setValue(choices[selection]); + setValue(choices[selection], 1); } else if (selection < selection_max && choices[selection + 1] == max) { selection = selection + 1; - setValue(choices[selection]); + setValue(choices[selection], 1); } } void MenuSettingMultiInt::dec() { if (selection > 0 && choices[selection - 1] >= min) { selection = selection - 1; - setValue(choices[selection]); + setValue(choices[selection], 1); } } void MenuSettingMultiInt::dec2x() { if (selection > 0 && ((choices[selection - 1] > min) || (choices[selection - 2] == min))) { selection = selection - 2; - setValue(choices[selection]); + setValue(choices[selection], 1); } else if (selection > 0 && choices[selection - 1] == min) { selection = selection - 1; - setValue(choices[selection]); + setValue(choices[selection], 1); } } -void MenuSettingMultiInt::setValue(int value) { +void MenuSettingMultiInt::current() { + setValue(*_value, 1); +} + +void MenuSettingMultiInt::setValue(int value, bool readValue) { *_value = value; stringstream ss; ss << *_value; strvalue = ""; ss >> strvalue; + if (readValue) gmenu2x->allyTTS(strvalue.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } void MenuSettingMultiInt::setDefault() { selection = reverseLookup(def); - setValue(choices[selection]); + setValue(choices[selection], 1); } int MenuSettingMultiInt::value() { diff --git a/src/menusettingmultiint.h b/src/menusettingmultiint.h index 4e701d9..0f74a9c 100644 --- a/src/menusettingmultiint.h +++ b/src/menusettingmultiint.h @@ -34,6 +34,7 @@ class MenuSettingMultiInt : public MenuSetting { void dec(); void inc2x(); void dec2x(); + void current(); int *choices; int reverseLookup(int value); @@ -47,7 +48,7 @@ class MenuSettingMultiInt : public MenuSetting { virtual void draw(int); virtual bool edited(); - virtual void setValue(int value); + virtual void setValue(int value, bool readValue); virtual void setDefault(); int value(); diff --git a/src/menusettingmultistring.cpp b/src/menusettingmultistring.cpp index e228da5..09b7608 100644 --- a/src/menusettingmultistring.cpp +++ b/src/menusettingmultistring.cpp @@ -25,7 +25,7 @@ using std::find; MenuSettingMultiString::MenuSettingMultiString(GMenu2X *gmenu2x, const string &title, const string &description, string *value, const vector *choices, msms_onchange_t onChange, msms_onselect_t onSelect): MenuSettingStringBase(gmenu2x, title, description, value), choices(choices), onChange(onChange), onSelect(onSelect) { - setSel(find(choices->begin(), choices->end(), *value) - choices->begin()); + setSel(find(choices->begin(), choices->end(), *value) - choices->begin(), 0); if (choices->size() > 1) { btn = new IconButton(gmenu2x, "dpad", gmenu2x->tr["Change"]); @@ -53,22 +53,29 @@ uint32_t MenuSettingMultiString::manageInput() { this->onSelect(); return this->onChange && this->onChange(); } + else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) { + currentSel(); + } else if (gmenu2x->input[MENU]) { - setSel(0); + setSel(0, 1); return this->onChange && this->onChange(); } return 0; // SD_NO_ACTION } void MenuSettingMultiString::incSel() { - setSel(selected + 1); + setSel(selected + 1, 1); } void MenuSettingMultiString::decSel() { - setSel(selected - 1); + setSel(selected - 1, 1); +} + +void MenuSettingMultiString::currentSel() { + setSel(selected, 1); } -void MenuSettingMultiString::setSel(int sel) { +void MenuSettingMultiString::setSel(int sel, bool readValue) { if (sel < 0) { sel = choices->size()-1; } else if (sel >= (int)choices->size()) { @@ -77,6 +84,8 @@ void MenuSettingMultiString::setSel(int sel) { selected = sel; setValue((*choices)[sel]); + + if (readValue) gmenu2x->allyTTS(value().c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } void MenuSettingMultiString::draw(int y) { diff --git a/src/menusettingmultistring.h b/src/menusettingmultistring.h index 0e6a184..7537da1 100644 --- a/src/menusettingmultistring.h +++ b/src/menusettingmultistring.h @@ -43,7 +43,8 @@ class MenuSettingMultiString : public MenuSettingStringBase { void incSel(); void decSel(); - void setSel(int sel); + void setSel(int sel, bool readValue); + void currentSel(); msms_onchange_t onChange; msms_onselect_t onSelect; // variable to store function pointer type diff --git a/src/menusettingrgba.cpp b/src/menusettingrgba.cpp index 15dcbbc..ff72d76 100644 --- a/src/menusettingrgba.cpp +++ b/src/menusettingrgba.cpp @@ -73,6 +73,7 @@ uint32_t MenuSettingRGBA::manageInput() { if (gmenu2x->input[SETTINGS]) return 0; if (gmenu2x->input[INC] || gmenu2x->input[UP] || gmenu2x->input.hatEvent(DUP) == DUP) inc(); else if (gmenu2x->input[DEC] || gmenu2x->input[DOWN] || gmenu2x->input.hatEvent(DDOWN) == DDOWN) dec(); + else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); else if (gmenu2x->input[LEFT] || gmenu2x->input.hatEvent(DLEFT) == DLEFT) leftComponent(); else if (gmenu2x->input[RIGHT] || gmenu2x->input.hatEvent(DRIGHT) == DRIGHT) rightComponent(); else if (gmenu2x->input[CONFIRM] || gmenu2x->input[CANCEL]) { @@ -83,6 +84,8 @@ uint32_t MenuSettingRGBA::manageInput() { buttonBox.add(btn); } return -1; + } else if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) { + current(); } else if (gmenu2x->input[CONFIRM]) { editing = true; @@ -118,6 +121,10 @@ void MenuSettingRGBA::inc() { setSelPart(constrain(getSelPart()+1,0,255)); } +void MenuSettingRGBA::current() { + setSelPart(getSelPart()); +} + void MenuSettingRGBA::leftComponent() { selPart = constrain(selPart-1,0,3); } @@ -157,6 +164,8 @@ void MenuSettingRGBA::setSelPart(uint16_t value) { case 3: setA(value); break; default: setR(value); break; } + string readRGBA = gmenu2x->tr["RGBA values are "] + strR + " " + strG + " " + strB + " " + strA; + gmenu2x->allyTTS(readRGBA.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } RGBAColor MenuSettingRGBA::value() { diff --git a/src/menusettingrgba.h b/src/menusettingrgba.h index 098bd01..d1ba428 100644 --- a/src/menusettingrgba.h +++ b/src/menusettingrgba.h @@ -36,6 +36,7 @@ class MenuSettingRGBA : public MenuSetting { void dec(); void inc(); + void current(); void leftComponent(); void rightComponent(); diff --git a/src/menusettingstring.cpp b/src/menusettingstring.cpp index a58a18d..2997b9c 100644 --- a/src/menusettingstring.cpp +++ b/src/menusettingstring.cpp @@ -38,4 +38,5 @@ MenuSettingStringBase(gmenu2x, title, description, value), dialogTitle(dialogTit void MenuSettingString::edit() { InputDialog id(gmenu2x, /*gmenu2x->ts,*/ description, value(), dialogTitle, dialogIcon); if (id.exec()) setValue(id.getInput()); + gmenu2x->allyTTS(value().c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); } diff --git a/src/menusettingstringbase.cpp b/src/menusettingstringbase.cpp index 7644c0a..292914e 100644 --- a/src/menusettingstringbase.cpp +++ b/src/menusettingstringbase.cpp @@ -36,6 +36,7 @@ void MenuSettingStringBase::draw(int y) { uint32_t MenuSettingStringBase::manageInput() { if (gmenu2x->input[MENU]) clear(); if (gmenu2x->input[CONFIRM]) edit(); + if (gmenu2x->input[MODIFIER] && !gmenu2x->input[MANUAL]) current(); return 0; // SD_NO_ACTION } @@ -43,6 +44,10 @@ void MenuSettingStringBase::clear() { setValue(""); } +void MenuSettingStringBase::current() { + gmenu2x->allyTTS(value().c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); +} + bool MenuSettingStringBase::edited() { return originalValue != value(); } diff --git a/src/menusettingstringbase.h b/src/menusettingstringbase.h index fcbb342..04f9fec 100644 --- a/src/menusettingstringbase.h +++ b/src/menusettingstringbase.h @@ -29,6 +29,7 @@ class MenuSettingStringBase : public MenuSetting { virtual void edit() = 0; void clear(); + void current(); public: MenuSettingStringBase( diff --git a/src/messagebox.cpp b/src/messagebox.cpp index 19146ed..396201e 100644 --- a/src/messagebox.cpp +++ b/src/messagebox.cpp @@ -68,6 +68,8 @@ gmenu2x(gmenu2x) { } do { + string readOption = options[selected].text; + gmenu2x->allyTTS(readOption.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); inputAction = gmenu2x->input.update(); if (gmenu2x->inputCommonActions(inputAction)) continue; @@ -247,6 +249,18 @@ int MessageBox::exec() { // } // } + string strButtons, strButtonsText; + + for (uint32_t i = 0; i < buttonText.size(); i++) { + if (buttonText[i] != "") { + if (button[i] == "a") button[i] = "[[eI]]"; //espeak doesn't recognize if it's a letter or article so let us use Phoneme Input for "A" letter + strButtons += " " + button[i] + " is " + buttonText[i]; + } + } + string strMessage = text; + string readMessage = strMessage + " " + strButtons; + gmenu2x->allyTTS(readMessage.c_str(), SLOW_GAP_TTS, SLOW_SPEED_TTS, 0); + bool inputAction = gmenu2x->input.update(); if (inputAction) { // if (gmenu2x->inputCommonActions(inputAction)) continue; // causes power button bounce diff --git a/src/platform/linux.h b/src/platform/linux.h index 528ce4b..d3976ee 100644 --- a/src/platform/linux.h +++ b/src/platform/linux.h @@ -3,6 +3,8 @@ #include +#define TTS_ENGINE "espeak" + volatile uint16_t *memregs; uint8_t memdev = 0; int SOUND_MIXER_READ = SOUND_MIXER_READ_PCM; diff --git a/src/platform/miyoo.h b/src/platform/miyoo.h index 56163f4..a8da151 100644 --- a/src/platform/miyoo.h +++ b/src/platform/miyoo.h @@ -58,6 +58,7 @@ #define MIYOO_FB0_FILE "/dev/miyoo_fb0" #define MIYOO_KBD_FILE "/dev/miyoo_kbd" #define MIYOO_VIR_FILE "/dev/miyoo_vir" +#define TTS_ENGINE "espeak" #define MULTI_INT #define DEFAULT_CPU 720 diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index b188b2e..1c330e2 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -36,16 +36,17 @@ SettingsDialog::~SettingsDialog() { bool SettingsDialog::exec() { bool ts_pressed = false, inputAction = false; uint32_t i, iY, firstElement = 0, action = SD_NO_ACTION, rowHeight, numRows; + string readSetting = title + " " + voices[selected]->getTitle() + " " + voices[selected]->getDescription(); + gmenu2x->allyTTS(readSetting.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); while (loop) { + bool ally = false; gmenu2x->menu->initLayout(); gmenu2x->font->setSize(gmenu2x->skinConfInt["fontSize"])->setColor(gmenu2x->skinConfColors[COLOR_FONT])->setOutlineColor(gmenu2x->skinConfColors[COLOR_FONT_OUTLINE]); gmenu2x->titlefont->setSize(gmenu2x->skinConfInt["fontSizeTitle"])->setColor(gmenu2x->skinConfColors[COLOR_FONT_ALT])->setOutlineColor(gmenu2x->skinConfColors[COLOR_FONT_ALT_OUTLINE]); rowHeight = gmenu2x->font->getHeight() + 1; numRows = (gmenu2x->listRect.h - 2)/rowHeight - 1; - if (selected < 0) selected = voices.size() - 1; - if (selected >= voices.size()) selected = 0; gmenu2x->setInputSpeed(); voices[selected]->adjustInput(); @@ -138,21 +139,31 @@ bool SettingsDialog::exec() { } break; case SD_ACTION_UP: + ally = true; selected--; break; case SD_ACTION_DOWN: + ally = true; selected++; break; case SD_ACTION_PAGEUP: + ally = true; selected -= numRows; if (selected < 0) selected = 0; break; case SD_ACTION_PAGEDOWN: + ally = true; selected += numRows; if (selected >= voices.size()) selected = voices.size() - 1; break; } } while (!inputAction); + if (selected < 0) selected = voices.size() - 1; + if (selected >= voices.size()) selected = 0; + if (ally) { + readSetting = voices[selected]->getTitle() + " " + voices[selected]->getDescription(); // read whole text for more clarity + gmenu2x->allyTTS(readSetting.c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 0); + } } gmenu2x->setInputSpeed(); diff --git a/src/terminaldialog.cpp b/src/terminaldialog.cpp index e951af2..1d49e4f 100644 --- a/src/terminaldialog.cpp +++ b/src/terminaldialog.cpp @@ -53,6 +53,8 @@ void TerminalDialog::exec(string cmd) { gmenu2x->powerManager->clearTimer(); + gmenu2x->allyTTS(gmenu2x->tr["Processing output."].c_str(), MEDIUM_GAP_TTS, MEDIUM_SPEED_TTS, 1); + while (!feof(pipe) && fgets(buffer, 128, pipe) != NULL) { rawText += buffer; split(text, rawText, "\r\n"); @@ -66,6 +68,8 @@ void TerminalDialog::exec(string cmd) { MessageBox mb(gmenu2x, gmenu2x->tr["Done processing."]); mb.setAutoHide(0); + string readText = gmenu2x->tr["Done processing."] + /*PAUSE*/ "[[_::_::]]" + gmenu2x->tr["Terminal output as follows"] + /*PAUSE*/ "[[_::_::_::]]" + rawText; + gmenu2x->allyTTS(readText.c_str()); mb.exec(); if (text.size() >= rowsPerPage) firstRow = text.size() - rowsPerPage; diff --git a/src/wallpaperdialog.cpp b/src/wallpaperdialog.cpp index 1bf0610..1b5e6a1 100644 --- a/src/wallpaperdialog.cpp +++ b/src/wallpaperdialog.cpp @@ -81,6 +81,7 @@ bool WallpaperDialog::exec() { } gmenu2x->setBackground(this->bg, "skins/" + skin + "/wallpapers/" + wallpapers[selected]); + gmenu2x->allyTTS(wallpapers[selected].c_str(), FAST_GAP_TTS, FAST_SPEED_TTS, 0); drawDialog(gmenu2x->s); diff --git a/translate.txt b/translate.txt index c6fda4f..66ba5a6 100644 --- a/translate.txt +++ b/translate.txt @@ -10,6 +10,7 @@ Alt= Appearance & skin settings= apps= Are you sure?= +at= Audio volume= Automatic load backdrops from skin pack= Autostart= @@ -69,6 +70,7 @@ Displays last launched program's output= Done processing.= Edit= emus= +Entering Text Dialog editor, press B to exit= Exit= Explorer= favorites= @@ -93,7 +95,9 @@ Hint: Hold 'X' to change Date & Time= Hint: Hold 'Y' to restart GMenu2X= Hint: Press 'Y' now quickly to disable AutoStart= Hint: Press 'Y' now quickly to reset gmenu2x.cfg= +Hint: To read a selected value or Link's description press X= Hint: You can AutoStart any game/app!? See settings= +Hint: You can skip reading a message, by pressing START= Hints= Home path= How to scale wallpaper, backdrops and game art= @@ -153,6 +157,7 @@ Power= Poweroff or reboot the device?= Poweroff= Preview mode= +Processing output.= Reboot= Rebooting= Remember selection= @@ -166,6 +171,7 @@ Reset link's icon back to default= Reset settings= Reset= Restart= +RGBA values are = Run last app on restart= Running.. Please wait..= Save changes?= @@ -224,7 +230,9 @@ Space= Suspend timeout= SW Clock= TEfix method= +Terminal output as follows= Terminal= +Text To Speak= Text viewer= The section this link belongs to= the settings. Continue?= @@ -234,6 +242,7 @@ This section is empty= Title font size= Title= Top/Section Bar= +Typed= Umount external media device= Umount= Uninstall IPK= @@ -245,7 +254,9 @@ Unset link's selector box art path= Unset link's selector directory= Unset link's selector file filters= Use file browser selector= +Use TTS engine to read menu out loud= Wallpaper= +Welcome to GMenu= Yes= Zip content= _about_= @@ -258,3 +269,4 @@ _keyboard_t2_l3_= _keyboard_t3_l1_= _keyboard_t3_l2_= _keyboard_t3_l3_= +_TTS_voice_=