Linux Keyboard Setup Mini-Howto
 Stephen Lee, [email protected]
 Version 1.3, 16 Sep 1995

 This Mini-HOWTO document describes setting up the kernel and applica-
 tions to handle the Cursor control keys.

 1.  Introduction


 It has been annoying to me that cursor keys had not work consistently
 across different programs (and on different machines), so I took some
 time and tried to fix all that.  Here I document my experience so
 others would not need to go through the same tedious cycle I did.

 I'm using Slackware 2.0.1, so pathnames to files might be different
 from yours if you are using a different distribution.

 Some of the material here appeared in an earlier ``BackSpace Mini-
 HOWTO''.  Although the method described there still works, I consider
 this a better solution.


 1.1.  Typography



 o  This is a program name.

 o  This is a ``command'' you'd type on a keyboard.

 o  This is a <Key> on the keyboard.  eg. <BackSpace>, <Delete>,
    <Shift-l>, <Ctrl-q> etc.

 o  This is an [X11 Keysym] which you can use for mapping keys under X.
    eg. [BackSpace], [Delete], [Left], [Home] etc.


 1.2.  Terminalogy



    ESC
       ASCII character 0x1B.


    BS ASCII character 0x08, or control-h.


    DEL
       ASCII character 0x7F.


    ^D ASCII character 0x04, or control-d.


    VC A Linux Virtual Console.




 1.3.  Acknowledgements


 Thanks to the following people who commented on my ``BackSpace Mini-
 HOWTO'':
 John Copella, Andrew Rakowski, Dr. Jacques Gelinas, Michael Bischoff,
 Topher Hughes, Chuck Meyer, Alexis Kotte, and especially Ted Stern and
 Steve Dunham.

 Thanks to Jamie Zawinski from Netscape Communications for pointing out
 the correct fix for the Backspace problem in Motif applications, and
 for the xkeycaps(1) program.


 2.  Non-X configuration


 I assume you came from the DOS world like I did, and is used to the
 mapping of function that <BackSpace> deletes character to the left of
 the cursor and <Delete> deletes character on top of the cursor.

 Under a shell, the most intuitive mapping is <BackSpace> -> BS and
 <Delete> -> DEL.  This is fine unless you want to use EMACS. EMACS map
 <Ctrl-h> to its help function, which, under ASCII, is unfortunately
 BS.  So each time you want to erase a character backwards, you invoke
 the help system.  Also, DEL under Emacs deletes BACKWARDS, like what
 you'd expect for BS.

 One choice is to remap the keys under Emacs.  Unfortunately you'll
 lose the ``<Ctrl-h> = help'' mapping.  So, I decided to map
 <BackSpace> -> DEL.  This leaves BS for use by <Ctrl-h> in Emacs.

 So, now what shall we do for the <Delete> key?  In a previous verion
 of this document I used ^D, which works under both Emacs and csh/tcsh
 as a ``Delete character on cursor'' function.  But since then I've
 found a better solution.  The kernel by default maps <Delete> as the
 VT100 ``Remove'' key sequence (``ESC[3~'').  It is not hard to teach
 Emacs and tcsh to recognize it.  The advantage is that you can bind it
 differently than <Ctrl-d> in programs.  Also, it is more consistent if
 you also map other cursor control keys.  The disadvantage is that you
 might not be able to use it in some application which you can't bind
 key sequences (but than apply to the <Delete> -> ^D binding as well).


 2.1.  Linux console


 Linux console key bindings are controlled by the kernel.  The kernel
 by default generates the correct bindings for <Backspace> and
 <Delete>, so you should not need to change that.

 However, if you do, the following programs (in the 'kbd' package,
 which should come with Slackware already) affect the key bindings:



    showkeys
       ``showkeys'' shows the Linux keycode generated by a key. The
       keycode can then be used by loadkeys(1) to change the keymap.


    dumpkeys
       Shows the current keybindings. See the manual page for more
       detail.


    loadkeys
       ``loadkeys file'' loads keybindings from file ``file''. Note
       that this changes the key bindings for ALL virtual consoles.
       This is usually done at boot time in /etc/rc.d/rc.local.

       You can start with one of the keytable files in
       /usr/lib/kbd/keytables/*.map and edit that. The one that is
       compiled into your kernel would be
       /usr/src/linux/drivers/char/defkeymap.map if you have the kernel
       source. The format of the file is described in the keytables(5)
       manual page.

       The keys of particular interest are <BackSpace> (keycode 14),
       <Delete> (111).


    setmetamode
       ``setmetamode'' controls whether the keystroke <Alt-x>, where x
       is some key, would send the keycode M-x or the key sequence ESC
       followed by x. This is virtual-console-specific, you can have
       different setting in different virtual consoles.



 2.2.  tty (including the Linux console)


 ``stty erase <ch>'' tells the terminal what character your <BackSpace>
 key generates.  It does NOT change your key bindings.  If you map
 <BackSpace> to DEL then do a ``stty erase '^H''' it won't magically
 changes your <BackSpace> key to generate ^H; it would only confuse
 your computer.

 To correctly set your terminal ``erase'' character to DEL, type ``stty
 erase '^?''' (where ^? can be '^' followed by '?' or <Ctrl-v>
 <BackSpace>) at your shell prompt.  You might want to put this in your
 $(HOME)/.cshrc or $(HOME)/.profile.

 Note: although csh/tcsh treats BS and DEL the same way, other programs
 don't.  So your mapping might seem to work under csh/tcsh but you get
 wierd stuff like ^? under some programs.  Solution: remember the
 ``stty'' command above.


 2.3.  Shells



 2.3.1.  tcsh


 tcsh provides the command ``bindkey'' for binding keys:


    bindkey
       lists all current bindings.


    bindkey ``str'' function
       binds input string ``str'' to ``function''.  A list of tcsh
       functions can be obtained by ``bindkey -l''.


    bindkey -k <up | down | left | right> function
       binds an arrow key to ``function''.


 Example: To bind cursor control keys, put this in $HOME/.cshrc:



 ______________________________________________________________________
     if ($term == "xterm" || $term == "vt100" \
           || $term == "vt102" || $term !~ "con*") then
         # bind keypad keys for console, vt100, vt102, xterm
         bindkey "\e[1~" beginning-of-line  # Home
         bindkey "\e[2~" overwrite-mode     # Ins
         bindkey "\e[3~" delete-char        # Delete
         bindkey "\e[4~" end-of-line        # End
     endif
 ______________________________________________________________________



 See the man page for tcsh(1) for a complete description.

 Example: You can have 4DOS-style command history under tcsh with the
 tcsh function-pair history-search-backward (Meta-p) and history-
 search-forward (Meta-n).  Typing ``abc<Meta-p>'' will only show lines
 in history that start with ``abc''.  Also, function magic-space
 expands !  histories as you type, and I prefer them over the default
 so I bound them to the up/down arrow keys and space:


 ______________________________________________________________________
     bindkey -k up history-search-backward
     bindkey -k down history-search-forward
     bindkey " " magic-space
 ______________________________________________________________________




 2.3.2.  bash


 The ``.inputrc'' file contains the list of key bindings to functions.

 For example, if you put the following line in $HOME/.inputrc:


 ______________________________________________________________________
     "\e[1~": beginning-of-line
     "\e[3~": delete-char
     "\e[4~": end-of-line
 ______________________________________________________________________



 It will map the <Home>, <Delete>, and <End> keys respectively to the
 corresponding functions.

 You might also need the following line if your <BackSpace> key sends
 the ASCII DEL:


 ______________________________________________________________________
     DEL: backward-delete-char
 ______________________________________________________________________



 You probably don't need it (I don't), but it's worth a try if you run
 into trouble.



 2.4.  Editors



 2.4.1.  Emacs 19


 Emacs 19 provides the elisp function define-key for binding keys.  You
 can bind a key sequence to a function key like this in $(HOME)/.emacs:


 ______________________________________________________________________
     ;; map function keys on PC keyboard
     (setq term (getenv "TERM"))
     (if (or
          (string= "xterm" term)
          (string= "con" (substring term 0 3)) ; linux consoles
          (string= "vt100" term)
          (string= "vt102" term))
         (progn
           (defun my-setkey-hook ()
             (define-key function-key-map "\e[1~" [home])
             (define-key function-key-map "\e[2~" [insert])
             (define-key function-key-map "\e[3~" [delete])
             (define-key function-key-map "\e[4~" [end])
             ;; these are just my own sequences
             ;; so I can use the keys under Emacs
             (define-key function-key-map "\e[40~" [C-prior])
             (define-key function-key-map "\e[41~" [C-next])
             ;; function keys: use same mapping as xterm
             (define-key function-key-map "\e[11~" [f1])
             (define-key function-key-map "\e[12~" [f2])
     ;; ...
             (define-key function-key-map "\e[24~" [f12])
             (define-key function-key-map "\e[25~" [S-f1])
             (define-key function-key-map "\e[26~" [S-f2])
     ;; ...
             (define-key function-key-map "\e[39~" [S-f12])
             )
           (add-hook 'term-setup-hook 'my-setkey-hook)
           )
       ()
       )
 ______________________________________________________________________



 Note the function key names are all in lowercase.

 You can also bind function keys (or key sequences, but we won't be
 using that here) to a emacs command with global-set-key like this:


 ______________________________________________________________________
     (global-set-key [delete] 'delete-char)
     (global-set-key [home] 'beginning-of-line)      ; you might not want this
     (global-set-key [end] 'end-of-line)             ; nor this
     (global-set-key [C-prior] 'beginning-of-buffer)
     (global-set-key [C-next] 'end-of-buffer)

     (global-set-key [f1] 'help-for-help)
     ;; ...
     (global-set-key [S-f12] 'info)
 ______________________________________________________________________


 2.4.2.  vi


 Anybody want to write this?


 2.5.  Other Programs



 2.5.1.  less


 lesskey(1) allows you to map keys for the less(1) pager.  Put the
 following lines in your $HOME/.lessrc (this is for VT100-like
 terminals):


 ______________________________________________________________________
     ^[[A   back-line
     ^[[B   forw-line
     ^[[C   next-file
     ^[[D   prev-file
     ^[OA   back-line
     ^[OB   forw-line
     ^[OC   next-file
     ^[OD   prev-file
     ^[[6~  forw-scroll
     ^[[5~  back-scroll
     ^[[1~  goto-line
     ^[[4~  goto-end
 ______________________________________________________________________



 replacing '^[' with the ESC character (ASCII 0x1B), then run ``lesskey
 .lessrc'' in your home directory.  You can then use the cursor pad
 keys for scrolling text under less(1).



 3.  X configuration


 Under the X windows system, every key can have a different keysym
 assigned to it, instead of just an ASCII value of key sequence.  Thus,
 X applications can distinguish easily between, for example, <Tab>
 (which generates the [Tab] keysym) and <Ctrl-i> (which generates the
 [i] keysym with the "Ctrl" modifier).

 One consequence is that we want <BackSpace> to generate the
 [BackSpace] keysym.  However, on most systems <BackSpace> as well as
 <Delete> generate the [Delete] keysym by default due to the way the
 XFree86 server is written (it reads the settings from Linux's key
 map).  This makes the two keys indistinguishable.  This is the number
 1 cause in the ``Backspace doesn't work in my X application'' problem.
 See the entry for xmodmap(1) or xkeycaps(1) for a fix.

 A list of keysyms can be found in <X11/keysymdef.h> (usually
 /usr/include/X11/keysymdef.h), without the XK_ prefix, and also
 /usr/lib/X11/XKeysymDB.  Note X keysyms are case sensitive.

 There are several modifiers (like ``Shift'' and ``Ctrl'') that can be
 generated under X: Shift, Ctrl, Meta, Alt, Super and Hyper.  Note that
 although ``Alt'' is present, most of the time the <Alt> key on the PC
 keyboard is bound to the ``Meta'' modifier; it works with more
 applications this way.


 3.1.  X server



    xev
       xev(1) allows you to see events generated on a window, including
       <KeyPress> and <KeyRelease> events where you can find the
       keycode for a particular key.  Once the keycode is found for a
       key it can be mapped into a X11 keysym with xmodmap.


    xkeycaps
       From the README file:

       xkeycaps is a graphical front-end to xmodmap.  It opens a window
       that looks like a keyboard; moving the mouse over a key shows
       what KeySyms and Modifier bits that key generates.  Clicking on
       a key simulates KeyPress/KeyRelease events on the window of your
       choice.  It is possible to change the KeySyms and Modifiers
       generated by a key through a mouse-based interface.  This
       program can also write an input file for xmodmap to recreate
       your changes in future sessions.  See the man page for more
       details.

       The latest version of xkeycaps is always ftpable from ftp.x.org.
       You can also get it from my web page at this place
       (http://www.netscape.com/people/jwz/).


    xmodmap
       One of the function of xmodmap(1) is to map X keycodes to
       keysyms.

       ``xmodmap <file>'' reads the keycode -> keysym table from the
       file ``file'' (usually named .xmodmaprc or .Xmodmap in the
       user's home directory).  This is usually done by xinit(1) or
       startx(1) when X starts up.

       By default, Slackware loads the file $HOME/.Xmodmap if it is
       present; so putting the following two lines in it should fix
       most problems.  Otherwise, read on.


       ________________________________________________________________
           keycode 22 = BackSpace
           keycode 107 = Delete
       ________________________________________________________________



    ``xmodmap -e "command"'' can be used to execute a single xmodmap
    command, for simple changes.

    For example, you can put the the following lines in $HOME/.xinitrc
    instead of using the $HOME/.Xmodmap file:








    ___________________________________________________________________
        # map the <BackSpace> key to the [BackSpace] keysym.
        xmodmap -e "keycode 22 = BackSpace"
        # map the <Delete> key to the [Delete] keysym.
        xmodmap -e "keycode 107 = Delete"
    ___________________________________________________________________



    (Warning: X exits when the last line of .xinitrc finishes, so if
    you don't have a .xinitrc before, you must put something that will
    continue to run (like the window manager or an xterm) at the end of
    .xinitrc, and don't put it in the background!)

    Lastly, you might generate a map file from your loadkey(1) *.map
    file using ``/usr/lib/kbd/keytables/mk_modmap foo.map > foo.xmap'';
    you need to remove all the ``compose'' command in the output.  Note
    that <BackSpace> would be mapped to the [Delete] keysym if you
    start with the keymap provided, so be sure to edit foo.xmap for
    keycode 22 (BackSpace) and 107 (Delete).



 3.2.  X applications


 X applications are usually configurated via resources.  User
 customizations are usually put in $HOME/.Xdefaults and loaded via
 ``xrdb -load $HOME/.Xdefaults'' in .xinitrc (again, see the warning in
 the xmodmap entry).


 3.2.1.  Terminal Emulators



 3.2.1.1.  xterm family


 Key mappings can be changed like this in $(HOME)/.Xresources:

 ______________________________________________________________________
     *VT100.Translations: #override <Key>BackSpace: string(0x7F)\n\
             <Key>Delete:        string(0x1b) string("[3~")\n\
             <Key>Home:          string(0x1b) string("[1~")\n\
             <Key>End:           string(0x1b) string("[4~")\n\
             Ctrl<Key>Prior:     string(0x1b) string("[40~")\n\
             Ctrl<Key>Next:      string(0x1b) string("[41~")
 ______________________________________________________________________



 This applies to most xterm-based emulators (xterm, color_xterm, kterm
 etc. but not rxvt).


 3.2.1.2.  rxvt


 There is apparaently no way to remap keys in rxvt except by patching
 the source.  Any proof to the contrary would be welcome.





 3.2.2.  Editors



 3.2.2.1.  FSF Emacs 19


 global-set-key can be used to map keys to Emacs commands.  See the
 Emacs 19 entry in the non-X section.  To find out what emacs symbol a
 key sends, press the key in question (in a scratch buffer so it won't
 clobber up your files) and then use the Emacs command view-lossage
 (usually <Ctrl-h> <l>) to see what the key generated.

 Usually the symbol is the X11 keysym in lowercase; for example,
 <Insert> (which generates the [Insert] keysym) would be [insert] in
 Emacs.

 <Shift-fkey>, <Ctrl-fkey>, <Meta-fkey> generates [S-fkey], [C-fkey],
 and [M-fkey] respectively.  Combinations generate something like [C-M-
 fkey].  Other modifiers are s- for "Super", H- for "Hyper" and A- for
 "Alt".


 3.2.2.2.  XEmacs


 Again, use define-key or global-set-key.  I believe both the [keysym]
 method as in FSF Emacs or 'keysym (like below) work.  The method of
 specifying <Ctrl-fkey> etc. is different; both [(control fkey)] or
 '(control fkey) should work.  But note that <Ctrl-A> is '(control a)
 while <Ctrl-Shift-A> is '(control A).  Save '(shift fkey) for non-
 alphabet keys.


 ______________________________________________________________________
 (define-key global-map 'delete 'delete-char)
 (define-key global-map 'backspace 'backward-delete-char-untabify)
 (define-key global-map '(control prior) 'fkey-beginning-of-buffer)
 (define-key global-map '(control next)  'fkey-end-of-buffer)
 (define-key global-map '(control home)  'fkey-scroll-right)
 (define-key global-map '(control end)   'fkey-scroll-left)

 (global-set-key 'f1 'help-for-help)
 (global-set-key 'f3 'isearch-forward)
 (global-set-key 'f4 'query-replace-regexp)
 (global-set-key '(shift f1) 'info)
 (global-set-key '(shift f3) 'isearch-backward)
 ______________________________________________________________________



 Sometimes the <Delete> key doesn't delete forward after changing a
 major mode even if you remapped it like the above.  Then you might
 need to remap it in the keymap for that major mode like the example
 below:











 ______________________________________________________________________
 ;;
 ;; Lisp modes setup
 ;;
 (defun my-lisp-mode-common-hook ()
          (define-key shared-lisp-mode-map 'backspace
            'backward-delete-char-untabify)
          (define-key shared-lisp-mode-map 'delete       'delete-char)
          )

 (add-hook 'lisp-mode-hook 'my-lisp-mode-common-hook)
 (add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-common-hook)
 (add-hook 'lisp-interaction-mode-hook 'my-lisp-mode-common-hook)
 ______________________________________________________________________




 3.2.3.  Other Programs



 3.2.3.1.  Motif applications (e.g. Mosaic, Netscape)


 <BackSpace> should work in Motif applications if it generates the
 [BackSpace] keysym.  See the entry for xmodmap(1).

 Previous version of this document suggested a fix using
 *XmText.translations or *XmTextField.translations resources.  This is
 not recommended anymore as it would break other things.  See the
 netscape FAQ for X
 (http://home.netscape.com/eng/mozilla/1.1/faq_navx.html)


 4.  For more information


 ``kbd.FAQ'' in the kbd package
 (ftp://sunsite.unc.edu/pub/Linux/system/Keyboards/kbd-0.89.tar.gz)
 contains more examples on remapping the keyboard.

 Man pages for the programs mentioned above are good sources of
 information, especially xterm(1x), xmodmap and stty(1).

 Info pages for Emacs tells you how to remap keys under it; use ``emacs
 -f info'' to read them.

 ``Keystroke-mini-HOWTO
 (ftp://sunsite.unc.edu/pub/Linux/doc/HOWTO/mini/Keystroke)'' describes
 a way to assign special action to some of the keys on the keyboard.

 ``the netscape FAQ
 (http://home.netscape.com/eng/mozilla/1.1/faq_navx.html#x12)'' has a
 solution for the ``Backspace doesn't work in Netscape'' problem.