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
|
||||
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:**
|
||||
- `desktop_viewer.py` — Tkinter, flaches Design, drei unabhängige Modi
|
||||
(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
|
||||
`default_combined()` zurück. Bei jedem "komisches Layout"-Report hier immer
|
||||
ALLE 3 Profile prüfen, nicht nur das gemeldete.
|
||||
- **Randloses Fenster (seit 2026-08-15):** Die Titelleiste ist per reinem Tk
|
||||
`overrideredirect(True)` ausgeblendet -- **niemals** per ctypes/WinAPI
|
||||
nachhelfen (kein `SetWindowLongW`/`ShowWindow` auf das eigene Fenster),
|
||||
siehe Speicher-Notiz "keine Selbstversteck-Fenstertricks": genau diese
|
||||
Kombination hat in einem anderen Projekt Bitdefender-Fehlalarme
|
||||
ausgelöst. Konsequenzen, die mitgebaut werden müssen: kein
|
||||
Taskleisten-Eintrag (Rückweg nur über das Tray-Icon), kein Ziehen am
|
||||
Rahmen (Kopfzeile ist deshalb per `<B1-Motion>` verschiebbar), keine
|
||||
System-Buttons (eigene `✕`/`—` in der Kopfzeile, beide legen ins Tray)
|
||||
und **keine Resize-Ränder**.
|
||||
- **Der Größen-Anfasser hängt per `place()` an der Fensterecke, nicht
|
||||
gepackt am Ende des Inhalts.** Gepackt verschwindet er, sobald das Fenster
|
||||
kleiner als der Inhalt ist -- also exakt dann, wenn man ihn zum
|
||||
Vergrößern bräuchte. `MIN_W/MIN_H` begrenzen das Verkleinern.
|
||||
- **WinAPI: was verboten bleibt und was nicht.** Verboten sind
|
||||
**Fenstermanipulation am eigenen Fenster** (`SetWindowLongW`,
|
||||
`ShowWindow`) und **globale Eingabehooks** (`SetWindowsHookEx`) — genau
|
||||
diese Kombination hat laut Speicher-Notiz „keine Selbstversteck-
|
||||
Fenstertricks" in einem anderen Projekt Bitdefender-Fehlalarme ausgeloest.
|
||||
Erlaubt und seit 2026-08-29 in Benutzung sind **passive Layout-Abfragen**
|
||||
(`MapVirtualKeyW`, `GetKeyNameTextW` in `versapad_keylayout.py`): sie
|
||||
lesen nur die Tastaturbelegung, fassen weder Fenster noch Prozesse noch
|
||||
den Eingabestrom an; die offizielle VersaGUI (C#) benutzt
|
||||
`GetKeyNameText()` fuer denselben Zweck. Die Grenze verlaeuft also nicht
|
||||
bei „ctypes", sondern bei „greift ins System ein".
|
||||
- **Normales Fenster mit Titelleiste (seit 2026-08-29).** Von 2026-08-15
|
||||
bis dahin lief das Fenster randlos (`overrideredirect(True)`) — das kostet
|
||||
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
|
||||
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.
|
||||
- **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
|
||||
(2026-08-28):** `_ModalDialog` baut sich `withdraw()`n auf, positioniert
|
||||
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:
|
||||
- Erkannt wird nur, was das fokussierte Fenster erreicht — Win+L,
|
||||
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
|
||||
die Erkennung nicht und wird von ihr nicht ersetzt.
|
||||
- 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.
|
||||
- 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).
|
||||
- **Tastenbeschriftungen kommen vom aktiven Layout** (seit 2026-08-29).
|
||||
`versapad_data.hid_key_name()` fragt fuer Zeichentasten
|
||||
`GetKeyNameTextW` (deutsch: HID 0x1C → „Z", 0x34 → „ä"); fuer alles
|
||||
andere bleiben die gepflegten deutschen Namen aus `_SPECIAL_KEYS`
|
||||
(„Enter", „Bild↑", „Num5") — die lesen sich besser als das, was Windows
|
||||
liefert („EINGABE", „4 (ZEHNERTASTATUR)"). Ohne Layout-Abfrage
|
||||
(Nicht-Windows) faellt alles auf die alte US-Naeherung zurueck.
|
||||
Konsequenzen, die man kennen muss:
|
||||
- Bestehende Belegungen aendern ihre **Anzeige**, nicht ihre Daten. Wer
|
||||
frueher im Dropdown „Z" gewaehlt hat, bekam 0x1D — das steht so in der
|
||||
Config und zeigt jetzt wahrheitsgemaess „Y", weil es auf dieser Tastatur
|
||||
ein Y tippt. Das ist keine Regression, sondern der sichtbar gewordene
|
||||
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
|
||||
Fremdthread (Serial-Thread, pystray-Thread) — hat in einer früheren
|
||||
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
|
||||
- **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
|
||||
drücken (Modifier inklusive). Erkannt wird die *physische* Taste, nicht
|
||||
das Zeichen — Y/Z, ÄÖÜ, `#`, `+` und `ß` landen also richtig auf dem
|
||||
Board, auch auf deutschem Layout. Läuft über das Dialogfenster, nicht
|
||||
ü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-Tabelle vom Board. Schritte einzeln erfassen oder die ganze Folge
|
||||
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)
|
||||
- **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.
|
||||
- **Normales Fenster mit Taskleisten-Eintrag** — Titelleiste, Alt+Tab,
|
||||
Aero-Snap und Größe ändern am Rahmen funktionieren nativ. `✕` beendet
|
||||
nicht, sondern legt ins Tray (wie die offizielle VersaGUI — das Programm
|
||||
läuft im Hintergrund weiter); Minimieren geht normal in die Taskleiste.
|
||||
- **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.
|
||||
Taste unter dem Mauszeiger kopieren/einfügen, `Esc` minimieren.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
|
|
@ -123,7 +127,8 @@ automatisch zuerst nach `%TEMP%` und baut nur dort.
|
|||
|
||||
| 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_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 |
|
||||
|
|
@ -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
|
||||
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
|
||||
- Ein Wechsel des Tastaturlayouts im laufenden Programm wird nicht bemerkt
|
||||
(die Tastennamen werden einmal beim ersten Zugriff ermittelt) — Neustart
|
||||
hilft. Unter Nicht-Windows fällt die Beschriftung auf eine
|
||||
US-Layout-Näherung zurück
|
||||
- Unsignierte `.exe` — kann von Antivirus/Smart App Control blockiert
|
||||
werden; `--onedir` (statt `--onefile`) verringert das Risiko, verhindert
|
||||
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). |
|
||||
| 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
|
||||
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
|
||||
andere vom Betriebssystem abgefangene Kombinationen kommen nie an. Ein
|
||||
globaler `SetWindowsHookEx`-Hook würde sie sehen, ist aber ausgeschlossen
|
||||
(AV-Fehlalarm-Risiko, siehe `AGENTS.md`).
|
||||
2. **Die Zuordnung ist eine US-Layout-Näherung.** HID-Keycodes bezeichnen
|
||||
physische Tastenpositionen des US-Layouts; Tk liefert nur `keysym` und
|
||||
Windows-Virtual-Key-Code, beide vom *aktiven* Layout abgeleitet. Die
|
||||
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.
|
||||
Zweite und wichtigere Folge betrifft die *Zuordnung*. HID-Keycodes
|
||||
bezeichnen **physische Tastenpositionen**: das Board sendet eine Position,
|
||||
erst Windows macht daraus über das aktive Layout ein Zeichen. Wer die
|
||||
Zuordnung über das *Zeichen* aufbaut, dreht diese Kette falsch herum — auf
|
||||
deutschem Layout landete dadurch jedes Y auf der Z-Taste des Boards und
|
||||
ÄÖÜ/#/+ waren gar nicht erfassbar. `versapad_data.tk_event_to_hid()` löst
|
||||
deshalb in dieser Reihenfolge auf:
|
||||
|
||||
Details der Zuordnungstabellen: `versapad_data.tk_event_to_hid()` und die
|
||||
`_TK_*`/`_WIN_VK_TO_HID`-Dicts darüber.
|
||||
1. **Benannte Tasten über den Tk-keysym** (Enter, Escape, Pfeile, F-Tasten,
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue