Microsoft Natural Multimedia KeyboardI bought a Microsoft Natural Multimedia Keyboard because of its splitted keyboard which I consider to be really comfortable. But since I do not use it under its "natural" operating system all those fancy keys that are present on the keyboard do pretty much nothing. In addition to that I also wanted to learn a little bit more about keyboard mapping when I am working in a remote terminal. Time to gain some more insight on the relationship between the Linux kernel and keyboards. Inside the keyboardThe initial steps of transmitting the information of a key event happen inside the keyboard. A small chip integrated into the keyboard constantly checks for activated keys. Once this chip identifies that the user pressed a key it encodes the type of key by sending one or several bytes over a serial line (the keyboard cable) to the computer. The chip on the keyboard can already choose between three different types of encodings for the keyboard events. They are identified as scancodes 1 - 3. Depending on the scancode each key stroke is reported in a specific way. Usually each key stroke will elicit a make code when it is being pressend and a break code once it is released. The following description of the three scancode sets was taken from Keyboard scancodes: For Set 1, if the make code of a key is For Set 2, if the make code of a key is For Set 3, by default most keys do not generate a break code. Usually mode 2 or 3 will be used. There is no way to influence this scan code mode directly from the keyboard. The only way to communicate with the keyboard is the keyboard controller chip inside the computer. So this will be the next element to look at. Inside the machine - The i8042The "i8042" chip (or any of its descendants) is the keyboard
controller inside the computer and attached to the PS/2 port of newer
computers as well as to the system bus (this excludes USB
keyboards). This keyboard controller is handled by the
#define I8042_COMMAND_REG 0x64 #define I8042_STATUS_REG 0x64 #define I8042_DATA_REG 0x60 You may use the command register outb 0x64 0xaa && inb 0x60 Usually the output should be The i8042 chip is mapped to the "/sys" filesystem under linux and you should be able to find some information about its current state there. My keyboard controller is listed under "/sys/bus/serio/devices/serio0". The "descripton" file inside one of the serio directories should identify it as "i8042 Kbd Port". There is a set file in the same directory that will display the current keyboard set that is being used (in my case this is set 2 for the microsoft keyboard). You can also try reading the current setting directly from the keyboard using something like the following sequence: outb 0x60 0xf0 && inb 0x64 && inb 0x60 && sleep 1 && outb 0x60 0x00 && inb 0x64 && inb 0x60 Writing Using the sys filesystem you can easily activate the debugging mode of the i8042 kernel module using: echo "Y" > /sys/module/i8042/parameters/debug This does generate a lot of output in your logfile (one or several lines per keystroke). A key stroke arrivesSo far we know that the keyboard can return a keystroke in one of three different "languages" (scancodes). But this is not the only mangling a key stroke may be submitted to. The i8042 is usually set to translate key codes from scancode 2 to scancode 1 (it does that by turning an f0 prefix into an OR with 80 for the next byte). You will find a comprehensive translation table at http://www.win.tue.nl/~aeb/linux/kbd/scancodes-9.html#scancodesets You can test your i8042 for translation mode using the following input: outb 0x64 0x20 && inb 0x60 I get a Actually the situation described here - translated scancode 2 - seems
to be the standard situation in most cases. Whatever the situation of
your keyboard and its controller, the intention of the This key code is then transferred to the kernel input system. What about my microsoft keyboard? It has a few special keys that are
probably not linked to a specific key code inside the Linux kernel
since they are uncommon among keyboards. But there exists the
possibility to redefine association between scancodes and key codes
using the tool One can play around with the standard keys: setkeycodes 1e 31 Pressing the key "a" (scnacode setkeycodes 1e 30 The main use of this tool is to make previously unknown keys known to
the linux kernel. The Microsoft keyboard emits the scancode setkeycodes e03b 204 will now emit the keycode The microsoft natural keyboard can be tuned to emit a key code for every single keypress by using the following "setkeycode" command:
setkeycodes e016 174 e064 212 e03c 213 \
e005 216 e03b 138 e008 131 \
e007 129 e03e 144 e03f 134 \
e040 206 e041 148 e042 149 \
e043 145 e023 202 e057 203 \
e058 210
# 174: KEY_EXIT (Abmelden)
# 212: KEY_CAMERA (Eigene Bilder)
# 213: KEY_SOUND (Eigene Musik)
# 216: KEY_CHAT (Messenger)
# 138: KEY_HELP (Hilfe)
# 131: KEY_UNDO (Rückg)
# 129: KEY_AGAIN (Wiederherstell)
# 144: KEY_FILE (Neu)
# 134: KEY_OPEN (Öffnen)
# 206: KEY_CLOSE (Schliessen)
# 148: KEY_PROG1 (Antwort)
# 149: KEY_PROG2 (Weiterleiten)
# 145: KEY_SENDFILE (Senden)
# 202: KEY_PROG3 (Rechtschreib)
# 203: KEY_PROG4 (Speichern)
# 210: KEY_PRINT (Drucken)
The listing of key codes below the command relates to the naming in the
The linux input systemThe input event system handles keyboard events with the driver
But the most important part is to map each key code to some useful output characters. While the whole translation part happening in the drivers described above was necessary to map each key to a well defined key code the approach disregarded a very important fact: not every keyboard layout is the same and in fact the ordering (or labeling) of keys are adapted to the language of the users. So each key code now needs to be translated into the correct language. At this point we need a key map that describes the labels on the specific keyboard in use. It would be nice if this would be the only problem at this point but in fact there are different requirements depending on the program receiving the key strokes. There exist two major modes which handle the key input in different ways. One is the kernel console (text mode) and the other one is the X server (graphical mode). Mapping keystrokes on the consoleSince the console is tightly integrated into the kernel, all
preprocessing to the correct characters is handled by the
kbd_mode -u There exists an older mode that uses ASCII characters but it is deprecated and should not be used anymore. Having your operating system to use unicode at its core level actually helps to prevent a lot of trouble with character conversions at later times. Don't expect every program and tool to be unicode aware (so there might be some problems) but it is clear that the computer world will develop more and more into that direction. Key mapsIn addition to the unicode mode selection we need the keymap that maps the kernel key codes to actual characters (or character sequences). Since we selected unicode mode this map has to be a unicode map but more on this later. It is possible to set an initial keymap for the kernel when you
compile it but it is better to set the keymap during runtime. The
command How can we define a keymap? The following is a short extract from a
file that can be fed into
# Normal Shift AltGr Strg
keycode 1 = Escape Escape
keycode 2 = one exclam
keycode 3 = two quotedbl two nul
keycode 4 = three numbersign three Escape
keycode 5 = four dollar
keycode 6 = five percent
keycode 7 = six ampersand
keycode 8 = seven slash braceleft
keycode 9 = eight parenleft bracketleft
keycode 10 = nine parenright bracketright
control altgr keycode 10 = Control_bracketright
In the chapter above we arrived at the so called key codes. With a keymap as shown above we are now able to link a kernel key code to key symbols. Lets look at some of the basics of the keymap definition. It is possible to link a key code not only to one but to up to 256 such key symbols. This is possible since each key code is not only regarded for itself but instead in context with so called modifier keys. This concept allows you to specify that pressing "a" on your keyboard will result in an "a" on the screen but yield an "A" if you press it while also holding the "Shift" modifier key down. Since there are eight such modifier keys present on a keyboard this results in 256 possible modifier key combinations. Actually it is highly unlikely that you will ever press more than three modifier keys at the same time but this concept is very useful for languages that have a more complicated symbol structure than ours.
# Normal Shift AltGr Strg
keycode 9 = eight parenleft bracketleft
keycode 10 = nine parenright bracketright
control altgr keycode 10 = Control_bracketright
As visible from the excerpt above there are two ways how a key code gets combined with a modifier. In the first version the key code is specified first, followed by an equal sign and several columns that each define the result of combining this key code with a given modifiers. In principle you'd be able to have the full 256 columns here but most keymaps only have the first four that stand for "No modifier", "Shift", "AltGr" and "Strg". If you need to define a more complex combination of modifiers you can do so using the structure given in the last line of the example above. Here the combination of modifiers is described first, followed by the key code. The part behind the equal sign then defines the result for exactly this type of key combination. How to describe the outcome of a specific combination of activated
keys? In principle you can use normal letters like "a" or "A" to
describe the various results of the key strokes. But all the special
characters have special names (like the Key maps in the kernelLets assume we are now able to define a keymap and store it in the
running kernel using Lets look at key symbols. A key symbol is in fact a combination of a
key type and a key value. Inside the kernel memory each key symbol is
a 16 bit value and is handled within the Now in case the value is larger than 0xf000 then bits 9-12 represent the key type and bits 1-8 the key value. The key type is being used to specify special key handlers inside the
kernel. The following key types exist (defined in
#define KT_LATIN 0 /* we depend on this being zero */ #define KT_FN 1 #define KT_SPEC 2 #define KT_PAD 3 #define KT_DEAD 4 #define KT_CONS 5 #define KT_CUR 6 #define KT_SHIFT 7 #define KT_META 8 #define KT_ASCII 9 #define KT_LOCK 10 #define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ #define KT_SLOCK 12 #define KT_SPKUP 14 Back to our definition of key symbols using The following are the possible functions: LATIN will just return the key value as character and thus represents the old ASCII characters. This is not really necessary anymore. FN will copy a string from a special table to the output. The table can hold a maximum of 256 entries. echo 'string F100 = "hello world"' | loadkeys echo 'keycode 30 = F100' | loadkeys Pressing "a" now will result in the string "hello world". Revert back using echo 'keycode 30 = a' | loadkeys SPEC will call special kernel functions. These are the functions available: #define FN_HANDLERS\ fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num You can reach these function using the following identifies for
static const char *spec_syms[] = {
"VoidSymbol",
"Return",
"Show_Registers",
"Show_Memory",
"Show_State",
"Break",
"Last_Console",
"Caps_Lock",
"Num_Lock",
"Scroll_Lock",
"Scroll_Forward",
"Scroll_Backward",
"Boot",
"Caps_On",
"Compose",
"SAK",
"Decr_Console",
"Incr_Console",
"KeyboardSignal",
"Bare_Num_Lock"
};
fn_enter will put character 13 in the queue (there is an option that will also append character 10 but I dont know where to activate that). fn_show_ptregs dumps the register content to your kernel log. fn_show_mem does the same with memory. echo 'keycode 30 = Show_Memory' | loadkeys Pressing "a" will now show echo the kernel memory information into
your echo 'keycode 30 = a' | loadkeys fn_show_state does the same with state. fn_send_intr sends a break signal (TTY_BREAK) to the terminal. fn_lastcons switch to the last used console. fn_caps_toggle toggle caps. fn_num toggles num lock. echo 'keycode 30 = Num_Lock' | loadkeys Pressing "a" will now toggle the Num Lock status. Revert back using: echo 'keycode 30 = a' | loadkeys fn_hold stops the tty. fn_scroll_forw scroll tty forward. fn_scroll_back scroll tty backward. fn_boot_it reboot the machine. echo 'keycode 30 = Boot' | loadkeys Pressing "a" will reboot the machine. Revert back using: echo 'keycode 30 = a' | loadkeys fn_caps_on turn caps on. fn_compose marks the key as dead and will compose a special character together with the next key. fn_SAK special attention key that can be used to call some disaster recovery functions in case the machine does not respond anymore. fn_dec_console switch console backward. fn_inc_console switch console forward. fn_spawn_con spawn new console. fn_bare_num switches the num lock flag without actually switching the internal state of the num lock flag. PAD a key from the numerical pad. Will issue a character depending on the num lock state. DEAD a dead key that will not directly result in a character but will be composed together with the next characters. CONS switches to a specific console. CUR cursor movement. SHIFT handles modifier keys. META handles the special meta key. ASCII directly entering ascii codes. Usually this is mapped to your keypad and the modifier Alt as well as AltGr. Holding down Alt and pressing 4, 1 should result in ")" (Ascii code 41). The same result can be obtained with AltGr and 2, 9 (")" has hex code 0x29). LOCK handles locking of modifier keys. LETTER not implemented. SLOCK no clue? SPKUP call speakup subsystem. Here is a list of the different modifier keys you can use: include/linux/keyboard.h: #define KG_SHIFT 0 #define KG_ALTGR 1 #define KG_CTRL 2 #define KG_ALT 3 #define KG_SHIFTL 4 #define KG_KANASHIFT 4 #define KG_SHIFTR 5 #define KG_CTRLL 6 #define KG_CTRLR 7 #define KG_CAPSSHIFT 8 This example shows the definition of modifier keys inside the kernel
and the following shows the names you can use for these modifiers
inside a
static const char *shift_syms[] = {
"Shift",
"AltGr",
"Control",
"Alt",
"ShiftL",
"ShiftR",
"CtrlL",
"CtrlR",
"CapsShift"
};
At this point you should know how to access the kernel specific
functionality by using Available key mapsThe basic settings for all standard keyboards are already defined by
standardized key maps also provided by the For my german keyboard I choose the The
After including Finally a compose map for latin1 ( It would be nice to actually have a keycode 127 = Compose I am not quite sure about the I don't need the I did save my echo "keycode 127 = Compose" | gzip -c > /usr/share/keymaps/i386/include/gunnar.map.gz And now I can load my key map definition using loadkeys de-latin1-nodeadkeys gunnar Character display on the consoleAll the steps mentioned above result in keystrokes that are being available in unicode format (actually UTF-8). Now these characters need to be transferred to characters that can be displayed on screen. We do obviously ignore the fact that there are programs involved in processing each keystroke before they actually appear on screen. But we can assume here that these programs accept UTF-8 encoded characters and also emit UTF-8 characters again. So we ignore this type of processing now. What do we need in order to map certain UTF-8 character bytes to glyphs printed on the screen? We need a font mapping and the tool By default You can easily check the different character support on your console
by downloading this UTF-8 demo file and trying to look at it using
You won't find a font mapping that will allow to display all characters in the test file since a console font mapping can provide at most 512 different character bitmaps. So you need to choose a font mapping that matches your language settings best. For the western world I would suggest the Another good option is the Once you chose your font mapping you can activate it for the current console by issuing something like the following command: setfont ter-v12n The €-Symbol on the consoleIf you use either the The following altgr keycode 18 = U+20AC Mapping keystrokes for the X serverThe X server does not really care about the processing of key strokes provided by the linux kernel. Once the server starts it sets the console into raw mode which instructs the kernel to revert all its key code generation back to scancodes. At least this seems to be the standard situation when using the X kbd driver. I guess this has historical reasons even though it does not really seem to be logical. Anyhow the X server recognizes all the keys of my keyboard without complaining about unkown keys. The X server maps each scancode to a key code (I don't know exactly how this is done) and the program xev can be used to display the key codes. Now I can use xmodmap to map the key codes that are currently unmapped to some useful actions. The ~/.Xmodmap file will hold all necessary information: ## Eigene Dateien keycode 239 = XF86Documents ## Eigene Bilder keycode 187 = XF86Pictures ## Eigene Musik keycode 118 = XF86Music ## Ton aus keycode 160 = XF86AudioMute ## Play keycode 162 = XF86AudioPlay ## Stop keycode 164 = XF86AudioStop ## Lauter keycode 176 = XF86AudioRaiseVolume ## Leiser keycode 174 = XF86AudioLowerVolume ## Voriger Titel keycode 144 = XF86AudioPrev ## Nächster Titel keycode 153 = XF86AudioNext ## Medien keycode 237 = XF86AudioMedia ## E-Mail keycode 236 = XF86Mail ## Startseite keycode 178 = XF86HomePage ## Messenger keycode 121 = XF86Messenger ## Rechner keycode 161 = XF86Calculater ## Abmelden keycode 209 = XF86LogOff ## Standby keycode 223 = XF86Standby ## Hilfe keycode 245 = XF86LightBulb ## Rückg keycode 135 = XF86History ## Wiederherstell keycode 133 = XF86Refresh ## Neu keycode 198 = XF86New ## Öffnen keycode 191 = XF86Open ## Schliessen keycode 175 = XF86Close ## Antwort keycode 159 = XF86Reply ## Weiterleiten keycode 151 = XF86MailForward ## Senden keycode 199 = XF86Send ## Rechtschreibung keycode 171 = XF86Spell ## Speichern keycode 172 = XF86Save ## Drucken keycode 185 = XF86Display This file needs to be sourced by xmodmap for each session start, so I add it to ~/.xprofile (KDM will source it on starting the session): /usr/X11R6/bin/xmodmap $HOME/.Xmodmap Alternative: LineakdLineakd is a background daemon that listens to the X server events and reacts to the special keys. This has the advantage that you can define actions independant of the window manager you actually use. The disadvantage is that this prevents you from using special features of your window manager. So it is a matter of preference. TODO... more to do ... ( ... tty ... network ...) Links Back to Personal Wiki |