Solaris Keyboard Howto

Recently I installed Solaris 11 Express in a VirtualBox VM on my MacBook Pro 3.1. Unfortunately my MacBook has a german keyboard (which is really strange BTW) and does not conform to the usual USB keyboards and thus there was no way to get the solid bar aka pipe symbol and some other essential signs printed on the command line (console). So I took some time to find out, how to make the keyboard behave as I want it to and here is, what I've found out.

Setting the default keyboard layout

If you have a standard keyboard, Solaris has usually all you need. If it did not find out automatically, what kind of keyboard is connected to the system, you may set it explictly by setting the keymap/layout property of the keymap:default service:

svccfg -s keymap:default setprop keymap/layout=German
svcadm refresh keymap

To choose another keyboard layout on the fly, one may use:

kbd -s
loadkeys

This tool shows you all available layout names (which can be used for the keymap/layout property of the keymap:default service as well) and lets you choose the one to use. The loadkeys command is required, to finally activate the new layout.

Another way to set the default keyboard layout is to set the appropriate eeprom/OBP property:

eeprom set keyboard-layout=German
# and to avoid confusion
svccfg -s keymap:default delprop keymap/layout
svcadm refresh keymap

This works, since the keymap service starter first looks at the eeprom/OBP settings for the keyboard-layout property, and if its value is valid, kbd -s $value is used to set the default keyboard layout. If it the keymap:default service property keymap/layout is also set, the starter uses kbd -i to set the keyboard layout according to property value (otherwise the currently set keyboard layout will be kept). Last but not least it does a loadkeys to activate the layout.

Further information can be found in:

Defining a new keyboard layout

As mentioned before, many laptops have their "own" keyboard layout, and thus using a default keyboard layout coming with Solaris is quite a pain. In this case it is the best to create a new keyboard layout map and use this one instead. All you need to do for this is to add your layout name and ID to the file kbd_layouts in the /usr/share/lib/keytables/type_6 directory (the type_6 directory hosts all layouts for USB keyboards) and to add the file layout_HexID, which contains your modifications to the default keyboard layout.

However, before you go ahead, you should read the man page for kbd and keytables, since I'm not going to explain/repeat every tiny detail.

scancodes

The first thing to know wrt. defining a new keyboard layout are the scancodes, which are sent by each key. Usually each key sends always the same scancode, no matter which modifiers (CapsLock, Shift, Alt, AltGr, Meta, Command, etc.) are pressed down. However, some keyboards (especially laptops/notbooks) have special keys as well as a function key (fn), which cause some keys to emit a different scancode when they are pressed together. Also if no separate numeric keypad is available on the keyboard, there is usually a key combination, which lets you switch the keyboard into the numeric keypad mode, where some keys also emit different or no scancodes at all.

However, since scancodes are almost always an undocumented feature of the keyboard, keys are named different than in the USB specification 1.12, HID Usage Tables, KEYBOARD/KEYPAD PAGE (0X07), page 53ff., or keyboard emulation is buggy (as in VirtualBox 3.2.10 and 3.2.12), we need a reliable way to find them out. With Solaris it is easy to do that using the function probe provider of its wonder wappen dtrace:

dtrace -n 'fbt:kbtrans:kbtrans_translate:entry { printf("%d\n",arg2) }'

Now you can press every key in each different keyboard mode, to see whether and which scancode gets emitted. For the MacBookPro 3.1 with the default german keyboard layout it may look like this table.

keyboard type

To determine the correct directory, where one needs to put the new keyboard definition file, one needs to get the type of keyboard in use. kbd -l shows, what you need to know. For later use, we store the type into the env variable KT :

KT=`kbd -l | fgrep type= | cut -f2 -d=`

For USB keyboards you will usually get type 6.

keytables directory

Now you should change your current working directoy to the directory, which contains the layout definitions for the type of keyboard in use:

cd /usr/share/lib/keytables/type_$KT

If it does not exist, create it, using mkdir -p and cd to it.

set the layout to use

To avoid a lot of typing, one should now choose a keyboard layout, which matches best your physical keyboard layout:

kbd -s

activate layout

When the keyboard layout to use has been set, one needs to activate it:

loadkeys

You may verify, that the changes are active, by pressing one of the "non-standard" keys wrt. your country (e.g. characters with diaresis aka umlaut or accent grave/acute).

layout name

To be able to select your keyboard layout with kbd -s and also to set it as default in eeprom or keymap:default service, one need to give it a name. It should be not longer than 30 characters. Also to avoid trouble, it is highly recommended to use ASCII letters, digits, underlines and hyphens, only and of course a name, which is not already defined in the file kbd_layouts. For later use, we store that name in the env variable KNAME:

KNAME='German-MacBook-Pro'
grep "$KNAME=" kbd_layouts

layout ID

Also you need to assign an ID to your new keyboard layout. Of course you need to make sure again, that the new ID is not already in use. E.g.:

fgrep = kbd_layouts  |sort -t= -k2n
KNUM=333
KHEX=`printf '%02x' $KNUM`

