# KeyBuddy2 - Dokumentation

von Mirko Kunze mirko.kunze(a)web.de
KeyBuddy2 ist ein Programm zur Umsetzung des neo-Layouts. Außerdem bietet es die Möglichkeit, kyrillische Zeichen einzugeben und Hotstrings zu definieren, wobei während des Tippens Zeichenketten ersetzt oder Programme gestartet werden können. KeyBuddy2 ist Freeware und kostet lediglich einen würdigenden Gedanken an den Autor.

## KeyBuddy2 benutzen

Einfach KeyBuddy2.exe ausführen. Im selben Ordner müssen folgende Dateien liegen: hotstrings.txt, keynames.txt, mousemap.txt, neomap.txt, rumap.txt, sendmap.txt, symbolmap.txt, uppercase.txt
Eine Tastatur öffnet sich, die Anzeigt, was passiert, wenn man eine Taste drückt. Im Groben verhält sich die Tastatur wie hier www.neo-layout.org beschrieben. Es gibt jedoch folgende Erweiterungen:

- Da man manchmal Shift und die Pfeiltasten benutzen möchte, wird im normalen neo-Layout kein Unterschied zwischen der 4. Ebene und Shift + 4. Ebene (Pseudo-Ebene) gemacht. Die rechte Hand hat in dieser Pseudo-Ebene jedoch keine Aufgabe, deswegen sind hier alle Umschalter über die rechte Hand in der Pseudo-Ebene zu erreichen.
- Man hat die Wahl, ob die Buchstaben wie im neo-Layout umsortiert sein sollen oder nicht. Die weiteren Ebenen sind auch im qwertz-Layout verfügbar. Umschalter ist standardmäßig Mod4+Shift+N (für neo).
- Man kann auf kyrillische Buchstaben umschalten, standardmäßig Mod4+Shift+K (für kyrillisch).
- Das Programm lässt sich deaktivieren über Mod4+Shift+L (für Layers). Der Mechanismus für die Tastaturüberwachung ist jedoch weiterhin aktiv und wartet auf erneute Eingabe dieser Tastenkombination zum reaktivieren.
- Über Mod4+Shift+Ö (für öffnen) lässt sich die Tastatur anzeigen und verstecken (geht auch durch Linksklicks auf das Tray-Icon).
- Mit Mod4+Shift+M (für Maus) kann man die Maussteuerung aktivieren und deaktivieren.
- Komplett schließen lässt sich das Programm entweder via Mod4+Shift+Z (für zu) oder über Rechtsklick auf das Tray-Icon -> Exit.
- Zusätzlich lassen sich Hotstrings definieren. Das Programm zeichnet die Eingabe des Nutzers permanent auf. Sobald eine vorher definierte Zeichenkette eingegeben wurde, wird sie ersetzt oder ein Programm wird ausgeführt.
- Damit alle Symbole auf den Tasten dargestellt werden können, wird empfohlen, die hässliche aber vollständige Schriftart Unifont als ttf herunterzuladen (http://unifoundry.com/unifont.html) und zu installieren.

Folgende Aspekte von neo wurden nicht umgesetzt:

- Das Numpad (Ich habe keins an meinem Laptop und die Hände gehören sowieso auf die Hauptebene!)
- Die Compose-Taste fügt nur eine Note in den Text ein. Benötigt man Compose-itionen, kann man mit Hotstrings und diesem Notensymbol arbeiten.
- Dead-keys fügen ebenfalls sofort ihre entsprechenden Symbole in den Text und sind damit nicht dead. Auch hier lässt sich mit Hotstrings das gewünschte Verhalten implementieren.
- Außerdem wird keinerlei Syntaxcheck beim Laden der Textdateien durchgeführt. Diese müssen also korrekt sein, sonst passiert sonstwas.

## KeyBuddy2 konfigurieren

Über die diversen Textdateien bietet KeyBuddy2 viele Konfigurationsmöglichkeiten. Zu ihrer bearbeitung empfiehlt sich Notepad++ mit unifont als Schriftart, sowie ein Hex-Editor. Alle Textdateien müssen mit einem Zeilenumbruch enden.

### Hotstrings

In hotstrings.txt werden die Hotstrings definiert, die KeyBuddy2 erkennen soll. Diese Datei muss im Format UCS-2 Little Endian vorliegen (In Notepad++ unter Kodierung einstellbar). Die Datei muss mit einem Zeilenumbruch enden.
Ein Hotstring lässt sich wie folgt definieren:

    h="hs" s="Hotstring"

Sobald man nun hs eingibt, wird zweimal die Löschtaste und anschließend das wort "Hotstring" gesendet. Die verschiedenen Hotstrings müssen durch Zeilenumbrüche getrennt sein. Statt des Sendens einer Zeichenkette kann auch ein beliebiges Programm gestartet werden. Beispiel:

    h="calc" l="calc.exe"

Tippt man calc, wird es wieder gelöscht und der Taschenrechner gestartet. Der Arbeitsordner des Programms und weitere Kommandozeilenparameter lassen sich wie folgt definieren:

    h="wineula" l="c:/windows/system32|notepad.exe|eula.txt"

Es lassen sich auch Filter definieren:

    t="Notepad++"

Der Hotstring feuert nur, wenn im Titel des Fensters, das den Fokus hat, die Zeichenkette "Notepad++" zu finden ist.

    c="Scintilla"

Dieser Hotstring feuert nur, wenn die Klasse des Objekts, das den Fokus hat, den Namen "Scintilla" trägt.
Die Reihenfolge, in der die Parameter eines Hotstrings aufgelistet werden, ist beliebig. Hauptsache ist, dass sie durch ein Leerzeichen getrennt sind und in der gleichen Zeile stehen. Zeilenumbrüche innerhalb der Anführungszeichen sind erlaubt und werden als zur Zeichenkette gehörend interpretiert. Das Maskierungszeichen ist \. Das bedeutet, dass Anführungszeichen innerhalb einer Zeichenkette durch \" und Backslashes selbst durch \\ realisiert werden können. Spezielle Tastendrücke, die sich nicht durch Unicode darstellen lassen, sowie Tastenkombinationen, können wie im nächsten Kapitel dargestellt codiert werden.

### neo-Remapping

Die Datei neomap.txt (ANSI) dient dazu, den Virtual-Key Code der gedrückten Taste auf den der entsprechenden neo-Taste zu ändern. Der Key-Code der gedrückten Taste entspricht hierbei der Zeilennummer (beginnend bei 1) und der ANSI-Code des Zeichens in einer Zeile entspricht dem neo-Key-Code. In Zeile 68 sollte also ein A stehen, da die reale D-Taste (vk=68) der neo-A-Taste (vk=65) entspricht. Leere Zeilen bedeuten, dass hier kein Mapping stattfinden soll.
Folgende Tasten lassen sich umdefinieren: A..Z, 0..9, Punkt, Komma, Bindestrich, Zirkumflex (^), Akut (´), Plus, Tab und die Leertaste.

### Allgemeines Layout

Das allgemeine Layout lässt sich in sendmap.txt (UCS-2 Little Endian) editieren. Die Zeilennummer eines Zeichens beschreibt den neo-Key-Code der Taste, die für dieses Zeichen gedrückt werden soll. Die Spalte eines Zeichens in seiner Zeile beschreibt die Ebene, die aktiv sein muss, damit das Zeichen gesendet wird. Pro Zeile müssen also sieben Zeichen definiert sein, Spalte sieben ist für die Pseudo-Ebene.
In der Basic Multilingual Plane des Unicode (U+0000 bis U+FFFF) gibt es die so genannte Private Use Area (U+E000 bis U+F8FF), die für selbstdefinierte Zeichen nutzbar ist. In KeyBuddy2 wird sie dazu verwendet, spezielle Tastenkombinationen zu senden. Normalerweise nutzt KeyBuddy2 die SendInput-Funktion der Windows API mit dem Flag KEYEVENTF_UNICODE, um Unicode-Zeichen an Programme zu senden. Damit lassen sich jedoch nicht alle Tasten simulieren (Cursor-Tasten, F1 bis F12, ...). Liegt das erste Byte eines zu sendenden Zeichens zwischen 0xE0 und 0xF7, wird kein Unicode-Zeichen gesendet, sondern ein Tastendruck simuliert (ebenfalls über SendInput). Hierbei beschreibt das zweite Byte den Virtual-Key Code der zu simulierenden Taste. Das erste Byte erlaubt noch weitere Konfigurationsmöglichkeiten, die in der folgenden Tabelle dargestellt werden.

Unicode | Shift | Strg | Alt | runter | hoch | echte Taste wird runtergedrückt | echte Taste wird losgelassen
--- | --- | --- | --- | --- | --- | --- | ---
U+E0xx |  |  |  | X |  | xx↓ |
U+E1xx | X |  |  | X |  | Shift↓ xx↓ |
U+E2xx |  | X |  | X |  | Strg↓ xx↓ |
U+E3xx | X | X |  | X |  | Strg↓ Shift↓ xx↓ |
U+E4xx |  |  | X | X |  | Alt↓ xx↓ |
U+E5xx | X |  | X | X |  | Shift↓ Alt↓ xx↓ |
U+E6xx |  | X | X | X |  | Strg↓ Alt↓ xx↓ |
U+E7xx | X | X | X | X |  | Strg↓ Shift↓ Alt↓ xx↓ |
U+E8xx |  |  |  |  | X | xx↑ |
U+E9xx | X |  |  |  | X | xx↑ Shift↑ |
U+EAxx |  | X |  |  | X | xx↑ Strg↑ |
U+EBxx | X | X |  |  | X | xx↑ Strg↑ Shift↑ |
U+ECxx |  |  | X |  | X | xx↑ Alt↑ |
U+EDxx | X |  | X |  | X | xx↑ Shift↑ Alt↑ |
U+EExx |  | X | X |  | X | xx↑ Strg↑ Alt↑ |
U+EFxx | X | X | X |  | X | xx↑ Strg↑ Shift↑ Alt↑ |
U+F0xx |  |  |  | X | X | xx↓ | xx↑
U+F1xx | X |  |  | X | X | Shift↓ xx↓ | xx↑ Shift↑
U+F2xx |  | X |  | X | X | Strg↓ xx↓ | xx↑ Strg↑
U+F3xx | X | X |  | X | X | Strg↓ Shift↓ xx↓ | xx↑ Strg↑ Shift↑
U+F4xx |  |  | X | X | X | Alt↓ xx↓ | xx↑ Alt↑
U+F5xx | X |  | X | X | X | Shift↓ Alt↓ xx↓ | xx↑ Shift↑ Alt↑
U+F6xx |  | X | X | X | X | Strg↓ Alt↓ xx↓ | xx↑ Strg↑ Alt↑
U+F7xx | X | X | X | X | X | Strg↓ Shift↓ Alt↓ xx↓ | xx↑ Strg↑ Shift↑ Alt↑

Über U+F8xx lassen sich die Tasten mit Umschaltern belegen:
U+F800 = KeyBuddy2 schließen
U+F801 = KeyBuddy2 aktivieren/deaktivieren
U+F802 = neo-Layout/qwertz-Layout
U+F803 = Kyrillisch an/aus
U+F804 = Capslock an/aus (geht auch über LShift+RShift)
U+F805 = Ebene 4 lock/unlock (geht auch über <+AltGr)
U+F806 = Maussteuerung an/aus
U+F807 = GUI öffnen/schließen (geht auch über Linksklick auf Tray-Icon)
Die Datei symbolmap.txt ist genauso aufgebaut wie sendmap.txt, allerdings enthält sie nicht die Zeichen, die gesendet werden sollen sondern was auf der Tastatur in der GUI abgebildet wird.
Das Editieren dieser Spezialkombinationen dürfte sich in einem Texteditor als schwierig erweisen, weswegen ein Hex-Editor empfohlen wird. Hierbei muss beachtet werden, dass U+ABCD im Little-Endian-Format als CDAB erscheint.

### Kyrillisches Layout

Das Layout für kyrillische Buchstaben ist in rumap.txt (UCS-2 Little Endian) definiert. Hierbei wird der Unicode des sonst zu sendenden Zeichens (wieder definiert durch Zeilennummer, muss zwischen 1 und 255 liegen) auf ein kyrillisches Symbol abgebildet. Es lässt sich (genau) ein Dead-Key (standardmäßig J) definieren. In seiner Zeile muss ein Kreuz (Unicode 0x2020) stehen. Definiert man in einer Zeile zwei kyrillische Symbole, lässt sich das zweite via Dead-Key erreichen.

### Maussteuerung

Die Maussteuerung ist in der Datei mousemap.txt (ANSI) definierbar. Hierbei werden die Virtual-Key Codes (nicht neo-Key-Codes!) für Mausaktionen in folgender Reihenfolge aufgelistet:
Nach links bewegen
Nach oben bewegen
Nach rechts bewegen
Nach unten bewegen
Linksklick
Rechtsklick
Mittelklick
Scrollrad hoch
Scrollrad runter

### Restliche Textdateien

Die Datei keynames.txt enthält die Namen der Tasten bei deaktiviertem Remapping, uppercase.txt enthält das Mapping von Kleinbuchstaben-Unicode auf Großbuchstaben-Unicode, was bei Capslock benutzt wird.

## Der Quellcode

KeyBuddy2 wurde mit Ultimate++ Version 4193 geschrieben und mit MinGW (finde keine Versionsnummer) kompiliert.

### Main Class

Die Programmklasse heißt KeyBuddy2 und findet sich in KeyBuddy2.h bzw. main.cpp. Beim Starten des Programms wird ihr Konstruktor aufgerufen, beim Beenden ihr Destruktor.

### ProcessKbdEvent

Dies ist die Kernfunktion des Programms, sie findet sich in main.cpp. Sie wird aufgerufen, sobald ein (echtes oder simuliertes) Tastaturereignis (Runterdrücken oder Loslassen einer Taste, wobei eine reale, gehaltene Taste ständig "Runterdrücken"-Signale sendet) passiert. Wenn sie true zurückliefert, wird das Ereignis weitergeleitet, bei false wird es blockiert. Folgendes tut sie:

- Falls das Ereignis nicht simuliert war, wird der Zustand der Taste (oben oder unten) in dem Array keyPressed gespeichert. Dieses Array ist programmweit die Referenz über den Tastaturzustand.
- Ist das dwExtraInfo-Flag des Ereignisses auf HOTSTRING gesetzt, handelt es sich um einen simulierten Tastendruck, der durch die Ausführung eines Hotstrings gesendet wird. In diesem Falle gibt es keine weitere Verarbeitung und die Funktion liefert true zurück.
- Handelt es sich bei dem Ereignis um eine Navigationstaste oder ähnliches (z.B. Cursor), wird der Hotstring-Buffer geleert. Dadurch wird verhindert, dass wenn man an einer Stelle eines Dokumentes schreibt, dann woanders hinspringt und dort weiterschreibt, zufällig ein Hotstring aus der Kombination beider Tippereien ausgelöst wird.
- Falls die Löschtaste gedrückt oder simuliert wurde, wird auch das letzte Zeichen des Hotstring-Buffers gelöscht.
- Falls das Ereignis simuliert ist, findet ab hier keine weitere Verarbeitung statt und die Funktion liefert true zurück.
- Wenn KeyBuddy2 deaktiviert ist, wird getestet, ob der aktuelle Tastendruck das Programm wieder aktivieren würde (er also U+F801 senden will). Falls ja, wird das Programm wieder aktiviert. Die Funktion liefert false.
- Wenn die Maussteuerung aktiv ist und ihr Deaktivierungs-Tastendruck registriert wird, wird sie deaktiviert. Die Funktion liefert false.
- Falls man sich zur Zeit in keiner neo-Ebene befindet (weil LStrg, LAlt oder LWin o.ä. gedrückt ist, oder weil KeyBuddy2 inaktiv ist), gibt es keine weitere Verarbeitung und die Funktion liefert true.
- Falls LShift und RShift gedrückt sind, wird Capslock aktiviert oder deaktiviert.
- Falls < und AltGr gedrückt sind, wird die 4. Ebene fixiert oder gelöst.
- Falls eine der Tasten A..Z, 0..9, Punkt, Komma, Bindestrich, Zirkumflex (^), Akut (´), Plus, Tab oder Leertaste gedrückt oder losgelassen wurde, passiert folgendes:

- Ist die Maussteuerung aktiv, wird das Ereignis an sie gesendet und die ProcessKbdEvent liefert false.
- Die aktuelle neo-Ebene wird bestimmt.
- Für Ebenen 3, 4 und 7 wird grundsätzlich Remapping von Virtual-Key Code auf neo-Key Code durchgeführt. In Ebenen 1, 2 und 5 nur falls das neo-Layout aktiviert ist.
- Anhand der Key Codes und der Ebene wird das zu sendende Symbol aus der Sendmap geladen (ein zweidimensionales Array namens map, bei Programmstart aus sendmap.txt geladen)
- Falls Kyrillisch eingeschaltet ist, werden lateinische Zeichen in entsprechende kyrillische umgewandelt (wobei der kyrillische Dead-Key berücksichtigt wird). Diese Projektion wird mit dem Array namens rumap durchgeführt.
- Falls Capslock aktiv ist, werden Kleinbuchstaben in Großbuchstaben gewandelt.
- Nun wird die Funktion SendUNIKey aufgerufen, welche sich um das zu sendende Zeichen kümmert.
- Das Zeichen wird außerdem dem Hotstring-Buffer angehängt und es wird geprüft, ob eine Hotstring-Ersetzung stattfindet. Darum kümmert sich die Funktion checkHotStrings.
- ProcessKbdEvent liefert false.

- Falls < oder # gedrückt wurden, werden sie blockiert.
- Sonst liefert die Funktion true.

Zwischendrin wird noch unter diversen Umständen die GUI neu gezeichnet.

### SendUNIKey

Im Falle des Sendens eines Unicode-Zeichens wird SendInput mit dwFlags=KEYEVENTF_UNICODE aufgerufen. Im Falle einer speziellen Tastenkombination (U+E000 .. U+F8FF) wird zunächst ermittelt, ob Strg, Shift oder Alt mitgesendet werden sollen. Anschließend wird der aktuelle Tastaturzustand über GetKeyboardState ausgelesen und in keyboardStateBuffer zwischengespeichert. Danach werden virtuell alle Tasten losgelassen. Die Tastenkombination wird mit SendInput gesendet und die Tastatur wird wieder in ihren ursprünglichen Zustand versetzt.

### Der Rest

Alle weiteren Funktionen sind hoffentlich ausreichend im Quelltext dokumentiert.

## Viel Spaß!

Mirko Kunze