Make your own custom keyboard layout for Linux

An introduction which may be safely skipped

A desire for custom keyboard layout is not very common, but it is in no sense unique. Usually, an interest to fancy keyboard layouts is inherent to multilingual persons. They are programmers, translators, journalists, (archeo-) linguists, touch-typists and simply people who do not have characters of their second or first language printed on the keys of their keyboards.

Common denominator of their reasons for such a desire can be expressed in one word: convenience. Consider a rather typical case well described here: https://michal.kosmulski.org/computing/articles/custom-keyboard-layouts-xkb.html

My own story is more intricate and involves a number of not uncommon reasons. I used to type a lot in Cyrillic and Latin alphabets and the mix of them. Four-finger typing and endless switching between layouts became a considerable burden soon enough and the task of teaching myself touch-typing became really urgent. Therefore I began to reckon my situation. Qwerty layout was not optimal for typing in Latin but there existed its optimized variety for English language, i.e. Dvorak layout. Legacy Cyrillic layout was not optimal for typing as well but there were no optimized Dvorak-like layout for Russian at all. At the same time I typed more in Cyrillic than in Latin. Next to it, the mere idea of learning two completely different layouts was much less than attractive however optimal they could be, which they were not.

Long story short, I have gathered a body of texts, extracted characters' and character combinations' frequencies and used Dvorak's principles to compose (hopefully efficient) keyboard layout for Russian language (GNR). Since then I have phonetically mapped keyboard layout for English language (GNE) to it while preserving punctuation marks placing. After having gained enough practice in touch-typing uising GNR and GNE, the first variant of these layouts was corrected according to the actual experience to rebalance stress on the right and left wrists and different fingers. Very soon I could not believe I managed to live without my layouts and touch-typing wasting my life time at keyboard in vain. And I enjoyed my layouts happily ever after.

Actual instructions on making proprietary keyboard layout

In general, you have to prepare your keyboard layout description file and to add your keyboard layout to the list of available keyboard layouts. The second feat requires superuser privileges. Detailed instructions follow.

  • Ensure that you know how characters will be placed on keys of your keyboard. For example:


  • Familiarize yourself with characters and keyboard keys naming conventions by reading symbol files for your language in /usr/share/X11/xkb/symbols directory. Please note, that symbol files do not necessarily denote alphabetic characters as you see them typed. Next to it, keyboard physical keys are assigned specific codes as follows:

  • Think out a short abbreviated name for your layout. GNR and GNE names are used in examples.

  • Create empty file with selected name and paste a template code into it. Feel free to use any of two examples below.


//   GNR         UGNVS, Russian

