エディタを作る-1の3 エスケープシーケンス

早速、次のソースファイルを見てみよう。

esc-01 ソース原本

解説が無いと 何をやっているのかすら分からない まるで暗号だが、これは昔から良く使われて来た【 エスケープ シーケンス 】= Escape sequence という コンソール画面の制御のためのコマンド群を使っているのだ。

1)エスケープ シーケンスが Win上で使えない

例えば、最初の //Clear とコメントされている行は、
 ① ESC+”[2j” と  ② ESC+”[1;1H” の 2つのコマンドが実行されている

① は 画面をクリアする (ただし、カーソルの位置は先頭には移動しない)
② は カーソルの位置を先頭(左上 x=1,y=1)に移動する

つまり、「画面を消している」わけだ。

この ソースをもう少し判り易く、Visual Studioでもビルドが通るように改変すると、↓ こうなる。 MacのC言語では、文字列の中の ”¥e” で ESCコードとして扱ってくれるようだが、VSではこれが出来ない。 

esc-01a ソース改

しかたなく、16進数 で ESC = 1Bh なので ”¥x1B” という 万国共通の書き方に直した。 (これなら どのC言語でも通用する)

これを ビルドして Windows10で実行すると ↓ こうなる。

esc-02 実行画面

文字列が そのまま表示されるだけで、意図する動作をしてくれない。

それも そのはず、Windows10 の コマンド プロンプト上で 「エスケープシーケンス」が動作しない事が 判明!!!

昔の MS-DOSの時代は、PC-9801版であれ AT版であれ、普通にエスケープシーケンスが動いていたよな? いや、Windows 98 とかでも 使っていた気がする・・・ どこから 使えなくなったんだ??

調べてみると、この機能が DOS系のOSで使えるのは、ANSI.SYSというデバイス ドライバが組み込まれているからであり、MS-DOSでは 大抵 標準で組み込む事になっていた・・・だから使える。 それが、Windows VISTAまでは、まだ ANSI.SYSが(System32内)に存在しているので、これを「組みこめば」使えるようになるらしい。

 ところがである、Windows 7以降は、ANSI.SYS自体が供給されたいない(OS内に存在しない)のだ。 Microsoftは 何の嫌がらせか知らないが、 エスケープシーケンスを意図的に(使えないように)除外したらしい。

さて、どうしよう?

Qiitaの中でも書かれているが、コンソールの画面を消すくらいなら、
  system("cls");
でも簡単に実行できるが、今度 それは Mac-OSで使えない。

とりあえず、まずは Windows10でも  エスケープシーケンスを使えるようにする方法を検索して見よう。

2)便利なツール ANSICON 発見

 探していると大変良く出来たツールを見つけた。
 ANSICON (現在の最新は Ver 1.89)

画像4

これをネットからダウンロードして来て 解凍すると、OSの違いによって 32bit版と 64bit版に分かれている。 Windows 10なら ほとんどが64bitだと思うので、x64フォルダ側を使う。
 どちらにも ansicon.exe が入っているので、これを -i のオプションスイッチを付けて実行してあげるだけで良い。 

画像5

コマンドプロンプトを起動して、この ↑ フォルダまで移動して、
  >ansicon -i
を実行しても良いのだが、cdコマンドで移動するのも面倒なので、GUI操作だけで済ませてしまおう。

 ① ansicon.exe の上で右クリックし、「ショートカットの作成」を実行
 ② その場に ショートカット・アイコンが出来たら、
  その上でまた右クリックし → [プロパティ]
 ③ 「ansicon.exe のプロパティ」画面の「ショートカット」タブ内 の
  「リンク先」に 実行するフォルダと 実行ファイル  -i を追加する。
   "D:・・・略・・・ ANSICON\ansi189\x64\ansicon.exe" -i
 
④ このショートカットアイコンを1回 実行すればOK

すると、コマンドプロンプトを起動し、今回のサンプルプログラムを実行すると ↓ こうなる。

ansi-03 ANSICON実行後

ちゃんと画面クリアが実行され、その後 背景は白? 文字色は赤でhello,world が書かれている。(さらに 元の色=背景:黒、 文字=白に戻っている)

この ツールの便利な点は、1回 -i オプションで実行すると、Windowsシステムに常駐して、コマンドプロンプトを閉じて、開いてしても ずっと エスケープシーケンスが有効になったままになる点だ。 さらに言えば、Windowsを再起動しても有効である。
     >ansicon -u
を実行しない限り 有効!  これは 使える!!

と、思ったのもつかの間、あろうことか 統合環境で使えない事がわかった。

ansi-03b IDEで使えない

デバッグの「出力」窓では、エスケープシーケンスが有効にならず、文字がそのまま表示されてしまう ・・・

Visual Studioで作成した 実行ファイルでは有効に働くが、これでは デバッグができない。

やはり、system関数を使って 画面を消す(clsコマンド)とか、色を変える(colorコマンド)ようにしないといけないのか?

試しにプログラムでsystem(”cls”)を使って、画面を消すのは 問題無く出来たが、colorコマンドの挙動が エスケープシーケンスと異なることが判明した。

   >color  背景色+文字色

背景色も文字色も 0~Fの16進数で指定。 例えば、背景=白、文字=黒 と反転させたい時は、
   >color f0
で良い。 >color のみを (引数無しで)実行すると 元々の色に戻る。

ansi-04 colorコマンド

色の一覧は、次の通り

ansi-04a colorコマンド

ただ、これも問題がある。

背景色を指定すると、その後の文字列の背景だけ色が変わるのではなく、画面全体の背景の色が ↓ 変わってしまう。
 color 7C の実行結果。 ⇒  7=灰色 が 全体を塗ってしまう。

ansi-04c colorコマンド

それでいて、 color 単独 (引数指定なし)で 元の 背景=黒に戻そうとすると、この時はなぜか、画面全体の背景色が変わるのでは無く その後に表示ちた文字列の背景だけが 黒に戻っている。

ansi-04d colorコマンド

 これでは 使えねーーー

/*	         ソリューション名   プロジェクト
 * main.cpp	(4_cls-color → cls-color)
 *
 *	画面消去&画面の文字に色を付ける。 システムコマンドで制御
 */
 # include <stdio.h>
 # include <stdlib.h>
 # include <windows.h>
 
 int   main(int argc, char *argv[])
 {
 	printf("hello,world.\n");
 
 # if defined(_WIN32) || defined(_WIN64)
     system("cls");		printf("CLS\n");
 # else
     printf("\x1B[2J\x1B[1;1H"); //clear(画面をクリアし、キャレット位置を左上にx,y=1,1)
 # endif
 
 # if defined(_MSC_VER)
     system("color 7c");	printf("Color\n");
 # else
 	printf("\x1B[31m\x1B[47m");		//color (白地に赤い文字)
 # endif


 # if defined(_MSC_VER)
    system("color 07");	printf("colorデフォルトに戻す\n");
 # else
    printf("\x1B[39m\x1B[49m");		//reset(元の文字色に戻す)
 # endif

    for(int i=0; i<argc; i++) {
        printf("receive > %s \n",argv[i]);
    }
    return 0;
}

こんな ↑ 感じのテスト・プログラムで動作テスト。
 ①ステップ実行での挙動と、②exeファイルを直接実行した時の挙動が違うのも気になる。 
 ①だと思った通りに色も変わり、最後はデフォルトの背景色=黒、文字色=白に戻るのに、②だと背景色=灰色、文字色=赤のまま終わる(デフォルト色に戻らない)

いずれにしても、colorコマンドは 画面全体の背景と文字色を一気に変えるためのコマンドあって、文字単位に色を変える用途には向かないのは分かった

 いっその事、WIN32/64のAPIで文字色を変えるコードを作った方が良さそうだ。


p.s.
 Windows 10 の新しい版(TH2/1511以降)から、エスケープシーケンスに対応するようになったらしい。 「らしい」としたのは、まだ試していないとの TH2/1511の更新ファイルに不具合があって(更新失敗する?)、ダウンロードが停止されているからだ。

 新しい Win10 では、SetConsoleMode呼び出しで エスケープシーケンスが使えるようになるとの事。 ただ、大半の 古いWin10(やWin7)の人がかなりの人数いる状態では、エスケープシーケンスだけで画面処理を作ったら、動かない人だらけになって、結局 これではダメってことになるように思える。


ハッシュタグ
#C言語 #エディタを作る

いいなと思ったら応援しよう!