奇怪的Emacs键绑定行为

时间:2014-10-02 15:15:23

标签: emacs key-bindings

我总是遇到Emacs的这个奇怪的问题,我真的想找到一个解决方案,却找不到任何解决方案。默认键映射ESC ESC ESC(三个转义)映射到keyboard-escape-quit,工作正常但是,如果我只按ESC两种类型然后按一个箭头键,它会在我的文本中插入特殊字符,我总是有重做删除以摆脱。换句话说,我得到了这种行为:

ESC ESC up - > OA

ESC ESC down - > OB

ESC ESC right - > OC

ESC ESC left - > OD

当我使用\ C-H K查找这些键已映射到哪些功能时,它显示我ESC ESC ESC,它映射到keyboad-escape-quit。

有没有人有任何解决方案如何摆脱这个烦人的键绑定?请注意,我在终端中使用Emacs。

谢谢

2 个答案:

答案 0 :(得分:2)

箭头键生成转义序列。 例如,如果你开始cat并点击向上箭头,你会在屏幕上看到如下内容:

$ cat
^[[A

即逃逸,开放式支架A(根据终端的不同而不同)。

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

因此,Emacs的行为符合文档。

如果要禁用键绑定,可以执行

(define-key esc-map (kbd "<ESC><ESC>") nil)

这不是一个非常好的解决方案,IMO,但不是灾难,因为你总是可以使用 C-g

答案 1 :(得分:1)

Sam已经描述了这个问题,但是对于一般的解决方案,你基本上需要教Emacs来区分收到的ESC,以响应你从作为“转义序列”的一部分收到的ESC命中“转义键”。当然,一般情况下无法完成,但在实践中,你可以检查时间:如果ESC后面跟着一些空闲时间,那么它可能是一个“转义键”,否则它可能是“转义序列“。

这个技巧用于VI仿真器,如Viper或Evil:

(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事件(而不是ESC事件)。如果ESC没有绑定,这将自动映射回escape,这要归功于function-key-map中的绑定(这在GUI模式中使用,其中转义键确实发送到{{} 1}}事件)。

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

escape

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