How to add new Keyboard Layout to Arduino IDE

victor

Member
Hello to everybody! I need to add Russian Keyboard Layout to Arduino IDE.
Please hint me what I have to do. Search an open source code, correct and compile it?
Yes, I am ready for it. From which point I must begin?:confused:
In a case of successfull I will upload new source code to Arduino's site.
Thanks.
 
Wikipedia says there are several Russian keyboard layouts.

Is this the keyboard you have?

http://www.microsoft.com/resources/msdn/goglobal/keyboards/kbdru.html

How do you type ordinary latin (eg, for English) characters on this keyboard?

The keyboard layouts are in keylayouts.h, in hardware/teensy/cores/teensy3 for Teensy 3.0 and hardware/teensy/cores/teensy for Teensy 2.0.

Currently the USB keyboard code only supports up to 10 unicode characters beyond U+00FF. To support this keyboard, the function unicode_to_keycode() in usb_keyboard.c will need to be redesigned to allow a large table instead of merely 10 special keys.
 
About second link:
My keyboard is very similar to this picture but not exactly the same. For typing
latin symbols each button has "second name" - latin symbol, look at this photo:
http://www.google.ru/imgres?imgurl=...a=X&ei=kuxhUtqnJuOU0AWCkIHoBg&ved=0CDAQ9QEwAg
This is exactly the same (excepting Moon-button: I have not it).

I have to note: this is a picture of keyboard (device), not of "keyboard layout".

I have few computers and few (different) keyboards, but I have the only one russian
"keyboard layout". Under WinXP and under Win7 - the only one russian "keyboard layout".

I think I can do programming self-test of my russian "keyboard layout" by this way:

while (symb != KEY_ESCAPE)
{
symb=getchar();
printf("symb=%c %x \n",symb,symb);
}

Would it be correct?
If "yes" then I need make a little addition to files "keylayouts.h", ok?
Or send you this addition? Or send it to Arduino site?
Thanks.
 
Supporting Russian keyboard layout will require substantial changes in the code. Changing keylayouts.h is only part of the issue. Other code must change, because the software only supports latin characters plus up to 10 non-latin. Obviously the code must be improved. I can try to help, but I need much more specific information.

The biggest question I have is regarding this:

For typing latin symbols each button has "second name" - latin symbol, look at this photo:

That photo helps. :)

But I do not understand what specific key actions are used to select the latin character vs cyrillic character. For example, the "Q" key can type 4 possible characters: "Q", "q", "Й" and "й". Also pressing the shift key at the same time makes the difference between "Q" and "q". Does shift also cause "Й" vs "й"?

What key(s) are pressed to change between "Q" and "Й"?

On European keyboards, the extra functions on the key are usually selected by holding the right Alt key. For example, on this German keyboard layout, that key can type "Q", "q" and "@". To type "Q", the shift key is pressed at the same time. To type "q", the key is pressed alone. To type "@", the right-Alt key is held while the key is pressed. (notice the Alt key to the right of the space bar is blue with "Alt Gr").

I know this question probably seems obvious if to you, but please remember I do not have a Russian keyboard and I have never used any computer configured for such a keyboard.
 
Perhaps I should write a bit more explanation about the coding?

I think I can do programming self-test of my russian "keyboard layout" by this way:

It's much more work.

Suppose you write this program in Arduino:

Code:
void setup() {
}

void loop() {
  delay(5000);
  Keyboard.println("Russian, Русский")
}

Every 5 seconds, Teensy will attempt to type that string. You didn't mention if you're using Teensy 2.0 or 3.0, so I'm going to assume 3.0 and talk about the code in hardware/teensy/cores/teensy3. The println() code is in Print.h, where an inline function will replace this with write(str, strlen(str)), which then calls the single-byte write() function, defined in usb_keyboard.h, which is inline translated to usb_keyboard_write().

So the interesting code is usb_keyboard_write() in usb_keyboard.c. If you read that code, you'll see it's a UTF-8 parser. The strings are UTF8 encoded. Those latin characters are a single byte. The cyrillic characters are 2 bytes. The UTF8 parser calls usb_keyboard_write_unicode() with the 16 bit unicode for each actual character.

