Keys & Consoles

A Member of the Linux Documentation Project

"The Linux Gazette...making Linux just a little more fun...! "

Copyright (c) 1996 John M. Fisk fiskjm@ctrvax.vanderbilt.edu
The LINUX GAZETTE is a member of the LINUX DOCUMENTATION PROJECT.

Of Keyboards and Consoles...

(The following article was submitted to the Linux Journal for publication and is being presented here with the permission of the publisher of the Linux Journal -- John M. Fisk)


Keyboards, Consoles, and VT Cruising

by
John M. Fisk <fiskjm@ctrvax.vanderbilt.edu>
July 1, 1996

"It's a GUI, GUI, GUI, GUI world!" -- or so the major OS manufacturers would have you belief. Truth is, that while this is increasingly the case, there are times when the command line interface (CLI) is still a very good choice for getting things done. It's fast, generally efficient, and is a good choice on memory or CPU constrained machines. And don't forget that there are still a lot of very nifty things that can be done "at the console."

In this spirit, I'd like to start by following up on a delightful and informative article written by Allesandro Rubini entitled "The Best Without X" that appeared in the November, 1995 (Issue 19) edition of the Linux Journal. Among a wealth of helpful ideas, Allesandro suggested converting the numeric keypad into a "console-switch scratch pad" to allow single key switching from one virtual terminal (VT) to another. We'll begin by looking at how this can be done. We'll also look at:

By the time that you get through tinkering around with these things I think you'll agree that the CLI isn't such a bad place after all :-) Also, the good news is that the programs you'll need for this are standard inclusions in most recent Linux distributions and include:

A listing of Linux FTP archives where these may be found is included at the end of this article.

THE KEYPAD VT-SWITCHER

The numeric keypad is an ideal candidate for remapping into a virtual terminal (VT) switching scratch pad as most of us have never learned to "touch type" using the keypad. In addition, on a 101-key keyboard, its non-numeric functions are already duplicated by the Home, End, Page Up, Page Down, Insert, Delete, and arrow keys. Since there may be occasions in which we still want to use the keypad for numeric input let's see how to set it up as a VT switcher while retaining numeric input ability.

To do this you'll need to have the kbd package installed on your system. The two programs we'll be using for this are the 'showkey' and 'loadkey' programs. To check whether they are installed on your system you can type in:

    % type loadkeys showkey

if you're using the BASH shell, or:

    % which loadkeys showkey

The 'which' program or the BASH shell built-in function 'type' will both print the path to the executable if they exist in the PATH search path. On my machine this produces:

    ~$ type showkey loadkeys
    showkey is /usr/bin/showkey
    loadkeys is /usr/bin/loadkeys

    ~$ which showkey loadkeys
    /usr/bin/showkey
    /usr/bin/loadkeys

If you don't have these programs installed you'll need to get the sources for the kbd package and install it yourself. (This comes as source only but installation is as simple as unachiving it into a temporary directory and typing in 'make && make install').

Converting the keypad into VT switcher involves defining a keyboard mapping and then using loadkeys to actually load this information into the kernel keyboard translation tables. It's a whole lot easier than it sounds although you must keep in mind that indiscriminate tinkering can render your keyboard useless (requiring one of those dreaded cold reboots) and that changing the keyboard translation tables affects ALL VT's, not just the one you're working on.

The kbd package default installation location is under /usr/lib/kbd with the key mapping files in the keytables subdirectory. Change to this directory and make a copy of the defkeymap.map file. This is the default keyboard mapping and is a useful place to start. You can call the new file anything you'd like - e.g.,

    cp defkeymap.map custom.map

Use your favorite editor and load up this file. At this point it's probably helpful to stop for a moment and have a look around. It's rather like visiting one of those fine old curio shops -- look, but don't touch! The first few lines may look something like this:

keycode   1 = Escape  Escape
    alt keycode   1 = Meta_Escape
keycode   2 = one  exclam
    alt keycode   2 = Meta_one
    shift   alt keycode   2 = Meta_exclam
keycode   3 = two   at   at
    control keycode   3 = nul
    shift   control keycode   3 = nul
    alt keycode   3 = Meta_two
    shift   alt keycode   3 = Meta_at

I won't go into all the gory details of how to remap the keyboard except to say that the basic format that we'll use is:

    keycode keynumber = keysym
    modifier keycode keynumber = keysym

in which 'keynumber' is the internal identification number of the key and 'keysym' represents the action to take. Now before you bail out on me let's put this into simple terms. Each key on the keyboard is identified by a unique number which is represented by 'keynumber'. When a key is pressed or released these events are passed to the operating system which responds by performing the appropriate action -- represented here by 'keysym'. The 'modifier' is a key which is held down at the same time that the key is pressed. These 'modifier' keys include the well known control, alt, and shift keys. Being able to define multi-key combinations extends the mapping available for each key.

So, using the example above, pressing the key associated with keynumber 3 actually causes the number '2' to be printed to the screen. If the shift key is held down at the same time as the key is pressed, the '@' sign is printed to the screen, and if the three key combination Shift+Alt+keynumber 3 is pressed, the output is the Meta_at (whatever one of those looks like).

Getting back to the task at hand, what we want to do is change to a specified VT when we press one of the keypad keys: pressing keypad 1 should switch to VT number 1, pressing keypad 2 should switch to VT number 2, and so forth. In your customized key map file find the section that defines the keypad keys -- it should look similar to this:

keycode  71 = KP_7
    alt keycode  71 = Ascii_7
keycode  72 = KP_8
    alt keycode  72 = Ascii_8
keycode  73 = KP_9
    alt keycode  73 = Ascii_9
[...]

Now, edit this section so that it reads something like:

# NUMERIC KEYPAD MAPPING
#
# The section remaps the keypad keys so that they act as a
# VT-switcher:  keypad 1 switches to VT 1, keypad 2 to VT 2,
# and so forth.  Note that pressing Shift+key switches to a VT
# which is 10+ the number of the key (Shift+3 = VT 13) and that
# pressing Alt+key (when Num Lock is on) causes numeric output.
#
# Keypad number 7
#
keycode  71 = Console_7
    shift       keycode  71 = Console_17
    alt         keycode  71 = KP_7
    alt control keycode  71 = Console_7
#
# Keypad number 8
#
keycode  72 = Console_8
    shift       keycode  72 = Console_18
    alt         keycode  72 = KP_8
    alt control keycode  72 = Console_8
#
# Keypad number 9
#
keycode  73 = Console_9
    shift       keycode  73 = Console_19
    alt         keycode  73 = KP_9
    alt control keycode  73 = Console_9
keycode  74 = KP_Subtract
#
# Keypad number 4
#
keycode  75 = Console_4
    shift       keycode  75 = Console_14
    alt         keycode  75 = KP_4
    alt control keycode  75 = Console_4
#
# Keypad number 5
#
keycode  76 = Console_5
    shift       keycode  76 = Console_15
    alt         keycode  76 = KP_5
    alt control keycode  76 = Console_5
#
# Keypad number 6
#
keycode  77 = Console_6
    shift       keycode  77 = Console_16
    alt         keycode  77 = KP_6
    alt control keycode  77 = Console_6
keycode  78 = KP_Add
#
# Keypad number 1
#
keycode  79 = Console_1
    shift       keycode  79 = Console_11
    alt         keycode  79 = KP_1
    alt control keycode  79 = Console_1
#
# Keypad number 2
#
keycode  80 = Console_2
    shift       keycode  80 = Console_12
    alt         keycode  80 = KP_2
    alt control keycode  80 = Console_2
#
# Keypad number 3
#
keycode  81 = Console_3
    shift       keycode  81 = Console_13
    alt         keycode  81 = KP_3
    alt control keycode  81 = Console_3
#
# Keypad number 0
#
keycode  82 = Last_Console
    shift keycode  82 = Console_10
    alt   keycode  82 = KP_0
#
# Keypad '.' key
#
keycode  83 = KP_Period
    altgr control keycode  83 = Boot
      control alt keycode  83 = Boot
keycode  84 = Last_Console

Before going on let's make a couple observations. First, it's not a bad idea to comment the file as you go. What's seems so clear and obvious now quickly fades into obscurity as the weeks pass. Adding comments will help prevent your having to pour back over manual pages, program documentation, and magazine articles looking for the correct syntax or usage.

Second, notice that with each entry there are "sub-stanzas" if you will, that begin with the words "alt keycode" "shift keycode" etc. These are the stanzas that define multi-key combinations in which a "modifier" key is pressed at the same time as the key being defined. A common example of this is the "Ctrl-C" combination that is used to terminate a program in execution.

Finally, you may be asking yourself how you're supposed to know which keynumber is associated with a key. Anyone know off hand what keynumber goes with the " key? The way you find this out is using the 'showkey' program. After you invoke the program, showkey prints the keynumber for any key that you hit (and quits after 10 seconds of no input). So, now that we've already edited the pertinent section in the 'custom.map' file, let's see how we'd arrive at this "from scratch."

The basic steps we'd need to take would be to:

To do this, let's begin by using the 'showkey' program which can be invoked using:

    % showkey

Now, any key that you press causes showkey to print the keynumber. On my machine, invoking showkey and pressing keypad keys 1 through 9 results in the following output:

~$ showkey
kb mode was XLATE

press any key (program terminates after 10s of last key press)...
keycode  79 press
keycode  79 release
keycode  80 press
keycode  80 release
keycode  81 press
keycode  81 release
keycode  75 press
keycode  75 release
keycode  76 press
keycode  76 release
keycode  77 press
keycode  77 release
keycode  71 press
keycode  71 release
keycode  72 press
keycode  72 release
keycode  73 press
keycode  73 release

You can see that both key press and key release events are detected. Also note that the numbering of the keypad keys is not sequential. The numeric keys have the following format:

Actual Key:                 Keynumber:

7    8    9                 71   72   73

4    5    6                 75   76   77

1    2    3                 79   80   81

So that keypad number 1 has keynumber 79, keypad number 2 has keynumber 80, and so forth. Knowing this, we can now set up the appropriate key map entry for each of these keys. The keysym event that we're interested in is Console_x, in which 'x' is the number of the VT to which the view is switched. So, a simple entry to map keypad number 1 to switching to VT 1 would look like:

    keycode 79 = Console_1

If you look at the example given above, you'll notice that this is what we've done. Suppose, however, that we wanted to switch to a VT greater than 9, how are we to do that? The solution to this is to use a modifier key combination. Looking again at the example above, using the Shift key with the keypad allows us to use Console_10 through Console_19.

We also wanted to be able to use the numeric keypad as just that -- a means of entering numeric data. In the example above, notice that the modifier 'alt' was used to do this:

keycode  71 = Console_7
    shift       keycode  71 = Console_17
    alt         keycode  71 = KP_7
    alt control keycode  71 = Console_7

In this stanza for the keypad 7 key, the first entry maps the keypad 7 key to switch to VT 7. The second line maps Shift+keypad 7 to switch to VT 17 and the third line maps the Alt+keypad 7 combination to KP_7 which is the keysym for numeric output when Num Lock is 'on'. Thus, to use the keypad as a numeric keypad, hit the Num Lock key so that it toggles to 'on' and then hold down the Alt key while you enter numbers at the keypad.

Note, too, that in this example, Alt+Ctrl+keypad was defined to switch to the same console as simply pressing the keypad key itself. In this case, it acts in exactly the same fashion as occurs when the the Alt+Fn (Alt + Function key) or Alt+Ctrl+Fn (Alt + Ctrl + Function key) combination is used. The intuitive will immediately have noticed that this is how one is typically instructed to switch from one VT to another. Looking at the stanzas for the function keys you'll notice entries such as the following:

keycode  59 = F1    F13    Console_13
    control keycode  59 = F25
    shift   control keycode  59 = F37
    alt keycode  59 = Console_1
    control alt keycode  59 = Console_1

Note that both Alt+F1 and Alt+Ctrl+F1 are used to switch to VT 1. Those of you using X will probably already have found that switching to a VT from X requires the three key Alt+Ctrl+Fn key combination while the two key Alt+Fn key combination is used at the console. Obviously, while you can change this default behavior it's best to leave this as is.

So, at this point, we've defined mappings for the keypad keys such that each key acts as a switch to the VT of the same number. Using Shift+keypad key switches to VT (10 + keypad number) and using Alt+keypad key with the Num Lock 'on' outputs the numeric value of the key. The final step is to actually load the new mapping and give it a try. This is done using 'loadkeys' and can be done without having to log in as root. To load the customized keymap enter:

    % loadkeys /usr/lib/kbd/keytables/custom.map

This will print a message indicating that the 'custom.map' file is being loaded. After this, you're all set! Give it a try. To revert back to the default mapping simply enter:

    % loadkeys /usr/lib/kbd/keytables/defkeymap.map

and the default mappings will be loaded once again. You can use this edit -> load customized map -> test -> load default map cycle to get the mapping that you want. Once you've created a custom map file and wish to have it loaded at boot, you can add an entry to one of the rc.* files, such as rc.local, to have loadkeys automatically load your customized mapping:

    if [ -r /usr/lib/kbd/keytables/custom.map ]; then
        loadkeys /usr/lib/kbd/keytables/custom.map
    fi

This ensures that the file is present and readable and then invokes loadkeys to load the file. Again, keep in mind that loading a key mapping changes the keytable information for ALL VT's, not just the one you are working on.

GETTING FROM HERE TO THERE

Now that we're on a bit of a roll, let's see how else we can move from one VT to another. The utility of being able to quickly switch from one VT to another should be obvious: you can be compiling a program on VT 1, editing a file on VT 2, reading program documentation on VT 3, and have a manual page displayed on VT 4. Now that you've remapped the keypad, switching from one VT to the next is as simple as pressing the keypad keys. But there are other handy means of getting around as well and these include:

The Incr_Console and Decr_Console keysym do as their names might imply: they switch to (VT + 1) or (VT - 1) respectively. So, if you were currently working at VT 3, the Incr_Console keysym would switch you to VT 4 while the Decr_Console keysym would switch you to VT 2. The Last_Console keysym also does as its name might imply: it switches to the last VT that you were previously at. If you were working at VT 3 and switched to VT 6, the Last_Console keysym would switch you back to VT 3.

You can map a key or modifier+key combination to invoke any of these keysyms. I've mapped these to:

    Ctrl+left arrow  = Decr_Console
    Ctrl+right arrow = Incr_Console
    keypad 0         = Last_Console

Obviously, you can map these in any manner you wish, but the relevant entries to map the above actions would be:

#keycode  82 = KP_0
keycode  82 = Last_Console
    shift keycode  82 = Console_10
    alt   keycode  82 = KP_0

[...]
keycode 105 = Left
    alt keycode 105 = Decr_Console
keycode 106 = Right
    alt keycode 106 = Incr_Console

These entries map the keypad 0 key to the Last_Console keysym and the Alt+ left or right arrows to Decr_Console or Incr_Console keysyms. The good news is that these last two are already the default so that you only have to edit the stanza for the keypad 0 key. Now, you can quickly cycle through all the VT's by holding down the Alt key and repeatedly pressing the left or right arrow. To alternate between two VT's you have only to repeatedly hit the keypad 0 key. I've found these mappings to be quite useful but, as has been mentioned before, they can be customized to anything that you find helpful.

The last bit of VT cruising magic is the 'chvt' program which is included with the kbd package. It's use is quite simple:

    % chvt 3

would change to VT 3. Substituting another number for '3' allows you to change to that VT. A foreshortened version of this can be set up using a shell alias:

    % alias vt='chvt'

so that entering:

    % vt 3

would switch you to VT 3.

So, now that we've defined several methods of getting from VT to VT it is important to note that works only at the console and not under the X Window system. Under X, the X server takes control of the keyboard, mouse, and display: setting up customized keyboard mappings is performed using the ~/.Xmodmap file or the program 'xkeycaps' and is a subject for some later article :-)

THE USEFUL UNUSED VT

Having the capacity to open multiple VT's and have programs running on these in the foreground or background is one of the things that makes running Linux such a huge amount of fun. As the old Surgery Prof used to harangue against his interns, "Help me, help me! If I had another set of hands I'd help myself!" Linux gives you that extra "set of hands." Generally, most VT's, to be useful, must have a 'getty' running on it in order to log in. A 'getty' is a program which is associated with a terminal and which:

Without going into all the details of this (again, a subject for a later article) suffice it to say that this is set up in the /etc/inittab file. A sample entry for this might look like:

# The getties in multi user mode on consoles an serial lines.
#
# NOTE NOTE NOTE adjust this to your getty or you will not be
#                able to login !!
#
# Note: for 'agetty' you use linespeed, line.
# for 'getty_ps' you use line, linespeed and also use 'gettydefs'
c1:1235:respawn:/sbin/agetty 38400 tty1 linux
c2:1235:respawn:/sbin/agetty 38400 tty2 linux
c3:5:respawn:/sbin/agetty 38400 tty3 linux
c4:5:respawn:/sbin/agetty 38400 tty4 linux
c5:5:respawn:/sbin/agetty 38400 tty5 linux
c6:45:respawn:/sbin/agetty 38400 tty6 linux

The important thing to note here is that the 'agetty' program is run on each of the tty devices from tty1 to tty6. Thus, at system startup there are a total of six getty's running allowing you to log in to VT 1 through 6. So what about VT 7 and beyond? Are they still usable in any way?

