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,135 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package input
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Intent records only the kind of input, never the text the user typed.
|
||||
type Intent uint8
|
||||
|
||||
const (
|
||||
NoIntent Intent = iota
|
||||
TypingIntent
|
||||
LineIntent
|
||||
WordIntent
|
||||
CharacterIntent
|
||||
DeleteIntent
|
||||
OtherIntent
|
||||
)
|
||||
|
||||
type Activity struct {
|
||||
Selecting bool
|
||||
Intent Intent
|
||||
Sequence uint64
|
||||
Clipboard ClipboardAction
|
||||
}
|
||||
|
||||
type ClipboardAction uint8
|
||||
|
||||
const (
|
||||
NoClipboardAction ClipboardAction = iota
|
||||
CopyAction
|
||||
CutAction
|
||||
PasteAction
|
||||
)
|
||||
|
||||
type IntentTracker struct {
|
||||
sequence uint64
|
||||
mutex sync.Mutex
|
||||
held map[string]bool
|
||||
intent Intent
|
||||
clipboard ClipboardAction
|
||||
selecting bool
|
||||
at time.Time
|
||||
}
|
||||
|
||||
func (tracker *IntentTracker) Observe(event Event) {
|
||||
tracker.mutex.Lock()
|
||||
defer tracker.mutex.Unlock()
|
||||
if event.Pressed {
|
||||
tracker.sequence++
|
||||
}
|
||||
if tracker.held == nil {
|
||||
tracker.held = make(map[string]bool)
|
||||
}
|
||||
if event.Kind == KeyModifier {
|
||||
tracker.held[event.Name] = event.Pressed
|
||||
if event.Pressed {
|
||||
tracker.intent, tracker.at = OtherIntent, time.Now()
|
||||
tracker.clipboard = NoClipboardAction
|
||||
tracker.selecting = false
|
||||
}
|
||||
return
|
||||
}
|
||||
if !event.Pressed {
|
||||
return
|
||||
}
|
||||
ctrl := tracker.held["Control_L"] || tracker.held["Control_R"]
|
||||
shift := tracker.held["Shift_L"] || tracker.held["Shift_R"]
|
||||
alt := tracker.held["Alt_L"] || tracker.held["Alt_R"] || tracker.held["Meta_L"] || tracker.held["Meta_R"]
|
||||
intent := OtherIntent
|
||||
tracker.clipboard = NoClipboardAction
|
||||
name := strings.TrimPrefix(event.Name, "KP_")
|
||||
if !alt {
|
||||
if ctrl && !shift {
|
||||
switch strings.ToLower(name) {
|
||||
case "c":
|
||||
tracker.clipboard = CopyAction
|
||||
case "x":
|
||||
tracker.clipboard = CutAction
|
||||
case "v":
|
||||
tracker.clipboard = PasteAction
|
||||
}
|
||||
}
|
||||
switch name {
|
||||
case "Up", "Down", "Page_Up", "Page_Down", "Prior", "Next":
|
||||
intent = LineIntent
|
||||
case "Left", "Right":
|
||||
intent = CharacterIntent
|
||||
if ctrl {
|
||||
intent = WordIntent
|
||||
}
|
||||
case "Home", "End":
|
||||
intent = CharacterIntent
|
||||
if ctrl {
|
||||
intent = LineIntent
|
||||
}
|
||||
case "Insert", "Caps_Lock", "Num_Lock", "Scroll_Lock", "Super_L", "Super_R":
|
||||
intent = OtherIntent
|
||||
case "BackSpace", "Delete":
|
||||
intent = DeleteIntent
|
||||
default:
|
||||
if !ctrl && (event.Name != "" && event.Kind == KeyUnknown) {
|
||||
intent = TypingIntent
|
||||
}
|
||||
}
|
||||
}
|
||||
tracker.selecting = shift && (intent == CharacterIntent || intent == WordIntent || intent == LineIntent)
|
||||
tracker.intent, tracker.at = intent, time.Now()
|
||||
}
|
||||
|
||||
func (tracker *IntentTracker) RecentIntent() Intent { return tracker.RecentInput().Intent }
|
||||
|
||||
// Reset retires held modifiers and presentation intent across secure input.
|
||||
func (tracker *IntentTracker) Reset() {
|
||||
tracker.mutex.Lock()
|
||||
defer tracker.mutex.Unlock()
|
||||
clear(tracker.held)
|
||||
tracker.intent, tracker.at = OtherIntent, time.Time{}
|
||||
tracker.clipboard, tracker.selecting = NoClipboardAction, false
|
||||
}
|
||||
|
||||
func (tracker *IntentTracker) RecentInput() Activity {
|
||||
tracker.mutex.Lock()
|
||||
defer tracker.mutex.Unlock()
|
||||
if time.Since(tracker.at) > time.Second {
|
||||
return Activity{}
|
||||
}
|
||||
return Activity{Intent: tracker.intent, Sequence: tracker.sequence, Clipboard: tracker.clipboard, Selecting: tracker.selecting}
|
||||
}
|
||||
Reference in new issue
Block a user