The first step within usb_keyboard_write_unicode() is turning the unicode number into a "keycode", by calling unicode_to_keycode(). A "keycode" is a number that contains information about the specific key sequences needed for the keyboard to type that unicode character. The exact definition of the keycode differs depending on the selected language.

Some languages use "dead keys". If such a language is selected, the keycode is checked if a deadkey press is needed for this character, and if so, the specific dead key is looked up and the keyboard action is taken by calling write_key(). Then the keycode is used with write_key().

The write_key() function separates the keycode into the actual key to be pressed, plus any of the modifiers (shift, control, alt-gr), and then it calls usb_keyboard_press() to actually transmit a pair of USB packets to press and release the key.

As you can see, this process is quite complex, to translate any string with any UTF8 encoded international characters into the sequence of USB packets to "type" each character.

To support Russian, first the mechanism to select latin vs cyrillic needs to be implemented. I do not know how that works on Russian keyboards. It is the same as the Alt-gr and deadkeys mechanisms used on European keyboards, then the existing code can work. The correct deadkey and alt-gr definitions only need to be created in keylayouts.h.

But if Russian uses some different mechanism to select between latin and cyrillic, obviously the code in usb_keyboard_write_unicode() would need to be updated to implement that mechanism.

Another challenge in the code is unicode_to_keycode(). If you look at that code, you'll see if supports only up to 10 non-latin (greater than U+00FF) conversions from unicode to keycodes. So that function will need to be expanded to support all the necessary cryillic characters. Simply replicating the code probably isn't a good plan. The fixed 10 checks probably needs to be changed to some more memory-efficient approach, like an array of unicode-keycode pairs to be searched?

Then, of course Russian needs to be added in keylayouts.h, and boards.txt. If an array is used for beyond U+00FF, code to generate that array needs to be written in keylayouts.c.


Hopefully this lengthy message helps explain the massive work needed in the software. I am actually interested in doing much of this work. There are 2 main reasons I have never attempted to implement non-latin keyboards. #1: I do not know how they work (exactly what key presses are used to select latin vs cryillic), and #2: I need someone like you to help test and verify if the code actually works on real computers in Russia....
 
Wikipedia says there are several Russian keyboard layouts.
How do you type ordinary latin (eg, for English) characters on this keyboard?
From the wikipedia article you linked to:
Keyboards in Russia always have Cyrillic letters on the keytops as well as Latin letters. Usually Cyrillic and Latin letters are labeled with different colors.

Currently the USB keyboard code only supports up to 10 unicode characters beyond U+00FF. To support this keyboard, the function unicode_to_keycode() in usb_keyboard.c will need to be redesigned to allow a large table instead of merely 10 special keys.
Yes, clearly this is needed for most languages. I recall that you held off doing so until users of those lannguages specifically asked for it.
 
Well, I just tried to set up Windows 7 test machine up, but it seems only the expensive Windows Ultimate supports installing Russian language. Frustrating!

Not so (but perhaps you mixed up installing a per-user complete user interface language, which is indeed a corporate (Ultimate) feature; with installing keyboards, which is available in all versions).

Here is a screenshot of Windows 7 'Home' adding a Russian keyboard (there are several options - Russian, Russian Typewriter, ...).

These seem to correspond to the «Русская» and «Русская (машинопись)» options on the Russian wikipedia page, where an Apple option is also listed.

The layout on adding 'Russian' seems to correspond to «Русская» in the wikipedia article.
 

Attachments

  • addrussian.png
    addrussian.png
    30.3 KB · Views: 288
  • russian-win7.png
    russian-win7.png
    29.2 KB · Views: 1,041
Last edited:
Having installed it, I'm unable to see how the Windows Russian keyboard supports Latin. Here are the results from typing the Q to Y keys, first alone and then with shift
йцукен
ЙЦУКЕН
left alt and right alt as combining keys produced no output. There must be some other dead-key combination.
 
Last edited:
First of all I have to say very big "thank you" for this "lengthy message". It really
"helps explain the massive work needed in the software".

I will try to answer to your questions.

"#1: I do not know how they work (exactly what key presses are used to select latin vs cryillic)."

