Merged changes from hunter. Attempt to fix cthulhu announcing modifiers when suspended for xterm.
This commit is contained in:
1 parent
27867a48cb
commit
f2cc47c8a0
24 files changed
+679
-67
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user