VIM如何区分`Ctrl-J`和`LF`?

9 投票
3 回答
3587 浏览
提问于 2025-04-17 14:15

我正在尝试创建一个简单的Python/curses应用程序。

但是据我所知,没有办法判断是按下了CTRL+J还是Enter。这可能是因为它们的ASCII码是一样的(都是10):

http://en.wikipedia.org/wiki/Control_character#In_ASCII

那么,VIM是怎么区分这两者的呢?

3 个回答

0

<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 中解决这个问题,但你可以从链接中的讨论中找到一些有用的见解。

0

我觉得 <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>*
13

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级别的调用改变了这些设置,导致假设被打破)。

撰写回答