Skip to content

Releases: yakuda-stack/yakuda-connect

v1.3.5 terminal appimage

Choose a tag to compare

@yakuda-stack yakuda-stack released this 22 Sep 23:17

🚀 v1.3.5 — 2026-09-23

🇩🇪 Deutsch

  • Neu: Terminal-Modus ohne Oberfläche (kein Qt, spart RAM unter VR). Befehle YC-help, YC-status, YC-wivrn-toggle, YC-openvr, YC-encoder, YC-GPU, YC-killapps, YC-autostart-reset, YC-pairing; Auswahl per Nummer oder direkt (YC-encoder vaapi). AUR-Paket und install.sh legen die Befehle systemweit an, für AppImage/Quellcode gibt es Einstellungen → Erweitert → „Befehle einrichten“ (~/.local/bin). „Im Terminal starten“ öffnet das Menü und schließt die Oberfläche, der Server läuft weiter. Neue Dateien: core/cli.py, core/cli_install.py, core/autostart_runner.py, tests/test_cli.py.
  • Autostart auch im Terminal-Modus. YC-wivrn-toggle schaltet wie der Dashboard-Schalter den Start-Timer scharf: ein kleiner Wächter im Hintergrund (ohne Qt) wartet aufs Headset, startet die Programme einmal und beendet sich. YC-killapps schließt sie (inkl. eigener Kill-Befehle, Server läuft weiter), YC-autostart-reset setzt den Start-Timer zurück. Beim Umschalten per „Im Terminal starten“ übernimmt der Terminal-Modus laufende Programme und einen noch wartenden Timer; umgekehrt schließt die Oberfläche auch Programme, die der Terminal-Modus gestartet hat.
  • Kopplung im Terminal: YC-pairing aktiviert die Kopplung (wivrnctl pair) und zeigt die PIN groß an. Enter oder Strg+C beendet sie.
  • AppImage: Delta-Updates per .zsync. Die AppImage trägt jetzt Update-Informationen (gh-releases-zsync), und zu jedem Release gibt es eine .zsync-Datei. AppImageUpdate, AppImageLauncher, AppManager, AM & Co. erkennen Updates selbst und laden nur die geänderten Teile statt der ganzen Datei. build_appimage.sh erzeugt beides und prüft es.
  • Behoben: AppImage-Start-Test meldete „nicht eindeutig“. --selftest lief durch, beim Beenden brach Qt aber ab, weil die GPU-Erkennung im Hintergrund noch lief (Exitcode 134). Der Selbsttest beendet sich jetzt sauber.

🇬🇧 English

  • New: terminal mode without GUI (no Qt, saves RAM in VR). Commands YC-help, YC-status, YC-wivrn-toggle, YC-openvr, YC-encoder, YC-GPU, YC-killapps, YC-autostart-reset, YC-pairing; pick by number or directly (YC-encoder vaapi). The AUR package and install.sh install the commands system-wide; for AppImage/source use Settings → Advanced → “Set up commands” (~/.local/bin). “Start in terminal” opens the menu and closes the GUI, the server keeps running. New files: core/cli.py, core/cli_install.py, core/autostart_runner.py, tests/test_cli.py.
  • Autostart in terminal mode too. Like the dashboard switch, YC-wivrn-toggle arms the start timer: a small background watcher (no Qt) waits for the headset, starts the programs once and exits. YC-killapps closes them (including custom kill commands, server keeps running), YC-autostart-reset resets the start timer. When switching via “Start in terminal”, terminal mode takes over running programs and a still-waiting timer; in turn the GUI also closes programs that terminal mode started.
  • Pairing in the terminal: YC-pairing enables pairing (wivrnctl pair) and shows the PIN in large type. Enter or Ctrl+C ends it.
  • AppImage: delta updates via .zsync. The AppImage now carries update information (gh-releases-zsync), and every release ships a .zsync file. AppImageUpdate, AppImageLauncher, AppManager, AM and others detect updates on their own and download only the changed parts instead of the whole file. build_appimage.sh creates and verifies both.
  • Fixed: AppImage start test said “not conclusive”. --selftest passed, but Qt aborted on exit because GPU detection was still running in the background (exit code 134). The self-test now exits cleanly.

v1.3.4: perf,old games, stick, deadzone

Choose a tag to compare

@yakuda-stack yakuda-stack released this 22 Sep 20:10

🚀 v1.3.4 — 2026-09-22

🇩🇪 Deutsch

Performance (wichtig unter VR)

  • Start rund 3 s schneller (gemessen: VRApp.__init__ 3,9 s → 0,5–0,6 s). Das Theme setzt Stylesheets nur noch, wenn sich wirklich etwas ändert. Qt poliert sonst bei jedem Aufruf neu, auch bei gleichem Text, und das bei über 1000 Widgets. Das Anwendungs-Stylesheet wird einmal gleich gefärbt gesetzt statt zweimal (theme.remember_app_base, set_style_if_changed).
  • Kein Einfrieren mehr beim Start: Die Paketprüfung lief direkt zweimal, und die zweite wartete per QThread.wait() im Haupt-Thread bis zu 2 s. Jetzt wird sie vorgemerkt und nach dem Ende des ersten Durchlaufs gestartet (beim Schließen nicht mehr).
  • Weniger Dauerlast: Der Mausrad-Schutz für Aufklapplisten hing als Event-Filter an der ganzen App. Damit lief jedes Ereignis (Mausbewegung, Neuzeichnen, Timer) durch Python, allein beim Start über 100.000 Mal. Jetzt wird nur QComboBox.wheelEvent ersetzt.
  • Tools-Tab erst beim ersten Öffnen bauen: Das sind rund 430 Widgets und etwa 10 MB, die die meisten Sitzungen nie brauchen. RAM beim Start etwa 115 → 106 MB. Der Controls-Tab liest die Tool-Daten direkt aus tools.json und baut die Karten nur, wenn er etwas installiert (_ensure_tools_ui). Im Leerlauf gemessen: 0,06 s CPU in 10 s. Der Autostart-Timer stoppt sich weiterhin selbst, sobald das Headset verbunden ist.
  • Grafikkarten-Erkennung im Hintergrund: vulkaninfo --summary lief beim Start bis zu dreimal im Haupt-Thread, und das kann auf echten Systemen spürbar dauern. Jetzt läuft die Erkennung einmal pro Sitzung in einem Hintergrund-Thread und wird gemerkt. Solange zeigt die Auswahl „Grafikkarten werden erkannt …“, die gespeicherte Karte bleibt ausgewählt. ↻ erkennt neu. Auch der Server-Start nutzt die gemerkte Liste.
  • Behoben: Design kam nach Neustart nicht zurück. theme.load() wurde nie aufgerufen, das gespeicherte Theme galt nur bis zum Schließen.
  • Aufklapplisten bleiben deckend: Qt setzt die Liste beim ersten Anzeigen der Combo zurück. Das hat bisher nur das ständige Neu-Setzen der Stylesheets überdeckt. Der Wächter beobachtet jetzt auch die Combo und merkt sich nichts mehr in Python-Attributen.

Controls: Stick-Drift, Kippen und alte Spiele (xrBinder)

  • Neu: „⇄ Kippen“ beim Stick-Drücken. Im Tasten-Dialog lässt sich für jede Funktion auf „Stick drücken“ einschalten, dass sie auch beim bloßen Kippen des Sticks auslöst (ab halbem Weg, auch schräg) — wie die beliebten Community-Bindings älterer Spiele unter SteamVR („dpad im Touch-Modus“). Geschrieben als Achs-Ausdruck für xrBinder (axis1 = step(…)), bewusst ohne max()/min(): die sind in xrBinder vertauscht.
  • Neu: Schwelle fürs Kippen (gegen Stick-Drift). Ist „⇄ Kippen“ an, steht daneben ein Regler (20–95 %, Standard 50 %): ab wie viel Ausschlag das Kippen als Drücken zählt. Ein driftender Stick bekommt einfach eine höhere Schwelle, pro Spiel und Hand. Getestet von Ketsu mit Gal*Gun 2: Menüs lassen sich jetzt ganz ohne Tastatur bedienen.
  • Neu: „◎ Deadzone“ gegen Stick-Drift. Klick auf den Stick öffnet den Dialog mit Tabs „Belegung | ◎ Deadzone“. Im Deadzone-Tab: Regler für Links, Rechts und Beide (0 = aus, 5–50 %), je mit ↺, dazu welche Funktionen betroffen sind. Gilt pro Spiel für alle Stick-Richtungen auf diesem Stick (z. B. Laufen, Drehen). Kleine Ausschläge um die Mitte kommen beim Spiel als 0 an. Geschrieben als Achs-Ausdrücke für xrBinder (axis1/axis2 = x/y * step(T, √(x²+y²))). Funktionen ohne Hand, die auf beiden Sticks liegen, bekommen keine Deadzone (sonst würde der andere Stick mit umgelegt). Ändern sich Deadzone oder Kippen, lädt YC nicht mehr live neu (stürzt in xrBinder ab), sondern meldet „gilt nach Neustart“. Klappt auch für OpenVR-Spiele, die über xrizer oder OpenComposite laufen – xrizer selbst ignoriert SteamVRs deadzone_pct. Noch nicht im Spiel getestet.
  • Alte OpenVR-Spiele über xrizer: xrizer meldet Unreal-Spiele unter ihrem Startpfad (z. B. GalGun2/Binaries/Win64/GalGun2-Win64-Shipping). Solche Namen wurden bisher aussortiert — jetzt werden sie unterstützt (Konfiguration in Unterordnern, abgesichert gegen ..), der auf 31 Zeichen gekürzte Name wird aus der Befehlszeile des Spiels vervollständigt, und in der Liste steht nur der letzte Teil. Damit lassen sich auch OpenVR-Spiele ohne Action-Datei umbelegen, solange sie über xrizer laufen.
  • xrizer unter WiVRn: Die Runtime meldet für xrizers Tasten keine Zuordnung (nur Vibration und Handposition), obwohl sie im Spiel funktionieren. Dann trägt Yakuda Connect xrizers feste Standardbelegung ein (aus dessen Quellcode, Touch/Index/Vive) und sagt das in der Statuszeile. Gesperrt wird nichts mehr, wenn die Runtime gar keine Quellen nennt.
  • Behoben: Verschieben/Kippen wirkte nie. Yakuda Connect schrieb die Tasten für beide Hände als /user/hand/both/… (ein interner Name wurde doppelt vergeben). Den Pfad gibt es nicht, deshalb lehnte die Runtime bei jedem Profil alle Layer-Tasten ab (XR_ERROR_PATH_UNSUPPORTED). „Aus“ ging trotzdem, weil es keine Taste braucht. Gefunden über das neue Diagnose-Log (Gal*Gun 2). Betroffene Dateien repariert YC beim Start selbst, die Umbelegungen bleiben erhalten.
  • xrBinder-Patch 2: Achs-Umbelegungen meldeten dem Spiel jedes Bild eine Änderung (für manche Spiele ein Dauer-Tastendruck). Beim Bauen wird das korrigiert — ältere Builds zeigen „bitte Neu bauen“.
  • xrBinder-Patch 3 (bitte „Neu bauen“): Diagnose-Log ~/.config/xrBinder/yakuda-debug.log (Ergebnis von Suggest/Attach/Sync und jede Zustandsänderung der Layer-Tasten), erreichbar über den Knopf „Diagnose-Log“ auf der Karte (immer sichtbar, sobald xrBinder gebaut ist). Scheitert der zusammengeführte Suggest, schlägt das Layer die Belegung des Spiels allein erneut vor — sonst hätte das Spiel für dieses Profil gar keine Tasten. Zwei Korrekturen für ältere xrBinder-Stände (Sync-Kopie count + sizeof, Vector2-Typ) greifen nur, wo der Fehler noch drin ist; die aktuelle Version hat sie schon behoben. Passt der Log-Teil nicht zur xrBinder-Version, wird ohne ihn gebaut.
  • xrBinder-Patch 4 (Diagnose): Das Diagnose-Log schreibt jetzt auch Stick- und Achswerte der Layer-Quellen und was das Spiel für umgelegte Sticks bekommt (nur bei Änderung, gerundet). Grundlage für ein späteres „Stick auf 4 Richtungen einrasten“.
  • Hinweis bei grauen Spielen: Läuft gerade ein OpenXR-Spiel, nennt der Hinweis unter einem Spiel „ohne Action-Datei“ dessen eigenen Eintrag in der Liste.
  • Neue Dateien: tests/test_performance.py, tests/test_xr_button_dialog.py.

