概要
対象は次のようなものです.
- K/B は PC-98 専用 および AT 互換機 (PS/2 および USB)
- FreeBSD は 4 系以降
- console および X Window System (XFree86 4 系, X.Org 6 系)
X.Org 7 系の HAL に関しては,X.Org on PC-98 (1), X.Org on AT (1) を参照して下さい.
概要
対象は次のようなものです.
目的は次のようなものです.
目次
キーボード上のキーは,様々な視点によって分類されます.
例えば,機能で分類すれば次のようになります. ただし,一つのキーは修飾キーとの組み合わせにより複数の機能を持つのが普通です. (それも含めて機能の実現と割り当ては OS の役割であり,変更可能です.)
また,xkb/geomerty, symbols では,機能よりもむしろ大雑把な配置で分類しています.
キーの挙動 (効き方) によっても分類できます. (AT 互換機ではこれらは OS が管理しており,変更可能です.)
一方,キーを押した際に PC が認識する仕方,キーの送る信号という観点からの分類もできます.
なお,PC-98 においては,次のような特有の「個性」があります.
LED の点灯ですが,AT 互換機においてはその制御は PC の側から OS により行なわれています. 一方 PC-98 においては,[CAPS], [かな] の LED は両方ともキーボードの中で制御が完結しています. これらの点灯は,それらのキーに割り当てられた機能に依らず,キーそのものに連動しています. LED の状態の監視や点灯の制御を PC 側から行なうことも可能なようですが,FreeBSD ではそれをサポートしていません.
[1] Latch のもう一つの例に console におけるアクセント・キーがあります.
(% jman 5 kbdmap を参照.)
そのキーを押して放した後で文字のキー (あらかじめそのアクセントと関係付けておいたもののみ) を押すと,そのアクセント付きの文字が入力されます.
X Window System でもこれに相当する "dead key" というものがあるようなのですが,使い方がわかりません.
どのようなものがあるかは /usr/X11R6/lib/X11/locale/*/Compose をご覧下さい.
[2] この動作を software で実現するのが,挙動のところに記した "Overlay" です.
先ず PC-98 専用,または AT 互換機の PS/2 キーボードを考えます. キーを押したり放したりすれば,例外のキーは別として,キーボードから PC に向けて信号が送られます. これが keyboard scan code です.[3]
PC 内部の keyboard controller は,それを変換して hardware で言えば CPU,software で言えば device driver に転送します. その変換された信号が system scan code です.
次に USB キーボードを考えます.
これは keyboard scan code とは違う信号 (usbcode
[4]) を送信しますが,device driver がそれを system scan code に変換します.[5]
よって,いずれの場合においても OS は system scan code の形で信号を受け取ります.
system scan code は,キーを識別するだけでなく,キーの状態の情報も含んでいます. すなわち,キーの状態を表わす最上位の 1 bit とキーを識別する 7 bit とから成ります.[6] 前者は,キーが押された場合に 0,放された場合に 1 です. キーが押された場合の system scan code を "make code",放された場合のそれを "break code" と呼びます. make code の値の範囲は 0-127,break code のそれは 128-255 です. (当然,同じキーについての二つの code の差は 128 です.)
[3] keyboard scan code に直にお目にかかることはありません.
そういう機会は無い方が幸せです.
Linux では入力を RAW モードに設定すればこれが得られるそうですが,試したことはありません.
[4] この信号の正式名称はわからないので,device driver で用いられている変数名で呼びます.
[5] source (/usr/src/sys/dev/usb/ukbd.c) の冒頭に
#define UKBD_EMULATE_ATSCANCODE 1
という部分があります.
これにより usbcode を system scan code へ変換することが選択されています.
変換に必要なデータは driver がその source の一部として持っています.
[6] それゆえ,キーは最大 128 個しか識別できません.
以後,system scan code を device driver の中での変数名 scancode で呼ぶことにします. 前述のように,この中には二つの情報が含まれています. そこで,device driver の中では
keycode = scancode & 0x7F;
のように,新たな変数 keycode を導入してキーを識別する部分を分離しています.
次に,これはキーマップの表の管理法の都合なのですが,alock または ashift が ON の場合には,keycode の値に 128 を足して 128-255 の範囲の値に変換しています. そして,この keycode によってキーマップを参照しています. これを通じて,キーの操作とその結果 (文字の入力とか何らかの機能) とが結び付けられます. また,複数用意されているキーマップの選択や自身の手によるその変更を通じて,目的に応じた結果が得られるようになります.
キーマップの一例として /usr/share/syscons/keymaps/us.iso.kbd の抜粋を示します. 一番左の列は,実際には scancode でなく keycode です.
# $FreeBSD: src/share/syscons/keymaps/us.iso.kbd,v 1.16 2001/03/11 23:41:19 ache Exp $ # alt # scan cntrl alt alt cntrl lock # code base shift cntrl shift alt shift cntrl shift state # ------------------------------------------------------------------ 000 nop nop nop nop nop nop nop nop O 001 esc esc esc esc esc esc debug esc O 002 '1' '!' nop nop '1' '!' nop nop O 003 '2' '@' nul nul '2' '@' nul nul O (中略) 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C (中略) 103 fkey61 fkey61 fkey61 fkey61 fkey61 fkey61 boot fkey61 O
(例 1) 英数キーの '1' は keycode = 002 です. 単独で押せば '1',shift + 1 で '!' が入力されます.
(例 2) 英数キーの 'q' は keycode = 016 です.
単独で押せば 'q',shift + q で 'Q' が入力されます.
また,行末の "C" は,このキーが Caps Lock の影響を受けることを指します.
(例 3) [DEL] キーは keycode = 103 です.
control + alt + DEL で reboot します.
(ちなみに,Pey Pad の '.' と共用する方の [DEL] キーは keycode = 83 です.)
"fkey61" の意味は,man keyboard に次のように書かれています.
The function keys are numbered like this: Delete key 61
この "fkey61" は "del" とどう違うのか,なぜ使い分けているのかは分かりません.
console では,標準で用意されているキーマップの選択肢以外のことをしたければ,設定ファイルを直接書き換える以外に手段はありません. 一方 X Window System では,それ以外の手段が幾層にも備わっています. キーマップを確認したり変更するためのツールが用意されていますし,自作のプログラムの中からそれらの操作を行なうための関数も用意されています.
設定の仕方は,以下に示すように console よりもかなり複雑になっていますが,修飾キーの取り扱いなど,より合理的になっています.
また,console では文字コードの差異も含めて設定ファイルを指定します. 一方 X Window System では,XF86Config, xorg.conf に規定する us, ja のような「言語を表わすキーワード」に文字コードの区別はなく,それは環境変数 LANG により設定されます.
X Window System においても console と同様に scancode を出発点にしています. OS から受け取る scancode は,次のようにして最終的に得られる結果に変換されます.
1. X Window System では,キーを物理的に識別するために keycode を用います. 押された,放されたという状態は "event" (KeyPress, KeyRelease) として別管理になりますが,ここでは触れません. (これは console の説明に現われた keycode と発想も名前も同じですが,別のものであり数値も違います.)
変数 keycode の値を "keycode 番号" と呼びます. その値域は 8-255 です. 単純に
keycode = (scancode & 0x7f) + 8
であれば,設定ファイルを追うのが楽です. 実際,PC-98 ではそうなっています. AT 互換機でも以前はそうでしたが,今はかなりのキーがそうなっていません.
以下では例として,AT 互換機における英数キー '1' と 'q' を考えます.
2. keycode 番号と keycode 名とは /usr/X11R6/lib/X11/xkb/keycodes/xfree86 によって,次のように結び付けられています.
<keycode 名> = keycode 番号; <AE01> = 10; ← キー '1' <AD01> = 24; ← キー 'q'
3. 一方,キーを論理的に識別するために keysym を用います. keycode 名と keysym 名とは,例えば us101 K/B ならば /usr/X11R6/lib/X11/xkb/symbols/pc/us によって,次のように結び付けられています.
key <keycode 名> { [keysym 名の列挙] }; key <AE01> { [ 1, exclam ] }; key <AD01> { [ q, Q ] };
keysym 名は /usr/X11R6/include/X11/keysymdef.h に定義されています.上の四つに対してこれを抜粋すると,次のようになっています.
#define XK_1 0x0031 /* U+0031 DIGIT ONE */ #define XK_exclam 0x0021 /* U+0021 EXCLAMATION MARK */ #define XK_q 0x0071 /* U+0071 LATIN SMALL LETTER Q */ #define XK_Q 0x0051 /* U+0051 LATIN CAPITAL LETTER Q */
厳密に区別するならば,"keysym" はここで定義された記号定数を,"keysym 値" はここで定義された数値を,"keysym 名" はこの記号定数から "XK_" を除いた文字列を指 します.
4. keysym 名 は,あくまでキーの持つ意味を記号化したものであり,そのキーが押された際に実際に得られる文字列を表わしているわけではありません. (ここでは 1 文字も「文字列」として扱います.) 実際に得られる文字列は「ASCII 文字ストリング」と呼ばれ,keysym と対応付けられています. 例えば keysym 名 の 1, exclam, q, Q には各々 ASCII 文字ストリング "1", "!", "q", "Q" が対応しています.
これらの対応関係は,何らかの設定ファイルに書かれているのでなく,自動的に決められているようです.
(自作のプログラムからこれを変更するための関数も用意されています.)
5. /usr/X11R6/include/X11/keysymdef.h には,keysym として種々の修飾キーも定義されています.
/* Modifiers */ #define XK_Shift_L 0xffe1 /* Left shift */ #define XK_Shift_R 0xffe2 /* Right shift */ #define XK_Caps_Lock 0xffe5 /* Caps lock */ #define XK_ISO_Lock 0xfe01
/usr/X11R6/lib/X11/xkb/symbols/pc/pc では,次のように modifier 名 が定義されています.
modifier_map modifier 名 { keysym 名の列挙 }; modifier_map Shift { Shift_L, Shift_R }; modifier_map Lock { Caps_Lock, ISO_Lock };
さらに /usr/X11R6/lib/X11/xkb/types/basic では,次のように修飾キーが効く対象とその効き方が定義されています.
このようにして,各々の修飾キーが各々のキーにどのように効くかが決まります.
(ここで type は各々のキーの属性であり,keysym から自動的に割り当てられるか,または /usr/X11R6/lib/X11/xkb/symbols/pc/pc にて規定します.)
type "TWO_LEVEL" { ← この type には (ここの例の場合はキー '1') modifiers = Shift; ← この modifier 名の修飾キーが効く. map[Shift] = Level2; ← Shift によって Level2 が選択される. level_name[Level1] = "Base"; level_name[Level2] = "Shift"; }; type "ALPHABETIC" { ← この type には (ここの例の場合はキー 'q') modifiers = Shift+Lock; ← この二つの modifier 名の修飾キーが効く. map[Shift] = Level2; ← Shift によって Level2 が選択される. map[Lock] = Level2; ← Lock によって Level2 が選択される. level_name[Level1] = "Base"; level_name[Level2] = "Caps"; };
/usr/X11R6/lib/X11/xkb/symbols/pc/us に戻れば,Level の後に続く数字は列挙された順番を指します.
key <AE01> { [ 1, exclam ] }; ← Shift すれば後者が選ばれる. key <AD01> { [ q, Q ] }; ← Shift または Lock すれば後者が選ばれる.
関数 XLookupString() は,keycode と修飾キーの状態とから,また必要な場合には環境変数 LANG も考慮し,それらに対応する keysym と ASCII 文字ストリングとを返してくれます.
1, 「X Window System の Server (/usr/X11R6/bin/XFree86, Xorg) が起動すると,キーボードは RAW モードになる」(すなわち「Server は keyboard scan code を受け取る」) と書いてある資料もありましたが,少なくとも XFree86, X.Org と PC-98, AT 互換機との組み合わせでは,受け取るのは system scan code の方です.
X Server を ports を利用して導入する場合,それらは /usr/ports/x11-servers/ の XFree86-4-Server または xorg-server にあります. そこで make をすると,work という directory が作成され,その中に source が展開されます. キーボードに関連するのはそこから辿って xc/programs/Xserver/hw/xfree86/common/ にある xf86Events.c や atKeynames.h などです. キーコードの変遷に注目して抜粋すると,次のようになります.
xf86PostKbdEvent(unsigned key) ← 変数 key は system scan code です. int scanCode = (key & 0x7f); ← 変数 scanCode は,キーを識別する部分です. ここで,特定のいくつかのキーの scanCode の値を変更します. keycode = scanCode + MIN_KEYCODE; ← keycode は scanCode に 8 を加えて得られます.
2, 設定に関連して次々と用語が登場するので,それらをなるべく変数名や設定ファイルの中で使われているキーワードを使って表わすようにしました. 次の表に用語の比較を示します.
この Home Page | XKB 関連の文書 | 日本語の書籍,雑誌記事 |
---|---|---|
scancode | scan code, raw keycodes reported by the device | スキャン・コード |
keycode | key code, keycode | キー・コード |
keycode 番号 | keycode number | キー・コード番号 |
keycode 名 | keycode symbolic name | |
keysym | キー・シンボル | |
keysym 値 | keysym value | keysym 値 |
keysym 名 | symbols symbolic name, keysym name | keysym 名 |
修飾キー | modifier | 修飾キー |
modifier 名 | modifier name | 修飾キー名,モデファイア名 |
ASCII 文字ストリング | actual symbol | ASCII 文字ストリング |
3, /usr/X11R6/lib/X11/xkb/types/basic では,type "ALPHABETIC" のために二つの修飾キーを同時に使った状態は定義されていません. 本来ならば,次のような定義を追加する必要があるでしょう. なぜこれなしに正常に動作しているのかは解りません. (どこかでちゃんと対処がなされているのですから,これをあえて加えない方が無難でしょう.)
map[Shift+Lock] = Level1;
4, /usr/X11R6/include/X11/keysymdef.h には,次のような文字や機能も定義されています.
#define XK_KP_0 0xffb0 ← Key Pad の '0' #define XK_F1 0xffbe ← Function Key の [F1] #define XK_kana_A 0x04b1 ← 半角カナの「ア」 #define XK_Cyrillic_YA 0x06f1 ← 1 byte キリル文字の "Я"
半角カナの「ア」の文字コードは 0xb1,KOI8-R の キリル文字の "Я" の文字コードは 0xf1 です. (環境変数 LANG として ISO8859-5 を設定した場合には,"Я" はその文字コードである 0xcf に変換されます.) このように,英字のアルファベットに相当する文字は,その文字コードに言語を識別するための 1 byte を付加して定義されています.
また,次のような文字や機能も定義されています.
#define XK_BackSpace 0xff08 /* Back space, back char */ #define XK_Tab 0xff09 #define XK_Return 0xff0d /* Return, enter */ #define XK_Delete 0xffff /* Delete, rubout */ #define XK_Left 0xff51 /* Move left, left arrow */ #define XK_Up 0xff52 /* Move up, up arrow */ #define XK_Right 0xff53 /* Move right, right arrow */ #define XK_Down 0xff54 /* Move down, down arrow */
Tab や Return は,それらの ASCII code に 0xff が付加された値です.
5. 自分で設定ファイルを追うことなしに現在の設定を確認したいならば,xev, xkbprint, xkbcomp -xkb, xmodmap -pk を活用します. 詳しくは 各種のツール を参照して下さい.
注意しなければならないのは,これらのツールの中でキーボードから実際に信号を受け取るのは xev だけだということです. 他のツールは,例え keycode 番号が違っていたとしてもそれを認識できず,設定ファイルに一貫性さえあればエラーになりません.
PC-98 用のキーボードに関しては,NEC や Borland C++ のマニュアルに記載されたキーボード BIOS に関する記述を参考にしました. 申し訳ありませんが,当方の手元にあるのは部分的なコピーなので,資料名はわかりません. これらに Windows Key に関する記載はありません. MS-DOS のキーボード BIOS ではこれらのキーは検知されないことは,実際にプログラムを作って確認しています.
1.2 節の AT 互換機用のキーボードの scan code に関しては,次の資料を参考にしました. ただし,OS は Linux や FreeDOS です. この記事に示された system scan code の値が一部のキーに対して keycodes の表と違うので要注意です. (FreeBSD の driver が keyboard controller から得られた値をいじっているのか?)
[1] 西田 亙「GCC プログラミング工房」 UNIX USER (ソフトバンク)
第 12 回「踊るキーボード LED」(2002.11)
第 13 回「FreeDOS でキーボードを探る」(2002.12)
第 14 回「指先からの旅」(2003.1)
第 15 回「キー入力処理を極める!」(2003.2)
3.2 節に関しては,次の書籍を参考にしました.
[2] 木下 凌一,林 秀幸「X-Window Ver.11 プログラミング (第 2 版)」 日刊工業新聞社 (1993)
[3] 砂原 秀樹 ら「プロフェッショナル BSD」pp.230-232, アスキー出版局 (1994)
設定ファイルの書式等,さらに詳細な情報は console におけるキーボード や X Window System におけるキーボード を参照して下さい.