Emacs 23和Emacs 24之间的按键绑定变化

8

我最近升级到了Emacs24,结果我的一些自定义键绑定就出问题了。

根据详细说明,可以让Emacs停止将功能键与它们的ASCII控制码混淆(例如,可以将C-mRET绑定到不同的东西,或者将C-iTAB绑定到不同的东西等等)。这一直是我对Emacs的一个大抱怨,因为这样有价值的“第一级”键盘快捷键被浪费在我已经在键盘上拥有专用键的事情上。我想将它们绑定到不同的东西,以我的情况为例,模仿gedit来“现代化”键绑定。在Emacs23中,这个功能运行得非常好:

(global-set-key (kbd "C-i") 'goto-line)
(global-set-key (kbd "C-m") 'comment-or-uncomment-region)
(global-set-key (kbd "C-d") 'kill-whole-line)

;; Fix some stuff broken by the above
(global-set-key [delete] 'delete-char)
(global-set-key (kbd "TAB") 'indent-for-tab-command)
(global-set-key (kbd "RET") 'newline)

然后,我升级到Emacs24,但它出了点问题。它仍然在某种程度上“工作”,比如C-m确实会执行一件事情,RET会做另一件事情,但问题是回车键在终端模式或迷你缓冲区中不再正常工作。在这两种情况下,回车键不会激活我刚刚输入的命令,而只是将光标移动到下一行,我无法激活在迷你缓冲区或终端中输入的命令。
具有讽刺意味的是,Emacs24引入了很多关于删除行为的更改,在此过程中,他们将C-dDEL分离,所以现在安全地将C-d绑定到其他内容而不需要将DEL绑定回预期的行为。因此,如果我可以使我的回车键具有类似“它只是工作”的功能,并将C-m绑定到其他内容,那就太好了。
因此,我可以想象这个问题有两个可能的解决方案。其中一个可能是这样的:
(global-set-key (kbd "C-m") 'comment-or-uncomment-region)
(global-set-key (kbd "RET") 'do-what-i-expect-the-return-key-to-do-in-any-mode)

或者,像这样更好:
(setq decouple-ascii-control-codes-from-function-keys t)

但是我不知道是否有任何变量或函数可以在这种情况下帮助我。

我尝试使用模式钩子来恢复终端和迷你缓冲区模式中的正确绑定,但是我似乎无法让任何东西正常工作。求助!

谢谢。

2个回答

5

这似乎有效:

(add-hook 'find-file-hook
          (lambda ()
            (local-set-key (kbd "C-m") 'comment-or-uncomment-region)
            (local-set-key (kbd "<return>") 'newline-and-indent)))

这里的想法是,不要全局干扰回车键(这会破坏终端和迷你缓冲区),我们只在每个缓冲区上设置这些按键绑定,但对于表示磁盘文件的所有缓冲区无条件地执行。
虽然每次打开文件都需要运行有点低效,但它很好,因为我不必考虑每种可能的模式来“修复”,它根本就不会破坏终端/迷你缓冲区等模式。

你不需要担心效率问题。如果你查看一下find-file通常所做的工作量(例如使用M-x find-function RET find-file-noselect RET命令),你会发现你对local-set-key的两次调用显然是微不足道的。 - user4815162342
它们可能微不足道,但“已经很慢了,不能让它变得更糟!”是一种粗心的态度。Stefan的答案非常出色,而且没有任何陷阱就解决了问题。 - robru
Stefan的回答很好,我只是指出你的回答也有价值,并且已经点赞了。我没有说它已经很慢,也没有关于评估更改如何影响执行路径的一般性问题。 - user4815162342

3
默认情况下,Emacs 处理这些“姐妹键”的方式是通过(function-key-map)将特殊键(如tabreturn)重定向到它们的 ASCII 等效项,然后仅为 ASCII 版本添加按键绑定。因此,您可以很容易地使用类似以下代码添加非 ASCII 版本的新意义:
(global-set-key [return] 'my-new-command)

但在您的情况下,您希望执行相反的操作,即使return像以前一样工作,同时更改C-m。我能想到的最可靠的方法(在大多数主要/次要模式绑定方面应该都有效)是尽早且无条件地将C-m重新映射到一些新事件,如下所示:

(define-key input-decode-map [?\C-m] [C-m])
(define-key input-decode-map [?\C-i] [C-i])

这不会影响returntab的处理,因为input-decode-map是在function-key-map之前应用的,也就是在将这些键转换为ASCII控制键之前。因此,您可以执行以下操作:

(global-set-key [C-m] 'my-new-command)
(global-set-key [C-i] 'my-newer-command)

一个缺点是这将不仅适用于C-i的绑定,而且也适用于C-c C-i的绑定,它现在只能作为C-c TAB(有时会非常好,但可能偶尔不太易记)。
另一个缺点是如果存在tab的绑定,则tab将无法用于到达C-i绑定。但我们可以通过添加以下内容来解决这两个问题:
(define-key function-key-map [C-i] [?\C-i])
(define-key function-key-map [C-m] [?\C-m])

如果没有使用新事件的绑定,它将把新的C-i事件转换回正常的C-i事件。


我完全复制并粘贴了你的解决方案,但它似乎只对“ C-m”起作用,而不对“ C-i”起作用。例如,“ C-m”和“ RET”成功执行不同的操作,但当我按下“ TAB”键时,它会执行我绑定到“ C-i”的操作。有什么想法吗?无论如何,我还是接受了你的答案,因为“ C-m”是我挣扎的部分;我已经使用“ global-set-key”使“ C-i”和“ TAB”起作用了。 - robru
没事了,看起来我的.emacs里有其他东西在干扰。我把它删除了,你的解决方案在emacs24上原样工作。谢谢! - robru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接