🇬🇧 English

Performance (matters in VR)

  • Startup about 3 s faster (measured: VRApp.__init__ 3.9 s → 0.5–0.6 s). The theme only sets stylesheets when something actually changes. Otherwise Qt re-polishes on every call, even with identical text, across more than 1000 widgets. The application stylesheet is set once, already tinted, instead of twice (theme.remember_app_base, set_style_if_changed).
  • No more freeze at startup: the package check ran twice right away, and the second one waited up to 2 s via QThread.wait() on the main thread. It is now queued and started when the first one ends (not while closing).
  • Less constant load: the mouse-wheel guard for dropdowns was an event filter on the whole app, so every event (mouse move, repaint, timer) went through Python, over 100,000 times at startup alone. Now only QComboBox.wheelEvent is replaced.
  • Tools tab is built on first open: that is about 430 widgets and roughly 10 MB that most sessions never need. RAM at startup about 115 → 106 MB. The Controls tab reads tool data straight from tools.json and only builds the cards when it installs something (_ensure_tools_ui). Measured at idle: 0.06 s CPU in 10 s. The autostart timer still stops itself once the headset is connected.
  • Graphics card detection in the background: vulkaninfo --summary ran up to three times on the main thread at startup, which can take noticeably long on real systems. Detection now runs once per session in a background thread and is remembered. Meanwhile the dropdown shows “Detecting graphics cards …” and the saved card stays selected. ↻ detects again. Server start uses the remembered list too.
  • Fixed: design didn't come back after restart. theme.load() was never called, so the saved theme only lasted until closing.
  • Dropdowns stay opaque: Qt resets the list the first time the combo is shown. Until now only the constant re-setting of stylesheets hid this. The guard now also watches the combo and no longer keeps state in Python attributes.

