VIM如何区分`Ctrl-J`和`LF`?
我正在尝试创建一个简单的Python/curses应用程序。
但是据我所知,没有办法判断是按下了CTRL+J还是Enter。这可能是因为它们的ASCII码是一样的(都是10):
http://en.wikipedia.org/wiki/Control_character#In_ASCII
那么,VIM是怎么区分这两者的呢?
3 个回答
<C-J>
相当于 <NL>
,而不是 <CR>
(后者对应 <C-M>
):
:echo "\<C-J>" ==# "\<CR>"
0
:echo "\<C-J>" ==# "\<NL>"
1
所以你的想法是错的;连 Vim 也无法区分这两个键。由于键盘输入的处理方式,以及终端和它们的 API 发展过程中的复杂历史,区分这些键是很困难的。不过在大多数现代终端模拟器中,现在是可以做到的。
一些人(主要是 Paul LeoNerd Evans)想要在 Vim 中解决这个问题,并提出了各种建议,具体可以参考 这个链接
但截至目前,还没有人提供补丁或志愿者来解决这个问题,尽管很多人希望在未来的 Vim 8 主要版本中能实现这个功能。我不知道如何在 Python 中解决这个问题,但你可以从链接中的讨论中找到一些有用的见解。
我觉得 <ctrl-J>
和 Enter
不是同一个东西。在 vim 里,<ctrl-j>
的键码是 10,而 Enter
的键码是 13。
有一些键是可以互换的,比如:
<ctrl-M> and Enter
<ctrl-H> and backspace
<ctrl-[> and ESC
...
你可以在你的 vim 里测试一下,<ctrl-M>
和 Enter
做的事情是一样的,无论你处于哪个模式。
其实,还有一个组合键也很难和 <Enter>
以及 <Ctrl-M>
区分开来,那就是 <C-Enter>
。我不知道你想要实现什么,你说你想做一些终端开发(ncurses),如果终端连这些键都无法区分,那你就可以不去管它。我对 ncurses 没有经验,如果我说错了别生气哦。^_^
如果你输入 :h keycodes
,你可以看到更多信息,下面的表格是从 vim 帮助中复制过来的。
notation meaning equivalent decimal value(s) ~
-----------------------------------------------------------------------
<Nul> zero CTRL-@ 0 (stored as 10) *<Nul>*
<BS> backspace CTRL-H 8 *backspace*
<Tab> tab CTRL-I 9 *tab* *Tab*
*linefeed*
<NL> linefeed CTRL-J 10 (used for <Nul>)
<FF> formfeed CTRL-L 12 *formfeed*
<CR> carriage return CTRL-M 13 *carriage-return*
<Return> same as <CR> *<Return>*
<Enter> same as <CR> *<Enter>*
<Esc> escape CTRL-[ 27 *escape* *<Esc>*
<Space> space 32 *space*
<lt> less-than < 60 *<lt>*
<Bslash> backslash \ 92 *backslash* *<Bslash>*
<Bar> vertical bar | 124 *<Bar>*
<Del> delete 127
<CSI> command sequence intro ALT-Esc 155 *<CSI>*
<xCSI> CSI when typed in the GUI *<xCSI>*
Enter键通常等同于C-m。但是,如果tty的icrnl
标志被激活(可以通过stty -a
查看),那么输入的C-m会自动转换为C-j(这样你只需按Enter就能轻松输入以Unix风格结束的行)。
在普通的C语言中,你可以使用termios函数tcgetattr(3)和tcsetattr(3)来关闭c_iflag
中的ICRNL标志,这样输入的C-m就不会被转换为C-j。如果你想对输入和输出有绝对的控制,可以使用“原始”模式(禁用所有输入和输出处理)。看起来Python也有这些termios函数。
curses库提供了一些更高级的函数来处理tty模式,比如savetty(3)、resetty(3)、nonl(3)、raw(3)、cbreak(3)等。似乎Python也有这些curses函数。
如果你在使用curses库的其他部分,最好也使用它的函数来调整ICRNL标志(例如nonl(3)),以避免破坏库所做的假设(也就是说,它假设tty是某种设置,但你的termios级别的调用改变了这些设置,导致假设被打破)。