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,74 @@
|
||||
// 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
|
||||
}
|
||||
Reference in new issue
Block a user