Controls: stick drift, tilt and old games (xrBinder)

  • New: “⇄ Tilt” for stick presses. In the button dialog, any function on “stick press” can be set to also trigger when the stick is merely tilted (past halfway, diagonals included) — like the popular community bindings for older games under SteamVR (“dpad in touch mode”). Written as an axis expression for xrBinder (axis1 = step(…)), deliberately without max()/min(): those are swapped in xrBinder.
  • New: tilt threshold (against stick drift). With “⇄ Tilt” on, a control next to it (20–95 %, default 50 %) sets how far the stick must be tilted to count as a press. A drifting stick simply gets a higher threshold, per game and hand. Tested by Ketsu with Gal*Gun 2: menus now work without the keyboard.
  • New: “◎ Deadzone” against stick drift. Clicking the stick opens the dialog with tabs “Bindings | ◎ Deadzone”. The deadzone tab has sliders for left, right and both (0 = off, 5–50 %), each with ↺, plus which functions are affected. Applies per game to all stick directions on that stick (e.g. move, turn). Small movements around the center reach the game as 0. Written as axis expressions for xrBinder (axis1/axis2 = x/y * step(T, √(x²+y²))). Functions without a hand that sit on both sticks get no deadzone (the other st...
Read more

1.3.3 openxr controlls

Choose a tag to compare

@yakuda-stack yakuda-stack released this 21 Sep 16:21

🚀 v1.3.3 — 2026-09-21

🇩🇪 Deutsch

Controls: Tasten für OpenXR-Spiele umlegen (xrBinder)

  • OpenXR-Spiele im selben Editor wie obah. Der Bereich heißt jetzt „Controls per obah & xrBinder“. OpenXR-Spiele (z. B. viele Unreal-Spiele unter Proton) stehen mit „· OpenXR“ in derselben Spieleliste (Reihenfolge: OpenVR-Spiele, OpenXR-Spiele, ganz unten die ohne Action-Datei) und bekommen dieselbe Controller-Ansicht: zwei Controller, je Taste eine Karte, Klick öffnet den Tasten-Dialog. Der Controller wird erkannt, im Hintergrund arbeitet xrBinder von mittorn (MIT). OpenVR-Spiele laufen weiter über obah.
  • Neue Karte „xrBinder“ oben neben XR HOTAS und obah, gleiches Design. Der Schalter baut xrBinder beim ersten Mal im sichtbaren Terminal (git + cmake, ohne GUI), trägt das Layer unter ~/.local/share/openxr/1/api_layers/implicit.d/yakuda-xrbinder.json ein, schreibt ~/.config/xrBinder/xrBinder.ini und startet den IPC-Dienst (yakuda-xrbinder-ipc.service, sonst Hintergrundprozess). Eine eigene xrBinder.ini wird vorher gesichert.
  • Tasten-Dialog: je Teil der Taste (Drücken, Berühren, Stärke …) die Funktionen des Spiels, die dort liegen. „+ Funktion zuweisen“ legt eine Funktion hierher (sie verschwindet von ihrer alten Taste), „✕“ nimmt sie weg (verschoben → zurück an ihre Taste, sonst abgeschaltet). „↪“ markiert verschobene Funktionen. Die Liste zeigt nur Funktionen des erkannten Controllers; Funktionen für andere Controller (z. B. „Mixed Reality …“ bei Unreal) stehen unten unter „Andere Controller / ohne Taste“.
  • Hinweis, wenn etwas fehlt: Ist obah oder xrBinder nicht installiert (oder xrBinder aus / neu zu bauen), steht das oben im Bereich — mit Knopf „Installieren“ bzw. „Einschalten“ (gleicher Weg wie der Schalter der Karte).
  • Zurücksetzen: „↺ Standard für diese Taste“ im Dialog, „↺ Alles auf Standard“ über der Ansicht.
  • Spiel einmal starten reicht. Laufende Spiele melden sich automatisch; ihre Aktionen werden gemerkt (~/.config/yakuda-connect/xrbinder/<Spiel>.json), danach geht das Bearbeiten auch ohne laufendes Spiel.
  • Nur Tasten, die es gibt. Angeboten wird nur, was im aktiven Controller-Profil des Spiels existiert und vom Typ passt. Die Quellen stammen aus einer Tabelle der Kern-Profile der OpenXR-Spezifikation (Simple, Touch, Index, Vive, WMR), jeder Pfad wurde gegen Monados Prüfung getestet. Ein falscher Pfad hätte sonst alle Tasten des Spiels für dieses Profil gekostet.
  • Live, wo es sicher ist. Läuft das Spiel, wird nach „Speichern“ neu geladen — aber nur, wenn dabei keine aktive Umbelegung wegfällt. Das Entfernen stürzt in xrBinder das Spiel ab (nachgestellt); dann heißt es „gilt nach Neustart“.
  • Unreal-Spiele (z. B. Wanderer): Sie fragen ihre Tasten ohne Hand ab. Das aktualisiert xrBinder nicht — Umbelegungen kamen nie an. Beim Bauen wird deshalb eine Zeile in xrBinder korrigiert, und jede Umbelegung gilt zusätzlich für die Abfrage ohne Hand (aktion.any). Ältere Builds zeigen „bitte Neu bauen“.
  • Von Hand kopierte xrBinder-Dateien im implicit.d-Ordner werden erkannt; „Aufräumen“ verschiebt sie in einen Sicherungsordner, damit das Layer nicht doppelt lädt.
  • Neue Dateien: core/xrbinder.py (Dateien, Dienst, Bauen), core/xrbinder_ipc.py (UDP-Protokoll, Offsets per offsetof aus xrBinders Headern), core/xrbinder_session.py, core/xr_bindings.py (Belegungsregeln), core/tabs/xr_controls_mixin.py, ui/xrbinder_panel.py (Karte), ui/xr_button_dialog.py, tests/test_xrbinder.py, tests/test_xr_bindings.py.

🇬🇧 English

Controls: remap buttons for OpenXR games (xrBinder)

  • OpenXR games in the same editor as obah. The section is now called “Controls via obah & xrBinder”. OpenXR games (e.g. many Unreal games under Proton) appear with “· OpenXR” in the same game list (order: OpenVR games, OpenXR games, games without an action file last) and get the same controller view: two controllers, one card per button, click opens the button dialog. The controller is detected; xrBinder by mittorn (MIT) does the work in the background. OpenVR games keep using obah.
  • New “xrBinder” card at the top next to XR HOTAS and obah, same design. The switch builds xrBinder on first use in a visible terminal (git + cmake, no GUI), registers the layer at ~/.local/share/openxr/1/api_layers/implicit.d/yakuda-xrbinder.json, writes ~/.config/xrBinder/xrBinder.ini and starts the IPC service (yakuda-xrbinder-ipc.service, otherwise a background process). An existing hand-made xrBinder.ini is backed up first.
  • Button dialog: per part of the button (press, touch, strength …) the game functions currently on it. “+ Assign function” moves a function here (it leaves its old button), “✕” removes it (moved → back to its button, otherwise disabled). “↪” marks moved functions. The list only shows functions of the detected controller; functions for other controllers (e.g. “Mixed Reality …” in Unreal games) are at the bottom under “Other controllers / no button”.
  • Notice when something is missing: if obah or xrBinder is not installed (or xrBinder is off / needs a rebuild), the section says so at the top — with an “Install” or “Switch on” button (same path as the card's switch).
  • Reset: “↺ Default for this button” in the dialog, “↺ All to default” above the view.
  • Starting the game once is enough. Running games register automatically; their actions are remembered (~/.config/yakuda-connect/xrbinder/<game>.json), so editing works without the game running afterwards.
  • Only buttons that exist. Only what exists in the game's active controller profile and matches the type is offered. Sources come from a table of the OpenXR core profiles (Simple, Touch, Index, Vive, WMR); every path was checked against Monado's validation. A wrong path would otherwise have cost the game all its bindings for that profile.
  • Live where it is safe. If the game is running, “Save” reloads the config — but only if no active remapping gets removed. Removing one crashes the game in xrBinder (reproduced); then the result says “applies after restart”.
  • Unreal games (e.g. Wanderer): they query their buttons without a hand. xrBinder does not update that case, so remappings never arrived. The build now patches one line in xrBinder, and every remapping also covers the no-hand query (action.any). Older builds show “please Rebuild”.
  • Hand-copied xrBinder files in the implicit.d folder are detected; “Clean up” moves them to a backup folder so the layer is not loaded twice.
  • New files: core/xrbinder.py (files, service, build), core/xrbinder_ipc.py (UDP protocol, offsets taken via offsetof from xrBinder's headers), core/xrbinder_session.py, core/xr_bindings.py (binding rules), core/tabs/xr_controls_mixin.py, ui/xrbinder_panel.py (card), ui/xr_button_dialog.py, tests/test_xrbinder.py, tests/test_xr_bindings.py.

v1.3.2 controlls tab and ui

Choose a tag to compare

@yakuda-stack yakuda-stack released this 21 Sep 12:15

🚀 v1.3.2 — 2026-09-21

🇩🇪 Deutsch

Controls: Punkte sitzen auf den neuen Controller-Bildern

  • Neue Bilder für Touch, Index (Knuckles), Vive Wand, Vive Focus 3 und Gamepad. Die Punkte (und damit die Linien) landeten bisher daneben: Sie kamen aus obahs Profilkoordinaten, und das Bild wurde in eine Fläche mit anderem Seitenverhältnis eingepasst.
  • Neu: assets/controls/points.json. Je Bild die Pixel jeder Eingabe ("knuckles_left": {"size": [...], "points": {"/input/trigger": [x, y], ...}}). Linke und rechte Bilder haben je eigene Punkte — die rechten sind keine exakten Spiegelungen.
  • Bild mit Punkten = eigenes Seitenverhältnis. Durchsichtige Ränder werden abgeschnitten, das Bild wird höchstens 330 × 380 px groß angezeigt. Die Karten stehen nach der Höhe der Bildpunkte sortiert, damit sich die Linien nicht kreuzen.
  • Eigene Bilder funktionieren weiter. points.json wird im selben Ordner wie das Bild gesucht, also auch in ~/.config/yakuda-connect/controls/. Fehlt der Eintrag oder passt das Seitenverhältnis nicht zur Angabe, gilt das alte Verfahren (Profilpunkte, Einpassen in die Zeichenfläche).
  • obahs Profilpunkte in core/obah_editor.py wieder im Original. Sie wurden lokal auf das alte Touch-Bild umgerechnet und passten damit nicht mehr zur eingebauten Zeichnung.
  • Bilder werden je Seite gepuffert. Vorher leerte jedes Laden den Puffer — linke und rechte Seite luden sich bei jedem Neuzeichnen gegenseitig neu von der Platte.

Controls: Controller gleich groß, Linien obendrauf, Wand in der Mitte

  • Bilder paarweise zugeschnitten. Touch, Focus 3, Index und Vive: durchsichtige Ränder entfernt, links und rechts auf dieselbe Leinwand gebracht, Controller jeweils zur Mitte hin ausgerichtet. points.json mitgerechnet. Die App schneidet nicht mehr selbst zu — dadurch sind beide Seiten auf dem Schirm immer exakt gleich groß.
  • Linien laufen über den Controller statt darunter zu verschwinden.
  • Controller bleibt im Kasten. Beim Ziehen hält er an der Mitte (und an den anderen Rändern) an, statt halb zu verschwinden — auch beim Laden einer alten Anordnung nach Verkleinern des Fensters.
  • Beide Seiten bewegen sich gespiegelt. Wer den linken Controller verschiebt, verschiebt den rechten spiegelbildlich mit (und umgekehrt); gemerkt werden beide.
  • Beide Controller auf derselben Höhe. Vorher stand jeder mittig zu seiner eigenen Kartenspalte — hatte eine Seite mehr oder längere Karten (andere Belegung), saß ihr Controller tiefer. Jetzt zählt nebeneinander die höhere Spalte für beide. Ältere Anordnungen mit eigenem Versatz je Seite werden beim Laden angeglichen (links gibt den Ton an).
  • Zweite Kartenspalte zum Sortieren. Eine Karte weit nach außen ziehen legt sie in eine äußere Spalte neben der inneren; zurückziehen holt sie wieder rein. In der äußeren Spalte steht jede Karte frei in der Höhe — dort, wo man sie loslässt, nicht von oben gestapelt. Überlappen kann nichts: ragt eine Karte in eine andere, rutscht die darunter liegende nach unten. Gemerkt wird die Höhe je Karte (outer: {pfad: y}; die ältere Listenform lädt weiter). Beim Ziehen springt nichts unter der Maus — Platz reserviert der Kasten erst nach dem Loslassen (bei schmalem Fenster stehen die Seiten dann untereinander). Gemerkt wird das in der Anordnung (outer), auch in Profilen; „Anordnung zurücksetzen“ holt alles zurück.
  • Mausrad ändert keine Aufklapplisten mehr. Beim Scrollen über eine Combo scrollt die Seite weiter, statt still Spiel, Controller oder Quelle umzustellen — gilt in der ganzen App (neu: ui/no_wheel.py). In der aufgeklappten Liste scrollt das Rad wie gewohnt.
  • In der Mitte nur noch ein dünner Strich statt 24 px Lücke; beide Controller haben 4 px Abstand zur Mitte.

Controls: alle Spiele aus dem Games-Tab in der Spielauswahl

  • ① Spiel zeigt jetzt jedes Spiel aus dem Games-Tab — getestete, ungetestete, Nicht-Steam-Spiele und eigene Einträge — zusätzlich zu allen Steam-Spielen mit Action-Datei (wie bisher).
  • Ordner von Nicht-Steam-Spielen: Startordner des Steam-Eintrags, sonst der Ordner der Programmdatei. Home, /, /usr/bin & Co. werden nicht durchsucht (Heroic-/Lutris-Starter), und die Suche bricht nach 4000 Ordnern ab.
  • Spiele ohne Action-Datei stehen grau in der Liste („keine Action-Datei“), Controller und Quelle sind dann gesperrt, und die Hinweiszeile sagt, wo gesucht wurde. Ohne actions.json gibt es keine Aktionen zum Belegen — bei Spielen, die OpenXR direkt nutzen, ist das normal.
  • Gründlichere Suche nach der Action-Datei. Zusätzlich zu obahs vier Namen zählt steamvr_manifest.json (Unreals SteamVR-Input-Plugin, liegt unter Config/SteamVRBindings/) — aber nur, wenn wirklich eine Liste actions drinsteht. Findet sich im Spielordner nichts, wird im Proton-Prefix gesucht (compatdata/<AppID>/pfx/…/AppData/Local, LocalLow, Roaming, Documents, Saved Games; höchstens 8000 Ordner).
  • Action-Datei von Hand wählen: Knopf „📂 Action-Datei …“ neben ① Spiel. Die Datei wird geprüft (Liste actions muss da sein), in controls_manifests.json gemerkt (games: {"<art>:<appid>": pfad}) und gewinnt danach immer. Hat das Spiel keinen Ordner, wird der Ordner der Datei genommen (für xrizer-/OpenComposite-Dateien). „✕“ vergisst die Wahl und sucht neu.
  • Hinweis bei fehlender Datei sagt jetzt, wo gesucht wurde, und dass Spiele mit OpenXR direkt keine Action-Datei haben — dort kommt die Belegung aus dem Spiel, obah/xrizer greifen nicht.
  • Kennzeichnung: „· Nicht-Steam“ bzw. „· ohne Steam“ hinter dem Namen; der Tooltip zeigt den Ordner.
  • Neu: games.games_tab_entries(), obah_bindings.library_folder(), ObahGame.kind / has_manifest / key. Das Dropdown merkt sich die Auswahl über key statt über den Ordner (Spiele ohne Ordner).
  • Tests: test_obah_bindings.py und test_obah_aux.py erweitert.

🇬🇧 English

Controls: points sit on the new controller images

  • New images for Touch, Index (Knuckles), Vive Wand, Vive Focus 3 and Gamepad. The points (and lines) missed their buttons: they came from obah's profile coordinates while the image was fitted into an area with a different aspect ratio.
  • New: assets/controls/points.json. Pixel position of every input per image. Left and right images have their own points — the right ones aren't exact mirrors.
  • An image with points keeps its own aspect ratio. Transparent borders are cropped, the image is shown at most 330 × 380 px. Cards are sorted by the height of the image points so lines don't cross.
  • Custom images still work. points.json is looked up next to the image, so also in ~/.config/yakuda-connect/controls/. Without an entry, or if the aspect ratio doesn't match, the old method applies.
  • obah's profile points in core/obah_editor.py restored. They had been converted to the old Touch image locally and no longer matched the built-in drawing.
  • Images are cached per side. Previously every load cleared the cache, so left and right reloaded each other from disk on every repaint.

Controls: controllers same size, lines on top, wall in the middle

  • Images cropped in pairs. Touch, Focus 3, Index and Vive: transparent borders removed, left and right on the same canvas, controller aligned towards the middle; points.json recalculated. The app no longer crops by itself, so both sides are always exactly the same size.
  • Lines run over the controller instead of vanishing underneath.
  • The controller stays inside its box — dragging stops at the middle and the other edges.
  • Both sides move mirrored. Dragging one controller moves the other one mirror-wise; both are remembered.
  • Both controllers at the same height. Each used to be centred on its own card column, so the side with more or longer cards sat lower. Side by side, the taller column now counts for both; older per-side offsets are aligned on load (left leads).
  • Second card column for sorting. Drag a card far outwards to put it in an outer column; drag it back to return it. In the outer column every card stays at the height where you drop it — no stacking from the top, and nothing overlaps. Nothing jumps during the drag; the box makes room after release. Stored in the layout (outer), profiles included.
  • The mouse wheel no longer changes dropdowns. Scrolling over a combo keeps scrolling the page instead of silently switching game, controller or source — app-wide (new: ui/no_wheel.py).
  • Just a thin line in the middle instead of a 24 px gap.

Controls: every game from the Games tab in the game picker

  • ① Game now lists every game from the Games tab — tested, untested, non-Steam and your own entries — plus all Steam games with an action file (as before).
  • Folder of non-Steam games: the Steam entry's start folder, otherwise the program's folder. Home, /, /usr/bin etc. are never searched (Heroic/Lutris launchers), and the search stops after 4000 folders.
  • Games without an action file are greyed out ("no action file"); controller and source are locked and the hint says where it looked. Without actions.json there are no actions to bind — normal for games using OpenXR directly.
  • More thorough action-file search. Besides obah's four names, steamvr_manifest.json counts (Unreal's SteamVR Input plugin) — only if it really contains an actions list. If the game folder has nothing, the Proton prefix is searched too (AppData/Local, LocalLow, Roaming, Documents, Saved Games; at most 8000 folders).
  • Pick the action file yourself: "📂 Action file …" button next to ① Game. The file is validated, remembered in controls_manifests.json and always wins afterwards. "✕" forgets it and searches again.
  • Missing-file hint now says where it looked, and that games using OpenXR directly have no action file — their controls come from the game, obah/xrizer don...
Read more

test

test Pre-release
Pre-release

Choose a tag to compare

@yakuda-stack yakuda-stack released this 21 Sep 17:53

you cuti nya :3

thanks for testing nya

v1.3.1: gpu select/ controls tab / app start

Choose a tag to compare

@yakuda-stack yakuda-stack released this 19 Sep 18:02

🚀 v1.3.1 — 2026-09-19

🇩🇪 Deutsch

Neue Installationsmethode „Cargo“ im Tools-Tab

  • obah und XR HOTAS lassen sich jetzt auf jeder Distribution direkt aus der App installieren. Bisher gab es obah nur über das AUR, XR HOTAS gar nicht — beide Karten zeigten nur einen Hinweis zum Abtippen.
  • Alles läuft in einem sichtbaren Terminal. Das Skript prüft der Reihe nach: C-Compiler, benötigte Systembibliotheken, Rust/Cargo, dann den Build. Fehlt etwas, wird es nachinstalliert (sudo-Passwort im Terminal).
  • Rust wird bei Bedarf mitgebracht. Arch und Fedora nehmen das Paket der Distribution. Auf Ubuntu/Debian ist das apt-Rust zu alt (1.75, beide Tools brauchen mindestens 1.85) — dort installiert das Skript rustup für den eigenen Benutzer, ohne sudo.
  • Fehler bleiben sichtbar. Bei einem Fehler erscheint eine rote Meldung, und das Terminal bleibt offen, bis Enter gedrückt wird. Jede Ausgabe steht zusätzlich in install.log im Tool-Ordner; die Karte zeigt den Pfad an.
  • Alles liegt in einem eigenen Ordner: ~/.config/yakuda-connect/tools/cargo/<tool>/, gebaut mit cargo install --root. Ohne --root landete die Binary in ~/.cargo/bin, egal in welchem Ordner man steht. Der Startbefehl wird nach ~/.local/bin verlinkt.
  • Status, Update und Löschen wie bei AppImages. Die Karte zeigt „Installiert (Cargo)“ mit Version. obah vergleicht mit crates.io, XR HOTAS mit dem neuesten Commit im GitHub-Repo. „Löschen“ entfernt Ordner und Link ohne sudo; Rust selbst bleibt installiert.
  • XR HOTAS: OpenXR-Bibliothek wird mitinstalliert. Ohne sie scheitert der Build am Linker (cannot find -lopenxr_loader). Pakete: openxr (Arch), openxr-devel (Fedora/openSUSE), libopenxr-dev (Ubuntu/Debian).
  • Ein kaputtes Fremd-Repository bricht die Installation nicht mehr ab. apt-get update darf scheitern (z. B. wegen einer alten PPA); installiert wird trotzdem.
  • Neues Modul core/cargo_installer.py, neue tools.json-Felder crate, cargo_git und cargo_sys_deps.

Neuer Tab „Controls“

  • Neuer Seitenleisten-Eintrag „Controls“ zwischen Games und Settings, mit zwei Schaltern: „Stick-Steuerung über XR HOTAS“ (oben) und „Controls über obah“.
  • Einschalten prüft, ob das Werkzeug installiert ist. Wenn ja, bleibt der Schalter an. Wenn nicht, fragt ein Fenster, wie installiert werden soll: ein Knopf je Methode, die auf diesem System geht (Cargo, yay, paru, …), jeweils mit einer Zeile Erklärung.
  • Installiert wird über den Tools-Tab, nicht über einen eigenen Weg: dasselbe sichtbare Terminal, dieselbe Fehleranzeige, dieselbe Karte. Während der Installation ist der Schalter gesperrt.
  • Abbruch oder Fehler schalten den Schalter wieder aus und sagen, wo die Fehlermeldung steht. Läuft im Tools-Tab schon eine andere Installation, wird gewartet statt eine zweite zu starten.
  • Wird das Werkzeug im Tools-Tab gelöscht, geht der Schalter aus. Der Zustand wird in config.json gemerkt (controls_xr_hotas, controls_obah); nach einem Neustart zählt „an“ nur, wenn das Werkzeug noch da ist.
  • „▶ Starten“ öffnet das installierte Werkzeug in einem Terminal. Beendet es sich mit Fehler, bleibt das Fenster offen.
  • Neu: core/tabs/controls_mixin.py, appimage_installer.installed_locally() (schnelle Prüfung ohne Netz). Die Seitenindizes für Settings werden jetzt über pages.indexOf(tab_settings) bestimmt statt fest als 5.
  • Neu: tests/test_controls_tab.py.

Controls-Tab: einklappbarer Bereich „Controls per obah“

  • Drei Dropdowns wie die drei Schritte in obah: ① Spiel, ② Controller, ③ Bindings laden. Beim ersten Öffnen des Tabs klappt der Bereich auf und sucht im Hintergrund; danach lässt er sich ein- und ausklappen.
  • Voreinstellung beim ersten Öffnen: VRChat (falls installiert) · Oculus/Meta Touch · xrizer-Bindings. Gibt es für die Auswahl keine xrizer-Datei, wird der erste verfügbare Eintrag genommen. Was du selbst wählst, bleibt beim Spielwechsel stehen; automatisch Erzwungenes (z. B. „Von vorne beginnen“ bei einem Spiel ohne Bindings) nicht.
  • ① Spiel: alle installierten Steam-Spiele mit OpenVR-Action-Datei (actions.json, action_manifest.json, vr_actions.json, steamvr_actions.json), alphabetisch — dieselben Regeln wie obah. Eine bewusste Abweichung: obah sucht den Spielordner über den Spielnamen, Steam legt ihn aber unter installdir ab. Weichen die ab (Doppelpunkte, Zusätze wie „Deluxe“), übersieht obah das Spiel; hier taucht es auf.
  • ② Controller: obahs sieben Profile mit lesbaren Namen (z. B. „Valve Index (Knuckles)“) und dahinter, welche Bindings es fürs gewählte Spiel schon gibt (✓ Default, xrizer bzw. „keine Bindings“). Vorausgewählt wird der erste Controller mit Bindings; einen selbst gewählten Controller behält die Auswahl beim Spielwechsel.
  • ③ Bindings laden: nur die Quellen, die es gibt, in obahs Reihenfolge — Spiel-Standard, xrizer, VapoR, OpenComposite — und immer „Von vorne beginnen“. Darunter steht, welche Datei geladen würde.
  • Fehlende Dateien werden angezeigt. Manche Spiele verweisen im Manifest auf Bindings, die sie gar nicht mitliefern; obah startet dann ohne Meldung leer. Hier steht stattdessen „⚠ Datei fehlt: …“.
  • Gegen das echte obah geprüft: Spieleliste und Häkchen je Controller stimmen mit obah 0.1.1 überein (bis auf die Abweichung oben).
  • Neu: core/obah_bindings.py, tests/test_obah_bindings.py.

Bindings-Ansicht unter der Auswahl

  • Action Sets als Tabs, benannt wie in obah — bei VRChat „Global (L/R)“, „One Hand“, „Menu“, „Action Menu“, „Drone (L/R)“. Gibt das Spiel Anzeigenamen mit (localization in der actions.json), werden die genommen, auf Deutsch bevorzugt die deutschen.
  • Beide Controller nebeneinander, SteamVR-Stil: eine Zeichnung je Hand, außen je Eingabe eine Karte („Als Trigger · Ziehen → Rennen · Klick → Benutzen“), und eine Linie von der Karte zur Taste. Belegte Eingaben haben eine durchgezogene Linie, freie eine gestrichelte. Beim Überfahren leuchten Karte, Linie und Punkt auf; der Tooltip zeigt die vollen Pfade.
  • Die Tastenpositionen kommen aus obahs Controller-Profilen (binding_image_point), damit sitzen die Linien dort, wo auch SteamVR sie ansetzt. Die Controller-Zeichnung ist eine eigene, schematische Grafik — für alle sieben Controller des Dropdowns ausgearbeitet. Die rechte Hand ist die gespiegelte linke, wie in SteamVR.
  • Welche Eingaben auf welcher Seite, welche Zeilen je Modus, wie Pfade zugeordnet werden — alles nach obahs Regeln (edit_bindings.rs). Unbekannte Eingaben aus der Datei werden mit angezeigt statt verschluckt.
  • Passt sich der Fensterbreite an: nebeneinander, bei schmalem Fenster untereinander. Der Controls-Tab scrollt jetzt; Titel und Untertitel bleiben stehen.
  • Kaputte Dateien (ungültiges JSON, keine Action Sets) zeigen eine lesbare Meldung statt einer leeren Ansicht.
  • Neu: core/obah_editor.py, ui/controller_view.py, tests/test_obah_editor.py.

Bindings bearbeiten (wie obah)

  • Klick auf eine Karte öffnet das Bearbeiten-Fenster, aufgebaut wie obahs Popup: links die Bindings der Taste („#1 Joystick · Move“), rechts das gewählte Binding.
  • Alles, was obah dort kann: Binding hinzufügen und entfernen, Modus wählen (nur die Modi, die diese Taste kann), je Feld eine Aktion wählen (nur Aktionen des Action Sets mit passendem Typ, oder „keine“), Parameter hinzufügen (bekannte mit Beschreibung wie Totzone oder Achse umkehren, oder eigene), ändern und entfernen. Werte mit json: davor werden als JSON gespeichert, wie in obah.
  • Nichts geht still verloren: Unbekannte Modi, Felder und Aktionen aus der Datei bleiben erhalten und wählbar. Beim Moduswechsel fallen — wie in obah — nur die Felder weg, die der neue Modus nicht kennt.
  • „Übernehmen“ ändert die Belegung im Tab, „Speichern“ schreibt die Datei — als xrizer-, VapoR- oder OpenComposite-Binding (Pfeil am Knopf), an dieselbe Stelle wie obah. Standardziel ist die geladene Quelle, sonst xrizer. Eine vorhandene Datei wird vorher als .bak gesichert (obah überschreibt ohne Sicherung). Geschrieben wird atomar.
  • Ungespeicherte Änderungen sind sichtbar (● in der Statuszeile) und gehen beim Wechsel von Spiel, Controller oder Quelle nicht verloren: Es kommt die Frage „Speichern oder Verwerfen“. Dazu ein Knopf „Verwerfen“.
  • Karten wachsen mit ihrem Inhalt: Kommt ein Binding dazu, wird die Karte höher und die Karten darunter rücken nach.
  • Karten und Controller lassen sich verschieben: Karte ziehen = Karte verschieben, Zeichnung ziehen = Controller verschieben. Ein Klick ohne Ziehen öffnet weiterhin das Fenster. Die Anordnung wird je Controller und Hand gemerkt (controls_layout.json); „Anordnung zurücksetzen“ stellt die automatische wieder her. Linien starten an der Kartenkante, die dem Punkt zugewandt ist.
  • Neu: ui/binding_dialog.py, tests/test_obah_edit.py.

Controls-Tab: Feinschliff, Profile, Posen und Chords

  • Aufklapplisten haben jetzt einen Hintergrund. Unter KDE/Breeze ist die Liste einer Combobox ein eigenes, halbdurchsichtiges Fenster — mit dem dunklen Stylesheet stand dort nur der Text, der Inhalt dahinter schien durch. Die Durchsicht ist für diese Listen abgeschaltet, und ein Ereignisfilter setzt das erneut, wenn der Stil es beim Anzeigen zurückdreht (neu: ui/opaque_combo.py).
  • Benannte Profile über der Auswahl. „Speichern unter …“ legt Anordnung und Belegung unter einem eigenen Namen ab, „Laden“ holt sie zurück, „Löschen“ entfernt sie (controls_profiles.json). Gehört ein Profil zu einem anderen Controllertyp, wird gefragt und nur die Anordnung übernommen — eine Belegung gehört zu genau einem Controller. Eine geladene Belegung ist eine ungespeicherte Änderung, bis du speicherst.
  • Alle Controller gezeichnet: Oculus/Meta Touch, Valve Index (Knuckles), Vive Wand, Vive Focus 3, Hand-Tracking, Gamepad und Oculus Rift CV1 — jeder mit ...
Read more

v1.3.0 app closed games tab

Choose a tag to compare

@yakuda-stack yakuda-stack released this 16 Sep 21:40

🚀 v1.3.0

🇩🇪 Deutsch

WiVRn-Server wird mit der App beendet — egal, wie die App endet.

  • Neue Einstellung „WiVRn-Server mit der App beenden" unter Einstellungen → Erweitert / System, standardmäßig an. Bisher lief der Server nach dem Schließen von yakuda-connect einfach weiter und hielt Encoder und Audiogerät belegt.
  • Beendet wird wie beim Ausschalten im Dashboard: Kopplung, eigene Kill-Befehle, Autostart-Programme, dann SIGTERM an den Server. Reagiert er nach 4 s nicht, wird ein eventueller systemd-Nutzerdienst gestoppt und per SIGKILL nachgefasst.
  • X am Fenster und Schließen über die Taskleiste: Das Fenster verschwindet sofort, das Beenden läuft danach. Ein Fenster, das nach dem Klick noch sekundenlang stehen bleibt, sieht aus wie eine hängende App.
  • pkill, „Beenden" im Taskmanager/Ressourcenmonitor, Strg+C, geschlossenes Terminal: SIGTERM, SIGINT und SIGHUP werden jetzt abgefangen und laufen denselben Weg wie ein Klick aufs X. Vorher starb Python einfach, ohne dass closeEvent lief. Damit Qt das Signal sofort bemerkt und nicht erst beim nächsten Timer, weckt signal.set_wakeup_fd die Ereignisschleife über einen QSocketNotifier auf.
  • kill -9, „Prozess abschießen", Absturz: SIGKILL lässt sich nicht abfangen. Deshalb gibt es jetzt einen kleinen Wächter-Prozess (yakuda-guard, neues Modul core/exit_guard.py). Er läuft nur, solange der Server läuft und die Einstellung an ist. Er hängt an einer Pipe zur App: Stirbt die App, liest er EOF und räumt auf. Beim normalen Beenden hat die App schon selbst aufgeräumt und entlässt ihn.
  • Der Wächter ignoriert SIGTERM. pkill -f yakuda-connect trifft auch ihn, weil der Pfad in seiner Kommandozeile steht. Würde er mitsterben, bliebe genau der Fall unbewacht, für den es ihn gibt. Herumhängen kann er trotzdem nicht: Er endet immer mit der App.
  • Autostart-Programme werden über PID und Startzeit erkannt. Eine PID wird nach dem Ende eines Prozesses irgendwann neu vergeben. Der Wächter schießt keine fremde Prozessgruppe ab, nur weil sie zufällig dieselbe Nummer bekommen hat.
  • Grenze: Werden App und Wächter gleichzeitig per SIGKILL beendet (pkill -9 -f yakuda-connect), räumt niemand auf.
  • Neu: wivrn_server.stop_blocking(). Dieselbe Eskalation wie der Timer in stop_wivrn_server, aber am Stück. Beim Beenden gibt es keine Ereignisschleife mehr, die einen Timer bedienen würde.
  • Eigene Kill-Befehle laufen über exit_guard.run_kill_commands(), weil App und Wächter dieselben Befehle ausführen müssen.

Nicht-Steam-Spiele im Games-Tab

  • „+ Spiel hinzufügen" zeigt jetzt auch Spiele, die in Steam als Nicht-Steam-Spiel eingetragen sind (Heroic-, Lutris- und GOG-Starter, eigene Builds, Emulatoren). Sie stehen in der Steam-Auswahl, gekennzeichnet mit „(Nicht-Steam-Spiel)".
  • Sie bekommen dieselben Einstellungen wie Steam-Spiele: Proton-Auswahl, Startparameter-Schalter, eigene Parameter, Config-Backup, Play-Knopf auf Kachel und Panel, „Entfernen". Das geht, weil ein Nicht-Steam-Spiel in Steam eine vollwertige AppID hat. Die gemerkten Einstellungen, CompatToolMapping und compatdata/ funktionieren damit unverändert.
  • Neues Modul core/steam_shortcuts.py liest Steams userdata/<Konto>/config/shortcuts.vdf. Die Datei ist binär, der Textparser für config.vdf kann sie nicht lesen. Alle Steam-Konten und Flatpak-Steam werden berücksichtigt; ein Link von ~/.steam/steam auf dieselbe Datei zählt einmal.
  • Die AppID wird vorzeichenlos verwendet. Steam speichert sie als vorzeichenbehaftete 32-Bit-Zahl, benutzt in CompatToolMapping, compatdata und grid aber dieselben Bits ohne Vorzeichen. Nicht-Steam-IDs haben das oberste Bit gesetzt und lassen sich so von echten AppIDs unterscheiden, ohne eine zweite ID-Art einzuführen. Sehr alte Einträge ohne appid-Feld bekommen Steams CRC32-ID.
  • Startparameter landen im Feld LaunchOptions in shortcuts.vdf, nicht in localconfig.vdf. Geschrieben wird verlustfrei: Jedes nicht geänderte Byte bleibt gleich, unbekannte Feldtypen führen zum Abbruch statt zu einer halb verstandenen Datei. Vorher entsteht shortcuts.vdf.bak.<Zeit>, geschrieben wird atomar.
  • Die Startparameter, die der Eintrag schon hatte, bleiben erhalten. Heroic- und Lutris-Einträge starten nur über sie (heroic://launch/..., lutris:rungameid/...). Sie werden beim Eintragen einmal gemerkt und im Panel als Basis-Parameter verwendet, wie die hinterlegten Parameter eines kuratierten Spiels. Später aus der Datei gelesen, stünden dort schon die eigenen Schalter, und ein abgeschalteter ließe sich nie mehr entfernen.
  • Gestartet wird über steam://rungameid/<Spiel-ID> mit der 64-Bit-ID (AppID << 32) | 0x02000000. -applaunch kennt nur echte Steam-Spiele.
  • Cover kommen nur aus dem Grid-Ordner, jetzt auch im Querformat (<AppID>.png) und als Hero-Bild. Einen Download-Versuch bei Steams Bildserver gibt es für Nicht-Steam-Spiele nicht.
  • Nur von Hand eingetragen, nie automatisch erkannt. Steam führt für sie keine VR-Kategorie, und der Programmpfad zeigt bei Heroic/Lutris nur auf einen Starter. Raten würde jeden Emulator mit einsammeln. Wird das Spiel in Steam gelöscht, verschwindet es beim nächsten Scan.
  • Hinweis bei laufendem Steam: Steam schreibt shortcuts.vdf selbst neu, sobald man dort einen Eintrag bearbeitet. Läuft Steam beim Play-Klick, empfiehlt die Statuszeile deshalb, Steam vorher zu schließen.

Windows-Spiele über Steam statt Wine, Bilder für eigene und Nicht-Steam-Spiele

  • Die rechte Spalte „Eigenes Spiel hinzufügen" nimmt keine .exe mehr als eigenes Spiel an. Ohne Steam liefen Windows-Programme nur über das nackte wine — ohne Proton, ohne Steams Runtime und damit für VR praktisch nie brauchbar. Wählt man eine .exe, erscheint statt „Hinzufügen" ein Hinweis und der Knopf „In Steam eintragen". Native Programme (AppImage, *.x86_64, Skripte) bleiben eigene Spiele wie bisher.
  • „In Steam eintragen" legt das Programm als Nicht-Steam-Spiel in Steam an (steam_shortcuts.add_shortcut) und holt es sofort in die Liste — mit Proton-Auswahl, Startparametern und allen übrigen Einstellungen. Die AppID wird wie bei Steam ROM Manager aus CRC32(Exe + Name) gebildet, dasselbe Programm unter demselben Namen bekommt also nie einen zweiten Eintrag. Pfade stehen wie bei Steam in Anführungszeichen, damit Leerzeichen funktionieren.
  • Das richtige Steam-Konto: Eingetragen wird beim zuletzt angemeldeten Konto (loginusers.vdf, MostRecent), sonst beim einzigen, sonst bei dem mit der jüngsten localconfig.vdf. Gibt es noch keine shortcuts.vdf, wird sie angelegt. Ist die vorhandene nicht lesbar, wird nichts geschrieben.
  • Steam wird vorher beendet, genau wie bei „Use" — sonst würde Steam den neuen Eintrag beim Beenden wieder löschen. Der Ablauf „nachfragen → steam -shutdown → warten → schreiben" liegt dafür jetzt in einem eigenen Modul core/steam_close.py, das Games-Tab und Dialog gemeinsam nutzen. Wird der Dialog geschlossen, während er noch auf Steam wartet, wird nichts mehr geschrieben.
  • Bestehende eigene .exe-Einträge bleiben erhalten. Ihr Panel zeigt denselben Hinweis und „In Steam eintragen". Klappt das, wird der eigene Eintrag durch den Steam-Eintrag ersetzt (sonst stünde das Spiel doppelt in der Liste). Scheitert es, bleibt er unverändert.
  • Neue Zeile „Bild (optional)" im Dialog und in den Panels eigener und Nicht-Steam-Spiele, mit „Bild wählen …" und „Bild entfernen" (PNG/JPG).
    • Bei eigenen Spielen wird das Bild in die App-Config kopiert, nicht nur verlinkt — ein Bild aus dem Download-Ordner wäre sonst nach dem Aufräumen weg. Der Dateiname ist zufällig: Kennungen wie local:3 werden nach dem Löschen wiederverwendet, ein neues Spiel soll nicht das Bild des alten erben. Beim Wechseln oder Entfernen wird nur die eigene Kopie gelöscht, nie das Original.
    • Bei Nicht-Steam-Spielen landet es als <AppID>p.png in Steams grid-Ordner und erscheint damit auch in der Steam-Bibliothek. Querformat-, Hero- und Logo-Bilder (z. B. von SteamGridDB) bleiben unberührt.
    • Auch links unter „Steam-Spiel hinzufügen": Wählt man dort ein Nicht-Steam-Spiel, erscheint dieselbe Bildzeile. Für echte Steam-Spiele bleibt sie ausgeblendet, die haben ihr Cover von Steam. Ein falscher Bildpfad trägt nichts ein; steht das Spiel schon in der Liste, wird nur das Bild gesetzt.

„Use" setzt Steams Haken „Kompatibilitätswerkzeug erzwingen" zuverlässig

  • Hintergrund: Dieser Haken in Steams Eigenschaften ist nichts anderes als der Eintrag des Spiels in config.vdfCompatToolMapping. „Use" hat ihn schon immer geschrieben, er kam aber in drei Fällen nicht an. Die sind jetzt behoben.
  • Steam wird vorher beendet. Steam hält config.vdf im Speicher und schreibt sie beim Beenden zurück. Ein Eintrag, der geschrieben wurde, während Steam lief, war danach weg — auch der bisherige Hinweis „greift nach einem Steam-Neustart" stimmte deshalb nicht, der Neustart war genau der Moment des Überschreibens. Läuft Steam, fragt „Use" jetzt, ob Steam beendet werden soll (steam -shutdown), wartet bis zu 30 Sekunden und schreibt erst danach. Klappt das Beenden nicht, wird nichts geschrieben.
  • Auch Valves Proton wird eingetragen. „Proton 11 (Standard)" hieß bisher: Eintrag entfernen, Steam nimmt sein Standard-Proton. Für Store-Spiele stimmt das, für Nicht-Steam-Spiele nicht — ohne Eintrag startete Steam die .exe ganz ohne Proton. Jetzt wird der interne Name des installierten Valve-Protons eingetragen (proton_11, sonst das neueste installierte, sonst proton_experimental). Ist gar keins installiert, sagt die App das.
  • Eingetragen wird der interne Tool-Name, nicht der Ordnername. Steam kennt ein Tool unter dem Namen aus seiner compatibilitytool.vdf. Meist ist das derselbe, bei Distributionspaketen oft nicht — und einen unbekannten Namen ignoriert Steam, der Haken bleibt aus. K...
Read more

v1.2.9 Discord link update and games tab scan and mauell added

Choose a tag to compare

@yakuda-stack yakuda-stack released this 16 Sep 07:36

🚀 v1.2.9

🇩🇪 Deutsch

Der Games-Tab ist überarbeitet: Erkennung, Auto-Scan, eigene Spiele.

  • VR-Spiele werden jetzt so erkannt, wie Steam selbst es tut. Bisher wurde geraten: für jedes installierte Spiel lief ein Verzeichnis-Durchlauf auf der Suche nach openvr_api.dll oder einem openxr_loader. Das war langsam (bei großen Bibliotheken zweistellige Sekunden) und in beide Richtungen ungenau.
  • Neue Datenquelle: appcache/appinfo.vdf (neues Modul core/steam_appinfo.py). Steams eigener PICS-Zwischenspeicher — genau das, was hinter dem VR-Filter in der Steam-Bibliothek steckt. Liegt lokal auf der Platte: kein Netz, kein Steam-Login, kein API-Schlüssel. Beide Formatversionen (v40 mit Zeichenketten-Schlüsseln, v41 mit Zeichenketten-Tabelle) werden gelesen; nicht gesuchte Apps werden im Datenstrom übersprungen statt zerlegt, deshalb bleibt der Aufruf auch bei einer großen Datei schnell.
  • Drei ODER-verknüpfte Signale aus derselben Datei: die *vrsupport-Felder (openvrsupport, onlyvrsupport, openxrsupport, othervrsupport*), Valves Kategorien 31/53/54 (VR Support / VR Supported / VR Only) und playareavr. Kein Signal deckt für sich alles ab — die Felder sind gewachsen und bei nachträglich um VR ergänzten Titeln oft nicht gesetzt, die Kategorie hängt dagegen an der Store-Angabe des Entwicklers.
  • Kategorie 52 (Tracked Controller Support) zählt bewusst NICHT. Sie heißt nur, dass ein Spiel mit VR-Controllern umgehen kann. Das allein sagt nichts darüber, ob es in VR läuft.
  • Der User-Tag „VR" (tagid 21978) wird ebenfalls NICHT ausgewertet. Er wird von Spielern vergeben und steht unter anderem an OBS Studio, VoiceAttack, BeamNG.drive und mehreren Visual Novels. Als Signal wäre er unbrauchbar.
  • Werkzeuge, DLC und Soundtracks fliegen über common/type raus, statt am Namen erkannt zu werden. Steam schreibt den Typ selbst hin.
  • Die alte Dateierkennung bleibt als zweite Quelle — für alles, was Steam nicht kennzeichnet. Dadurch kann die Liste nie kürzer sein als vorher.
  • Damit das bezahlbar bleibt, wird jedes Ergebnis gecacht (Schlüssel: AppID + Änderungszeit des Installationsordners). Der teure Verzeichnis-Durchlauf läuft einmal je Spiel; danach ist der Scan sofort da. Aktualisiert Steam ein Spiel, springt die Änderungszeit und es wird neu geprüft — ein Titel, der VR nachrüstet, taucht von selbst auf. Eine Cache-Version entwertet alte Ergebnisse, wenn sich die Erkennung ändert.
  • Was Steam schon beantwortet hat, wird nicht nochmal durchsucht. Der teure Zweig läuft nur für Spiele, zu denen Steams Daten schweigen.

Auto-Scan

  • Der Tab scannt beim Öffnen selbst. Den „Spiele scannen"-Knopf haben viele schlicht übersehen und standen vor einer unvollständigen Liste — der häufigste Grund für „erkennt meine Spiele nicht". Jetzt wird zuerst der Cache angezeigt und dann im Hintergrund nachgesehen. Standardmäßig an, abschaltbar unter Einstellungen → Allgemein → Spiele.
  • Die Kacheln werden nur bei einer echten Änderung neu gebaut. Sonst würde ein aufgeklapptes Spiel bei jedem Tab-Wechsel zuklappen. Verglichen wird über eine Signatur aus AppIDs und Namen; benennt Steam ein Spiel um, zieht die Kachel nach.
  • Der Scan-Knopf bleibt währenddessen bedienbar. Ein Vorgang, den der Nutzer nicht angestoßen hat, darf ihm nicht die Oberfläche sperren.

„+ Spiel hinzufügen"

  • Neuer Knopf mit zweispaltigem Dialog (core/games_add_dialog.py). Das Ventil neben der Erkennung: die bleibt streng, und alles, was Steam nicht (oder falsch) kennzeichnet, trägt man hier selbst ein.
  • Option 1 — Steam-Spiel: ein durchsuchbares Auswahlfeld über ALLE installierten Steam-Spiele, unabhängig von der VR-Kennzeichnung. Gesucht wird nach Wortteilen statt nach dem Anfang („saber" findet „Beat Saber"). Bereits eingetragene Spiele bleiben sichtbar und werden gekennzeichnet. Ein Handeintrag überlebt jeden Neuscan und ist über einen Knopf im Detail-Panel zurücknehmbar.
  • Option 2 — Eigenes Spiel: Name, Pfad zur Programmdatei mit „Durchsuchen ..." und optionale Startparameter. Unterstützt native Binaries, Unity-Builds (.x86_64/.x86), AppImages, Start-Skripte (.sh) und Windows-Programme (.exe) über Wine.
  • Eigene Spiele bekommen eine eigene Sektion und ein schlankeres Panel. Ohne AppID gibt es kein CompatToolMapping, keine Proton-Auswahl und keine Steam-Startparameter — diese Bedienelemente anzuzeigen wäre eine Zusage, die für so einen Eintrag nicht einzuhalten ist.
  • Windows-Programme laufen über Wine, nicht über Proton. Proton braucht ein von Steam verwaltetes Prefix samt AppID. Fehlt Wine, sagt die App das, statt kommentarlos nichts zu tun.
  • Das Arbeitsverzeichnis wird auf den Ordner der Programmdatei gesetzt. Unity- und Godot-Builds suchen ihre Datenordner relativ dazu und starten sonst mit schwarzem Bild.
  • Fehlt die Programmdatei, steht das im Panel und nicht erst beim Startversuch. Nach einem Spiele-Umzug ist das der Normalfall.
  • Kacheln eigener Spiele lösen keinen Cover-Download aus — sonst liefe für jeden Eintrag eine Anfrage an Steams Bildserver mit local:3 als AppID.

Spiele aus der Liste entfernen

  • Neu: „Entfernen" im aufgeklappten Panel, direkt neben „Config zurückspielen". Nimmt ein Spiel dauerhaft aus der VR-Liste — die Erkennung liegt gelegentlich daneben.
  • Die Rückfrage sagt, was NICHT passiert: das Spiel bleibt installiert, nur der Eintrag verschwindet. Ein Knopf mit der Aufschrift „Entfernen" neben einer Spielekachel liest sich sonst leicht als „deinstallieren".
  • Zwei Wege zurück: das Spiel über „+ Spiel hinzufügen" wieder eintragen, oder Einstellungen → Allgemein → Spiele → „Games-Tab zurücksetzen".
  • Ein Handeintrag hebt das Entfernen auf und umgekehrt. Sonst stünden zwei gegensätzliche Wünsche in der Config, und welcher gewinnt, wäre eine Frage der Auswertungsreihenfolge statt einer Entscheidung des Nutzers.

Kleineres

  • Neuer Discord-Server: https://discord.gg/ShNKvvZu74 (gepflegt in core/main.py, Zeile 50).
  • Thief VR: Legacy of Shadow hat wieder eine Kachelgrafik. Steams Bildpfade folgen nicht durchgängig dem Muster .../<appid>/header.jpg; neuere Titel haben einen Hash im Pfad. games.json kennt dafür jetzt ein Feld picture, dessen URL beim Download zuerst probiert wird.
  • Neu: scripts/steam_vr_debug.py. Zeigt die Zwischenschritte, die man sonst nicht sieht: welche appinfo.vdf gefunden wurde und in welcher Formatversion, welche VR-Felder und Kategorien Steam pro Spiel setzt, welches Signal gegriffen hat ([VR ] Steam, [DAT] Dateien, [HAND] von Hand) und wie groß der Cache ist. Reines Lesewerkzeug.
  • Eine f-Zeichenkette ohne Platzhalter in core/netbuffers.py entfernt — ruff lief deswegen rot.

Tests

  • Drei neue Testdateien mit zusammen 100 Prüfungen (test_steam_appinfo.py, test_games_scan.py, test_games_tab.py); gesamt 617 statt 486. Der Smoke-Test steht bei 35 statt 24 Prüfungen.
  • Der Parser wird gegen selbst gebaute appinfo.vdf-Dateien geprüft — in beiden Formatversionen UND in beiden Formen (mit dem Rahmen-Knoten appinfo, so wie Steam schreibt, und ohne). Der Rahmen ist die Stelle, an der die Erkennung beim Bau einmal komplett gescheitert ist: common eine Ebene zu hoch gesucht, jedes Spiel galt als „kein VR", und kein Fehler tauchte auf, weil eine leere Angabe ein gültiges Ergebnis ist. Ein selbst gebauter Prüfling ist nur so gut wie das Verständnis des Formats.
  • Festgenagelt sind unter anderem: das Überspringen nicht gesuchter Apps landet auf dem richtigen Byte (ein Fehler dabei liefert nicht nichts, sondern zufällig aussehende Treffer), Kategorie 53/54/31 zählt und 52 nicht, die Dateierkennung ergänzt wirklich was Steam verschweigt, der teure Durchlauf läuft beim zweiten Scan gar nicht mehr, ein entferntes Spiel bleibt nach dem Scan weg, der stille Scan lässt ein offenes Panel stehen, und der Scan-Knopf scannt nicht still.

🇬🇧 English

The Games tab has been reworked: detection, auto-scan, local games.

  • VR games are now detected the way Steam itself does it. It used to guess: for every installed game it walked the install folder looking for openvr_api.dll or an openxr_loader. That was slow (double-digit seconds on large libraries) and inaccurate both ways.
  • New data source: appcache/appinfo.vdf (new module core/steam_appinfo.py). Steam's own PICS cache — exactly what backs the VR filter in your Steam library. It sits on your disk: no network, no Steam login, no API key. Both format versions (v40 with string keys, v41 with a string table) are supported; apps you didn't ask for are skipped in the stream rather than decoded, which keeps the call fast even on a large file.
  • Three OR-linked signals from the same file: the *vrsupport fields (openvrsupport, onlyvrsupport, openxrsupport, othervrsupport*), Valve's categories 31/53/54 (VR Support / VR Supported / VR Only) and playareavr. No single signal covers everything — the fields have grown organically and are often unset on titles that added VR later, while the category follows what the developer declares in the store.
  • Category 52 (Tracked Controller Support) deliberately does NOT count. It only means a game can handle VR controllers, which on its own says nothing about whether it runs in VR.
  • The "VR" user tag (tagid 21978) is NOT used either. Players assign it, and it sits on OBS Studio, VoiceAttack, BeamNG.drive and several visual novels. As a signal it would be useless.
  • Tools, DLC and soundtracks are filtered via common/type instead of being guessed from the name. Steam writes the type itself.
  • The old file detection stays as a second source — for anything Steam doesn't tag. The list can therefore never be shorter than before.
  • To keep that affordable, every result is cached (key: app ID + the install folder's modification time)....
Read more

v1.2.8 usb/usb connection fix and diagnostic tool

Choose a tag to compare

@yakuda-stack yakuda-stack released this 15 Sep 09:36

🚀 v1.2.8 2026-09-15

🇩🇪 Deutsch-

  • Neu: „adb reparieren" (core/adb_doctor.py). Nach einem Systemupdate von android-tools findet adb die Brille oft nicht mehr, obwohl sich am Kabel nichts geändert hat. Dahinter stecken vier verschiedene Ursachen, die für den Nutzer identisch aussehen — die App unterscheidet sie jetzt und sagt, welcher Handgriff dran ist.
  • Ursache 1, Versionskonflikt: das Update hat /usr/bin/adb ersetzt, der laufende adb-Server ist aber noch der alte. Normalerweise heilt das von selbst; nicht aber, wenn ein anderes Programm (SideQuest, Android Studio) den Server festhält oder er unter einem anderen Benutzer läuft. Der Knopf macht kill-server + start-server.
  • Ursache 2, fehlende Bestätigung: beim Serverneustart fragt die Brille erneut „USB-Debugging zulassen?". Liegt sie auf dem Tisch, tippt das niemand weg. Die App wertet ein unauthorized nach der Reparatur deshalb nicht als Fehlschlag, sondern schickt den Nutzer gezielt in die Brille — samt Hinweis auf den Haken „Immer von diesem Computer zulassen".
  • Ursache 3, udev-Regeln: adb meldet no permissions. Wird sauber von unauthorized getrennt, weil der eine Fall auf dem PC spielt und der andere in der Brille. Nur hier werden die Regeln per pkexec neu geladen — die Passwortabfrage kommt also nicht bei jedem Klick auf „Reparieren", und der Dialog kündigt sie vorher an.
  • Ursache 4, MTP hält das Gerät: läuft gvfsd-mtp oder ein anderes MTP-Backend, hängt die Meldung im Dateimanager („Zugriff auf das Gerät ist nicht möglich") mit dem schweigenden adb zusammen. Steht als Zusatz in der Statuszeile, blockiert aber nichts — es ist ein Indiz, kein Beweis.
  • „Gestern ging es noch" bekommt ein Datum. Nach jedem erfolgreichen Handshake merkt sich die App die Version von android-tools; klemmt es später, steht die Erklärung in der Statuszeile: „wurde seit dem letzten funktionierenden Zugriff aktualisiert (36.0.0-1 → 36.1.0-1)". Abgefragt wird über pacman, rpm oder dpkg, je nach Distribution; fehlt das Paket überall (handinstalliertes adb), entfällt der Hinweis, statt zu raten.
  • stderr wird mitgelesen. Die entscheidenden Sätze („doesn't match this client", „no permissions") schreibt adb nach stderr, während die leere Geräteliste auf stdout steht. Wer nur stdout liest, meldet „kein Gerät" und schickt den Nutzer in die falsche Richtung.
  • ~/.android/adbkey wird nicht angefasst. Das Löschen ist der häufigste Forenrat und der schädlichste: danach muss jedes Android-Gerät des Nutzers neu bestätigt werden, nicht nur die Brille. Ein Test nagelt fest, dass das Modul das auch in Zukunft nicht tut.
  • Der Reparatur-Knopf erscheint nur neben einem echten Problem — und nicht bei „adb ist nicht installiert", denn da hilft kein Serverneustart, sondern der Tools-Tab.
  • Worker-Referenzen werden erst bei Qts finished freigegeben, nicht im Ergebnis-Slot. Das eigene Ergebnis-Signal wird aus run() heraus gesendet, also bevor der Thread endet — fällt dort die letzte Referenz weg, räumt Python das QThread-Objekt ab, während es noch läuft, und Qt beendet den Prozess mit „Destroyed while thread is still running". Das trat beim Smoke-Test genau einmal auf und lief danach zwanzigmal sauber durch; solche Abstürze fallen je nach Speicherbereinigung an oder eben nicht. Betrifft _apk_worker, _connect_worker und _doctor_worker.
  • Neue Testdatei tests/test_adb_doctor.py mit 15 Tests, ohne adb und ohne Gerät: Versionskonflikt auf stderr, Trennung von no permissions und unauthorized, ein bereites Gerät gewinnt gegen ein hängendes, Paketupdate-Erkennung samt kaputter Zustandsdatei, udev nur bei Rechteproblem, und der adbkey-Wächter.
  • Neuer Knopf „Verbinden (USB)" neben der Headset-Liste. Macht genau das, was WiVRns eigenes Dashboard macht: adb reverse tcp:9757 tcp:9757, dann am start mit dem Intent wivrn+tcp://localhost. Über WLAN gibt es den Knopf bewusst nicht — dort kann der PC die Verbindung gar nicht auslösen, da klickt immer die Brille.
  • Fehlerbehebung: „Automatisch per USB verbinden" verbindet jetzt auch automatisch. Der Haken schrieb die Option bisher nur in wivrn-dashboard.conf — gelesen und ausgeführt wird sie aber vom WiVRn-Dashboard, das dafür selbst adb pollt. Wer Yakuda Connect statt des Dashboards benutzt, also der Normalfall, hatte damit einen Haken, der eine Einstellung setzt, die niemand ausführt: man musste trotzdem zum PC laufen und klicken. Jetzt pollt Yakuda Connect selbst — der Takt war ohnehin da (usb_poll_timer, alle vier Sekunden).
  • Ausgelöst wird an der Kante, nicht am Zustand. Verbunden wird einmal pro Ansteckvorgang; scharf wird der Auslöser erst wieder, wenn die Brille verschwunden war. Ohne diese Bremse feuerte alle vier Sekunden ein Intent — auch mitten im Spielen —, und ein absichtliches „Trennen" wäre vier Sekunden später wieder rückgängig gemacht gewesen. Man käme gegen sein eigenes Programm nicht an.
  • Manuelles Trennen und ein abgebrochener Versuch entschärfen den Auslöser. Wer trennt oder abbricht, will das auch.
  • Läuft das offizielle WiVRn-Dashboard, hält sich Yakuda Connect heraus — dort passiert dasselbe schon. Der Auslöser bleibt aber scharf: wird das Dashboard beendet, übernehmen wir.
  • Ohne laufenden Server wird gewartet, nicht aufgegeben. Der Tunnel wäre sinnlos und die Brille liefe in einen Verbindungsversuch ins Leere. Startet der Server danach, greift der nächste Durchlauf — ohne dass das Kabel noch einmal angefasst werden muss.
  • Neue Testdatei tests/test_usb_autoconnect.py mit 12 Tests am Mixin, ohne Fenster: einmal pro Ansteckvorgang, Kabel ab macht wieder scharf, manuelles Trennen wird nicht überstimmt, laufendes Dashboard und fehlender Server, unauthorized ist kein Anlass.
  • core/main.py ist geteilt: neues core/tabs/dashboard_mixin.py. Die Datei war wieder über 4500 Zeilen lang — der Punkt, an dem man Änderungen darin nicht mehr gern macht. Umgezogen sind 38 Blöcke mit rund 920 Zeilen: USB-Ampel, Headset-Liste, Kopplung, Verbinden per Kabel, adb-Doktor und die APK-Logik, samt der fünf Worker-Klassen, die ausschließlich dort gebraucht werden. Dritter Schnitt nach games_mixin und tools_mixin, gleiches Muster — main.py steht jetzt bei 3640 Zeilen.
  • Die Worker bleiben unter ihrem alten Namen erreichbar (main.UsbConnectWorker und so weiter): ein Umzug soll keine Importpfade brechen, weder in Tests noch bei irgendetwas, das sich darauf verlässt.
  • Beim Schnitt aufgefallen: PairingPinWorker war verschwunden. Der Umbau des Connect-Workers in dieser Version hat den Block mit überschrieben, toggle_pairing_mode hätte beim Einschalten des Kopplungsmodus einen NameError geworfen. Kein Test hat es bemerkt, weil die Klasse nirgends konstruiert wird — erst der Umzug hat sie vermisst. Wiederhergestellt.
  • Neu: „Diagnose kopieren" (core/diagnostics.py). Sammelt die Randbedingungen, nach denen sonst bei jeder zweiten Fehlermeldung einzeln gefragt wird: Versionen, Distribution, Desktop und Sitzungstyp, Flatpak/AppImage, GPU, OpenXR-Runtime, adb-Zustand, Firewall und Netzwerkpuffer. Als Textblock in der Zwischenablage, fertig zum Einfügen in ein GitHub-Issue oder den Chat.
  • Der Versionsabgleich steht ausgewertet im Bericht, nicht als zwei Nummern zum Selbstvergleichen: „Versions match: NEIN — Client und Server passen nicht zusammen". Das ist die häufigste Ursache für „verbindet nicht" und gehört als Klartext dorthin.
  • Schwärzung im Diagnosebericht zerlegte den Programmnamen. Wenn der Benutzername im Programmnamen steckt — beim Autor ist genau das der Fall: Benutzer yakuda, Programm yakuda-connect — wurde aus der Kopfzeile <user>-connect diagnostics und aus jedem Cache-Pfad ~/.cache/<user>-connect/app.log. Der Bericht war damit an den Stellen unleserlich, an denen er etwas aussagen soll. Geschützte Namen (SAFE_LITERALS) werden jetzt vor der Schwärzung beiseitegelegt und danach in ihrer Originalschreibweise zurückgelegt.
  • Der Benutzername fällt jetzt unabhängig von der Groß-/Kleinschreibung. Vorher überlebte er jede abweichende Schreibweise — chown Yakuda failed stand unverändert im Bericht.
  • Nichts Persönliches im Bericht. Er landet in öffentlichen Issues: der Heimatpfad wird zu ~ gekürzt, und der Benutzername fällt auch aus Pfaden heraus, die anders gebaut sind — Steam-Bibliotheken auf anderen Laufwerken, Flatpak-Pfade, Fehlermeldungen. IP-Adressen und Hostnamen werden gar nicht erst gesammelt. Namen unter drei Zeichen werden nicht ersetzt, sonst schlüge ein Benutzer namens „vr" mitten in anderen Wörtern zu.
  • Der Bericht entsteht auch, wenn alles kaputt ist. Jede Abfrage ist einzeln abgesichert und liefert im Fehlerfall einen Platzhalter — gebraucht wird er ja genau dann, wenn etwas nicht funktioniert.
  • Der bestehende Speichern-Knopf nutzt denselben Bericht und hängt nur zusätzlich das Ende des Logs an. Der neue Kopier-Knopf lässt es weg: in eine Chatnachricht passt es ohnehin nicht.
  • Neue Testdatei tests/test_diagnostics.py mit 12 Tests: Bericht trotz durchgehend scheiternder Abfragen, einzelne Ausfälle kippen die folgenden Abschnitte nicht, Schwärzung von Heimatpfad und Benutzername (auch im Logschwanz), kurze Namen bleiben stehen, ausgewerteter Versionsabgleich.
  • Verbinden per USB hält jetzt Stille aus (PICO-4-Fall). Die PICO blockiert adb, solange die USB-Schnittstelle im Dateiübertragungs-Modus verhakt ist — adb antwortet dann gar nicht, und ein einzelner Aufruf endet mit „adb meldet: timeout". Gelöst wird das an der Brille, indem man in den USB-Optionen kurz auf „Nur Laden" und zurück auf „Dateiübertragung" stellt. Das offizielle Dashboard verbindet genau deshalb sofort, sobald man umschaltet: es fragt einfach weiter. Jetzt fragt Yakuda Connect auch weiter.
  • Jeder adb-Aufruf wird bei Stille bis zu dreimal versucht (20 s Zeitlimit, 2,5 s Pause). Nur bei Zeitüberschreitung — ein echte...
Read more

v 1.2.7 fixxes and better vr perfoamnce

Choose a tag to compare

@yakuda-stack yakuda-stack released this 14 Sep 07:42

🚀 v1.2.7

🇩🇪 Deutsch

  • VRChat hat jetzt drei Proton-Slots statt zwei. Empfehlung ist Proton-RTSP-Wayland-GE Beta 3 — RTSP-Medienstack plus native Wayland-Patches aus GE-Proton11-6, opt-in über PROTON_USE_WAYLAND=1. Als Backup steht der Upstream proton-rtsp-11.0-20260609-4 darunter, aus dem der Fork stammt. Dritter Slot ist die risikoarme Wahl ohne Video-Fixes: auf CachyOS der CachyOS-Build, sonst Steams Proton 11.
  • Der neue Slot heißt safe und ist bewusst nicht alternative. Bei VRChat ist die Alternative ein zweiter Medien-Build, während safe gerade der Verzicht darauf ist. Zwei gegensätzliche Empfehlungen unter einem Label hätten den Nutzer ratlos zurückgelassen.
  • Proton-Metadaten wandern von der Spiel- in die Versionsebene. proton_versions durfte schon immer dict-Form haben; jetzt trägt ein Eintrag dort auch tool_prefix, protonplus_runner, download_url und checksum_url. Dieselbe Proton-Version wird bei mehreren Spielen eingetragen und musste sonst mehrfach gepflegt werden.
  • _infer_protonplus_runner() hätte Wayland-GE falsch zugeordnet. Die Funktion prüft "rtsp" in name vor "ge" in name — „Proton-RTSP-Wayland-GE" traf auf die RTSP-Regel und hätte den Runner proton-ge-rtsp bekommen. Der Install-Knopf hätte damit etwas völlig anderes installiert als die Karte verspricht. Ein expliziter Eintrag in proton_versions gewinnt jetzt über die Ableitung, null eingeschlossen — die Unterscheidung zwischen „ausdrücklich kein Runner" und „nicht angegeben" macht "key in meta" statt meta.get().
  • resolve_steam_tool() hätte VRChat still auf Stock-Proton zurückgesetzt. Bei runner is None lieferte die Funktion „Steam-Standard, Mapping entfernen". Das stimmt für Valves Proton, nicht aber für manuell installierte Builds, die ebenfalls keinen Runner haben. Ein Klick auf „Use" hätte Wayland-GE angezeigt und Stock-Proton eingetragen. Der Kurzschluss greift jetzt nur noch ohne tool_prefix.
  • Ordner-Namenskollision zwischen Fork und Upstream. Proton-RTSP-Wayland-GE-Beta3 beginnt mit proton-rtsp und wurde von der Upstream-Karte als eigener Build erkannt. Wer nur den Fork installiert hatte, bekam auf der RTSP-Karte „installiert" angezeigt. Neue _TOOL_EXCLUDES-Tabelle neben _TOOL_PREFIXES.
  • Die Ausblendlogik der Alternative war an alternative_cachyos gekoppelt. Zufällig richtig, solange es nur einen Zusatz-Slot gab — mit safe_cachyos wäre das RTSP-Backup auf CachyOS mitverschwunden. Beide Slots haben jetzt getrennte Sichtbarkeitsregeln, und visible_protons() sortiert über eine feste Rollen-Reihenfolge statt über die Reihenfolge in der games.json.
  • Neuer Download-Knopf für manuell verteilte Proton-Builds (core/proton_manual_install.py). Lädt den Tarball vom GitHub-Release, prüft die mitgelieferte SHA-512-Summe, entpackt nach compatibilitytools.d und meldet anschließend „Steam neu starten". Läuft im Worker-Thread, weil das Archiv über ein Gigabyte groß ist.
  • Drei Fallstricke sind im Installer abgefangen: Das -source.tar.gz eines LGPL-Releases enthält nur vorbereiteten Quellcode und keine compatibilitytool.vdf — eine darauf zeigende URL wird abgelehnt, bevor geladen wird. Das Zielverzeichnis kommt aus compat_tools_install_dir() statt aus einem festen Flatpak-Pfad, denn auf Arch/CachyOS läuft Steam meist nativ. Und entpackt wird mit dem data-Filter beziehungsweise einer Pfadprüfung, damit ein präpariertes Archiv nicht aus dem Zielordner ausbricht.
  • Eine Neuinstallation über einen bestehenden Build ersetzt den Ordner, statt darüberzupacken — sonst entstünden Mischordner aus zwei Versionen.
  • Neuer Schalter „Natives Wayland" bei VRChat. Setzt PROTON_USE_WAYLAND=1 vor den Startbefehl. Wie PROTON_LOG eine Umgebungsvariable, steht also vor %command% und nicht dahinter. Standardmäßig aus. Builds ohne WineWayland-Patches ignorieren die Variable — der Schalter kann dort nichts kaputtmachen, bringt aber auch nichts. Der Tooltip nennt die Nebenwirkung: im Wayland-Pfad ist Xalia aus und Steam Input standardmäßig ab.
  • Die Werkzeugliste des Tools-Tabs liegt jetzt in config/tools.json. Vorher standen die Einträge als Python-Literale in core/programs.py. Jedes neue Tool war damit eine Code-Änderung, und wer sich selbst eines eintragen wollte, musste eine installierte .py-Datei editieren — die beim nächsten Update überschrieben wird.
  • Eigene Tools gehören in ~/.config/yakuda-connect/config/tools.json. Diese Datei wird zusätzlich gelesen und mit der mitgelieferten Liste verschmolzen, nicht an deren Stelle. Ein unbekannter key wird angehängt, ein bekannter ersetzt den mitgelieferten Eintrag an Ort und Stelle. Ersetzen statt Anhängen ist Absicht: wer eine AppImage-URL oder einen Startbefehl korrigieren will, soll das können, ohne dieselbe Karte zweimal zu sehen. Eine kaputte Nutzerdatei wird protokolliert und übersprungen, statt den Tab zu leeren.
  • programs.all_tools() und reload_tools_config() ergänzt. core/main.py importiert zusätzlich das Modul selbst — die from programs import TOOLS_APPS-Namen sind Momentaufnahmen vom Programmstart und würden ein Neuladen nicht mitbekommen.
  • Autostart: Autovervollständigung im CMD-Modus. Vorgeschlagen werden zuerst die Startbefehle der installierten Tools, danach der restliche PATH. Bewusst Popup- statt Inline-Ergänzung — Inline schreibt beim Tippen eigener Befehle ständig dazwischen.
  • Autostart: der Knopf am Zeilenende heißt im CMD-Modus „Apps". Ein Dateidialog führt dort nicht weiter, gesucht ist ein Befehl. Der Klick öffnet ein Fenster mit allen installierten Programmen und OSC-Apps; Auswahl oder Doppelklick übernimmt den Startbefehl samt launch_args in die Zeile. Im Pfadmodus bleibt es der gewohnte Dateidialog.
  • Erkennung ohne Netzzugriff. Das Auswahlfenster benutzt absichtlich nicht compute_status() — das ruft für AppImages latest_version() auf und geht ins Netz. Ein Fenster, das erst nach dreizehn GitHub-Abfragen aufgeht, wäre unbrauchbar. Geprüft wird lokal: AppImage-Symlink plus Datei, Befehl im PATH, Flatpak-ID.
  • Der Umschalter zwischen Pfad- und Befehlsmodus war halb kaputt. Der bisherige Einzeiler bediente nur eine Richtung: beim Wechsel auf CMD wurde der Knopf deaktiviert und beim Zurückwechseln nie wieder aktiv, und setReadOnly(True) passierte überhaupt nie. Beide Richtungen werden jetzt gesetzt.
  • Filterleiste über dem Tools-Tab: Suchfeld, Kategorie und Installationsstatus. Mit 17 Einträgen scrollt man mehr als man liest, und es werden mehr. Gesucht wird über Name, Schlüssel, Paketname, Kategorie und Beschreibung — wer „tracker" tippt, meint das Thema und nicht ein Tool, das zufällig so heißt. Gefiltert wird über die Sichtbarkeit der bestehenden Karten statt durch Neuaufbau: die Karten hängen an Signalen und am Status-Cache, ein Neubau würde beides wegwerfen.
  • Neun Kategorien, aus den Tools selbst gelesen. Overlays, Tracking & Kalibrierung, Face-/Eye-Tracking, Eingabe & Bindings, OSC, VRChat, System & Proton, Entwicklung, Sonstiges. Die Auswahlliste baut sich aus den vorhandenen category-Feldern auf — eine neue Kategorie in der tools.json taucht ohne Code-Änderung im Filter auf.
  • Statusfilter: Alle / Installiert / Nicht installiert / Update verfügbar. „Installiert" schließt Karten mit verfügbarem Update ein, weil die ja installiert sind; „Update verfügbar" ist die engere Auswahl darunter. Gelesen wird der Status, den _render_tool_card zuletzt gesetzt hat — ein eigener Check liefe sonst bei jedem Tastendruck im Suchfeld über alle Tools.
  • Zähler und Leer-Hinweis. Rechts steht „X von Y"; lässt der Filter eine Unterseite leer, erscheint dort ein Hinweis statt einer leeren Fläche, die wie ein Fehler aussieht. Nach Installation oder Entfernung wird der Filter neu angewandt, damit eine Karte korrekt aus dem Statusfilter fällt oder hineinfällt. Ein Sprachwechsel baut die Beschriftungen neu auf und stellt die getroffene Auswahl über currentData wieder her.
  • Vier neue Werkzeuge unter Anwendungen, alle vier auch über die Autostart-App-Auswahl erreichbar, sobald sie installiert sind:
    • SpaceCal for Monado — richtet VR-Geräte aus verschiedenen Tracking-Systemen über Monado in einen gemeinsamen Raum aus. AUR-Paket vorhanden.
    • obah — Terminal-Oberfläche für OpenVR-Bindings (xrizer, VapoR, OpenComposite), statt JSON von Hand. AUR-Paket obah-git. Läuft als TUI, für Autostart daher wenig sinnvoll — steht so auch im Hinweis auf der Karte.
    • XR HOTAS — macht die VR-Controller zu Schubhebel und Joystick für Elite: Dangerous und DCS World. Nur über Cargo installierbar.
    • VIVE Hub for Linux (Beta) — HTCs App für die VIVE Ultimate Tracker. Nur als Tarball von HTC, mit einmaligem sudo ./install-udev.sh.
  • supported_methods() behandelte eine leere install_methods-Liste wie eine fehlende Angabe. if m: ist bei [] falsch, also fiel die Funktion auf ["aur"] zurück. XR HOTAS und VIVE Hub hätten damit einen Install-Knopf bekommen, der yay -S auf ein nicht existierendes Paket losgelassen hätte. Eine leere Liste ist jetzt eine Aussage — „von hier aus nicht installierbar" — und die beiden Karten zeigen nur ihren Hinweistext mit dem echten Installationsweg.
  • GitHub-Knopf auf den Karten ohne Installationsweg. XR HOTAS und VIVE Hub lassen sich von hier aus nicht installieren; statt eines toten Install-Knopfes steht dort jetzt „Auf GitHub öffnen" mit dem GitHub-Mark als Icon. Der Hinweistext darüber nennt den echten Weg, der Knopf führt mit einem Klick dorthin — statt die URL aus dem kleinen 🌐-Knopf fischen zu müssen. Das Logo liegt als assets/github-mark.svg in Nord-Weiß, damit es auf dunklem Grund nicht als schwarzer Klecks verschwindet.
  • Neuer Knopf „Netzwerkpuffer fixen (Ruckeln)“ im Dashboard, neben dem Firewall-Knopf in der Servergruppe. WiVRn schiebt das Videobild über UDP; ist der Socket-Puffer des Kernels kleiner als ein ...
Read more