// Cthulhu screen reader. // Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // // This program 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 Foundation, either version 3 of the License, or (at your option) // any later version. // // This program 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 // this program. If not, see . package app import ( "git.stormux.org/storm/cthulhu/internal/config" "git.stormux.org/storm/cthulhu/internal/input" "git.stormux.org/storm/cthulhu/internal/presentation" "git.stormux.org/storm/cthulhu/internal/sound" "git.stormux.org/storm/cthulhu/internal/speech" ) func speechSettingsFromConfig(settings config.Settings) speech.Settings { speechSettings := speech.Settings{ OutputModule: settings.SpeechOutputModule, Punctuation: map[int]string{0: "all", 1: "most", 2: "some", 3: "none"}[settings.VerbalizePunctuationStyle], Capitalization: settings.CapitalizationStyle, } if settings.DefaultVoice.Rate != nil { value := int(2*(*settings.DefaultVoice.Rate) - 98) speechSettings.Rate = &value } if settings.DefaultVoice.AveragePitch != nil { value := int(20*(*settings.DefaultVoice.AveragePitch) - 90) speechSettings.Pitch = &value } if settings.DefaultVoice.Gain != nil { value := int(15*(*settings.DefaultVoice.Gain) - 35) speechSettings.Volume = &value } if family := settings.DefaultVoice.Family; family != nil { speechSettings.Language = family.Lang if family.Dialect != "" { speechSettings.Language += "-" + family.Dialect } speechSettings.SynthesisVoice = family.Name } return speechSettings } func inputEchoSettingsFromConfig(settings config.Settings) input.EchoSettings { return input.EchoSettings{ EnableKeyEcho: settings.EnableKeyEcho, EnableModifierKeys: settings.EnableModifierKeys, EnableFunctionKeys: settings.EnableFunctionKeys, EnableActionKeys: settings.EnableActionKeys, EnableNavigationKeys: settings.EnableNavigationKeys, EnableDiacriticalKeys: settings.EnableDiacriticalKeys, CthulhuModifierKeys: append([]string(nil), settings.CthulhuModifierKeys...), } } func presentationSettingsFromConfig(settings config.Settings, soundEnabled bool) presentation.Options { return presentation.Options{ Reading: &settings.Reading, SpeakDescription: settings.SpeakDescription && !settings.Reading.OnlySpeakDisplayedText, ReadFullRowInGUITable: settings.Reading.ReadFullRowInGUITable, SpeechVerbosityLevel: settings.SpeechVerbosityLevel, SpeakBlankLines: settings.Reading.SpeakBlankLines && !settings.Reading.OnlySpeakDisplayedText, SayAllStyle: settings.SayAllStyle, EnableSound: soundEnabled && soundConfiguration(settings).Enabled, PlaySoundForRole: settings.PlaySoundForRole, PlaySoundForState: settings.PlaySoundForState, RoleSoundPresentation: settings.RoleSoundPresentation, SpatializeObjectSounds: settings.SpatializeObjectSounds, EnableKeyEcho: settings.EnableKeyEcho, EnableEchoByCharacter: settings.EnableEchoByCharacter, EnableEchoByWord: settings.EnableEchoByWord, EnableEchoBySentence: settings.EnableEchoBySentence, EnableAlphabeticKeys: settings.EnableAlphabeticKeys, EnableNumericKeys: settings.EnableNumericKeys, EnablePunctuationKeys: settings.EnablePunctuationKeys, EnableSpace: settings.EnableSpace, EnableDiacriticalKeys: settings.EnableDiacriticalKeys, PlaySoundForPositionInSet: settings.PlaySoundForPositionInSet, } } func soundConfiguration(settings config.Settings) sound.Configuration { return sound.Configuration{ Enabled: settings.EnableSound && settings.SoundTheme != "none" && settings.SoundVolume > 0, Sink: settings.SoundSink, Theme: settings.SoundTheme, Volume: settings.SoundVolume, } } func captureSoundGeometry(settings config.Settings) bool { return soundConfiguration(settings).Enabled && settings.SpatializeObjectSounds && (settings.PlaySoundForRole || settings.PlaySoundForState || settings.PlaySoundForPositionInSet) } func captureTextAttributes(settings config.Settings) bool { if !settings.EnableBraille || settings.TextAttributes.Indicator == 0 { return false } for _, choice := range settings.TextAttributes.Choices { if choice.Braille { return true } } return false }