default partial alphanumeric_keys
xkb_symbols "basic" {

    name[Group1]= "GNR";

    // Alphanumeric section
    key <TLDE> {	[     grave,	asciitilde	]	};
    key <AE01> {	[	  1,	exclam 		]	};
    key <AE02> {	[	  2,	question	]	};
    key <AE03> {	[	  3,	slash		]	};
    key <AE04> {	[	  4,	dollar		]	};
    key <AE05> {	[	  5,	percent		]	};
    key <AE06> {	[	  6,	less		]	};
    key <AE07> {	[	  7,	greater		]	};
    key <AE08> {	[	  8,	asterisk	]	};
    key <AE09> {	[	  9,	parenleft	]	};
    key <AE10> {	[	  0,	parenright	]	};
    key <AE11> {	[     minus,	underscore	]	};
    key <AE12> {	[     equal,	plus		]	};

    key <AD01> {	[ Cyrillic_pe, Cyrillic_PE	]	};
    key <AD02> {	[ Cyrillic_de, Cyrillic_DE	]	};
    key <AD03> {	[ Cyrillic_em, Cyrillic_EM	]	};
    key <AD04> {	[ Cyrillic_ka, Cyrillic_KA	]	};
    key <AD05> {	[ Cyrillic_ze, Cyrillic_ZE	]	};
    key <AD06> {	[ Cyrillic_be, Cyrillic_BE	]	};
    key <AD07> {	[ Cyrillic_u, Cyrillic_U	]	};
    key <AD08> {	[ Cyrillic_ya, Cyrillic_YA	]	};
    key <AD09> {	[ Cyrillic_softsign, Cyrillic_SOFTSIGN, Cyrillic_hardsign, Cyrillic_HARDSIGN	]	};
    key <AD10> {	[ Cyrillic_yeru, Cyrillic_YERU	]	};
    key <AD11> {	[ Cyrillic_ghe, Cyrillic_GHE	]	};
    key <AD12> {	[     colon,	semicolon	]	};

    key <AC01> {	[ Cyrillic_a, Cyrillic_A	]	};
    key <AC02> {	[ Cyrillic_i, Cyrillic_I	]	};
    key <AC03> {	[ Cyrillic_ie, Cyrillic_IE, Cyrillic_io, Cyrillic_IO	]	};
    key <AC04> {	[ Cyrillic_o, Cyrillic_O	]	};
    key <AC05> {	[ Cyrillic_el, Cyrillic_EL	]	};
    key <AC06> {	[ Cyrillic_ve, Cyrillic_VE	]	};
    key <AC07> {	[ Cyrillic_en, Cyrillic_EN 	]	};
    key <AC08> {	[ Cyrillic_te, Cyrillic_TE	]	};
    key <AC09> {	[ Cyrillic_es, Cyrillic_ES	]	};
    key <AC10> {	[ Cyrillic_er, Cyrillic_ER	]	};
    key <AC11> {	[     comma,	period		]	};

    key <AB01> {	[ Cyrillic_shcha, Cyrillic_SHCHA	]	};
    key <AB02> {	[ Cyrillic_tse, Cyrillic_TSE	]	};
    key <AB03> {	[ Cyrillic_e, Cyrillic_E	]	};
    key <AB04> {	[ Cyrillic_yu, Cyrillic_YU	]	};
    key <AB05> {	[ Cyrillic_ef, Cyrillic_EF	]	};
    key <AB06> {	[ Cyrillic_ha, Cyrillic_HA	]	};
    key <AB07> {	[ Cyrillic_che, Cyrillic_CHE	]	};
    key <AB08> {	[ Cyrillic_zhe, Cyrillic_ZHE	]	};
    key <AB09> {	[ Cyrillic_shorti, Cyrillic_SHORTI	]	};
    key <AB10> {	[ Cyrillic_sha, Cyrillic_SHA	]	};

    key <BKSL> {	[ apostrophe,	quotedbl	]	};
    
    // End alphanumeric section

};

//   GNE         UGNVS, English