For our convinience we store the new ID in the env variable KNUM and its hexadecimal value in the env variable KHEX.

dumping the active layout

Now dump the the keyboard layout, which is currently active, to the new layout file to use: it must have a name in the format layout_ID , whereby the ID must be the hexadecimal value with at least two digits of the layout ID you have choosen in the previous step. E.g.:

dumpkeys >layout_$KHEX

publish keyboard layout name and ID

A you probably already guessed, to make the new layout available to the kbd -s as well as the keymap:default service, one needs to "publish" its name and ID. This can be done by just adding a new entry to the kbd_layouts in the appropriate keyboard type directory. The format of the entry is simple: layoutName=ID. Obviously the layoutName is the name you have choosen for your new keyboard layout, and the ID is the ID of the layout - this time in decimal (see above). E.g.:

echo "$KNAME=$KNUM" >>kbd_layouts

Finally try, whether the previously dumped layout works, using the kbd -s and loadkeys command. If you see any errors, just comment out the line in question by inserting a # at the start of the line (i.e. column 0) and try again.

If it finally works without any error message, you have now a starting point and shoud be able to modify the layout as you like (see man page keytables) and set it as the default keyboard layout to use as described above.

Solaris 11 Express seems to have bug wrt. the swap number1 with number2 instruction: it assigns the values for keystation number1 to keystation number2, but keystation number1 is set to an empty value aka 'all hole' and not to the previous values of number2!

Function key names

When defining a new keyboard layout, you probably get curious, what strings to use for the top (tf), left (lf), bottom (bf) and right (rf) function keys or what these keys are actually supposed to be. Actually, under the hood this is a block of 4*16=64 scancodes, where lf(1) marks the start of the first, rf(1) the start of the second, tf(1) the start of the third and bf(1) the start of the last block (see /usr/include/sys/kbd.h and the man page for kb). The corresponding Escape Sequences start at 192 for lf(1) and stop at 255 for bf(15).

Unfortuetaly I haven't found a reliable source yet, which lets you determine easily, which function is assigned to the Escape Sequences mentioned above, and also no source, which defines, what ?f(n) to use for which "special key". So I took an original SUN keyboard, dumped its keyboard layout and assigned they names on those keys to the used ?f(n) code via their scancode:

Function Names and Scancodes for a SUN™ keyboard
KeyCodefn NameEscape Seq.Notes
Left Function block
Stop120buckybits+systembit
Again121lf(2)^[[193z
Props118lf(3)^[[194z
Undo122lf(4)^[[195z
Front119lf(5)^[[196z
Copy124lf(6)^[[197z
Open116lf(7)^[[198z
Paste125lf(8)^[[199z
Find126lf(9)^[[200z
Cut123lf(10)^[[201z
Help117lf(16)^[[207z
Right Function block
Pause72rf(1)^[[208z
Print70rf(2)^[[209z
ScrollLock71rf(3)^[[210z
Speaker toggle/Degauss127rf(4)^[[211z
:84rf(5)^[[212zkeypad
*85rf(6)^[[213zkeypad
Home / Pos 174rf(7)^[[214z
Home / Pos 195rf(7)^[[214zkeypad
Page Up75rf(9)^[[216z
Page Up97rf(9)^[[216zkeypad
93rf(11)^[[218zkeypad (on 5)
End77rf(13)^[[220z
End89rf(13)^[[220zkeypad
Page Down78rf(15)^[[222z
Page Down91rf(15)^[[222zkeypad
Top Function block
F158tf(1)^[[224z
F259tf(2)^[[225z
F360tf(3)^[[226z
F461tf(4)^[[227z
F562tf(5)^[[228z
F663tf(6)^[[229z
F764tf(7)^[[230z
F865tf(8)^[[231z
F966tf(9)^[[232z
F1067tf(10)^[[233z
F1168tf(11)^[[234z
F1269tf(12)^[[235z
Bottom Function block
Ins73bf(8)^[[247z
Ins98bf(8)^[[247zkeypad
Del99bf(10)^[[249zkeypad
Enter88bf(11)^[[250zkeypad
Sleep/Suspend102bf(13)^[[252z
+87bf(14)^[[253zkeypad
-86bf(15)^[[254zkeypad
Other
Volume/Contrast decrease129
Volume/Contrast increase128
NumLock83shiftkeys+numlock
arrow up82string+uparrow^[[A
arrow left81string+downarrow^[[B
arrow right79string+rightarrow^[[C
arrow left80string+leftarrow^[[D
Del76'\177'
Ctrl left224shiftkeys+leftctrl
Alt226shiftkeys+alt
Meta right231buckybits+metabit
Meta left227buckybits+metabit
Compose1010x309
AltGr230shiftkeys+altgraph
Esc41^[
Tab43'\t'
CapsLock57shiftkeys+capslock
Shift left225shiftkeys+leftshift
Shift right229shiftkeys+rightshift
Enter40'\r'
Backspace42'\b'

Resources

Copyright (C) 2010 Jens Elkner (jel+mac@cs.uni-magdeburg.de)