;COMMA000.ASM テンキーの｢000｣を｢,｣に変換する
		page 58,132
		.8086
comment		*
		COMMA000.COM (C)1991. Boko.

	テンキー部の「000」キーを「,」（カンマ）に変更する。

	常駐してINT 90（キーボードＢＩＯＳ）をフックし、
	キーの読み取り時にコードをすりかえる

	1991.05.19 V1.0	初版(Nifty-Serve FTOWNS1 DL3 にアップロード)
	1991.06.09      常駐サイズの縮小
	1991.08.11 V1.1 フリコレ４用(^^;)にコメントを追加

		*

TAB		EQU	009H	;タブコード
CR		EQU	00DH	;キャリッジリターンコード
LF		EQU	00AH	;ラインフィードコード
EOS		EQU	'$'	;End Of String 文字列の終端(DOS call用)

CODE		SEGMENT		;COM形式
		ASSUME	CS:CODE
		ASSUME	DS:CODE
		ASSUME	ES:CODE

		org	002CH
ENV_SEG		DW	?		;環境変数のセグメント(DOSが設定する)

		org	0070H

	;	データ部
	;	(PSP内のFCB領域をワークエリアとして利用している)

KEY_INT_VEC	label	dword		;INT 90ベクトルの保存領域
KEY_INT_OFF	DW	?
KEY_INT_SEG	DW	?

SAVE_AX		DW	?		;キー待ちあり?なし?の保存領域

		org	0080h
COMMAND_PARAM	DB	80h  dup(?)	;コマンドラインからのパラメータ
					;(1文字目はパラメータの長さ)

	;	コード部
	;

		org	0100h
START:
		JMP short INITIALIZE	;初期化ルーチンへジャンプ

	;	常駐部
	;	~~~~~~

ENTRY_INT90H	proc	far
	;アプリケーションソフトが
	;INT 90を実行するとまず
	;ここに制御が移る

	;INT 90 ｢文字の読込｣のインタフェィス
	;CALL WITH
	;  AH=09H
	;  AL=0	:キー入力待ち
	;  AL=1 :キー入力待ちなし
	;RETURNS
	;  AH=0 :正常終了
	;  DH=0FFH :入力文字なし
	;  DH!=0FFH:入力文字あり
	;  DL: 文字コード/スキャンコード
	;  BH: キーアドレス
	;  BL: シフトキー状態

		CMP	AH,009H		; 「文字の読込」の機能？
		JE	ZERO_TO_COMMA
		JMP	CS:KEY_INT_VEC	;それ以外は本当のINT 90hに制御を渡す
ENTRY_INT90H	endp

ZERO_TO_COMMA	proc	far
	;この部分が実行されるときには
	;ES,DS,SSが何を指しているかは
	;不定であることに注意。データ
	;部をアクセスするためにCS:で
	;セグメントオーバーライトする
	;必要がある

		STI			;割り込み許可
		MOV	CS:SAVE_AX,AX	;呼び出し機能をセーブしておく
		
	;ここで本来のINT 90を呼ぶのだ
	;が実際にINT 90Hを実行すると
	;無限ループになるのでCALLで呼
	;び出す。次のpushf〜callで
	;INT 90と同じになる。

		PUSHF
		CLI
		CALL	CS:KEY_INT_VEC	;本当のINT 90h FUNC 9を呼ぶ

	;｢000｣キー以外は呼び出しもとの
	;アプリケーションに戻る
	;キー待ちなしが指定されていて
	;キー入力がないときも戻る

		CMP	BH,04AH		;｢000｣キーのキーアドレス？
		JNE	RETURN_TO_APL

	;｢000｣キーの場合は一つ目と二つ目
	;の｢0｣は読み捨てる

		MOV	AX,CS:SAVE_AX
		PUSHF
		CLI
		CALL	CS:KEY_INT_VEC	;本当のINT 90h FUNC 9をコール
		CMP	BH,04AH		;｢000｣キーのキーアドレス？
		JNE	RETURN_TO_APL

	;｢000｣キーの場合三つ目の｢0｣を｢,｣
	;に変えてもとのアプリに戻る

		MOV	AX,CS:SAVE_AX
		PUSHF
		CLI
		CALL	CS:KEY_INT_VEC	;本当のINT 90h FUNC 9をコール
		CMP	BH,04AH		;｢000｣キーのキーアドレス？
		JNE	RETURN_TO_APL
		MOV	DL,','		;CAMMAにすりかえる
RETURN_TO_APL:

	;呼び出しもとのアプリケーション
	;にもどる。
	;INTからの戻りなのでふつうの
	;RET命令は使えないことに注意

		IRET

ZERO_TO_COMMA	endp
 
	;	初期化部
	;	~~~~~~~~
	;初期化部はプログラムが起動
	;したときに一度だけ実行される
	;常駐終了するときに初期化部は
	;開放される


INITIALIZE	proc

	;コマンドラインのパラメータを
	;チェックします。

		CLD
		MOV	SI,offset COMMAND_PARAM+1

SKIP_BLANK:
		LODSB
		CMP	AL,' '		;空白は無視
		JE	SKIP_BLANK
		CMP	AL,TAB		;タブコードは無視
		JE	SKIP_BLANK
		CMP	AL,CR		;パラメータは全く無かった
		JE	NO_PARAM

	;｢S｣とか｢R｣とかの直前の文字は
	;｢/｣でも｢-｣でもよい
	;はっきりいってなんでも良い
	;(手抜き)
	;またこれ以降の文字もまったく
	;チェックしていない。したがって
	;comma000 /s /r
	;のように書くと最初のパラメータ
	;のみが有効になる。

		LODSB
		CMP	AL,'S'
		JE	START_STAY	;S Stay 常駐開始
		CMP	AL,'s'
		JE	START_STAY
		CMP	AL,'R'		;R Remove 常駐終了
		JE	END_STAY
		CMP	AL,'r'
		JE	END_STAY
NO_PARAM:
		;パラメターなし
		CALL	STAY_CHK
		JE	END_STAY
	;	JMP	START_STAY	;次に流れ込む
INITIALIZE	endp

		
START_STAY	PROC

	;	常駐開始

		CALL	STAY_CHK
		PUSH	CS
		POP	ES		;ES←CS
		JE	ALREADY_STAY

	;常駐しているかどうかの判断の
	;鍵になる文字列を転送する
	;PSP内を使うのはVMAPなどの
	;メモリ利用状況表示ツールで
	;PSPを見るものが多いから

		MOV	DI,offset COMMAND_PARAM
		MOV	SI,offset ID_MSG
		MOV	CX,27
		REPNZ	MOVSB

	;INT 90のベクトルを取得する

		MOV	AX,03590H	;割り込みベクトルの取得
		INT	021H		;DOSシステムコール

	;INT 90のベルトルを保存する
	;ES:BX 割込みベクトルのアドレス

		MOV	KEY_INT_OFF,BX	
		MOV	KEY_INT_SEG,ES

	;新しい割り込みベクトルの設定
	;COMMA000の入口を設定する

		MOV	DX,offset ENTRY_INT90H
		MOV	AX,02590H	;割り込みベクトルの設定
		INT	021H		;DOSシステムコール

	;常駐開始メッセージを出力

	;MS-DOSのシステムコールで文字を
	;出力する場合キーのチェックが
	;行われる
	;すでにINT 90は書換え済なので
	;常駐部が呼ばれることになる
	;もしもメッセージが正常に出力
	;されない時は、常駐部が変なの
	;かもしれません。

		MOV	DX,offset STR_MSG
		CALL	PUTS

		MOV	ES,ENV_SEG	;環境変数エリアの
		MOV	AH,049H		;メモリブロックの開放
		INT	021H		;DOSシステムコール
		XOR	AX,AX		;AX←0
		MOV	ENV_SEG,AX	;cf. ◎h!FM 1990-12-p148.

	;常駐するメモリサイズの計算は
	;パラグラフ単位なので計算が
	;ちょっとめんどう
	;PSPの分を忘れてはいけない

		MOV	DX,(INITIALIZE+15-START)/10H+10H
		MOV	AX,03100H	;常駐終了
		INT	021H		;DOSシステムコール
START_STAY	endp

NO_OPERATION	proc

CANT_REMOVE:	MOV	DX,offset EN2_MSG
		JMP short PUT_END
ALREADY_STAY:
		MOV	DX,offset ST2_MSG
PUT_END:
		CALL	PUTS
		MOV	AX,04C00H	;プロセスの終了(リタンコード0)
		INT	021H		;DOSシステムコール
NO_OPERATION	endp


END_STAY	proc
		CALL	STAY_CHK
		JNE	CANT_REMOVE
		;INT90ベクタをもとに戻す
		LDS	DX,ES:KEY_INT_VEC
		MOV	AX,02590H	;割り込みベクタの設定
		INT	21H		;DOSシステムコール
		;常駐していたメモリブロック開放
		MOV	AH,049H		;メモリブロック(ES)の開放
		INT	21H		;DOSシステムコール
		;常駐終了メッセージの出力
		PUSH	CS
		POP	DS
		MOV	DX,offset END_MSG
		JMP	PUT_END
END_STAY	endp



STAY_CHK	PROC
	;すでにCOMMA000が常駐しているかどうかのチェック
	;RETURN
	; Z :COMMA000が常駐している
	; NZ:COMMA000はみつからなかった

	;｢COMMA000｣の文字列がINT 90のセグメントにあるかどうかを
	;調べている。まぁこの程度のチェックで十分でしょう。
	;本当は別のソフトがINT 90をフックしてるかもしれないのだが
	;その場合は開放することもできなくなるのでチェックはしない。

	;このルーチンからリターンした後はESの値が変わることに注意

		MOV	AX,03590H	;割り込みベクトルの取得(ES:BX)
		INT	021H		;DOSシステムコール

		MOV	DI,offset COMMAND_PARAM
		MOV	SI,offset ID_MSG
		MOV	CX,ID_LEN
		REPZ	CMPSB
		RET
STAY_CHK	ENDP

	;	メッセージ出力
	;	(DX:メッセージ開始アドレス)
	;MS-DOSのシステムコールによる
	;文字列な出力なので
	;Townsｼｽﾃﾑｿﾌﾄｳｪｱで実行する場合は
	;出力は見えない

PUTS		proc
		MOV	AH,09H		;文字列の出力
		INT	021H		;DOSシステムコール
		RET
PUTS		endp

ID_MSG		DB 24
		DB 'Comma000 (C)1991. Boko.',CR,0
STR_MSG		DB 'Comma000 V1.1 for FM TOWNS & FMR Series'
        	DB ' (C)1991. Boko.',CR,LF
		DB 'テンキーの｢000｣を｢,｣に変更します。',CR,LF
		DB EOS
END_MSG		DB 'テンキーの｢000｣はもとどおりの｢000｣です。',CR
		DB EOS
ST2_MSG		DB 'Comma000はすでに常駐しています',CR
		DB EOS
EN2_MSG		DB 'Comma000はありません',CR
		DB EOS
ID_LEN		=	STR_MSG - ID_MSG
CODE		ENDS
		END	START
