Programming the Keyboard : キーボードのプログラミング


免責

私は、このファイル、その中に含まれる情報、もしくはそれの使用が、 あなた、あなたの精神的な健康、コンピュータ、配偶者、子供、ペットやその他あなたに関係するものなんでも、もしくはあなたの存在にどのような影響を与えようとも責任を負わない。
この情報について、明示黙示を問わず一切の保証はしない。

I assume no responsibility whatsoever for any effect that this file, the information contained therein or the use thereof has on you, your sanity, computer, spouse, children, pets or anything else related to you or your existance.
No warranty is provided nor implied with this information.

概要

キーボードの動作は本当にとても単純である。
キーが押されたり離されたりする毎に割り込み 9 番が生成され、 ポート 60h を読むことで何が起こったのか把握する。

キーボードバイトのデコード

あなたはすべてのキーボードイベントをハンドルするための割り込みハンドラを設置でき、 そして割り込みが生成された際に、あなたのハンドラは ポート 60h からバイトを読む。

えーっと・・、 キーボード上のそれぞれのキーは、バイトの低位 7 ビット の中に含まれている、スキャンコードを持つ。

最も重要なビット (Bit7 )は、何がなされたのかを教えてくれる。(0 = キーが押された、1 = キーが離された) 例えば仮に誰かが ESC キーを押したならば、ポートは値 1 を示す。( 1 は ESC キーのスキャンコード) もしそのままボタンの上に指を置き続けていたなら、キーボードは割り込み 9 番を生成し続け、その度にポートは値 1 を示すだろう。

キーを離すと、最後の割り込みが生成され、ポートは 129 ( 1 + 128, 最上位ビットがキーを離したことを示すためにセットされる) を返すだろう。

えーっと・・・、この単純なのがほとんどだ。

いくつかのキーは「拡張された」キーである。 拡張キーが押されると、割り込みが生成され、キーボードポートは値 224 (E0h)を返す。 これは、拡張キーが押されたこと、そしてその *拡張された* スキャンコードが *次* の割り込みの間有効であろう、ということを示している。

左コントロールキーがスキャンコード 29 を持つ一方、 *右* コントロールキーもスキャンコード 29 を持つということに注意せよ。 同じ事は ALT キーと矢印キー(キーパッドの矢印と他のもの)にも言える。

もし全てのキーが等しく作られ、我々が単に拡張バイト 224 を捨てて全ての次のバイトを普通にハンドルする、ということができればよかったのに。 不幸にも、私のマシンにおいて(そして私の試した他のものにおいても)いくつか本当にどうしようもない動作をする2つのボタンがある。

PrtScn(プリントスクリーン)

このボタンを押すと、ハンドラに *2 つの* 拡張文字 42 と 55 が送信される。
つまり実際のバイト列は 224, 42, 224, 55 となるだろう。
(また、左シフトキーは一般のスキャンコード 42 を持っているので、単に 224 を捨てるという考えはないということに注意せよ。)
拡張文字 55 だけは、オートリピートの間送信され続ける。
キーが離された時、2つは最上位ビットをセットされて(224, 170, 224, 183)再び送信される。
もし PrtScn キーが押されていて、離されるときにコントロールキーかシフトキーのいずれかを押し続けられているならば、、???
もし ALT キーが押され続けている(System Request キー)ならば、キーはスキャンコード 84 を持つ通常のキーとして振る舞う。
これら全てへの現実的な結論は、普通のキーや拡張キーをハンドルするためにあなたが書くハンドラが 全ての異なる PrtScn の組み合わせに対してうまく働くようにすることだ。
(しかしどのキーが現在押されているかを決定するために、プログラムは普通のキー 84 *と* 拡張キー 55 をチェックする必要がある。)

Pause/Break

地獄へようこそ。
もしあなたがコントロールキーのどちらかが押し続けられている間にこのキーを押すならば それは拡張キー 70 のように振る舞うだろう。
他の場合全てにおいては以下のバイトを送信するように(225, 29, 69, 225, 157, 197)、 振る舞うだろう。
キーを押し続けることはオートリピートの結果にはならない。
225 は 224 ではない,つまり我々の普通の拡張文字ハンドラがこれを処理しないであろう、ということに注意せよ。
私の個人的な理論は、スキャンコード 224 (E0h) はもう一つ文字が続くことを意味している一方、 スキャンコード 225 (E1h) は もう *2つ* 続くことを意味しているということだ。
私は多くのキーボードハンドラライブラリを見たことがあるが、それら全てはこのキーを見落としているようだ。
なぜ、あなたの障害物に対して、Pause/Break キーを適切にサポートするキーボードハンドラを持とうとする最初の若者がいないのか?
チェックせよ!!

ハンドラを書く

キーボードハンドラを書くことは???
この章ではパスカルでそれをする方法を示すつもりだ。 (C と アセンブラのプログラマはいずれにせよ多分すでにこれを知っているだろう。)

まず、必要な最小限のものを宣言する。

const KEYBOARDINTR = 9;
      KEYBOARDPORT = $60;

var BIOSKeyboardHandler : procedure;
    CallBIOSHandler : boolean;

変数 CallBIOSHandler は呼び出すプログラムによって初期化される。 もしすべてのキー入力を見る BIOS ハンドラも欲しいなら、この変数は true にセットされなければならない。

