- Rust 100%
- Adw.ApplicationWindow mit Geraeteliste links, Panels rechts (Info, Batterie, DPI-Level, Lighting) wie gui/main_window.py - gui ist ein Feature: CLI und Daemon bauen ohne GTK-Toolchain - Fenster unter Xvfb verifiziert: 1000x700, Titel ghub4linux - README nennt die noch fehlenden Editoren als offen, nicht als erledigt |
||
|---|---|---|
| data | ||
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
ghub4linux-rs
Rust-Port von Ghub4Linux: Konfiguration, HID++-2.0-Kommunikation, Treiber
für die unterstützten Logitech-Geräte, CLI und (im Aufbau) die GTK4-Oberfläche.
Bauen
cargo build --release # nur CLI + Daemon, kein GTK nötig
cargo build --release --features gui # zusätzlich das Fenster (gtk4, libadwaita)
cargo test # 50 Tests, keine Hardware, kein X-Server
Das GUI ist ein Feature, weil der Daemon auf einem Server ohne GTK laufen soll — sonst zöge jeder CLI-Build eine komplette GTK-Toolchain mit.
CLI
Gleiche Kommandos, gleiche Optionen, gleiche Ausgabe wie ghub4linux-cli:
ghub4linux-cli list
ghub4linux-cli --json list
ghub4linux-cli info 046d:407f:mock123
ghub4linux-cli dpi 046d:407f:mock123 --level 0 --dpi 1600
ghub4linux-cli lighting 046d:407f:mock123 --on --effect breathing
ghub4linux-cli profile list 046d:407f:mock123
ghub4linux-cli profile copy-to-device src dst Default -n Laptop
ghub4linux-cli daemon --interval 60
ghub4linux-cli install-daemon
ghub4linux-cli monitor --interval 5
--json ist global und funktioniert auch hinter dem Subkommando. Der Exit-Code ist 1, wenn ein
Gerät oder Profil nicht gefunden wird — dieselbe Konvention wie im Original.
Die Config liegt weiter unter $XDG_CONFIG_HOME/ghub4linux/config.json und ist dateikompatibel:
Schlüsselnamen sind die Python-Dataclass-Felder, ein bestehendes File lädt unverändert. Eine
kaputte Datei wird als config.json.corrupt beiseitegelegt, statt den Start zu verhindern;
geschrieben wird über eine Temp-Datei + rename, damit ein voller Datenträger die alte Config
nicht zerstört.
Was geprüft ist
cargo test — 50 Tests:
tests/hid_framing.rs(19) — Port vontest_hid.py: exakte Bytes des 7-Byte-Kurz- und 20-Byte-Langframes, Umschalten bei vier Parametern, Function-Nibble (0x13 << 4 → 0x30), Device-Index, Truncation bei mehr als 16 Parametern, Read-Größe = Framelänge, leere Antwort →No response from device, Fehler-Wrapping für Write/Read.tests/config_and_devices.rs(22) — DPI-Defaults (400/800/1600/3200/6400, aktiv Level 1), Hex-Ausgabe, Klemmen eines veraltetenactive_profile, Save/Load-Runde,.corrupt-Backup, JSON-Schlüsselnamen, Registry-Matching inklusive geteilter Lightspeed-Receiver-PIDs über den Produktstring, DPI-Validierung (0 und >16 Bit werden vor dem Senden abgelehnt), Effekt-Codes, Batterie-Lesepfad inklusive „kaputter Read istNone, nicht 0 %", Pro DEX 2 ohne RGB, Powerplay als Mauspad.tests/cli.rs(9) — echte Binary-Aufrufe:No devices found.,[]bei--json,Device not found: …mit Exit 1 in allen sechs Kommandos, Hilfe listet alle Kommandos,install-daemonschreibt eine Unit mit absolutem Pfad und räumt die alte Template-Unit weg, Platzhalter-Ersetzung.
Abweichungen zum Original
- Ein Treiber statt Klassenhierarchie: G502 Hero/Lightspeed/X Plus und Pro DEX 2 teilen sich
LogitechMousemit einerMouseModel-Tabelle. Die Python-Subklassen unterschieden sich nur in Konstanten undhas_rgb. - Doppeltes
#korrigiert:dpiundlightingdruckten##ff0000, weilto_hex()schon ein#liefert und das Format noch eins davorsetzte. Sieht wie ein Tippfehler aus, war einer. _get_firmware_versionliefert immerUnknown: der Python-Code fragte IRoot-Funktion 5 und wertete zwei Bytes als Version — auf echter Hardware kam nie etwas anderes alsUnknownheraus. Die Funktion ist nicht portiert, das Feld bleibt ehrlich leer.- Monitor/Daemon nutzen
signal-hookstattsignal.pause();--interval 0heißt hier „so schnell wie möglich", nicht „bis zum Signal blockieren". - GUI ist im Aufbau (siehe unten): Info-, Batterie-, DPI- und Lighting-Panel sind lesend da, die Editoren für DPI/Lighting/Profile/Makros fehlen noch.
Status der GUI
cargo run --features gui öffnet ein Adw.ApplicationWindow mit Geräteliste links und Panels
rechts — dieselbe Struktur wie gui/main_window.py. Portiert sind Anzeige und Gerätewechsel;
die schreibenden Dialoge (DPI-Level setzen, Effekt wählen, Profile anlegen/umbenennen/löschen,
Makro-Editor) sind noch Python. Diese Lücke steht als Todo, nicht als erledigt.
Herkunft
Portiert am 2026-11-05 aus Ghub4Linux (src/ghub4linux, ~4.300 Zeilen inklusive Tests).
Das Original bleibt unverändert; der Wechsel ist ein install des Binaries.