blog · git · desktop · images · contact & privacy · gopher


Die „R-Go Tools Split“-Tastatur und ihre LED unter Linux

2020-12-05

Anfang 2019 hatte ich mich nach „ergonomischeren“ Tastaturen umgeschaut. Mein Job erfordert ständiges Tippen, das ist unausweichlich, also was kann ich da verbessern? Es ist ziemlich offensichtlich, dass das Standardlayout von so Tastaturen echt nicht optimal ist: Man schaue sich nur seine Hände beim Tippen an und bemerke all die Verrenkungen und Verdrehungen, die man da so machen muss.

Viele „ergonomische Tastaturen“ haben eine Art geteiltes Layout, aber nur sehr wenige Modelle sind wirklich geteilt. Ich halte das für ziemlich wichtig, weil ich die beiden Teile dann jeweils in eine Position bringen kann, die für mich gut ist.

Am Ende habe ich ein „R-Go Tools Split Keyboard“ gekauft:

img

Da sind Magnete drin, sodass man es wieder zusammenschieben und so tun kann, als wäre es ein normales Layout – was gut für Besucher und Kollegen ist. (Außerdem kann man dadurch so tun, als breche man das Ding entzwei, was ganz witzig beim Frustabbau ist.)

Eine Weile lang hatte ich dann noch mit Aufstellern mit verschiedenen Anstellwinkeln experimentiert, die ich mit dem 3D-Drucker gemacht habe:

img img

Die haben Gummifüßchen und es sollte noch ein weiteres Teil dazukommen, was sicherstellt, dass der Abstand gleich bleibt.

Hat aber nicht so toll funktioniert. Die Hände können dann nicht mehr auf der Tastatur oder dem Tisch ruhen, man muss sie ständig hochhalten. Bin jetzt kein Ergonomie-Experte, aber es fühlt sich an, als führe das alles nur zu weiterer Belastung und ist’s wahrscheinlich nicht wert.

Allgemein bin ich von der Idee geteilter Tastaturen mittlerweile ziemlich überzeugt. Man kann damit einfach in natürlicheren Winkeln tippen. Sehr angenehm.

Es gibt aber eine wirklich lästige Eigenart an diesem Keyboard: Es meldet sich als zwei Devices am System an. Das verwirrt den Firefox dann ganz massiv (unter X11). Er fragt jedes Mal, wenn er eine „neue“ Tastatur bemerkt, vom X-Server das Tastaturlayout neu an. Bei mir heißt das: Buchstabe „a“ ist auf einem anderen Device als Buchstabe „u“, also sieht der Firefox ständig neue Devices. Habe dem Bug noch nicht hinterhergejagt, sorgt aber dafür, dass der Firefox mit der Zeit immer langsamer und irgendwann unbenutzbar wird, bis man ihn letztlich neustartet. Betrifft aber eben auch nur Firefox, was derzeit nicht mein Hauptbrowser ist. Mit Wayland habe ich’s auch noch nicht probiert.

– Nachtrag 2020-12-18: Ein schneller Test mit Weston legt nahe, dass das Problem mit Wayland tatsächlich nicht existiert. Im Gegenzug ist der Firefox voll von grafischen Artefakten gewesen.

Die LED in der Ecke links oben

Wie man oben auf den Fotos sehen kann, gibt es auf der Tastatur oben links ein „R“. Standardmäßig pulsiert die LED nur. Man kann das mit Fn + A abstellen, was direkt von der Firmware der Tastatur erledigt wird.

Die LED soll eigentlich einen Zweck erfüllen: Der Hersteller bietet eine Software an, die überwacht, wie viel man so tippt, und die dann bei langen Episoden mithilfe der LED an eine Pause erinnert.

Das ist natürlich proprietäre Software, die nicht auf Linux läuft. Ich hätte mir das jetzt mit QEMU zurechtsniffen können, was die denn so tut, war ich aber immer zu faul für. Allem voran habe ich hier gar keine VM mit Windows. Hat mich zwar immer interessiert, ob ich das Ding auch von Linux aus steuern kann, aber am Ende war es nur ein Spielzeug und mir fehlte die Motivation.

Kürzlich habe ich dann den Hersteller einfach mal per E-Mail angeschrieben. Man höre und staune: Die haben geantwortet. Die haben mir tatsächlich gesagt, welche Daten ich an das Device schicken muss, um die LED zu steuern! Ich hatte nie erwartet, irgendwas von denen zu hören, weil Hardwarehersteller in der Regel „schwarze Löcher“ sind, wenn es um Anfragen geht. Aber diesmal nicht.

