Messages read as you tab through discord again.
This commit is contained in:
1 parent
6ed0e36960
commit
9374b5a2e5
10 files changed
+162
-3
No files matched your search
@@ -220,8 +220,22 @@ func (presenter *eventPresenter) speak(event atspi.Event, capturedIntent ...inpu
|
||||
line = &speechLine{Object: event.Source.ID(), Raw: event.Source.BrailleLine}
|
||||
}
|
||||
browseContext := browser.speech_context_enabled() && event.Source.BusName == browser.document.BusName
|
||||
context := event.Source.SpeechContext
|
||||
if !browseContext && isFocusGainEvent(event) {
|
||||
// Named articles label a focused descendant even in focus mode (for
|
||||
// example, a chat message's Reply button), including while browser
|
||||
// context discovery is pending. Other container context retains its
|
||||
// browse-mode policy.
|
||||
context = nil
|
||||
for _, ancestor := range event.Source.SpeechContext {
|
||||
if ancestor.Role == "article" && ancestor.Name != "" {
|
||||
context = append(context, ancestor)
|
||||
}
|
||||
}
|
||||
browseContext = len(context) != 0
|
||||
}
|
||||
speech.Enqueue(speechRequest{
|
||||
Context: event.Source.SpeechContext, ResetContext: !browseContext, VoiceType: ancestor_voice(event.Source.SpeechContext),
|
||||
Context: context, ResetContext: !browseContext, VoiceType: ancestor_voice(event.Source.SpeechContext),
|
||||
Window: eventWindow(event),
|
||||
IntroducesWindow: (event.Type == atspi.WindowActivatedEvent || event.Type == atspi.WindowCreateEvent) &&
|
||||
activationTitle(event) != "",
|
||||
|
||||
@@ -59,7 +59,9 @@ func (worker *speechWorker) context_messages_for(ancestors []atspi.Snapshot, say
|
||||
enabled = presentation.SayAllContextEnabled
|
||||
}
|
||||
for _, item := range previous {
|
||||
if !contains(current, item) && enabled(presentation.ContextType(item), settings) {
|
||||
// Article labels can contain an entire chat message. Python announces
|
||||
// them on entry only; repeating the label on exit obscures the next one.
|
||||
if item.Role != "article" && !contains(current, item) && enabled(presentation.ContextType(item), settings) {
|
||||
appendMessage(item, "Leaving "+presentation.ContextLabel(item)+".")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,3 +94,41 @@ func TestReviewContextSuppressedOutsideBrowseMode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageArticleAnnouncedOnceWhenTabbingIntoControls(t *testing.T) {
|
||||
for name, mode := range map[string]review.DocumentMode{"browse": review.BrowseMode, "focus": review.FocusMode, "resolving": review.InactiveMode} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
logger := slog.New(slog.DiscardHandler)
|
||||
queue := &fakeSpeechQueue{spoken: make(chan string, 16), requests: make(chan speechRequest, 16)}
|
||||
speaker := &spellingTestSpeaker{}
|
||||
worker := newSpeechWorker(logger, speaker)
|
||||
worker.reading = func() config.ReadingSettings { return config.DefaultSettings().Reading }
|
||||
browser := &browserModeController{ready: mode != review.InactiveMode, mode: mode, document: atspi.NewObjectID(":1.42", "/document")}
|
||||
state := &eventLoopState{}
|
||||
state.presentationOptions = presentation.DefaultOptions()
|
||||
presenter := eventPresenter{state: state, logger: logger, speech: queue, browser: browser}
|
||||
article := atspi.Snapshot{BusName: ":1.42", Path: "/message1", Role: "article", Name: "Author: First message"}
|
||||
check := func(path, name string, ancestors []atspi.Snapshot, want []string) {
|
||||
t.Helper()
|
||||
control := atspi.Snapshot{BusName: ":1.42", Path: path, Role: "button", Name: name, SpeechContext: ancestors}
|
||||
presenter.speak(atspi.NewEvent(atspi.FocusEvent, control))
|
||||
speaker.parts = nil
|
||||
if len(queue.requests) != 1 {
|
||||
t.Fatalf("queued %d requests", len(queue.requests))
|
||||
}
|
||||
if err := worker.deliver(context.Background(), <-queue.requests); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(speaker.parts, want) {
|
||||
t.Fatalf("speech = %q, want %q", speaker.parts, want)
|
||||
}
|
||||
}
|
||||
check("/reply1", "Reply", []atspi.Snapshot{article}, []string{"Author: First message article", "Reply", "button"})
|
||||
check("/forward1", "Forward", []atspi.Snapshot{article}, []string{"Forward", "button"})
|
||||
article.Path, article.Name = "/message2", "Author: Second message"
|
||||
check("/reply2", "Reply", []atspi.Snapshot{article}, []string{"Author: Second message article", "Reply", "button"})
|
||||
check("/outside", "Outside", []atspi.Snapshot{}, []string{"Outside", "button"})
|
||||
check("/reply2", "Reply", []atspi.Snapshot{article}, []string{"Author: Second message article", "Reply", "button"})
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user