[技巧] 用 VSCode Terminal 連到遠端 Linux 但是有些組合鍵按不了?

如果你想用 VSCode Terminal 取代傳統用 PuTTY, MobaXterm 等 SSH 工具,第一個會遇到的障礙就是像是 Ctrl + K, Ctrl + E, Ctrl + V 有些組合鍵都沒辦法用。

"不能用"的原因可能有幾個:

  • VSCode 傳送的 ASCII code 和 PuTTY 傳送的 ASCII code 不一樣
  • VSCode 的組合鍵被 VSCode 上面的東西給搶先攔截了 (像是 Ctrl + E 會開啟 Go to file... 功能)
  • 再來也有可能不是 VSCode 的問題,是 stty 或 SSH 端的程式沒設置好

按鍵傳送的 ASCII Code 和想像的不一樣

像是我們開 PuTTY 的設定 Terminal -> Keyboard 就會發現裡面有設置像是 Backspace 按下去應該會送出什麼 ASCII code:

預設是送出 127 (^?, 0x7f),但是有可能會出於各種因素設置到 Control-H (也就是 Ctrl + H, ^H, 8, 0x8)。但 VSCode 預設設定是右邊的。所以如果你習慣的設定剛好就和 VSCode 預設不一樣的話就會發現 VSCode terminal 中 backspace 按下去怎麼不是刪除文字而是會冒出一些怪怪的符號、或是一些不該有的行為。

按鍵被 VSCode 搶先攔截

就算你在 VSCode terminal 按 Ctrl + E,VSCode Go to file... 的功能就會搶先跳出來,terminal 根本沒有機會知道你按了什麼:

其他還有很多按鍵通通會觸發 VSCode 的功能。

別讓 VSCode 攔截按鍵

你可以在 settings.json 裡面用 "terminal.integrated.commandsToSkipShell" 來關閉哪些 VSCode commands 不要使用,記得在前面加上一個 "-" 字元,它自然就會把按鍵乖乖傳給 shell:

{
    "terminal.integrated.commandsToSkipShell": [
        "-editor.action.toggleTabFocusMode", // Ctrl + M
        "-workbench.action.quickOpen", // Ctrl + E
        "-workbench.action.quickOpenView", // Ctrl + Q
        "-workbench.action.terminal.focusFind", // Ctrl + F
        "-workbench.action.terminal.paste", // Ctrl + V
        "-workbench.action.togglePanel", // Ctrl + J
    ]
}


這些 commands ID 不難查,你只要去 Keyboard Shortcuts 的頁面 (Ctrl + K, Ctrl + S) 先輸入例如 "Ctrl + E" 再找想關掉的 command 點右鍵就可以複製 ID 了。

Ctrl + K 因為對於 VSCode 來說比較特別,就像 Visual Studio 一樣有特殊功能,不過我們還是可以在 settings.json 裡面用這樣的設定讓你只有在 terminal 做事時乖乖傳給 shell:

{
    "terminal.integrated.allowChords": false // Ctrl + K
}


但是像我還是比較喜歡直接按 Ctrl + V 把指令貼到 terminal 上,所以後來 Ctrl + V 的設定我還是把他註解掉了。

進階: 設定和 PuTTY 一樣的 ASCII Code

假設今天我們想要設置 Ctrl + Backspace 好了。

我們可以先開 PuTTY 或其他你喜歡用的 SSH program 用 showkey -a 來知道按下 Ctrl + Backspace 會傳送什麼 ASCII Code:

如果這時候開 VSCode terminal 也同樣用 showkey -a 按 Ctrl + Backspace 會發現他傳送不一樣的 ASCII code:


這時我們只要在 VSCode 按 Ctrl + Shift + P 輸入 Open Keyboard Shortcuts (JSON) 按 Enter 打開 keybindings.json,在 "text" 後面把 0x7f 改成 \u007f:

[
    {
        "key": "ctrl+backspace",
        "command": "workbench.action.terminal.sendSequence",
        "args": {
            "text": "\u007f"
        },
        "when": "terminalFocus"
    },
]


我們再回 VSCode terminal 再試一次:


看到和 PuTTY 打出一樣的 ASCII code 就對啦。

那如果你看到 showkey -a 按某個鍵就吐出兩三行的 ASCII code 怎麼辦? 那就是把很多 \u00xx 串在一起,例如像這樣:


[
    {
        "key": "ctrl+backspace",
        "command": "workbench.action.terminal.sendSequence",
        "args": {
            "text": "\u001b\u007f"
        },
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+left",
        "command": "workbench.action.terminal.sendSequence",
        "args": {
            "text": "\u001bb"
        },
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+right",
        "command": "workbench.action.terminal.sendSequence",
        "args": {
            "text": "\u001bf"
        },
        "when": "terminalFocus"
    }
]


如果某個 ASCII code 剛好是純英文數字的話其實也可以直接打那個字,例如 "\u001bb" 就是 "\u001b" + "b"。

我們記得要加上 "when": "terminalFocus",就是告訴 VSCode 只有在 terminal 中才會這樣做,不要影響到沒在使用 terminal 時的按鍵。

有興趣看更多細節的話可以參考我當初搜尋的文章或教學:

其他 Terminal 好用的鍵盤設置

這個我是在這篇 Mastering VS Code's Terminal 看到的,按 Ctrl + Shift + M (用 maximize 來記) 就可以切換最大化/還原 terminal 視窗,尤其是 VSCode 重開後第一次連進去 tmux 按兩下 Ctrl + Shift + M 就可以刷新 render 的問題:


[
    {
        "key": "ctrl+shift+m",
        "command": "workbench.action.toggleMaximizedPanel"
    }
] 


非 VSCode 的問題

像是公司就有一個 script 要給全部的 R&D 去 source,但是裡面就寫了客製化的 stty,導致我在 vim 按 Backspace 就會產生奇怪的 characters。後來就查到用 stty sane 其實就解決了,和用什麼 VSCode 還是 PuTTY 連進去沒有關係。

其他時候甚至有可能用一些 bind/bindkey 來做到一些事,所以如果上面 showkey -a 那招發現 ASCII code 都一樣卻還不是你預期的,就要檢查一下你用的 program 是不是有吃一些特殊設定。像是 tmux 就可以設定是 vim 還是 emacs mode,當初沒設定他就給我預設一個 mode 害我以為是 VSCode 的問題。

結語

因為 VSCode 重點不是用 terminal,是享受 VSCode 本身的功能,所以他設計就希望按鍵是拿去操控 GUI 的,但是他也夠 flexible 可以客製化各種按鍵的行為。

留言

此網誌的熱門文章

[試算表] 追蹤台股 Google Spreadsheet (未實現損益/已實現損益)

[Side Project] 互動式教學神經網路反向傳播 Interactive Computational Graph

[插件] 在 Chrome 網頁做區分大小寫的搜尋