default partial alphanumeric_keys
xkb_symbols "basic" {

    name[Group1]= "GNE";

    // Alphanumeric section
    key <TLDE> {	[     grave,	asciitilde	]	};
    key <AE01> {	[	  1,	exclam 		]	};
    key <AE02> {	[	  2,	at		]	};
    key <AE03> {	[	  3,	numbersign	]	};
    key <AE04> {	[	  4,	dollar		]	};
    key <AE05> {	[	  5,	percent		]	};
    key <AE06> {	[	  6,	asciicircum	]	};
    key <AE07> {	[	  7,	ampersand	]	};
    key <AE08> {	[	  8,	asterisk	]	};
    key <AE09> {	[	  9,	parenleft	]	};
    key <AE10> {	[	  0,	parenright	]	};
    key <AE11> {	[     minus,	underscore	]	};
    key <AE12> {	[     equal,	plus		]	};

    key <AD01> {	[	  p,	P 		]	};
    key <AD02> {	[	  d,	D		]	};
    key <AD03> {	[	  m,	M		]	};
    key <AD04> {	[	  k,	K		]	};
    key <AD05> {	[	  z,	Z		]	};
    key <AD06> {	[	  b,	B		]	};
    key <AD07> {	[	  u,	U		]	};
    key <AD08> {	[	  q,	Q		]	};
    key <AD09> {	[	  x,	X		]	};
    key <AD10> {	[	  y,	Y		]	};
    key <AD11> {	[	  g,	G		]	};
    key <AD12> {	[     colon,	semicolon	]	};

    key <AC01> {	[	  a,	A 		]	};
    key <AC02> {	[	  i,	I		]	};
    key <AC03> {	[	  e,	E		]	};
    key <AC04> {	[	  o,	O		]	};
    key <AC05> {	[	  l,	L		]	};
    key <AC06> {	[	  v,	V		]	};
    key <AC07> {	[	  n,	N		]	};
    key <AC08> {	[	  t,	T		]	};
    key <AC09> {	[	  s,	S		]	};
    key <AC10> {	[ 	  r,	R		]	};
    key <AC11> {	[     comma,	period		]	};

    key <AB01> {	[ backslash,	bar 		]	};
    key <AB02> {	[	  c,	C		]	};
    key <AB03> {	[ bracketleft,	braceleft	]	};
    key <AB04> {	[ bracketright,	braceright	]	};
    key <AB05> {	[	  f,	F		]	};
    key <AB06> {	[	  h,	H		]	};
    key <AB07> {	[	  less,	greater		]	};
    key <AB08> {	[	  w,	W		]	};
    key <AB09> {	[	  j,	J		]	};
    key <AB10> {	[     slash,	question	]	};

    key <BKSL> {	[ apostrophe,	quotedbl	]	};
    
    // End alphanumeric section
};

  • Substitute 'GNR' with your layout short name in line name[Group1]= "GNR";

  • Edit key definitions.

Lines like key <AD01> { [ p, P ] }; are obvious enough. This particular line instructs that a press on <AD01> physical key will normally emit lower-case 'p' character. Upper-case character 'P' will be emitted when <AD01> will be pressed while <shift> physical key will be held down. <Shift> key is addressed as a modifier key.

Lines like key <AC03> { [ Cyrillic_ie, Cyrillic_IE, Cyrillic_io, Cyrillic_IO ] }; are not incomprehensible as well. This particular line instructs that a press on <AC03> physical key will normally emit lower-case 'Cyrillic_ie' character. Upper-case character 'Cyrillic_IE' will be emitted when <AC03> will be pressed while <shift> physical key will be held down. Similarly, a press on <AC03> physical key will emit 'Cyrillic_io' or 'Cyrillic_IO' depending on the <shift> key state provided that an extra modifier key will be held down. Such a modifier key is addressed as 3rd level chooser. You can select this extra modifier key according to your taste later in System > Preferences > Hardware > Keyboard > Options dialogue.

  • Copy your finished symbol file into /usr/share/X11/xkb/symbols directory.

  • Navigate to the directory /usr/share/X11/xkb/rules.

  • Open files base.lst and evdev.lst. They are identical and you have to edit both of them identically. Find ! layout line and insert your own layout definition, e.g. GNR UGNVS Russian below.

  • Open files evdev.xml and base.xml. They are identical and you have to edit both of them identically. Find <layoutList> line and insert your own layout definition below. For example:

    <layout>
      <configItem>
        <name>GNR</name>
        <shortDescription>GNR</shortDescription>
	  <description>UGNVS Russian</description>
        <languageList><iso639Id>rus</iso639Id></languageList>
      </configItem>
      <variantList/>
    </layout>

Please do not forget to enter the short name of your layout and its description instead of those provided in the example. Pay attention to correctly denote your language abbreviation as well.

  • Be warned however, that base.lst, evdev.lst, evdev.xml and base.xml may be sometimes overwritten during distribution version upgrades. As a result your keyboard layout may disappear from selection list.

  • Select and instantiate your new keyboard layout using System > Preferences > Hardware > Keyboard > Layouts > Add. Tip: search your layout by language.

Happy typing!

ugnvs

