前回までの作業でCP/M-80とCP/M-80アプリを動かせるようになったのですが、キー入力周りで若干問題があります。また、CP/M-80用のスクリーンエディタとして有名な「WordMaster」は、そのままの状態ではうまく動きません。今回は、キー入力に関する問題の解消と、WordMasterの改造に取り組みます。
キー入力の問題を解消
前回までに作成したCP/M-80起動用プログラム「startcpm.c」には問題があります。例えば、CP/M-80に付属する「ED」というラインエディタでは、テキスト入力用のモード(インサートモード)からコマンドモードに移動するのに、Ctrl+zというキー入力を用います。しかし現状のstartcpm.cでは、Ctrl+zを入力すると(通常のLinuxプログラムと同様に)SIGTSTPシグナルが送られてプロセスが停止してしまいます。また、WordMasterでは、カーソルの上下左右の移動にCtrl+e、Ctrl+x、Ctrl+s、Ctrl+dというキー入力を用いますが、現状のstartcpm.cでは、Ctrl+sを入力すると端末への出力が停止してしまいます。
Backspaceキーに関する問題もあります。GNOME TerminalなどのLinuxの端末エミュレータでは、デフォルトでBackspaceキーに「ASCII DEL」(コード「0x7F」)が割り当てられています。しかし、CP/M-80は、同キーに「Ctrl+h」(コード「0x08」)が割り当てられることを想定しています。そのため、期待通りの動作になりません。
これらの問題を解消するには、startcpm.cのbios()関数にある、文字入力用のBIOSコールの処理部分を次のように書き換えます。
case 0xFFE0:
tcgetattr(0,&save_settings);
settings = save_settings;
settings.c_lflag &= ~(ECHO|ICANON|ISIG);
settings.c_cc[VTIME] = 0;
settings.c_cc[VMIN] = 1;
settings.c_cc[VSTOP] = 0;
settings.c_cc[VSTART] = 0;
settings.c_cc[VSUSP] = 0;
tcsetattr(0, TCSANOW, &settings);
c = getchar();
tcsetattr(0, TCSANOW, &save_settings);
if (c == 0x0A) {
c = 0x0D;
}
if (c == 0x10) {
exit(0);
}
if (c == 0x7F) {
c = 0x08;
}
regA = (c & 0x7F);
break;
この書き換えでは、端末に設定するフラグから「ISIG」を取り除いています。ISIGは、「INTR」「QUIT」「SUSP」「DSUSP」を示す文字入力があった際に、対応するシグナルを発生させるためのフラグです。また、端末の出力を停止する「VSTOP」と、再開する「VSTART」、SIGTSTPシグナルを送信する「VSUSP」の二つの処理に対応付けた文字をクリアするコードも追加しています。これにより、Ctrl+zとCtrl+q、Ctrl+sの入力をCP/M(またはCP/Mアプリ)側で処理できるようになります。
さらに、WordMasterでは、Ctrl+oも編集用のキー入力として用います。そのため、プログラム終了用のキー入力を、Ctrl+o(コード「0x0F」)からCtrl+p(コード「0x10」)に変更しています。CP/M-80 2.2においてCtrl+pは、コンソール出力をプリンタにもエコーするかどうかを切り替えるのに用いられます。しかし、今回作成したBIOSはプリンタ出力に対応していませんので、終了用のキーとして使っても問題ないでしょう。
Backspaceキーの問題については、単純に「0x7F」の入力があった場合にそれを「0x08」に置き換えるコードで対処しています。
変更後、EDを使ってテキストを編集できることを確認してください。なお、「CBIOS.ASM」の入手に用いたアーカイブファイル「cpm2-plm.zip」に含まれる「ED.COM」は高速化の改造を施されたもので、そのままでは正常に動作しません。「ED1.COM」の方がオリジナル版なので、それをリネームして使いましょう。「CPM.SYS」の入手に用いたアーカイブファイル「cpm22-b.zip」に含まれるED.COMはオリジナル版なので、そのまま使えます。
WordMasterを改造する
キー入力の問題は解決できましたが、WordMasterはまだ利用できません。WordMasterが利用する端末制御シーケンスが、Linuxの端末エミュレータなどで使われているANSI/VT100互換の端末制御シーケンスと異なるからです。
問題を解決する方法の一つが、WordMasterにパッチを当ててANSI/VT100互換の端末制御シーケンスに対応させることです。パッチの当て方はさまざまな場所で解説されていますが、ここでは、「CP/M Word-Master patch for vt100 up to 255 columns.」で紹介されている方法でパッチを当てます。
まず、WordMasterを入手します。http://www.retroarchive.org/cpm/text/text.htm から「Wrdmastr.zip」ファイルをダウンロードし、その中にある「WM.COM」をCP/Mのディスクにコピーします。続いて、前述のリンク先から「WM3.HEX」というパッチファイルをダウンロードします。また、http://www.s100computers.com/Software%20Folder/Assembler%20Collection/ZSID,%20SID%20&%20DDT.zip などをダウンロードして、デバッガの「SID.COM」を入手してください。これらのファイルも、CP/Mのディスクにコピーします。
準備を終えたら、CP/M-80を起動して次のコマンドを実行します。
A>SID WM.COM
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2700 2700 0100 C8FF
#Rwm3.hex
NEXT MSZE PC END
29DF 29DF 0100 C8FF
#Wwm3vt100.com
0052h record(s) written.
#g0
A>
作成された「WM3VT100.COM」が、ANSI/VT100互換の端末制御シーケンスに対応したWordMasterの実行ファイルです。テキストファイルを編集して確かめてください。
CP/M-80の画面をグリーンディスプレイ風にする
レトロ感を出すために、画面をグリーンディスプレイ風にしてみましょう。startcpm.cファイルのmain()関数にある、CP/Mの起動メッセージを出力している部分の前に、次のコードを挿入します。printf文で出力しているのは、文字を太字にして、文字色を緑にするエスケープシーケンスです。
printf("\x1b[1;32m");
さらに、プログラム終了時に文字色を標準色(白)に戻せるように、bios()関数内のプログラム終了処理部分を次のように書き換えます。
if (c == 0x10) {
printf("\x1b[0;39m\n");
exit(0);
}
書き換え後、CP/M-80を起動して操作している様子を次に示します。なかなか良い感じではないでしょうか。
なお、カーソルの色は変えていません。「\e]12;green\a」といったエスケープシーケンスを使えば、端末によってはカーソルの色も変えられるのですが、筆者がリモートアクセスに使っているTera Termでは効かないのでそのままにしています。
コメント