Hotkey Node Module
In diesem Post erläutere ich, wie ich ein ein natives Hotkey Modul für einen Discord Soundboard Bot entwickelt habe.
Ich habe sehr lange darüber nachgedacht ob ich das hier der Öffentlichkeit zugänglich machen sollte, da ich mir dessen bewusst bin das man auch viel Unsinn damit anstellen kann.
Allerdings entstand es aus einen Projekt, das mir durch eine sehr schwere Zeit half und wo sehr, sehr viel Herzblut drin steckt. Ich würde es gerne der Nachwelt erhalten und habe mich entschieden in Teilen zu erläutern wie ich vorgegangen bin.
Eine kurze Einführung
Ich habe an einem Soundboard - Bot für Discord gearbeitet. Er sollte sich in Voice Channel verbinden und dann mittels klicken auf Buttons lokale MP3 Dateien streamen. Den Bot habe ich mit Node.js und Electron realisiert.
Ich glaube das war mein aller erster Gehversuch mit Electron und ich hatte vorher aus gesundheitlichen Gründen sehr lange nicht mehr programmiert. Dementsprechend sah der Code auch aus.
Mir erschien es Sinnvoll die Buttons auch per Hotkey auslösen zu können. Das Feature war nicht angefragt und wurde vermutlich auch nicht genutzt. Ich wollte das einfach machen, weil ich es als äußerst interessant empfand.
Relativ schnell wurde mir klar das Electron so etwas nicht standardmäßig bietet und ich da selbst etwas schreiben muss.
Das Module
Die Entwicklung des Bots zog sich über gut 2 Jahre und in der Zeit hat sich sehr viel an der C++ API für Node getan. Zudem war ich bestrebt die Electron Version aktuell zu halten und damit musste ich auch das Module mehrmals anpassen. Mit den neusten Entwicklungen sollte das allerdings ein Ende haben.
Hotkey Klasse
Die Klasse sollte die übergebenen Werte der Hotkeys halten. Die Hotkey Structure besteht eigentlich nur aus zwei Integer Variablen. Wenn ich das heute machen würde, dann vermutlich nur mit der struct Hotkey
und den Vector.
KeyWorker Klasse
Die KeyWorker Klasse ist ein Child von Napi::AsyncWorker
und implementiert die nötigen Methoden zum Ausführen und beenden des Worker Threads.
An der Execute()
Methode kann man sehr schön sehen warum man einen Worker Thread benötigt. Es wird in einem Loop permanent geprüft ob ein Tastendruck einem Hotkey entspricht. Das würde natürlich den Event Loop blockieren sollte man das ohne Threading lösen. Das Modul musste nur unter Windows kompilieren von daher reichte es die Win API Funktion GetKeyState()
zu nutzen.
Die while()
Schleife läuft so lange wie run = true
ist und die Stop()
Methode setzt lediglich run = false
. Somit kann man von außen das Beenden des Workers triggern.
Falls ein Hotkey gedrückt wurde, wird der Worker beendet und eine Callback Funktion aufgerufen. Die Parameter sind die Charcodes für Modifier (Shift | Alt | Ctrl | no-mod) und Hotkey. Der Wert für no-mod entspricht 0.
Node Integration
Es werden zwei Funktionen für JavaScript zugänglich gemacht. Stop()
beendet den Worker und Listen()
startet ihn.
Mit dem hier beschriebenen Code kann man eine Hotkey kombination abfragen und dann beendet sich der Worker. Die JavaScript Callback Funktion ruft die Hotkey entsprechende Callback Funktion auf und startet mit der
Listen()
Funktion den Worker erneut. Vorab müssen die Hotkeys noch speziell sortiert werden.