这个问题的灵感来自于关于 vi.SE 的另一个问题。在那里,OP在运行时遇到Shift+F8组合键问题。该组合键永远不会起作用,因为终端模拟器没有正确地传递它(至少从我设法调试的情况来看)。vim
urxvt
vim
我不太了解F
终端模拟器如何处理密钥。
在urxvt
- 当我按Shift+时F8
~
会回显。 - 当我按下F7(或任何其他 F 键)时
~
也会回显。
在vim
里面urxvt
- 当我按Shift+时F8,我得到了 的效果
~~
。 - 当我按Shift+时F7,我得到了 的效果
~
。 - 当我按Shift+时F6,我得到了 的效果
~~~
。
另一方面xterm
:
- 当我按Shift+时F8
;2~
会回显。 - 当我按下F8(或任何其他 F 键)时,只会
~
回显。
我不明白为什么会得到这个输出。
为了进一步调试,我运行xev
并得到了以下结果:
为了F8
KeyPress event, serial 29, synthetic NO, window 0x2000001,
root 0x7e, subw 0x0, time 17730758, (431,256), root:(432,275),
state 0x0, keycode 74 (keysym 0xffc5, F8), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
对于左Shift
KeyPress event, serial 32, synthetic NO, window 0x2000001,
root 0x7e, subw 0x0, time 17733031, (431,256), root:(432,275),
state 0x0, keycode 50 (keysym 0xffe1, Shift_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
并为右Shift
KeyPress event, serial 32, synthetic NO, window 0x2000001,
root 0x7e, subw 0x0, time 17733372, (431,256), root:(432,275),
state 0x0, keycode 62 (keysym 0xffe2, Shift_R), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
然而,我在那里绝对没有看到任何奇怪的地方。
终端模拟器如何处理这些键(F 键)?终端仿真器从什么接收信息x11
?他们如何将其进一步传递给内部运行的程序?
我一直认为F键只是Esc加一个数字的组合。现在我发现我错了。
附录
F 键在里面Shift效果不好。如果我做:vim
urxvt
:map <f8> :echo "yay"<CR>
当我按下 时,我确实正确地得到了“yay”的回声F8。
答案1
终端和应用程序之间的接口发送字节,而不是密钥。可打印字符被解释为与终端的字符编码相对应的字节序列。功能键被编码为转义序列。这些转义序列有常见的约定,但它们并未完全标准化。
有关更一般的背景,请参阅键盘输入和文本输出如何工作?。有关更多信息,另请参阅当我在控制台登录屏幕上按向上箭头时,有什么原因导致我收到 ^[[A ?和键绑定表?
所有功能键转义序列均以转义字符并且大多数都以 结尾~
。 Vim 根据其编译时设置和终端上的信息识别许多转义序列。如果 Vim 无法识别转义序列,它会忽略它,但 Vim 不知道转义序列有多长(它不假设最后一个字符是 a ~
,情况并非总是如此)。~
在 Vim 识别的部分之后经常会有一个迷失,有时甚至更多。
您可以在 shell 或 Vim 的插入模式下通过先按Ctrl+来准确地看到终端发送的内容。V
你可以让 Vim 了解与转义序列对应的功能键:set
,例如
:set <S-F8>=^[[19;2~
(将后面的部分替换^[
为您的终端实际发送的内容)。
答案2
一些键用作修饰语(shift、control是最常用的)。终端仿真器接收一系列X事件,您可以使用 来查看xev
。终端模拟器结合了其中一些事件,例如shifta使用 X 库来获取A.对于其他情况,例如功能键和光标键(称为“特殊键”)X 库没有预定义转换。终端模拟器决定是否以及何时使用这些修饰符来生成由特殊键发送的不同转义序列。
不同的终端模拟器可以为此使用不同的规则:没有标准可以发送的序列。只有惯例例如,决定模仿某些终端,或者通过制作其他终端没有的新序列来扩展事物。
rxvt 和 xterm 都使用这些修饰符来提供不同的功能键序列,允许在终端中运行的程序就像您的终端有几十个功能键一样。
然而 - 终端也可以有一个模式,由从应用程序到终端的控制序列设置改变为功能键发送的转义序列。在全屏程序(例如 vim)中使用这些模式切换控制序列是很常见的。所以你会看到差异。
因为没有标准,有一个终端描述对于每个终端,它描述其行为(使用TERM
环境变量)。对于大多数终端,描述初始化要使用的终端应用方式(对于键盘和光标键)。全屏应用程序使用这些初始化序列并使用这些描述中列出的功能键和光标键,以便它们获得一致的行为。
并非所有终端都发送功能键的转义序列。例如,阿尔托斯工作站使用插入符号,wyse-85支持使用 8 位模式( \233
CSI \033[
),qnx用过的\377
。但最开始与 ASCII 转义字符。最终的角色是一个不同的故事。大约一半rxvt 的修改功能键以 ASCII 波形符以外的字符结尾~
(ncurses FAQ 中有一个表格说明了这一点)。由于这些差异,终端描述与实际终端匹配非常重要。
在当前版本的 vim (7.3) 中,我认为没有问题。它识别移位F8。几年前,出现了一个问题。 vim 对功能键的检查不需要分号,如 xterm 发送的那样。一旦遇到分号,它就停止识别功能键。您可能有旧版本的 vim,或者某些键映射会干扰它识别按键。 vim 现在可能(无论你使用什么版本),但确实不是查看扩展键的终端描述,但依赖于它自己的表。让情况变得复杂的是,vim可能使用 xterm 功能(称为tcap 查询) 获取 xterm 发送的实际按键序列。
另一方面,vim 可能有一个映射,它为 rxvt 键序列提供不同的结果。其shifted F6( \E[29~
)、shifted F7( \E[31~
)、shifted F8( \E[32~
)没有特殊区别。
进一步阅读:
- 如何使用移位或控制修饰符?(ncurses 常见问题解答)
- 我的光标键不起作用(ncurses 常见问题解答)