package app import ( "context" "time" "unicode/utf8" "git.stormux.org/storm/cthulhu/internal/atspi" "git.stormux.org/storm/cthulhu/internal/braille" ) type brailleRouter interface { RouteBraille(context.Context, atspi.BrailleRoute) error } func (worker *brailleWorker) route(ctx context.Context, event braille.RoutingEvent) { worker.mu.Lock() frame := worker.frame length := utf8.RuneCountInString(frame.Text) if worker.secure || worker.stopping || frame.ID == 0 || event.ID != frame.ID || event.Offset < 0 || (frame.Virtual == nil && event.Offset >= length) || (frame.Virtual != nil && event.Offset > length) { worker.mu.Unlock() return } if route := frame.Virtual; route != nil { if worker.ocr == nil || event.Offset < route.Start || event.Offset > route.End { worker.mu.Unlock() return } routeCtx, cancel := context.WithTimeout(ctx, time.Second) worker.routeCancel = cancel worker.mu.Unlock() defer cancel() worker.ocr.RouteBraille(routeCtx, route.Generation, route.SourceStart+event.Offset-route.Start) return } if worker.router == nil && frame.Document == nil { worker.mu.Unlock() return } var target *braille.TextRoute for _, route := range frame.Routes { if event.Offset >= route.Start && event.Offset < route.End { target = &route break } } if target == nil { worker.mu.Unlock() return } routeCtx, cancel := context.WithTimeout(ctx, time.Second) worker.routeCancel = cancel worker.mu.Unlock() defer cancel() if document := frame.Document; document != nil { if worker.document == nil { return } worker.logger.Debug("routing document braille", "frame_id", frame.ID, "document_epoch", document.Epoch, "source_bus", target.BusName, "source_path", target.Path, "source_start", target.SourceStart, "native_offset", target.SourceStart+min(event.Offset-target.Start, target.TextLength)) err := worker.document.RouteDocumentBraille(routeCtx, document.Epoch, atspi.NewObjectID(document.FocusBus, document.FocusPath), atspi.NewObjectID(document.DocumentBus, document.DocumentPath), atspi.NewObjectID(target.BusName, target.Path), target.SourceText, target.SourceStart, target.SourceStart+min(event.Offset-target.Start, target.TextLength)) if err != nil && routeCtx.Err() == nil { worker.logger.Debug("document braille routing rejected", "error", err) } return } err := worker.router.RouteBraille(routeCtx, atspi.BrailleRoute{ Focus: atspi.NewObjectID(target.BusName, target.Path), Line: target.SourceText, Start: target.SourceStart, Offset: target.SourceStart + min(event.Offset-target.Start, target.TextLength), }) if err != nil && routeCtx.Err() == nil { worker.logger.Debug("braille routing rejected", "error", err) } }