AGENTS.md: die Regel "Auswahl ist ein Dropdown, kein Tastendruck-Capture" ist ueberholt -- Capture gibt es jetzt, aber weiterhin ohne WinAPI-Hook, und genau diese Grenze muss bleiben. Dazu die Layout-Naeherung (Y/Z vertauscht auf deutschem Layout, minus-Kollision bewusst zugunsten der US-Position aufgeloest), die neuen UI-Regeln (Dialogposition, Grab-Rueckgabe bei verschachtelten Dialogen, feste Panel-Hoehe, In-Memory-Ablage fuers Kopieren) und ein Verifikationsrezept fuer UI-Aenderungen inkl. der DPI-Falle beim Screenshot-Vergleich. Der Deferred-Work-Eintrag zum Capture faellt weg. README.md: neue Bedienung in den Features, Tastenkuerzel-Uebersicht, und die Einschraenkung praezisiert (nicht mehr "Dropdown statt Capture", sondern was die Fenster-basierte Erkennung nicht sehen kann). docs/architecture.md: _ModalDialog/_KeyCapture in der UI-Schicht, plus zwei neue Abschnitte zu den Grenzen der Erkennung und zur Kopier-Ablage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
219 lines
12 KiB
Markdown
219 lines
12 KiB
Markdown
# VersaPad Viewer
|
||
|
||
Ein eigenständiges Tool für das [VersaPad](https://git.jappel.io/jappel/VersaMCU)-Makropad
|
||
(4×5-Button-Grid + 4 Encoder, SAMD21-Firmware von jappel). Zeigt die aktuelle
|
||
Belegung an, kann sie live mit dem Board synchronisieren und komplett neu
|
||
programmieren — als Ergänzung zur offiziellen [VersaGUI](https://git.jappel.io/jappel/VersaGUI)
|
||
(C#/.NET), nicht als Ersatz.
|
||
|
||
Aktive Weiterentwicklung. Lesemodus, Live-Sync, Programmiermodus (inkl.
|
||
Board-Schreibzugriff) und der MCP-Server sind funktionsfähig und gegen ein
|
||
echtes Board getestet (Read-Modify-Write ist byte-identisch zum Original,
|
||
inklusive CRC). Nicht vorhanden: automatisierte Tests (Verifikation läuft
|
||
manuell gegen ein angeschlossenes Board), eine vorgefertigte `.exe` zum
|
||
Download (siehe unten, warum), und Mehrbenutzer-/Netzwerkbetrieb. Die eigene
|
||
Config-Datei (`versapad_config_all.json`) liegt automatisch unter
|
||
`%APPDATA%\VersaPadViewer\` (siehe „Aufbau" unten) und wird bei Bedarf
|
||
automatisch neu angelegt — kein manuelles Pfad-Anpassen mehr nötig. Nur die *optionale*
|
||
Lese-Interop mit den JSON-Exports der offiziellen VersaGUI
|
||
(`versapad_data.CONFIG_PATHS`) ist noch für eine bestimmte Windows-Maschine
|
||
hartkodiert (OneDrive-Desktop) — für einen anderen Rechner dort anpassen,
|
||
falls gewünscht.
|
||
|
||
## Features
|
||
|
||
- **Steuermatrix-Anzeige** — 4×5-Button-Grid + 4 Encoder, farbige LED-Vorschau,
|
||
lesbare Beschriftung (z.B. "Strg+S" statt Rohwerten)
|
||
- **Zwei Anzeige-Wege:** Browser (`server.py`, `localhost:8765`) oder natives
|
||
Desktop-Fenster (`desktop_viewer.py`, Tkinter)
|
||
- **Live-Sync** — pollt per Serial, welches Profil gerade am Board aktiv ist,
|
||
und schaltet die Ansicht automatisch mit
|
||
- **Programmiermodus** — Zellen anklicken und bearbeiten (Taste, Medientaste,
|
||
Makro, Profilwechsel, LED-Farbe/Animation), direkt aufs Board schreiben
|
||
oder als Datei speichern. Der Dialog öffnet über dem Hauptfenster,
|
||
Enter bestätigt, Escape bricht ab
|
||
- **Tastendruck-Erkennung** — statt die Taste im Dropdown zu suchen,
|
||
„⌨ Taste drücken" klicken und die gewünschte Kombination einfach
|
||
drücken (Modifier inklusive). Läuft über das Dialogfenster, nicht über
|
||
einen System-Hook — vom System abgefangene Kombinationen (Win+L,
|
||
Strg+Alt+Entf) kommen deshalb nicht an, und das Dropdown bleibt zum
|
||
Nachkorrigieren daneben stehen
|
||
- **Makro-Editor** — bis zu 8 Schritte pro Slot, liest/schreibt die echte
|
||
Makro-Tabelle vom Board. Schritte einzeln erfassen oder die ganze Folge
|
||
am Stück aufnehmen („⏺ Folge aufnehmen"). Die Slot-Auswahl listet alle 32
|
||
Slots samt Inhalt, statt sie einzeln durchklicken zu müssen
|
||
- **Makros im Grid lesbar** — eine Makro-Belegung zeigt die tatsächliche
|
||
Tastenfolge (`Makro 3: Strg+C → Strg+V`) statt nur der Slot-Nummer; das
|
||
gilt auch in der Browser-Ansicht und in den MCP-Antworten
|
||
- **Farb-Schnellwahl** — zwölf Grundfarben direkt in der LED-Zeile des
|
||
Dialogs, der System-Farbdialog nur noch für den Rest („mehr…")
|
||
- **Kopieren/Einfügen zwischen Tasten** — Rechtsklick auf eine Karte im
|
||
Programmiermodus: Belegung und/oder Farbe kopieren und auf andere Tasten
|
||
anwenden, oder die Belegung leeren. Strg+C/Strg+V wirken auf die Karte
|
||
unter dem Mauszeiger
|
||
- **Notizen** — freier Text pro Button/Encoder-Aktion, was sie tatsächlich
|
||
tut (z.B. "Speichern in Fusion 360"), zusätzlich zur automatischen
|
||
Beschriftung ("Strg+S"). Rein lokal wie Profilnamen, geht nie aufs Board,
|
||
bleibt beim Tastenwechsel und beim "Vom Board laden" erhalten
|
||
- **MCP-Server** — lässt eine KI (Claude o.ä.) die Belegung direkt per
|
||
Tool-Aufruf ändern, ohne Klicks in der GUI (siehe unten)
|
||
- **Tray-Icon** — minimiert/schließt ins Tray statt in die Taskleiste, wie
|
||
die offizielle VersaGUI
|
||
- **Randloses Fenster** — ohne Windows-Titelleiste, dafür kompakter Kopf
|
||
(Modus-Checkboxen direkt neben dem Titel). Verschieben durch Ziehen an
|
||
der Kopfzeile, Größe ändern am Anfasser unten rechts, `✕`/`—` legen ins
|
||
Tray. Einen Taskleisten-Eintrag gibt es dadurch nicht — das Fenster kommt
|
||
über das Tray-Icon zurück.
|
||
- **Tastenkürzel im Hauptfenster** — `Strg+1/2/3` Profil wechseln, `F2`
|
||
Profil umbenennen, `Strg+E` Programmiermodus an/aus, `Strg+C`/`Strg+V`
|
||
Taste unter dem Mauszeiger kopieren/einfügen, `Esc` ins Tray.
|
||
|
||
## Voraussetzungen
|
||
|
||
- Python 3.11 oder neuer
|
||
- Alle Pakete stehen in `requirements.txt` (`pyserial` fürs Board,
|
||
`pystray` + `pillow` fürs Tray-Icon/Desktop-Fenster, `mcp` für den
|
||
MCP-Server, `pyinstaller` fürs `.exe`-Bauen):
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
Für den Browser-Modus (`server.py`) reicht die Python-Standardbibliothek —
|
||
keine zusätzlichen Pakete nötig. `build_and_deploy.ps1` installiert
|
||
`requirements.txt` beim Bauen automatisch selbst — ein manuelles
|
||
`pip install` vorher ist dafür nicht nötig.
|
||
|
||
## Starten
|
||
|
||
**Aus dem Quellcode:**
|
||
|
||
```bash
|
||
py server.py # Browser-Ansicht: http://127.0.0.1:8765
|
||
py desktop_viewer.py # natives Fenster (Konsole sichtbar, zum Debuggen)
|
||
pyw desktop_viewer.py # natives Fenster ohne Konsolenfenster
|
||
```
|
||
|
||
**Als eigenständige `.exe` (Windows):** Es liegt keine fertige `.exe` im
|
||
Repo (Build-Artefakte sind bewusst nicht eingecheckt — sie sind groß und pro
|
||
Maschine/Python-Version unterschiedlich). Selbst bauen:
|
||
|
||
```powershell
|
||
.\build_and_deploy.ps1
|
||
```
|
||
|
||
Das Skript installiert/aktualisiert selbst alle nötigen Pakete aus
|
||
`requirements.txt` (kein manuelles `pip install` vorher nötig), baut dann
|
||
mit PyInstaller (`--onedir --windowed`, eigenes Icon) und kopiert das
|
||
Ergebnis nach `%LOCALAPPDATA%\VersaPadViewer\VersaPadViewer.exe`.
|
||
Bricht ein Schritt ab (fehlendes Python, PyInstaller-Fehler, ...), zeigt das
|
||
Skript eine klare Fehlermeldung und wartet auf einen Tastendruck, statt sich
|
||
bei Doppelklick im Explorer kommentarlos zu schließen (`-NoPause`
|
||
unterdrückt das für automatisierte Aufrufe/CI).
|
||
|
||
**Wichtig:** Sowohl Bauen als auch Ausführen müssen auf einem lokalen
|
||
Laufwerk passieren — von einem Netzlaufwerk (SMB-Share) aus scheitert
|
||
PyInstaller beim Bauen (Pfadlängen-Problem mit Tcl/Tk-Zeitzonendaten) und
|
||
die fertige `.exe` startet zur Laufzeit gar nicht erst (Windows blockiert
|
||
das Nachladen der Bundle-DLLs von einem Netzwerkpfad, ohne jede
|
||
Fehlermeldung). `build_and_deploy.ps1` kopiert den Quellcode deshalb
|
||
automatisch zuerst nach `%TEMP%` und baut nur dort.
|
||
|
||
## Aufbau
|
||
|
||
| Datei | Zweck |
|
||
|---|---|
|
||
| `versapad_data.py` | Decoding für die Anzeige: JSON laden, HID-Keycodes/Consumer-IDs/Modifier → lesbarer Text |
|
||
| `versapad_protocol.py` | Binäres NVM-Layout des Boards (740B Config + 512B Makros), CRC16 — pack/unpack |
|
||
| `versapad_serial.py` | Serial-Client: liest/schreibt Config + Makros per 8-Byte-Paket-Protokoll |
|
||
| `versapad_combined.py` | Ein-Datei-Format für alle 3 Profile + Makros + lokale Profilnamen |
|
||
| `server.py` | Browser-Frontend (nur lesend) |
|
||
| `desktop_viewer.py` | Tkinter-Frontend (lesend, Live-Sync, Programmiermodus, Tray) |
|
||
| `action_dialog.py` | Bearbeiten-Dialoge für den Programmiermodus |
|
||
| `versapad_mcp_server.py` | MCP-Server für KI-Tool-Aufrufe |
|
||
|
||
Das Binärformat (`versapad_protocol.py`) ist 1:1 aus den
|
||
VersaMCU-Firmware-Quellen übernommen und gegen ein echtes Board validiert
|
||
(Read → unpack → pack ist bytegenau identisch zum Original, inklusive CRC).
|
||
|
||
Die eigene Config-Datei (`versapad_config_all.json` — alle 3 Profile +
|
||
Makros + lokale Profilnamen + Notizen, siehe `versapad_combined.py`) liegt
|
||
unter `%APPDATA%\VersaPadViewer\` (`versapad_data.app_dir()`), also
|
||
**getrennt vom Installationsordner** und unabhängig davon, ob die `.exe`
|
||
oder der Quellcode gestartet wurde. Beides ist Absicht: das Build-Skript
|
||
räumt sein Zielverzeichnis vor jedem Deploy komplett ab (läge die Config
|
||
dort, würde jeder Rebuild sie löschen), und ein vom Startweg abhängiger
|
||
Pfad hatte zu zwei auseinanderlaufenden Configs geführt. Fehlt die Datei
|
||
(z.B. frische Installation), wird sie automatisch angelegt — per Serial vom
|
||
Board, falls eins angeschlossen ist, sonst als leere Default-Config.
|
||
Profilnamen (`profile_names`) stehen direkt in dieser Datei und lassen sich
|
||
per Doppelklick auf einen Tab (in jedem Modus — Nur-Lesen, Live-Sync oder
|
||
Programmiermodus) oder `rename_profile()` (MCP) ändern. Notizen ebenso —
|
||
im Bearbeiten-Dialog des Programmiermodus oder per
|
||
`set_button_note()`/`set_encoder_note()` (MCP).
|
||
|
||
Die klassischen `versapad_config1/2/3.json` sind kein von diesem Tool
|
||
geschriebenes Format, sondern optionale Lese-Interop mit einem JSON-Export
|
||
der offiziellen VersaGUI (C#/.NET) — Pfad aktuell hartkodiert auf den
|
||
OneDrive-Desktop einer bestimmten Windows-Maschine, siehe `CONFIG_PATHS` in
|
||
`versapad_data.py`.
|
||
|
||
## MCP-Server
|
||
|
||
`versapad_mcp_server.py` macht die Config per Tool-Aufruf statt Hand-JSON
|
||
programmierbar — nutzbar von jeder MCP-fähigen KI-Anwendung (Claude Code,
|
||
Claude Desktop, andere). Für Claude Code liegt bereits eine projektgebundene
|
||
[`.mcp.json`](.mcp.json) im Repo (Server "versapad", Kommando `py
|
||
versapad_mcp_server.py`) — beim Öffnen des Projekts wird sie automatisch
|
||
zum Verbinden angeboten. Für andere Anwendungen oder user-scope-Registrierung
|
||
in der jeweiligen MCP-Server-Liste eintragen: Kommando `python`/`py`,
|
||
Argument der Pfad zu `versapad_mcp_server.py`.
|
||
|
||
Werkzeuge (Auszug): `list_profiles`, `get_profile`, `get_macro`,
|
||
`get_board_status` (lesen) · `set_button_key`/`_consumer`/`_macro`/
|
||
`_profile_switch`/`_none`/`_led`, dieselben `set_encoder_*`, `set_macro`,
|
||
`rename_profile` (bearbeiten) · `save_local`/`load_local` (Datei),
|
||
`load_from_board`/`write_to_board` (Board). `set_*`-Aufrufe ändern nur
|
||
einen In-Memory-Zustand — erst `save_local()` oder `write_to_board()` macht
|
||
die Änderung dauerhaft. Volle Liste mit Details: Info-Button (ⓘ) oben
|
||
rechts im Fenster, oder direkt in `versapad_mcp_server.py`.
|
||
|
||
## Bekannte Einschränkungen
|
||
|
||
- Der COM-Port ist exklusiv — Live-Sync/Programmiermodus können nicht
|
||
gleichzeitig mit der offiziellen VersaGUI laufen (die läuft dauerhaft als
|
||
Tray-App weiter, auch wenn nur ihr Konfigurationsfenster geschlossen wird
|
||
— für Parallelbetrieb muss sie über ihr Tray-Menü beendet werden)
|
||
- Die Tastendruck-Erkennung läuft bewusst über das Dialogfenster statt über
|
||
einen globalen WinAPI-Hook — vom System abgefangene Kombinationen (Win+L,
|
||
Strg+Alt+Entf) erreichen das Fenster nie und lassen sich so nicht erfassen
|
||
- Zeichentasten-Labels zeigen eine US-Layout-Näherung, nicht das tatsächlich
|
||
aktive Tastatur-Layout. Das betrifft auch die Tastendruck-Erkennung:
|
||
HID-Keycodes sind physische US-Tastenpositionen, erkennbar ist ohne
|
||
WinAPI aber nur das Zeichen des aktiven Layouts — auf deutschem Layout
|
||
landen Y und Z deshalb vertauscht auf dem Board. Das Ergebnis steht immer
|
||
sichtbar im Dropdown und lässt sich dort korrigieren
|
||
- Unsignierte `.exe` — kann von Antivirus/Smart App Control blockiert
|
||
werden; `--onedir` (statt `--onefile`) verringert das Risiko, verhindert
|
||
es aber nicht
|
||
|
||
## Dokumentation
|
||
|
||
Ausführlichere technische Doku im [`docs/`](docs/)-Ordner:
|
||
|
||
- [`docs/architecture.md`](docs/architecture.md) — Schichtenmodell,
|
||
Prozessmodell, Modi, Config-Speicherort, Nebenläufigkeit
|
||
- [`docs/data-model.md`](docs/data-model.md) — JSON-Formate (kombiniert +
|
||
Legacy), binäres NVM-Layout, Geometrie, Enums
|
||
- [`docs/protocol.md`](docs/protocol.md) — Serial-Wire-Protokoll (Befehle,
|
||
Events, Paketformat, CRC16)
|
||
|
||
## Weiterentwicklung
|
||
|
||
Agentenseitige Notizen (Domänenregeln, bekannte Bugs und ihre Fixes,
|
||
Implementierungsdisziplin, Design-Entscheidungen) stehen in
|
||
[`AGENTS.md`](AGENTS.md).
|
||
|
||
## Lizenz / Herkunft
|
||
|
||
Eigenständiges Begleit-Tool, kein Teil der offiziellen VersaGUI/VersaMCU-Repos.
|