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,130 @@
|
||||
// Cthulhu screen reader.
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation, either version 3 of the License, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
// more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/lifecycle"
|
||||
"git.stormux.org/storm/cthulhu/internal/nvda2cthulhu"
|
||||
"git.stormux.org/storm/cthulhu/internal/remote"
|
||||
"git.stormux.org/storm/cthulhu/internal/wine"
|
||||
)
|
||||
|
||||
// remoteServiceDependencies are held by the service closures for the lifetime
|
||||
// of the runner. The input and adapter counters are read only on snapshot calls.
|
||||
type remoteServiceDependencies struct {
|
||||
logger *slog.Logger
|
||||
stopRun context.CancelFunc
|
||||
adapter Adapter
|
||||
inputListener InputListener
|
||||
speech *speechWorker
|
||||
braille *brailleWorker
|
||||
live *liveSettings
|
||||
preferences *preferencesWorker
|
||||
onPreferences func()
|
||||
}
|
||||
|
||||
func newRemoteRuntimeServices(deps remoteServiceDependencies) []lifecycle.Service {
|
||||
remoteHandler := remoteSpeech{braille: lockFeedbackBraille{deps.braille}}
|
||||
remoteHandler.live = deps.live
|
||||
remoteHandler.preferences = deps.preferences
|
||||
remoteHandler.showPreferences = deps.onPreferences
|
||||
remoteHandler.quit = func() { time.AfterFunc(100*time.Millisecond, deps.stopRun) }
|
||||
remoteHandler.runtimeSnapshot = func() string {
|
||||
snapshot := "CTHULHU RUNTIME STATE SNAPSHOT\n[event_manager]\noverflow: " + strconv.FormatUint(deps.adapter.Overflow(), 10)
|
||||
if deps.inputListener != nil {
|
||||
snapshot += "\n[input_event_manager]\noverflow: " + strconv.FormatUint(deps.inputListener.Overflow(), 10)
|
||||
}
|
||||
return snapshot
|
||||
}
|
||||
if deps.speech != nil {
|
||||
remoteHandler.speech = deps.speech
|
||||
}
|
||||
wineEvents := newWineEventPresenter(func(message string) bool {
|
||||
return remoteHandler.presentMessage(message, "wine-accessible-event")
|
||||
})
|
||||
wineEvents.logger = deps.logger
|
||||
connectWineWindowTitles(wineEvents, deps.live, deps.adapter)
|
||||
remoteHandler.wine = wineEvents
|
||||
if deps.live != nil {
|
||||
remoteHandler.wineReview = deps.live.wineReview
|
||||
}
|
||||
remoteService := remote.New(deps.logger, remoteHandler)
|
||||
services := []lifecycle.Service{{
|
||||
Name: "self-voice D-Bus",
|
||||
Start: func(ctx context.Context) error {
|
||||
if err := remoteService.Start(ctx); err != nil {
|
||||
deps.logger.Warn("Cthulhu D-Bus service unavailable", "error", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Stop: func(ctx context.Context) error {
|
||||
wineEvents.Close()
|
||||
if err := remoteService.Stop(ctx); err != nil {
|
||||
deps.logger.Warn("Cthulhu D-Bus service shutdown", "error", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}}
|
||||
if remoteHandler.wineReview != nil {
|
||||
registry := remoteHandler.wineReview
|
||||
// Reverse shutdown cancels captures before the borrowed service bus closes.
|
||||
services = append(services, lifecycle.Service{Name: "Wine flat review", Start: func(ctx context.Context) error {
|
||||
if err := registry.Start(ctx); err != nil {
|
||||
deps.logger.Warn("Wine flat review unavailable", "error", err)
|
||||
}
|
||||
return nil
|
||||
}, Stop: registry.Stop})
|
||||
}
|
||||
orcaService := remote.NewOrca(deps.logger, remoteHandler)
|
||||
services = append(services, lifecycle.Service{
|
||||
Name: "Orca compatibility D-Bus",
|
||||
Start: func(ctx context.Context) error {
|
||||
if err := orcaService.Start(ctx); err != nil {
|
||||
deps.logger.Warn("Orca compatibility D-Bus service unavailable", "error", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Stop: func(ctx context.Context) error {
|
||||
if err := orcaService.Stop(ctx); err != nil {
|
||||
deps.logger.Warn("Orca compatibility D-Bus service shutdown", "error", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
bridgeServer := nvda2cthulhu.New(deps.logger, remoteHandler)
|
||||
services = append(services, lifecycle.Service{
|
||||
Name: "NVDA to Cthulhu bridge",
|
||||
Start: func(ctx context.Context) error {
|
||||
if err := bridgeServer.Start(ctx); err != nil {
|
||||
deps.logger.Warn("NVDA to Cthulhu bridge unavailable", "error", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Stop: bridgeServer.Stop,
|
||||
})
|
||||
wineManager := wine.New(deps.logger)
|
||||
services = append(services, lifecycle.Service{
|
||||
Name: "Wine accessibility", Start: wineManager.Start, Stop: wineManager.Stop,
|
||||
})
|
||||
return services
|
||||
}
|
||||
Reference in new issue
Block a user