Fixed some element types being spoken even though sound only is selected.

This commit is contained in:
Storm Dragon committed 2026-10-26 02:41:07 -04:00
1 parent 6ee0454fbe
commit 0d76e44f9a
5 files changed
+53 -6

No files matched your search

+4 -2
View File
@@ -127,7 +127,10 @@ func FocusSpeechWithOptions(snapshot atspi.Snapshot, options Options) Speech {
role = ""
}
_, replaceRole := roleSoundCue(snapshot, options)
if options.RoleSoundPresentation == "sound_only" && replaceRole {
_, replaceState := stateSoundCue(snapshot, options)
// A control-specific state cue also identifies its role. Keep the role
// spoken when role sounds are disabled or no replacement cue is available.
if options.RoleSoundPresentation == "sound_only" && (replaceRole || options.PlaySoundForRole && replaceState) {
role = ""
}
if options.SpeechVerbosityLevel != 0 && snapshot.ChildCountKnown && snapshot.ChildCount > 0 {
@@ -147,7 +150,6 @@ func FocusSpeechWithOptions(snapshot atspi.Snapshot, options Options) Speech {
}
fields = append(fields, snapshot.Name, role)
states := controlStates(snapshot)
_, replaceState := stateSoundCue(snapshot, options)
if options.RoleSoundPresentation == "sound_only" && replaceState {
states = removeReplacedState(states)
}
+43 -1
View File
@@ -18,6 +18,7 @@
package presentation
import (
"fmt"
"math"
"reflect"
"testing"
@@ -209,7 +210,7 @@ func TestElementPresentationStrategiesKeepRoleAndStateIndependent(t *testing.T)
checkbox := atspi.Snapshot{Name: "Accept", Role: "check box", Checked: true, Required: true, Invalid: true}
options := Options{EnableSound: true, PlaySoundForRole: true, PlaySoundForState: true, RoleSoundPresentation: "sound_only"}
if got := FocusTextWithOptions(checkbox, options); got != "Accept, check box, required, invalid entry" {
if got := FocusTextWithOptions(checkbox, options); got != "Accept, required, invalid entry" {
t.Fatalf("sound-only checkbox text = %q", got)
}
unsupported := atspi.Snapshot{Name: "Document", Role: "text frame", Expandable: true, Expanded: true}
@@ -222,6 +223,47 @@ func TestElementPresentationStrategiesKeepRoleAndStateIndependent(t *testing.T)
}
}
func TestStateCueReplacesControlRoleInSoundOnlyFocus(t *testing.T) {
for _, role := range []string{"check box", "check menu item", "radio button", "radio menu item", "switch", "menu item"} {
for _, checked := range []bool{false, true} {
for _, strategy := range []string{"sound_only", "sound_and_speech", "speech_only"} {
t.Run(fmt.Sprintf("%s/%t/%s", role, checked, strategy), func(t *testing.T) {
snapshot := atspi.Snapshot{Name: "Option", Role: role, Checked: checked, Checkable: role == "menu item"}
options := Options{EnableSound: true, PlaySoundForRole: true, PlaySoundForState: true, RoleSoundPresentation: strategy}
want := FocusText(snapshot)
if strategy == "sound_only" {
want = "Option"
}
if got := FocusTextWithOptions(snapshot, options); got != want {
t.Fatalf("focus speech = %q, want %q", got, want)
}
if strategy != "sound_only" {
return
}
for _, disabled := range []string{"sound", "state", "unavailable"} {
fallback := options
switch disabled {
case "sound":
fallback.EnableSound = false
case "state":
fallback.PlaySoundForState = false
case "unavailable":
fallback.SoundCueAvailable = func(string) bool { return false }
}
if got := FocusTextWithOptions(snapshot, fallback); got != FocusText(snapshot) {
t.Errorf("%s fallback = %q, want %q", disabled, got, FocusText(snapshot))
}
}
options.PlaySoundForRole = false
if got, want := FocusTextWithOptions(snapshot, options), "Option, "+snapshot.ControlRole(); got != want {
t.Errorf("disabled role sound speech = %q, want %q", got, want)
}
})
}
}
}
}
func TestStateChangeSoundOnlySuppressesOnlyReplacedState(t *testing.T) {
options := Options{EnableSound: true, PlaySoundForRole: true, PlaySoundForState: true, RoleSoundPresentation: "sound_only"}
event := atspi.NewEvent("object:state-changed:checked", atspi.Snapshot{Role: "check box", Checked: true})