Files
cthulhu/internal/app/braille_context.go

77 lines
2.2 KiB
Go

package app
import (
"strings"
"unicode/utf8"
"git.stormux.org/storm/cthulhu/internal/atspi"
"git.stormux.org/storm/cthulhu/internal/braille"
"git.stormux.org/storm/cthulhu/internal/config"
)
// Python includes context at the first line of text areas and omits desktop
// ancestry within web documents. Verbosity changes roles, not group labels.
func braille_context_frame(frame braille.Frame, snapshot atspi.Snapshot, options config.BrailleOptions) braille.Frame {
if snapshot.Role == "terminal" || snapshot.TextCaretKnown && snapshot.BrailleLineStart > 0 {
return frame
}
for _, ancestor := range snapshot.BrailleContext {
if atspi.IsWebDocumentRole(ancestor.Role) {
return frame
}
}
parts := []string{}
groupSkipped := false
ancestors := snapshot.BrailleContext
if len(ancestors) > 0 {
switch ancestors[0].Role {
case "menu", "menu bar", "page tab list", "redundant object", "unknown", "combo box":
ancestors = ancestors[1:]
}
}
for index := len(ancestors) - 1; index >= 0; index-- {
ancestor := ancestors[index]
if ancestor.ID().Valid() && ancestor.ID() == snapshot.ID() {
continue
}
switch ancestor.Role {
case "invalid", "unknown", "redundant object", "section", "split pane", "desktop frame", "scroll pane", "viewport":
continue
case "panel", "filler", "grouping":
if strings.TrimSpace(ancestor.Name) == "" {
continue
}
if snapshot.Role == "radio button" && ancestor.Name == snapshot.RadioGroupName && !groupSkipped {
groupSkipped = true
continue
}
}
if ancestor.Role == "table" && ancestor.LayoutTable {
continue
}
text := braille_object_frame(ancestor, options).Text
if text != "" {
parts = append(parts, text)
}
}
parts = append(parts, snapshot.TableRowHeaders, snapshot.TableColumnHeaders, snapshot.RadioGroupName)
prefix := brailleJoin(parts...)
if prefix == "" {
return frame
}
prefix += " "
shift := utf8.RuneCountInString(prefix)
frame.Text = prefix + frame.Text
if frame.Cursor >= 0 {
frame.Cursor += shift
}
if len(frame.Dots) != 0 {
frame.Dots = append(make([]byte, shift), frame.Dots...)
}
for index := range frame.Routes {
frame.Routes[index].Start += shift
frame.Routes[index].End += shift
}
return frame
}