ESCがターミナル、さらに各プロセスに送られる仕組み
その昔キーボードにMetaキーと呼ばれるキーがあって、 このキーと同時に他のキーを押す(Meta-Aの様な)と別の動作をするような仕組みがありました。
このキーを押した状態だと送られる文字コードの最上位の8桁目のビットが1に変わった状態になります。 Altキーと言うものも最初は同じ動作をしたようです。 ただ、この最上位ビットが他の用途に使われる様になったため、 また受け取るソフトウェア側で色々認識できる様になったため Altキーは受け取るソフトウェア側で認識して使う様になりました。
この様な歴史からAlt-AはMeta-Aと同様の入力として理解するソフトウェアが多くあります。 MacだとOptionがMetaの後継的な立場ですが、 ものによってはCommandとの組み合わせでMetaと同様の動作をするものもあります。
もう一つ、ESC A(ESCを一度押して離してからAを押す) も一部のソフトウェアではMeta-Aと解釈されます。
これがターミナル上のソフトウェアになると、まずターミナルが受け取って、それをシェルが受け取ったり エディタなどで受け取ったりしてそれぞれの段階で解釈があります。
なのでこの辺りの動作が思い通りに行かない時はターミナルと中で立ち上げてるシェルやソフトウェアの設定など色々調べる必要があります。
Vim及びNeovimでのESC
VimやNeovimではESCはノーマルモードに入るために使う最も重要なキーです。
なのでこの辺のキーの扱いは難しいところですが、 この2つで扱いが違う様です。
VimではESCが来た場合必ずESCと解釈します。 また、Meta-Aの様なキーが送られてきても ESC Aの2つが順に送られて来た様に解釈されます。 実際インサートモードでAlt-hとか押すとノーマルモードに戻ります。
一方、NeovimではMeta-Aはその通り解釈され、 マッピングしてあればその動作を行えます。 ただESCを押してすぐ次のキーを押した場合は別々に解釈されます。
実際、Vimで
" Meta key
nnoremap <M-a> 0
" Alt key
nnoremap <A-a> 0
" Mac Command Kky
nnoremap <D-a> 0
みたいな設定がありますがこれは通常動作しません。 これを同じ設定をNeovimで試してみると動きます。
一方、Neovimでも普通にターミナルを開いてNeovimを立ち上げて ESC Aと素早く打ってもMeta-Aとはなりません。
この部分ちゃんと分かってませんが、Neovimの中でこれらの区別が出来るのか、 もしくはESCを押してからのtimeout設定が物凄い短いか。
上のFAQでは:help xterm-cursor-keys
も見てみろということなので見てみると
vt100-cursor-keys* *xterm-cursor-keys*
Other terminals (e.g., vt100 and xterm) have cursor keys that send <Esc>OA,
<Esc>OB, etc. Unfortunately these are valid commands in insert mode: Stop
insert, Open a new line above the new one, start inserting 'A', 'B', etc.
Instead of performing these commands Vim will erroneously recognize this typed
key sequence as a cursor key movement. To avoid this and make Vim do what you
want in either case you could use these settings: >
:set notimeout " don't timeout on mappings
:set ttimeout " do timeout on terminal key codes
:set timeoutlen=10 " timeout after 100 msec
This requires the key-codes to be sent within 100 msec in order to recognize
them as a cursor key. When you type you normally are not that fast, so they
are recognized as individual typed commands, even though Vim receives the same
sequence of bytes.
とあってtimeout
、ttimeout
、timeoutlen
の設定が書いてありますが
Vimではtimeout
はtrue、ttimeout
はfalse(nottimeout
)、timeoutlen
は1000でした。
Neovimではtimeout
はtrue、ttimeout
もtrue、timeoutlen
は1000でした。
この辺の設定前にも見た気がしますがちょっと良くわからないんですが、 色々と値を変えてみましたがVimでMeta設定を有効にすることは上手くできませんでした。
GNU screen/tmuxでのESC
さらにGNU screenやtmuxを使ってる時は、 キー入力は一度それらに渡されてから内部プロセスに渡されます。
この際に両方ともESCが来てから次のキーを待って 合わせてMeta-Aなどとして送る機能がついています。
この待ち時間がデフォルトでGNU screenでは300 ms、tmuxでは500 msとなっていて 結構長いです。
なのでGNU screen/tmuxの中でNeovimを立ち上げてESCを送るとすぐに インサートモードからノーマルモードに戻らず、 しばらく立ってから移ります。 この際、即座に次のキーを入力してしまうとMeta-Aとかになってしまうので ノーマルモードになれません。
一方、VimでもESCが送られてくるまでの遅延はあるのですが、 次のキーが送られた瞬間にESCが実行され次のキーは別に実行されるので 期待通りの動きになります。
この現象はGNU screen/tmuxの待ち時間の問題で、 上のFAQにも書いてありますが これら次の設定で変更できます。
GNU screen:
1
|
|
tmux:
1
|
|
これらは待ち時間をmsで設定するもので、10msだと普通の人がいくら素早く連打しても 空く位の間隔になり、 ESCを押した場合に即座にESCが送られる様になります。
これでやっとNeovimをまともに使える様になりました。
他のソフトウェアへの影響は?
この設定は勿論他のソフトウェアにも影響するのでESCを 使ったり、特にそれをメタキー用のプレフィックスとして使っている場合には影響がでるかもしれません。
ただ、Meta-Aなどの入力はそのまま送られますし、 もともとESC Aなどでメタキー入力代わりにしているソフトウェア上では 同様のシグナルとして捉えられるので問題ないはずです。
逆に今までESCの入力でなんとなく遅延を感じてた様な物が反応良くなるかもしれません。 Vim以外だとあまりつかいませんが。
Windows & Puttyでの設定
追記: 2017/11/21
WindowsではリモートサーバーへはPuttyを使ってログインして作業していますが、 Puttyを使うとデフォルト設定ではEscapeを分けて送る様な設定になっているらしく 上に書いた様な問題が起こります。
これを上手く扱うためには 設定の Terminalの項目にあるEnable extra keyboard featuresの 中の Control-Alt is different from AltGr(Control-Alt を AltGr と区別する)という項目のチェックを外します。
この項目はヨーロッパなどの言語でアクセント記号付き記号などを入力する時に使う AltGrが無いキーボードでCtrl-AltをAltGrとして扱うかどうか、 という設定なのですが、 区別する、つまりこの代替を無効にすると、 どうもAltと何かキーを入力した時にESCと区別して送る様に全体的に変わるらしく? 上の問題が起こる様です。
そもそもAltGrは全く使わないですし、 Ctrl-Altという修飾キーを直接エディタなどで使う事はないので この設定はどちらにしておいても他に影響はほとんどないです。
ので、これを外すとNeovimの問題がなくなったので外しておくようにしました。
ちなみにWindowsでもCygwin (Mintty)とかだとデフォルトのままでも 問題なくESCがNeovimで使えます。
追記ここまで
追記: 2017/11/22
下記のPuttyの設定で問題がなくなる、というのはちょっと嘘でした。
やはり別途Escapeを送る仕様があるらしく下記の設定を変えても 上の問題は起こります。
他の設定が効くかもしれませんが色々いじってみて今のところ駄目です。
このままだと共用のマシンではNeovimは使いづらい。。。
(vi
にnvim
をエイリアスしたいので。)
追記ここまで