docs: add concise user guide
Build AppImage / build-appimage (push) Successful in 43s

This commit is contained in:
2026-08-03 20:34:37 +02:00
parent 39646bd778
commit 5d623e34a4
+63 -198
View File
@@ -1,225 +1,90 @@
# Korin Timer (Linux) # Korin Timer
Eigenständige Neu-Implementierung eines 2-Step-Title-Switching-Timers als Korin Timer ist ein transparentes Linux-Overlay für Elsword. Es zeigt die
Overlay (kein Reverse Engineering, keine Codeübernahme aus proprietärer Cooldowns deiner Titel an und lässt sich komplett über globale Hotkeys
Software - nur nach Funktionsbeschreibung neu gebaut). bedienen.
## Funktionsprinzip ## Schnellstart
- **Ohne Vor-Aktivierung** (Normalfall): Hotkey drücken startet den 1. Öffne im Repository den Bereich **Releases** und lade
Cooldown-Timer direkt, ein einziger Druck reicht. `Korin-Timer.AppImage` herunter.
- **Mit Vor-Aktivierung** (optional, pro Titel im Settings-Fenster 2. Mache die Datei ausführbar und starte sie:
einstellbar): eine zusätzliche Taste/Kombination - z.B. eine Taste, die
im Spiel ohnehin gedrückt wird - die den Titel in Standby versetzt
(gepulster Rahmen zeigt das an). Die Haupttaste startet dann, *ein
einziges Mal gedrückt*, den Cooldown; sie allein (ohne vorherige
Vor-Aktivierung) macht in diesem Modus nichts.
- **Standby-Timeout** (optional, pro Titel, 0 = aus, wirkt nur im
Vor-Aktivierungs-Modus): springt automatisch zurück auf Idle, wenn die
Haupttaste nicht innerhalb der eingestellten Sekundenzahl nach der
Vor-Aktivierung gedrückt wird - inklusive Countdown-Anzeige im Overlay,
solange er läuft.
- **Neu triggerbar** (Checkbox pro Titel, aus per Default): normalerweise
wird die Haupttaste während laufendem Cooldown ignoriert. Mit dieser
Option gedrückt startet sie den Cooldown stattdessen neu (volle Dauer ab
dem Zeitpunkt des Drucks) - für Buffs, die man aktiv auffrischen will.
- **Dogma-Modus** (`dogma_mode: true` in der Config, Schalter im
Settings-Fenster): solange irgendein Cooldown läuft, werden Hotkeys für
*andere* Titel ignoriert. Aus, wenn alle Titel unabhängig voneinander
gleichzeitig laufen sollen.
- **Verschieben**: `Strg+Alt` gedrückt halten + mit der linken Maustaste aufs
Overlay klicken und ziehen. Die neue Position wird beim Loslassen in der
Config-Datei des aktiven Charakter-Profils (`overlay.x`/`overlay.y`,
siehe unten) gespeichert und bleibt über Neustarts erhalten. Funktioniert
wie die Hotkeys über
rohes `evdev` (siehe unten) - das Overlay ist click-through, bekommt also
nie normale Mausereignisse vom Fenstersystem. (Nicht nur `Alt`, weil das
mit GNOMEs eigenem "Alt+Drag verschiebt jedes Fenster"-Standardverhalten
kollidiert.)
## Warum XWayland/EWMH statt Layer-Shell
Erster Ansatz war `gtk4-layer-shell` (`wlr-layer-shell`-Protokoll) - das
funktioniert aber nur auf wlroots-Compositors (Sway, Hyprland). **GNOME/Mutter
implementiert dieses Protokoll nicht.** Getestet gegen eine echte GNOME-
Wayland-Session: die Layer-Shell-Initialisierung schlug fehl
(`compositor does not support the Layer Shell protocol`).
Stattdessen läuft das Overlay über XWayland als normales X11-Fenster mit
EWMH-Hints (`_NET_WM_STATE_ABOVE`, `_NET_WM_STATE_SKIP_TASKBAR`, Klick-durch
via XShape-Extension). Das funktioniert auf GNOME, KDE *und* wlroots-
Compositors, weil XWayland praktisch überall mitläuft. Einzige Falle dabei:
Mutter respektiert `_NET_WM_STATE_ABOVE` nur, wenn es per ClientMessage
**nach** dem Mapping des Fensters gesendet wird (nicht als Property davor,
im Gegensatz zu SKIP_TASKBAR/SKIP_PAGER) - siehe `x11_overlay.raise_above()`.
Das umgeht auch das ursprüngliche Wine-Problem: statt eines transparenten
DirectX-Fensters unter Wine (das dort schwarz statt durchsichtig gerendert
wurde) ist das hier ein natives GTK4-Fenster mit echter RGBA-Transparenz.
## Charakter-Profile
Jeder Charakter hat eine eigene, vollständige Config unter
`~/.config/titletimer/profiles/<Name>.json` (Titel, Hotkeys, Cooldowns,
Dogma-Modus, Overlay-Position - alles). Im Einstellungsfenster oben eine
Zeile "Charakter:" mit Dropdown + `Neu`/`Duplizieren`/`Umbenennen`/`Löschen`:
- **Neu**: legt ein Profil mit den Beispiel-Titeln aus `config.example.json`
an, das direkt umbenannt/umgebaut werden kann.
- **Duplizieren**: kopiert das aktuell aktive Profil unter neuem Namen -
praktisch für einen zweiten Charakter mit ähnlichem Titel-Setup.
- **Umbenennen** / **Löschen**: benennt die Profil-Datei um bzw. entfernt
sie (der letzte verbleibende Charakter lässt sich nicht löschen).
Profil-Wechsel im Dropdown lädt sofort das gewählte Profil - laufendes
Overlay übernimmt es ohne Neustart, wie beim normalen "Speichern". Nicht
gespeicherte Änderungen am vorherigen Profil gehen beim Wechsel verloren
(genau wie beim Schließen des Fensters ohne zu speichern). Das zuletzt
aktive Profil wird gemerkt (`~/.config/titletimer/last_profile.txt`) und
beim nächsten Start automatisch wieder geladen.
Bereits vorhandene Configs aus einer Version vor diesem Feature
(`~/.config/titletimer/config.json`) werden beim ersten Start automatisch
zu einem Profil namens "Default" migriert (per Umbenennen in
`profiles/Default.json`) - kein manueller Schritt nötig.
`--config <pfad>` umgeht das Profil-System komplett und lädt direkt eine
beliebige Datei (z.B. zum Testen) - dann ist die Profil-Zeile im
Einstellungsfenster ausgeblendet, da es kein Profil-Konzept dafür gibt.
## Setup (aus dem Quellcode, ohne AppImage)
Falls du nicht das AppImage nutzt, sondern direkt aus `src/` starten willst,
brauchst du GTK4/PyGObject/evdev/xlib systemweit oder per `nix-shell`
(siehe `shell.nix` im Repo - relevant auf NixOS, wo es kein systemweites
`python3`/GTK4 auf dem `PATH` gibt):
```bash ```bash
# Arch/CachyOS chmod +x Korin-Timer.AppImage
sudo pacman -S python-gobject gtk4 gtk4-layer-shell python-evdev python-xlib ./Korin-Timer.AppImage
# NixOS ```
nix-shell # nutzt die shell.nix im Repo-Root
# Nutzer muss in der input-Gruppe sein, damit evdev /dev/input lesen darf 3. Beim ersten Start öffnen sich Overlay und Einstellungsfenster. Lege dort
deine Titel, Hotkeys und Cooldowns an und klicke auf **Speichern**.
Die App benötigt Leserechte auf die Eingabegeräte, damit Hotkeys außerhalb
des Fensters funktionieren. Führe einmal aus und melde dich anschließend
vollständig ab und wieder an:
```bash
sudo usermod -aG input "$USER" sudo usermod -aG input "$USER"
# danach ab- und wieder anmelden (Gruppenmitgliedschaft wird erst beim
# nächsten Login aktiv)
``` ```
Config: Falls beim ersten Start noch kein Charakter-Profil existiert ## Bedienung
(`~/.config/titletimer/profiles/`, siehe oben), wird automatisch eines
namens "Default" aus der eingebauten `config.example.json` angelegt (auch
im AppImage - keine separate Datei nötig). Danach anpassen - entweder
per Hand:
```bash - Drücke den Hotkey eines Titels, um seinen Cooldown zu starten.
$EDITOR ~/.config/titletimer/profiles/Default.json - Optional kann ein Titel erst per Vor-Aktivierungs-Hotkey in den Standby
# hotkey ist entweder ein einzelner evdev-Keycode-String ("KEY_F1") oder wechseln. Erst der normale Hotkey startet dann den Cooldown.
# eine Liste für eine Tastenkombination (["KEY_LEFTCTRL", "KEY_F1"]) - alle - Mit **Neu triggerbar** startet derselbe Hotkey einen bereits laufenden
# gelisteten Tasten muessen gleichzeitig gehalten werden. Keycode-Namen: Cooldown erneut.
# python3 -c "from evdev import ecodes; print([k for k in dir(ecodes) if k.startswith('KEY_')])" - Im Dogma-Modus ist immer nur ein Titel gleichzeitig aktiv.
``` - Verschiebe das Overlay mit **Strg + Alt + linker Maustaste ziehen**.
Die Position wird im aktiven Profil gespeichert.
oder über das eingebaute Einstellungsfenster (Titel hinzufügen/entfernen, Das Einstellungsfenster muss geöffnet bleiben: Sein Schließen beendet auch
Hotkeys per Klick-und-Tastendruck erfassen - auch Mehrfachkombinationen das rahmenlose, klickdurchlässige Overlay.
wie Strg+F1 -, Cooldowns, Farben, optionales Icon pro Titel, Dogma-Modus,
Anker/Rand/Skalierung, sowie die per Alt+Drag gesetzte Position
zurücksetzen) - das öffnet sich automatisch mit dem Overlay zusammen.
"Speichern" wirkt sofort auf das laufende Overlay, kein Neustart nötig
(ein aktuell laufender Cooldown wird dabei zurückgesetzt).
Starten (aus dem Projektverzeichnis): ## Profile
Jeder Charakter erhält ein eigenes Profil unter
`~/.config/titletimer/profiles/`. Über das Dropdown im Einstellungsfenster
kannst du Profile anlegen, duplizieren, umbenennen, wechseln und löschen.
Ein Wechsel übernimmt die neue Konfiguration sofort; nicht gespeicherte
Änderungen des vorherigen Profils gehen dabei verloren.
## Neues Release erstellen
Jeder Push auf `main` startet automatisch einen Gitea-Actions-Build. Nach
einem erfolgreichen Lauf:
1. Öffne **Actions** und den aktuellen erfolgreichen Build.
2. Lade das Artefakt `Korin-Timer.AppImage` herunter.
3. Öffne **Releases** → **New Release**.
4. Erstelle einen Tag, etwa `v0.1.0`, und hänge die AppImage-Datei an.
5. Veröffentliche das Release.
Das Actions-Artefakt wird nach 30 Tagen gelöscht; der Release-Anhang bleibt
verfügbar.
## Aus dem Quellcode starten
Für Entwicklung brauchst du GTK4, PyGObject, `evdev` und `python-xlib`.
Danach startest du die Anwendung aus dem Projektverzeichnis mit:
```bash ```bash
PYTHONPATH=src python3 -m titletimer PYTHONPATH=src python3 -m titletimer
``` ```
Startet Overlay **und** Einstellungsfenster zusammen. Das Einstellungs- Nur das Einstellungsfenster öffnest du mit:
fenster zu schließen beendet die ganze App (auch das Overlay) - das ist
aktuell der einzige Weg, das rahmenlose, click-through Overlay wieder zu
stoppen. Nur das Einstellungsfenster ohne Overlay:
```bash ```bash
PYTHONPATH=src python3 -m titletimer --settings PYTHONPATH=src python3 -m titletimer --settings
# oder: ./Korin-Timer.AppImage --settings
``` ```
## AppImage bauen (voll gebündelt, keine Systemabhängigkeiten) ## AppImage lokal bauen
Der CI-Workflow ist der empfohlene Buildweg. In einer Debian-artigen
Umgebung kann das AppImage auch lokal gebaut werden:
```bash ```bash
./packaging/build-appimage.sh ./packaging/build-appimage.sh
``` ```
Das AppImage ist **vollständig in sich geschlossen**: eigener Das Ergebnis liegt anschließend unter `build/Korin-Timer.AppImage` und wird
Python-Interpreter + Standardbibliothek, GTK4, `gtk4-layer-shell`, nicht ins Repository eingecheckt.
PyGObject, pycairo, `evdev`, `python-xlib` - und deren *gesamter*
transitiver Shared-Library-Baum (~78 `.so`-Dateien), inklusive `ld.so` und
`libc` selbst. Nichts davon kommt vom Zielsystem.
Warum so radikal gebündelt: Auf NixOS gibt es kein FHS-`/usr/bin/python3`
und kein System-GTK4 auf dem `PATH` - der ursprüngliche Ansatz ("GTK4 ist
auf so gut wie jedem Desktop schon da") war für NixOS schlicht falsch.
`packaging/bundle-runtime.sh` sammelt den kompletten Abhängigkeitsbaum per
rekursivem `ldd` über Python3-Binary, PyGObject-Extensions
(`_gi`, `_gi_cairo`), pycairo, `libgtk-4.so.1` und
`libgtk4-layer-shell.so.0` ein. `AppRun` ruft danach nicht mehr `python3`
über `PATH` auf, sondern das gebündelte `ld-linux-x86-64.so.2` direkt mit
`--library-path` auf das gebündelte `lib/`-Verzeichnis, plus
`PYTHONHOME`/`PYTHONPATH`/`GI_TYPELIB_PATH` auf die gebündelten Pfade.
Damit entfällt auch die vorherige Sorge um `evdev`s Python-ABI-Tag
(CPython-Minor-Version-Mismatch) komplett - es ist ja unser eigener
Interpreter, keiner vom Zielsystem.
Größe: ca. 28 MB (statt vorher 1,4 MB) - der Preis für echte
Systemunabhängigkeit.
Der Build erzeugt `build/Korin-Timer.AppImage`. Das Artefakt gehört nicht
zum Repository und wird nicht eingecheckt.
```bash
chmod +x build/Korin-Timer.AppImage # nur falls Ausführbarkeit fehlt
./build/Korin-Timer.AppImage
```
Einzige verbleibende Voraussetzung auf dem Zielsystem: die `input`-Gruppen-
Mitgliedschaft für `evdev` (s.o.) - das kann eine AppImage-Datei nicht
selbst mitbringen, das ist eine Kernel-Berechtigung.
**Wie das `.AppImage` selbst gebaut wurde**: `appimagetool`s eigene
AppImage-Datei ist selbst eine statisch-PIE-gelinkte ELF-Datei ohne
`PT_INTERP` - in meiner Sandbox (ein eingeschränkter Podman-Container)
ließ sich dieses Binärformat gar nicht ausführen (`execve` schlug mit
ENOENT fehl, unabhängig von FUSE). Deshalb baut das Skript jetzt
automatisch alternativ von Hand: die separate `runtime-x86_64`-Datei (der
reine ELF-Loader-Stub) direkt mit `mksquashfs AppDir` zusammen-`cat`en -
exakt das, was `appimagetool` intern auch tut. Auf deinem echten System
sollte `appimagetool` normal durchlaufen; falls nicht, greift derselbe
Fallback automatisch.
## Was tatsächlich getestet wurde
- **Config-Loader + State-Machine** (2-Step-Umschaltung, Dogma-Mutex,
Cooldown-Expiry): per Skript ausgeführt und alle Assertions verifiziert.
- **GTK4/GdkX11/evdev-Imports**: installiert und erfolgreich importiert.
- **Overlay live gegen deine echte laufende GNOME-Wayland-Session getestet**
(nicht nur eine isolierte Testumgebung): Fenster wird erzeugt, `evdev`
findet deine echten Tastatur-Devices, und per `xprop` verifiziert:
`_NET_WM_STATE_ABOVE`, `_NET_WM_STATE_SKIP_TASKBAR`,
`_NET_WM_STATE_SKIP_PAGER` und `_NET_WM_WINDOW_TYPE_UTILITY` sind
tatsächlich gesetzt, Fenster läuft ohne Exceptions.
- **AppImage-Datei selbst**: ELF-Header und eingebettetes SquashFS per
`unsquashfs` an der korrekten Byte-Offset-Grenze extrahiert und geprüft
(`AppRun`, `.desktop`-Datei lesbar) - der Aufbau der Datei ist also
korrekt. **Nicht** verifiziert: das tatsächliche Doppelklick-Starten der
`.AppImage`, weil meine Sandbox dieses Binärformat generell nicht
ausführen kann (s.o.) - das musst du einmal bei dir bestätigen.
- **Nicht** verifiziert: wie es *visuell* aussieht (Puls-Rahmen-Optik,
Transparenz-Feinschliff) und ob es zuverlässig über einem Vollbild-Spiel
liegt - das kannst nur du im echten Gameplay beurteilen.
## Aktueller Funktionsumfang
Nur der 2-Step Title-Switching-Timer + Dogma-Mode ist implementiert (siehe
Absprache). Flow-System (Pet-Tracking), Horary Loop Timer, Custom/Foto-Timer
und Post-it-Labels aus dem Original sind bewusst noch nicht gebaut - können
bei Bedarf nachgezogen werden.