<Alt>+<Shift> selects latin on my computers. The second <Alt>+<Shift> selects cyrillic.
Any combination of <Left_Alt>+<Right_Shift>, <Right_Alt>+<Left_Shift>, <Right_Alt>+<Right_Shift>,
<Left_Alt>+<Left_Shift> in any sequence is good. The pressing and releasing of this changes
"keyboard layout". (It may be 3 or 4 or more keyboard layouts, these "hot keys" go by circle
along them.)
This works under WinXP and under Win7 Prof.

But there is one computer with Server 2003 at my work, <Ctrl>+<Shift> selects latin/cyrillic
there. I think it depends on system settings (or installation disk?). (Many years ago I had an
installation disk WinXP which asked the question about "hot keys" for switching "keyboard
layout" during installation.)

"#2: I need someone like you to help test and verify if the code actually works on real
computers in Russia".

Be sure! I will do testing as hardly as it needs.
----------------------------------------------------

Addition to #1:
Yes, I see that "this process is quite complex". Due of that I have to say the next:
I know there is special method "ActivateKeyboardLayout(hkl, flags);" in C++ but I do not
know in what class. I have never worked wtih it but now I try to work.

It could be greatly if some Arduino's class (Keyboard or Serial) had such method.
I think there is similar function in some system DLL. I will try to learn all about it
and then let you know.
 
Ok, I installed the Russian keyboard. In Notepad, pressing Alt-Shift switches to Russian.

I also can not find any way to type latin characters from the Russian keyboard. Victor, what is the secret trick?
 
After more searching, I found this thread on another forum. Message #2 and #40 have really good info.

My computer must have same problem as mentioned in #40, where Alt-Shift can change my layout to Russian, but it can't change back to English once in Russian mode.

Even if Alt-Shift changes between Russian & English, I do not see how this can work for Teensy, because Teensy does not have any way to see your screen.

For a human using Alt-Shift, you know if the computer is in English or Russian mode. The task bar is supposed to show an icon (my computer does not, but I've seen screenshots of others that do). You also know because you've been typing and you can see which characters appear. Visual feedback from the computer screen is required to use this Alt-Shift mechanism.

But Teensy can not see the computer screen. It does not know if the computer is currently in English or Russian mode. When you use Serial.print("q"), Teensy may need to send Alt-Shift before the key code, to change back to English mode. But if the computer is already in English mode, sending Alt-Shift will switch to Russian and the cyrillic character "й" will be received instead of "q". The same problem would occur from cyrillic characters, Teensy can not know which mode the computer is currently using.

I really do want to make this work. I'm open to ideas. But so far, I do not see any reliable way.
 
I tried that, set the keyboard to russian, typed, got cyrillic. Pressed alt-shift and indeed got latin. Also, the taskbar indicator switched from RU to EN. In other words, that combination appears to switch between virtual keyboard layouts. More specifically, it switches to whatever you have set as the default keyboard 9which is why the same combination does not switch back).
I suspect therefore that an actual physical russian keyboard uses some different mechanism.
 
Paul, please give me links to messages #2 and #40 (I couldn't find).

May be it is offtopic, sorry, but may be it will be usefull for you:
there is a method "GetKeyboardLayoutList(HKL *phkl, DWORD flags);" in C++.
This C-code:

int nBuff=0; // layout’s count
TCHAR szKeyboard[KL_NAMELENGTH];
HKL *phkl=NULL, *phkl1=NULL;
// Keyboard layout structure
typedef struct
{
HKL hArabic;
bool bArabic;
HKL hEnglish;
bool bEnglish;
HKL hRussian;
bool bRussian;
HKL hUzbek;
bool bUzbek;
} KBDLAYOUT;
KBDLAYOUT myKbds;

int get_layout_list()
{
nBuff=::GetKeyboardLayoutList(0, NULL); // get layout's count
if ((phkl = new HKL[nBuff])==NULL) // create array for layouts
{
printf("get_layout_list: phkl=%8.8x - Out of Memory!\n",phkl);
return -1;
}
// printf("nBuff=%d phkl=%8.8x \n",nBuff,phkl);

// setting default values (as not installed = false)
myKbds.bArabic=false;
myKbds.bEnglish=false;
myKbds.bRussian=false;
myKbds.bUzbek=false;

// Get and parse layout items
::GetKeyboardLayoutList(nBuff,phkl); // fill layout's array

// iterate through list to check needed layouts
for(int nKeyboard=0; nKeyboard<nBuff; nKeyboard++)
{
::ActivateKeyboardLayout(phkl[nKeyboard], KLF_SETFORPROCESS);
GetKeyboardLayoutName(szKeyboard);
printf("szKeyboard=%s \n",szKeyboard);
if(strcmp(szKeyboard,"00000401")==0)
{
myKbds.bArabic=true;
myKbds.hArabic=phkl[nKeyboard];
}
if(strcmp(szKeyboard,"00000409")==0)
{
myKbds.bEnglish=true;
myKbds.hEnglish=phkl[nKeyboard];
}
if(strcmp(szKeyboard,"00000419")==0)
{
myKbds.bRussian=true;
myKbds.hRussian=phkl[nKeyboard];
}
if(strcmp(szKeyboard,"00000843")==0)
{
myKbds.bUzbek=true;
myKbds.hUzbek=phkl[nKeyboard];
}
} // eind of for

printf("Arabic=%d Eng=%d Rus=%d Uzb=%d \n",
myKbds.bArabic,myKbds.bEnglish,myKbds.bRussian,myKbds.bUzbek);
printf("Arabic=%8.8x Eng=%8.8x Rus=%8.8x Uzb=%8.8x \n",
myKbds.hArabic,myKbds.hEnglish,myKbds.hRussian,myKbds.hUzbek);
delete [] phkl;

if(!myKbds.bEnglish) printf("English(USA) keyboard layout not installed");
if(!myKbds.bRussian) printf("Russian keyboard layout not installed");

if(myKbds.bEnglish)::ActivateKeyboardLayout(myKbds.hEnglish, KLF_SETFORPROCESS);
hkl=GetKeyboardLayout(0);
printf("hkl=%8.8x \n",hkl);

return nBuff;
} // eof "get_layout_list()"

is workable. But it switches layout only for his own window, I don't know why.
 
Yes, Teensy can not see the screen, but may be Teensy can know about KeyboardLayoutList?

About russian letters on keyboard:
1. to draw russian letters with marker;
2. special self-adhesive labels with russian-letters-pictograms from computer shop.
As you can see, I have no any "secret tricks".
 
If you can not switch back to Latin, may be you need to look at the
menu "Control Panel -> Languages and Regional standarts -> Languages and keyboards ->
Change Keyboard -> Switching Keyboard" and do some settings?
 
It seems to me that we may have been looking at theis the wrong way. Based on other keyboards that use dead-keys, we were asking "how do you make a russian keyboard produce latin keys" and then getting various platform-specific methods.

Because the actual answer is "you can't. It produces cyrillic letters only. To make latin, you switch to another keyboard".

Thus, from a Teensyduino/Arduino perspective, the current USB keyboard selection is done one time, in the IDE; you select USB keyboard and you select (one) keyboard type. While what is needed is to select one (default) keyboard and then, from within the sketch, have a way to switch between keyboards. So you would have, in the sketch, something along the lines of (this is all hand-wavy as regards naming conventions)

Code:
Keyboard US("US English");
Keyboard RU("Russian");

EN.activate();
Keyboard.print("Hello World "); 
RU.activate();
Keyboard.print("привет мир ");

I'm suggesting that each Keyboard object be explicitly instantiated in the sketch, so that you don't pull in definitions for every keyboard in existence.

or maybe

Code:
EN.print("Hello World "); 
RU.print("привет мир ");
 
Victor, are you still here? If this is ever going to be made, I will need your help with feedback and testing.

Nantonos, runtime selectable layouts is not a direction I'm likely to take. The code is all designed for a single layout configured at compile time, which makes the code much smaller and more efficient. I'd like to support more layouts, and I'm willing to add some code to do so, but I just don't see such a large change as feasible. There's only so many hours I can spend programming every day, and I have a LOT of projects all demanding more of my programming time!

A single Russian layout could have keycodes for both Cyrillic and Latin characters. If the PC is configured for Russian and you key Keyboard.print("Hello World"), you'll get "Руддщ Цщкдв", but at least Teensy will send the correct keystrokes.

The one part where I'm not sure what to do is characters that exist on both layouts. For example, with "...", should Teensy send the key next to the right shift, which is "." on the Russian layout, or the next left, which is its location on an English keyboard? All the code is designed for a mapping from unicode characters to a one (perhaps complex) sequence of codes to send to the PC to type that character.

Maybe a partial solution that at least supports Cyrillic characters would be a good start, even if some other difficult issues aren't resolved?
 
Another rethink. Paul, your responses and mine both make the assumption "this is about Teensy in USB keyboard mode". The thread title, and Victor's mention of Windows APIs for keyboards, now makes me wonder whether the actual question is entirely different: "How do I use the Russian keyboard on my PC when using the Arduino IDE". Just a thought. The original poster would need to confirm the intent.

About runtime selectable layouts: ok, it was just an idea. I think the main problem here is that the original Arduino design of keyboard.print(arbitrary unicode string) rests on some flawed assumptions about the nature of that mapping; assumptions which aren't so visible in a us-ascii or latin-1 context.
 
Good point on the original question.

I still do want to add other keyboard layouts for Keyboard.print(), working with the current system and adding relatively small amounts of code, like removing the 10 non-latin key mapping limit. The main limitation is finding people who actually use those systems for testing and verification.

As a matter of history, I do not believe there ever was an "original Arduino design" for Keyboard.print(). The UTF8 encoding was inherited from Processing. I created the first non-Serial board compatible with the Arduino IDE and most libraries. I wrote Keyboard.print() about 2 years before Massimo announced Leonardo. Even the non-US keyboard mappings were started before then. Has Arduino ever done any of this non-US keyboard stuff in their code?
 
Removing the 10 non-latin limit would be excellent.

The more i learn about keyboards the more i see that the only beneficiary of their current design is keyboard manufacturerrs (same electronics, just different plastic mouldings for keycaps). Everyone else - OS designers, application developers, users - suffers. In theory there is a USB device that emits straight UTF-16 Unicode but the spec looks both old and very draft-like. I suspect there is no OS support.

Thanks for the history. I don't have a Leonardo nor do I see any point in getting one; there seems to be zero ongoing effort on the keyboard and mouse support or on adding other USB types.

Out of interest for the history, what were the release dates for Teensy 1, ++1, 2, and ++2?
 
Yep. I've been told the keyboard manufacturers exerted a lot of influence in creating the USB and HID standards in the early 1990's. Apparently there were very heated discussions where developers felt keyboards should enumerate with useful info, but the keyboard manufacturers insisted they must keep costs low by making exactly 1 electronic and physical design and then just print different stuff on the keys. Obviously "cheap" won over "good".

Teensy 1.0 was designed in late 2008 and I believe we started shipping in December. Teensy++ 1.0 was released in March 2009. I don't know exactly when the 2.0 versions came, but I believe it was later in 2009. I recall having a prototype built from 32u4 sample only a month or two after 1.0 started, but we had to wait the better part of a year before Atmel actually sold any 32u4 chips through distributors. I know it was sometime in mid-2009. It was also sometime mid-2009 when Teensyduino got keyboard and mouse support. I believe the work on USB MIDI, USB Disk, and international keyboard support mostly happened in 2010.

Teensy became more widely known in the Arduino world towards the end of 2010. Before 2011, Teensy sales were very slow and my development time was split between Teensy and several private consulting projects. In 2011, I worked to port most of the Arduino libraries that existed at the time, and I developed many optimizations and improvements to Arduino.

Arduino Leonardo was announced at the New York Maker Faire in September 2011. Sparkfun and others started shipping clones based on the buggy beta test bootloader Arduino in early 2012. Leonardo was officially released at San Mateo Maker Faire in May 2012 (apparently only 50 units were sold), and actually became widely available in July 2012.

I spent most of 2012 developing Teensy 3.0, which released in September 2012 with a Kickstarter campaign.

In early 2013 I ported many libraries and worked on a lot of minor AVR compatibility issues, and also developed OctoWS2811. Recently I've been working on the audio board and library, which you'll see soon, and a couple other things which I can't talk about until they release next year....
 
Back
Top