3 Likes

Thanks a lot! This solves my issue with 3 layouts, when i want to switch between 2 by default.

Here is my russian layuot with custom ukrainian symbols mapped:

//   ra         Russian (Ukraine)

default partial alphanumeric_keys
xkb_symbols "basic" {

    name[Group1]= "ra";

    // Alphanumeric section
    key <AE01> { [            1, exclam,  bar ] };
    key <AE02> { [           2,    quotedbl  ] };
    key <AE03> { [           3,  numerosign  ] };
    key <AE04> { [           4,   semicolon  ] };
    key <AE05> { [           5,     percent  ] };
    key <AE06> { [           6,       colon  ] };
    key <AE07> { [           7,    question  ] };
    key <AE08> { [           8,  asterisk, U20BD  ] };
    key <AE09> { [           9,   parenleft  ] };
    key <AE10> { [           0,  parenright  ] };
    key <AE11> { [       minus,  underscore  ] };
    key <AE12> { [       equal,        plus  ] };
    key <BKSL> { [   backslash,  slash  ,Ukrainian_ghe_with_upturn, Ukrainian_GHE_WITH_UPTURN ] };

    key <AB10> { [      period,       comma,       apostrophe  ] };
    key <LSGT> { [       slash,         bar  ] };

    key <TLDE> { [       Cyrillic_io,       Cyrillic_IO  ] };
    key <AD01> { [   Cyrillic_shorti,   Cyrillic_SHORTI  ] };
    key <AD02> { [      Cyrillic_tse,      Cyrillic_TSE  ] };
    key <AD03> { [        Cyrillic_u,        Cyrillic_U  ] };
    key <AD04> { [       Cyrillic_ka,       Cyrillic_KA  ] };
    key <AD05> { [       Cyrillic_ie,       Cyrillic_IE  ] };
    key <AD06> { [       Cyrillic_en,       Cyrillic_EN  ] };
    key <AD07> { [      Cyrillic_ghe,      Cyrillic_GHE  ] };
    key <AD08> { [      Cyrillic_sha,      Cyrillic_SHA  ] };
    key <AD09> { [    Cyrillic_shcha,    Cyrillic_SHCHA  ] };
    key <AD10> { [       Cyrillic_ze,       Cyrillic_ZE  ] };
    key <AD11> { [       Cyrillic_ha,       Cyrillic_HA  ] };
    key <AD12> { [ Cyrillic_hardsign, Cyrillic_HARDSIGN,    Ukrainian_yi,    Ukrainian_YI     ] };

    key <AC01> { [       Cyrillic_ef,       Cyrillic_EF  ] };
    key <AC02> { [     Cyrillic_yeru,     Cyrillic_YERU,     Ukrainian_i,     Ukrainian_I  ] };
    key <AC03> { [       Cyrillic_ve,       Cyrillic_VE  ] };
    key <AC04> { [        Cyrillic_a,        Cyrillic_A  ] };
    key <AC05> { [       Cyrillic_pe,       Cyrillic_PE  ] };
    key <AC06> { [       Cyrillic_er,       Cyrillic_ER  ] };
    key <AC07> { [        Cyrillic_o,        Cyrillic_O  ] };
    key <AC08> { [       Cyrillic_el,       Cyrillic_EL  ] };
    key <AC09> { [       Cyrillic_de,       Cyrillic_DE  ] };
    key <AC10> { [      Cyrillic_zhe,      Cyrillic_ZHE  ] };
    key <AC11> { [        Cyrillic_e,        Cyrillic_E,    Ukrainian_ie,    Ukrainian_IE  ] };

    key <AB01> { [       Cyrillic_ya,       Cyrillic_YA  ] };
    key <AB02> { [      Cyrillic_che,      Cyrillic_CHE  ] };
    key <AB03> { [       Cyrillic_es,       Cyrillic_ES  ] };
    key <AB04> { [       Cyrillic_em,       Cyrillic_EM  ] };
    key <AB05> { [        Cyrillic_i,        Cyrillic_I  ] };
    key <AB06> { [       Cyrillic_te,       Cyrillic_TE  ] };
    key <AB07> { [ Cyrillic_softsign, Cyrillic_SOFTSIGN  ] };
    key <AB08> { [       Cyrillic_be,       Cyrillic_BE  ] };
    key <AB09> { [       Cyrillic_yu,       Cyrillic_YU  ] };
    
    // End alphanumeric section

};

