奇怪的Emacs键绑定行为

奇怪的Emacs键绑定行为,emacs,key-bindings,Emacs,Key Bindings,我经常遇到Emacs这个奇怪的问题,我真的很想找到一个解决方案,但却找不到任何解决方案。默认情况下,键映射ESC(三个转义)映射到键盘转义退出,这可以正常工作,但是,如果我只按ESC两种类型,然后按箭头键,它会将特殊字符插入到我的文本中,我总是需要重做或删除才能删除这些字符。换句话说,我有这样的行为: ESC向上->OA ESC向下->OB ESC右->OC ESC左->外径 当我使用\C-hk查找这些键已映射到的函数时,它会显示映射到keyboad escape quit的ESC 有没有人有办

我经常遇到Emacs这个奇怪的问题,我真的很想找到一个解决方案,但却找不到任何解决方案。默认情况下,键映射ESC(三个转义)映射到键盘转义退出,这可以正常工作,但是,如果我只按ESC两种类型,然后按箭头键,它会将特殊字符插入到我的文本中,我总是需要重做或删除才能删除这些字符。换句话说,我有这样的行为:

ESC向上->OA

ESC向下->OB

ESC右->OC

ESC左->外径

当我使用\C-hk查找这些键已映射到的函数时,它会显示映射到keyboad escape quit的ESC

有没有人有办法摆脱这种讨厌的密钥绑定?注意,我在终端中使用Emacs


谢谢

箭头键生成转义序列。 例如,如果启动
cat
并点击向上箭头,您将在屏幕上看到如下内容:

$ cat
^[[A
i、 例如,escape、开放式支架、
A
(根据终端的不同而有所不同)

这意味着,如果按ESC up键,Emacs会看到ESC[A]并做出相应的反应(键盘退出,然后插入
[A

因此,Emacs的行为与文档一致

如果要禁用密钥绑定,可以执行以下操作

(define-key esc-map (kbd "<ESC><ESC>") nil)
(定义键esc映射(kbd“”)无)

IMO,这不是一个很好的解决方案,但也不是一场灾难,因为您可以始终使用C-g来代替。

Sam已经描述了这个问题,但对于一般的解决方案,您基本上需要教Emacs区分您在按下“退出键”时收到的ESC和作为“退出序列”一部分收到的ESC当然,一般来说这是不可能的,但在实践中,你可以检查计时:如果ESC后面有一点空闲时间,那么它可能是一个“退出键”,否则它可能是“退出序列”的一部分

此技巧在Viper或Evil等VI模拟器中使用:

(defvar viper-fast-keyseq-timeout 200)

(defun viper--tty-ESC-filter (map)
  (if (and (equal (this-single-command-keys) [?\e])
           (sit-for (/ viper-fast-keyseq-timeout 1000.0)))
      [escape] map))

(defun viper--lookup-key (map key)
  (catch 'found
    (map-keymap (lambda (k b) (if (equal key k) (throw 'found b))) map)))

(defun viper-catch-tty-ESC ()
  "Setup key mappings of current terminal to turn a tty's ESC into `escape'."
  (when (memq (terminal-live-p (frame-terminal)) '(t pc))
    (let ((esc-binding (viper--lookup-key input-decode-map ?\e)))
      (define-key input-decode-map
        [?\e] `(menu-item "" ,esc-binding :filter viper--tty-ESC-filter)))))
如果您调用
viper catch tty ESC
,它将设置解码,以便按escape键现在应生成
escape
事件(而不是
ESC
事件)。由于
功能键映射
中的绑定,如果
退出
没有绑定,这将自动映射回
ESC
(这在GUI模式中使用,退出键确实发送到
退出
事件)

请注意,这不会解决您的问题:“ESC-ESC-up”仍将插入“OA”。问题在于,Emacs的键盘翻译仍将显示“ESC-O-A”(前两个以循环方式出现,经过
escape
并返回)。因此,要最终解决问题,您还需要删除“ESC-ESC”绑定并将其替换为仅在新的
escape
事件中触发的绑定:

(global-unset-key [?\e ?\e ?\e])
(global-set-key [?\e ?\e escape] 'keyboard-escape-quit)

注意:这都是棘手的事情。我对相应的代码非常熟悉,但是我在写这个答案时的前两次尝试都失败了,因为我没有预料到一些交互作用。

你完全正确,但我认为我必须继续使用默认配置,因为如果我取消映射,我将永远无法获得keyboard-escape-quit开始工作(即使我只绑定它)。谢谢你的回答。Stefan,谢谢你的例子。但是它将
ESC
转换为
escape-ESC
,而不是
escape-ESC-escape
escape-escape
。这里是更一般和准确的解决方案(从邪恶模式)