次に現在のハンドラの値を保存し、我々のものにセットアップしなくてはならない。 実際の割り込みをハンドルするための KeyboardHandler を呼び出すプロシージャを使う。

CallBIOSHandler := false; { ...or set it to true if you want. }
GetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);
SetIntVec(KEYBOARDINTR, Addr(KeyboardHandler));

オーケー。 すべてセットアップされ我々のハンドラはすべてのキーボードイベントを処理できるようになる。 実際の割り込みハンドラはこんな風に見えるはずだ。


{$F+}
procedure KeyboardHandler(Flags, CS, IP, AX, BX, CX, DX,
                          SI, DI, DS, ES, BP: Word);
interrupt;
var key : byte;
begin

  key := Port[KEYBOARDPORT];

  { PROCESS THE KEYSTROKE HERE }

  if CallBIOSHandler then

  { Call the BIOS keyboard handler if the calling program wants us to }
    begin
      asm pushf end;
      BIOSKeyboardHandler;
    end

  { Otherwise just acknowledge the interrupt }
  else Port[$20] := $20;
end;
{$F-}

プログラムが終了する際に、再び古いキーボードハンドラをセットできる。

SetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);

ちょっとした警告

私がこのファイルの中の情報をテストするために単純なハンドラを書いていたとき、 私が世界と共有したい本当にバカなことをした。

プログラムを終了させたとき、 エディタ(Borland Pascal 7.0)がまるでコントロールボタンが押し続けられているかのように動いたので、 私はプログラムがキーボードを詰まらせてしまったのだと考えた。 (あなたがたのうちの何人かは、もうすでに笑いはじめたのではないかと私は確信している。)

私はただそれを分類するためにプログラムを走らせる毎に、そのあとそれを押さなければならなかった。 可能性として間違っているであろう情報をそこらじゅうから探しだすために何時間か費やした後、 私は私が何をしていたのかを理解した。

私は、直ちにそれを動かすプログラムをコンパイルするために CTRL+F9 を押していた。 私のプログラムが動いているとき、すなわち本来の BIOS ハンドラ がコントロールキーの 「キー上げ」命令を受け取っていないときに、私はコントロールキーを離していた。 私のプログラムがそれに制御を戻したとき、それはキーが未だ押し続けられているように考えていた。

うーん・・・

スキャンコード

以下は番号順に並べられたすべての本来のキーのスキャンコードである。

Scan                                   Scan
Code Key                               Code Key
--------------------------             --------------------------
 1   ESC                               44   Z
 2   1                                 45   X
 3   2                                 46   C
 4   3                                 47   V
 5   4                                 48   B
 6   5                                 49   N
 7   6                                 50   M
 8   7                                 51   , <
 9   8                                 52   . >
10   9                                 53   / ?
11   0                                 54   RIGHT SHIFT
12   - _                               55   *            (KEYPAD)
13   = +                               56   LEFT ALT
14   BACKSPACE                         57   SPACEBAR
15   TAB                               58   CAPSLOCK
16   Q                                 59   F1
17   W                                 60   F2
18   E                                 61   F3
19   R                                 62   F4
20   T                                 63   F5
21   Y                                 64   F6
22   U                                 65   F7
23   I                                 66   F8
24   O                                 67   F9
25   P                                 68   F10
26   [ {                               69   NUMLOCK      (KEYPAD)
27   ] }                               70   SCROLL LOCK
28   ENTER (RETURN)                    71   7 HOME       (KEYPAD)
29   LEFT CONTROL                      72   8 UP         (KEYPAD)
30   A                                 73   9 PGUP       (KEYPAD)
31   S                                 74   -            (KEYPAD)
32   D                                 75   4 LEFT       (KEYPAD)
33   F                                 76   5            (KEYPAD)
34   G                                 77   6 RIGHT      (KEYPAD)
35   H                                 78   +            (KEYPAD)
36   J                                 79   1 END        (KEYPAD)
37   K                                 80   2 DOWN       (KEYPAD)
38   L                                 81   3 PGDN       (KEYPAD)
39   ; :                               82   0 INSERT     (KEYPAD)
40   ' "                               83   . DEL        (KEYPAD)
41   ` ~                               87   F11
42   LEFT SHIFT                        88   F12

以下は番号順に並べられたすべての拡張キースキャンコードの表である。

Scan                                   Scan
Code Key                               Code Key
-------------------------------        -------------------------------
28   ENTER        (KEYPAD)              75   LEFT         (NOT KEYPAD)
29   RIGHT CONTROL                      77   RIGHT        (NOT KEYPAD)
42   PRINT SCREEN (テキスト参照)        79   END          (NOT KEYPAD)
53   /            (KEYPAD)              80   DOWN         (NOT KEYPAD)
55   PRINT SCREEN (テキスト参照)        81   PAGE DOWN    (NOT KEYPAD)
56   RIGHT ALT                          82   INSERT       (NOT KEYPAD)
71   HOME         (NOT KEYPAD)          83   DELETE       (NOT KEYPAD)
72   UP           (NOT KEYPAD)         111   MACRO
73   PAGE UP      (NOT KEYPAD)


(訳注)

この文書は、 Worsit Format(http://www.worsit.org) 内の文書 "Programming the Keyboard" を日本語に翻訳し、HTML 化したものです。

拙い訳ですので、翻訳の内容・正確さについて翻訳者は一切の責任を負いません。 正確な内容を知りたい場合には、原文(英語)をお読みください。