• Windows Terminal ベスト設定 第14回「Windows Terminal V1.19安定版 V1.20 Preview」その2

今回も、安定版Windows Terminal Ver.1.19とプレビュー版Ver.1.20に搭載された新機能を見ていく。前回は目に見える変更を中心に解説したが、今回は、内部的な変更を解説する。

レンダリングエンジン変更など

安定版Windows Terminal Ver.1.19では、これまでプレビュー版でしか有効になっていなかった「新テキストレンダリングエンジン」(開発コード名Atlas)が、標準で有効になった。Ver.1.20でもデフォルトで有効である。

Ver.1.20では、テキストの流し込み、折り返し処理が変更になり、ウィンドウ幅を変更したときの折り返し処理が異なる(写真01)。従来、ウィンドウ幅を縮めるなどの操作で、本来折り返すべきでないところで折り返しが起こり、以後の表示が崩れることがあった。また、単語の折り返しを正しく認識するようになったため、ウィンドウ右端にある折り返された単語をダブルクリックすると、次の行にある単語の末尾部分も正しく選択されるようになった(写真02)。

  • 写真01: Terminal Ver.1.18(写真左)は旧レンダリングエンジンで動作し、Ver.1.19(写真中央)Ver.1.20(写真右)は、レンダリングエンジンは同一だが、折り返しのアルゴリズムが変更になっている。この3者では、同一のテキストを表示させ、ウィンドウ幅を変更したとき文字の位置などや折り返しの位置などが異なる

  • 写真02: Ver.1.20では、単語が右端で折り返された場合でも、ダブルクリックで正しく単語全体を選択できる

エスケープシーケンスの追加

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)が利用できる。

  • ■表01

  • ■表02

  • ■表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で行われているが表示はできなかった)。

  • ■表04

  • 写真03: Ver.1.19では、アンダーラインの表示で色指定とスタイル指定が有効になった。色は文字色と同じく16色でスタイルは現状5種類をサポートしている

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が無効であるため、ターミナルの左上の領域は、デフォルトの背景色である黒となる。

  • 写真04: DECECM Setを指定すると、部分消去であるDECERAシーケンスでは、背景値のデフォルト値を使って消去が行われる

DECECM resetを使う場合は、


$VTHOME+$DECECMRESET+($COUT* 11)+$DECERA+$SGRRESET

を実行する(写真05)。このとき、ターミナル左上の領域は、この時点で設定されている背景色で消去される。

  • 写真05: DECECM Resetでは、DECERAによる消去時にその時点の背景色を使って消去が行われる

V1.20の拡張(表05)は、水平タブ医位置の初期化(DECST8C。Set Tab at Every 8 Columns)とDSR(Device Status Reports)である。前者は、水平タブ位置を8カラムごとに初期化するもの。後者は、デバイスの状況を報告するもの。端末装置にはキーボードやプリンタ、のちにはマウスなども接続された。DSRは、そのデバイスや端末自体の情報を返すもの。応答もエスケープシーケンスになっている。

  • ■表05

ただし、これは、互換性のために追加されたエスケープシーケンスであり、どの場合も固定した応答を返す。

ここでは、こうした応答を伴うエスケープシーケンスを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)である。

  • 写真06: DSRエスケープシーケンスは、パラメーターに応じた応答を戻す。「5」を指定すると、端末の状態を返す。ただしWindows Terminalでは、応答は固定したものとなり、常に「CSI 0 n」(Esc [ 0 n)を戻す

DSRは、中間にあるパラメーターで、調べる対象を指定できる。「5」を指定すると、端末の状態を表すOperating statusを返す。Windows Terminalでは、固定の応答として「CSI 0 n」が返る。これは、端末が故障や異常状態にないことを示す応答である。

多くの場合、エスケープシーケンスを直接扱うことはなく、またソフトウェア開発でもライブラリなどを利用する。しかし、Windows Terminalでは、バージョンより対応するエスケープシーケンスが追加されことが多く、新機能として確認したいこともあるだろう。この場合、PowerShell(またはWindows付属のWindows PowerShell)を使えば簡単に試すことが可能だ。

>> Windows Terminal ベスト設定 連載バックナンバー
https://news.mynavi.jp/tag/winterminal/