Overview Examples Materials Deutsch

A level for special characters


As a programmer, one often must type in special characters. Therefore, it seems desirable to take special characters into account when designing an alternative keyboard layout. In the following, it will be described how to achieve this with the optimiser. In the approach described, the special characters are located in a «third level», as it is known, for example, from Neo 2.


I assume that you have downloaded the optimiser and are roughly familiar with it. The optimiser and its documentation can be found on the overview page. For the present article, I have used version 1.246. Here you can find a collection of files that help to reproduce this article more easily:

Download supporting material

As the frequency of special characters is dependent on the programming language, and as the frequency with which they actually must be typed furthermore depends on the programming environment, the requirements differ from person to person. Therefore, the first and most difficult step is coming up with a personalised corpus. The supporting material contains frequency files, however, only for the purpose of demonstration. For this reason, I will not comment on how they have been obtained.



One of the most severe limitations of the optimiser is that one must predefine which characters form a pair that shares a key, and which character in that pair must be entered with shift. This limitation is insignificant as long as one only deals with letters. For special characters, it becomes an obstacle.

To blur the limitation, the optimiser allows to specify multiple keys at the same location. Each of those specifications corresponds to a character specification. For the character specification, instead of pairs of characters, only one character for the first level is given, and for the second level, a pair is specified, the first character of which is a placeholder. Thereby, first and second level are decoupled, however, the assignment of characters to levels is still predetermined.

One more limitation is that the optimiser only fully supports two levels, but we want to have three levels. If we proceed strictly as just explained, we must drop the level with the capital letters. We also can keep it and pretend that the shift keys and the keys which are used to select the third level are identical. If those keys are operated by the same fingers, this is not severely wrong. However, I still opted for the first approach, with the additional twist of treating the shift keys as dead keys.

We start from an existing layout for the letters and the important punctuation characters, in our example, from “Aus der Neo-Welt” without “ß”. This layout is not modified, but it is taken into account while optimising the layout for the special characters. One also could try to treat the letters and special characters in one single step. The two-step scheme is chosen because it is faster, it accounts for the precedence of normal texts as compared to source code, and because it allows to handle capital letters as dead key sequences. For the latter to be possible, we must know on which side of the keyboard each letter is located, in order to specify the proper shift key in the dead key sequence.


In the configuration, the letters and punctuations characters are fixed to the keys on which they belong according to the base layout. For example, for “Aus der Neo-Welt”, the letter “k” is located on the QWERTZ-Q key:

FixesZeichen AD01 'k'

The shift keys of the base layout are redefined as normal keys,

Taste  LSGT   1  3    1.00  3   -5   -   5
Taste  RTSH  13  3   12.00  3    5   -   7

and we add a fixed mapping of the characters to them which are used for the dead key sequences. We choose for the left and for the right shift key

FixesZeichen LSGT '←'
FixesZeichen RTSH '→'

and use them in the sequences with which we approximate how capital letters are entered. For example, for “Aus der Neo-Welt”, the letter “k” is located on the left side and, therefore, to type “K”, the right shift keys is needed, resulting in

Ersatz 'K→k'

as the dead key sequence.

For each special character, we introduce a new key, for example the key BD01, which is located at the same spot (QWERTZ-Q) as AD01:

Taste  AD01   2  1    1.25  1   -5   -   5.
Taste  BD01   2  1    1.25  1   -5   -   5.

Furthermore, we introduce the special characters themselves, for example, the less-than character as

Zeichen '¦<'

The ¦ is a placeholder and is specified as

Platzhalter '¦'

As explained above, we need the placeholder, as our special characters are supposed to be located in the third level, that is, they only are reachable in connection with a shift key. For this reason, the special character must not appear as the first one in a Zeichen definition.

Then, we must specify the level three shift keys. In our example, I use the left shift key and the QWERTZ-Ä key:

ShiftL LFSH   0  3    0.00  3   -5   -   7
ShiftR BC11  13  2   11.50  2    5   -   5

If we are using a corpus that is made up of programme source code exclusively, the character frequency in it is not representative of the all our typing and, therefore, the finger load cannot be computed correctly. In this case, one can simply put the weights for the related efforts to zero:

Fingerbelastung  0 0 0 0 0  0 0 0 0 0

Alternatively, one can collect a corpus that contains a mixture of normal text and programme source code in realistic proportions, and leave the efforts unmodified. That is what is done in this example.

Finally, we must compile the optimiser for the right number of keys. Doing so, we must not use the -DOHNE2SHIFT option:

g++ -std=c++11 -Ofast -DNDEBUG -DTASTENZAHL=66 -DMIT_THREADS -DENGLISH -pthread opt.cc -o opt66

And at last, it is the computer’s turn:

./opt66 -K ebene3.cfg -2 demo.txt -t 4


The result, of course, depends on the corpus. Using the frequency files included in the supporting material we get

                 385.537 total effort   283.415 positional effort    left right
                   2.465 same finger rp   8.725 shift same finger top  5.2 11.5
  ?*-+# |}:{…%    67.945 hand alternat.  39.673 shift hand alter. mid 29.5 34.6
  =_(/> ])\;<      0.828 inward/outward  26.908 inward or outward bot 11.1  8.1
 ←`&^"! $@['~→     8.773 adjacent         6.677 shift adjacent    sum 45.8 54.2
                 11.7 11.7  9.6 12.8 --.- --.- 17.7  9.5 11.1 16.0 Sh  6.2  7.2
Version 23. Mär 2017Impressum