Arduino Leonardo und das Keyboard-API-Problem

Nachdem ich letztens die erste Revision meines Hardwareprojektes fertiggestellt habe, habe ich nun damit begonnen, die eigentliche Ein- und Ausgabe zu entwickeln. In meinem Fall soll das Arduino als eine Art Tastatur dienen. Mit dem Arduino Uno war das leider nicht möglich...

...glücklicherweise gibt es seit letztem Jahr das Arduino Leonardo, das eine eigene Keyboard-API mitbringt. Damit kann es normale Tastenanschläge an den Computer senden - wie eine richtige Tastatur. Das ganze hat jedoch einen Haken: Tastaturen sind komplizierter als man denkt.

Die Zeichen, die man normalerweise auf dem Computer sieht, werden als sogenante ASCII-Codes dargestellt. Tastaturen, wie man sie alltäglich verwendet, kennen jedoch kein ASCII. Sie verwenden sogenannte Keycodes, die erstmal in ASCII-Codes umkodiert werden müssen. Welcher Keycode nun genau welches Zeichen darstellt, das definieren die so genannten Universal Serial Bus Human Interface Device Usage Tables (kurz: "HUT") in Kapitel 10. Dort findet man die "Keyboard/Keypad Page" des USB-Standards. Die dort beschriebene Zuordnung gilt jedoch nur für amerikanische Tastaturen. Hierzu gibt es im Dokument sogar einen entsprechenden Hinweis:

A general note on Usages and languages: Due to the variation of keyboards from language to language, it is not feasible to specify exact key mappings for every language. Where this list is not specific for a key function in a language, the closest equivalent key position should be used, so that a keyboard may be modified for a different language by simply printing different keycaps. One example is the Y key on a North American keyboard. In Germany this is typically Z. Rather than changing the keyboard firmware to put the Z Usage into that place in the descriptor list, the vendor should use the Y Usage on both the North American and German keyboards. This continues to be the existing practice in the industry, in order to minimize the number of changes to the electronics to accommodate other languages.

Hier nun das Problem des Arduino Leonardo: Dem Arduino kann man nicht den Keycode mitgeben, das er an den PC senden soll. Dieser könnte anhand der Spracheinstellung des Betriebssystems herausfinden, welches Zeichen auf der Tastatur gedrückt worden ist. Stattdessen muss man dem Arduino ein ASCII-Zeichen übergeben und er wandelt es dann in den entsprechenden Keycode um. Dummerweise sind auf deutschen und englischen Tastaturen zum Beispiel die Buchstaben Y und Z vertauscht. Der Arduino selbst geht aber IMMER davon aus, dass man ein englisches System verwendet. Wenn man nun dem Arduino sagt, er soll ein Y an den PC schicken, wandelt er dies in den Keycode für das amerikanische Y um und schickt es an den PC. Wenn der nun auf Deutsch gestellt ist, denkt er, dass ein Z geschickt worden ist. Hier mal ein Beispiel dazu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void setup() {
  Keyboard.begin();
 
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
}

void loop() {
  while (digitalRead(2) == HIGH) {
    delay(500);
  }
  delay(1000);
 
  // prints "qwerty" on German OS
  Keyboard.print("qwertz");
}

Das ist nicht nur sehr schwer zu verstehen, sondern auch noch sehr umständlich. Denn es gibt keine Möglichkeit, selbst die Umwandlung in die Keycodes vorzunehmen. Dann könnte man das in Abhängigkeit der gewünschten Sprache sehr einfach implementieren. Stattdessen muss man gucken, welchen Text man ausgeben will und muss das in eine falsche ASCII-Repräsentation überführen. Aus diesem Grund habe ich hierzu auch ein Issue beim Arduino-Projekt eröffne. Da ich am Wochenende ein wenig Zeit hatte, habe ich mich zudem mal in den Arduino-Quelltext eingegraben und selbst eine mögliche Lösung implementiert. Mit der kann ich jetzt schon einmal weiterarbeiten, bis die offizielle Lösung zur Verfügung steht.
Sprachabhängige Grüße, Kenny