要让删除键和退格键恰到好处地工作并非易事,尤其是在混合环境中,您需要与控制台、X
、bash
、emacs
、远程登录等交互。您可能需要编辑多个配置文件,以精确地告知所有涉及的程序您想要什么。一方面,存在哪个键生成哪个代码的问题(以及这些代码如何被 kermit
或 emacs
等重新映射),另一方面,存在哪些功能绑定到哪些代码的问题。
人们经常抱怨“我的退格键不起作用”,好像这个键有一个内置的功能“删除前一个字符”。不幸的是,这个键,或任何键,所做的只是生成一个代码,而人们只能希望内核 tty 驱动程序和所有应用程序可以被配置成使得退格键确实能像“删除前一个字符”键一样工作。
大多数 Unix 程序通过内核 tty 驱动程序在“cooked”模式下获取它们的 tty 输入,而一个简单的 stty
命令决定了擦除字符。然而,像 bash
和 emacs
以及 X
这样的程序会进行自己的输入处理,并且必须逐个说服它们做正确的事情。
% stty erase ^?
如果字符被擦除了,但是以一种奇怪的方式,那么您的 tty 设置肯定有问题。如果设置了 echoprt
,那么擦除的字符会被 \
和 /
包围。如果 echoe
没有设置,那么擦除字符会被回显(当它是一个可打印字符时,比如 #,这是合理的)。大多数人会想要 stty echoe -echoprt
。输入 stty sane
会完成这个以及更多。输入 stty -a
会显示您当前的设置。为什么默认情况下不是正确的呢?如果您使用正确的 getty
,那就是正确的。请注意,许多程序(如 bash
、emacs
等)都有自己的按键绑定(在 ~/.inputrc
、~/.emacs
等中定义),并且不受擦除字符设置的影响。
标准的 Unix tty 驱动程序不识别光标,或用于移动当前位置的键(如方向键),因此也没有“删除当前字符”命令。但是,例如,您可以通过将以下内容放入 ~/.inputrc
来让控制台上的 bash
识别 Delete 键:
set editing-mode emacs
"\e[3~":delete-char
早些时候,控制台驱动程序在收到 DEL (\177
) 时会执行 BS Space BS (\010\040\010
)。如今,DEL 被忽略了(这是应该的,因为驱动程序模拟了 vt100)。使用一个更好的 getty,即不输出 DEL 的 getty。
在第一次尝试时,您正在与 getty
对话。在第二次尝试时,您正在与 login
对话,这是一个不同的程序。
在控制台上,或者更准确地说,当不在 (MEDIUM)RAW 模式下时,使用
% loadkeys mykeys.map
在 X 下使用
% xmodmap mykeys.xmap
请注意,(自 XFree86-2.1 起)X 在初始化 X 键盘映射时会读取 Linux 的键盘映射设置。尽管这两个系统不是 100% 兼容,但这应该意味着在许多情况下,使用 xmodmap
已经变得多余。例如,假设您希望 Backspace 键发送 BackSpace(Ctrl-H,八进制 010),而灰色 Delete 键发送 DEL(八进制 0177)。将以下内容添加到 /etc/rc.local
(或您存放本地启动时内容的地方)
/usr/bin/loadkeys << EOF
keycode 14 = BackSpace
keycode 111 = Delete
EOF
请注意,这只会更改这些键在未使用修饰键时的功能。(如果您想更改更多键盘映射上的绑定,则需要指定一个 keymaps 行来告知应影响哪些键盘映射。)Linux 内核默认让 Ctrl-Backspace 生成 BackSpace - 这有时作为紧急转义非常有用,当您发现您只能生成 DEL 时。左 Alt 键有时被称为 Meta 键,默认情况下,组合键 AltL-X 绑定到符号 MetaX。但是 MetaX 是什么字符序列呢?这由 Meta 标志(通过命令 setmetamode
设置)按 tty 确定。有两种选择:ESC X 或 X 与 0200 进行或运算。
许多发行版在启动序列的某个地方都有一个 loadkeys
命令。例如,可能在 /etc/sysconfig/keyboard
中有所需键盘映射的名称,而在 /etc/rc.d/init.d/keytable
中有加载它的 loadkeys
命令。或者可能在 /etc/default.keytab
中有实际的默认键盘映射,而在 /etc/rc.d/boot
中有加载它的 loadkeys 命令。等等。除了向默认值添加本地修改外,当然也可以通过编辑默认键盘映射或更改启动时要加载的键盘映射的名称来更改默认值。请注意,loadkeys
本身具有默认键盘映射 defkeymap.map
,它位于 /usr/lib/kbd
或 /usr/share/kbd
下的某个位置(就像所有其他键盘映射一样),并且在挂载 /usr
之前,这可能在单用户启动中尚不可用。
命令
% loadkeys dvorak
将为您提供 dvorak 布局,可能是通过加载类似 /usr/lib/kbd/keymaps/i386/dvorak/dvorak.map.gz
的内容。在 X
下,将
XkbLayout "dvorak"
放入 XF86Config
。
(i)因为 VT100 在 Enter 键上方有一个 Delete 键。
(ii)因为 Linus 这样决定。
% xmodmap -e "keysym BackSpace = Delete" -e "keysym Delete = BackSpace"
或者,如果您只是想让 Backspace 键生成 BackSpace
% xmodmap -e "keycode 22 = BackSpace"
或者,如果您只是想让 Delete 键生成 Delete
% xmodmap -e "keycode 107 = Delete"
(但这通常已经是默认绑定)。
在您的 .emacs
文件中放入类似以下的行
(global-set-key "\?" 'help-command)
(global-set-key "\C-h" 'delete-backward-char)
当然,您可以用相同的方式将其他命令绑定到其他键。请注意,各种主要和次要模式会重新定义按键绑定。例如,在增量搜索模式中,可以找到以下代码
(define-key map "\177" 'isearch-delete-char)
(define-key map "\C-h" 'isearch-mode-help)
这意味着使用上述两个 global-set-key 命令可能不是一个好主意。有太多的地方对 Ctrl-H = help 和 DEL = delete 有内置的假设。但这并不意味着您必须设置键,以便 Backspace 生成 DEL。但如果不是这样,那么最简单的方法是在 emacs 中尽可能低的级别重新映射它们。
在您的 .emacs
文件中放入以下行
(setq keyboard-translate-table (make-string 128 0))
(let ((i 0))
(while (< i 128)
(aset keyboard-translate-table i i)
(setq i (1+ i))))
(aset keyboard-translate-table ?\b ?\^?)
(aset keyboard-translate-table ?\^? ?\b)
最新版本的 emacs 有一个函数 keyboard-translate
,可以简化上述操作为
(keyboard-translate ?\C-h ?\C-?)
(keyboard-translate ?\C-? ?\C-h)
请注意,在 X 下,emacs 可以区分 Ctrl-h 和 Backspace 键(无论这些键在控制台上产生什么代码),并且默认情况下,emacs 会将 Backspace 键视为 DEL(并执行绑定到该字符的删除操作,而不是绑定到 Ctrl-H 的帮助操作)。可以区分 Backspace 和 Delete,例如通过
(global-unset-key [backspace] )
(global-set-key [backspace] 'delete-backward-char)
(global-unset-key [delete] )
(global-set-key [delete] 'delete-char)
在您的 .kermrc
文件中放入以下行
set key \127 \8
set key \8 \127
XTerm*VT100.Translations: #override\n\
<KeyPress> BackSpace : string(0x7f)\n\
<KeyPress> Delete : string(0x08)\n
通常,xterm 会从其调用者继承 tty 模式。在 xdm
下,默认的擦除和删除字符是 #
和 @
,就像在古老的 Unix Version 6 中一样。如果您不喜欢这样,您可以将类似以下的内容放入 /usr/lib/X11/app-defaults/XTerm
或 $HOME/.Xresources
中,假设您在您的 $HOME/.xinitrc
或 $HOME/.xsession
中有一行
XTerm*ttymodes: erase ^? kill ^U intr ^C quit ^\ eof ^D \
susp ^Z start ^Q stop ^S eol ^@
在您的 $HOME/.xinitrc
或 $HOME/.xsession
中。
xrdb -merge $HOME/.Xresources
在您的 $HOME/.xinitrc
或 $HOME/.xsession
中。
将
*Text.translations: #override \
~Shift ~Meta <Key>Delete: delete-next-character()
放入 .Xresources
中,使非 Motif X 应用程序(如 xfig
、xedit
等)正常工作。(Daniel T. Cobra)
将
*XmText.translations: #override\n\
<Key>osfDelete: delete-previous-character()
*XmTextField.translations: #override\n\
<Key>osfDelete: delete-previous-character()
放入您的 $HOME/.Xdefaults
或 $HOME/.Xresources
中会有帮助。(哪个文件?馈送给 xrdb
的文件,例如在 .xinitrc
中。)然而,netscape FAQ 说
Why doesn't my Backspace key work in text fields? By default, Linux and XFree86 come with the Backspace and Delete keys misconfigured. All Motif programs (including, of course, Netscape Navigator) will malfunction in the same way. The Motif spec says that Backspace is supposed to delete the previous character and Delete is supposed to delete the following character. Linux and XFree86 come configured with both the Backspace and Delete keys generating Delete. You can fix this by using any one of the xmodmap, xkeycaps, or loadkeys programs to make the key in question generate the BackSpace keysym instead of Delete. You can also fix it by having a .motifbind file; see the man page for VirtualBindings(3). Note: Don't use the *XmText.translations or *XmTextField.translations resources to attempt to fix this problem. If you do, you will blow away Netscape Navigator's other text-field key bindings.
Ted Kandell (ted@tcg.net
) 建议如下
在您的 .profile 中的某个位置添加以下内容
stty erase ^H
如果您正在使用 bash
,请将以下行添加到您的 .inputrc
中
"\C-?": delete-char
"\C-h": backward-delete-char
将以下行添加到您的 .xinitrc 文件中
xmodmap <<-EOF
keycode 22 = BackSpace osfBackSpace
keycode 107 = Delete
EOF
# start your window manager here, for example:
#(fvwm) 2>&1 | tee /dev/tty /dev/console
stty sane
stty erase ^H
loadmap <<-EOF
keycode 14 = BackSpace
keycode 111 = Delete
EOF
这将肯定适用于任何带有 Linux/XFree86 布局的 PC 101 或 102 键键盘。
使像 Netscape 这样的 Motif 应用程序正常工作的关键部分是在 keycode 22 中除了 BackSpace 之外还添加 osfBackSpace。
请注意,在 = 号的两侧必须有空格。
当人们遇到退格键问题时,他们倾向于查看终端的 termcap(或 terminfo)条目,并且确实存在一个 kb(或 kbs)功能,描述了 Backspace 键生成的代码。然而,没有太多程序使用它,所以除非您只在一个特定程序中遇到问题,否则问题可能出在其他地方。当然,无论如何更正您的 termcap(terminfo)条目是一个好主意。另请参阅下面的“TERM 变量”部分。
有很多方法可以获得一个正常工作的系统。您能否给出一个适用于所有环境的完整设置?
获得在所有上下文中都可行的设置的一种方法是让 Backspace 键在控制台(或 xterm)上生成 DEL,而在 X 下生成 BackSpace。也许这最方便 - 有太多的 X 实用程序期望 BackSpace,而控制台或 xterm 上的 emacs 期望 DEL,而 X 下的 emacs 可以区分 [BackSpace] 和 Ctrl-H 并做正确的事情。
需要什么?无需 loadkeys 更改,因为默认情况下 Backspace 键已经生成 DEL。无需 stty 设置,它们默认情况下是可以的。无需 X 设置,它们默认情况下是可以的。只需告诉 xterm Backspace 键应该生成 DEL:将
XTerm*VT100.Translations: #override\n\
<KeyPress> BackSpace : string(0x7f)\n\
放入 .Xresources
中,并将
xrdb -merge .Xresources
放入 .xinitrc
中,您就搞定了。有关这些事情的更广泛讨论和替代解决方案,请参阅 Anne Baretta 的页面。