終端下如何讓Emacs用上Ctrl+F1, Shift+Up等組合鍵


最近常用Putty訪問Linux,在上面用Emacs修改代碼、運行shell、進行SQL交互,最大的問題是很多組合鍵(比如我常用的Shift+Up/Down/Left/Right, Ctrl+F1..F12, Ctrl+Home/End)不能使用,春節前兩天有些時間,研究了一下這個問題,算是基本找到了一些解決辦法。

問題分析

首先需要了解Xterm control sequences這個概念,這個鏈接中的說明很晦澀,我簡單地說明一下:對於有對應 ASCII字符的組合健,就發送對應的ASCII字符,否則用一個特殊序列來表示,比 如 F1 就用 ^[OP (也就是先按Ctrl+[, 然后按O,然后再按P),或者用 ^[[11~ 來表示, C-F7 就用 ^[[18;5~ 表示 。這個序列一般都是以 ESC(也即ASCII碼中的27,對應實際按鍵 ESC 或者 Ctrl+[ ,常寫為 \e 或者 ^[ )開始,所以也常常叫做Escape sequences(除了表達按鍵之外,它還用來表達終端顏色控制)。

當在終端里運行應用程序時,按下一個組合鍵之后的事情是這樣:

  1. 終端模擬器將其翻譯為對應的Xterm control sequences,發送給對端主機;
  2. 對端主機根據 TERM 在terminfo中查找翻譯表,翻譯為對應的按鍵信息,傳遞給應用程序(如果某些組合鍵在翻譯表中找不到,則透傳)
  3. 應用程序對組合健做出響應。

所以可能存在的問題是:

  1. 終端模擬器不能將某些組合鍵翻譯為Xterm control sequences
  2. 終端模擬器與terminfo中的翻譯表不一致

對於第一個問題

可以用AutoHotKey攔截組合鍵,自行翻譯到control sequences發送出去:

#if WinActive("ahk_class PuTTY") or WinActive("ahk_class mintty")
;;** Ctrl+Fn
^F1::SendInput  {ESC}[1;5P
^F2::SendInput  {ESC}[1;5Q
^F3::SendInput  {ESC}[1;5R
^F4::SendInput  {ESC}[1;5S
^F5::SendInput  {Esc}[15;5~
^F6::SendInput  {Esc}[17;5~

(完整的代碼見這里: bamanzi / dotemacs-elite / source / term / putty-ctlseqs.ahk — Bitbucket)

備注一下,我的辦公用機是Windows,我用的終端模擬器是putty及其變種 (包括mintty, putty-nd以及MobaXterm)。至於Linux桌面,GNOME Terminal和XFCE Terminal兼容vt102和vt220的組合鍵Ctrl+Up, Alt+F1這些大都是支持的(但有少數不支持,但我目前不知道什么工具可以完成類似AutoHotKey這樣的功能)

對於第二個問題

對於Emacs而言,我們並不需要直接去解決第二個問題,因為Emacs可以自己將control sequences翻譯為其它按鍵:

(define-key input-decode-map "\eO5P"    [C-f1])
(define-key input-decode-map "\eO5Q"    [C-f2])
(define-key input-decode-map "\eO5R"    [C-f3])
(define-key input-decode-map "\eO5S"    [C-f4])
(define-key input-decode-map "\e[15;5~" [C-f5])
(define-key input-decode-map "\e[17;5~" [C-f6])

這里有一個比較完整的包,包含了很多control sequences: http://www.dur.ac.uk/p.j.heslin/Software/Emacs/Download/xterm-extras.el )

補充說明

  • 對於同一個鍵,可能有多種control sequences,比如F1^[11~ , ^[[1P^[OP 這三種序列,但每種終端模擬器只發送其中一種。上面的xterm-extra.el 對光標鍵提供了CSI和SS3序列的映射,這意味着在多種終端上按這些鍵都可以正確翻譯; 但對於F1..F4只提供了CSI的序列映射,沒有提供SS3序列映射(而Putty/Mintty對於F1..F4恰好使用的是CSI序列)。不過反過來比較好的是,不會一個序列對應多種按鍵。
  • 獲取你的終端上某個鍵的control sequences的簡單方法是用cat命令(不過對於少數特殊鍵和application keypad不好使)

  • 上面的xterm-extra.el里面對keypad序列似乎不是標准的,我沒有查到^[z開頭的序列,似乎是作者利用了一個尚未使用的序列。不過SS3序列中是有keypad序列的(vim wiki中有一篇相關的貼士: PuTTY numeric keypad mappings - Vim Tips Wiki;
  • Putty本身對於F1, Shift+F1, Alt+F1, Alt+Shift+F1, 支持挺好,但不支持帶Ctrl修飾鍵的(比如Ctrl+F1, Ctrl+Shift+F1, Ctrl+Alt+F1),如果是Windows平台,可以用AutoHotKey來解決;
  • 對於Ctrl+標點這個列表,部分(比如Ctrl+*, Ctrl+.等)是有control sequences定義的,還有一些(比如Ctrl+!, Ctrl+#, Ctrl+; )則沒有正式的control sequences。詳細說明可以參考我的配置文件里面的說明: init.d / 80-ports.el。如果要使用,也只能用AutoHotKey來解決

 (這篇文章有個完整的版本,包含了更多細節,我放在了bitbucket里面,如果有興趣,可以前往閱讀)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM