ここのところMinEdの端末判定・エンコーディング判定について調べているんですが、前提となる事項としてDA2(Secondary Device Attributes, 第2端末特性応答)を説明する必要が出てきました。そこでDA2についてのおおざっぱな解説を書いてみたところ少し長くなってしまうようなので、この話題を独立したポストとして分けてみます。これ自体の内容はあまり面白くないと思います。
またここではクエリ・応答という言葉を普通に使っていきますが、端末エミュレーションの文脈でクエリというと、アプリケーションから端末に対する特殊な問い合わせシーケンスをTTYデバイスの出力側に送ることを指します。それに対する端末からの応答(報告)は入力側からキーインプットと同じ要領で入ってきます。
具体的な応答の見方はTrachetのチュートリアルでも若干触れたので興味があれば読んでみてください。
DA2の意義
環境変数$TERMは偽装が横行しているため役に立っていない状況が多く、termcap/terminfoが提供する端末特性情報も、あまり参考にならない場合があります。
そこでよく使われるのが、DA2です。
これをDA1(Primary Device Attributes, 第1端末特性応答)と組み合せるだけで、端末の種類を特定できたりする場合があります。
DA1についてはここでは詳しく触れませんが、DA2が端末のIDやバージョン等、端末の特定に役立つ情報を提供するのに対して、DA1は主に端末の能力・ファシリティ情報を中心に提供する、という違いがあります。
DA2の形式
以下のクエリ
ESC [ > c
は、DA2を端末に要求し、端末からは以下の形式の応答が返ることが期待されます。
ESC [ > {端末ID} ; {バージョン} ; {キーボードオプション} c
{}の中身は10進数で表現されます。
さて、この応答のうち、最初の「端末ID」のセクションですが、DEC VT200以降の端末では、以下のような数値が返ります。
1 : VT200 family (VT220)
32: VT300 family (VT300/VT320/VT382)
41: VT400 family (VT420)
61: VT510
64: VT520
65: VT525
これにならう形で、ソフトウェア端末では以下のような端末IDを返すことになっています。
0 : xterm (patch #279以前)
6 : Haiku Terminal
28: DECterm window
82: rxvt ('R'を意味する)
83: GNU Screen ('S'を意味する)
77: MinTTY ('M'を意味する)
85: rxvt-unicode ('U'を意味する)
さらに近年の端末の場合、2番目の引数であるバージョンも重要です。
以下の例のように、端末自身のソフトウェアバージョンやパッチレベルを埋め込むことがあるからです。
DA2応答の例
ESC [ >0;270;0c : xterm #270 (270はパッチレベル)
ESC [ >77;10101;c : MinTTY 1.1.1
ESC [ >83;40001;0c : GNU Screen 4.0.1
このあたりまではよかったのですが、アプリケーション側でバージョン判定を行うソフトウェアが増えてきたため、また近年の端末がエミュレータという性格を持つソフトウェアであるがゆえに少し話がこじれました。
以下の例は、特定の端末の特定のバージョンを模倣するDA2応答です。
これらの応答を評価する場合は本家なのかエミュレーションなのかを注意深く見ていく必要があります。
ESC [ >0;95;0c : tmux (xterm patch #95を模倣)
ESC [ >0;115;0c : Konsole (xterm patch #115を模倣)
ESC [ >0;136;0c : PuTTY/MinTTY version 0.3 (xterm patch #136を模倣)
ESC [ >0;276;0c : tty.js (xterm mode, xterm patch #276を模倣)
ESC [ >0;277;0c : tanasinn (xterm patch #277を模倣)
ESC [ >1;10;0c : mosh/WizConsole VT200 mode (VT220を模倣)
ESC [ >82;20710;0c : ck (rxvt 2.7.10を模倣)
ESC [ >83;40003;0c : tty.js(screen mode, GNU Screen 4.0.3を模倣)
ESC [ >85;95;0c : tty.js(rxvt-unicode mode, rxvt-unicodeを模倣)',
また、端末IDは何かに似せて、バージョン部分に独自の値を埋め込むことで差別化をはかっている実装もあります。
例:
ESC [ >0;95;c : iTerm/iTerm2 (xterm patch #95に似るが、区別可能)
ESC [ >1;96;0c : mlterm (端末IDはVT200 family, 96は固定の模様)
ESC [ >1;2403;0c : VTE 2.4.3 (端末IDはVT200 family)
ESC [ >41;280;0c : xterm patch#280 (端末IDはVT400 family)
ESC [ >32;100;2c : TeraTerm (端末IDはVT300 familyだがversionで区別可能)
ESC [ >65;100;1c : RLogin (端末IDはVT525だがversionで区別可能)
ESC [ >32;277;2c : mouseterm-plus (端末IDはVT300 familyだがversionで区別可能)
ESC [ >82;0.5.4;0c : mrxvt 0.5.4 (端末IDはVT200 familyだがversionで区別可能)
ここでバージョンに95付近の値が多いのは、アプリケーション側の実装の都合によるものです。
アプリケーション側では、しばしばこのファームウェアバージョンの値がxtermのパッチレベルとみされるため、端末側がこれに適応したのです。
この想定でバージョンセクションが解釈されることを意図した場合、95よりちょっと上くらいのファームウェアバージョンは「マウスが使えてドラッグもイベントとして検出する」ということを示唆していますが、これは単に雰囲気的なものであり、どこかにきちんと仕様として明示されているものではありません。
他の例については知りたい人は、このあたりを見てください。
https://github.com/saitoha/trachet/blob/master/trachet/seqdb.py#L125
DA2を利用するアプリケーション
実際にDA2応答を利用するアプリケーションはいくつかあります。例を挙げてみます。
-
Vim
VimはDA2のバージョンセクションを見ます。
マウスレポーティングのプロトコル(ttymouse)自動判定にはこの値が使用されています。バージョンが95以上であればButton Mouse Trackingを、277以上であればSGR形式のマウストラッキングを有効にします。
また141以上であればxtermのtermcap queryという機能を有効にします。 -
Emacs
Emacsも端末IDが0のときに、バージョンセクションの値を利用します。
バージョンが216以上であればxterm由来のmodifyOtherKeysという機能を端末に期待し、242以上であれば端末背景色の自動判定をします。
ただしパッチレベル280以降のxtermは端末IDとして41を返すので、最新のxtermではこの判定は失敗するという問題があります。 -
MinEd
MinEdは様々なところでこのDA2応答を使用しています。
バージョンセクションだけではなく、端末IDも見ています。
詳しくは、@ttdodaさんが書いたこちらのメモを見ると良いと思います。
https://gist.github.com/ttdoda/4728768
これはMinEdが行っている端末判定のごくごく一部に過ぎないので、そのあたりについては、追って詳しい説明を書いていきたいと思います。