Files
cthulhu/internal/app/application_behavior.go
2026-10-15 01:10:43 -04:00

61 lines
2.3 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import "git.stormux.org/storm/cthulhu/internal/atspi"
type applicationEventResult struct {
event atspi.Event
adoptFocus bool
suppress bool
resetPresentation bool
}
// prepareApplicationEvent runs after security/foreground checks and before
// generic focus and text filters. Application policy receives copied semantics;
// the reader retains ownership, review, cancellation, and output services.
// Application-specific state stays on the event loop with an explicit focus
// lifetime, rather than hidden in native callbacks.
func (handler *accessibilityEventHandler) prepareApplicationEvent(event atspi.Event) (atspi.Event, bool) {
result := applicationEventResult{event: event}
if atspi.IsLibreOfficeProcess(event.Source.ApplicationProcess) {
result = prepareLibreOfficeEvent(event, handler.state.current, handler.state.owner)
}
if !result.suppress || event.Type == atspi.SelectionChangedEvent {
handler.handleLibreOfficeSelection(result.event)
}
if result.adoptFocus {
if handler.focusGate.Suspended() {
return event, false
}
state := handler.state
if !state.owner.follow(result.event) {
return event, true
}
state.pending.caret.clear()
state.focusedID = result.event.Source.ID()
state.current = result.event.Source
state.managedContainerID, state.managedDescendantID = atspi.ObjectID{}, atspi.ObjectID{}
if result.event.Source.Role != "table" && result.event.Source.Role != "table cell" {
// A late-created editor has no ordinary focus event to reset
// row history. Returning to its old cell is a fresh focus.
state.lastTable, state.lastTableCell = atspi.ObjectID{}, atspi.ObjectID{}
}
state.selection.reset(result.event.Source)
if handler.objectReview != nil {
handler.objectReview.SyncFocus(result.event.Source.ID())
}
}
if result.resetPresentation {
handler.state.pending.caret.clear()
handler.state.lastSpokenPath, handler.state.lastSpokenText, handler.state.lastSound = "", "", ""
}
if result.suppress {
handler.logger.Debug("skipped application-specific accessibility event", "type", event.Type,
"application_process", event.Source.ApplicationProcess, "role", event.Source.Role)
}
return result.event, result.suppress
}