Die LED unter Linux ansteuern

Die Tastatur gibt sich als mehrere USB-Devices aus:

$ lsusb
Bus 003 Device 008: ID 0911:2188 Philips Speech Processing
Bus 003 Device 009: ID 0911:2188 Philips Speech Processing USB Keyboard
Bus 003 Device 007: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 003 Device 006: ID 05e3:0608 Genesys Logic, Inc. Hub

Die Hubs können wir ignorieren: Oben an der Tastatur sind USB-Buchsen, an denen man ein optionales Numpad anschließen kann. Außerdem ist eben die rechte Hälfte ebenfalls als USB-Device angebunden.

Es gibt aber keine „OUT“-Endpunkte:

$ lsusb -d 0911:2188 -v 2>&1 | grep bEndpointAddress
        bEndpointAddress     0x81  EP 1 IN
        bEndpointAddress     0x82  EP 2 IN
        bEndpointAddress     0x81  EP 1 IN
        bEndpointAddress     0x82  EP 2 IN

Da die Tastatur die normalen LEDs wie Numlock hat und Linux die auch ansteuern kann, muss Linux ja irgendwie Daten an die Tastatur senden können – also wie? Das geht über einen besonderen „control“-Endpunkt, der – wie ich dann gelernt habe – auch gar nicht so besonders ist. Das ist Endpunkt Nummer 0 und der wird von jedem USB-Gerät unterstützt, weil das der grundlegende Kommunikationskanal für sehr viele Dinge ist, inklusive Geräteidentifikation und derlei mehr. Daten hierüber zu senden, wird dann „control tansfer“ genannt.

Wenn man jetzt ein USB-Gerät ansteckt, prüft Linux, ob es das Gerät kennt. Falls ja, dann wird automatisch ein Treiber geladen und ans Gerät gebunden. Bei einer normalen USB-Tastatur passiert das natürlich. Normalerweise ist das dann ein Problem, wenn man seine eigenen Daten senden will: Dafür muss man den Kernel-Treiber wieder deaktivieren, die eigenen Daten senden und dann den Treiber wieder aktivieren. Einerseits dauert das (so etwa 0,8 Sekunden), andererseits ist das Keyboard während dieser Zeit auch nicht benutzbar, weil halt kein Treiber mehr dafür zuständig ist – es verschwindet aus X11 und sonst auch allem.

Zum Glück sind die Daten, die wir da senden müssen, in einem Standardformat: Wir müssen einen „feature report“ senden. (USB hat ganz seltsame Terminologie.)

Man schaue sich kurz Abschnitt 7.2.2 der USB-HID-Spec an:

https://www.usb.org/sites/default/files/documents/hid1_11.pdf

Eine Anfrage vom Typ SET_REPORT mit dem oberen Byte von wValue auf 0x03 bedeutet das Senden eines „feature reports“. In unserem Fall muss die Report-ID auf 0x30 stehen. Und das war’s eigentlich auch schon – das data-Feld muss man der magische Payload sein, um die Farbe auszuwählen:

uint8_t red[]    = {0x30, 0x91, 0x01, 0x00,  0x00, 0x00, 0x00, 0x00};
uint8_t green[]  = {0x30, 0x91, 0x02, 0x00,  0x00, 0x00, 0x00, 0x00};
uint8_t yellow[] = {0x30, 0x91, 0x03, 0x00,  0x00, 0x00, 0x00, 0x00};
uint8_t off[]    = {0x30, 0x91, 0x04, 0x00,  0x00, 0x00, 0x00, 0x00};

Wenn man sich so ein Paket mit usbmon anschaut, sieht es so aus:

usbmon

Das alles lässt sich prima mit den „hidraw“-Devices von Linux machen, denn damit ist das ohne Entladen des originalen Treibers möglich:

https://www.kernel.org/doc/html/v5.9/hid/hidraw.html

Lange Rede, kurzer Sinn: Man öffne die richtige Datei aus /dev und setze einen ioctl() ab. Das war’s. Das kann man aus dem Userspace tun, muss keinen eigenen Treiber dafür schreiben und nichts. Eigentlich ist das … fast schon trivial. Man muss eben nur die Report-ID und den Payload kennen.

