** Svgalib keyboard scancode remapping: the Readme **

** Introduction

After a poll on Slashdot.org about keyboard layouts, I decided to switch from
QWERTY to the Dvorak simplified keyboard. (Such is the power of Slashdot!) It
was easy to switch the keymaps used by the console and X and even LILO, but
svgalib programs that used raw keyboard weren't affected since they interpret
the keyboard scancodes into characters themselves - often assuming a standard
US keyboard with QWERTY layout.

In order for my machine to present a ``unified front'' with a single consistent
keyboard layout, I added to svgalib the ability to remap scancodes. This is
done in keyboard_getevents(), before the event handler is called, so it will
work whether or not a program provides its own handler. Programs that do not
use raw keyboard are not affected, so by setting both the console and svgalib
itself to use the same keymap a consistent keyboard layout is available to all
svgalib programs.


** Background

When you press or release a key on your keyboard, it sends a byte of data to
your computer. The top bit indicates whether the key was pressed or released,
and the lower seven bits hold the scancode, a number that uniquely identifies
the key. A program on the computer interprets these scancodes as representing
characters (`A', `%', etc) or actions to be taken (`Page Up', `Back Space') or
modifiers that alter the interpretation of other keys (`Shift', `Alt', etc).
Most programs do not perform this interpretation themselves, but leave it up
to some other piece of software: the system BIOS, or the operating system,
or the graphical user interface system.

On Linux this is normally done by the kernel or by the X server for X clients,
but this doesn't meet the needs of some programs (especially games) which
care more about whether a key is up or down than what it means and treat the
modifiers the same way as other keys. These programs open the keyboard in `raw'
mode and deal directly with scancodes.

The problem comes because these programs often do need to interpret the keys
into characters, or it is important for a certain key to be identifiable to
the user as being associated with a certain key. For instance, a game player
might need to type a description of a saved game or be directed to press a
certain key to activate a game feature. Interpretation of keyboard scancodes
can be difficult since there are many different keyboard layouts which do not
have the same associations between scancodes, modifiers, characters, and
commands. So the author of the program must choose between writing a complex
and customizable conversion routine that can handle any layout the user might
have, and a simple routine that is hard-coded to use a single layout. In the
latter case, users of other keyboard layouts will encounter numerous
discrepancies between what he or she tries to type and what the program
interprets.


** How it works

Svgalib's scancode conversion is meant to at least partially fill this gap by
converting the scancodes that the keyboard produces to equivalent, or nearly
equivalent, scancodes for the keyboard layout that the program expects. The
program then (hopefully) interprets the new scancode into the intended
character.

As an example, let us consider a US keyboard with Dvorak layout and the game
Quake, which expects a US keyboard with QWERTY layout. Both layouts have the
same scancodes for each physical key, but different characters are produced.
For intance, the first row of letters produces the scancodes 16 through 27, but
on QWERTY this produces the charaters qwertyuiop[] while Dvorak produces
',.pyfgcrl/=. Thus when the Dvorak letter `p' is pressed, the scancode 19
is interpreted by Quake as the letter `r', which occupies scancode 19 on the
QWERTY layout.

The solution lies in the fact that svgalib acts as an intermediary between the
keyboard and the program and has the opportunity to present a different
scancode to the program than the keyboard produced. In this case we tell Quake
that the scancode was not 19 but rather 25, which is the letter `p' in the
QWERTY layout, so when Quake interprets the scancode the correct character is
produced.


** The keymap files

In order to know what scancodes to convert to what other scancodes, a keymap
file is read which lists scancodes produced by the keyboard and their
equivalents in the layout expected by the program.

A program called svgakeymap is provided to generate these maps from the
keytable files in /usr/lib/kbd/keytables; you must have perl for it to work.
Creating a keymap file with svgakeymap is easy; to make a map to convert
scancodes from a US Dvorak keyboard to a US QWERTY keyboard as for our example
above:

  svgakeymap dvorak us > dvorak-us.keymap

The path and .map and .gz suffixes are automatically added if necessary. If
your keytables are stored elsewhere, specify a complete path. If only one
keytable is specified, a keymap is generated that performs no conversions but
contains the correct key names so you can specify scancodes used by fake
keyboard and mouse events by name instead of by number. If none are specified,
this is done for the standard US QWERTY layout.

dvorak-us.keymap and default.keymap (the US QWERTY layout) are provided with
the svgalib distribution and can serve as an example if you wish to make your
own keymap files manually or create an improved generator.


** Configuration

You can specify a keymap to use for all svgalib programs (keeping in mind that
only those that use raw keyboard are affected) by putting a line like this into
libvga.config or ~/.svgalibrc:

  kbd_keymap /etc/vga/dvorak-us.keymap

You must specify a complete path to the keymap file. If no keymap is specified,
no conversion is performed.

You can also override the global keymap by setting the environment variable
SVGALIB_KEYMAP to point to the appropriate keymap file. This can be useful if
some programs support alternate keymaps directly but not others, or if
different users use their own keyboard layouts based on preference.


** Security issues

It can be dangerous to let users arbitrarily reassign keyboard scancodes; for
instance all keys could be routed to an unused scancode, making the console
unusable. To prevent this, put the option kbd_only_root_keymaps into
libvga.config; only keymaps owned by root will be accepted, so the available
keymaps can be limited to safe ones.


** Bugs and limitations

There are no known bugs, but there probably are some. If you find any please
let me know at brion@pobox.com.

Limitations however we definitely have. The scancode conversion performed is
very simple, and can only achieve 100% success when the keyboard layouts being
converted between differ _only_ in arrangement of keys while producing the same
characters from each key. Example: the de facto standard Dvorak keyboard has
the left and right brackets (`[' and `]') on separate keys, with the curly
braces (`{' and `}') produced by those keys when shifted. The standard QWERTY
keyboard produces those characters the same way, the only difference is that
the keys are a row higher on Dvorak; switching the scancodes around results in
proper character interpretation. However the official ANSI standard Dvorak
layout has tho two brackets on _the same key_, one regular and one shifted.
The curly braces similarly have their own key. These cannot be properly mapped
by scancode to the QWERTY keyboard since they produce different characters
in conjunction with modifiers, and the wrong character is produced by the
program.

This could be worked around by interpreting the modifiers in svgalib and
simulating the proper modifier/character keypress/release sequences, but it
would be very complex and would do nothing to help the situation where
characters on the physical keyboard layout do not exist on the target layout
(quite likely when dealing with national or language-specific keyboards);
they cannot be converted into any key sequence since they do not exist.

Ultimately it might be better to set up a ``medium-rare'' keyboard mode where
keys are interpreted into characters but ``raw''-style non-interpreted key
press and release events are available.


** Further information

There isn't really any further information right now unless you want to Use The
Source... More to come in the future. If it does you'll find it at:

  Brion Vibber's Svgalib Stuff - http://pobox.com/~brion/linux/svgalib.html


-- brion vibber (brion@pobox.com)
   3 July 1998
