Document the layout fix and the return of the title bar
AGENTS.md: die WinAPI-Regel praeziser gefasst -- verboten bleiben Fenstermanipulation und globale Hooks, passive Layout-Abfragen sind es nicht (und die offizielle VersaGUI macht dasselbe). Dazu die neue Aufloesungsreihenfolge samt Warnung, nicht auf "Zeichen auswerten" zurueckzubauen, die Kollisionsregel bei Tastennamen, der Mehrmonitor-Fix und die Folgen der Titelleiste (welche Eigenbauten dadurch entfallen sind und warum randlos nicht ohne Ruecksprache zurueckkommt). README.md und docs/architecture.md entsprechend: Position statt Zeichen, layoutrichtige Beschriftungen inkl. der Anzeigeaenderung an bestehenden Belegungen, Taskleisten-Eintrag statt randlosem Fenster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e1e3d0e466
commit
78e9640dec
3 changed files with 152 additions and 61 deletions
112
AGENTS.md
112
AGENTS.md
|
|
@ -59,6 +59,13 @@ Nutzerorientierte Einführung: [`README.md`](README.md).
|
||||||
`read_profile_names()` liest nur die Namen (kein Board-Zugriff, fuer
|
`read_profile_names()` liest nur die Namen (kein Board-Zugriff, fuer
|
||||||
Tab-Beschriftungen im Nur-Lese-Modus, siehe Installierbarkeit-Notiz).
|
Tab-Beschriftungen im Nur-Lese-Modus, siehe Installierbarkeit-Notiz).
|
||||||
|
|
||||||
|
- `versapad_keylayout.py` (seit 2026-08-29) — passive Abfragen ans aktive
|
||||||
|
Windows-Tastaturlayout: `hid_for_vk()` (Virtual-Key → Scan-Code → HID über
|
||||||
|
`MapVirtualKeyW`) und `key_name()` (Beschriftung über `GetKeyNameTextW`).
|
||||||
|
Optional: auf Nicht-Windows/ohne ctypes bleibt `AVAILABLE` False und
|
||||||
|
`versapad_data` faellt auf seine US-Naeherung zurueck. Zur Abgrenzung
|
||||||
|
gegen die WinAPI-Verbote siehe Domaenenregeln.
|
||||||
|
|
||||||
**UI:**
|
**UI:**
|
||||||
- `desktop_viewer.py` — Tkinter, flaches Design, drei unabhängige Modi
|
- `desktop_viewer.py` — Tkinter, flaches Design, drei unabhängige Modi
|
||||||
(Nur lesen / Live-Sync / Programmiermodus, siehe Kritische Domänenregeln),
|
(Nur lesen / Live-Sync / Programmiermodus, siehe Kritische Domänenregeln),
|
||||||
|
|
@ -235,24 +242,47 @@ Protokoll) liegt in `docs/`, siehe „Dokumentation und Verifikation" unten.
|
||||||
`vcomb.DEFAULT_PATH`, fällt nur bei fehlender/kaputter Datei auf
|
`vcomb.DEFAULT_PATH`, fällt nur bei fehlender/kaputter Datei auf
|
||||||
`default_combined()` zurück. Bei jedem "komisches Layout"-Report hier immer
|
`default_combined()` zurück. Bei jedem "komisches Layout"-Report hier immer
|
||||||
ALLE 3 Profile prüfen, nicht nur das gemeldete.
|
ALLE 3 Profile prüfen, nicht nur das gemeldete.
|
||||||
- **Randloses Fenster (seit 2026-08-15):** Die Titelleiste ist per reinem Tk
|
- **WinAPI: was verboten bleibt und was nicht.** Verboten sind
|
||||||
`overrideredirect(True)` ausgeblendet -- **niemals** per ctypes/WinAPI
|
**Fenstermanipulation am eigenen Fenster** (`SetWindowLongW`,
|
||||||
nachhelfen (kein `SetWindowLongW`/`ShowWindow` auf das eigene Fenster),
|
`ShowWindow`) und **globale Eingabehooks** (`SetWindowsHookEx`) — genau
|
||||||
siehe Speicher-Notiz "keine Selbstversteck-Fenstertricks": genau diese
|
diese Kombination hat laut Speicher-Notiz „keine Selbstversteck-
|
||||||
Kombination hat in einem anderen Projekt Bitdefender-Fehlalarme
|
Fenstertricks" in einem anderen Projekt Bitdefender-Fehlalarme ausgeloest.
|
||||||
ausgelöst. Konsequenzen, die mitgebaut werden müssen: kein
|
Erlaubt und seit 2026-08-29 in Benutzung sind **passive Layout-Abfragen**
|
||||||
Taskleisten-Eintrag (Rückweg nur über das Tray-Icon), kein Ziehen am
|
(`MapVirtualKeyW`, `GetKeyNameTextW` in `versapad_keylayout.py`): sie
|
||||||
Rahmen (Kopfzeile ist deshalb per `<B1-Motion>` verschiebbar), keine
|
lesen nur die Tastaturbelegung, fassen weder Fenster noch Prozesse noch
|
||||||
System-Buttons (eigene `✕`/`—` in der Kopfzeile, beide legen ins Tray)
|
den Eingabestrom an; die offizielle VersaGUI (C#) benutzt
|
||||||
und **keine Resize-Ränder**.
|
`GetKeyNameText()` fuer denselben Zweck. Die Grenze verlaeuft also nicht
|
||||||
- **Der Größen-Anfasser hängt per `place()` an der Fensterecke, nicht
|
bei „ctypes", sondern bei „greift ins System ein".
|
||||||
gepackt am Ende des Inhalts.** Gepackt verschwindet er, sobald das Fenster
|
- **Normales Fenster mit Titelleiste (seit 2026-08-29).** Von 2026-08-15
|
||||||
kleiner als der Inhalt ist -- also exakt dann, wenn man ihn zum
|
bis dahin lief das Fenster randlos (`overrideredirect(True)`) — das kostet
|
||||||
Vergrößern bräuchte. `MIN_W/MIN_H` begrenzen das Verkleinern.
|
unter Windows zwingend den Taskleisten-Eintrag. Als der ausdruecklich
|
||||||
|
gebraucht wurde, gab es nur drei Wege: Titelleiste zurueck,
|
||||||
|
`SetWindowLongW`+WS_EX_APPWINDOW (siehe Verbot oben) oder ein
|
||||||
|
unsichtbares Proxy-Fenster. Der User hat sich fuer die Titelleiste
|
||||||
|
entschieden. Damit sind ersatzlos entfallen: ziehbare Kopfzeile
|
||||||
|
(`_start_move`/`_on_move`), Groessen-Anfasser unten rechts
|
||||||
|
(`_start_resize`/`_on_resize`, ersetzt durch `self.minsize()`), die
|
||||||
|
eigenen `✕`/`—`-Knoepfe und der `<Unmap>`-Handler, der Minimieren ins Tray
|
||||||
|
umgeleitet hat. **Wer das Fenster wieder randlos machen will, nimmt dem
|
||||||
|
User den Taskleisten-Eintrag weg** — nicht ohne Ruecksprache.
|
||||||
|
- Schliessen (`✕`) legt weiterhin ins Tray statt zu beenden (wie die
|
||||||
|
offizielle VersaGUI, das Programm laeuft im Hintergrund weiter),
|
||||||
|
Minimieren geht jetzt aber ganz normal in die Taskleiste. `Escape`
|
||||||
|
minimiert ebenfalls, statt wie frueher ins Tray zu legen — mit
|
||||||
|
Taskleisten-Eintrag waere „verschwindet spurlos" die unangenehmere
|
||||||
|
Ueberraschung.
|
||||||
- Fensterhöhe muss zum Karteninhalt passen: seit die Karten eine Notizzeile
|
- Fensterhöhe muss zum Karteninhalt passen: seit die Karten eine Notizzeile
|
||||||
haben (`CARD_H` 84 → 114) braucht das Fenster ~960px, sonst liegen
|
haben (`CARD_H` 84 → 114) braucht das Fenster ~960px, sonst liegen
|
||||||
Encoder-Bereich und Fußzeile unterhalb des Rands. Wer `CARD_H` ändert,
|
Encoder-Bereich und Fußzeile unterhalb des Rands. Wer `CARD_H` ändert,
|
||||||
muss `geometry()` mit anpassen.
|
muss `geometry()` mit anpassen.
|
||||||
|
- **Dialogposition wird gegen das ELTERNFENSTER begrenzt, nie gegen
|
||||||
|
`winfo_screenwidth()` (2026-08-29):** Tk meldet dort nur den
|
||||||
|
Hauptbildschirm. Die erste Fassung hat damit geklemmt — lag das
|
||||||
|
Hauptfenster auf einem zweiten Monitor, zog genau diese Begrenzung den
|
||||||
|
Dialog zurueck an den Rand des ersten. Passt der Dialog nicht ins
|
||||||
|
Elternfenster (der Makro-Schritte-Dialog ist breiter als der
|
||||||
|
Action-Dialog), wird er an dessen linker oberer Ecke ausgerichtet statt
|
||||||
|
zentriert.
|
||||||
- **Dialoge öffnen über dem Hauptfenster, nicht in der Bildschirmecke
|
- **Dialoge öffnen über dem Hauptfenster, nicht in der Bildschirmecke
|
||||||
(2026-08-28):** `_ModalDialog` baut sich `withdraw()`n auf, positioniert
|
(2026-08-28):** `_ModalDialog` baut sich `withdraw()`n auf, positioniert
|
||||||
sich in `run()` per `_center_on_parent()` und wird erst dann
|
sich in `run()` per `_center_on_parent()` und wird erst dann
|
||||||
|
|
@ -290,6 +320,23 @@ Protokoll) liegt in `docs/`, siehe „Dokumentation und Verifikation" unten.
|
||||||
baut genau dieses Risiko ein. Konsequenzen, die so bleiben müssen:
|
baut genau dieses Risiko ein. Konsequenzen, die so bleiben müssen:
|
||||||
- Erkannt wird nur, was das fokussierte Fenster erreicht — Win+L,
|
- Erkannt wird nur, was das fokussierte Fenster erreicht — Win+L,
|
||||||
Strg+Alt+Entf und andere vom System abgefangene Kombinationen nicht.
|
Strg+Alt+Entf und andere vom System abgefangene Kombinationen nicht.
|
||||||
|
- **Welche Taste gemeint ist, wird ueber die PHYSISCHE POSITION
|
||||||
|
aufgeloest, nie ueber das erzeugte Zeichen** (2026-08-29, nach
|
||||||
|
Fehlermeldung aus der Praxis). HID-Keycodes *sind* Positionen: das Board
|
||||||
|
sendet eine Position, erst Windows macht daraus ein Zeichen. Die erste
|
||||||
|
Fassung ging ueber keysym/Zeichen und war auf deutschem Layout
|
||||||
|
entsprechend kaputt — Y und Z landeten vertauscht auf dem Board, ÄÖÜ
|
||||||
|
und #/+ waren gar nicht erfassbar. Reihenfolge jetzt: (1) benannte
|
||||||
|
Tasten ueber den keysym, (2) Zeichentasten ueber
|
||||||
|
`versapad_keylayout.hid_for_vk()`, (3) die alte Naeherung nur noch als
|
||||||
|
Fallback ohne WinAPI. **Nicht auf "Zeichen auswerten" zurueckbauen** —
|
||||||
|
das ist genau der Fehler, der hier behoben wurde.
|
||||||
|
- Schritt (1) ist keine Bequemlichkeit, sondern noetig: `MapVirtualKeyW`
|
||||||
|
liefert fuer die Pfeiltasten denselben Scan-Code wie fuer ihre
|
||||||
|
Numpad-Zwillinge (gemessen: VK_LEFT und VK_NUMPAD4 beide 0x4B, das
|
||||||
|
E0-Praefix von `MAPVK_VK_TO_VSC_EX` bleibt dort aus). Ueber den
|
||||||
|
Scan-Code allein waeren Pfeiltasten nicht von Numpad-Tasten zu
|
||||||
|
unterscheiden.
|
||||||
- Das Dropdown bleibt daneben stehen (Korrekturmöglichkeit), es ersetzt
|
- Das Dropdown bleibt daneben stehen (Korrekturmöglichkeit), es ersetzt
|
||||||
die Erkennung nicht und wird von ihr nicht ersetzt.
|
die Erkennung nicht und wird von ihr nicht ersetzt.
|
||||||
- Modifier werden doppelt ermittelt (selbst mitgeführte Press/Release-Bits
|
- Modifier werden doppelt ermittelt (selbst mitgeführte Press/Release-Bits
|
||||||
|
|
@ -300,19 +347,30 @@ Protokoll) liegt in `docs/`, siehe „Dokumentation und Verifikation" unten.
|
||||||
würden die laufende Aufnahme mit ihrem eigenen Klick beantworten.
|
würden die laufende Aufnahme mit ihrem eigenen Klick beantworten.
|
||||||
- Makro-Schritte filtern das Win-Bit weg (`allow_win=False`), passend zur
|
- Makro-Schritte filtern das Win-Bit weg (`allow_win=False`), passend zur
|
||||||
Firmware-Regel oben.
|
Firmware-Regel oben.
|
||||||
- Zeichentasten-Labels zeigen eine US-Layout-Näherung, nicht das tatsächlich
|
- **Tastenbeschriftungen kommen vom aktiven Layout** (seit 2026-08-29).
|
||||||
aktive Windows-Tastaturlayout (die echte VersaGUI löst das über
|
`versapad_data.hid_key_name()` fragt fuer Zeichentasten
|
||||||
`GetKeyNameText()`, das bilden wir ohne WinAPI-Call nicht nach).
|
`GetKeyNameTextW` (deutsch: HID 0x1C → „Z", 0x34 → „ä"); fuer alles
|
||||||
**Dieselbe Näherung gilt für die Tastendruck-Erkennung:** HID-Keycodes
|
andere bleiben die gepflegten deutschen Namen aus `_SPECIAL_KEYS`
|
||||||
sind physische US-Tastenpositionen, Tk liefert aber nur keysym/VK-Code des
|
(„Enter", „Bild↑", „Num5") — die lesen sich besser als das, was Windows
|
||||||
aktiven Layouts — die Position (Scan-Code) wäre dafür nötig und ist ohne
|
liefert („EINGABE", „4 (ZEHNERTASTATUR)"). Ohne Layout-Abfrage
|
||||||
WinAPI nicht zu bekommen. Auf deutschem Layout landen Y und Z deshalb
|
(Nicht-Windows) faellt alles auf die alte US-Naeherung zurueck.
|
||||||
vertauscht auf dem Board, und die einzige echte Keysym-Kollision (`minus`:
|
Konsequenzen, die man kennen muss:
|
||||||
US-Position 0x2D vs. deutsche Position 0x38) ist bewusst zugunsten der
|
- Bestehende Belegungen aendern ihre **Anzeige**, nicht ihre Daten. Wer
|
||||||
US-Position aufgelöst, damit Erkennung und Dropdown-Beschriftung dasselbe
|
frueher im Dropdown „Z" gewaehlt hat, bekam 0x1D — das steht so in der
|
||||||
sagen. Bei gehaltenem Shift zählt zuerst der VK-Code, weil der keysym dann
|
Config und zeigt jetzt wahrheitsgemaess „Y", weil es auf dieser Tastatur
|
||||||
das verschobene Zeichen ist (deutsch: Shift+7 → `slash`, was sonst
|
ein Y tippt. Das ist keine Regression, sondern der sichtbar gewordene
|
||||||
fälschlich auf Taste 0x38 zeigen würde).
|
Altfehler.
|
||||||
|
- Namen sind Schluessel (Dropdown, `hid_key_code_for_name()`) und muessen
|
||||||
|
eindeutig bleiben. Es gibt echte Kollisionen: auf deutschem Layout heisst
|
||||||
|
HID 0x31 schlicht „#" — den Namen trug bisher HID 0x32. Der Layoutname
|
||||||
|
gewinnt, der verdraengte US-Name wird als „# (US-Layout)" gekennzeichnet
|
||||||
|
statt verworfen, damit die Taste ansprechbar bleibt.
|
||||||
|
- `hid_key_code_for_name()` akzeptiert weiterhin beide Schreibweisen, bei
|
||||||
|
Kollision gewinnt das Layout. Fuer den MCP-Server heisst das:
|
||||||
|
`set_button_key(key="Z")` trifft die Taste, die auf dieser Tastatur ein
|
||||||
|
Z tippt (0x1C), nicht mehr die US-Position 0x1D.
|
||||||
|
- Ein Layoutwechsel zur Laufzeit wird nicht bemerkt (Namen werden einmal
|
||||||
|
ermittelt und behalten).
|
||||||
- Tk-Aufrufe (`self.after()`, Widget-Konfiguration) NIE direkt aus einem
|
- Tk-Aufrufe (`self.after()`, Widget-Konfiguration) NIE direkt aus einem
|
||||||
Fremdthread (Serial-Thread, pystray-Thread) — hat in einer früheren
|
Fremdthread (Serial-Thread, pystray-Thread) — hat in einer früheren
|
||||||
Version einen stillen Absturz verursacht. Threads legen Ergebnisse nur in
|
Version einen stillen Absturz verursacht. Threads legen Ergebnisse nur in
|
||||||
|
|
|
||||||
37
README.md
37
README.md
|
|
@ -34,10 +34,15 @@ falls gewünscht.
|
||||||
Enter bestätigt, Escape bricht ab
|
Enter bestätigt, Escape bricht ab
|
||||||
- **Tastendruck-Erkennung** — statt die Taste im Dropdown zu suchen,
|
- **Tastendruck-Erkennung** — statt die Taste im Dropdown zu suchen,
|
||||||
„⌨ Taste drücken" klicken und die gewünschte Kombination einfach
|
„⌨ Taste drücken" klicken und die gewünschte Kombination einfach
|
||||||
drücken (Modifier inklusive). Läuft über das Dialogfenster, nicht über
|
drücken (Modifier inklusive). Erkannt wird die *physische* Taste, nicht
|
||||||
einen System-Hook — vom System abgefangene Kombinationen (Win+L,
|
das Zeichen — Y/Z, ÄÖÜ, `#`, `+` und `ß` landen also richtig auf dem
|
||||||
Strg+Alt+Entf) kommen deshalb nicht an, und das Dropdown bleibt zum
|
Board, auch auf deutschem Layout. Läuft über das Dialogfenster, nicht
|
||||||
Nachkorrigieren daneben stehen
|
über einen System-Hook: vom System abgefangene Kombinationen (Win+L,
|
||||||
|
Strg+Alt+Entf) kommen nicht an
|
||||||
|
- **Layoutrichtige Tastennamen** — Beschriftungen kommen vom aktiven
|
||||||
|
Windows-Layout (`Strg+Z` heißt auf deutscher Tastatur auch `Strg+Z`, und
|
||||||
|
`ä`/`ö`/`ü` heißen so). Bestehende Belegungen ändern dadurch ihre
|
||||||
|
Anzeige, nicht ihre Funktion
|
||||||
- **Makro-Editor** — bis zu 8 Schritte pro Slot, liest/schreibt die echte
|
- **Makro-Editor** — bis zu 8 Schritte pro Slot, liest/schreibt die echte
|
||||||
Makro-Tabelle vom Board. Schritte einzeln erfassen oder die ganze Folge
|
Makro-Tabelle vom Board. Schritte einzeln erfassen oder die ganze Folge
|
||||||
am Stück aufnehmen („⏺ Folge aufnehmen"). Die Slot-Auswahl listet alle 32
|
am Stück aufnehmen („⏺ Folge aufnehmen"). Die Slot-Auswahl listet alle 32
|
||||||
|
|
@ -59,14 +64,13 @@ falls gewünscht.
|
||||||
Tool-Aufruf ändern, ohne Klicks in der GUI (siehe unten)
|
Tool-Aufruf ändern, ohne Klicks in der GUI (siehe unten)
|
||||||
- **Tray-Icon** — minimiert/schließt ins Tray statt in die Taskleiste, wie
|
- **Tray-Icon** — minimiert/schließt ins Tray statt in die Taskleiste, wie
|
||||||
die offizielle VersaGUI
|
die offizielle VersaGUI
|
||||||
- **Randloses Fenster** — ohne Windows-Titelleiste, dafür kompakter Kopf
|
- **Normales Fenster mit Taskleisten-Eintrag** — Titelleiste, Alt+Tab,
|
||||||
(Modus-Checkboxen direkt neben dem Titel). Verschieben durch Ziehen an
|
Aero-Snap und Größe ändern am Rahmen funktionieren nativ. `✕` beendet
|
||||||
der Kopfzeile, Größe ändern am Anfasser unten rechts, `✕`/`—` legen ins
|
nicht, sondern legt ins Tray (wie die offizielle VersaGUI — das Programm
|
||||||
Tray. Einen Taskleisten-Eintrag gibt es dadurch nicht — das Fenster kommt
|
läuft im Hintergrund weiter); Minimieren geht normal in die Taskleiste.
|
||||||
über das Tray-Icon zurück.
|
|
||||||
- **Tastenkürzel im Hauptfenster** — `Strg+1/2/3` Profil wechseln, `F2`
|
- **Tastenkürzel im Hauptfenster** — `Strg+1/2/3` Profil wechseln, `F2`
|
||||||
Profil umbenennen, `Strg+E` Programmiermodus an/aus, `Strg+C`/`Strg+V`
|
Profil umbenennen, `Strg+E` Programmiermodus an/aus, `Strg+C`/`Strg+V`
|
||||||
Taste unter dem Mauszeiger kopieren/einfügen, `Esc` ins Tray.
|
Taste unter dem Mauszeiger kopieren/einfügen, `Esc` minimieren.
|
||||||
|
|
||||||
## Voraussetzungen
|
## Voraussetzungen
|
||||||
|
|
||||||
|
|
@ -123,7 +127,8 @@ automatisch zuerst nach `%TEMP%` und baut nur dort.
|
||||||
|
|
||||||
| Datei | Zweck |
|
| Datei | Zweck |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `versapad_data.py` | Decoding für die Anzeige: JSON laden, HID-Keycodes/Consumer-IDs/Modifier → lesbarer Text |
|
| `versapad_data.py` | Decoding für die Anzeige: JSON laden, HID-Keycodes/Consumer-IDs/Modifier → lesbarer Text, Tastendruck → HID-Keycode |
|
||||||
|
| `versapad_keylayout.py` | Abfragen ans aktive Windows-Tastaturlayout: physische Tastenposition und Tastenname (optional, nur Windows) |
|
||||||
| `versapad_protocol.py` | Binäres NVM-Layout des Boards (740B Config + 512B Makros), CRC16 — pack/unpack |
|
| `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_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 |
|
| `versapad_combined.py` | Ein-Datei-Format für alle 3 Profile + Makros + lokale Profilnamen |
|
||||||
|
|
@ -187,12 +192,10 @@ rechts im Fenster, oder direkt in `versapad_mcp_server.py`.
|
||||||
- Die Tastendruck-Erkennung läuft bewusst über das Dialogfenster statt über
|
- Die Tastendruck-Erkennung läuft bewusst über das Dialogfenster statt über
|
||||||
einen globalen WinAPI-Hook — vom System abgefangene Kombinationen (Win+L,
|
einen globalen WinAPI-Hook — vom System abgefangene Kombinationen (Win+L,
|
||||||
Strg+Alt+Entf) erreichen das Fenster nie und lassen sich so nicht erfassen
|
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
|
- Ein Wechsel des Tastaturlayouts im laufenden Programm wird nicht bemerkt
|
||||||
aktive Tastatur-Layout. Das betrifft auch die Tastendruck-Erkennung:
|
(die Tastennamen werden einmal beim ersten Zugriff ermittelt) — Neustart
|
||||||
HID-Keycodes sind physische US-Tastenpositionen, erkennbar ist ohne
|
hilft. Unter Nicht-Windows fällt die Beschriftung auf eine
|
||||||
WinAPI aber nur das Zeichen des aktiven Layouts — auf deutschem Layout
|
US-Layout-Näherung zurück
|
||||||
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
|
- Unsignierte `.exe` — kann von Antivirus/Smart App Control blockiert
|
||||||
werden; `--onedir` (statt `--onefile`) verringert das Risiko, verhindert
|
werden; `--onedir` (statt `--onefile`) verringert das Risiko, verhindert
|
||||||
es aber nicht
|
es aber nicht
|
||||||
|
|
|
||||||
|
|
@ -155,27 +155,57 @@ Drei Checkboxen, unabhängig voneinander:
|
||||||
| Live-Sync | Fragt per Serial das aktuell aktive Profil ab, schaltet die Ansicht mit | Hintergrund-Thread pollt `read_active_profile()`, hält dafür den COM-Port dauerhaft offen, solange die Checkbox an ist. Schließt sich mit VersaGUI/Programmiermodus/MCP-Board-Zugriff gegenseitig aus (exklusiver Port). |
|
| Live-Sync | Fragt per Serial das aktuell aktive Profil ab, schaltet die Ansicht mit | Hintergrund-Thread pollt `read_active_profile()`, hält dafür den COM-Port dauerhaft offen, solange die Checkbox an ist. Schließt sich mit VersaGUI/Programmiermodus/MCP-Board-Zugriff gegenseitig aus (exklusiver Port). |
|
||||||
| Programmiermodus | Zellen anklicken zum Bearbeiten | Lädt `self.combined` **einmalig pro Prozesslauf** beim ersten Aktivieren (bevorzugt `DEFAULT_PATH`, sonst `default_combined()`). Jede Bearbeitung speichert sofort automatisch (`_autosave_combined()`). **Achtung:** Da der Snapshot nur einmal geladen wird, sieht der Programmiermodus externe Änderungen (z.B. per MCP) erst nach einem Neustart der exe oder einem expliziten „Datei laden…“. |
|
| Programmiermodus | Zellen anklicken zum Bearbeiten | Lädt `self.combined` **einmalig pro Prozesslauf** beim ersten Aktivieren (bevorzugt `DEFAULT_PATH`, sonst `default_combined()`). Jede Bearbeitung speichert sofort automatisch (`_autosave_combined()`). **Achtung:** Da der Snapshot nur einmal geladen wird, sieht der Programmiermodus externe Änderungen (z.B. per MCP) erst nach einem Neustart der exe oder einem expliziten „Datei laden…“. |
|
||||||
|
|
||||||
### Grenzen der Tastendruck-Erkennung
|
### Tastendruck-Erkennung: Position statt Zeichen
|
||||||
|
|
||||||
Die Erkennung im Bearbeiten-Dialog nutzt ausschließlich Tk-Events des
|
Die Erkennung im Bearbeiten-Dialog nutzt ausschließlich Tk-Events des
|
||||||
fokussierten Fensters. Daraus folgt zweierlei, und beides ist bewusst so:
|
fokussierten Fensters — kein globaler `SetWindowsHookEx`-Hook (siehe
|
||||||
|
`AGENTS.md`). Erste Folge: **nur was das Fenster erreicht, wird erkannt.**
|
||||||
|
Win+L, Strg+Alt+Entf und andere vom Betriebssystem abgefangene
|
||||||
|
Kombinationen kommen nie an.
|
||||||
|
|
||||||
1. **Nur was das Fenster erreicht, wird erkannt.** Win+L, Strg+Alt+Entf und
|
Zweite und wichtigere Folge betrifft die *Zuordnung*. HID-Keycodes
|
||||||
andere vom Betriebssystem abgefangene Kombinationen kommen nie an. Ein
|
bezeichnen **physische Tastenpositionen**: das Board sendet eine Position,
|
||||||
globaler `SetWindowsHookEx`-Hook würde sie sehen, ist aber ausgeschlossen
|
erst Windows macht daraus über das aktive Layout ein Zeichen. Wer die
|
||||||
(AV-Fehlalarm-Risiko, siehe `AGENTS.md`).
|
Zuordnung über das *Zeichen* aufbaut, dreht diese Kette falsch herum — auf
|
||||||
2. **Die Zuordnung ist eine US-Layout-Näherung.** HID-Keycodes bezeichnen
|
deutschem Layout landete dadurch jedes Y auf der Z-Taste des Boards und
|
||||||
physische Tastenpositionen des US-Layouts; Tk liefert nur `keysym` und
|
ÄÖÜ/#/+ waren gar nicht erfassbar. `versapad_data.tk_event_to_hid()` löst
|
||||||
Windows-Virtual-Key-Code, beide vom *aktiven* Layout abgeleitet. Die
|
deshalb in dieser Reihenfolge auf:
|
||||||
physische Position (Scan-Code) wäre nötig, um das exakt aufzulösen, und
|
|
||||||
ist ohne WinAPI-Aufruf nicht verfügbar. Praktische Folge auf deutschem
|
|
||||||
Layout: Y und Z landen vertauscht auf dem Board. Das Ergebnis wird immer
|
|
||||||
ins Dropdown und in die Modifier-Checkboxen geschrieben und ist dort
|
|
||||||
korrigierbar — die Erkennung ersetzt die manuelle Auswahl nicht, sie
|
|
||||||
beschleunigt sie nur.
|
|
||||||
|
|
||||||
Details der Zuordnungstabellen: `versapad_data.tk_event_to_hid()` und die
|
1. **Benannte Tasten über den Tk-keysym** (Enter, Escape, Pfeile, F-Tasten,
|
||||||
`_TK_*`/`_WIN_VK_TO_HID`-Dicts darüber.
|
Numpad, Entf …). Layoutunabhängig eindeutig — und hier zwingend, weil
|
||||||
|
`MapVirtualKeyW` für die Pfeiltasten denselben Scan-Code liefert wie für
|
||||||
|
ihre Numpad-Zwillinge (gemessen: VK_LEFT und VK_NUMPAD4 beide 0x4B).
|
||||||
|
2. **Zeichentasten über die physische Position** —
|
||||||
|
`versapad_keylayout.hid_for_vk()`: Virtual-Key → Scan-Code
|
||||||
|
(`MapVirtualKeyW`) → HID über die layoutunabhängige Tabelle
|
||||||
|
`SCANCODE_TO_HID`. Der Virtual-Key ist unabhängig davon, ob Shift oder
|
||||||
|
AltGr mitgehalten wird.
|
||||||
|
3. **Näherung ohne WinAPI** (keysym-Zeichentabelle, dann VK-Tabelle) — nur
|
||||||
|
relevant, wenn `versapad_keylayout` nicht verfügbar ist (Nicht-Windows,
|
||||||
|
kein ctypes). Auf dieser Ebene bleibt es bei der US-Layout-Näherung
|
||||||
|
inklusive vertauschtem Y/Z.
|
||||||
|
|
||||||
|
### Tastenbeschriftungen
|
||||||
|
|
||||||
|
`versapad_data.hid_key_name()` fragt für Zeichentasten `GetKeyNameTextW`
|
||||||
|
und zeigt damit den Namen des aktiven Layouts (deutsch: HID 0x1C → „Z“,
|
||||||
|
0x34 → „ä“). Für alles andere bleiben die gepflegten deutschen Namen aus
|
||||||
|
`_SPECIAL_KEYS` („Enter“, „Bild↑“, „Num5“) — die lesen sich besser als das,
|
||||||
|
was Windows dafür liefert („EINGABE“, „4 (ZEHNERTASTATUR)“).
|
||||||
|
|
||||||
|
Diese Namen sind zugleich Schlüssel (Dropdown-Einträge,
|
||||||
|
`hid_key_code_for_name()` für den MCP-Server) und müssen eindeutig bleiben.
|
||||||
|
Echte Kollisionen kommen vor: auf deutschem Layout heißt HID 0x31 schlicht
|
||||||
|
„#“, und diesen Namen trug bisher HID 0x32. Der Layoutname gewinnt, der
|
||||||
|
verdrängte US-Name wird als „# (US-Layout)“ gekennzeichnet statt verworfen.
|
||||||
|
`hid_key_code_for_name()` akzeptiert beide Schreibweisen; bei Kollision
|
||||||
|
gewinnt das Layout, damit `set_button_key(key="Z")` die Taste trifft, die
|
||||||
|
auf dieser Tastatur ein Z tippt.
|
||||||
|
|
||||||
|
Bestehende Belegungen ändern dadurch ihre **Anzeige, nicht ihre Daten**:
|
||||||
|
eine früher über das Dropdown gesetzte „Z“ steht als 0x1D in der Config und
|
||||||
|
wird jetzt wahrheitsgemäß als „Y“ angezeigt, weil sie auf dieser Tastatur
|
||||||
|
ein Y tippt. Ein Layoutwechsel zur Laufzeit wird nicht nachgezogen.
|
||||||
|
|
||||||
### Kopieren/Einfügen zwischen Tasten
|
### Kopieren/Einfügen zwischen Tasten
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue