Keyboards, Consoles, and VT Cruising
“It's a GUI, GUI, GUI, GUI world!”—or so the major OS manufacturers would have you believe. The 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, 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 Alessandro Rubini entitled “The Best Without X” in the November 1995 issue (#19) of Linux Journal. Among a wealth of helpful ideas, Alessandro 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 conversion can be done. We'll also look at:
Getting from Here to There: handy methods for VT cruising
The Useful Unused VT: where to put all that logging information, and where X-Windows really ends up
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 to do this conversion are standard inclusions in most recent Linux distributions and include:
kbd 0.91 (keyboard font and utility programs)
utils 2.5 (Rick Faith's huge collection of utilities)
GNU shell-utils 1.12 (shell utilities including the stty program)
A listing of Linux FTP archives where these utilities can be found is included in the sidebar.
The numeric keypad is an ideal candidate for re-mapping into a virtual terminal-switching scratch pad since most of us have never learned “ten-key by touch”. In addition, the non-numeric functions on a 101-key keyboard 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. You'll need to have the kbd package installed on your system. The two programs we'll be using are showkey and loadkey. To check whether they are installed on your system type:
$ 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 the kbd package source, and install it yourself. This package is available only as source code, but installation is as simple as un-archiving it into a temporary directory, then typing:
$make && make install
Converting the keypad into a VT switcher involves defining a keyboard mapping and using loadkeys to actually load this information into the kernel keyboard translation tables. It's 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 VTs, not just the one you're working on. The kbd package's 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, which contains the default keyboard mapping and is a useful place to begin. You can name the new file anything you'd like—e.g.,
cp defkeymap.map custom.map
Use your favorite editor and load up the copied file. At this point it's probably helpful to have a look around at the current contents. The experience is 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 re-map the keyboard except to say that the basic format to 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, the press or release event is 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. The ability 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-3 is pressed, the output is the Meta_at (whatever that looks like).
Getting back to the task at hand, we want to change to a specified VT when we press one of the keypad keys: i.e., pressing keypad 1 should switch to VT number 1, pressing keypad 2 should switch to VT number 2, etc. 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 Listing 1.
Before continuing, let's make a couple of observations. First, it's not a bad idea to comment the file as you go. What seems clear and obvious now fades into obscurity as the weeks pass. Adding comments now will prevent your having to pore over manual pages, program documentation and magazine articles later, looking for the correct syntax or usage. Second, notice that with each entry there are sub-stanzas, beginning with the words alt keycode, shift keycode, etc. These stanzas 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 crtl-c combination used to terminate a program during execution.
Finally, you may be asking yourself how you're supposed to know which keynumber is associated with a key. Does anyone know off-hand what keynumber goes with the ; key? You can find this out by using the showkey program. After you invoke the program, showkey will print the keynumber for any key you press and will quit after 10 seconds of no input. So, now that we've edited the pertinent section in the custom.map file, let's see how we'd arrive at this from scratch. The basic steps would be:
Find the keynumber for the keypad keys.
Edit the customized mapping for the keys so that pressing them would change to the appropriate VT.
Edit the customized mapping for the keys so that the keypad could still be used for numeric input (using a modifier key combination in this case).
Load the customized mapping and see whether it works.
Optionally, have the default key mapping loaded at system boot.
To do this, let's begin by invoking the showkey program:
Now, any key you press causes showkey to print the keynumber. On my machine, invoking showkey and pressing keypad keys 1 through 9 results in the output shown in Listing 2. 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 format shown in Table 1:
Actual Key: Keynumber: 7 8 9 71 72 73 4 5 6 75 76 77 1 2 3 79 80 81
Table 1 shows that keypad number 1 has keynumber 79, keypad number 2 has keynumber 80, etc, Knowing this, we can 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. A simple entry to map keypad number 1 to switching to VT 1 would look like:
keycode 79 = Console_1
If you look at Listing 1, you'll notice that this is what we've done. Suppose, however, we wanted to switch to a VT greater than 9—how are we to do that? The solution 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, press the num lock key so that it toggles to on, then hold down the alt key while you enter numbers at the keypad. Note, too, that alt-crtl-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 the alt-fn (alt-Function_key) or alt-crtl-fn (alt-crtl-Function key) combination. You may have noticed that using the function keys 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-crtl-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-crtl-fn key combination while the two key alt-fn key combination is used at the console. Although you can change this default behavior, it's best not to. 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. The loading is done using loadkeys and can be done without logging on 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 obtain the desired mapping. 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 entry ensures that the file is present and readable and invokes loadkeys to load the file. Again, keep in mind that loading a key mapping changes the keytable information for all VTs, not just your current one.
Now that we're on a bit of a roll, let's look at another method for moving 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 having a manual page displayed on VT 4. Now that you've re-mapped 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:
Using the keysym functions Last_Console, Incr_Console and Decr_Console
Using the chvt program (which is part of the kbd package)
The Incr_Console and Decr_Console keysym functionsdo as their names 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 implies: it switches to the last VT used. 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 keysym functions. I've mapped these functions as follows:
Ctrl+left arrow = Decr_Console Ctrl+right arrow = Incr_Console keypad 0 = Last_Console
Obviously, you can map these functions 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 arrow] or [right arrow] to Decr_Console or Incr_Console keysyms. The good news is that these last two are already the default so that you have to edit only the stanza for the keypad 0 key. Now, you can quickly cycle through all the VTs by holding down the alt key and repeatedly pressing the left or right arrow. To alternate between two VTs you have only to repeatedly press the keypad 0 key. I've found these particular mappings to be quite useful but, as I mentioned before, they can be customized to anything you wish. The last bit of VT cruising magic is the chvt program included with the kbd package. Its 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 this 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 a later article.
Having the capacity to open multiple VTs and to have programs running on them 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 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 VTs, to be useful, must have a getty process running on them in order to log in. A getty is a program associated with a terminal that:
Opens the tty line and sets its mode.
Prints the login prompt and gets the user's name.
Initiates the login process for the user.
Without going into all the details (again, a subject for a later article), suffice it to say that this program is set up in the /etc/inittab file. An entry for a getty might look like Listing 3.
The important thing to note in this listing 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 gettys running, allowing you to log into VT 1 through 6. So what about VT 7 and beyond? Are they still usable in any way? If you've re-mapped your keyboard—try pressing keypad_7—alternatively, press alt-f7—and see what happens. In general, the screen is blank with the cursor positioned at the upper left corner. You can type at the keyboard, and the output is displayed on the screen. Despite this, there is no way to execute programs at this terminal. A terminal you can't log in on isn't much use. There are, however, two important exceptions to this statement.
The first exception to note is 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 ttys had gettys running on them, X would, in the example above, start on tty 7. Now we know the solution to the great riddle, “So where is X ?”, when you switch from X to a console. Pressing crtl-alt-f1 in X would switch you to VT 1. If you wanted to get back to X, simply:
press keypad_0 if you've mapped this to the Last_Console keysym.
press keypad_7 to switch to VT 7 on which X is running.
press alt-f7 to switch to VT 7.
The other exception 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 ability 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 logins, kernel messages, mail logging, etc. 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 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 is 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 your machine thrashing about and swapping like crazy, or, while on-line, 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. These instructions should get you started. 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 among the growing number of Linux HOWTOs http://www.ssc.com/linux/howto.html).
John Fisk (firstname.lastname@example.org) After three years as a General Surgery resident and Research Fellow at the Vanderbilt University Medical Center, he decided to “hang up the stethoscope” and pursue a career in Medical Information Management. He's currently a full time student at the Middle Tennessee State University and working on a graduate degree in Computer Science before entering a Medical Informatics Fellowship. In his dwindling free time, he and his wife Faith enjoy hiking and camping in Tennessee's beautiful Great Smoky Mountains. An avid Linux fan since his first Slackware 2.0.0 installation a year and a half ago