summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqwertfisch <qwertfisch@b9310e46-f624-0410-8ea1-cfbb3a30dc96>2012-11-19 21:25:24 +0000
committerqwertfisch <qwertfisch@b9310e46-f624-0410-8ea1-cfbb3a30dc96>2012-11-19 21:25:24 +0000
commit4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d (patch)
tree6f6ea79393d093d6fb1627bc6279f2dfae20b155
parent2d7fc76824f63c6e72193e0a4c48ce55cbb53aee (diff)
downloadneo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.tar.gz
neo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.tar.bz2
neo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.zip
KeyBuddy2: ein neuer Ansatz eines Layouttools, ähnlich zu NeoVars, aber in C++ geschrieben
git-svn-id: https://svn.neo-layout.org@2431 b9310e46-f624-0410-8ea1-cfbb3a30dc96
-rw-r--r--windows/keybuddy2/KeyBuddy2.exebin0 -> 2941440 bytes
-rw-r--r--windows/keybuddy2/doku.html153
-rw-r--r--windows/keybuddy2/hotstrings.txtbin0 -> 624 bytes
-rw-r--r--windows/keybuddy2/keynames.txtbin0 -> 1490 bytes
-rw-r--r--windows/keybuddy2/license.txt23
-rw-r--r--windows/keybuddy2/mousemap.txt1
-rw-r--r--windows/keybuddy2/neomap.txt255
-rw-r--r--windows/keybuddy2/rumap.txtbin0 -> 1166 bytes
-rw-r--r--windows/keybuddy2/sendmap.txtbin0 -> 4592 bytes
-rw-r--r--windows/keybuddy2/src/KeyBuddy2.h83
-rw-r--r--windows/keybuddy2/src/KeyBuddy2.lay66
-rw-r--r--windows/keybuddy2/src/KeyBuddy2.upp29
-rw-r--r--windows/keybuddy2/src/KeyBuddy2_debug.lay67
-rw-r--r--windows/keybuddy2/src/hookfuncs.cpp60
-rw-r--r--windows/keybuddy2/src/hookfuncs.h10
-rw-r--r--windows/keybuddy2/src/hotstrings.cpp268
-rw-r--r--windows/keybuddy2/src/hotstrings.h53
-rw-r--r--windows/keybuddy2/src/icon.icobin0 -> 894 bytes
-rw-r--r--windows/keybuddy2/src/icon.rc1
-rw-r--r--windows/keybuddy2/src/includes.h45
-rw-r--r--windows/keybuddy2/src/init4
-rw-r--r--windows/keybuddy2/src/kb2images.iml136
-rw-r--r--windows/keybuddy2/src/keyButton.h25
-rw-r--r--windows/keybuddy2/src/keybuttons.inc121
-rw-r--r--windows/keybuddy2/src/keydefines.inc58
-rw-r--r--windows/keybuddy2/src/logger.cpp57
-rw-r--r--windows/keybuddy2/src/logger.h30
-rw-r--r--windows/keybuddy2/src/main.cpp819
-rw-r--r--windows/keybuddy2/src/mousecontrol.cpp107
-rw-r--r--windows/keybuddy2/src/mousecontrol.h24
-rw-r--r--windows/keybuddy2/src/mousedefines.inc9
-rw-r--r--windows/keybuddy2/symbolmap.txtbin0 -> 4592 bytes
-rw-r--r--windows/keybuddy2/uppercase.txtbin0 -> 2670 bytes
33 files changed, 2504 insertions, 0 deletions
diff --git a/windows/keybuddy2/KeyBuddy2.exe b/windows/keybuddy2/KeyBuddy2.exe
new file mode 100644
index 0000000..52d150d
--- /dev/null
+++ b/windows/keybuddy2/KeyBuddy2.exe
Binary files differ
diff --git a/windows/keybuddy2/doku.html b/windows/keybuddy2/doku.html
new file mode 100644
index 0000000..ba81baf
--- /dev/null
+++ b/windows/keybuddy2/doku.html
@@ -0,0 +1,153 @@
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>KeyBuddy2 - Dokumentation</title>
+ </head>
+ <body>
+ <font face="arial">
+ <h1>KeyBuddy2 - Dokumentation</h1>
+von Mirko Kunze mirko.kunze(&#97;)web.de<br><br>
+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.
+ <h2>KeyBuddy2 benutzen</h2>
+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<br>
+Eine Tastatur öffnet sich, die Anzeigt, was passiert, wenn man eine Taste drückt. Im Groben verhält sich die Tastatur wie hier <a href="http://www.neo-layout.org/">www.neo-layout.org</a> beschrieben. Es gibt jedoch folgende Erweiterungen:
+ <ul>
+ <li>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.
+ <li>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 <b>n</b>eo).</li>
+ <li>Man kann auf kyrillische Buchstaben umschalten, standardmäßig Mod4+Shift+K (für <b>k</b>yrillisch).</li>
+ <li>Das Programm lässt sich deaktivieren über Mod4+Shift+L (für <b>L</b>ayers). Der Mechanismus für die Tastaturüberwachung ist jedoch weiterhin aktiv und wartet auf erneute Eingabe dieser Tastenkombination zum reaktivieren.
+ <li>Über Mod4+Shift+Ö (für <b>ö</b>ffnen) lässt sich die Tastatur anzeigen und verstecken (geht auch durch Linksklicks auf das Tray-Icon).</li>
+ <li>Mit Mod4+Shift+M (für <b>M</b>aus) kann man die Maussteuerung aktivieren und deaktivieren.</li>
+ <li>Komplett schließen lässt sich das Programm entweder via Mod4+Shift+Z (für <b>z</b>u) oder über Rechtsklick auf das Tray-Icon -> Exit.</li>
+ <li>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.</li>
+ <li>Damit alle Symbole auf den Tasten dargestellt werden können, wird empfohlen, die hässliche aber vollständige Schriftart Unifont als ttf herunterzuladen (<a href="http://unifoundry.com/unifont.html">http://unifoundry.com/unifont.html</a>) und zu installieren.</li>
+ </ul>
+Folgende Aspekte von neo wurden nicht umgesetzt:
+ <ul>
+ <li>Das Numpad (Ich habe keins an meinem Laptop und die Hände gehören sowieso auf die Hauptebene!)</li>
+ <li>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.</li>
+ <li>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.</li>
+ <li>Außerdem wird keinerlei Syntaxcheck beim Laden der Textdateien durchgeführt. Diese müssen also korrekt sein, sonst passiert sonstwas.</li>
+ </ul>
+ <h2>KeyBuddy2 konfigurieren</h2>
+ Über die diversen Textdateien bietet KeyBuddy2 viele Konfigurationsmöglichkeiten. Zu ihrer bearbeitung empfiehlt sich <a href="http://notepad-plus-plus.org/">Notepad++</a> mit <a href="http://unifoundry.com/unifont.html">unifont</a> als Schriftart, sowie ein <a href="http://mh-nexus.de/de/hxd/">Hex-Editor</a>. Alle Textdateien müssen mit einem Zeilenumbruch enden.
+ <h3>Hotstrings</h3>
+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.<br>
+Ein Hotstring lässt sich wie folgt definieren:
+<pre>h="hs" s="Hotstring"</pre>
+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:
+<pre>h="calc" l="calc.exe"</pre>
+Tippt man calc, wird es wieder gelöscht und der Taschenrechner gestartet. Der Arbeitsordner des Programms und weitere Kommandozeilenparameter lassen sich wie folgt definieren:
+<pre>h="wineula" l="c:/windows/system32|notepad.exe|eula.txt"</pre>
+Es lassen sich auch Filter definieren:
+<pre>t="Notepad++"</pre>
+Der Hotstring feuert nur, wenn im Titel des Fensters, das den Fokus hat, die Zeichenkette "Notepad++" zu finden ist.
+<pre>c="Scintilla"</pre>
+Dieser Hotstring feuert nur, wenn die Klasse des Objekts, das den Fokus hat, den Namen "Scintilla" trägt.<br>
+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.
+ <h3>neo-Remapping</h3>
+Die Datei neomap.txt (ANSI) dient dazu, den <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx">Virtual-Key Code</a> 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.<br>
+Folgende Tasten lassen sich umdefinieren: A..Z, 0..9, Punkt, Komma, Bindestrich, Zirkumflex (^), Akut (´), Plus, Tab und die Leertaste.
+ <h3>Allgemeines Layout</h3>
+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.<br>
+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 <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310%28v=vs.85%29.aspx">SendInput</a>-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 <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx">Virtual-Key Code</a> der zu simulierenden Taste. Das erste Byte erlaubt noch weitere Konfigurationsmöglichkeiten, die in der folgenden Tabelle dargestellt werden.<br><br>
+<table border cellpadding=2>
+<tr><th>Unicode</th><th>Shift</th><th>Strg</th><th>Alt</th><th>runter</th><th>hoch</th><th>echte Taste wird runtergedrückt</th><th>echte Taste wird losgelassen</th></tr>
+<tr><td>U+E0xx</td><td> </td><td> </td><td> </td><td>X</td><td> </td><td>xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E1xx</td><td>X</td><td> </td><td> </td><td>X</td><td> </td><td>Shift&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E2xx</td><td> </td><td>X</td><td> </td><td>X</td><td> </td><td>Strg&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E3xx</td><td>X</td><td>X</td><td> </td><td>X</td><td> </td><td>Strg&downarrow; Shift&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E4xx</td><td> </td><td> </td><td>X</td><td>X</td><td> </td><td>Alt&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E5xx</td><td>X</td><td> </td><td>X</td><td>X</td><td> </td><td>Shift&downarrow; Alt&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E6xx</td><td> </td><td>X</td><td>X</td><td>X</td><td> </td><td>Strg&downarrow; Alt&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E7xx</td><td>X</td><td>X</td><td>X</td><td>X</td><td> </td><td>Strg&downarrow; Shift&downarrow; Alt&downarrow; xx&downarrow;</td><td> </td></tr>
+<tr><td>U+E8xx</td><td> </td><td> </td><td> </td><td> </td><td>X</td><td>xx&uparrow;</td><td> </td></tr>
+<tr><td>U+E9xx</td><td>X</td><td> </td><td> </td><td> </td><td>X</td><td>xx&uparrow; Shift&uparrow; </td><td> </td></tr>
+<tr><td>U+EAxx</td><td> </td><td>X</td><td> </td><td> </td><td>X</td><td>xx&uparrow; Strg&uparrow; </td><td> </td></tr>
+<tr><td>U+EBxx</td><td>X</td><td>X</td><td> </td><td> </td><td>X</td><td>xx&uparrow; Strg&uparrow; Shift&uparrow; </td><td> </td></tr>
+<tr><td>U+ECxx</td><td> </td><td> </td><td>X</td><td> </td><td>X</td><td>xx&uparrow; Alt&uparrow; </td><td> </td></tr>
+<tr><td>U+EDxx</td><td>X</td><td> </td><td>X</td><td> </td><td>X</td><td>xx&uparrow; Shift&uparrow; Alt&uparrow; </td><td> </td></tr>
+<tr><td>U+EExx</td><td> </td><td>X</td><td>X</td><td> </td><td>X</td><td>xx&uparrow; Strg&uparrow; Alt&uparrow;</td><td> </td></tr>
+<tr><td>U+EFxx</td><td>X</td><td>X</td><td>X</td><td> </td><td>X</td><td>xx&uparrow; Strg&uparrow; Shift&uparrow; Alt&uparrow;</td><td> </td></tr>
+<tr><td>U+F0xx</td><td> </td><td> </td><td> </td><td>X</td><td>X</td><td>xx&downarrow;</td><td>xx&uparrow;</td></tr>
+<tr><td>U+F1xx</td><td>X</td><td> </td><td> </td><td>X</td><td>X</td><td>Shift&downarrow; xx&downarrow;</td><td>xx&uparrow; Shift&uparrow; </td></tr>
+<tr><td>U+F2xx</td><td> </td><td>X</td><td> </td><td>X</td><td>X</td><td>Strg&downarrow; xx&downarrow;</td><td>xx&uparrow; Strg&uparrow; </td></tr>
+<tr><td>U+F3xx</td><td>X</td><td>X</td><td> </td><td>X</td><td>X</td><td>Strg&downarrow; Shift&downarrow; xx&downarrow;</td><td>xx&uparrow; Strg&uparrow; Shift&uparrow; </td></tr>
+<tr><td>U+F4xx</td><td> </td><td> </td><td>X</td><td>X</td><td>X</td><td>Alt&downarrow; xx&downarrow;</td><td>xx&uparrow; Alt&uparrow;</td></tr>
+<tr><td>U+F5xx</td><td>X</td><td> </td><td>X</td><td>X</td><td>X</td><td>Shift&downarrow; Alt&downarrow; xx&downarrow;</td><td>xx&uparrow; Shift&uparrow; Alt&uparrow;</td></tr>
+<tr><td>U+F6xx</td><td> </td><td>X</td><td>X</td><td>X</td><td>X</td><td>Strg&downarrow; Alt&downarrow; xx&downarrow;</td><td>xx&uparrow; Strg&uparrow; Alt&uparrow;</td></tr>
+<tr><td>U+F7xx</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>Strg&downarrow; Shift&downarrow; Alt&downarrow; xx&downarrow;</td><td>xx&uparrow; Strg&uparrow; Shift&uparrow; Alt&uparrow;</td></tr>
+</table><br>
+
+Ãœber U+F8xx lassen sich die Tasten mit Umschaltern belegen:<br><br>
+U+F800 = KeyBuddy2 schließen<br>
+U+F801 = KeyBuddy2 aktivieren/deaktivieren<br>
+U+F802 = neo-Layout/qwertz-Layout<br>
+U+F803 = Kyrillisch an/aus<br>
+U+F804 = Capslock an/aus (geht auch über LShift+RShift)<br>
+U+F805 = Ebene 4 lock/unlock (geht auch über &lt;+AltGr)<br>
+U+F806 = Maussteuerung an/aus<br>
+U+F807 = GUI öffnen/schließen (geht auch über Linksklick auf Tray-Icon)<br>
+<br>
+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.<br><br>
+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.
+
+ <h3>Kyrillisches Layout</h3>
+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.
+
+<h3>Maussteuerung</h3>
+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:<br>
+<br>
+Nach links bewegen<br>
+Nach oben bewegen<br>
+Nach rechts bewegen<br>
+Nach unten bewegen<br>
+Linksklick<br>
+Rechtsklick<br>
+Mittelklick<br>
+Scrollrad hoch<br>
+Scrollrad runter<br>
+<h3>Restliche Textdateien</h3>
+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.
+<h2>Der Quellcode</h2>
+KeyBuddy2 wurde mit <a href="http://www.ultimatepp.org/">Ultimate++</a> Version 4193 geschrieben und mit <a href="http://www.mingw.org/">MinGW</a> (finde keine Versionsnummer) kompiliert.
+<h3>Main Class</h3>
+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.
+<h3>ProcessKbdEvent</h3>
+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:
+<ul>
+<li>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.</li>
+<li>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.</li>
+<li>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.</li>
+<li>Falls die Löschtaste gedrückt oder simuliert wurde, wird auch das letzte Zeichen des Hotstring-Buffers gelöscht.</li>
+<li>Falls das Ereignis simuliert ist, findet ab hier keine weitere Verarbeitung statt und die Funktion liefert true zurück.</li>
+<li>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.</li>
+<li>Wenn die Maussteuerung aktiv ist und ihr Deaktivierungs-Tastendruck registriert wird, wird sie deaktiviert. Die Funktion liefert false.</li>
+<li>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.</li>
+<li>Falls LShift und RShift gedrückt sind, wird Capslock aktiviert oder deaktiviert.</li>
+<li>Falls &lt; und AltGr gedrückt sind, wird die 4. Ebene fixiert oder gelöst.</li>
+<li>Falls eine der Tasten A..Z, 0..9, Punkt, Komma, Bindestrich, Zirkumflex (^), Akut (´), Plus, Tab oder Leertaste gedrückt oder losgelassen wurde, passiert folgendes:</li>
+<ul>
+<li>Ist die Maussteuerung aktiv, wird das Ereignis an sie gesendet und die ProcessKbdEvent liefert false.</li>
+<li>Die aktuelle neo-Ebene wird bestimmt.</li>
+<li>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.</li>
+<li>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)</li>
+<li>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.</li>
+<li>Falls Capslock aktiv ist, werden Kleinbuchstaben in Großbuchstaben gewandelt.</li>
+<li>Nun wird die Funktion SendUNIKey aufgerufen, welche sich um das zu sendende Zeichen kümmert.</li>
+<li>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.</li>
+<li>ProcessKbdEvent liefert false.</li>
+</ul>
+<li>Falls &lt; oder &#35; gedrückt wurden, werden sie blockiert.</li>
+<li>Sonst liefert die Funktion true.</li>
+</ul>
+Zwischendrin wird noch unter diversen Umständen die GUI neu gezeichnet.
+<h3>SendUNIKey</h3>
+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.
+<h3>Der Rest</h3>
+Alle weiteren Funktionen sind hoffentlich ausreichend im Quelltext dokumentiert.
+<h2>Viel Spaß!</h2>
+Mirko Kunze
+ </font>
+ </body>
+</html>
diff --git a/windows/keybuddy2/hotstrings.txt b/windows/keybuddy2/hotstrings.txt
new file mode 100644
index 0000000..ed164a3
--- /dev/null
+++ b/windows/keybuddy2/hotstrings.txt
Binary files differ
diff --git a/windows/keybuddy2/keynames.txt b/windows/keybuddy2/keynames.txt
new file mode 100644
index 0000000..4deed68
--- /dev/null
+++ b/windows/keybuddy2/keynames.txt
Binary files differ
diff --git a/windows/keybuddy2/license.txt b/windows/keybuddy2/license.txt
new file mode 100644
index 0000000..82e2150
--- /dev/null
+++ b/windows/keybuddy2/license.txt
@@ -0,0 +1,23 @@
+KeyBuddy2 - License
+Copyright © 2012 by Mirko Kunze <mirko.kunze(a)web.de>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE. \ No newline at end of file
diff --git a/windows/keybuddy2/mousemap.txt b/windows/keybuddy2/mousemap.txt
new file mode 100644
index 0000000..5880ee7
--- /dev/null
+++ b/windows/keybuddy2/mousemap.txt
@@ -0,0 +1 @@
+SEFDJLKUM \ No newline at end of file
diff --git a/windows/keybuddy2/neomap.txt b/windows/keybuddy2/neomap.txt
new file mode 100644
index 0000000..761d156
--- /dev/null
+++ b/windows/keybuddy2/neomap.txt
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+
+
+
+
+
+
+U
+Z
+A
+L
+E
+O
+S
+G
+N
+R
+T
+M
+B
+F
+Q
+X
+C
+I
+W
+H
+P
+V
+K
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+J
+
+D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/windows/keybuddy2/rumap.txt b/windows/keybuddy2/rumap.txt
new file mode 100644
index 0000000..72d5a7b
--- /dev/null
+++ b/windows/keybuddy2/rumap.txt
Binary files differ
diff --git a/windows/keybuddy2/sendmap.txt b/windows/keybuddy2/sendmap.txt
new file mode 100644
index 0000000..ac5bad4
--- /dev/null
+++ b/windows/keybuddy2/sendmap.txt
Binary files differ
diff --git a/windows/keybuddy2/src/KeyBuddy2.h b/windows/keybuddy2/src/KeyBuddy2.h
new file mode 100644
index 0000000..0acec8f
--- /dev/null
+++ b/windows/keybuddy2/src/KeyBuddy2.h
@@ -0,0 +1,83 @@
+#ifndef _KeyBuddy2_KeyBuddy2_h
+#define _KeyBuddy2_KeyBuddy2_h
+
+#include "includes.h"
+
+// main class of the program
+class KeyBuddy2 : public WithKeyBuddy2Layout<TopWindow> {
+public:
+
+ typedef KeyBuddy2 CLASSNAME;
+ KeyBuddy2(); // init stuff
+ ~KeyBuddy2(); // clean up stuff
+
+ Button::Style buttonStyle[7]; // standard/pushed/index finger/middle finger/ring finger/small finger
+ Font buttonFont;
+ Font smallButtonFont;
+ Font buttonFontU;
+
+ TrayIcon trayicon;
+ void trayclick(){Show(!IsShown());}
+ void traymenu(Bar& bar){bar.Add(t_("Exit"), THISBACK(closeProgram));}
+ void closeProgram(){Break();}
+
+ static KeyBuddy2* pKB2; // pointer to the main class instance
+ static LineEdit* pdisplay; // pointer to the display
+ static keyButton* pKeyButton[256]; // pointers to gui key buttons
+ static BYTE keyFinger[256]; // which finger is associated to this key (=style index)
+
+ static bool neoLevelsActive; // whether the additional layers of neo are active
+ static bool neoRemapActive; // false=qwertz layout, true=neo layout
+ static bool cyrillicActive; // if roman letters are translated into cyrillic
+ static bool capslockActive; // if capital letters shall be sent
+ static bool lockLayer4Active; // if neo layer 4 is locked
+ static bool mouseControlActive; // if mouse control via keyboard is active
+ static bool dummySwitch; // that is switched by badly assigned switch pointers to prevent memory access violation
+ static bool keyPressed[256]; // key state
+ static wchar lastDeadKey; // buffer that stores which dead key was pressed
+ static wchar ruDeadChar[2]; // the dead characters for the russian keyboard (small and capital)
+ static wchar map[256][7]; // character to send = map[vkCode][mod]
+ static wchar symbolMap[256][7]; // character to draw on keyboard = map[vkCode][mod]
+ static BYTE neoRemap[256]; // vkNeoKey = neoRemap[vkQWERTZKey]
+ static wchar rumap[256][2]; // cyrillic character = rumap[ansi of latin character][ruDeadKey toggled]
+ static bool* pSwitch[256]; // pointer to the switches
+ static WString keyNames[256]; // names of unmodified keys
+ static wchar upperCaseMap[1023][2]; // mapping lowercase unicode characters to uppercase
+
+ // this function gets called by the hook callback procedure:
+ static bool ProcessKbdEvent( // return true: pass event, return false: block event
+ WPARAM upDownInfo, //WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN or WM_SYSKEYUP
+ DWORD vkCode, // virtual keycode
+ DWORD scanCode, // scancode
+ bool isExtended, // no clue
+ bool isInjected, // if it is a simulated keystroke
+ bool isAltDown, // if alt is down
+ bool isReleased, // if key was not pushed down but released
+ ULONG_PTR dwExtraInfo);
+
+ static WString buttonLabel(DWORD vkCode); // which char appears on the button with this keycode?
+
+ static int getNeoMod(); // which mod key combination is pressed?
+
+ static void SendUNIKey(wchar key, bool release, ULONG_PTR extraInfo=0); // send one virtual unicode key
+ // if the first byte of 'key' is 0xF8, then the other byte
+ // is interpreted as virtual keycode, not unicode character
+ // F8 was chosen because it lies at the end of the "Private Use Area" of unicode
+
+ static void releaseAllKeys(); // release all keys
+
+ static void loadMaps(); // loads the maps
+ // QWERTZ keycode -> neo keycode (neomap.txt, ANSI)
+ // keycode -> character (charmap.txt, UCS-2 little endian)
+ // latin character -> russian character (rumap.txt, UCS-2 little endian)
+ // keycode -> keyname on unmodified keyboard
+
+ void initKeyButtons();
+ void drawKeyButtons();
+
+ static wchar upperCase(wchar letter); // uppercase of unicode letter (for capslock)
+};
+
+#endif
+
+
diff --git a/windows/keybuddy2/src/KeyBuddy2.lay b/windows/keybuddy2/src/KeyBuddy2.lay
new file mode 100644
index 0000000..958a283
--- /dev/null
+++ b/windows/keybuddy2/src/KeyBuddy2.lay
@@ -0,0 +1,66 @@
+LAYOUT(KeyBuddy2Layout, 664, 224)
+ ITEM(keyButton, but_invis, SetFont(StdFontZ(24)).LeftPosZ(668, 48).TopPosZ(180, 40))
+ ITEM(keyButton, but_rctrl, SetFont(StdFontZ(24)).LeftPosZ(612, 48).TopPosZ(180, 40))
+ ITEM(keyButton, but_contmenu, SetFont(StdFontZ(24)).LeftPosZ(560, 48).TopPosZ(180, 40))
+ ITEM(keyButton, but_rwin, SetFont(StdFontZ(24)).LeftPosZ(504, 52).TopPosZ(180, 40))
+ ITEM(keyButton, but_altgr, SetFont(StdFontZ(24)).LeftPosZ(448, 52).TopPosZ(180, 40))
+ ITEM(keyButton, but_space, SetFont(StdFontZ(24)).LeftPosZ(176, 268).TopPosZ(180, 40))
+ ITEM(keyButton, but_lalt, SetFont(StdFontZ(24)).LeftPosZ(120, 52).TopPosZ(180, 40))
+ ITEM(keyButton, but_lwin, SetFont(StdFontZ(24)).LeftPosZ(64, 52).TopPosZ(180, 40))
+ ITEM(keyButton, but_lctrl, SetFont(StdFontZ(24)).LeftPosZ(4, 56).TopPosZ(180, 40))
+ ITEM(keyButton, but_rshift, SetFont(StdFontZ(24)).LeftPosZ(548, 112).TopPosZ(136, 40))
+ ITEM(keyButton, but_dash, SetFont(StdFontZ(24)).LeftPosZ(504, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_dot, SetFont(StdFontZ(24)).LeftPosZ(460, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_comma, SetFont(StdFontZ(24)).LeftPosZ(416, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_M, SetFont(StdFontZ(24)).LeftPosZ(372, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_N, SetFont(StdFontZ(24)).LeftPosZ(328, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_B, SetFont(StdFontZ(24)).LeftPosZ(284, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_V, SetFont(StdFontZ(24)).LeftPosZ(240, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_C, SetFont(StdFontZ(24)).LeftPosZ(196, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_X, SetFont(StdFontZ(24)).LeftPosZ(152, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_Y, SetFont(StdFontZ(24)).LeftPosZ(108, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_smaller, SetFont(StdFontZ(24)).LeftPosZ(64, 40).TopPosZ(136, 40))
+ ITEM(keyButton, but_lshift, SetFont(StdFontZ(24)).LeftPosZ(4, 56).TopPosZ(136, 40))
+ ITEM(keyButton, but_hash, SetFont(StdFontZ(24)).LeftPosZ(572, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_AE, SetFont(StdFontZ(24)).LeftPosZ(528, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_OE, SetFont(StdFontZ(24)).LeftPosZ(484, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_L, SetFont(StdFontZ(24)).LeftPosZ(440, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_K, SetFont(StdFontZ(24)).LeftPosZ(396, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_J, SetFont(StdFontZ(24)).LeftPosZ(352, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_H, SetFont(StdFontZ(24)).LeftPosZ(308, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_G, SetFont(StdFontZ(24)).LeftPosZ(264, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_F, SetFont(StdFontZ(24)).LeftPosZ(220, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_D, SetFont(StdFontZ(24)).LeftPosZ(176, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_S, SetFont(StdFontZ(24)).LeftPosZ(132, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_A, SetFont(StdFontZ(24)).LeftPosZ(88, 40).TopPosZ(92, 40))
+ ITEM(keyButton, but_capslock, SetFont(StdFontZ(24)).LeftPosZ(4, 80).TopPosZ(92, 40))
+ ITEM(keyButton, but_enter, SetFont(StdFontZ(24)).LeftPosZ(616, 44).TopPosZ(48, 84))
+ ITEM(keyButton, but_plus, SetFont(StdFontZ(24)).LeftPosZ(556, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_UE, SetFont(StdFontZ(24)).LeftPosZ(512, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_P, SetFont(StdFontZ(24)).LeftPosZ(468, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_O, SetFont(StdFontZ(24)).LeftPosZ(424, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_I, SetFont(StdFontZ(24)).LeftPosZ(380, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_U, SetFont(StdFontZ(24)).LeftPosZ(336, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_Z, SetFont(StdFontZ(24)).LeftPosZ(292, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_T, SetFont(StdFontZ(24)).LeftPosZ(248, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_R, SetFont(StdFontZ(24)).LeftPosZ(204, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_E, SetFont(StdFontZ(24)).LeftPosZ(160, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_W, SetFont(StdFontZ(24)).LeftPosZ(116, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_Q, SetFont(StdFontZ(24)).LeftPosZ(72, 40).TopPosZ(48, 40))
+ ITEM(keyButton, but_tab, SetFont(StdFontZ(24)).LeftPosZ(4, 64).TopPosZ(48, 40))
+ ITEM(keyButton, but_backspace, SetFont(StdFontZ(24)).LeftPosZ(576, 84).TopPosZ(4, 40))
+ ITEM(keyButton, but_acut, SetFont(StdFontZ(24)).LeftPosZ(532, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_sz, SetFont(StdFontZ(24)).LeftPosZ(488, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_0, SetFont(StdFontZ(24)).LeftPosZ(444, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_9, SetFont(StdFontZ(24)).LeftPosZ(400, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_8, SetFont(StdFontZ(24)).LeftPosZ(356, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_7, SetFont(StdFontZ(24)).LeftPosZ(312, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_6, SetFont(StdFontZ(24)).LeftPosZ(268, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_5, SetFont(StdFontZ(24)).LeftPosZ(224, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_4, SetFont(StdFontZ(24)).LeftPosZ(180, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_3, SetFont(StdFontZ(24)).LeftPosZ(136, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_2, SetFont(StdFontZ(24)).LeftPosZ(92, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_1, SetFont(StdFontZ(24)).LeftPosZ(48, 40).TopPosZ(4, 40))
+ ITEM(keyButton, but_circ, SetFont(StdFontZ(24)).LeftPosZ(4, 40).TopPosZ(4, 40))
+END_LAYOUT
+
diff --git a/windows/keybuddy2/src/KeyBuddy2.upp b/windows/keybuddy2/src/KeyBuddy2.upp
new file mode 100644
index 0000000..bc3a8ca
--- /dev/null
+++ b/windows/keybuddy2/src/KeyBuddy2.upp
@@ -0,0 +1,29 @@
+uses
+ CtrlLib;
+
+file
+ hookfuncs.cpp,
+ hookfuncs.h,
+ logger.cpp,
+ logger.h,
+ keyButton.h,
+ KeyBuddy2.h,
+ kb2images.iml,
+ hotstrings.h,
+ hotstrings.cpp,
+ icon.ico,
+ icon.rc,
+ includes.h,
+ info.txt,
+ keydefines.inc,
+ keybuttons.inc,
+ mousecontrol.cpp,
+ mousedefines.inc,
+ mousecontrol.h,
+ main.cpp,
+ KeyBuddy2_debug.lay,
+ KeyBuddy2.lay;
+
+mainconfig
+ "" = "GUI";
+
diff --git a/windows/keybuddy2/src/KeyBuddy2_debug.lay b/windows/keybuddy2/src/KeyBuddy2_debug.lay
new file mode 100644
index 0000000..0c0bf3c
--- /dev/null
+++ b/windows/keybuddy2/src/KeyBuddy2_debug.lay
@@ -0,0 +1,67 @@
+LAYOUT(KeyBuddy2Layout, 972, 520)
+ ITEM(LineEdit, display, SetFont(MonospaceZ(12)).SetEditable(false).LeftPosZ(0, 968).TopPosZ(264, 252))
+ ITEM(keyButton, but_invis, SetFont(StdFontZ(24)).LeftPosZ(828, 48).TopPosZ(200, 40))
+ ITEM(keyButton, but_rctrl, SetFont(StdFontZ(24)).LeftPosZ(772, 48).TopPosZ(200, 40))
+ ITEM(keyButton, but_contmenu, SetFont(StdFontZ(24)).LeftPosZ(720, 48).TopPosZ(200, 40))
+ ITEM(keyButton, but_rwin, SetFont(StdFontZ(24)).LeftPosZ(664, 52).TopPosZ(200, 40))
+ ITEM(keyButton, but_altgr, SetFont(StdFontZ(24)).LeftPosZ(608, 52).TopPosZ(200, 40))
+ ITEM(keyButton, but_space, SetFont(StdFontZ(24)).LeftPosZ(336, 268).TopPosZ(200, 40))
+ ITEM(keyButton, but_lalt, SetFont(StdFontZ(24)).LeftPosZ(280, 52).TopPosZ(200, 40))
+ ITEM(keyButton, but_lwin, SetFont(StdFontZ(24)).LeftPosZ(224, 52).TopPosZ(200, 40))
+ ITEM(keyButton, but_lctrl, SetFont(StdFontZ(24)).LeftPosZ(164, 56).TopPosZ(200, 40))
+ ITEM(keyButton, but_rshift, SetFont(StdFontZ(24)).LeftPosZ(708, 112).TopPosZ(156, 40))
+ ITEM(keyButton, but_dash, SetFont(StdFontZ(24)).LeftPosZ(664, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_dot, SetFont(StdFontZ(24)).LeftPosZ(620, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_comma, SetFont(StdFontZ(24)).LeftPosZ(576, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_M, SetFont(StdFontZ(24)).LeftPosZ(532, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_N, SetFont(StdFontZ(24)).LeftPosZ(488, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_B, SetFont(StdFontZ(24)).LeftPosZ(444, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_V, SetFont(StdFontZ(24)).LeftPosZ(400, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_C, SetFont(StdFontZ(24)).LeftPosZ(356, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_X, SetFont(StdFontZ(24)).LeftPosZ(312, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_Y, SetFont(StdFontZ(24)).LeftPosZ(268, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_smaller, SetFont(StdFontZ(24)).LeftPosZ(224, 40).TopPosZ(156, 40))
+ ITEM(keyButton, but_lshift, SetFont(StdFontZ(24)).LeftPosZ(164, 56).TopPosZ(156, 40))
+ ITEM(keyButton, but_hash, SetFont(StdFontZ(24)).LeftPosZ(732, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_AE, SetFont(StdFontZ(24)).LeftPosZ(688, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_OE, SetFont(StdFontZ(24)).LeftPosZ(644, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_L, SetFont(StdFontZ(24)).LeftPosZ(600, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_K, SetFont(StdFontZ(24)).LeftPosZ(556, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_J, SetFont(StdFontZ(24)).LeftPosZ(512, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_H, SetFont(StdFontZ(24)).LeftPosZ(468, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_G, SetFont(StdFontZ(24)).LeftPosZ(424, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_F, SetFont(StdFontZ(24)).LeftPosZ(380, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_D, SetFont(StdFontZ(24)).LeftPosZ(336, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_S, SetFont(StdFontZ(24)).LeftPosZ(292, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_A, SetFont(StdFontZ(24)).LeftPosZ(248, 40).TopPosZ(112, 40))
+ ITEM(keyButton, but_capslock, SetFont(StdFontZ(24)).LeftPosZ(164, 80).TopPosZ(112, 40))
+ ITEM(keyButton, but_enter, SetFont(StdFontZ(24)).LeftPosZ(776, 44).TopPosZ(68, 84))
+ ITEM(keyButton, but_plus, SetFont(StdFontZ(24)).LeftPosZ(716, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_UE, SetFont(StdFontZ(24)).LeftPosZ(672, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_P, SetFont(StdFontZ(24)).LeftPosZ(628, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_O, SetFont(StdFontZ(24)).LeftPosZ(584, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_I, SetFont(StdFontZ(24)).LeftPosZ(540, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_U, SetFont(StdFontZ(24)).LeftPosZ(496, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_Z, SetFont(StdFontZ(24)).LeftPosZ(452, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_T, SetFont(StdFontZ(24)).LeftPosZ(408, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_R, SetFont(StdFontZ(24)).LeftPosZ(364, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_E, SetFont(StdFontZ(24)).LeftPosZ(320, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_W, SetFont(StdFontZ(24)).LeftPosZ(276, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_Q, SetFont(StdFontZ(24)).LeftPosZ(232, 40).TopPosZ(68, 40))
+ ITEM(keyButton, but_tab, SetFont(StdFontZ(24)).LeftPosZ(164, 64).TopPosZ(68, 40))
+ ITEM(keyButton, but_backspace, SetFont(StdFontZ(24)).LeftPosZ(736, 84).TopPosZ(24, 40))
+ ITEM(keyButton, but_acut, SetFont(StdFontZ(24)).LeftPosZ(692, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_sz, SetFont(StdFontZ(24)).LeftPosZ(648, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_0, SetFont(StdFontZ(24)).LeftPosZ(604, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_9, SetFont(StdFontZ(24)).LeftPosZ(560, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_8, SetFont(StdFontZ(24)).LeftPosZ(516, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_7, SetFont(StdFontZ(24)).LeftPosZ(472, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_6, SetFont(StdFontZ(24)).LeftPosZ(428, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_5, SetFont(StdFontZ(24)).LeftPosZ(384, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_4, SetFont(StdFontZ(24)).LeftPosZ(340, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_3, SetFont(StdFontZ(24)).LeftPosZ(296, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_2, SetFont(StdFontZ(24)).LeftPosZ(252, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_1, SetFont(StdFontZ(24)).LeftPosZ(208, 40).TopPosZ(24, 40))
+ ITEM(keyButton, but_circ, SetFont(StdFontZ(24)).LeftPosZ(164, 40).TopPosZ(24, 40))
+END_LAYOUT
+
diff --git a/windows/keybuddy2/src/hookfuncs.cpp b/windows/keybuddy2/src/hookfuncs.cpp
new file mode 100644
index 0000000..26686a4
--- /dev/null
+++ b/windows/keybuddy2/src/hookfuncs.cpp
@@ -0,0 +1,60 @@
+
+#include "includes.h"
+
+HHOOK hHookKB2=NULL;
+
+// install low level keyboard hook
+int SetHook()
+{
+ int err = 0;
+ hHookKB2 = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, GetModuleHandle( NULL ),0);
+ if(hHookKB2==NULL)
+ {
+ err = (int)GetLastError();
+ return err;
+ }
+ return 0;
+}
+
+// remove low level keyboard hook
+int RemoveHook()
+{
+ BOOL Hbool = 0;
+ int err = 0;
+ Hbool = UnhookWindowsHookEx(hHookKB2);
+ if(Hbool == 0)
+ {
+ err = (int)GetLastError();
+ return err;
+ }
+ return 0;
+}
+
+// this function is called by windows if a key is pressed
+LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ KBDLLHOOKSTRUCT *kbdl_struct;
+
+ if(nCode != HC_ACTION){
+ return ( CallNextHookEx(hHookKB2, nCode, wParam, lParam) );
+ }
+
+ kbdl_struct = (KBDLLHOOKSTRUCT*) lParam;
+
+ if(KeyBuddy2::ProcessKbdEvent(
+ wParam,
+ kbdl_struct->vkCode,
+ kbdl_struct->scanCode,
+ (kbdl_struct->flags & LLKHF_EXTENDED) !=0,
+ (kbdl_struct->flags & LLKHF_INJECTED) !=0,
+ (kbdl_struct->flags & LLKHF_ALTDOWN) !=0,
+ (kbdl_struct->flags & LLKHF_UP) !=0,
+ kbdl_struct->dwExtraInfo))
+ {
+ return ( CallNextHookEx(hHookKB2, nCode, wParam, lParam) );
+ }
+ else
+ {
+ return 1;
+ }
+}
diff --git a/windows/keybuddy2/src/hookfuncs.h b/windows/keybuddy2/src/hookfuncs.h
new file mode 100644
index 0000000..8405af0
--- /dev/null
+++ b/windows/keybuddy2/src/hookfuncs.h
@@ -0,0 +1,10 @@
+#ifndef _KeyBuddy2_hookfuncs_h_
+#define _KeyBuddy2_hookfuncs_h_
+
+#include "includes.h"
+
+int SetHook();
+int RemoveHook();
+LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
+
+#endif
diff --git a/windows/keybuddy2/src/hotstrings.cpp b/windows/keybuddy2/src/hotstrings.cpp
new file mode 100644
index 0000000..2c5a397
--- /dev/null
+++ b/windows/keybuddy2/src/hotstrings.cpp
@@ -0,0 +1,268 @@
+#include "includes.h"
+
+hotString* hotString::pHotStrings=NULL;
+int hotString::numHotStrings=0;
+WString hotString::hsBuffer;
+int hotString::bufferLen=0;
+long hotString::lastFocusPtr=0;
+
+// load all hotstrings from file
+void hotString::loadHotStrings(){
+
+ // in a first pass, just rush through the file and count the number of hotstrings
+
+ FILE* pFile;
+ int i;
+ char buffer;
+ wchar unibuffer;
+
+ #define FGETUC(pbuf,pfile) fread(pbuf,sizeof(wchar),1,pfile)
+
+ numHotStrings=0;
+ bool valueEnd;
+
+ pFile = fopen(SRCPATH "hotstrings.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read hotstrings.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ while(!feof(pFile)){
+ FGETUC(&unibuffer,pFile); // read identifier
+ if( unibuffer>=97 && unibuffer<=122 ){
+
+ FGETUC(&unibuffer,pFile); // read =
+ FGETUC(&unibuffer,pFile); // read "
+
+ valueEnd=false;
+ while(!valueEnd){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==34){valueEnd=true;} // read " -> end of value
+ if(unibuffer==92){FGETUC(&unibuffer,pFile);} // read \ -> skip next character
+ }
+ FGETUC(&unibuffer,pFile); // read separator
+ if(unibuffer==13){ // line break -> entry complete
+ numHotStrings++;
+ FGETUC(&unibuffer,pFile); // read chr10
+ }
+ }
+ }
+
+ // now allocate as much memory as needed
+ pHotStrings = new hotString[numHotStrings];
+
+ // now go through in a second pass and store hotstrings
+ int iEntry=0;
+
+ rewind(pFile);
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ WString* pTarget=NULL;
+ fpos_t valueStart;
+ int valueLength;
+ bool isH;
+
+ while(!feof(pFile)){
+ FGETUC(&unibuffer,pFile); // read identifier
+ if(feof(pFile)){break;} // sometimes the first feof didnt indicate the end, so check again after read operatio
+
+ isH=false;
+
+ switch(unibuffer){
+ case 'h':
+ case 'H':
+ pTarget=&(hotString::pHotStrings[iEntry].hs);
+ isH=true;
+ break;
+ case 'c':
+ case 'C':
+ pTarget=&(hotString::pHotStrings[iEntry].winClass);
+ break;
+ case 't':
+ case 'T':
+ pTarget=&(hotString::pHotStrings[iEntry].winTitle);
+ break;
+ case 's':
+ case 'S':
+ pTarget=&(hotString::pHotStrings[iEntry].value);
+ hotString::pHotStrings[iEntry].launch=false;
+ break;
+ case 'l':
+ case 'L':
+ pTarget=&(hotString::pHotStrings[iEntry].value);
+ hotString::pHotStrings[iEntry].launch=true;
+ break;
+ default:
+ PromptOK("Error parsing hotstrings.txt: unknown element"); exit(1);
+ }
+
+ FGETUC(&unibuffer,pFile); // read =
+ FGETUC(&unibuffer,pFile); // read "
+
+ fgetpos(pFile, &valueStart);
+
+ // read value first to determine its length, then again and store
+
+ valueEnd=false;
+ valueLength=0;
+ while(!valueEnd){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==34){ // read " -> end of value
+ valueEnd=true;
+ }
+ else{
+ if(unibuffer==92){ // read \ -> dont check next character
+ FGETUC(&unibuffer,pFile);
+ valueLength++;
+ }
+ else{ // increase number of chars
+ valueLength++;
+ }
+ }
+ }
+
+ if(isH && valueLength>bufferLen){
+ bufferLen=valueLength;
+ }
+
+ *pTarget = WString(0,valueLength);
+ fsetpos(pFile, &valueStart);
+ for(i=0;i<valueLength;i++){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==92){FGETUC(&unibuffer,pFile);} // read \ -> skip to next character
+ pTarget->Set(i,unibuffer);
+ }
+
+ FGETUC(&unibuffer,pFile); // read "
+ FGETUC(&unibuffer,pFile); // read separator
+ if(unibuffer==13){ // line break -> entry complete
+ LOGG("Read hotstring: hs=");LOGG(pHotStrings[iEntry].hs);
+ LOGG(" winTitle=");LOGG(pHotStrings[iEntry].winTitle);
+ LOGG(" winClass=");LOGG(pHotStrings[iEntry].winClass);
+ LOGG(" value=");LOGG(pHotStrings[iEntry].value);LOGGNL;
+ iEntry++;
+ FGETUC(&unibuffer,pFile); // read chr10
+ }
+ }
+ fclose(pFile);
+
+ // create log buffer as long as the longest hotstring
+ hsBuffer = WString(0,bufferLen);
+
+ // sort list
+ qsort(pHotStrings,numHotStrings,sizeof(hotString),compareHotStrings);
+
+}
+
+// compare the hotstringbuffer to all hotstrings and fire if there is a match
+// to be more efficient, this could be done using a trie
+// however, c++ takes very few time to compare thousands of strings, so this was
+// not considered necessary
+void hotString::checkHotStrings(){
+ int i,k;
+ bool hit;
+
+ for(i=0;i<numHotStrings;i++){
+
+ if(pHotStrings[i].hs.IsEqual(hsBuffer.Right(pHotStrings[i].hs.GetLength()))){ // current hotstring matches typed letters
+
+ hit=false;
+
+ if(pHotStrings[i].winClass.IsEmpty() && pHotStrings[i].winTitle.IsEmpty()){ // no further conditions, send
+ hit=true;
+ }
+ else{ // check if focus object class and foreground window title match
+ WString wt,oc;
+ getFocusInfo(oc,wt);
+
+ if( (pHotStrings[i].winClass.IsEmpty() || pHotStrings[i].winClass.IsEqual(oc))
+ && (pHotStrings[i].winTitle.IsEmpty() || wt.Find(pHotStrings[i].winTitle)>-1) ){ // ok, everything matches, fire!
+
+ hit=true;
+ }
+ }
+
+ if(hit){
+
+ for(k=0;k<pHotStrings[i].hs.GetLength();k++){ // backspaces to delete the typement
+ KeyBuddy2::SendUNIKey(0xF008,false,HOTSTRING);
+ KeyBuddy2::SendUNIKey(0xF008,true,HOTSTRING);
+ }
+
+ if(!pHotStrings[i].launch){ // send string
+ for(k=0;k<pHotStrings[i].value.GetLength();k++){
+ KeyBuddy2::SendUNIKey(pHotStrings[i].value[k],false,HOTSTRING);
+ KeyBuddy2::SendUNIKey(pHotStrings[i].value[k],true,HOTSTRING);
+ }
+ break;
+ clearBuffer();
+ }
+ else{ // launch program
+ WString cmd=pHotStrings[i].value;
+
+ WString path,exe,params;
+ int delim1=-2,delim2=-2;
+
+ delim1=cmd.Find("|");
+ if(delim1==-1){
+ path="";
+ exe=cmd;
+ params="";
+ }
+ else{
+ delim2=cmd.Find("|",delim1+1);
+
+ if(delim2==-1){
+ path=cmd.Left(delim1);
+ exe=cmd.Mid(delim1+1);;
+ params="";
+ }
+ else{
+ path=cmd.Left(delim1);
+ exe=cmd.Mid(delim1+1,delim2-delim1-1);
+ params=cmd.Mid(delim2+1);
+ }
+ }
+
+ ShellExecuteW( NULL, NULL, exe, params, path, SW_SHOWNORMAL );
+
+ LOGG("working directory: ");LOGG(path);LOGGNL;
+ LOGG("exe: ");LOGG(exe);LOGGNL;
+ LOGG("params: ");LOGG(params);LOGGNL;
+ }
+ }
+ }
+ }
+}
+
+long hotString::getFocusWindowPtr(){
+
+ DWORD unused;
+
+ long myThread=GetWindowThreadProcessId(KeyBuddy2::pKB2->GetHWND(),&unused);
+ long otherThread=GetWindowThreadProcessId(GetForegroundWindow(),&unused);
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,true);
+ }
+
+ long result=(long)GetFocus();
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,false);
+ }
+
+ return result;
+}
+
+void hotString::getFocusInfo(WString& objectClass, WString& parentTitle){
+
+ char buffer[256];
+ GetClassName((HWND)getFocusWindowPtr(),buffer,255);
+ objectClass=WString(buffer);
+
+ GetWindowText(GetForegroundWindow(),buffer,255);
+ parentTitle=WString(buffer);
+}
diff --git a/windows/keybuddy2/src/hotstrings.h b/windows/keybuddy2/src/hotstrings.h
new file mode 100644
index 0000000..0ec6bf8
--- /dev/null
+++ b/windows/keybuddy2/src/hotstrings.h
@@ -0,0 +1,53 @@
+#ifndef _KeyBuddy2_hotstrings_h_
+#define _KeyBuddy2_hotstrings_h_
+
+#include "includes.h"
+
+// when certain strings are typed ("hotstrings"), they get replaced or they launch programs
+
+class hotString{
+ public:
+ WString hs; // string that activates this hotstring when typed
+ WString winTitle; // only if the window that has the focus contains this string
+ WString winClass; // only if the window that has the focus is of this class
+ WString value; // string that is to be sent / program that is to be launched
+ bool launch; // false = send the string in value, true = launch program with name value
+ //launching: "xxx|yyy|zzz" will run program yyy with parameters zzz in working directory xxx
+
+ static hotString* pHotStrings; // pointer to the array of hotstrings
+ static int numHotStrings; // number of hotstrings
+ static WString hsBuffer; // the buffer that is filled with letters while typing
+ // after each sent character, the end of the buffer is compared to all the hotstrings in the list
+ // if there is a match, the hotstring is activated
+ static int bufferLen; // number of letters in the buffer
+ static long lastFocusPtr; // the window that had the focus while the last character was typed
+ // if the window changes, the hotstring buffer is cleared
+
+ static void loadHotStrings();
+ static void clearBuffer(){hsBuffer = WString(0,bufferLen);};
+ static void appendBuffer(wchar c){ // appends one character to the buffer
+ int i;
+ for(i=0;i<bufferLen-1;i++){
+ hsBuffer.Set(i,(int)hsBuffer[i+1]);
+ }
+ hsBuffer.Set(bufferLen-1,(int)c);
+ };
+
+ // compare the length of two hotstrings and return the difference, so qsort can sort the hotstringlist by length
+ static int compareHotStrings(const void * pa, const void * pb){
+ hotString* a=(hotString*)pa;
+ hotString* b=(hotString*)pb;
+
+ return b->hs.GetLength() - a->hs.GetLength();
+ }
+ // the list needs to be sorted: if the user types "abcde" and both "cde" and "de" are hotstrings,
+ // always the longer one is to be used and will be picked when the list is checked from long to short
+
+ static void checkHotStrings(); // check if the typed characters activate a hotstring and activates it
+ static long getFocusWindowPtr(); // get the pointer to the object that has the focus
+ static void getFocusInfo(WString& objectClass, WString& parentTitle); // get classname of this object
+ // and the title of its parent window
+
+};
+
+#endif
diff --git a/windows/keybuddy2/src/icon.ico b/windows/keybuddy2/src/icon.ico
new file mode 100644
index 0000000..fcbb545
--- /dev/null
+++ b/windows/keybuddy2/src/icon.ico
Binary files differ
diff --git a/windows/keybuddy2/src/icon.rc b/windows/keybuddy2/src/icon.rc
new file mode 100644
index 0000000..77db3bb
--- /dev/null
+++ b/windows/keybuddy2/src/icon.rc
@@ -0,0 +1 @@
+9999 ICON "icon.ico"
diff --git a/windows/keybuddy2/src/includes.h b/windows/keybuddy2/src/includes.h
new file mode 100644
index 0000000..de54bc1
--- /dev/null
+++ b/windows/keybuddy2/src/includes.h
@@ -0,0 +1,45 @@
+#ifndef _KeyBuddy2_includes_h_
+#define _KeyBuddy2_includes_h_
+
+// custom #defines:
+//#define DEBUG
+
+#ifdef DEBUG
+ //#define SRCPATH "C:/Eigene Dateien/c-gefrickel/KeyBuddy2/"
+ #define SRCPATH ""
+#else
+ #define SRCPATH ""
+#endif
+
+#define HOTSTRING 0x80 // random number
+
+#include "keydefines.inc"
+#include "mousedefines.inc"
+
+// includes and functional defines
+
+#define WINVER 0x0500 // otherwise SendInput and KEYEVENTF_UNICODE are unknown
+#include <CtrlLib/CtrlLib.h>
+using namespace Upp;
+
+#include "keyButton.h"
+
+#ifdef DEBUG
+ #define LAYOUTFILE <KeyBuddy2/KeyBuddy2_debug.lay>
+#else
+ #define LAYOUTFILE <KeyBuddy2/KeyBuddy2.lay>
+#endif
+
+#include <CtrlCore/lay.h>
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hookfuncs.h" // windows api specific functions needed for keyboard hook
+#include "KeyBuddy2.h" // programm class
+#include "logger.h" // logging functions for debug
+#include "hotstrings.h" // logging and replacing for hotstrings
+#include "mousecontrol.h" // well, mouse control
+
+#endif
diff --git a/windows/keybuddy2/src/init b/windows/keybuddy2/src/init
new file mode 100644
index 0000000..acd5bbe
--- /dev/null
+++ b/windows/keybuddy2/src/init
@@ -0,0 +1,4 @@
+#ifndef _KeyBuddy2_icpp_init_stub
+#define _KeyBuddy2_icpp_init_stub
+#include "CtrlLib/init"
+#endif
diff --git a/windows/keybuddy2/src/kb2images.iml b/windows/keybuddy2/src/kb2images.iml
new file mode 100644
index 0000000..893f37c
--- /dev/null
+++ b/windows/keybuddy2/src/kb2images.iml
@@ -0,0 +1,136 @@
+PREMULTIPLIED
+IMAGE_ID(b_std)
+IMAGE_ID(b_pushed)
+IMAGE_ID(b_f2)
+IMAGE_ID(b_f3)
+IMAGE_ID(b_f4)
+IMAGE_ID(b_f5)
+IMAGE_ID(b_space)
+IMAGE_ID(tray)
+
+IMAGE_BEGIN_DATA
+IMAGE_DATA(120,156,237,217,219,78,83,89,28,6,112,146,185,225,25,184,157,11,47,36,94,248,8,222,204,149,215,6,140,33,24,18)
+IMAGE_DATA(76,26,139,149,168,80,198,34,16,24,40,39,1,109,145,30,16,132,114,232,180,28,10,109,161,165,5,74,143,208,41,202)
+IMAGE_DATA(249,124,40,81,196,97,244,13,190,89,255,197,238,4,31,160,217,59,153,69,243,165,176,187,178,246,143,181,246,186,249,154)
+IMAGE_DATA(115,35,231,70,206,47,236,245,43,123,185,221,110,236,236,236,32,157,78,227,228,228,4,135,135,135,216,223,223,199,238,238)
+IMAGE_DATA(46,191,158,237,108,111,111,99,107,107,11,235,235,235,72,165,82,8,135,195,152,153,153,129,195,225,224,159,157,157,157,241)
+IMAGE_DATA(144,141,92,153,241,155,155,155,89,207,198,198,6,119,173,174,174,34,30,143,35,16,8,96,122,122,26,99,99,99,220,115)
+IMAGE_DATA(122,122,202,61,126,191,159,95,27,31,31,199,196,196,4,38,39,39,225,114,185,48,53,53,197,199,211,26,83,60,30,15)
+IMAGE_DATA(188,94,47,255,255,102,103,103,121,124,62,31,230,230,230,248,220,148,96,48,136,249,249,121,44,44,44,96,113,113,145,39)
+IMAGE_DATA(20,10,97,105,105,9,145,72,132,39,26,141,34,22,139,113,83,34,145,224,239,52,143,211,233,132,221,110,199,209,209,17)
+IMAGE_DATA(15,185,232,154,156,54,10,125,62,58,58,138,129,129,1,28,28,28,240,103,139,92,74,176,45,47,47,99,120,120,24,22)
+IMAGE_DATA(139,5,123,123,123,252,217,82,146,109,112,112,16,6,131,129,159,21,122,38,149,100,235,235,235,67,103,103,39,183,209,89)
+IMAGE_DATA(81,146,205,106,181,162,173,173,141,159,79,165,217,232,89,107,109,109,21,54,97,19,54,97,19,54,97,19,54,97,19,54)
+IMAGE_DATA(97,19,54,97,19,54,97,147,213,102,50,153,208,220,220,252,95,47,167,36,91,119,119,55,26,27,27,177,182,182,198,123)
+IMAGE_DATA(57,37,217,90,90,90,80,83,83,131,100,50,201,199,208,189,149,96,163,185,181,90,45,42,43,43,249,88,154,147,238,77)
+IMAGE_DATA(22,57,109,52,103,93,93,29,212,106,53,52,26,13,255,59,179,102,212,23,142,140,140,240,254,139,122,38,58,47,102,179)
+IMAGE_DATA(57,171,233,233,233,129,209,104,228,231,178,170,170,10,101,101,101,80,169,84,168,168,168,224,125,116,198,69,38,234,151,168)
+IMAGE_DATA(151,235,232,232,224,227,233,188,100,51,122,189,30,13,13,13,252,249,162,189,44,47,47,231,251,217,219,219,139,156,235,133)
+IMAGE_DATA(62,251,177,178,116,178,52,177,212,178,188,146,41,53,44,245,44,45,121,121,121,246,155,55,111,6,36,151,142,69,205,82)
+IMAGE_DATA(194,82,36,83,138,89,74,89,52,146,51,179,94,228,42,100,185,203,242,155,140,161,251,23,176,168,36,95,173,180,94,116)
+IMAGE_DATA(253,150,204,185,205,114,71,242,105,164,189,46,146,220,114,219,50,190,187,210,254,42,205,118,75,178,20,43,216,86,36,108)
+IMAGE_DATA(194,38,108,194,38,108,194,38,108,194,38,108,194,38,108,194,38,108,194,38,108,194,150,37,27,245,92,197,10,180,145,137)
+IMAGE_DATA(122,76,234,147,168,87,186,173,0,215,245,142,171,37,231,170,135,163,62,238,142,204,190,159,186,193,220,220,92,139,180,175)
+IMAGE_DATA(42,233,154,156,189,234,79,157,106,126,126,126,166,143,174,145,214,175,84,218,107,249,187,232,235,133,254,228,164,23,177,88)
+IMAGE_DATA(26,201,228,15,36,18,255,32,28,190,196,194,194,223,8,4,190,193,239,191,200,122,124,190,11,120,189,95,49,53,245,5)
+IMAGE_DATA(14,199,41,62,124,216,129,197,18,135,205,54,129,104,52,141,84,234,7,15,217,200,53,59,123,53,222,237,62,207,122,166)
+IMAGE_DATA(167,207,225,114,125,129,211,121,134,161,161,3,152,205,159,208,213,21,103,9,50,207,119,172,172,124,71,48,248,153,121,83)
+IMAGE_DATA(104,111,15,227,245,235,8,58,58,40,81,105,92,2,111,222,44,227,237,219,21,150,36,12,134,191,96,52,166,120,186,187)
+IMAGE_DATA(87,241,238,221,71,150,79,48,153,214,89,54,216,252,155,108,174,45,150,109,88,173,148,29,244,246,238,226,253,251,61,150)
+IMAGE_DATA(125,244,247,31,178,28,177,53,58,198,192,192,9,207,224,224,41,123,63,230,243,181,182,46,66,175,15,178,117,187,68,36)
+IMAGE_DATA(114,41,185,150,100,181,217,108,105,254,185,94,31,64,125,189,27,161,208,213,179,213,214,22,82,132,205,102,59,67,99,163)
+IMAGE_DATA(15,213,213,78,182,151,223,48,51,243,85,81,182,250,122,250,118,117,8,115,115,23,240,120,206,21,101,171,173,117,225,249)
+IMAGE_DATA(243,126,126,134,233,172,40,201,86,93,61,134,242,114,171,66,109,78,60,125,106,17,54,97,19,54,97,19,54,97,19,54)
+IMAGE_DATA(97,19,54,97,19,54,97,19,182,255,145,141,250,44,165,217,116,58,7,52,26,19,239,217,168,255,82,146,173,170,106,4)
+IMAGE_DATA(106,181,145,185,62,243,94,78,73,54,141,198,140,71,143,218,97,183,31,179,235,123,252,254,74,176,209,252,15,31,254,193)
+IMAGE_DATA(210,192,198,108,179,249,62,178,123,199,185,69,78,27,205,171,82,117,161,160,64,139,251,247,117,108,158,24,191,255,85,143)
+IMAGE_DATA(25,64,83,147,159,247,95,212,51,209,121,209,233,178,155,151,47,255,132,86,59,204,207,101,73,73,19,10,11,127,199,189)
+IMAGE_DATA(123,47,80,90,90,203,214,113,156,217,2,82,143,233,225,253,18,245,114,207,158,245,241,241,116,94,178,153,39,79,122,240)
+IMAGE_DATA(248,177,129,63,95,180,151,15,30,188,98,191,215,177,245,239,195,191,36,148,53,215,0,0,0,0,0,0,0,0,0,0)
+IMAGE_END_DATA(1216, 3)
+
+IMAGE_BEGIN_DATA
+IMAGE_DATA(120,156,237,216,105,83,154,87,24,6,96,103,250,83,250,33,63,166,211,118,58,147,109,210,137,38,105,98,107,92,26,77)
+IMAGE_DATA(130,70,19,131,138,70,227,2,136,138,32,24,86,1,77,4,55,80,92,35,136,40,40,138,251,18,101,115,137,73,127,195)
+IMAGE_DATA(221,231,156,116,50,237,183,126,40,227,59,211,51,206,61,142,204,225,125,47,120,159,199,15,119,206,149,156,43,57,223,208)
+IMAGE_DATA(207,183,244,227,241,141,96,246,56,138,247,23,113,76,159,175,194,119,186,140,161,147,16,6,211,65,188,77,207,103,53,3)
+IMAGE_DATA(148,254,212,123,56,146,179,176,28,79,162,103,127,20,170,181,126,180,206,91,97,117,59,49,115,20,65,224,211,6,15,179)
+IMAGE_DATA(49,151,43,53,135,190,228,12,236,137,105,216,18,83,89,141,53,49,9,243,177,31,61,7,99,208,108,14,162,113,201,10)
+IMAGE_DATA(249,156,30,138,113,29,102,62,198,48,119,177,142,161,100,16,173,97,59,170,103,186,241,114,86,135,151,115,58,126,166,102)
+IMAGE_DATA(190,7,181,1,3,106,131,70,212,45,244,162,46,212,11,69,232,13,234,23,77,168,15,155,208,176,100,70,195,178,5,175)
+IMAGE_DATA(34,22,52,174,216,208,180,98,71,211,170,29,175,99,125,120,189,230,64,243,186,3,45,113,39,90,54,92,104,101,217,236)
+IMAGE_DATA(71,219,246,0,148,59,111,161,218,125,7,213,222,32,212,251,44,110,254,55,187,102,165,191,3,21,94,53,38,206,162,24)
+IMAGE_DATA(63,139,160,37,108,67,245,180,246,82,109,237,7,30,180,108,186,80,62,166,198,227,193,102,140,158,134,49,152,9,226,197)
+IMAGE_DATA(148,86,18,182,246,67,15,100,35,109,40,113,212,195,147,89,128,147,102,81,74,182,39,238,22,20,152,228,180,47,1,62)
+IMAGE_DATA(243,82,178,149,14,52,34,191,167,10,3,180,195,86,218,23,41,217,74,156,13,184,175,125,198,255,191,72,206,70,179,246)
+IMAGE_DATA(75,87,185,176,9,155,176,9,155,176,9,155,176,9,155,176,9,155,176,9,155,176,101,197,54,41,73,27,235,179,44,18)
+IMAGE_DATA(179,21,219,21,184,215,33,131,35,57,3,211,177,95,82,182,66,75,13,242,212,143,97,62,250,210,203,73,201,118,175,179)
+IMAGE_DATA(28,183,154,138,161,219,29,70,123,252,45,25,12,146,176,177,235,95,171,249,21,215,228,249,80,198,92,120,21,182,64,78)
+IMAGE_DATA(6,230,185,76,27,187,246,237,214,82,124,255,244,54,126,172,184,131,214,121,11,57,244,188,199,100,125,161,108,84,201,251)
+IMAGE_DATA(47,214,51,177,125,41,238,83,100,53,69,182,58,60,52,203,249,94,94,175,251,13,63,200,114,241,93,217,207,200,173,46)
+IMAGE_DATA(228,125,180,194,167,227,46,102,98,253,18,235,229,242,245,85,252,60,219,151,108,230,174,230,41,114,149,101,124,190,216,179)
+IMAGE_DATA(252,169,234,30,242,94,22,65,103,50,32,231,239,133,190,111,104,8,201,197,69,124,94,94,198,39,250,253,113,126,30,103)
+IMAGE_DATA(211,211,56,245,251,113,58,62,158,245,156,248,124,200,140,142,34,229,241,224,131,203,133,205,55,111,16,212,233,224,233,235)
+IMAGE_DATA(67,98,97,1,127,68,163,60,204,198,92,39,94,47,63,159,25,30,70,58,219,161,239,38,229,118,227,184,191,31,59,22)
+IMAGE_DATA(11,162,90,45,130,74,37,38,85,42,238,249,188,180,132,12,153,98,189,189,8,181,183,35,164,209,96,145,18,238,232,192)
+IMAGE_DATA(114,103,39,34,93,93,252,61,43,148,213,238,110,196,232,115,177,172,233,245,88,239,233,65,156,178,97,48,96,203,104,196)
+IMAGE_DATA(54,93,99,135,62,251,46,139,201,132,61,179,25,251,148,3,186,239,161,213,138,15,148,99,187,29,9,74,146,190,155,164)
+IMAGE_DATA(195,129,20,37,237,116,242,215,163,116,175,233,166,38,76,52,52,224,34,16,224,137,209,117,23,212,234,75,181,101,232,153)
+IMAGE_DATA(30,208,89,230,26,174,169,193,249,236,44,159,173,32,185,164,96,59,161,120,21,10,244,87,85,225,108,106,10,153,177,49)
+IMAGE_DATA(73,217,70,232,59,179,202,100,56,157,152,64,102,100,68,82,182,193,234,106,244,150,149,241,29,102,187,34,37,219,192,243)
+IMAGE_DATA(231,208,63,122,36,73,27,155,53,93,73,137,176,9,155,176,9,155,176,9,155,176,9,155,176,9,155,176,9,155,176,253)
+IMAGE_DATA(159,108,94,47,210,30,143,164,108,206,202,74,104,139,139,191,244,114,110,183,164,108,246,242,114,104,10,11,145,252,171,151)
+IMAGE_DATA(147,146,173,155,158,103,203,131,7,56,160,215,183,233,189,75,228,144,130,109,133,238,165,200,203,67,29,37,78,215,98,247)
+IMAGE_DATA(254,234,186,68,27,115,169,10,10,80,126,253,58,42,111,222,68,144,238,21,104,107,251,218,99,250,20,10,222,127,177,158)
+IMAGE_DATA(137,237,139,139,230,50,155,113,60,123,6,27,205,23,219,203,250,187,119,81,113,227,6,158,92,189,138,151,244,76,221,228)
+IMAGE_DATA(247,43,149,220,197,76,172,95,98,189,156,177,172,140,159,103,251,146,205,116,81,218,233,187,98,243,197,158,229,139,91,183)
+IMAGE_DATA(80,147,159,15,51,61,139,127,22,250,190,33,36,18,33,124,254,188,140,139,139,16,206,207,223,227,236,108,10,167,167,19)
+IMAGE_DATA(56,57,241,101,61,153,140,151,50,138,100,210,141,195,67,39,54,54,122,17,8,116,195,227,161,33,72,4,201,21,165,68)
+IMAGE_DATA(184,141,185,216,249,116,122,132,50,148,245,164,82,30,114,13,226,232,200,133,237,109,51,34,145,46,178,181,193,239,87,226)
+IMAGE_DATA(211,167,69,202,18,121,166,17,139,25,17,90,160,5,9,181,99,145,18,94,212,96,121,169,3,145,229,78,68,233,61,43)
+IMAGE_DATA(209,46,172,174,104,17,91,165,229,136,117,99,45,166,195,250,154,30,241,117,61,54,226,61,216,218,52,96,123,203,136,157)
+IMAGE_DATA(237,94,236,238,80,118,223,96,111,215,132,253,61,19,14,246,205,56,60,176,224,195,161,5,199,71,54,36,142,109,72,38)
+IMAGE_DATA(104,57,146,125,72,81,210,41,7,127,61,18,233,196,212,84,35,38,38,234,241,241,99,128,50,79,247,51,96,33,168,186)
+IMAGE_DATA(84,91,38,237,164,115,38,140,143,215,99,104,72,78,243,53,75,179,229,71,48,160,146,132,237,36,227,196,216,88,29,92)
+IMAGE_DATA(174,74,114,77,242,89,148,146,109,120,88,14,139,229,41,237,202,56,205,228,176,164,108,239,222,189,128,209,88,202,247,152)
+IMAGE_DATA(237,138,148,108,253,253,85,208,235,127,39,155,87,114,54,54,107,221,221,37,194,38,108,194,38,108,194,38,108,194,38,108)
+IMAGE_DATA(194,38,108,194,38,108,194,246,31,219,88,103,36,108,255,222,230,112,60,67,87,87,17,239,217,88,255,37,37,155,205,38)
+IMAGE_DATA(131,70,243,16,137,196,151,94,78,74,54,173,182,24,205,205,247,177,191,223,135,173,45,19,194,97,141,36,108,43,209,78)
+IMAGE_DATA(212,213,229,161,182,54,23,241,184,145,119,133,65,230,10,169,47,213,198,92,42,101,1,100,178,107,168,172,188,201,123,223)
+IMAGE_DATA(64,160,149,247,152,172,47,244,122,21,188,255,98,61,19,219,23,167,51,187,113,56,42,96,181,202,248,94,214,215,223,65)
+IMAGE_DATA(69,197,13,60,121,114,21,213,213,247,225,118,219,121,239,203,92,204,196,250,37,214,203,25,12,165,252,60,219,151,108,166)
+IMAGE_DATA(179,179,8,106,117,1,159,47,246,44,159,63,191,5,185,252,1,204,230,30,252,9,55,14,171,85,0,0,0,0,0,0)
+IMAGE_END_DATA(1600, 3)
+
+IMAGE_BEGIN_DATA
+IMAGE_DATA(120,156,237,152,91,76,147,103,24,199,223,196,41,51,158,38,195,73,230,192,139,93,120,97,34,120,227,212,76,135,139,58)
+IMAGE_DATA(4,77,140,46,154,101,202,150,41,113,9,166,13,86,145,210,170,1,13,33,156,98,185,0,66,129,166,10,179,156,205,22)
+IMAGE_DATA(78,165,80,40,80,192,132,180,9,229,124,10,135,221,140,121,163,81,163,168,127,191,231,173,69,82,215,121,136,216,183,9)
+IMAGE_DATA(253,242,187,104,223,239,223,254,190,247,123,222,183,249,30,182,137,109,98,75,164,227,107,233,168,169,169,193,224,224,32,166)
+IMAGE_DATA(166,166,48,49,49,129,177,177,49,140,140,140,96,104,104,136,127,190,208,12,12,12,160,191,191,31,14,135,3,54,155,13)
+IMAGE_DATA(237,237,237,168,175,175,71,69,69,5,31,155,158,158,230,144,27,121,185,206,239,235,235,91,112,122,123,123,185,151,221,110)
+IMAGE_DATA(71,87,87,23,154,154,154,80,93,93,141,170,170,42,238,51,57,57,137,209,209,81,238,77,227,222,164,161,161,1,149,149)
+IMAGE_DATA(149,40,43,43,195,248,248,56,71,4,47,162,173,173,13,165,165,165,40,42,42,226,243,69,181,213,217,217,41,12,6,131)
+IMAGE_DATA(1,5,5,5,24,30,30,230,181,213,209,209,33,12,197,197,197,200,206,206,230,107,133,106,210,219,62,243,209,235,245,200)
+IMAGE_DATA(202,202,226,110,180,86,188,237,51,159,194,194,66,100,102,102,242,253,130,220,172,86,171,48,80,173,101,100,100,248,132,27)
+IMAGE_DATA(237,199,162,224,238,70,251,138,40,248,146,91,107,107,171,48,184,187,89,44,22,97,240,37,183,150,150,22,97,112,119,107)
+IMAGE_DATA(110,110,22,134,69,183,15,227,102,54,155,133,193,151,220,232,25,66,20,220,221,26,27,27,133,193,151,220,76,38,147,48)
+IMAGE_DATA(184,187,209,115,161,40,248,146,155,209,104,20,6,119,55,234,143,136,194,162,219,135,113,171,171,171,19,6,173,86,139,180)
+IMAGE_DATA(180,180,185,190,156,183,125,230,147,155,155,139,148,148,20,244,244,244,240,190,92,109,109,173,48,164,167,167,35,49,49,17)
+IMAGE_DATA(221,221,221,188,7,65,251,10,245,87,189,77,121,121,57,18,18,18,160,84,42,249,243,32,253,135,145,47,205,167,55,189)
+IMAGE_DATA(168,199,155,148,148,4,153,76,134,216,216,88,238,67,253,85,234,99,82,191,176,164,164,132,247,191,168,207,68,235,37,63)
+IMAGE_DATA(63,127,65,201,203,203,67,78,78,14,95,151,42,149,10,114,185,28,49,49,49,136,143,143,231,174,46,47,114,162,254,18)
+IMAGE_DATA(245,229,52,26,13,63,159,214,203,66,146,154,154,138,228,228,100,94,95,116,47,21,10,5,191,159,58,157,14,236,51,233)
+IMAGE_DATA(112,189,54,250,179,208,132,8,102,182,168,25,238,27,86,227,201,159,193,152,173,221,130,89,211,110,204,182,28,194,83,235)
+IMAGE_DATA(73,60,187,115,22,207,108,42,60,119,164,225,161,93,131,219,215,194,16,181,131,153,215,175,98,161,234,72,102,190,121,74)
+IMAGE_DATA(202,22,49,60,174,88,243,198,252,243,65,45,30,245,234,112,249,32,195,201,111,152,249,143,104,6,202,63,54,188,202,203)
+IMAGE_DATA(14,7,64,118,116,195,92,94,254,83,8,228,63,111,155,203,99,172,148,231,213,17,12,255,149,151,46,139,227,202,187,222)
+IMAGE_DATA(127,172,252,251,250,95,58,254,233,91,205,159,167,252,254,173,159,224,159,91,95,121,204,63,232,78,134,242,76,132,199,252)
+IMAGE_DATA(137,176,101,176,102,4,122,204,219,43,207,225,240,222,173,30,243,113,71,252,160,149,125,142,153,242,205,152,185,189,19,51)
+IMAGE_DATA(213,225,248,215,120,28,119,27,163,113,215,162,64,254,213,99,136,59,29,254,90,254,198,203,252,95,234,21,8,92,187,4)
+IMAGE_DATA(65,235,150,74,248,33,232,139,229,8,90,191,66,98,37,130,2,87,35,48,96,21,76,122,5,207,95,138,148,242,7,156)
+IMAGE_DATA(121,253,111,82,253,221,124,183,250,83,133,51,14,229,117,191,50,24,227,24,238,221,122,115,253,63,176,105,80,162,254,14)
+IMAGE_DATA(23,247,50,40,247,59,243,133,191,48,100,29,99,72,146,124,226,191,103,56,191,155,65,65,236,114,114,110,30,177,223,58)
+IMAGE_DATA(199,46,236,145,206,221,39,93,131,180,126,10,162,24,174,255,200,112,229,7,103,86,190,243,255,161,239,56,31,198,112,106)
+IMAGE_DATA(59,115,4,251,179,16,101,56,107,127,215,223,255,125,7,251,59,244,75,118,246,5,30,106,113,62,0,0,0,0,0,0)
+IMAGE_END_DATA(960, 2)
diff --git a/windows/keybuddy2/src/keyButton.h b/windows/keybuddy2/src/keyButton.h
new file mode 100644
index 0000000..38e9484
--- /dev/null
+++ b/windows/keybuddy2/src/keyButton.h
@@ -0,0 +1,25 @@
+#ifndef _KeyBuddy2_keyButton_h_
+#define _KeyBuddy2_keyButton_h_
+
+// custom button class, that is extended by simulated pushes and releases
+class keyButton:public Button{
+public:
+ int finger; // for which finger is this button? (determines the drawing color)
+ void simDown(){
+ if(IsReadOnly() || !IsEnabled() || IsPush()) return;
+ KeyPush();
+ Sync();
+ }
+ void simUp(){
+ if(!IsPush()) return;
+ FinishPush();
+ Sync();
+ }
+ bool isPushed(){
+ return IsPush();
+ }
+ void LeftDown(Point, dword){}; // overwrite mouse action so buttons do not react to clicking
+ void LeftUp(Point, dword){};
+};
+
+#endif
diff --git a/windows/keybuddy2/src/keybuttons.inc b/windows/keybuddy2/src/keybuttons.inc
new file mode 100644
index 0000000..d5a09d0
--- /dev/null
+++ b/windows/keybuddy2/src/keybuttons.inc
@@ -0,0 +1,121 @@
+
+// pointers to button objects on the GUI
+pKeyButton[VK_TAB]=&but_tab;
+pKeyButton[VK_CAPITAL]=&but_capslock;
+pKeyButton[VK_LSHIFT]=&but_lshift;
+pKeyButton[VK_LCONTROL]=&but_lctrl;
+pKeyButton[VK_LWIN]=&but_lwin;
+pKeyButton[VK_LMENU]=&but_lalt;
+pKeyButton[VK_SPACE]=&but_space;
+pKeyButton[VK_RMENU]=&but_altgr;
+pKeyButton[VK_RWIN]=&but_rwin;
+pKeyButton[VK_APPS]=&but_contmenu;
+pKeyButton[VK_RCONTROL]=&but_rctrl;
+pKeyButton[VK_RSHIFT]=&but_rshift;
+pKeyButton[VK_RETURN]=&but_enter;
+pKeyButton[VK_BACK]=&but_backspace;
+
+pKeyButton[VK_0]=&but_0;
+pKeyButton[VK_1]=&but_1;
+pKeyButton[VK_2]=&but_2;
+pKeyButton[VK_3]=&but_3;
+pKeyButton[VK_4]=&but_4;
+pKeyButton[VK_5]=&but_5;
+pKeyButton[VK_6]=&but_6;
+pKeyButton[VK_7]=&but_7;
+pKeyButton[VK_8]=&but_8;
+pKeyButton[VK_9]=&but_9;
+
+pKeyButton[VK_A]=&but_A;
+pKeyButton[VK_B]=&but_B;
+pKeyButton[VK_C]=&but_C;
+pKeyButton[VK_D]=&but_D;
+pKeyButton[VK_E]=&but_E;
+pKeyButton[VK_F]=&but_F;
+pKeyButton[VK_G]=&but_G;
+pKeyButton[VK_H]=&but_H;
+pKeyButton[VK_I]=&but_I;
+pKeyButton[VK_J]=&but_J;
+pKeyButton[VK_K]=&but_K;
+pKeyButton[VK_L]=&but_L;
+pKeyButton[VK_M]=&but_M;
+pKeyButton[VK_N]=&but_N;
+pKeyButton[VK_O]=&but_O;
+pKeyButton[VK_P]=&but_P;
+pKeyButton[VK_Q]=&but_Q;
+pKeyButton[VK_R]=&but_R;
+pKeyButton[VK_S]=&but_S;
+pKeyButton[VK_T]=&but_T;
+pKeyButton[VK_U]=&but_U;
+pKeyButton[VK_V]=&but_V;
+pKeyButton[VK_W]=&but_W;
+pKeyButton[VK_X]=&but_X;
+pKeyButton[VK_Y]=&but_Y;
+pKeyButton[VK_Z]=&but_Z;
+
+pKeyButton[VK_UE]=&but_UE;
+pKeyButton[VK_PLUS]=&but_plus;
+pKeyButton[VK_COMMA]=&but_comma;
+pKeyButton[VK_DASH]=&but_dash;
+pKeyButton[VK_DOT]=&but_dot;
+pKeyButton[VK_HASH]=&but_hash;
+pKeyButton[VK_OE]=&but_OE;
+pKeyButton[VK_SZ]=&but_sz;
+pKeyButton[VK_CIRCUMFLEX]=&but_circ;
+pKeyButton[VK_ACUT]=&but_acut;
+pKeyButton[VK_AE]=&but_AE;
+pKeyButton[VK_SMALLER]=&but_smaller;
+
+
+
+
+keyFinger[VK_0]=4;
+keyFinger[VK_1]=5;
+keyFinger[VK_2]=5;
+keyFinger[VK_3]=4;
+keyFinger[VK_4]=3;
+keyFinger[VK_5]=2;
+keyFinger[VK_6]=2;
+keyFinger[VK_7]=2;
+keyFinger[VK_8]=2;
+keyFinger[VK_9]=3;
+
+keyFinger[VK_A]=5;
+keyFinger[VK_B]=2;
+keyFinger[VK_C]=3;
+keyFinger[VK_D]=3;
+keyFinger[VK_E]=3;
+keyFinger[VK_F]=2;
+keyFinger[VK_G]=2;
+keyFinger[VK_H]=2;
+keyFinger[VK_I]=3;
+keyFinger[VK_J]=2;
+keyFinger[VK_K]=3;
+keyFinger[VK_L]=4;
+keyFinger[VK_M]=2;
+keyFinger[VK_N]=2;
+keyFinger[VK_O]=4;
+keyFinger[VK_P]=5;
+keyFinger[VK_Q]=5;
+keyFinger[VK_R]=2;
+keyFinger[VK_S]=4;
+keyFinger[VK_T]=2;
+keyFinger[VK_U]=2;
+keyFinger[VK_V]=2;
+keyFinger[VK_W]=4;
+keyFinger[VK_X]=4;
+keyFinger[VK_Y]=5;
+keyFinger[VK_Z]=2;
+
+keyFinger[VK_UE]=5;
+keyFinger[VK_PLUS]=5;
+keyFinger[VK_COMMA]=3;
+keyFinger[VK_DASH]=5;
+keyFinger[VK_DOT]=4;
+keyFinger[VK_OE]=5;
+keyFinger[VK_SZ]=5;
+keyFinger[VK_CIRCUMFLEX]=5;
+keyFinger[VK_ACUT]=5;
+keyFinger[VK_AE]=5;
+
+keyFinger[VK_SPACE]=6;
diff --git a/windows/keybuddy2/src/keydefines.inc b/windows/keybuddy2/src/keydefines.inc
new file mode 100644
index 0000000..b68ce5f
--- /dev/null
+++ b/windows/keybuddy2/src/keydefines.inc
@@ -0,0 +1,58 @@
+#define VK_MOD_2 VK_SHIFT
+#define VK_MOD_21 VK_LSHIFT
+#define VK_MOD_22 VK_RSHIFT
+#define VK_MOD_31 VK_CAPITAL
+#define VK_MOD_32 VK_OEM_2 // #' button on german keyboard
+#define VK_MOD_41 VK_OEM_102 // <>| button on german keyboard
+#define VK_MOD_42 VK_RMENU
+
+#define VK_0 48
+#define VK_1 49
+#define VK_2 50
+#define VK_3 51
+#define VK_4 52
+#define VK_5 53
+#define VK_6 54
+#define VK_7 55
+#define VK_8 56
+#define VK_9 57
+
+#define VK_A 65
+#define VK_B 66
+#define VK_C 67
+#define VK_D 68
+#define VK_E 69
+#define VK_F 70
+#define VK_G 71
+#define VK_H 72
+#define VK_I 73
+#define VK_J 74
+#define VK_K 75
+#define VK_L 76
+#define VK_M 77
+#define VK_N 78
+#define VK_O 79
+#define VK_P 80
+#define VK_Q 81
+#define VK_R 82
+#define VK_S 83
+#define VK_T 84
+#define VK_U 85
+#define VK_V 86
+#define VK_W 87
+#define VK_X 88
+#define VK_Y 89
+#define VK_Z 90
+
+#define VK_UE 186
+#define VK_PLUS 187
+#define VK_COMMA 188
+#define VK_DASH 189
+#define VK_DOT 190
+#define VK_HASH 191 // #
+#define VK_OE 192
+#define VK_SZ 219
+#define VK_CIRCUMFLEX 220
+#define VK_ACUT 221
+#define VK_AE 222
+#define VK_SMALLER 226
diff --git a/windows/keybuddy2/src/logger.cpp b/windows/keybuddy2/src/logger.cpp
new file mode 100644
index 0000000..936723b
--- /dev/null
+++ b/windows/keybuddy2/src/logger.cpp
@@ -0,0 +1,57 @@
+
+#include "includes.h"
+
+FILE* plogfile;
+char linebuffer[2048]={0};
+
+void startLog(const char* fname){
+ plogfile=fopen(fname, "wb");
+}
+
+void logg(const char* txt){
+ fprintf(plogfile,"%s",txt);
+ sprintf(linebuffer,"%s%s",linebuffer,txt);
+}
+
+void logg(WString txt){
+ String utf8=ToUtf8(txt);
+ fprintf(plogfile,"%s",utf8.Begin());
+ sprintf(linebuffer,"%s%s",linebuffer,utf8.Begin());
+}
+
+void logg(bool b){
+ if(b){
+ fprintf(plogfile,"true");
+ strcat(linebuffer,"true");
+ }
+ else{
+ fprintf(plogfile,"false");
+ strcat(linebuffer,"false");
+ }
+}
+
+void logg(int num){
+ fprintf(plogfile,"%d",num);
+ sprintf(linebuffer,"%s%d",linebuffer,num);
+}
+
+void logg(double num){
+ fprintf(plogfile,"%f",num);
+ sprintf(linebuffer,"%s%f",linebuffer,num);
+}
+
+void logg(wchar uni){
+ fprintf(plogfile,"&#%d;",uni);
+ sprintf(linebuffer,"%s[U+%d]",linebuffer,uni);
+}
+
+void loggnl(){
+ fprintf(plogfile,"<br>\n");
+ sprintf(linebuffer,"%s\n",linebuffer);
+ KeyBuddy2::pdisplay->Insert(0,linebuffer);
+ memset(linebuffer,0,sizeof(linebuffer));
+}
+
+void endLog(){
+ fclose(plogfile);
+}
diff --git a/windows/keybuddy2/src/logger.h b/windows/keybuddy2/src/logger.h
new file mode 100644
index 0000000..86adb02
--- /dev/null
+++ b/windows/keybuddy2/src/logger.h
@@ -0,0 +1,30 @@
+#ifndef _KeyBuddy2_logger_h_
+#define _KeyBuddy2_logger_h_
+
+#include "includes.h"
+
+// Logging functions
+// if DEBUG is enabled, these functions display debug messages in the GUI and into an html file
+
+#ifdef DEBUG
+ #define STARTLOG(FNAME) startLog(FNAME)
+ #define LOGG(ARG) logg(ARG)
+ #define LOGGNL loggnl()
+ #define ENDLOG endLog()
+
+ void startLog(const char* fname);
+ void logg(const char* txt);
+ void logg(WString txt);
+ void logg(int num);
+ void logg(double num);
+ void logg(wchar uni);
+ void loggnl();
+ void endLog();
+#else
+ #define STARTLOG(FNAME)
+ #define LOGG(ARG)
+ #define LOGGNL
+ #define ENDLOG
+#endif
+
+#endif
diff --git a/windows/keybuddy2/src/main.cpp b/windows/keybuddy2/src/main.cpp
new file mode 100644
index 0000000..fa8418f
--- /dev/null
+++ b/windows/keybuddy2/src/main.cpp
@@ -0,0 +1,819 @@
+
+#include "includes.h"
+
+#define IMAGECLASS KB2Images
+#define IMAGEFILE <KeyBuddy2/kb2images.iml>
+
+#include <Draw/iml.h>
+
+KeyBuddy2* KeyBuddy2::pKB2=NULL;
+LineEdit* KeyBuddy2::pdisplay=NULL; // pointer to the display
+keyButton* KeyBuddy2::pKeyButton[256]={0}; // pointers to gui key buttons
+BYTE KeyBuddy2::keyFinger[256]={0}; // which finger is associated to this key (=style index)
+bool KeyBuddy2::neoLevelsActive=true; // whether the additional layers of neo are active
+bool KeyBuddy2::neoRemapActive=false; // false=qwertz layout, true=neo layout
+bool KeyBuddy2::cyrillicActive=false; // if roman letters are translated into cyrillic
+bool KeyBuddy2::capslockActive=false; // if capital letters shall be sent
+bool KeyBuddy2::lockLayer4Active=false; // if neo layer 4 is locked
+bool KeyBuddy2::mouseControlActive=false; // if mouse control via keyboard is active
+bool KeyBuddy2::dummySwitch=false; // that is switched by badly assigned switch pointers to prevent memory access violation
+bool KeyBuddy2::keyPressed[256]={0}; // key states
+wchar KeyBuddy2::lastDeadKey; // buffer that stores which dead key was pressed
+wchar KeyBuddy2::ruDeadChar[2]; // the dead characters for the russian keyboard (small and capital)
+wchar KeyBuddy2::map[256][7]={0}; // character to send = map[vkCode][mod]
+wchar KeyBuddy2::symbolMap[256][7]={0}; // character to draw on keyboard = symbolMap[vkCode][mod]
+BYTE KeyBuddy2::neoRemap[256]={0}; // vkNeoKey = neoRemap[vkQWERTZKey]
+wchar KeyBuddy2::rumap[256][2]={0}; // cyrillic character = rumap[ansi of latin character][ruDeadKey toggled]
+bool* KeyBuddy2::pSwitch[256]={0}; // pointer to the switches
+WString KeyBuddy2::keyNames[256]; // names of unmodified keys
+wchar KeyBuddy2::upperCaseMap[1023][2]={0}; // mapping lowercase unicode characters to uppercase
+
+KeyBuddy2::KeyBuddy2()
+{
+ pKB2 = this;
+ #ifdef DEBUG
+ pdisplay = &display;
+ #endif
+
+ STARTLOG(SRCPATH "log.html");
+ loadMaps();
+ hotString::loadHotStrings();
+
+ int i;
+ for(i=0;i<=255;i++){
+ pSwitch[i]=&dummySwitch;
+ }
+ pSwitch[1]=&neoLevelsActive;
+ pSwitch[2]=&neoRemapActive;
+ pSwitch[3]=&cyrillicActive;
+ pSwitch[4]=&capslockActive;
+ pSwitch[5]=&lockLayer4Active;
+ pSwitch[6]=&mouseControlActive;
+
+ KeyBuddy2::Zoomable();
+
+ Icon(KB2Images::tray(),KB2Images::tray());
+ trayicon.Icon(KB2Images::tray());
+ trayicon.WhenBar=THISBACK(traymenu);
+ trayicon.WhenLeftDown=THISBACK(trayclick);
+ trayicon.Tip("KeyBuddy2 (verändert Tastatur)");
+
+ CtrlLayout(*this, "KeyBuddy2");
+ releaseAllKeys();
+ SetHook();
+ initKeyButtons();
+
+ NoAccessKeysDistribution();
+
+ #ifndef DEBUG
+ WhenClose=THISBACK(Hide);
+ #endif
+
+ ToolWindow();
+ TopMost();
+}
+
+KeyBuddy2::~KeyBuddy2()
+{
+ releaseAllKeys();
+ RemoveHook();
+ ENDLOG;
+}
+
+bool KeyBuddy2::ProcessKbdEvent(
+ WPARAM upDownInfo,
+ DWORD vkCode,
+ DWORD scanCode,
+ bool isExtended,
+ bool isInjected,
+ bool isAltDown,
+ bool isReleased,
+ ULONG_PTR dwExtraInfo)
+{
+
+ if(scanCode==0x21d){ // AltGr also presses left Strg but with scancode 0x21d, filter that out, it sucks
+ return false;
+ }
+ if(!isInjected){ // memorize physical key states
+ keyPressed[vkCode]=!isReleased;
+ if(isReleased){pKeyButton[vkCode]->simUp();}
+ else{pKeyButton[vkCode]->simDown();}
+ }
+
+ // log information about captured event:
+
+ char udi[14]; // up down info string
+ char buffer[512];
+ //bool forceRedraw=false; // force keyboard redraw
+
+ switch(upDownInfo){
+ case WM_KEYDOWN:
+ sprintf(udi,"WM_KEYDOWN");
+ break;
+ case WM_KEYUP:
+ sprintf(udi,"WM_KEYUP");
+ break;
+ case WM_SYSKEYDOWN:
+ sprintf(udi,"WM_SYSKEYDOWN");
+ break;
+ case WM_SYSKEYUP:
+ sprintf(udi,"WM_SYSKEYUP");
+ break;
+ default:
+ sprintf(udi,"UNKNOWN");
+ }
+
+ sprintf(buffer,"upDownInfo: %s\tvkCode: %d (0x%X)\tscanCode: %d (0x%X)\textended: %d\tinjected: %d\taltdown: %d\tup: %d\tdwExtraInfo: %d",
+ udi,vkCode,vkCode,scanCode,scanCode,(int)isExtended,(int)isInjected,(int)isAltDown,(int)isReleased,dwExtraInfo);
+
+ LOGG(buffer);
+ LOGGNL;
+
+ if(dwExtraInfo==HOTSTRING){ // a hotstring is being sent, dont do anything
+ return true;
+ }
+
+ // flush the hotstring buffer if certain navi or special keys are pressed (even if they are injected)
+ if(vkCode==VK_UP || vkCode==VK_LEFT || vkCode==VK_RIGHT || vkCode==VK_DOWN
+ || vkCode==VK_PRIOR || vkCode==VK_NEXT || vkCode==VK_END || vkCode==VK_HOME
+ || keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL]
+ || keyPressed[VK_LWIN] || keyPressed[VK_RWIN] || keyPressed[VK_LMENU]){
+
+ hotString::clearBuffer();
+ }
+
+ // delete one key from hotstring buffer if backspace is pushed
+ if(vkCode==VK_BACK && !isReleased){
+ int i;
+ for(i=hotString::bufferLen-1;i>0;i--){
+ hotString::hsBuffer.Set(i,(int)hotString::hsBuffer[i-1]);
+ }
+ hotString::hsBuffer.Set(0,(int)0);
+ }
+
+ if(isInjected){ // dont stop or change generated key events
+ return true;
+ }
+
+ // check if the key combination would activate the neo levels
+ if(!neoLevelsActive && !isReleased){
+
+ neoLevelsActive=true; // only simulative to fool getNeoMod
+ int mod=getNeoMod();
+ WORD vkCode_neo;
+
+ if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
+ vkCode_neo=neoRemap[vkCode];
+ }
+ else{
+ vkCode_neo=vkCode;
+ }
+ if(map[vkCode_neo][mod-1]!=0xF801){ // keystroke would not activate layers, leave true otherwise
+ neoLevelsActive=false; // deactivate again
+ }
+ else{ // leave activated
+ pKB2->drawKeyButtons();
+ return false;
+ }
+ }
+
+ // check if the key combination turns off mouse control
+ if(mouseControlActive && !isReleased){
+ int mod=getNeoMod();
+ WORD vkCode_neo;
+
+ if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
+ vkCode_neo=neoRemap[vkCode];
+ }
+ else{
+ vkCode_neo=vkCode;
+ }
+ if(map[vkCode_neo][mod-1]==0xF806){ // keystroke deactivates mouse control
+ mouseControlActive=false; // deactivate again
+ pKB2->drawKeyButtons();
+ return false;
+ }
+ }
+
+ // dont do substitutions if neolevels are off or
+ // certain functional keys are being pressed or held (getNeoMod returns 0)
+ // this means that ctrl+a/x/c/v/z... remain on their standard position
+ // also clear hotstring buffer then
+ if(getNeoMod()==0
+ || vkCode==VK_LCONTROL || vkCode==VK_RCONTROL
+ || vkCode==VK_LWIN || vkCode==VK_RWIN
+ || vkCode==VK_LMENU){
+
+ // redraw keyboard
+ pKB2->drawKeyButtons();
+
+ return true;
+ }
+
+ // capslock
+ if(keyPressed[VK_LSHIFT] && keyPressed[VK_RSHIFT]
+ && (vkCode==VK_LSHIFT || vkCode==VK_RSHIFT)
+ && !isReleased){
+ capslockActive=!capslockActive;
+ pKB2->drawKeyButtons();
+ }
+
+ // lock 4th layer
+ if(keyPressed[VK_MOD_41] && keyPressed[VK_MOD_42]
+ && (vkCode==VK_MOD_41 || vkCode==VK_MOD_42)
+ && !isReleased){
+ lockLayer4Active=!lockLayer4Active;
+ pKB2->drawKeyButtons();
+ }
+
+ // number keys, letter keys, ",", "-", ".", dead keys, space
+ if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
+ || vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
+ || vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
+ || vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
+ || vkCode==VK_SPACE || vkCode==VK_TAB){
+
+ if(mouseControlActive){
+ mouseController::mouseEvent(vkCode,isReleased);
+ return false;
+ }
+
+ WORD vkCode_neo;
+ int mod=getNeoMod();
+
+ if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
+ vkCode_neo=neoRemap[vkCode];
+ }
+ else{
+ vkCode_neo=vkCode;
+ }
+
+ LOGG("vkCode: ");
+ LOGG((int)vkCode);
+ LOGG(" vkCode_neo: ");
+ LOGG((int)vkCode_neo);
+ LOGG(" mod: ");
+ LOGG(mod);
+
+ if(mod>=1 && mod<=7){
+ wchar charToSend=map[vkCode_neo][mod-1];
+
+ if(cyrillicActive){
+ if(charToSend==ruDeadChar[0] || charToSend==ruDeadChar[1]){
+ lastDeadKey=charToSend;
+ pKB2->drawKeyButtons();
+ return false;
+ }
+ if(charToSend>0 && charToSend<256){
+ if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
+ charToSend=rumap[charToSend][1];
+ lastDeadKey=0;
+ pKB2->drawKeyButtons();
+ }
+ else{
+ charToSend=rumap[charToSend][0];
+ lastDeadKey=0;
+ }
+ }
+ }
+
+ if(capslockActive){
+ charToSend=upperCase(charToSend);
+ }
+
+ LOGG(" sending: ");
+ LOGG(charToSend);
+ LOGG(" (U+");
+ LOGG((int)charToSend);
+ LOGG(")");
+ LOGGNL;
+
+ SendUNIKey(charToSend,isReleased);
+ if(!isReleased){
+ long focusPtr=hotString::getFocusWindowPtr();
+
+ if(focusPtr!=hotString::lastFocusPtr){ // if a new window has the focus, clear the buffer
+ hotString::clearBuffer();
+ hotString::lastFocusPtr=focusPtr;
+ }
+
+ hotString::appendBuffer(charToSend);
+ hotString::checkHotStrings();
+ }
+ }
+
+ return false;
+ }
+
+ if(!neoLevelsActive){
+ return true;
+ }
+
+ // redraw keyboard
+ if(vkCode==VK_LSHIFT || vkCode==VK_RSHIFT
+ || vkCode==VK_MOD_31 || vkCode==VK_MOD_32
+ || vkCode==VK_MOD_41 || vkCode==VK_MOD_42
+ || vkCode==VK_LCONTROL || vkCode==VK_RCONTROL){
+ pKB2->drawKeyButtons();
+ }
+
+ // block mod keys that have symbols
+ if(vkCode==VK_MOD_32 || vkCode==VK_MOD_41){
+ return false;
+ }
+
+ return true;
+}
+
+WString KeyBuddy2::buttonLabel(DWORD vkCode){
+
+ wchar res=0;
+
+ if(getNeoMod()==0){
+ return keyNames[vkCode];
+ }
+
+ // number keys, letter keys, ",", "-", ".", dead keys, tab, space
+ if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
+ || vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
+ || vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
+ || vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
+ || vkCode==VK_TAB || vkCode==VK_SPACE){
+
+ WORD vkCode_neo;
+ int mod=getNeoMod();
+
+ if(mouseControlActive){
+ int i;
+ for(i=0;i<9;i++){
+ if(vkCode==mouseController::mouseKeys[i]){
+ res=mouseController::mouseSymbols[i];
+ return WString((int)res,1);
+ }
+ }
+ return "";
+ }
+
+ if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
+ vkCode_neo=neoRemap[vkCode];
+ }
+ else{
+ vkCode_neo=vkCode;
+ }
+
+ if(mod>=1 && mod<=7){
+ res=symbolMap[vkCode_neo][mod-1];
+
+ if(cyrillicActive){
+ if(res==ruDeadChar[0] || res==ruDeadChar[1]){
+ return WString((int)res,1);
+ }
+ if(res>0 && res<256){
+ if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
+ res=rumap[res][1];
+ }
+ else{
+ res=rumap[res][0];
+ }
+ }
+ }
+
+ if(capslockActive){
+ res=upperCase(res);
+ }
+
+ return WString((int)res,1);
+ }
+
+ }
+
+ switch(vkCode){ // layer-independent keys
+ case VK_LSHIFT: case VK_RSHIFT: return WString(0x21e7,1); break;
+ case VK_MOD_31: case VK_MOD_32: return WString("Mod3"); break;
+ case VK_MOD_41: case VK_MOD_42: return WString("Mod4"); break;
+ case VK_RETURN: return WString(0x21b5,1); break;
+ case VK_BACK: return WString(0x232b,1); break;
+ case VK_LCONTROL: case VK_RCONTROL: return WString("Strg"); break;
+ case VK_LMENU: return WString("Alt"); break;
+ case VK_LWIN: case VK_RWIN: return WString(0x229e,1)+WString(0x224b,1); break;
+ case VK_APPS: return WString(0x2338,1)+WString(0x21d6,1); break;
+ }
+
+ return WString("");
+
+}
+
+int KeyBuddy2::getNeoMod(){
+
+ if(keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL] // functional keys, disable neo stuff
+ || keyPressed[VK_LWIN] || keyPressed[VK_RWIN]
+ || keyPressed[VK_LMENU] || !neoLevelsActive){
+
+ return 0;
+ }
+
+ bool kp2=keyPressed[VK_MOD_21] || keyPressed[VK_MOD_22];
+ bool kp3=keyPressed[VK_MOD_31] || keyPressed[VK_MOD_32];
+ bool kp4=keyPressed[VK_MOD_41] || keyPressed[VK_MOD_42] || lockLayer4Active;
+
+ if(!kp2 && !kp3 && !kp4){return 1;} // small letters
+
+ if( kp2 && !kp3 && !kp4){return 2;} // capital letters
+
+ if(!kp2 && kp3 && !kp4){return 3;} // special characters
+
+ if(!kp2 && !kp3 && kp4){return 4;} // numbers/navi
+
+ if( kp2 && kp3 && !kp4){return 5;} // small greek
+
+ if(!kp2 && kp3 && kp4){return 6;} // capital greek/math
+
+ if( kp2 && !kp3 && kp4){return 7;} // pseudo layer
+
+ return 0;
+
+}
+
+void KeyBuddy2::loadMaps(){
+ FILE* pFile;
+ int i;
+ BYTE buffer;
+ wchar unibuffer;
+
+ #define FGETUC(pbuf,pfile) fread(pbuf,sizeof(wchar),1,pfile)
+
+ // QWERTZ keycode -> neo keycode
+
+ pFile = fopen(SRCPATH "neomap.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read neomap.txt"); exit(1);}
+
+ neoRemap[0]=0;
+
+ for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in map.txt does not match the keycode
+ buffer=fgetc(pFile);
+ if(buffer==13){ // line break, no mapping
+ neoRemap[i]=i;
+ fgetc(pFile); // skip second line break character
+ }
+ else{
+ neoRemap[i]=buffer;
+ fgetc(pFile); // skip line break characters
+ fgetc(pFile);
+ }
+ LOGG("neoRemap ");LOGG(i);LOGG("->");LOGG(neoRemap[i]);LOGGNL;
+ }
+ fclose(pFile);
+
+
+ // keycode -> unicode character to send
+
+ pFile = fopen(SRCPATH "sendmap.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read sendmap.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ memset(map[0],0,7);
+
+ for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in sendmap.txt does not match the keycode
+ fread(map[i],sizeof(wchar),7,pFile); // read from file
+ fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
+ fgetc(pFile);
+ fgetc(pFile);
+ fgetc(pFile);
+
+ LOGG("key ");LOGG(i);LOGG(": ");LOGG(map[i][0]);LOGG(map[i][1]);LOGG(map[i][2]);LOGG(map[i][3]);LOGG(map[i][4]);LOGG(map[i][5]);LOGG(map[i][6]);LOGGNL;
+ }
+ fclose(pFile);
+
+
+ // keycode -> unicode character to draw on keyboard
+
+ pFile = fopen(SRCPATH "symbolmap.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read symbolmap.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ memset(symbolMap[0],0,7);
+
+ for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in symbolmap.txt does not match the keycode
+ fread(symbolMap[i],sizeof(wchar),7,pFile); // read from file
+ fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
+ fgetc(pFile);
+ fgetc(pFile);
+ fgetc(pFile);
+
+ LOGG("key ");LOGG(i);LOGG(": ");LOGG(map[i][0]);LOGG(map[i][1]);LOGG(map[i][2]);LOGG(map[i][3]);LOGG(map[i][4]);LOGG(map[i][5]);LOGG(map[i][6]);LOGGNL;
+ }
+ fclose(pFile);
+
+
+ // latin character -> cyrillic character
+ pFile = fopen(SRCPATH "rumap.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read rumap.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ rumap[0][0]=0;
+ rumap[0][1]=0;
+
+ int idead=0;
+
+ for(i=1;i<=255;i++){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==13){ // line break, no mapping
+ rumap[i][0]=i;
+ rumap[i][1]=i;
+ FGETUC(&unibuffer,pFile); // skip second line break character
+ }
+ else{
+ if(unibuffer==0x2020){ // dagger, symbol for the dead character
+ rumap[i][0]=0;
+ rumap[i][1]=0;
+ ruDeadChar[idead]=i;
+ idead++;
+ FGETUC(&unibuffer,pFile); // skip line break characters
+ FGETUC(&unibuffer,pFile);
+ }
+ else{
+ rumap[i][0]=unibuffer;
+ rumap[i][1]=unibuffer;
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==13){ // line break, no special character if dead key is toggled
+ FGETUC(&unibuffer,pFile); // skip second line break character
+ }
+ else{ // special character if cyrillic dead key is toggled
+ rumap[i][1]=unibuffer;
+ FGETUC(&unibuffer,pFile); // skip line break characters
+ FGETUC(&unibuffer,pFile);
+ }
+ }
+ }
+ LOGG("russianRemap ");LOGG(i);LOGG("->");LOGG(rumap[i][0]);LOGG("/");LOGG(rumap[i][1]);LOGGNL;
+ }
+ fclose(pFile);
+
+ // keycode -> keyname
+
+ pFile = fopen(SRCPATH "keynames.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read keynames.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ keyNames[0]="";
+ for(i=1;i<=255;i++){
+ keyNames[i]="";
+
+ FGETUC(&unibuffer,pFile);
+ while(unibuffer!=13){ // line break
+ keyNames[i]=keyNames[i]+unibuffer;
+ FGETUC(&unibuffer,pFile);
+ }
+
+ FGETUC(&unibuffer,pFile); // skip second line break character
+ }
+ fclose(pFile);
+
+ // lowercase -> uppercase
+
+ pFile = fopen(SRCPATH "uppercase.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read uppercase.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ i=0;
+ while(!feof(pFile) && i<1023){
+ FGETUC(&(upperCaseMap[i][0]),pFile);
+ FGETUC(&(upperCaseMap[i][1]),pFile);
+ i++;
+ }
+ fclose(pFile);
+
+ while(i<1023){
+ upperCaseMap[i][0]=0xFFFF;
+ upperCaseMap[i][1]=0xFFFF;
+ i++;
+ }
+
+ // keycode -> mouseevent
+
+ pFile = fopen(SRCPATH "mousemap.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read mousemap.txt"); exit(1);}
+
+ fread(mouseController::mouseKeys,sizeof(byte),9,pFile);
+ fclose(pFile);
+}
+
+void KeyBuddy2::SendUNIKey(wchar key, bool release, ULONG_PTR extraInfo){
+
+ // use unicodes Personal Usage Area (E000-F8FF) specially
+ if(key/256>=0xE0 && key/256<=0xF8){ // send keystroke instead of unicode
+ byte flags=key/256;
+ bool onlyDown=flags<=0xE7;
+ bool onlyUp=flags>=0xE8 && flags<=0xEF;
+ bool swtch=(flags==0xF8);
+ bool shift=(flags & 1)!=0;
+ bool ctrl=(flags & 2)!=0;
+ bool alt=(flags & 4)!=0;
+
+ // E0-E7: only down event gets sent
+ // E8-EF: only up event gets sent (but if key is pushed down)
+ // F0-F7: down and up according to release parameter
+ // F8: switch
+ // unicode AND 0x0100 = shift also pressed
+ // unicode AND 0x0200 = ctrl also pressed
+ // unicode AND 0x0400 = alt also pressed
+
+ if(swtch && !release){
+ if(key % 256==0){ // end program
+ KeyBuddy2::pKB2->Break();
+ }
+ if(key % 256==7){ // show / hide GUI
+ KeyBuddy2::pKB2->Show(!KeyBuddy2::pKB2->IsShown());
+ return;
+ }
+ *(KeyBuddy2::pSwitch[key % 256])=!*(KeyBuddy2::pSwitch[key % 256]);
+ return;
+ }
+
+ if((onlyDown || onlyUp) && release){return;}
+
+ // first release all other keys
+ byte keyboardStateBuffer[256];
+ byte allUp[256];
+ DWORD unused;
+
+ memset(keyboardStateBuffer,0,256);
+ memset(allUp,0,256);
+
+ long myThread=GetWindowThreadProcessId(KeyBuddy2::pKB2->GetHWND(),&unused);
+ long otherThread=GetWindowThreadProcessId(GetForegroundWindow(),&unused);
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,true);
+ }
+
+ GetKeyboardState(keyboardStateBuffer);
+ SetKeyboardState(allUp);
+
+ // then send the key
+
+ INPUT in[4];
+ int iIn=0;
+
+ for(iIn=0;iIn<4;iIn++){
+ in[iIn].type=INPUT_KEYBOARD;
+ in[iIn].ki.dwExtraInfo=extraInfo;
+ in[iIn].ki.time=0;
+ in[iIn].ki.wScan=0;
+ in[iIn].ki.dwFlags=0;
+ if(release){in[iIn].ki.dwFlags=KEYEVENTF_KEYUP;}
+ }
+
+ iIn=0;
+
+ if(release){ // if we release the buttons, release the key of interest first, then ctrl, alt or shift
+ in[iIn].ki.wVk=key % 256;
+ iIn++;
+ }
+ if(ctrl){
+ in[iIn].ki.wVk=VK_LCONTROL;
+ iIn++;
+ }
+ if(shift){
+ in[iIn].ki.wVk=VK_LSHIFT;
+ iIn++;
+ }
+ if(alt){
+ in[iIn].ki.wVk=VK_LMENU;
+ iIn++;
+ }
+ if(!release){ // if we push the buttons, push ctrl alt shift first, then the key of interest
+ in[iIn].ki.wVk=key % 256;
+ iIn++;
+ }
+
+ SendInput(iIn,in,sizeof(INPUT));
+
+ Sleep(1); // otherwise the other thread does not see the changed keyboard state
+
+ // revert keyboard to its original state
+ SetKeyboardState(keyboardStateBuffer);
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,false);
+ }
+ }
+ else{ // only send unicode character
+ INPUT in[1];
+ in[0].type=INPUT_KEYBOARD;
+ in[0].ki.dwExtraInfo=extraInfo;
+ in[0].ki.wVk=0;
+ in[0].ki.wScan=key;
+ in[0].ki.dwFlags=KEYEVENTF_UNICODE;
+ if(release){in[0].ki.dwFlags=in[0].ki.dwFlags | KEYEVENTF_KEYUP;}
+ SendInput(1,in,sizeof(INPUT));
+ }
+}
+
+void KeyBuddy2::releaseAllKeys(){
+ BYTE zeros[256]={0};
+ SetKeyboardState(zeros);
+ for(int i=0;i<256;i++){
+ keyPressed[i]=false;
+ }
+}
+
+void KeyBuddy2::initKeyButtons(){
+ int i,j;
+
+ for(i=0; i<7; i++){
+ buttonStyle[i] = Button::StyleNormal();
+ for(j=0;j<4;j++){
+ buttonStyle[i].look[j] = KB2Images::Get(i);
+ }
+ buttonStyle[i].look[2] = KB2Images::Get(1);
+ buttonStyle[i].pressoffset = Point(0,0);
+ }
+
+ for(i=0;i<256;i++){
+ pKeyButton[i]=&but_invis;
+ keyFinger[i]=0;
+ }
+
+ but_invis.Hide();
+
+ #include "keybuttons.inc"
+
+ int bfid=buttonFont.FindFaceNameIndex("unifont");
+ buttonFont.Face(bfid);
+ buttonFontU.Face(bfid);
+ buttonFontU.Underline();
+ smallButtonFont.Face(bfid);
+ buttonFont.Height(32);
+ buttonFontU.Height(32);
+ smallButtonFont.Height(16);
+
+ for(i=0;i<256;i++){
+ pKeyButton[i]->SetStyle(buttonStyle[keyFinger[i]]);
+ if(i==VK_MOD_31 || i==VK_MOD_32 || i==VK_MOD_41 || i==VK_MOD_42
+ || i==VK_LMENU || i==VK_LCONTROL || i==VK_RCONTROL){
+ pKeyButton[i]->SetFont(smallButtonFont);
+ }
+ else{
+ if(i==VK_A || i==VK_S || i==VK_D || i==VK_F
+ || i==VK_J || i==VK_K || i==VK_L || i==VK_OE){
+ pKeyButton[i]->SetFont(buttonFontU);
+ }
+ else{
+ pKeyButton[i]->SetFont(buttonFont);
+ }
+ }
+
+ pKeyButton[i]->SetLabel(ToUtf8(buttonLabel(i)));
+ //pKeyButton[i]->Disable();
+ }
+}
+
+void KeyBuddy2::drawKeyButtons(){
+ int i;
+ String newLabel,oldLabel;
+
+ for(i=0;i<256;i++){
+ newLabel=ToUtf8(buttonLabel(i));
+ oldLabel=pKeyButton[i]->GetLabel();
+ if(!newLabel.IsEqual(oldLabel)){
+ if(!pKeyButton[i]->isPushed()){
+ pKeyButton[i]->SetLabel(newLabel);
+ }
+ else{
+ pKeyButton[i]->simUp();
+ pKeyButton[i]->SetLabel(newLabel);
+ pKeyButton[i]->simDown();
+ }
+ }
+ }
+}
+
+wchar KeyBuddy2::upperCase(wchar letter){
+ int a=0,b=1022,c;
+
+ while(a<=b){
+ c=(a+b)/2;
+ if( letter< upperCaseMap[c][0] ){b=c-1; continue;}
+ if( letter> upperCaseMap[c][0] ){a=c+1; continue;}
+ if( letter==upperCaseMap[c][0] ){return upperCaseMap[c][1];}
+ }
+
+ return letter;
+}
+
+GUI_APP_MAIN
+{
+ KeyBuddy2().Run();
+}
+
diff --git a/windows/keybuddy2/src/mousecontrol.cpp b/windows/keybuddy2/src/mousecontrol.cpp
new file mode 100644
index 0000000..34b4b97
--- /dev/null
+++ b/windows/keybuddy2/src/mousecontrol.cpp
@@ -0,0 +1,107 @@
+#include "includes.h"
+
+int mouseController::vx=0;
+int mouseController::vy=0;
+
+byte mouseController::mouseKeys[9]={0};
+bool mouseController::mouseButtonStates[3]={0};
+
+wchar mouseController::mouseSymbols[9]={0x15CF,0x15CB,0x15CC,0x15CA,0x15E1,0x15DE,0x15DD,0x15E3,0x15E2};
+
+// generate mouse event for the specified button
+void mouseController::mouseEvent(DWORD vkCode, bool isReleased){
+
+ INPUT in;
+ memset(&in,0,sizeof(INPUT));
+ in.type=INPUT_MOUSE;
+
+ if(vkCode==mouseKeys[MOUSE_MOVE_L]){
+ if(isReleased){
+ vx=0;
+ return;
+ }
+ if(vx>0){vx=0;}
+ if(vx>-20){vx--;}
+ in.mi.dx=vx;
+ in.mi.dwFlags=MOUSEEVENTF_MOVE;
+ }
+ else if(vkCode==mouseKeys[MOUSE_MOVE_R]){
+ if(isReleased){
+ vx=0;
+ return;
+ }
+ if(vx<0){vx=0;}
+ if(vx<20){vx++;}
+ in.mi.dx=vx;
+ in.mi.dwFlags=MOUSEEVENTF_MOVE;
+ }
+ else if(vkCode==mouseKeys[MOUSE_MOVE_U]){
+ if(isReleased){
+ vy=0;
+ return;
+ }
+ if(vy>0){vy=0;}
+ if(vy>-20){vy--;}
+ in.mi.dy=vy;
+ in.mi.dwFlags=MOUSEEVENTF_MOVE;
+ }
+ else if(vkCode==mouseKeys[MOUSE_MOVE_D]){
+ if(isReleased){
+ vy=0;
+ return;
+ }
+ if(vy<0){vy=0;}
+ if(vy<20){vy++;}
+ in.mi.dy=vy;
+ in.mi.dwFlags=MOUSEEVENTF_MOVE;
+ }
+ else if(vkCode==mouseKeys[MOUSE_BUTTON_L]){
+ if(!isReleased && mouseButtonStates[0]){return;} // dont resend clicks
+ if(!isReleased){
+ in.mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
+ mouseButtonStates[0]=true;
+ }
+ else{
+ in.mi.dwFlags=MOUSEEVENTF_LEFTUP;
+ mouseButtonStates[0]=false;
+ }
+ }
+ else if(vkCode==mouseKeys[MOUSE_BUTTON_R]){
+ if(!isReleased && mouseButtonStates[1]){return;} // dont resend clicks
+ if(!isReleased){
+ in.mi.dwFlags=MOUSEEVENTF_RIGHTDOWN;
+ mouseButtonStates[1]=true;
+ }
+ else{
+ in.mi.dwFlags=MOUSEEVENTF_RIGHTUP;
+ mouseButtonStates[1]=false;
+ }
+ }
+ else if(vkCode==mouseKeys[MOUSE_BUTTON_M]){
+ if(!isReleased && mouseButtonStates[2]){return;} // dont resend clicks
+ if(!isReleased){
+ in.mi.dwFlags=MOUSEEVENTF_MIDDLEDOWN;
+ mouseButtonStates[2]=true;
+ }
+ else{
+ in.mi.dwFlags=MOUSEEVENTF_MIDDLEUP;
+ mouseButtonStates[2]=false;
+ }
+ }
+ else if(vkCode==mouseKeys[MOUSE_SCROLL_U]){
+ if(isReleased){return;}
+ in.mi.dwFlags=MOUSEEVENTF_WHEEL;
+ in.mi.mouseData=WHEEL_DELTA;
+ }
+ else if(vkCode==mouseKeys[MOUSE_SCROLL_D]){
+ if(isReleased){return;}
+ in.mi.dwFlags=MOUSEEVENTF_WHEEL;
+ in.mi.mouseData=-WHEEL_DELTA;
+ }
+ else{
+ return; // do not call sendinput
+ }
+
+ // send mouse event
+ SendInput(1,&in,sizeof(INPUT));
+}
diff --git a/windows/keybuddy2/src/mousecontrol.h b/windows/keybuddy2/src/mousecontrol.h
new file mode 100644
index 0000000..1b34550
--- /dev/null
+++ b/windows/keybuddy2/src/mousecontrol.h
@@ -0,0 +1,24 @@
+#ifndef _KeyBuddy2_mousecontrol_h_
+#define _KeyBuddy2_mousecontrol_h_
+
+#include "includes.h"
+
+class mouseController{
+
+public:
+ static int vx,vy; // mouse velocity
+
+ static byte mouseKeys[9];
+ static bool mouseButtonStates[3];
+ static wchar mouseSymbols[9];
+
+ static void mouseEvent(DWORD vkCode, bool isReleased);
+
+};
+
+
+
+
+
+
+#endif
diff --git a/windows/keybuddy2/src/mousedefines.inc b/windows/keybuddy2/src/mousedefines.inc
new file mode 100644
index 0000000..f063239
--- /dev/null
+++ b/windows/keybuddy2/src/mousedefines.inc
@@ -0,0 +1,9 @@
+#define MOUSE_MOVE_L 0
+#define MOUSE_MOVE_U 1
+#define MOUSE_MOVE_R 2
+#define MOUSE_MOVE_D 3
+#define MOUSE_BUTTON_L 4
+#define MOUSE_BUTTON_R 5
+#define MOUSE_BUTTON_M 6
+#define MOUSE_SCROLL_U 7
+#define MOUSE_SCROLL_D 8
diff --git a/windows/keybuddy2/symbolmap.txt b/windows/keybuddy2/symbolmap.txt
new file mode 100644
index 0000000..91e140c
--- /dev/null
+++ b/windows/keybuddy2/symbolmap.txt
Binary files differ
diff --git a/windows/keybuddy2/uppercase.txt b/windows/keybuddy2/uppercase.txt
new file mode 100644
index 0000000..6d92670
--- /dev/null
+++ b/windows/keybuddy2/uppercase.txt
Binary files differ