// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package xorg /* #include "commands_native.h" #include #include #include static Display *remote_key_open(void) { Display *display = XOpenDisplay(NULL); if (!display) return NULL; int event, error, major, minor; if (!XTestQueryExtension(display, &event, &error, &major, &minor)) { XCloseDisplay(display); return NULL; } return display; } static int remote_key_resolve(Display *display, const char *name) { KeySym wanted = XStringToKeysym(name); if (wanted == NoSymbol) return 0; int result = 0; cthulhu_x11_begin_read(display); XkbStateRec state; XkbDescPtr map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd); // Multi-group and level-three policy is not implemented. Never guess a // physical key from an inactive group's symbol or a shifted-only symbol. if (map && XkbGetState(display, XkbUseCoreKbd, &state) == Success && state.group == 0) { unsigned int modifiers = state.mods & ~(ShiftMask | LockMask); for (int code = map->min_key_code; code <= map->max_key_code; code++) { unsigned int consumed; KeySym actual; if (XkbTranslateKeyCode(map, code, modifiers, &consumed, &actual) && actual == wanted) { if (result) { result = 0; break; } // Ambiguous destination. result = code; } } } if (map) XkbFreeKeyboard(map, XkbAllComponentsMask, True); if (cthulhu_x11_end_read(display)) result = 0; return result; } static int remote_key_held(Display *display, unsigned int code) { char held[32]; cthulhu_x11_begin_read(display); int success = XQueryKeymap(display, held); int error = cthulhu_x11_end_read(display); if (!success || error) return -1; return !!((unsigned char)held[code / 8] & (1u << (code % 8))); } static int remote_key_set(Display *display, unsigned int code, int pressed) { cthulhu_x11_begin_read(display); int success = XTestFakeKeyEvent(display, code, pressed, CurrentTime); int error = cthulhu_x11_end_read(display); return success && !error; } */ import "C" import ( "unsafe" "git.stormux.org/storm/cthulhu/internal/input" ) // Quarantined native prerequisite, with no production caller. All methods // require one serial caller on a locked OS thread. Xlib can block: the future // production owner must live in an independent helper, never the reader loop. type remoteKeyTarget struct { backend *remoteKeyBackend ledger *input.RemoteKeyLedger } type remoteKeyBackend struct{ display *C.Display } func openRemoteKeyTarget() (*remoteKeyTarget, error) { display := C.remote_key_open() if display == nil { return nil, input.ErrRemoteKeyUnavailable } backend := &remoteKeyBackend{display: display} ledger, err := input.NewRemoteKeyLedger(backend) if err != nil { C.XCloseDisplay(display) return nil, err } return &remoteKeyTarget{backend: backend, ledger: ledger}, nil } func (backend *remoteKeyBackend) Resolve(name string) (uint16, error) { if backend.display == nil || !input.ValidRemoteKeyName(name) { return 0, input.ErrRemoteKeyUnavailable } value := C.CString(name) defer C.free(unsafe.Pointer(value)) code := C.remote_key_resolve(backend.display, value) if code < 8 || code > 255 { return 0, input.ErrRemoteKeyUnavailable } return uint16(code), nil } func (backend *remoteKeyBackend) Held(code uint16) (bool, error) { if backend.display == nil || code < 8 || code > 255 { return false, input.ErrRemoteKeyBackend } held := C.remote_key_held(backend.display, C.uint(code)) if held < 0 { return false, input.ErrRemoteKeyBackend } return held != 0, nil } func (backend *remoteKeyBackend) Set(code uint16, pressed bool) error { if backend.display == nil || code < 8 || code > 255 { return input.ErrRemoteKeyBackend } var down C.int if pressed { down = 1 } if C.remote_key_set(backend.display, C.uint(code), down) == 0 { return input.ErrRemoteKeyBackend } return nil } func (target *remoteKeyTarget) apply(name string, pressed bool) error { return target.ledger.Apply(name, pressed) } func (target *remoteKeyTarget) retire() error { return target.ledger.Retire() } // Failed cleanup keeps the connection and ledger available for explicit retry. // Closing a connection alone is not XTEST key cleanup. func (target *remoteKeyTarget) close() error { if err := target.retire(); err != nil { return err } if target.backend.display != nil { C.XCloseDisplay(target.backend.display) target.backend.display = nil } return nil }