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,102 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package atspi
|
||||
|
||||
/*
|
||||
#include "adapter_native.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// CharacterAttributes is a copy of the current AT-SPI text attribute run.
|
||||
// Native handles remain on the GLib thread.
|
||||
type CharacterAttributes struct {
|
||||
Object ObjectID
|
||||
Values map[string]string
|
||||
}
|
||||
|
||||
var spokenCharacterAttributeKeys = [...]string{
|
||||
"size", "family-name", "weight", "indent", "underline",
|
||||
"strikethrough", "justification", "style", "paragraph-style",
|
||||
"text-spelling", "fg-color", "bg-color", "invalid", "invalid-spelling", "spelling",
|
||||
}
|
||||
|
||||
func (adapter *Adapter) ReadCharacterAttributes(ctx context.Context, object ObjectID) (CharacterAttributes, error) {
|
||||
if !object.Valid() {
|
||||
return CharacterAttributes{}, ErrStaleObject
|
||||
}
|
||||
result, err := adapter.documentOperation(ctx, treeCaptureRequest{reviewFocus: object, readAttributes: true})
|
||||
return result.attributes, err
|
||||
}
|
||||
|
||||
func (adapter *Adapter) readNativeCharacterAttributes(ctx context.Context, object ObjectID) (CharacterAttributes, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return CharacterAttributes{}, err
|
||||
}
|
||||
if len(adapter.nativeFocus) == 0 || adapter.nativeFocus[len(adapter.nativeFocus)-1].id.BusName != object.BusName {
|
||||
return CharacterAttributes{}, ErrStaleObject
|
||||
}
|
||||
var source *C.AtspiAccessible
|
||||
if adapter.nativeFocusIs(object) {
|
||||
source = adapter.nativeFocus[len(adapter.nativeFocus)-1].source
|
||||
} else {
|
||||
source = adapter.nativeDocument[object]
|
||||
}
|
||||
if source == nil {
|
||||
return CharacterAttributes{}, ErrStaleObject
|
||||
}
|
||||
if C.atspi_accessible_get_role(source, nil) == C.ATSPI_ROLE_PASSWORD_TEXT {
|
||||
return CharacterAttributes{Object: object}, nil
|
||||
}
|
||||
text := C.atspi_accessible_get_text_iface(source)
|
||||
if text == nil {
|
||||
return CharacterAttributes{Object: object}, nil
|
||||
}
|
||||
defer C.g_object_unref(C.gpointer(text))
|
||||
var nativeErr *C.GError
|
||||
count := C.atspi_text_get_character_count(text, &nativeErr)
|
||||
if nativeErr != nil {
|
||||
err := nativeError("read character attribute text length", nativeErr)
|
||||
C.g_error_free(nativeErr)
|
||||
return CharacterAttributes{}, err
|
||||
}
|
||||
if count <= 0 {
|
||||
return CharacterAttributes{Object: object}, nil
|
||||
}
|
||||
offset := C.atspi_text_get_caret_offset(text, &nativeErr)
|
||||
if nativeErr != nil {
|
||||
err := nativeError("read character attribute caret", nativeErr)
|
||||
C.g_error_free(nativeErr)
|
||||
return CharacterAttributes{}, err
|
||||
}
|
||||
if offset < 0 || offset >= count {
|
||||
offset = count - 1
|
||||
}
|
||||
var start, end C.gint
|
||||
attributes := C.atspi_text_get_attribute_run(text, offset, 1, &start, &end, &nativeErr)
|
||||
if nativeErr != nil {
|
||||
err := nativeError("read character attributes", nativeErr)
|
||||
C.g_error_free(nativeErr)
|
||||
return CharacterAttributes{}, err
|
||||
}
|
||||
if attributes == nil {
|
||||
return CharacterAttributes{Object: object}, nil
|
||||
}
|
||||
defer C.g_hash_table_unref(attributes)
|
||||
result := CharacterAttributes{Object: object, Values: make(map[string]string)}
|
||||
for _, key := range spokenCharacterAttributeKeys {
|
||||
name := C.CString(key)
|
||||
value := C.g_hash_table_lookup(attributes, C.gconstpointer(unsafe.Pointer(name)))
|
||||
C.free(unsafe.Pointer(name))
|
||||
if value != nil {
|
||||
result.Values[key] = sanitizeSnapshotField(C.GoString((*C.char)(value)))
|
||||
}
|
||||
}
|
||||
return result, ctx.Err()
|
||||
}
|
||||
Reference in new issue
Block a user