61 lines
2.3 KiB
Go
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
|
|
}
|