Files
cthulhu/internal/config/profile_mapping.go

577 lines
24 KiB
Go

// 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 <https://www.gnu.org/licenses/gpl-3.0.html>.
package config
import (
"reflect"
"git.stormux.org/storm/cthulhu/internal/datetime"
"git.stormux.org/storm/cthulhu/internal/input"
)
// Application profiles store only values that differ from the global profile.
// The writable schema is made of nested value structs and pointer fields, so
// clearing equal leaves preserves its existing patch semantics.
func applicationProfileDifference(global, application Settings) writableProfile {
base := profileFromSettings(global)
result := profileFromSettings(application)
clearEqualProfileFields(reflect.ValueOf(&result).Elem(), reflect.ValueOf(base))
return result
}
func clearEqualProfileFields(result, base reflect.Value) {
for index := 0; index < result.NumField(); index++ {
field, baseline := result.Field(index), base.Field(index)
if field.Kind() == reflect.Struct {
clearEqualProfileFields(field, baseline)
} else if reflect.DeepEqual(field.Interface(), baseline.Interface()) {
field.SetZero()
}
}
}
// RebaseApplicationSettings keeps session-only application choices when the
// global profile changes, while newly inherited values follow the new global.
func RebaseApplicationSettings(oldGlobal, newGlobal, application Settings) Settings {
patch := applicationProfileDifference(oldGlobal, application)
rebased := newGlobal
applyProfile(&rebased, patch)
rebased.ActiveProfile = application.ActiveProfile
return rebased
}
func profileFromSettings(settings Settings) writableProfile {
return writableProfile{
OCR: writableOCR{Language: stringPointer(settings.OCR.Language), Layout: intPointer(settings.OCR.Layout), Scale: intPointer(settings.OCR.Scale), Grayscale: boolPointer(settings.OCR.Grayscale), Invert: boolPointer(settings.OCR.Invert), BlackWhite: boolPointer(settings.OCR.BlackWhite), Threshold: intPointer(settings.OCR.Threshold), AutoRefresh: boolPointer(settings.OCR.AutoRefresh), RefreshInterval: intPointer(settings.OCR.RefreshInterval), ConfirmClick: boolPointer(settings.OCR.ConfirmClick), CopyFirstResult: boolPointer(settings.OCR.CopyFirstResult), AutoReadAll: boolPointer(settings.OCR.AutoReadAll)},
ProgressBar: writableProgressBar{
OutputMode: stringPointer(settings.ProgressBar.OutputMode),
ReportBackground: boolPointer(settings.ProgressBar.ReportBackground),
BeepPercentageInterval: intPointer(settings.ProgressBar.BeepPercentageInterval),
SpeechPercentageInterval: intPointer(settings.ProgressBar.SpeechPercentageInterval),
},
Presentation: writablePresentation{
Pronunciations: pronunciationSlicePointer(settings.Pronunciations),
TextAttributes: writableTextAttributes{Choices: textAttributeSlicePointer(settings.TextAttributes.Choices), Indicator: intPointer(settings.TextAttributes.Indicator)},
TimeFormat: stringPointer(settings.TimeFormat), DateFormat: stringPointer(settings.DateFormat),
SpeakDescription: boolPointer(settings.SpeakDescription),
SpeechVerbosityLevel: intPointer(settings.SpeechVerbosityLevel),
SayAllStyle: stringPointer(settings.SayAllStyle),
Reading: writableReading{
AutomaticallyReadClipboardChanges: boolPointer(settings.Reading.AutomaticallyReadClipboardChanges),
AutomaticallyReadTitleChanges: boolPointer(settings.Reading.AutomaticallyReadTitleChanges),
EnablePauseBreaks: boolPointer(settings.Reading.EnablePauseBreaks),
SpeakNumbersAsDigits: boolPointer(settings.Reading.SpeakNumbersAsDigits),
SpeakMultiCaseStringsAsWords: boolPointer(settings.Reading.SpeakMultiCaseStringsAsWords),
EnableIndentation: boolPointer(settings.Reading.EnableIndentation),
IndentationPresentationMode: stringPointer(settings.Reading.IndentationPresentationMode),
OnlySpeakDisplayedText: boolPointer(settings.Reading.OnlySpeakDisplayedText),
SpeakBlankLines: boolPointer(settings.Reading.SpeakBlankLines),
EnableMnemonicSpeaking: boolPointer(settings.Reading.EnableMnemonicSpeaking),
EnablePositionSpeaking: boolPointer(settings.Reading.EnablePositionSpeaking),
EnableTutorialMessages: boolPointer(settings.Reading.EnableTutorialMessages),
MessagesAreDetailed: boolPointer(settings.Reading.MessagesAreDetailed),
UseColorNames: boolPointer(settings.Reading.UseColorNames),
PresentTooltips: boolPointer(settings.Reading.PresentTooltips),
EnableMouseReview: boolPointer(settings.Reading.EnableMouseReview),
SpeakMisspelledIndicator: boolPointer(settings.Reading.SpeakMisspelledIndicator),
SpeakContextBlockquote: boolPointer(settings.Reading.SpeakContextBlockquote),
SpeakContextList: boolPointer(settings.Reading.SpeakContextList),
SpeakContextTable: boolPointer(settings.Reading.SpeakContextTable),
SpeakContextPanel: boolPointer(settings.Reading.SpeakContextPanel),
SpeakContextLandmark: boolPointer(settings.Reading.SpeakContextLandmark),
SpeakContextNonLandmarkForm: boolPointer(settings.Reading.SpeakContextNonLandmarkForm),
SayAllContextBlockquote: boolPointer(settings.Reading.SayAllContextBlockquote),
SayAllContextList: boolPointer(settings.Reading.SayAllContextList),
SayAllContextTable: boolPointer(settings.Reading.SayAllContextTable),
SayAllContextPanel: boolPointer(settings.Reading.SayAllContextPanel),
SayAllContextLandmark: boolPointer(settings.Reading.SayAllContextLandmark),
SayAllContextNonLandmarkForm: boolPointer(settings.Reading.SayAllContextNonLandmarkForm),
ReadFullRowInGUITable: boolPointer(settings.Reading.ReadFullRowInGUITable),
ReadFullRowInDocumentTable: boolPointer(settings.Reading.ReadFullRowInDocumentTable),
ReadFullRowInSpreadSheet: boolPointer(settings.Reading.ReadFullRowInSpreadSheet),
},
},
Speech: writableSpeech{
HardwareDevice: stringPointer(settings.HardwareSpeechDevice),
HardwareBaudRate: intPointer(settings.HardwareSpeechBaudRate),
Enabled: boolPointer(settings.EnableSpeech), ServerFactory: stringPointer(settings.SpeechServerFactory),
HistoryLimit: intPointer(settings.SpeechHistoryLimit),
Punctuation: intPointer(settings.VerbalizePunctuationStyle), Capitalization: stringPointer(settings.CapitalizationStyle),
DefaultVoice: voicePointer(settings.DefaultVoice),
UppercaseVoice: voicePointer(settings.UppercaseVoice),
HyperlinkVoice: voicePointer(settings.HyperlinkVoice),
SystemVoice: voicePointer(settings.SystemVoice),
OutputModule: stringPointer(settings.SpeechOutputModule),
},
Braille: writableBraille{Enabled: boolPointer(settings.EnableBraille),
Contracted: boolPointer(settings.EnableContractedBraille),
ContractionTable: stringPointer(settings.BrailleContractionTable),
AbbreviateRoles: boolPointer(settings.Braille.AbbreviateRoles),
DisableEOL: boolPointer(settings.Braille.DisableEOL), WordWrap: boolPointer(settings.Braille.WordWrap),
Verbosity: intPointer(settings.Braille.Verbosity), SelectionIndicator: intPointer(settings.Braille.SelectionIndicator),
LinkIndicator: intPointer(settings.Braille.LinkIndicator), FlashMessages: boolPointer(settings.Braille.FlashMessages),
FlashTime: intPointer(settings.Braille.FlashTime), FlashPersistent: boolPointer(settings.Braille.FlashPersistent),
FlashDetailed: boolPointer(settings.Braille.FlashDetailed)},
Sound: writableSound{
Enabled: boolPointer(settings.EnableSound), Volume: floatPointer(settings.SoundVolume),
Sink: stringPointer(settings.SoundSink), Theme: stringPointer(settings.SoundTheme),
PlayForRole: boolPointer(settings.PlaySoundForRole), PlayForState: boolPointer(settings.PlaySoundForState),
PlayForPosition: boolPointer(settings.PlaySoundForPositionInSet),
Spatialize: boolPointer(settings.SpatializeObjectSounds),
RolePresentationStrategy: stringPointer(settings.RoleSoundPresentation),
},
Keyboard: writableKeyboard{
Bindings: bindingSlicePointer(settings.KeyBindings),
Layout: intPointer(settings.KeyboardLayout),
ScreenReaderKeys: stringSlicePointer(settings.CthulhuModifierKeys),
},
KeyEcho: writableKeyEcho{
UseCustomEchoVoice: boolPointer(settings.UseCustomEchoVoice),
UseCustomEchoSpeechServer: boolPointer(settings.UseCustomEchoSpeechServer),
UseCustomEchoForKey: boolPointer(settings.UseCustomEchoForKey),
UseCustomEchoForCharacter: boolPointer(settings.UseCustomEchoForCharacter),
UseCustomEchoForWord: boolPointer(settings.UseCustomEchoForWord),
UseCustomEchoForSentence: boolPointer(settings.UseCustomEchoForSentence),
EchoVoice: voicePointer(settings.EchoVoice), EchoSpeechServer: stringPointer(settings.EchoSpeechServer),
Enabled: boolPointer(settings.EnableKeyEcho), ByCharacter: boolPointer(settings.EnableEchoByCharacter),
ByWord: boolPointer(settings.EnableEchoByWord), BySentence: boolPointer(settings.EnableEchoBySentence),
Alphabetic: boolPointer(settings.EnableAlphabeticKeys), Numeric: boolPointer(settings.EnableNumericKeys),
Punctuation: boolPointer(settings.EnablePunctuationKeys), Space: boolPointer(settings.EnableSpace),
Modifiers: boolPointer(settings.EnableModifierKeys), FunctionKeys: boolPointer(settings.EnableFunctionKeys),
ActionKeys: boolPointer(settings.EnableActionKeys), NavigationKeys: boolPointer(settings.EnableNavigationKeys),
Diacritical: boolPointer(settings.EnableDiacriticalKeys),
},
}
}
func applyProfile(settings *Settings, profile writableProfile) {
apply_profile_ocr(&settings.OCR, profile.OCR)
// Keep the established patch order; absent fields leave prior values intact.
apply_profile_formats(settings, profile)
apply_profile_echo_voice(settings, profile)
apply_profile_reading(settings, profile)
apply_profile_output(settings, profile)
apply_profile_speech(settings, profile)
apply_profile_sound(settings, profile)
if value := profile.ProgressBar.OutputMode; value != nil {
settings.ProgressBar.OutputMode = *value
}
if value := profile.ProgressBar.ReportBackground; value != nil {
settings.ProgressBar.ReportBackground = *value
}
if value := profile.ProgressBar.BeepPercentageInterval; value != nil {
settings.ProgressBar.BeepPercentageInterval = *value
}
if value := profile.ProgressBar.SpeechPercentageInterval; value != nil {
settings.ProgressBar.SpeechPercentageInterval = *value
}
apply_profile_keyboard(settings, profile)
apply_profile_echo_keys(settings, profile)
}
func apply_profile_ocr(settings *OCRSettings, patch writableOCR) {
if patch.Language != nil {
settings.Language = *patch.Language
}
if patch.Layout != nil {
settings.Layout = *patch.Layout
}
if patch.Scale != nil {
settings.Scale = *patch.Scale
}
if patch.Grayscale != nil {
settings.Grayscale = *patch.Grayscale
}
if patch.Invert != nil {
settings.Invert = *patch.Invert
}
if patch.BlackWhite != nil {
settings.BlackWhite = *patch.BlackWhite
}
if patch.Threshold != nil {
settings.Threshold = *patch.Threshold
}
if patch.AutoRefresh != nil {
settings.AutoRefresh = *patch.AutoRefresh
}
if patch.RefreshInterval != nil {
settings.RefreshInterval = *patch.RefreshInterval
}
if patch.ConfirmClick != nil {
settings.ConfirmClick = *patch.ConfirmClick
}
if patch.CopyFirstResult != nil {
settings.CopyFirstResult = *patch.CopyFirstResult
}
if patch.AutoReadAll != nil {
settings.AutoReadAll = *patch.AutoReadAll
}
}
func apply_profile_formats(settings *Settings, profile writableProfile) {
if v := profile.Presentation.TimeFormat; v != nil {
settings.TimeFormat = *v
}
if v := profile.Presentation.DateFormat; v != nil {
settings.DateFormat = datetime.NormalizeDate(*v)
}
}
func apply_profile_echo_voice(settings *Settings, profile writableProfile) {
if v := profile.KeyEcho.UseCustomEchoVoice; v != nil {
settings.UseCustomEchoVoice = *v
}
if v := profile.KeyEcho.UseCustomEchoSpeechServer; v != nil {
settings.UseCustomEchoSpeechServer = *v
}
if v := profile.KeyEcho.UseCustomEchoForKey; v != nil {
settings.UseCustomEchoForKey = *v
}
if v := profile.KeyEcho.UseCustomEchoForCharacter; v != nil {
settings.UseCustomEchoForCharacter = *v
}
if v := profile.KeyEcho.UseCustomEchoForWord; v != nil {
settings.UseCustomEchoForWord = *v
}
if v := profile.KeyEcho.UseCustomEchoForSentence; v != nil {
settings.UseCustomEchoForSentence = *v
}
if v := profile.KeyEcho.EchoVoice; v != nil {
settings.EchoVoice = cloneVoice(*v)
}
if v := profile.KeyEcho.EchoSpeechServer; v != nil {
settings.EchoSpeechServer = *v
}
}
func apply_profile_reading(settings *Settings, profile writableProfile) {
if value := profile.Presentation.Pronunciations; value != nil {
settings.Pronunciations = append([]PronunciationEntry(nil), (*value)...)
}
if value := profile.Presentation.TextAttributes.Choices; value != nil {
settings.TextAttributes.Choices = append([]TextAttributeChoice(nil), (*value)...)
}
if value := profile.Presentation.TextAttributes.Indicator; value != nil {
settings.TextAttributes.Indicator = *value
}
if value := profile.Presentation.SpeakDescription; value != nil {
settings.SpeakDescription = *value
}
if value := profile.Presentation.SpeechVerbosityLevel; value != nil {
settings.SpeechVerbosityLevel = *value
}
if value := profile.Presentation.SayAllStyle; value != nil {
settings.SayAllStyle = *value
}
if value := profile.Presentation.Reading.AutomaticallyReadClipboardChanges; value != nil {
settings.Reading.AutomaticallyReadClipboardChanges = *value
}
if value := profile.Presentation.Reading.AutomaticallyReadTitleChanges; value != nil {
settings.Reading.AutomaticallyReadTitleChanges = *value
}
if value := profile.Presentation.Reading.OnlySpeakDisplayedText; value != nil {
settings.Reading.OnlySpeakDisplayedText = *value
}
if value := profile.Presentation.Reading.EnablePauseBreaks; value != nil {
settings.Reading.EnablePauseBreaks = *value
}
if value := profile.Presentation.Reading.SpeakNumbersAsDigits; value != nil {
settings.Reading.SpeakNumbersAsDigits = *value
}
if value := profile.Presentation.Reading.SpeakMultiCaseStringsAsWords; value != nil {
settings.Reading.SpeakMultiCaseStringsAsWords = *value
}
if value := profile.Presentation.Reading.EnableIndentation; value != nil {
settings.Reading.EnableIndentation = *value
}
if value := profile.Presentation.Reading.IndentationPresentationMode; value != nil {
settings.Reading.IndentationPresentationMode = *value
}
if value := profile.Presentation.Reading.SpeakBlankLines; value != nil {
settings.Reading.SpeakBlankLines = *value
}
if value := profile.Presentation.Reading.EnableMnemonicSpeaking; value != nil {
settings.Reading.EnableMnemonicSpeaking = *value
}
if value := profile.Presentation.Reading.EnablePositionSpeaking; value != nil {
settings.Reading.EnablePositionSpeaking = *value
}
if value := profile.Presentation.Reading.EnableTutorialMessages; value != nil {
settings.Reading.EnableTutorialMessages = *value
}
if value := profile.Presentation.Reading.MessagesAreDetailed; value != nil {
settings.Reading.MessagesAreDetailed = *value
}
if value := profile.Presentation.Reading.UseColorNames; value != nil {
settings.Reading.UseColorNames = *value
}
if value := profile.Presentation.Reading.PresentTooltips; value != nil {
settings.Reading.PresentTooltips = *value
}
if value := profile.Presentation.Reading.EnableMouseReview; value != nil {
settings.Reading.EnableMouseReview = *value
}
if value := profile.Presentation.Reading.SpeakMisspelledIndicator; value != nil {
settings.Reading.SpeakMisspelledIndicator = *value
}
if value := profile.Presentation.Reading.SpeakContextBlockquote; value != nil {
settings.Reading.SpeakContextBlockquote = *value
}
if value := profile.Presentation.Reading.SpeakContextList; value != nil {
settings.Reading.SpeakContextList = *value
}
if value := profile.Presentation.Reading.SpeakContextTable; value != nil {
settings.Reading.SpeakContextTable = *value
}
if value := profile.Presentation.Reading.SpeakContextPanel; value != nil {
settings.Reading.SpeakContextPanel = *value
}
if value := profile.Presentation.Reading.SpeakContextLandmark; value != nil {
settings.Reading.SpeakContextLandmark = *value
}
if value := profile.Presentation.Reading.SpeakContextNonLandmarkForm; value != nil {
settings.Reading.SpeakContextNonLandmarkForm = *value
}
if value := profile.Presentation.Reading.SayAllContextBlockquote; value != nil {
settings.Reading.SayAllContextBlockquote = *value
}
if value := profile.Presentation.Reading.SayAllContextList; value != nil {
settings.Reading.SayAllContextList = *value
}
if value := profile.Presentation.Reading.SayAllContextTable; value != nil {
settings.Reading.SayAllContextTable = *value
}
if value := profile.Presentation.Reading.SayAllContextPanel; value != nil {
settings.Reading.SayAllContextPanel = *value
}
if value := profile.Presentation.Reading.SayAllContextLandmark; value != nil {
settings.Reading.SayAllContextLandmark = *value
}
if value := profile.Presentation.Reading.SayAllContextNonLandmarkForm; value != nil {
settings.Reading.SayAllContextNonLandmarkForm = *value
}
if value := profile.Presentation.Reading.ReadFullRowInGUITable; value != nil {
settings.Reading.ReadFullRowInGUITable = *value
}
if value := profile.Presentation.Reading.ReadFullRowInDocumentTable; value != nil {
settings.Reading.ReadFullRowInDocumentTable = *value
}
if value := profile.Presentation.Reading.ReadFullRowInSpreadSheet; value != nil {
settings.Reading.ReadFullRowInSpreadSheet = *value
}
}
func apply_profile_output(settings *Settings, profile writableProfile) {
if value := profile.Speech.Enabled; value != nil {
settings.EnableSpeech = *value
}
if value := profile.Speech.HistoryLimit; value != nil {
settings.SpeechHistoryLimit = *value
}
if value := profile.Braille.Enabled; value != nil {
settings.EnableBraille = *value
}
if value := profile.Braille.Contracted; value != nil {
settings.EnableContractedBraille = *value
}
if value := profile.Braille.ContractionTable; value != nil {
settings.BrailleContractionTable = *value
}
if value := profile.Braille.AbbreviateRoles; value != nil {
settings.Braille.AbbreviateRoles = *value
}
if value := profile.Braille.DisableEOL; value != nil {
settings.Braille.DisableEOL = *value
}
if value := profile.Braille.WordWrap; value != nil {
settings.Braille.WordWrap = *value
}
if value := profile.Braille.Verbosity; value != nil {
settings.Braille.Verbosity = *value
}
if value := profile.Braille.SelectionIndicator; value != nil {
settings.Braille.SelectionIndicator = *value
}
if value := profile.Braille.LinkIndicator; value != nil {
settings.Braille.LinkIndicator = *value
}
if value := profile.Braille.FlashMessages; value != nil {
settings.Braille.FlashMessages = *value
}
if value := profile.Braille.FlashTime; value != nil {
settings.Braille.FlashTime = *value
}
if value := profile.Braille.FlashPersistent; value != nil {
settings.Braille.FlashPersistent = *value
}
if value := profile.Braille.FlashDetailed; value != nil {
settings.Braille.FlashDetailed = *value
}
}
func apply_profile_speech(settings *Settings, profile writableProfile) {
if value := profile.Speech.HardwareDevice; value != nil {
settings.HardwareSpeechDevice = *value
}
if value := profile.Speech.HardwareBaudRate; value != nil {
settings.HardwareSpeechBaudRate = *value
}
if value := profile.Speech.ServerFactory; value != nil {
settings.SpeechServerFactory = *value
}
if value := profile.Speech.Punctuation; value != nil {
settings.VerbalizePunctuationStyle = *value
}
if value := profile.Speech.Capitalization; value != nil {
settings.CapitalizationStyle = *value
}
if value := profile.Speech.OutputModule; value != nil {
settings.SpeechOutputModule = *value
}
if value := profile.Speech.DefaultVoice; value != nil {
settings.DefaultVoice = cloneVoice(*value)
}
if value := profile.Speech.UppercaseVoice; value != nil {
settings.UppercaseVoice = cloneVoice(*value)
}
if value := profile.Speech.HyperlinkVoice; value != nil {
settings.HyperlinkVoice = cloneVoice(*value)
}
if value := profile.Speech.SystemVoice; value != nil {
settings.SystemVoice = cloneVoice(*value)
}
}
func apply_profile_sound(settings *Settings, profile writableProfile) {
if value := profile.Sound.Enabled; value != nil {
settings.EnableSound = *value
}
if value := profile.Sound.Volume; value != nil {
settings.SoundVolume = *value
}
if value := profile.Sound.Sink; value != nil {
settings.SoundSink = *value
}
if value := profile.Sound.Theme; value != nil {
settings.SoundTheme = *value
}
if value := profile.Sound.PlayForRole; value != nil {
settings.PlaySoundForRole = *value
}
if value := profile.Sound.PlayForState; value != nil {
settings.PlaySoundForState = *value
}
if value := profile.Sound.PlayForPosition; value != nil {
settings.PlaySoundForPositionInSet = *value
}
if value := profile.Sound.Spatialize; value != nil {
settings.SpatializeObjectSounds = *value
}
if value := profile.Sound.RolePresentationStrategy; value != nil {
settings.RoleSoundPresentation = *value
}
}
func apply_profile_keyboard(settings *Settings, profile writableProfile) {
if value := profile.Keyboard.Bindings; value != nil {
settings.KeyBindings = input.CloneBindingOverrides(*value)
}
if value := profile.Keyboard.Layout; value != nil {
settings.KeyboardLayout = *value
}
if value := profile.Keyboard.ScreenReaderKeys; value != nil {
settings.CthulhuModifierKeys = append([]string(nil), (*value)...)
}
}
func apply_profile_echo_keys(settings *Settings, profile writableProfile) {
if value := profile.KeyEcho.Enabled; value != nil {
settings.EnableKeyEcho = *value
}
if value := profile.KeyEcho.ByCharacter; value != nil {
settings.EnableEchoByCharacter = *value
}
if value := profile.KeyEcho.ByWord; value != nil {
settings.EnableEchoByWord = *value
}
if value := profile.KeyEcho.BySentence; value != nil {
settings.EnableEchoBySentence = *value
}
if value := profile.KeyEcho.Alphabetic; value != nil {
settings.EnableAlphabeticKeys = *value
}
if value := profile.KeyEcho.Numeric; value != nil {
settings.EnableNumericKeys = *value
}
if value := profile.KeyEcho.Punctuation; value != nil {
settings.EnablePunctuationKeys = *value
}
if value := profile.KeyEcho.Space; value != nil {
settings.EnableSpace = *value
}
if value := profile.KeyEcho.Modifiers; value != nil {
settings.EnableModifierKeys = *value
}
if value := profile.KeyEcho.FunctionKeys; value != nil {
settings.EnableFunctionKeys = *value
}
if value := profile.KeyEcho.ActionKeys; value != nil {
settings.EnableActionKeys = *value
}
if value := profile.KeyEcho.NavigationKeys; value != nil {
settings.EnableNavigationKeys = *value
}
if value := profile.KeyEcho.Diacritical; value != nil {
settings.EnableDiacriticalKeys = *value
}
}
func boolPointer(value bool) *bool { return &value }
func intPointer(value int) *int { return &value }
func floatPointer(value float64) *float64 { return &value }
func stringPointer(value string) *string { return &value }
func stringSlicePointer(value []string) *[]string {
copy := append([]string(nil), value...)
return &copy
}
func pronunciationSlicePointer(value []PronunciationEntry) *[]PronunciationEntry {
copy := append([]PronunciationEntry{}, value...)
return &copy
}
func textAttributeSlicePointer(value []TextAttributeChoice) *[]TextAttributeChoice {
copy := append([]TextAttributeChoice{}, value...)
return &copy
}
func voicePointer(value Voice) *Voice { copy := cloneVoice(value); return &copy }
func bindingSlicePointer(value []input.BindingOverride) *[]input.BindingOverride {
copy := input.CloneBindingOverrides(value)
if copy == nil {
copy = []input.BindingOverride{}
}
return &copy
}