简体   繁体   English

奇怪的Emacs键绑定行为

[英]Strange Emacs keybinding behavior

I always had this strange problem with Emacs that I really want to find a solution but unable to find any. 我始终对Emacs遇到这个奇怪的问题,我确实想找到一个解决方案,但找不到任何解决方案。 By default key map ESC ESC ESC (three escapes) are mapped to keyboard-escape-quit, which works fine but, if I press ESC only two types and then press an arrow key, it inserts special characters into my text that I always have to redo of delete to get rid of. 默认情况下,键映射ESC ESC ESC(三个转义)被映射到键盘转义退出,效果很好,但是,如果我只按ESC的两种类型,然后按箭头键,它将在我一直有的文字中插入特殊字符重做删除以摆脱。 In other words I get this behavior: 换句话说,我得到这种行为:

ESC ESC up -> OA ESC ESC up-> OA

ESC ESC down -> OB ESC ESC向下-> OB

ESC ESC right -> OC ESC ESC右-> OC

ESC ESC left -> OD ESC ESC左-> OD

When I use \\CH K to find which functions these keys have been mapped to it shows me ESC ESC ESC which is mapped to keyboad-escape-quit. 当我使用\\ CH K查找这些键已映射到哪些功能时,向我显示ESC ESC ESC ESC映射到keyboad-escape-quit。

Does anyone have any solution how to get rid of this annoying key-binding? 有谁能解决这个烦人的键绑定问题? Note that I use Emacs in terminal. 请注意,我在终端中使用Emacs。

Thank you 谢谢

The arrow keys generate escape sequences. 箭头键生成转义序列。 Eg, if you start cat and hit the up arrow, you will see on your screen something like this: 例如,如果您启动cat并按下向上箭头,您将在屏幕上看到以下内容:

$ cat
^[[A

ie, escape, open bracket, A (it will be different depending on the terminal). 即,逃生,开括号, A (视终端而定)。

This means that if you hit ESC ESC up , Emacs sees ESC ESC ESC [ A and reacts accordingly (keyboard quit, then insert [A ). 这意味着如果您按ESC ESC键 ,Emacs会看到ESC ESC ESC [A并做出相应的反应(退出键盘,然后插入[A )。

So, the Emacs behaves as per the docs. 因此,Emacs的行为与文档相同。

If you want to disable the key binding, you can do 如果要禁用键绑定,可以执行

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

This is not a very good solution, IMO, but not a disaster since you can always use Cg instead. IMO,这不是一个很好的解决方案,但不是灾难,因为您始终可以使用Cg

Sam has described the problem, but as for a general solution, you basically need to teach Emacs to distinguish the ESC received in response to you hitting the "escape key" from the ESC received as part of an "escape sequence". Sam已经描述了问题,但是对于一般的解决方案,您基本上需要教Emacs区分响应于您击中“转义键”的Esc与作为“转义序列”的一部分而收到的ESC的区别。 Of course, in general it can't be done, but in practice, you can check the timing: if ESC is followed by a bit of idle time, then it's probably an "escape key", and otherwise it's probably part of an "escape sequence". 当然,通常这是无法完成的,但实际上,您可以检查时间:如果ESC后面有一点空闲时间,则可能是“转义键”,否则可能是“转义序列”。

This trick is used in VI emulators such as Viper or Evil: 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)))))

If you call viper-catch-tty-ESC , it will setup the decoding such that hitting the escape key should now generate an escape event (instead of an ESC event). 如果调用viper-catch-tty-ESC ,它将设置解码,以便现在按下转义键将生成escape事件(而不是ESC事件)。 This will automatically be mapped back to ESC if there is no binding for escape , thanks to a binding in function-key-map (this is used in GUI mode where the escape key indeed sends to escape event). 如果没有用于escape的绑定,这将自动映射回ESC ,这要归功于function-key-map的绑定(这在GUI模式下使用,其中转义键确实发送了escape事件)。

Note that this will not fix your problem: "ESC ESC up" will still insert "OA". 请注意,这不能解决您的问题:“ ESC ESC up”仍将插入“ OA”。 The problem there is that Emacs's keyboard translation will still see "ESC ESC ESC OA" (tho the first two appeared in a round-about way going through escape and back). 问题在于,Emacs的键盘翻译仍会看到“ ESC ESC ESC OA”(前两个以回旋的方式出现在escape和退回的位置)。 So to finally fix the problem, you additionally need to remove the "ESC ESC ESC" binding and replace it with a binding that will only be triggered with the new escape event: 因此,为最终解决该问题,您还需要删除“ ESC ESC ESC”绑定,并将其替换为仅由新的escape事件触发的绑定:

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

Note: This is all tricky business. 注意:这都是棘手的事情。 I'm intimately familiar with the corresponding code, yet my first two attempts while writing this answer failed because of some interaction I did not anticipate. 我对相应的代码非常熟悉,但是由于无法预料到某些交互,我在编写此答案时的前两次尝试均失败了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM