Cthulhu is no longer a fork. Now it is a screen reader written in Golang.
This commit is contained in:
1 parent
a998fe67de
commit
069fc674dc
708 files changed
+112482
-532
No files matched your search
@@ -0,0 +1,74 @@
|
||||
// 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/config"
|
||||
"git.stormux.org/storm/cthulhu/internal/input"
|
||||
"git.stormux.org/storm/cthulhu/internal/presentation"
|
||||
)
|
||||
|
||||
// handleBrowserTab presents a selected tab while leaving native focus in chrome.
|
||||
func (handler *accessibilityEventHandler) handleBrowserTab(event atspi.Event, activity input.Activity) bool {
|
||||
state := handler.state
|
||||
browser := handler.browser
|
||||
objectReview := handler.objectReview
|
||||
speech := handler.speech
|
||||
brailleOutput := handler.brailleOutput
|
||||
live := handler.live
|
||||
if event.Source.BrowserTab && (event.Type == atspi.SelectedStateEvent || event.Type == atspi.SelectionChangedEvent) {
|
||||
// Python's web page-switch handler presents the tab without moving
|
||||
// the locus of focus. Repeated Ctrl+T can keep the same address
|
||||
// control focused and produce no further focus events at all.
|
||||
selected := event.Type == atspi.SelectedStateEvent && event.Detail1 != 0 ||
|
||||
event.Type == atspi.SelectionChangedEvent && event.Source.Selected &&
|
||||
strings.EqualFold(event.Source.ToolkitName, "Gecko")
|
||||
if !selected || event.Source.StatesKnown && !event.Source.Selected ||
|
||||
event.Source.Defunct || !state.owner.containsLoad(event) || event.Source.ID() == state.selectedBrowserTab {
|
||||
return true
|
||||
}
|
||||
state.selectedBrowserTab = event.Source.ID()
|
||||
state.tabFocusWindow, state.tabFocusSequence = eventWindow(event), activity.Sequence
|
||||
state.pending.caret.clear()
|
||||
state.documentLineFocus, state.documentLineRequest, state.documentLineEvent = atspi.ObjectID{}, 0, atspi.Event{}
|
||||
state.loadingDocument, state.loadedDocument = atspi.ObjectID{}, atspi.ObjectID{}
|
||||
state.chromeLoadedDocument, state.chromeLoadedWindow = atspi.ObjectID{}, atspi.ObjectID{}
|
||||
if browser != nil {
|
||||
browser.clear()
|
||||
}
|
||||
if objectReview != nil {
|
||||
focus := atspi.ObjectID{}
|
||||
if state.current.Autocomplete {
|
||||
focus = state.current.ID()
|
||||
}
|
||||
objectReview.ResetDocument(focus)
|
||||
}
|
||||
spoken := presentation.FocusSpeechWithOptions(event.Source, state.presentationOptions)
|
||||
text := spoken.Text
|
||||
if text != "" {
|
||||
speech.Enqueue(speechRequest{Text: text, Chunks: spoken.Chunks, Role: event.Source.Role, Cause: event.Type})
|
||||
}
|
||||
if brailleOutput != nil {
|
||||
brailleOptions := config.DefaultSettings().Braille
|
||||
textAttributes := config.DefaultTextAttributes()
|
||||
if live != nil {
|
||||
settings := live.Load()
|
||||
brailleOptions, textAttributes = settings.Braille, settings.TextAttributes
|
||||
}
|
||||
brailleOutput.EnqueueFrame(brailleFocusFrameWithOptions(event.Source, brailleOptions, textAttributes))
|
||||
}
|
||||
return true
|
||||
}
|
||||
if event.Source.Autocomplete && eventWindow(event) == state.tabFocusWindow &&
|
||||
activity.Sequence != 0 && activity.Sequence == state.tabFocusSequence &&
|
||||
(event.Type == atspi.CaretEvent || event.Type == "object:state-changed:expanded") {
|
||||
return true // Automatic address reset must not cut off the selected tab.
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in new issue
Block a user