Files
cthulhu/internal/app/wine_echo_focus_test.go

99 lines
3.7 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"testing"
"git.stormux.org/storm/cthulhu/internal/config"
"git.stormux.org/storm/cthulhu/internal/remote"
)
func TestWineEditFieldsOnlyTypingAndVoices(t *testing.T) {
settings := config.DefaultSettings()
settings.KeyEchoInEditFieldsOnly = true
settings.UseCustomEchoVoice = true
settings.UseCustomEchoForKey = true
settings.UseCustomEchoForCharacter = false
live := &liveSettings{}
live.Store(settings)
speech := &remoteSpeechQueue{}
braille := &remoteBrailleQueue{running: true}
presenter := remoteSpeech{speech: speech, braille: braille, live: live}
owner := newWineEventPresenter(func(string) bool { return true })
defer owner.Close()
presenter.wine = owner
for _, tc := range []struct {
role, states, description string
want bool
}{
{"edit", "", "", true}, {"read only edit", "", "", false}, {"edit", "read only", "", false},
{"button", "", "", false}, {"text", "", "", false}, {"edit", "", "password", false},
} {
presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "control", EventType: "focus", Role: tc.role, States: tc.states, Description: tc.description})
owner.flush()
before := len(speech.requests)
accepted := presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "control", EventType: "text", Name: "A", States: "kind=8"})
if accepted != tc.want || (len(speech.requests) > before) != tc.want {
t.Fatalf("role=%s states=%s protected=%s accepted=%v", tc.role, tc.states, tc.description, accepted)
}
if tc.want && (!speech.requests[before].CustomEcho || !speech.requests[before].Character || braille.text[len(braille.text)-1] != "A") {
t.Fatal("Wine key voice or braille lost")
}
}
presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "edit", EventType: "focus", Role: "edit"})
owner.flush()
settings.EnableEchoByCharacter = true
live.Store(settings)
presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "edit", EventType: "text", Name: "a", States: "kind=8"})
if speech.requests[len(speech.requests)-1].CustomEcho {
t.Fatal("character routing used key-only custom voice")
}
// Moving focus to a menu invalidates the preceding editor's text actions.
presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "menu", EventType: "focus", Role: "menu item"})
owner.flush()
if presenter.PresentAccessibleEvent(remote.AccessibleEvent{SourceID: "edit", EventType: "text", Name: "a", States: "kind=8"}) {
t.Fatal("old editor still echoes")
}
}
func TestWineKeyEchoRequiresCurrentDesktopFocus(t *testing.T) {
_, _, monitor, _ := reviewFocusSetup(t)
owner := newWineEventPresenter(func(string) bool { return true })
defer owner.Close()
owner.foreground, owner.titles = monitor, monitor
focus := remote.AccessibleEvent{SourceID: "edit", EventType: "focus", Role: "edit", WindowTitle: monitor.title.Title.Title}
owner.Present(focus)
owner.flush()
if !owner.EditFieldFocused() {
t.Fatal("current Wine editor rejected")
}
monitor.state.Epoch++
if owner.EditFieldFocused() {
t.Fatal("stale Wine editor survived foreground switch")
}
monitor.title.Epoch = monitor.state.Epoch
owner.Present(focus)
owner.flush()
if !owner.EditFieldFocused() {
t.Fatal("new focus did not restore editor")
}
monitor.title.Title.Wine = false
if owner.EditFieldFocused() {
t.Fatal("native window reused Wine focus")
}
monitor.title.Title.Wine = true
focus.Role = "menu item"
owner.Present(focus)
owner.flush()
if owner.EditFieldFocused() {
t.Fatal("menu retained editor echo")
}
owner.Close()
if owner.EditFieldFocused() {
t.Fatal("closed helper retained focus")
}
}