Meine Entwicklungsstrategie für private Projekte folgt meist einer Stack-Strategie: je älter die Idee, desto tiefer vergraben, ständig kommt neues Zeugs oben drauf, und in seltenen Fällen findet das jüngste Projekt direkt zur Reife. Und so geschah es mit dem jüngsten Spross meines bunten Straußes an Java-Projekten: KVMPortSwitcher. Wer nur den technischen Sermon lesen und den Code sehen will, darf direkt zum Projekt auf GitHub abbiegen.
Um was geht es? Seit einiger Zeit besitze ich einen “TESmart 16-port HDMI KVM Switch” (das exakte Modell gibt es offenbar nicht mehr, aber hier ist der Nachfolger zu finden). TESmart ist der einzige mir bekannte Hersteller, der KVM-Switches mit 8 Ports und mehr zu einigermaßen bezahlbaren Preisen anbietet und trotzdem problemlos funktioniert – meine Anforderungen damals waren “4K, HDMI, 8 Ports oder mehr, keine Spezialkabel”. Dadurch schrumpfte die Zahl der zur Auswahl stehenden Geräte nach ausführlicher Recherche auf “1”.
Nun gehört alles mit 8 Ports und mehr offenbar üblicherweise der Profi-Fraktion an, und so hat dieser Switch zusätzlich einen Ethernet-Anschluss, mit dem man ihn ins LAN integrieren kann, um ihn so über IP steuern zu können. Warum würde man das wollen? Zum einen zwecks Konfiguration des Geräts. Aber vor allem zur Steuerung des ausgewählten Ports. Denn die anderen Wege, den Port zu wechseln, sind mit verschiedenen Problemen und Nicklichkeiten verbunden, die einem ganz schön auf die Nerven gehen können.
Man kann die Knöpfe an der Front des KVM-Switches verwenden. Prinzipiell keine schlechte Idee, aber beim 16-Port-Modell braucht man dabei für die Geräte 10-16 zwei Tastendrücke. Oder sogar drei, denn wenn der Display-Timeout zugeschlagen hat, dient der erste Tastendruck gar nicht dem Umschalten, sondern dem Aktivieren. Also zwei oder drei Tastendrücke, und man muss natürlich die Hand von der Tastatur nehmen.
Wie wäre es mit der IR-Fernbedienung? Anders, aber nicht besser. Wenn man sie denn mal gefunden hat (vorsichtshalber steht nur “Remote Control” drauf, damit man sie ja nicht klar zuordnen kann), kann man zwar die Ports 2-9 durch einen Tastendruck auswählen, die Ports 1 und 10-16 hingegen nicht – was besonders bei “1” sehr dumm ist, da drückt man auf “1” und wundert sich, dass nix passiert, bis dem Gerät klar wird, dass keine Eingabe mehr erfolgt. Wer jetzt denkt, er könne durch zwei Tastendrücke “0” und “1” das Gerät überlisten, sieht sich getäuscht. auch “1” gefolgt von “OK” hilft nicht. Immerhin braucht es den “Aktivierungstastendruck” wie bei den Front-Panel-Buttons nicht.
Wie wäre es mit der eingebauten Möglichkeit, über die Tastatur den Port zu wechseln? Im Prinzip eine gute Idee, aber: es funktioniert nur mit den im Gerät hartcodierten Shortcuts, und die sind eher komisch, aber natürlich so gewählt, dass sie möglichst nicht mit anderen gängigen Tastatursteuerungen kollidieren: zwei Mal Scroll Lock (aka “Rollen”), dann 1-n. Man erkennt direkt das Problem für die 16-Port-Variante: bei Rollen-Rollen-1 gibt es die von der Fernbedienung bekannte Gedenksekunde, bis klar ist, dass man wirklich “1” meint und nicht “10” oder “13” und nur langsam tippt. Und noch ein Haken: das funktioniert natürlich nur, wenn die Tastatur im dafür vorgesehenen spezifischen USB-Port steckt, der diese Logik enthält – dieser Port ist aber nicht kompatibel mit allen Tastaturen dieser Welt, und so muss man manchmal auf den “nackten” USB-Port ausweichen. Und schon ist es Essig mit der Hotkey-Funktionalität.
Insgesamt gibt es also ausreichend Gründe, alternative Möglichkeiten zum Umschalten der Ports zu suchen. Eine davon bietet TESmart selbst an mit einem kleinen Tool, das eine IP-Verbindung aufbauen kann, dadurch den aktiven Port feststellt und dann per Mausclick das Umschalten erlaubt. Schön, aber natürlich eher keine Verbesserung zu den anderen drei Varianten. Tatsächlich dauert es doch recht lange, bis das Tool endlich den “Connect” hergestellt hat – keine Ahnung, warum. Mehrere Sekunden jedenfalls.
Nun muss man TESmart zugutehalten, dass sie das Protokoll über die IP-Schnittstelle zur Ansteuerung der Funktionalität öffentlich dokumentiert haben – leider muss man solche Dinge ja positiv vermerken, da es sich nicht um eine Selbstverständlichkeit handelt. Jedenfalls ist es denkbar einfach: IP-Verbindung herstellen, ein paar Bytes senden, fertig ist die Laube.
Ich hatte also so ein Projekt schon länger im Hinterkopf – meine Brot-und-Butter-Implementierungssprache Java schien da aber ungeeignet, weil man dort keine systemweiten Keyboard-Shortcuts beim Betriebssystem registrieren kann, und eine weitere grafische Oberfläche, wo man per Click den KVM-Switch bedienen kann, wollte ich nun auch nicht bauen. Zufällig bin ich bei meinen Streifzügen durch das Internet dann aber über eine Bibliothek namens JNativeHook gestolpert, die für alle gängigen Betriebssysteme und CPU-Architekturen native code zusammen mit etwas Java-Glue-Code zur Verfügung stellt, um solche globalen Hotkey-Listener zu implementieren. Kurz getestet, tut, also frisch ans Werk.
Der Code an sich und die UI war natürlich trivial. Kurz noch ein TrayIcon dazugeschraubt (denn für eine Anwendung, die normalerweise im Hintergrund läuft, ist es immer geschickt, noch einen Haken zur Kontrolle derselben zu haben), ausprobiert. Funktionierte – meistens. Denn es gab ein interessantes Phänomen, dass der NativeKey-Event-Dispatcher manchmal, wenn der Port umgeschaltet wurde, munter weiter denselben Event wieder und wieder feuerte. Ich bin dem noch nicht auf den Grund gegangen, aber habe einen klassischen Workaround gefunden: asynchrone Verarbeitung, der Listener löst nicht direkt den Port-Switch aus, sondern scheduled einen extra Thread, der kurz wartet und dann erst umschaltet. Das scheint das Problem zuverlässig gelöst zu haben.
Wer bis hierhin durchgehalten hat, darf jetzt zum GitHub-Projekt abbiegen. Es gibt auch ein runnable jar nebst inkludiertem jnativehook-Jar als Release 0.1.0 zum Download bei GitHub, Java 8 wird zur Ausführung benötigt. Wer also zufällig einen TESmart HDMI-KVM-Switch sein Eigen nennt und ihn in sein Heimnetz integriert (hat), kann direkt loslegen.
Auf der GitHub-Projektseite kann man auch nachlesen, was noch die TODOs sind. Konfigurierbare Port-Namen (bei 16 Ports kann man schon mal den Überblick verlieren), konfigurierbare Keyboard-Shortcuts, i18n (bis jetzt ist alles hartcodiert englisch). Und vielleicht auch noch für die old-school-Generation die Steuermöglichkeit über die serielle Schnittstelle des TESmart-KVM-Switches?