Ein normaler User darf das natürlich nicht, weil ihm die Rechte fehlen, also muss man entweder eine eigene udev-Regel hinterlegen oder man nimmt einfach sudo. (Ich habe mich für sudo entschieden, weil das für mich einfacher zu warten ist.)

Das habe ich dann in ein winziges Programm gepackt, um die „R“-LED ansteuern zu können:

https://uninformativ.de/git/r-go-tools-led

Das ist sehr minimalistisch, es steuert wirklich nur die LED und das war’s, sprich, es ist so gedacht, dass man das von anderen Tools aus benutzt. Blinken lassen bei neuer Mail oder wenn der Tee fertig ist oder so. Das kann sich der User dann nach Belieben zusammenbasteln.

(Das Programm ist Linux-spezifisch und nicht portabel. Sind wir mal ehrlich, ich bin sehr wahrscheinlich der einzige Mensch auf dem Planeten, der das jemals benutzen wird. Außerdem ist es wirklich sehr, sehr einfach, das für eine andere Plattform neuzuschreiben. Oder für bessere Portabilität könnte man auch sowas wie hidapi benutzen. Das mache ich vielleicht, wenn ich es mal brauche, aber für den Moment würde ich mir gerne die Abhängigkeit ersparen.)

Der Hersteller hat jetzt nicht gesagt, was als Report-ID zu wählen ist oder dass es überhaupt ein „feature report“ sein muss. Hab’s einfach riskiert, zunächst einen „output report“ geschickt, was nicht funktioniert hat, und dann einen „feature report“. Bei hidraw ist das so, dass automatisch das erste Byte aus dem Payload als Report-ID verwendet wird, was dann gestimmt hat. Also, ja, ein bisschen Glück war schon auch dabei. Oder die USB-Specs fordern das so, aber da habe ich keinen Beleg für finden können. (0x04 zum Ausschalten war auch geraten, weil 0x00 nicht funktionierte.)

Die normalen LEDs wie Numlock lassen sich übrigens fast genauso ansteuern:

https://wiki.osdev.org/USB_Human_Interface_Devices#LED_lamps

Es ist aber nicht besonders praktikabel, das über hidraw zu machen, weil der Kernel seinen eigenen State über die LEDs vorhält. Also, man kann darüber die LEDs schon blinken lassen, aber es kann dann sein, dass der Kernel das wieder überschreibt (zum Beispiel, wenn man normal Numlock drückt). Um die Standard-LEDs zu steuern, ist sowas wie xset led 3 viel ratsamer.

Und was mache ich jetzt mit dem Lämpchen?

Wie gesagt, die originale Software von R-Go Tools beobachtet das Tippen und warnt bei langen Phasen ohne Pause. Und genau dafür benutze ich die LED auch im Moment. In meinem r-go-tools-led-Repo ist ein kleines Skript namens r-go-break-reminder drin, was genau das tut. Das kann man zum Beispiel in die ~/.xinitrc werfen. Ich benutze das jetzt seit einiger Zeit und bin ziemlich überrascht, wie schnell 30 Minuten vorbeiziehen. Kann nur mutmaßen, dass ich bisher die Gewohnheit entwickelt habe, für 1-2 Stunden ohne Pause zu tippen. Uff.

Ich weiß jetzt nicht, ob ich das Skript weiterhin verwenden werde oder die LED für was anderes benutze – oder sie am Ende doch wieder dauernd ausschalte. Bei der ganzen Aktion ging es auch vielmehr darum, das endlich mal mit Linux zum Laufen zu kriegen. Das hat geklappt – und sogar ohne endloses Gefrickel und Reverse-Engineeren. Einfach gefragt und sie haben geantwortet! Das war mal eine angenehme Erfahrung!

Ich mein’, für mich ist es die ideale Lösung, wenn ich einfach nur weiß, welche USB-Pakete ich da hinschicken muss. Da kann ich mir dann was bauen, was genau das tut, was ich möchte. Ich wünschte nur, alle Hersteller würden endlich einfach mal ihre Specs zugänglich machen.

(Aus den unterschiedlichsten Gründen würde ich übrigens die originale Software von R-Go Tools nicht verwenden, selbst wenn es sie für Linux gäbe. Ist eine komplizierte Geschichte und dieses Fass will ich jetzt nicht aufmachen.)

Comments?