Document key capture, dialog placement and copy/paste
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>
This commit is contained in:
parent
21f9cbc2ed
commit
8a00b3ae36
3 changed files with 152 additions and 12 deletions
82
AGENTS.md
82
AGENTS.md
|
|
@ -16,6 +16,11 @@ Nutzerorientierte Einführung: [`README.md`](README.md).
|
|||
- `versapad_data.py` — Decoding für Anzeige: JSON laden, HID-Keycode/
|
||||
Consumer-Usage/Modifier → lesbarer Text, Grid-Geometrie
|
||||
(`index = spalte*5+reihe`), `hid_key_choices()`/`consumer_choices()`.
|
||||
Seit 2026-08-28 zusätzlich `tk_event_to_hid()` (Tk-Tastendruck →
|
||||
HID-Keycode+Modifier, siehe Tastendruck-Erkennung unten) und
|
||||
`macro_slot_choices()`/`macro_slot_from_choice()` für die Slot-Auswahl.
|
||||
`action_label()`/`annotate_profile()` nehmen die Makrotabelle optional
|
||||
entgegen und zeigen dann statt „Makro (Slot 7)" die echte Tastenfolge.
|
||||
`app_dir()` liefert das Verzeichnis für die eigene Config
|
||||
(`versapad_combined.DEFAULT_PATH`) — bei der `.exe` der Installations-
|
||||
ordner, sonst der Projektordner, siehe Installierbarkeit-Notiz unten.
|
||||
|
|
@ -59,7 +64,9 @@ Nutzerorientierte Einführung: [`README.md`](README.md).
|
|||
(Nur lesen / Live-Sync / Programmiermodus, siehe Kritische Domänenregeln),
|
||||
Tray-Icon statt Taskleisten-Minimierung, Info-Button mit MCP-Doku.
|
||||
- `action_dialog.py` — Bearbeiten-Dialoge (`ActionEditDialog`,
|
||||
`MacroStepsDialog`) für den Programmiermodus.
|
||||
`MacroStepsDialog`) für den Programmiermodus. Gemeinsame Basis
|
||||
`_ModalDialog` (Positionierung über dem Elternfenster, Enter/Escape,
|
||||
Verteilung der Tastenevents) und `_KeyCapture` (Tastendruck-Erkennung).
|
||||
|
||||
**MCP-Server:**
|
||||
- `versapad_mcp_server.py` — registriert als projektgebundener MCP-Server
|
||||
|
|
@ -246,12 +253,66 @@ Protokoll) liegt in `docs/`, siehe „Dokumentation und Verifikation" unten.
|
|||
haben (`CARD_H` 84 → 114) braucht das Fenster ~960px, sonst liegen
|
||||
Encoder-Bereich und Fußzeile unterhalb des Rands. Wer `CARD_H` ändert,
|
||||
muss `geometry()` mit anpassen.
|
||||
- HID-Tasten-Auswahl im Programmiermodus ist ein Dropdown, kein
|
||||
Tastendruck-Capture (bewusst — kein WinAPI-Hook, um keinen AV-Fehlalarm
|
||||
wie bei den Fensterverstecktricks in anderen Projekten zu riskieren).
|
||||
- **Dialoge öffnen über dem Hauptfenster, nicht in der Bildschirmecke
|
||||
(2026-08-28):** `_ModalDialog` baut sich `withdraw()`n auf, positioniert
|
||||
sich in `run()` per `_center_on_parent()` und wird erst dann
|
||||
`deiconify()`t. Ohne das legt Tk jeden Toplevel bei `+0+0` an — bei 20
|
||||
Tasten hintereinander wandert der Blick jedes Mal in die linke obere Ecke.
|
||||
Das `withdraw()` gehört zwingend dazu, sonst blitzt der Dialog dort auf,
|
||||
bevor er springt.
|
||||
- **Verschachtelte Dialoge geben den Grab zurück:** `MacroStepsDialog` läuft
|
||||
im `ActionEditDialog`. `_finish()` ruft `grab_release()`, was den Grab des
|
||||
*aufrufenden* Dialogs mit wegnimmt — `run()` setzt ihn deshalb am Ende
|
||||
wieder, wenn der Parent ein `_ModalDialog` ist.
|
||||
- **Panel-Höhe im `ActionEditDialog` ist fix** (`grid_propagate(False)`):
|
||||
sonst springt die Fenstergröße bei jedem Typwechsel (Keine/Taste/Makro/…)
|
||||
und OK/Abbrechen wandern unter dem Mauszeiger weg.
|
||||
- **Kopieren/Einfügen zwischen Tasten** (Rechtsklickmenü bzw. Strg+C/Strg+V
|
||||
auf der Karte unter dem Mauszeiger) benutzt eine reine In-Memory-Ablage
|
||||
(`self._clip`), **nicht** die System-Zwischenablage — dort liegen
|
||||
Action-Dicts, kein Text. Immer `copy.deepcopy()`, sonst teilen sich zwei
|
||||
Tasten dasselbe Dict und eine spätere Bearbeitung ändert beide. „Leeren"
|
||||
behält die Notiz (gleiche Regel wie beim Typwechsel im Dialog, siehe
|
||||
Notizen-Bullet oben). Eine kopierte LED-Farbe auf einen Encoder
|
||||
einzufügen ist wirkungslos (Encoder haben keine eigene LED) — das ist
|
||||
Absicht, kein Fehler.
|
||||
- Die Toolbar des Programmiermodus ist bei der Standardbreite (790px) fast
|
||||
voll — zusätzliche Hinweistexte dort kurz halten, sonst werden sie rechts
|
||||
abgeschnitten.
|
||||
- **Tastendruck-Erkennung (seit 2026-08-28, auf expliziten User-Wunsch):**
|
||||
Tasten lassen sich im Bearbeiten-Dialog per „⌨ Taste drücken" erfassen,
|
||||
Makro-Schritte zusätzlich als Folge am Stück („⏺ Folge aufnehmen").
|
||||
Umgesetzt **ausschließlich über Tk-Fenster-Events** (`<KeyPress>`/
|
||||
`<KeyRelease>` auf dem Dialog-Toplevel, ausgewertet in
|
||||
`versapad_data.tk_event_to_hid()`) — **weiterhin kein WinAPI-Hook**
|
||||
(`SetWindowsHookEx` o.ä.), aus demselben AV-Fehlalarm-Grund wie bei den
|
||||
Fensterverstecktricks. Wer hier auf einen globalen Hook „aufrüstet",
|
||||
baut genau dieses Risiko ein. Konsequenzen, die so bleiben müssen:
|
||||
- Erkannt wird nur, was das fokussierte Fenster erreicht — Win+L,
|
||||
Strg+Alt+Entf und andere vom System abgefangene Kombinationen nicht.
|
||||
- Das Dropdown bleibt daneben stehen (Korrekturmöglichkeit), es ersetzt
|
||||
die Erkennung nicht und wird von ihr nicht ersetzt.
|
||||
- Modifier werden doppelt ermittelt (selbst mitgeführte Press/Release-Bits
|
||||
*plus* `event.state`), weil ein KeyRelease bei Fokuswechsel verloren
|
||||
gehen kann.
|
||||
- `_KeyCapture` hängt an einem `tk.Label`, nicht an einem `tk.Button`:
|
||||
Buttons reagieren per Klassen-Binding selbst auf Leertaste/Enter und
|
||||
würden die laufende Aufnahme mit ihrem eigenen Klick beantworten.
|
||||
- Makro-Schritte filtern das Win-Bit weg (`allow_win=False`), passend zur
|
||||
Firmware-Regel oben.
|
||||
- Zeichentasten-Labels zeigen eine US-Layout-Näherung, nicht das tatsächlich
|
||||
aktive Windows-Tastaturlayout (die echte VersaGUI löst das über
|
||||
`GetKeyNameText()`, das bilden wir ohne WinAPI-Call nicht nach).
|
||||
**Dieselbe Näherung gilt für die Tastendruck-Erkennung:** HID-Keycodes
|
||||
sind physische US-Tastenpositionen, Tk liefert aber nur keysym/VK-Code des
|
||||
aktiven Layouts — die Position (Scan-Code) wäre dafür nötig und ist ohne
|
||||
WinAPI nicht zu bekommen. Auf deutschem Layout landen Y und Z deshalb
|
||||
vertauscht auf dem Board, und die einzige echte Keysym-Kollision (`minus`:
|
||||
US-Position 0x2D vs. deutsche Position 0x38) ist bewusst zugunsten der
|
||||
US-Position aufgelöst, damit Erkennung und Dropdown-Beschriftung dasselbe
|
||||
sagen. Bei gehaltenem Shift zählt zuerst der VK-Code, weil der keysym dann
|
||||
das verschobene Zeichen ist (deutsch: Shift+7 → `slash`, was sonst
|
||||
fälschlich auf Taste 0x38 zeigen würde).
|
||||
- Tk-Aufrufe (`self.after()`, Widget-Konfiguration) NIE direkt aus einem
|
||||
Fremdthread (Serial-Thread, pystray-Thread) — hat in einer früheren
|
||||
Version einen stillen Absturz verursacht. Threads legen Ergebnisse nur in
|
||||
|
|
@ -334,8 +395,6 @@ selbst vorgegeben (`SAction.data`), dort beibehalten statt umzubenennen.
|
|||
explizit vom User abgelehnt ("lass uns weg"), Live-Sync bleibt read-only
|
||||
- Profilnamen aufs Board schreiben — technisch unmöglich (kein Platz im
|
||||
Firmware-Struct), bleibt lokal
|
||||
- Tastendruck-Capture statt Dropdown im Programmiermodus — bewusst
|
||||
vermieden (WinAPI-Hook-Risiko)
|
||||
- Hintergrund-Thread für "Vom Board laden"/"Zum Board übertragen" — laufen
|
||||
aktuell synchron im UI-Thread (kurzzeitiges Einfrieren möglich)
|
||||
- Vorgefertigte `.exe` im Repo/als Release-Asset — bewusst nicht committet
|
||||
|
|
@ -363,6 +422,17 @@ Prüfungen vor einem Commit an Binärformat/Protokoll:
|
|||
```bash
|
||||
python -m py_compile *.py
|
||||
```
|
||||
|
||||
Für UI-Änderungen (Dialoge, Tastendruck-Erkennung, Kopieren/Einfügen) hat
|
||||
sich zusätzlich bewährt, ein Wegwerf-Skript im Scratchpad zu fahren, das die
|
||||
Dialoge ohne Board aufbaut, Tk-Events als kleine Fake-Event-Objekte
|
||||
(`keysym`/`keycode`/`state`) durchreicht und das Ergebnis-Dict prüft — die
|
||||
komplette Capture- und Copy/Paste-Logik ist so ohne Klicken verifizierbar.
|
||||
Wichtig dabei: `versapad_combined.DEFAULT_PATH` vorher auf eine Temp-Datei
|
||||
umbiegen, sonst schreibt `_autosave_combined()` in die echte Nutzer-Config.
|
||||
Für Screenshots gilt: Tk rechnet in logischen Pixeln, `ImageGrab` liefert
|
||||
physische — bei aktiver Windows-Skalierung (hier 125%) sonst ein zu kleiner
|
||||
Ausschnitt, der wie ein Layout-Fehler aussieht.
|
||||
Danach ein Live-Testskript gegen ein angeschlossenes Board laufen lassen
|
||||
(read → unpack → pack → Bytevergleich, siehe Existing-Codebase-Regel) —
|
||||
es gibt keine automatisierten Unit-Tests dafür, die Verifikation läuft
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue