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,98 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/atspi"
|
||||
"git.stormux.org/storm/cthulhu/internal/config"
|
||||
"git.stormux.org/storm/cthulhu/internal/notification"
|
||||
"git.stormux.org/storm/cthulhu/internal/webscripts"
|
||||
)
|
||||
|
||||
// webScriptController is owned by processEventsWithInput. Delayed presentation
|
||||
// runs in that loop, preserving event order without timer callback goroutines.
|
||||
type webScriptController struct {
|
||||
registry webscripts.Registry
|
||||
timer *time.Timer
|
||||
due <-chan time.Time
|
||||
speech speechEnqueuer
|
||||
notifications *notification.Presenter
|
||||
braille interface {
|
||||
Flash(string, config.BrailleOptions) bool
|
||||
}
|
||||
live *liveSettings
|
||||
gate *focusGate
|
||||
}
|
||||
|
||||
func (controller *webScriptController) handle(event atspi.Event) bool {
|
||||
retiring := event.Type == atspi.WindowDestroyedEvent || event.Type == atspi.DefunctStateEvent && event.Detail1 != 0
|
||||
if retiring {
|
||||
id := event.Source.ID()
|
||||
if event.Type == atspi.WindowDestroyedEvent && event.Window.Valid() {
|
||||
id = event.Window
|
||||
}
|
||||
controller.registry.Retire(id.BusName, id.Path)
|
||||
}
|
||||
messages, handled := controller.registry.Receive(event.Source.ApplicationProcess,
|
||||
event.Type, event.Detail1, event.WebNotification, time.Now())
|
||||
controller.present(messages)
|
||||
if handled || retiring {
|
||||
controller.schedule()
|
||||
}
|
||||
return handled
|
||||
}
|
||||
|
||||
func (controller *webScriptController) schedule() {
|
||||
deadline := controller.registry.Deadline()
|
||||
controller.due = nil
|
||||
if controller.timer != nil {
|
||||
controller.timer.Stop()
|
||||
}
|
||||
if deadline.IsZero() {
|
||||
return
|
||||
}
|
||||
if controller.timer == nil {
|
||||
controller.timer = time.NewTimer(time.Until(deadline))
|
||||
} else {
|
||||
controller.timer.Reset(time.Until(deadline))
|
||||
}
|
||||
controller.due = controller.timer.C
|
||||
}
|
||||
|
||||
func (controller *webScriptController) flush() {
|
||||
if controller.gate.Locked() {
|
||||
controller.reset()
|
||||
return
|
||||
}
|
||||
controller.present(controller.registry.Flush(time.Now()))
|
||||
controller.schedule()
|
||||
}
|
||||
|
||||
func (controller *webScriptController) present(messages []string) {
|
||||
if controller.gate.Locked() {
|
||||
return
|
||||
}
|
||||
for _, message := range messages {
|
||||
controller.notifications.Save(message, notification.SaveOptions{AppName: "Steam", Source: "steam"})
|
||||
if controller.braille != nil {
|
||||
options := config.DefaultSettings().Braille
|
||||
if controller.live != nil {
|
||||
options = controller.live.Load().Braille
|
||||
}
|
||||
controller.braille.Flash(message, options)
|
||||
}
|
||||
controller.speech.Interrupt()
|
||||
controller.speech.Enqueue(speechRequest{
|
||||
Text: message, Role: "notification", Cause: "steam-notification", BypassFocusGate: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (controller *webScriptController) reset() {
|
||||
controller.registry.Reset()
|
||||
controller.schedule()
|
||||
}
|
||||
Reference in new issue
Block a user