75 lines
2.8 KiB
Go
75 lines
2.8 KiB
Go
// Cthulhu screen reader.
|
|
// 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/input"
|
|
)
|
|
|
|
func (handler *accessibilityEventHandler) handleSelectionAndClipboard(event atspi.Event, activity input.Activity, intent input.Intent) bool {
|
|
state := handler.state
|
|
logger := handler.logger
|
|
speech := handler.speech
|
|
if activity.Clipboard == input.PasteAction && activity.Sequence == state.lastPasteSequence &&
|
|
event.Source.ID() == state.lastPasteID && time.Since(state.lastPasteAt) < time.Second &&
|
|
(event.Type == atspi.TextInsertedEvent || event.Type == atspi.TextDeletedEvent ||
|
|
event.Type == atspi.TextSelectionChangedEvent || event.Type == atspi.CaretEvent) {
|
|
if event.Type == atspi.CaretEvent {
|
|
state.suppressNextCaretPath = ""
|
|
} else if event.Type == atspi.TextSelectionChangedEvent {
|
|
state.selection.changed(event.Source)
|
|
}
|
|
logger.Debug("skipped text event following paste confirmation", "type", event.Type)
|
|
return true
|
|
}
|
|
if event.Type == atspi.TextSelectionChangedEvent {
|
|
if event.Source.ID() != state.focusedID || !event.Source.Editable || event.Source.ReadOnly ||
|
|
event.Source.Role == "password text" || event.Source.Autocomplete {
|
|
return true
|
|
}
|
|
fragmentLimit := selectionFragmentLimit
|
|
if activity.Selecting && intent == input.LineIntent {
|
|
fragmentLimit = lineSelectionFragmentLimit
|
|
}
|
|
message := state.selection.changedWithLimit(event.Source, fragmentLimit)
|
|
if message != "" {
|
|
state.pending.caret.clear()
|
|
state.selectionCaretID = event.Source.ID()
|
|
state.selectionCaretSequence = activity.Sequence
|
|
state.selectionCaretAt = time.Now()
|
|
if activity.Clipboard != input.CutAction && activity.Clipboard != input.PasteAction {
|
|
speech.Enqueue(speechRequest{Text: message, Role: "system", Cause: event.Type})
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
if activity.Sequence != 0 && activity.Sequence != state.lastClipboardSequence &&
|
|
event.Source.ID() == state.focusedID && event.Source.Editable && !event.Source.ReadOnly &&
|
|
!event.Source.Autocomplete && event.Source.Role != "password text" {
|
|
message := ""
|
|
if event.Type == atspi.TextDeletedEvent && activity.Clipboard == input.CutAction {
|
|
message = "cut"
|
|
} else if event.Type == atspi.TextInsertedEvent && activity.Clipboard == input.PasteAction {
|
|
message = "pasted from clipboard"
|
|
}
|
|
if message != "" {
|
|
state.lastClipboardSequence = activity.Sequence
|
|
if activity.Clipboard == input.PasteAction {
|
|
state.lastPasteSequence = activity.Sequence
|
|
state.lastPasteID = event.Source.ID()
|
|
state.lastPasteAt = time.Now()
|
|
state.pending.caret.clear()
|
|
}
|
|
speech.Enqueue(speechRequest{Text: message, Role: "system", Cause: "clipboard"})
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|