Merged changes from hunter. Attempt to fix cthulhu announcing modifiers when suspended for xterm.

This commit is contained in:
Storm Dragon committed 2026-10-31 16:07:29 -04:00
1 parent 27867a48cb
commit f2cc47c8a0
24 files changed
+679 -67

No files matched your search

+8 -1
View File
@@ -58,7 +58,8 @@ func RebaseApplicationSettings(oldGlobal, newGlobal, application Settings) Setti
func profileFromSettings(settings Settings) writableProfile {
settings = RoundSpeechValues(settings)
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)},
Wine: writableWine{ControllerOnly: boolPointer(settings.Wine.ControllerOnly), ExcludedPrograms: &settings.Wine.ExcludedPrograms},
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),
@@ -169,6 +170,12 @@ func profileFromSettings(settings Settings) writableProfile {
}
func applyProfile(settings *Settings, profile writableProfile) {
if profile.Wine.ControllerOnly != nil {
settings.Wine.ControllerOnly = *profile.Wine.ControllerOnly
}
if profile.Wine.ExcludedPrograms != nil {
settings.Wine.ExcludedPrograms = append([]string(nil), (*profile.Wine.ExcludedPrograms)...)
}
apply_profile_ocr(&settings.OCR, profile.OCR)
// Keep the established patch order; absent fields leave prior values intact.
apply_profile_formats(settings, profile)
+6
View File
@@ -32,7 +32,13 @@ type writableDocument struct {
// Profiles are patches over built-in defaults. The writer emits a complete
// active profile so saved behavior remains stable if defaults later change.
type writableWine struct {
ControllerOnly *bool `toml:"controller-only,omitempty"`
ExcludedPrograms *[]string `toml:"excluded-hook-programs,omitempty"`
}
type writableProfile struct {
Wine writableWine `toml:"wine"`
OCR writableOCR `toml:"ocr"`
ProgressBar writableProgressBar `toml:"progress-bar"`
Presentation writablePresentation `toml:"presentation"`
+6
View File
@@ -112,7 +112,13 @@ func DefaultProgressBarSettings() ProgressBarSettings {
return ProgressBarSettings{OutputMode: "beep", BeepPercentageInterval: 1, SpeechPercentageInterval: 10}
}
type WineSettings struct {
ControllerOnly bool
ExcludedPrograms []string
}
type Settings struct {
Wine WineSettings
StructuralNavigationTriggersFocusMode bool
OCR OCRSettings
+1
View File
@@ -22,6 +22,7 @@ import (
)
func cloneSettings(settings Settings) Settings {
settings.Wine.ExcludedPrograms = append([]string(nil), settings.Wine.ExcludedPrograms...)
settings.SpeechInterruption.Keys = append([]string(nil), settings.SpeechInterruption.Keys...)
settings.KeyBindings = input.CloneBindingOverrides(settings.KeyBindings)
settings.CthulhuModifierKeys = append([]string(nil), settings.CthulhuModifierKeys...)
+15
View File
@@ -24,6 +24,7 @@ import (
"path/filepath"
"strings"
"unicode"
"unicode/utf16"
"git.stormux.org/storm/cthulhu/internal/datetime"
"git.stormux.org/storm/cthulhu/internal/input"
@@ -33,6 +34,20 @@ import (
func Validate(settings Settings) error { return validate(settings) }
func validate(settings Settings) error {
if len(settings.Wine.ExcludedPrograms) > 256 {
return errors.New("too many Wine hook exclusions")
}
exclusionUnits := 0
for _, name := range settings.Wine.ExcludedPrograms {
exclusionUnits += len(utf16.Encode([]rune(name))) + 1
if name == "" || len(name) > 255 || strings.TrimSpace(name) != name || strings.ContainsAny(name, "\x00\r\n/\\") {
return errors.New("Wine hook exclusions must be executable basenames")
}
}
if exclusionUnits >= 32766 {
return errors.New("Wine hook exclusion list is too long")
}
if err := settings.SpeechInterruption.Validate(); err != nil {
return err
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package config
import (
"path/filepath"
"reflect"
"testing"
)
func TestWineSettingsRoundTripAndValidation(t *testing.T) {
settings := DefaultSettings()
settings.Wine = WineSettings{ControllerOnly: true, ExcludedPrograms: []string{"Game.exe", "Another Game.exe"}}
path := filepath.Join(t.TempDir(), "settings.toml")
store, err := NewStore(path)
if err != nil {
t.Fatal(err)
}
if err := store.Save(settings); err != nil {
t.Fatal(err)
}
loaded, err := Load(path)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(loaded.Wine, settings.Wine) {
t.Fatalf("Wine settings = %+v", loaded.Wine)
}
cloned := cloneSettings(settings)
cloned.Wine.ExcludedPrograms[0] = "Changed.exe"
if settings.Wine.ExcludedPrograms[0] != "Game.exe" {
t.Fatal("clone aliases exclusions")
}
for _, name := range []string{"", "../game.exe", `C:\game.exe`, "Game.exe\rOther.exe", "game.exe\n"} {
settings.Wine.ExcludedPrograms = []string{name}
if err := Validate(settings); err == nil {
t.Fatalf("accepted exclusion %q", name)
}
}
}