このエントリーをはてなブックマークに追加
スポンサーリンク

キーボードBIOS

PC-9801のキーボード

PC-9801のキーボードは、FM-7と違ってキーボードコントローラーのI/Oに直接アクセスする事によって、現在キーが押し下げられているか離されているかをチェックする事ができます。それが、PC-9801が一時期ゲームマシンとして大流行した理由の1つでもあります。

MS-DOS割り込み INT21H

キー入力ルーチンを作る場合、大抵はMS-DOSのINT 21Hで十分ですし、できる限りこちらを使うべきです。

キーボードから1文字入力
AHレジスタ エコーバック [Ctrl][C]チェック
01H あり あり
06H あり なし
07H なし なし
08H なし あり
キーボードから1文字入力します。入力があるまで待ちます。出力は、いずれもALに文字コードが入ります。

キーバッファの検査
入力 出力
AH=0BH AL
  00H キーバッファにデーターなし
  FFH キーバッファにデーターあり
AH=01H,06H,07H,08Hはいずれもキーボードから入力があるまで待ちます。キーが押されるまで待ちたくない場合は、このAH=0BHでキーバッファをチェックして、キーバッファにデーターがある事を確認してから、AH=01H,06H,07H,08Hを使います。

キーバッファをクリアしてから1文字入力
AHレジスタ ALレジスタ エコーバック [Ctrl][C]チェック
0CH 01H あり あり
06H あり なし
07H なし なし
08H なし あり
いったんキーバッファをクリアしてから1文字入力を求めます。そのため、キー入力があるまで必ず待ちます。重要なメッセージを表示させる場合、その前にキーボードを連打していたら読む前にメッセージが先に進んでしまうと困るので、このファンクションでキーバッファをクリアしてからキー入力待ちをさせましょう。

キーボードBIOS INT18H

大抵はMS-DOS割り込みだけで十分なのですが、それだけだとPFキーの判別ができない、シフトキーの状態を読めない、キーが押し下げられているか離されているかがわからない、といった問題があります。

え?PFキーって何かって?これは「プログラマブル・ファンクションキー」の略です。だって、「Fキー」って表記したら単なる[F]のキーみたいじゃん?というわけで、このサイトで「PFキー」という表記が出てきたら、[F1]〜[F10]の事だと思ってください。

MS-DOS割り込みは汎用性を重視するため、シフトキーやPFキーの状態の取得までは対応していません。そこで、PFキー、シフトキーの状態を読み取る場合には、キーボードBIOSを利用します。

AH=00 キーボードから1文字入力
入力 出力
AH=00H AH キーコード
AL キーデータ
キーボードから1文字入力し、入力があるまで待ちます。エコーバックはされません。このファンクションを使うと、MS-DOS割り込みではできなかったキーコードを取得する事ができます。なので、フルキーとテンキーの区別やPFキーの判別ができます。

AHレジスターに返るキーコードは以下の通りです。16進数です。
キー キーコード キー キーコード キー キーコード
フルキー1 01 テンキー0 4E A 1D
フルキー2 02 テンキー1 4A B 2D
フルキー3 03 テンキー2 4B C 2B
フルキー4 04 テンキー3 4C D 1F
フルキー5 05 テンキー4 46 E 12
フルキー6 06 テンキー5 47 F 20
フルキー7 07 テンキー6 48 G 21
フルキー8 08 テンキー7 42 H 22
フルキー9 09 テンキー8 43 I 17
フルキー0 0A テンキー9 44 J 23
= - ほ 0B テンキー/ 41 K 24
~ ^ へ 0C テンキー* 45 L 25
| \_ 0D テンキー- 40 M 2F
Back Space 0E テンキー+ 49 N 2E
TAB 0F テンキーEnter 1C O 18
ESC 00 P 19
Enter 1C Q 10
HELP 3F R 13
HomeCLR 3E S 1E
XFER 35 T 14
Ctrl XFER B5 U 16
NFER 51 V 2C
Ctrl NFER B1 W 11
VF1 52 X 2A
VF2 53 Y 15
VF3 54 Z 29
VF4 55 < , ね 30
VF5 56 > . る 31
F1 62 ? / め 32
F2 63 _ \ ろ FF
F3 64
F4 65
F5 66
F6 67
F7 68
F8 69
F9 6A
F10 6B
資料がなかったので、自前のプログラムを作って1つ1つ押してみて調べました。確認ミスで違ってる場合もあります。違ってたら掲示板かツイッターで教えてください。

ALレジスターにはキーデーター、要するに押した時に出力されるアスキーコードが入ります。Aなら41H、aなら61Hですね。キーデーターは同じキーを押してもシフトキーやCAPSロック、カナロックの状態により変化します。PFキーやVFキーにはキーデーターはないので00Hが返ります。

PFキーの1〜10が押されるまで待つためには、キーコードに62H〜6BHが返るまでキー入力を待てば良いわけです。例えば、F1〜F10が押された場合は、AXレジスタに1〜10、それ以外は0が返るとして・・・
YOMI		=	$
		MOV	AH,0
		INT	18H

		CMP	AH,62H
		JAE	$+5
		JMP	YOMI2

		CMP	AH,6BH
		JBE	$+5
		JMP	YOMI2

		MOV	AL,AH
		MOV	AH,0
		SUB	AL,61H
		JMP	YOMI3

YOMI2		=	$
		MOV	AX,0
YOMI3		=	$
		:
	     (省略)
		:
よく「レジスタに0を入れる時は自分自身とXORを取らないとダメだろ」って言われるんですけど、一応私個人としては0を入れるという事が見てわかりやすくするために、あえて0をMOVで入れてます。それに、自分自身とXORしないで0をMOVする事で体感的に遅いと感じた事もないし。

AH=01 キーバッファのチェック
入力 出力
AH=01H AH キーコード
AL キーデータ
BH 0バッファにデーターなし
  1バッファにデーターあり
キーバッファをチェックして、キーバッファにデーターがあればBHレジスタに1を返します。キー入力があるまで待ちません。キーバッファにデーターがある場合は、キーバッファの先頭のキーコードとキーデータを返しますが、キーバッファはそのままになります。したがって、キーバッファにデーターがあればキーバッファから1つ取り出したい場合は、キーバッファをチェックしてBHレジスタが1ならAH=00Hのファンクションをもう一度呼ぶ必要があります。

これを利用して、キーバッファをクリアする事ができます。
;-----------------------------------------------------------------------------
;		キーバッファ初期化
;-----------------------------------------------------------------------------
BUFFC		=	$
		MOV	CX,100

BUFFC1		=	$
		MOV	AH,1
		INT	18H
		CMP	BH,1
		JE	$+5
		JMP	OWARI

		MOV	AH,0
		INT	18H
		LOOP	BUFFC1

		JMP	OWARI
ここでOWARIは、PUSHしていたレジスタをPOPしてMS-DOSに戻るルーチンなので、あまり気にしないでください。

キーバッファのクリアを100回で強制的に終わらせている理由は、ユーザーがキーボードを押しっぱなしにしていたり、キーボードに物が乗っている場合に無限ループになってしまうからです。その場合は、画面に「11111111111111…」と延々に表示されてユーザーが「あ、やべっ」と自分で気がついた方がいいので、あえて有限ループになっています。

AH=02H シフトキーの状態のチェック
入力 出力
AH=02H AL シフトキーの状態

AL シフトキーの状態
ビット 意味
4 0 Ctrl キーが押されてない
1 Ctrl キーが押されてる
3 0 GRAPHキーが押されてない
1 GRAPHキーが押されてる
2 0 カナロックされてない
1 カナロックされてる
1 0 CAPS LOCKされてない
1 CAPS LOCKされてる
0 0 シフトキーが押されてない
1 シフトキーが押されてる

シフトキー、Ctrlキー、GRAPHキー、CAPS LOCKの状態、カナロックの状態は、AH=00ではわかりません。これらのキーはキーバッファにたまらないので、キーバッファをチェックしてもわかりません。そこで、このファンクションで押下状態をチェックします。

どのキーが押し下げられているかのチェック

AH=04H キーの押下状態のチェック
入力 出力
AH=04H
AL キーコードのグループ番号
AH グループ内の8つのキー押下状態
このファンクションを使う事で、キーが押し下げられているか放されているかチェックする事ができます。FM-7みたいにテンキーを押すと5キーで固定するまでずっとその方向に動きっぱなしなんて事になりません。

どのキーがどのグループで、どのビットが立つのか手持ちの資料に掲載されていませんでしたので、こちらでテストプログラムを作って調べましたが、T98-Nextでは対応していないキーは調べることができませんでした。

グループ ビット
7 6 5 4 3 2 1 0
00H フルキー7 フルキー6 フルキー5 フルキー4 フルキー3 フルキー2 フルキー1 ESC
01H TAB Back Space フルキー \ フルキー ^ フルキー - フルキー0 フルキー9 フルキー8
02H I U Y T R E W Q
03H D S A Enter [ @ P O
04H : * け ; + れ L K J H G F
05H M N B V C X Z ]
06H ROLLDOWN ROLLUP XFER SPACE \ _ ろ / ? め . > る , < ね
07H HELP HOME CLR DEL INS
08H テンキー5 テンキー4 テンキー * テンキー9 テンキー8 テンキー7 テンキー / テンキー -
09H テンキー, テンキー0 テンキー = テンキー3 テンキー2 テンキー1 テンキー + テンキー6
0AH VF5 VF4 VF3 VF2 VF1 NFER テンキー .
0BH
0CH F5 F4 F3 F2 F1 COPY
0DH F10 F9 F8 F7
0EH カナ CTRL GRAPH CAPS SHIFT

※注
・Enterはフルキーとテンキーともに同じみたいです。
・ROLLUPはエミュレーターではPageDown、ROLLDOWNはエミュレーターではPageUPです。
・STOPキーのコードはわかりませんでした。なにしろ押すとテストプログラムが止まってしまいますので・・・。
・CAPSはロックしている間は押下と判断されるみたいです。カナは実際に押下されている間だけです。
・F6だけはどうやってもビットが立ちませんでした。T98-Nextのバグかも?まあ、アクションゲームでF6は使わないでしょうし・・・。

参考文献(PC-9801スーパーテクニック)によると、キーバッファオーバーのBEEP音を鳴らないようにキーボードコントローラにコマンドを送らないといけなかったり、キーリピート中に断続的にキーが放されているように見えるのを、リピート中か手動で連打してるのかを見分けないといけなかったりと、色々大変なようです。 残念ながら、ここではこのファンクションについては詳しく説明できません。申し訳ありません。

参考文献
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク
スポンサーリンク