今回も、安定版Windows Terminal Ver.1.19とプレビュー版Ver.1.20に搭載された新機能を見ていく。前回は目に見える変更を中心に解説したが、今回は、内部的な変更を解説する。
レンダリングエンジン変更など
安定版Windows Terminal Ver.1.19では、これまでプレビュー版でしか有効になっていなかった「新テキストレンダリングエンジン」(開発コード名Atlas)が、標準で有効になった。Ver.1.20でもデフォルトで有効である。
Ver.1.20では、テキストの流し込み、折り返し処理が変更になり、ウィンドウ幅を変更したときの折り返し処理が異なる(写真01)。従来、ウィンドウ幅を縮めるなどの操作で、本来折り返すべきでないところで折り返しが起こり、以後の表示が崩れることがあった。また、単語の折り返しを正しく認識するようになったため、ウィンドウ右端にある折り返された単語をダブルクリックすると、次の行にある単語の末尾部分も正しく選択されるようになった(写真02)。
エスケープシーケンスの追加
Windows Terminalなど一般的なターミナルエミュレーターでは、画面の制御などを「エスケープシーケンス」を使って行う。これらは制御文字を使い、ASCII文字やUTF-8エンコードされたユニコード文字などと混在が可能になっている。シェルやその上のアプリケーションからは、制御コードを送ることで、カーソル位置を変更する、表示テキストに色や下線などの属性を付けることができる。そのほか、あるいは画面のクリアやスクロールなども行うことができる。
こうしたエスケープシーケンスは、コンピュータの表示装置として長い歴史を持つ端末装置に由来し、膨大な数のエスケープシーケンスが存在する。現状、こうしたエスケープシーケンスには、標準化されたもの(ANSIエスケープシーケンスやISO/IEC 2022など)、事実上の標準となった旧DEC社(Digital Equipment Corporation。Compaq社との合併を経てHP社に買収された)の端末装置固有のものがある。さらにターミナル・エミュレーターソフトウェア(たとえばX Window System用に作られたxterm)で定義されたソフトウェア固有のものもあり、現状、大きく3種類がある。さまざまなソフトウェアが独自の判断でエスケープシーケンスを使っており、どこまでサポートすれば良いかという具体的な範囲は不明確である。このため、比較的最近登場したWindows Terminalでは、バージョンアップのたびにエスケープシーケンスの強化が行われている。
実際には、プログラミングを行わないユーザーがエスケープシーケンスを直接扱うことはないが、ここでは新機能を見るために、エスケープシーケンスを直接扱って表示を行わせてみる。
エスケープシーケンス基本編
エスケープシーケンスを理解するのに必要な情報として、端末装置の時代から使われてきた「文字コード」について「ざっくり」と解説しておく。というのも、文字コードや制御コードについては、多数の仕様、規格があり、多くの定義が行われている。エスケープシーケンスも端末の制御だけでなく、文字セットの切り替えなど、多くのものがある。これらをそれぞれ説明していくと、本が何冊もかけてしまうぐらいの量になってしまう。なので、あえて誤解を恐れず、ざっくりとした解説を行うことにする。
端末装置は、キーボードを使って文字コードをホストコンピュータに送信し、ホストコンピュータも文字コードを返す。このとき、表示される通常文字とともにエスケープシーケンスを送信し、端末の表示を制御する。たとえば、文字に色を付ける、あるいは、文字の表示開始位置を制御するなどである。基本となるのは、米国のASCIIコードである。ただしASCIIコードは本来7 bitコードとして定義されている。その後、各国の固有文字を含めるため、コードを8bitに拡張した。
エスケープシーケンスは、文字コードと同時に送信できるように「制御コード」(表01)を使う。制御コードは、7 bit文字コードなら0x00~0x1Fまでのコード(C0制御コード。表02)であり、8 bit文字コードでは、さらに0x80~0x9F(C1制御コード。表03)が利用できる。
エスケープシーケンスと呼ばれるように、先頭に制御コードの0x1B(Escコード)を置き、その後ろにパラメーターを並べた。すべてのエスケープシーケンスでは、末尾の文字が固定したものであり、途中に数字や文字によるパラメーターが入る。パラメーターの区切りにはセミコロンを使う。数値のパラメーターは、バイナリではなく、文字コードによる表現を使う。パラメーターとして数値の18を使う場合、"1"(ASCIIコードでは0x31)と"8"(同0x38)を使う。
7 bit文字コードでもC1制御コードが使えるようにC1制御コードはすべてEscと1文字の組み合わせで表現できるようにしてある。
文字部分には0x40(ASCIIコードではアットマーク@)~0x5F(ASCIIコードのアンダーバー_)を使う。端末を制御するためのエスケープシーケンスでは、主にC1制御コードを使う。それは、C1制御文字そのもので表現されることも可能だし、C0制御文字のEscと文字コードを使っても表現できる。このため、エスケープシーケンスでは、C1制御文字の略号を使って表現される。
たとえば、CSI(Control Sequence Introducer。制御シーケンス開始)は、C1制御コードとしては0x9Bだが、7 bitでは、エスケープ(Esc)と左角カッコ(])の組み合わせで表記する。
現在では、文字セットとしてユニコードを使い、文字エンコードとしてUTF-8を使う。このため、C1制御領域を使うことができない。エスケープシーケンスはC0制御コードを使い、Escと1文字の組合せを使ってシーケンスを作る。
Ver.1.19の追加エスケープシーケンス
前述の旧DEC社端末VTシリーズのエスケープシーケンスには、「DEC~」で始まる名称がある。これは、同社のプログラミングマニュアルなどに記載されており、この名前でエスケープシーケンスを特定することが多い。標準であるANSIエスケープシーケンス(ANSI X3.64、ISO/IEC 6429)は、広く使われていたDEC社のVT-100のエスケープシーケンスをベースに作られた。このためANSIエスケープシーケンスをVTエスケープシーケンスと呼ぶこともあり、ANSIエスケープシーケンスの定義内であってもDEC社の呼称を使うことがある。 Ver.1.19に新規に搭載されたエスケープシーケンスには、「DECECM」、「DECIC」、「DECDC」、「DECBI」、「DECFI」がある(表04)。また、文字属性を指定するSGR(Select Graphic Rendition)のアンダーラインで色指定とスタイルの指定(写真03)が可能になった(エスケープシーケンス自体の実装はVer.1.18で行われているが表示はできなかった)。
DECECMは、「Erase Color Mode」と呼ばれるシーケンスで、DECERA(Erase Rectangular Area)などで領域をクリア(消去)するときに、その時点の背景色設定を残すかどうかを指定するもの。これを使うことでDECERAで消去を行うときに背景色が標準の黒に戻るか、現在の背景色のままになるのかを指定できる。
DECECMには、setとresetの2つのパターンがあり、DECECM setでは、標準の背景色(黒)で消去が行われ、DECECM resetでは、現在の背景色で消去が行われる。
これを試すには、まず(リスト01)のコマンドを実行する。これは、あらかじめPowerShellの変数にエスケープシーケンスを構成する文字列を定義するためのもの。PowerShellでは、ダブルクオートで囲まれた文字列内に変数を「${変数名}」として埋め込むことが可能。
■リスト01
$Esc=[char]0x1b
$CSI="${Esc}[";
$DECECMSET="${CSI}?117h";
$DECECMRESET="${CSI}?117l";
$DECERA="${CSI}1;1;10;40`$z"
$SGRRESET="${CSI}0m";
$VTHOME="${CSI}1;1f"
$COUT="${CSI}33m${CSI}47m"+("a"*120);
その上でDECECM setとresetを含んだコマンドを実行してみる。DECECM setの場合は、
$VTHOME+$DECECMSET+($COUT* 11)+$DECERA+$SGRRESET
とする(写真04)。部分消去を行うDECERAでは、ターミナルの「1,1」(左上)から「10,40」(10行40文字目)までを消去している。このときはColor Erase Modeが無効であるため、ターミナルの左上の領域は、デフォルトの背景色である黒となる。
DECECM resetを使う場合は、
$VTHOME+$DECECMRESET+($COUT* 11)+$DECERA+$SGRRESET
を実行する(写真05)。このとき、ターミナル左上の領域は、この時点で設定されている背景色で消去される。
V1.20の拡張(表05)は、水平タブ医位置の初期化(DECST8C。Set Tab at Every 8 Columns)とDSR(Device Status Reports)である。前者は、水平タブ位置を8カラムごとに初期化するもの。後者は、デバイスの状況を報告するもの。端末装置にはキーボードやプリンタ、のちにはマウスなども接続された。DSRは、そのデバイスや端末自体の情報を返すもの。応答もエスケープシーケンスになっている。
ただし、これは、互換性のために追加されたエスケープシーケンスであり、どの場合も固定した応答を返す。
ここでは、こうした応答を伴うエスケープシーケンスをPowerShellから扱う方法を示す。
エスケープシーケンスからの応答を受け取るには、PowerShellで「[console]::ReadKey()」メソッドを使う。キーボードからの入力を受け取るためのメソッドだが、エスケープシーケンスの応答は、キーボード入力と同じなので、このメソッドで応答を受け取ることができる。ただし、エスケープシーケンスの応答の長さは不定で、特に上限があるわけではない。しかし、応答が必ずあるのであれば、応答の末尾の文字は固定なので、その文字が来るまで入力を繰り返すことができる。具体的には、
Write-Output "${CSI}5n";$(do { $y=[console]::ReadKey().KeyChar; $y } while ($y -ne 'n')) | Format-Hex
というコマンドを実行させる(写真06)。このうち先頭の「Write-Output」の部分がDSRエスケープシーケンスの送信、その後ろが応答の取得と16進数ダンプ(Format-Hex)である。
DSRは、中間にあるパラメーターで、調べる対象を指定できる。「5」を指定すると、端末の状態を表すOperating statusを返す。Windows Terminalでは、固定の応答として「CSI 0 n」が返る。これは、端末が故障や異常状態にないことを示す応答である。
多くの場合、エスケープシーケンスを直接扱うことはなく、またソフトウェア開発でもライブラリなどを利用する。しかし、Windows Terminalでは、バージョンより対応するエスケープシーケンスが追加されことが多く、新機能として確認したいこともあるだろう。この場合、PowerShell(またはWindows付属のWindows PowerShell)を使えば簡単に試すことが可能だ。
>> Windows Terminal ベスト設定 連載バックナンバー
https://news.mynavi.jp/tag/winterminal/