Reset master to testing content
This commit is contained in:
1 parent
0f2587b719
commit
42afa2a56c
1483 files changed
+145308
-938069
No files matched your search
@@ -0,0 +1,93 @@
|
||||
// Cthulhu screen reader.
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/atspi"
|
||||
"git.stormux.org/storm/cthulhu/internal/input"
|
||||
"git.stormux.org/storm/cthulhu/internal/sound"
|
||||
)
|
||||
|
||||
// handleAutocomplete may rewrite insertion payload before normal presentation.
|
||||
// A true consumed result discards popup and address-bar echo events in place.
|
||||
func (handler *accessibilityEventHandler) handleAutocomplete(event atspi.Event, activity input.Activity, intent input.Intent) (atspi.Event, speechRequest, bool) {
|
||||
state := handler.state
|
||||
live := handler.live
|
||||
logger := handler.logger
|
||||
speak := handler.speak
|
||||
var autocompleteRequest speechRequest
|
||||
state.autocompleteAvailable.focus(event)
|
||||
if event.Type == atspi.TextInsertedEvent && supportsAutocomplete(event.Source) {
|
||||
if live != nil {
|
||||
available := state.presentationOptions.SoundCueAvailable
|
||||
state.presentationOptions = presentationSettingsFromConfig(live.Load(), true)
|
||||
state.presentationOptions.SoundCueAvailable = available
|
||||
}
|
||||
if address := state.autocompleteAvailable.offered(event, activity); address != "" {
|
||||
autocompleteRequest = speechRequest{Text: address, Role: "autocomplete", Cause: "autocomplete-available"}
|
||||
if state.presentationOptions.EnableSound && state.presentationOptions.RoleSoundPresentation != "speech_only" &&
|
||||
(state.presentationOptions.SoundCueAvailable == nil || state.presentationOptions.SoundCueAvailable("autocomplete")) {
|
||||
autocompleteRequest.Sound = []sound.Cue{{Name: "autocomplete"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
if event.Source.AutocompletePopup {
|
||||
explicitItem := isAutocompletePopupItem(event.Source.Role) &&
|
||||
((isFocusGainEvent(event) && intent == input.LineIntent) ||
|
||||
(event.Type == "object:state-changed:selected" && event.Detail1 != 0 && intent == input.LineIntent))
|
||||
if explicitItem && event.Source.ID() != state.lastAutocompletePopupItem {
|
||||
state.lastAutocompletePopupItem = event.Source.ID()
|
||||
presentationEvent := event
|
||||
presentationEvent.Type = atspi.FocusEvent
|
||||
speak(presentationEvent)
|
||||
}
|
||||
logger.Debug("skipped autocomplete popup noise", "type", event.Type, "role", event.Source.Role)
|
||||
return event, autocompleteRequest, true
|
||||
}
|
||||
if event.Source.Autocomplete {
|
||||
if isFocusGainEvent(event) {
|
||||
state.lastAutocompletePopupItem = atspi.ObjectID{}
|
||||
}
|
||||
if (isTextChangeEvent(event.Type) || event.Type == atspi.CaretEvent) && intent == input.LineIntent {
|
||||
return event, autocompleteRequest, true // Up/Down presents the popup item, not the entry's replacement text.
|
||||
}
|
||||
if event.Type == atspi.TextDeletedEvent && intent == input.TypingIntent {
|
||||
return event, autocompleteRequest, true // Replacing the selected URL or completion is not a user deletion.
|
||||
}
|
||||
if event.Type == atspi.TextInsertedEvent && intent == input.TypingIntent {
|
||||
event.Payload = state.autocompleteTyping.insertion(event, activity)
|
||||
if autocompleteRequest.Text != "" {
|
||||
event.Payload = "" // The selected address replaces this insertion's character echo.
|
||||
}
|
||||
}
|
||||
}
|
||||
return event, autocompleteRequest, false
|
||||
}
|
||||
|
||||
func isBrowserUINameNoise(event atspi.Event, focus atspi.Snapshot) bool {
|
||||
if event.Type != atspi.AccessibleNameEvent {
|
||||
return false
|
||||
}
|
||||
// Browser chrome labels, status bars, and frames can change independently
|
||||
// of focus. Current controls and rows still need their new names presented.
|
||||
// Orca's web UI noise filter likewise limits these ignored roles.
|
||||
switch strings.ToLower(event.Source.ToolkitName) {
|
||||
case "chromium", "gecko", "webkit", "webkitgtk":
|
||||
return event.Source.Role == "status bar" || event.Source.Role == "label" ||
|
||||
event.Source.Role == "frame"
|
||||
}
|
||||
if event.Source.AutocompletePopup {
|
||||
return true
|
||||
}
|
||||
return focus.Autocomplete && event.Source.ID().BusName != "" &&
|
||||
event.Source.ID().BusName == focus.ID().BusName
|
||||
}
|
||||
|
||||
func isAutocompletePopupItem(role string) bool {
|
||||
return role == "list item" || role == "menu item"
|
||||
}
|
||||
Reference in new issue
Block a user