Keyboard module with a non-US keyboard?

I am building a special low radiation keyboard.
Every single key is properly registered, and if I send the characters I decode through the serial interface, the correct show up on the serial monitor. Including the non-US characters (Danish).

If I send the very same characters through the Keyboard interface ( Keyboard.write(Key); ) Characters a-z, A-Z and 0-9 all work fine.
Backspace, Enter, arrows, Home, End etc all seem to work.

The more ‘strange’ characters, however, may be there, but on the wrong keys! Or not at all.
Comma and decimal point do come through correctly, but adding shift give me, what fits an US- keyboard (< and >). On a DK keyboard, however, and the characters I actually do put into Key before transmitting, are ; and :.

The data I put into the Key parameter is the correct Ascii value for the character, I want to transmit, but Arduino seems to have its own mind about what to transmit.

How to get around this, or can Arduino not handle anything but specifically US layout?
Is it actually something else, the Keyboard module transmits?
Where to find a translation?
That fits a non-US keyboard! They are sort of hard to get by on this side of the Atlantic!

My hardware is a clone of Pro Micro (32u4 chip)

My device is to work on a Chromebook and under Windows. With or without extended character set enabled. The keyboard do have DK character keys, but they may not be used. Normal US keyboard characters must be handled from the keys showing them. NOT where an American would like them to be!
I use an old keyboard with all electronics stripped out, thus only the key matrix. Decoding (passive scanning) is done by my code and some special hardware!

A keyboard does not transmit characters, like “a” or “b” nor ASCII numbers. It does transmit something like “key numbers” (scancodes). So the transmitted information is more like: key number 2 on row 4 was pressed (or released).

The only difference between a Danish a German or an US keyboard is the printing on the keys, but the hardware is completely the same.
The operating system on your computer with the language settings interpretes the information comming from the keyboard and “produces” the characters that appear on the screen.
So the example (“key 2 on row 4”) would lead to the letter a on computers in the US, in Germany and Denmark (with appropriate language settings) because “a” is on the same spot.

Arduino Leonardo and Micro (ATmega32u4) use US keyboard layout.
There is no (easy) way to switch to an other language layout.

There are some workarounds. The one I prefer is using scancodes.
You can find the scancodes of an USB-Keyboard here (US layout): USB HID usage table (see #7 Keyboard).

For some reasons Arduino keyboard functions will treat values below 128 (0x7F) as “printable” so it will look them up in a table of ascii keycodes. This is not what you want. To get past that you have to add 136 (0x88) to the scancode.

To find out what scancode produces what letter (or F key and so on) with your language settings you can use a simple test sketch like this:

#include "Keyboard.h"

void setup() {
  delay(7000);   // to get you some time to switch to your editor


  for (int i = 0x04; i < 0x38; i++) {
    int j = i + 0x88;
    Keyboard.print(j, HEX);
    Keyboard.print(" ");

    Keyboard.print("  ");;


void loop() {

This will “print” the result of several scan codes without and with the shift key pressed simultaneously.
A text editor should be active when running this code.
The scancodes can be used with Keyboard.write(nnn) and

An å on your Danish computer should appear with:


But I could not test this (with my German language settings). :slight_smile:

Thanks, that did provide quite some help!

I had figured out that a limited keyboard layout was in use, and I am now doing all testing in an US environment. And I try to convert those relatively few characters that need it.
DK characters now work fine transmitted as AltGr + Z, L and W on the US extended keyboard.

Coming to your little sketch.
It delivers 94 visible character, plus Space, I guess. Making it the expected 95.

I have encountered a peculiarity with that, however.

0xB5 - _
0xB6 = +
0xB7 [ {
0xB8 ] }
0xB9 \ |
0xBA \ |
0xBB ; :
0xBC ’ "
0xBD ` ~
0xBE , <
0xBF . >

As you can see for 0xB9 and 0xBA I am missing the ‘/’ + ‘?’ key!
If that key is somehow unavailable on my system, it could explain why I have not been able to work my way around those particular characters today.

As much as I know 0xB9 and 0xBA are the same signs with most keyboard language settings.

But there is some error - I am sorry for that:
Just change line

for (int i = 0x04; i < 0x38; i++) {


for (int i = 0x04; i < 0x39; i++) {

I suppose you may get the missing signes at 0xC0.

You can even go with higher numbers - take a look at the scancode table (USB HID usage table):

0x37	Keyboard . and >
0x38	Keyboard / and ?
0x39	Keyboard Caps Lock
0x3A	Keyboard F1
0x3B	Keyboard F2
0x3C	Keyboard F3
0x3D	Keyboard F4
0x3E	Keyboard F5
0x3F	Keyboard F6
0x40	Keyboard F7
0x41	Keyboard F8
0x42	Keyboard F9
0x43	Keyboard F10
0x44	Keyboard F11
0x45	Keyboard F12

But take care, there are the F keys which may start some special functions, depending on the software. So you may lose control of your computer. :slight_smile: