手元に実機も実行環境もありませんのでサポート不可です。
文章は執筆当時のものをそのまま掲載していますので、時代・時節と合わない表現が含まれています。
また、一部に半角カナ文字が使用されています。
さてさて、1年ぶりの開講ですね。長々とさぼってました。
今回の講義内容は前回宣言した内容とは少しだけ変えて、まずはキー入力判定から進めたいと思います。
まず、キー入力というものの必要性は言うに及ばないでしょう。
Keyboardというものは、現在のComputerでは最も重要なUser Interfaceの1つで、様々な情報の入力には欠かせないものとなっています。
特にCursorというのは、現在自分がどの情報を参照し、どこに必要な情報を書き込む或いは選択するべきかを示したもので、画面上に展開された種々の情報の選別には欠かせないものです。
という事で、今回はカーソルの移動よりも先にキー入力判定というものを本題に掲げました。
さてこのキー入力の方法というのには幾つかの方式が考えられます。
大体以下の方法があるでしょう。
|
No. |
手段 |
コメント |
|
1 |
I/O Portの直接制御 |
電算機の直接制御を目的とするには適するが、Auto Repeatなども全て自身の手で行わなければならず、またKey Bufferの処理の仕方などの問題や、更にKeyboard Deviceの初期化などに苦労を要する場合もあり、あまり実用的とはいいきれないし、BIOSとの両立が困難な場合がある。 |
|
2 |
BIOSを使用 |
どちらかというと、BIOSを利用した方がKeyboard Deviceの制御には適すると言える(Keyboardは一旦BIOSを経由してからUserに対する反応が示されるようになっているからです)。 |
という事で今回の講義内容は2つのテーマで進めますが、特に後者の方を重要視して進めています。
まず、I/O Portの直接制御によるものですが、PC-9800 Seriesでは特に適さない方式なのかもしれません。上級の技術を持ち、Hardwareに対する知識・BIOSに対する知識が十分に備わっているのであれば問題はないのですが、Keyboard Deviceの初期化には数段階の要素があり、また各段階毎のタイミングの取り方など、あまりにも初心者がするには難しい内容を含むからです。まぁ、本講義ではそこまでの高度なものは考えていませんので、そういう事は割愛します(^^;
逆に、PC-88VA SeriesではKeyboard DeviceのInitializeは全てBIOSが一手に握っており、我々Programmerがそこまで意識する必要はないようになっています。
さてこのようなHardwareの違いはありますが、最終目標としては単にI/O Portから直接Keyboardの状況、特に押しているKeyの状態判別を読み取る事にあります。
大抵の内部資料を記した書籍でれば、Keyboard上の各KeyがどのI/O Portに反映されるようになっているのかを示していますが、そういうのを参考にしながら以下の事を考えられるといいでしょう。
;Sample Program1 For PC-88VA
Ideal
P186
Model Small
Stack 0200h
CodeSeg
InputCheck:
in al,002h ;I/O Port Read
test al,000000010b ;Press 'A' Check
jnz InputCheck
mov ax,04c00h ;Return to PC-Engine(or MS-DOS)
int 021h
End
この方法では単に「A」を押したらApplicationが終了するようになっています。
内容は特に簡単で、常にA KeyをMapしているI/O Portを読み込み、A Keyが押されたというFlagが立てば終了するというだけで、難しい事は何もしていません。尚PC-9800 Series用がないのは、諸般の事情から動作確認がとれなくなった為と、手元にそのようなLibralyがないため、動作保証が全くとれないものを掲載するべきではないと考えた為です。
複数のKeyを同時に判別したいのであれば、複数のI/O Portを読み込み、1つずつ認識していけばいい事になります。
さて次にBIOSを利用した場合についてですが、これは実にSimpleにできます。
Keyboard Device InitializeからStatus Readまで全てBIOSに任せればよく、先程と同じ動作をするものを組んでみましょう。
;Sample Program2 For PC-88VA
Ideal
P186
Model Small
Stack 0200h
CodeSeg
mov ax,00500h ;Keyboard Initialize
int 082h
InputCheck:
mov ax,00d02h ;Keyboard Status Read
int 082h
test ah,000000010b ;Press 'A' Check
jz InputCheck
mov ax,00400h ;Key Buffer Clear
int 082h
mov ax,04c00h ;Return to PC-Engine(or MS-DOS)
int 021h
End
;Sample Program2 For PC-9800
Ideal
P186
Model Small
Stack 0200h
CodeSeg
mov ax,00300h ;Keyboard Initialize
int 018h
InputCheck:
mov ax,00403h ;Keyboard Status Read
int 018h
test ah,000100000b ;Press 'A' Check
jz InputCheck
KeyBufferClearLoop:
mov ax,00100h ;Key Buffer Clear
int 018h
or bh,bh
jz KeyBufferClearEnd
xor ax,ax
int 018h
jmp Short KeyBufferClearLoop
KeyBufferClearEnd:
mov ax,04c00h ;Return to MS-DOS
int 021h
End
多少長くなったように思うかもしれませんが、それはBIOSを使う為ですので仕方がありません。
因みに、I/O Portの直接制御でもKeyboard BIOSのInitiailzeを利用すれば、Keyboard Device Initializeができますので、それを利用しても問題はありません。
ただ両Programの結果に大きな違いがあると思います。
前者の方では画面に「A」と表示されるのに対し、後者の方では何も表示されていません。これはKeybuffer Clearを最後にかけているからです。
I/O Portだけを利用する場合にはどうしてもBIOSにためられた情報を抑え切れないのに対し、うまくBIOSを利用すればそのような問題はありません。
しかし、I/O Portだけを利用する事に固執せずにBIOSを併用するようにすれば、恐らくにして問題はないでしょう。というより、BIOSというのはあくまで補助動作用のもので、面倒な処理を全て任せてしまうという為のものと考えるべきなのかも知れませんが。
プログラミング時のまめ知識その3−DOSによるKeyboard入力判定−
やる事は大変簡単です。DOS Commandを1個用いるだけです。
Ideal
P186
Model Small
Stack 0200h
CodeSeg
InputCheck:
mov ah,001h
int 021h
sub al,020h
cmp al,'A' ;Press 'A' Check
jnz InputCheck
mov ax,04c00h ;Return to PC-Engine(or MS-DOS)
int 021h
End
DOS互換のSoftwareなら、こういう方式(或いはそれに近いもの)でやってる事が殆どだと思います。
では次に複数入力の例を示しましょう。
;Sample Program3 For PC-88VA
Ideal
P186
Model Small
Stack 0200h
CodeSeg
call KeyboardInitialize
MainRoutine:
call KeyInputCheck
test al,000010000b
jz MainRoutine
call KeyBufferClear
mov ax,04c00h
int 021h
Proc KeyboardInitialize Near
push ax
mov ax,00500h
int 082h
pop ax
ret
EndP
Proc KeyInputCheck Near
pushf
push bx cx ds
cld
mov ax,cs
mov ds,ax
mov si,Offset InputKeyTable
xor bx,bx
mov cx,5
KeyInputCheckLoop:
push cx
lodsb
mov ah,00dh
int 082h
lodsb
mov cl,al
shr ah,cl
rcl bl,1
pop cx
loop KeyInputCheckLoop
mov ax,bx
pop ds cx bx
popf
ret
EndP
InputKeyTable:
db 009h,1 ;Stop
db 008h,2 ;Up
db 00ah,2 ;Down
db 00ah,3 ;Left
db 008h,3 ;Right
Proc KeyBufferClear Near
push ax
mov ax,00400h
int 082h
pop ax
ret
EndP
End
;Sample Program3 For PC-9800
Ideal
P186
Model Small
Stack 00200h
.Code
call KeyboardInitialize
MainRoutine:
call KeyInputCheck
test al,000010000b
jz MainRoutine
call KeyBufferClear
mov ax,04c00h
int 021h
Proc KeyboardInitialize Near
push ax
mov ax,00300h
int 018h
pop ax
ret
EndP
Proc KeyInputCheck Near
pushf
push bx cx ds
cld
mov ax,cs
mov ds,ax
mov si,Offset InputKeyTable
xor bx,bx
mov cx,5
KeyInputCheckLoop:
push cx
lodsb
mov ah,004h
int 018h
lodsb
mov cl,al
shr ah,cl
rcl bl,1
pop cx
loop KeyInputCheckLoop
mov ax,bx
pop ds cx bx
popf
ret
EndP
InputKeyTable:
db 00ch,1 ;Stop
db 007h,3 ;Up
db 007h,6 ;Down
db 007h,4 ;Left
db 007h,5 ;Right
Proc KeyBufferClear Near
push ax bx
KeyBufferClearLoop:
mov ax,00100h
int 018h
or bh,bh
jz KeyBufferClearEnd
xor ax,ax
int 018h
jmp Short KeyBufferClearLoop
KeyBufferClearEnd:
pop bx ax
ret
EndP
End
この方法でやっている事は、Table処理を利用しているというぐらいで大した事は何もしていません(尚、Stop KeyとCursor Keyの判別をしていますが、Stop Keyを押さない限り終了しませんし、反応はないようになっています)。
またBIOSによる入力判定をしていますが、これをI/O Portによるものと入れ替えても、そう動作に問題はないでしょう。というより、前述してきた方法はあくまで別々に行った場合を取り上げただけで、実際にはやりたい事だけを限定すれば、ここまで簡単にできるという事を示したかっただけのものです。
さて、Tableにかかれているものですが、前者はKey Mapの何れのAdderssを読むのか、を示し、後者の列はそのAddressの何Bit目を読むのかを示しています。
この方法を利用すれば、ほぼ大抵の単一のKey入力には応用できます。
現実私も多用する程のものです。
さて、今回の講義内容はまずはここまでとします。
次回は実際にCursorを表示し、Cursor Keyによって移動する所までを示しましょう。
手元に実機も実行環境もありませんのでサポート不可です。
文章は執筆当時のものをそのまま掲載していますので、時代・時節と合わない表現が含まれています。
また、一部に半角カナ文字が使用されています。