Maybe you know how to add left ctrl key to trigger 3rd level? There is only right one in the list.

I'm afraid that left ctrl can not be used at 3rd level switch just because it is used in many shortcuts already.
They say, predetermined list of possible 3rd level choosers is configured in evdel.lst file.

I get it. This makes no sense because of ctrl+c, ctrl+v and so on ...
I will just use left win.

Dear Eugene,
I'm trying to write a keyboard layout for Ubuntu, but I'm working on Windows. I have the question: Microsoft Keyboard Layout Creator allows to set two or more consecutive characters for one key. Is it possible in Linux? And if so, how to write it? Can I just list it with a space?
Thanks

Dear Ruben,

I am afraid that I am unaware of that Windows possibility and have never seen something like that in Windows. On the other hand, I have to confess that I have no information of such Linux feature as well.

Surely, one can assign several character codes to the same keyboard key and invoke them by pressing 1, 2, 3, 5 level modifiers together with this key. No cycling through all the possible characters by pressing an extra special key though.
A good introduction to the Linux keyboard can be found here
https://help.ubuntu.com/community/ComposeKey
and here

Hopefully, this will help clarify your questions.

Thanks, Eugene. I am not a connoisseur of Windows. Just created keyboard layouts using KLC, which gives this opportunity.

You are welcome, Ruben!

Hi my community, I'm newbie over Ubuntu, so about this topic, that's my case,
I'm latin developer who live in germany so I need use the german keyboard and in order of that i thank that jave a custom keyboard shall a excellen idea, wiht my windows 10, and the win sw called KLC was easy, now here in Linux Ubuntu will be a challeger, My german keyboar layout changes that i need are:

key [change "^" to ']: for get the whole "N" y "n" with "~", like: Ñ, ñ,

---so that's the idea with this special character below:

":slight_smile:", "¦","↑","•","Ñ","ñ","×","á","é","í","ó","ú","·","."

--but the main point is like developer use, cause in the default german kyb layout the decimal symbol is "," , that's ok but in the numeric kyb i want use "." instead "," because is very useful when i do my web development.

I need some hints, for this first objective, the next objective i want to learn russian languaje and i want do my own layout using my german kyb!

thks in advance for the attention
Kind Regards from Hamburg, Germany with a Ecuadorian soul!

Please, could you create belarusian phonetic keyboard layout for linux? I use russian pfonetic on macOS (with belarusian and ukrainian symbols) and it is very convenient.

What about the dead keys that needs Alt-Gr (Compose key) to work? What is the layout of the file to program them?

IMHO, the following link answers your question on overriding standard dead keys:

https://help.ubuntu.com/community/ComposeKey#Compose_key

Dear Eugene, thank you very much for your answer, however, the Alt-Gr key and the Compose key are "different" ways to get those characters that are not primary (direct and shift) characters on a keyboard. My question referred to the former. I got an answer by reviewing the symbols file at /xkb/. Each group of special symbols has the following line at their ends, for example

partial alphanumeric _keys
xkb_symbols "intl" { // <--this is only an example

name[Group1]= "English (US, intl., with dead keys)";

// The key definitions go here

include "level3(ralt_switch)" // <-- I think this is the answer that I needed.

};

This article explains the differences between Alt-Gr (Classic way to access alternate characters in European KB Layouts) and Compose-key. For those that may need it, I am sure that you are already acquainted with it.

https://help.ubuntu.com/community/ComposeKey#Compose_key