If you've remapped you keyboard, try pressing keypad 7 -- alternatively, hit Alt-F7 -- and see what happens. In general, the screen is blank with the cursor positioned at the upper left corner. You can type in at the keyboard and the output is displayed on the screen. Despite this, there is no way to execute programs at this terminal. Now you see the purpose of the 'getty' program: without being able to log in at a terminal it really isn't much use. There are, however, two important exceptions to this.

SO WHERE DID X GO...?

The first is to note that when the X Window system starts, it is displayed on the first unused tty -- one that doesn't have a getty running on it. Since the first six tty's had getty's running on them, X would, in the example above, start on tty 7. This is the solution to the great riddle of, "so where is X ?!" when you switch from X to a console. Hitting Ctrl+Alt+F1 in X would switch you to VT 1. If you wanted to get back to X simply:

You get the idea.

PUTTING THAT UNUSED VT TO WORK...

The other thing to note is that while you can't run programs on a VT without logging in, you can still send output there. As a simple experiment try the following:

    % echo "This is a test" > /dev/tty7

Switching to VT 7, you'll see the words, "This is a test" displayed. This becomes useful with system logging. Without going into an exhaustive discussion of system logging and configuration, it is worth noting that the output of all logging facilities can be "dumped" to an unused VT which allows quick perusal for events such as login's, kernel messages, mail logging, and so forth.

To do this simply add the following line to the /etc/syslog.conf file (after logging in as root):

# this one will log ALL messages to the /dev/tty9 terminal
# since this is an unused terminal at the moment.  This way, we
# don't need to hang a getty on it or take up a lot of system resources.
*.*						/dev/tty9

Once you've added this stanza to /etc/syslog.conf, you'll need to either kill and restart the syslog daemon or else send it the HUP (hang up) signal. Since this latter method is fairly easy let's do it:

    % ps -x | grep syslog
    28  ?  S     0:01 /usr/sbin/syslogd

will output the PID (process ID number) of the syslog daemon which in this case is 28. Now, just type in:

    % kill -HUP 28

in which '28' is the PID number. The syslog daemon will then re-read its initialization files. From here on, all logging that occurs, regardless of its source, will be output to tty9 (or whichever tty device you specify).

Switching to VT 9 you might see something like the following:

Jul  1 10:11:37 FiskHaus kernel: Max size:342694   Log zone size:2048
Jul  1 10:11:38 FiskHaus kernel: First datazone:68   Root inode number 139264
Jul  1 10:11:38 FiskHaus kernel: ISO9660 Extensions: RRIP_1991A
Jul  1 12:21:50 FiskHaus login: ROOT LOGIN ON tty2
Jul  1 17:26:56 FiskHaus login: 1 LOGIN FAILURE ON tty5, fiskjm

The first three lines represent kernel messages that occur when a CD was mounted. Root logins are noted by the 'login' program as well as login failures -- in this last case I purposely entered an incorrect password.

The value of all of this logging may not be immediately evident, but if you've ever noticed that your machine begins thrashing about and swapping like crazy or that, while online, your hard drive lights begin to light up when you're not doing anything -- a quick switch to VT 9 can often give you an idea about what's going on.

Well, all of this should get you going! The manual pages for 'loadkeys', 'showkey', and 'keytables' have much more complete technical descriptions of key mapping. Also, the kbd package comes with a good deal of helpful documentation in its /doc subdirectory. And finally, don't forget the Keyboard-HOWTO which can be found amongst the growing number of Linux HOWTO's.


APPENDIX:

FTP sites where programs can be found:

kbd-0.91.tar.gz:
ftp://ftp.cc.gatech.edu/pub/linux/systems/Keyboards/kbd-0.91.tar.gz

util-linux-2.5.tar.gz
ftp://ftp.cc.gatech.edu/pub/linux/systems/Misc/util-linux-2.5.tar.gz

sh-utils-1.12-bin.ELF.tar.gz
sh-utils-1.12-bin.tar.gz
ftp://ftp.cc.gatech.edu/pub/linux/utils/shell/sh-utils-1.12-bin.ELF.tar.gz
ftp://ftp.cc.gatech.edu/pub/linux/utils/shell/sh-utils-1.12-bin.tar.gz

Keyboard-HOWTO
ftp://ftp.cc.gatech.edu/pub/linux/docs/HOWTO/Keyboard-HOWTO

Note that the FTP site is GA Tech -- a Sunsite mirror. Please check the MIRRORS file in the /pub/Linux subdirectory for a site nearest you.



Back to Linux Gazette #8

This page written and maintained by:
John M. Fisk at fiskjm@ctrvax.vanderbilt.edu