Logo address

Raw モード

プログラミングの好きな人なら大抵最初に挑戦する「難問」が raw モードプログラミングである。UNIX の raw モードの実現は極めて難解であり、おまけにシステムに強く依存している。さらにタチの悪い事には途中でプログラムが転けると端末制御を失う。

Plan9 では次の様に /dev/consctl に "rawon". "rawoff" を書き込む事で行う。
rawon の効果は rawoff が書き込まれるか、あるいは fd が close されるまで有効で
ある。

うーん、巧いな。これだと下手なプログラムを書いて、raw モード実行中に転けても
絶対に端末のコントロールを失う事が無い!

#include <u.h>
#include <libc.h>

void
main(void){
	int fd;
	...
	fd = open("/dev/consctl",OWRITE);
	write(fd,"rawon",5);
	... /* raw mode here */
	...
	write(fd,"rawoff",6);
	... /* cooked mode here */
}

Plan9では raw mode が初等的なプログラミング課題になってしまったので、
早速役に立つプログラムを作りました。このプログラムはキーボードから
読み取った文字を 16進数で表示します。F1 - F12 などのファンクションキーを
打つと2文字分の出力を行います。終了するには '.' を打ちます。
(UNIXではこのようなプログラムを作るのはなかなか難しいのですよ)

#include <u.h>
#include <libc.h>
/*
 *  turn keyboard raw mode on
 */
void
rawon(void){
        int fd;
        fd = open("/dev/consctl", OWRITE);
        if(fd < 0){
                fprint(2, "can't open consctl\n");
                exits("consctl");
        }
        write(fd, "rawon", 5);
}

void
main(void){
        int n, i;
        uchar buf[128];
        rawon();
        do{
                n = read(0, buf, sizeof(buf));
                for(i = 0; i < n; i++) print("%.02x ",buf[i]);
        } while (buf[0] != '.');
}

Plan9 には read と readn の2つの読み取り関数があります。

	long read(int fd, void *buf, long nbytes)
	long readn(int fd, void *buf, long nbytes)
このうち、readn が UNIX の read に相当し、nbytes の文字の読み取りを待ちます。
read はファイルからの読み取りの場合には UNIX の read と同様に nbyte を待ちま
すが、コンソールからの読み取りでは 1 行単位に読み取ります。さらに raw mode
では基本的に1文字の読み取りを待っています。しかし1文字を読み取った時に、
続けて文字が来る可能性を考慮し、連続した文字を読み取ります。
何れも EOF で 0 を返します。

さて

	main()
	{
	...
	}
と書かないで
	main(){
	...
	}
と書くのは私が臍曲がりなだけです。でもこれは大した事はない。
でも
	print("%02x ",buf[i]);
と書かせないで
	print("%.02x ",buf[i]);
と書かせるのは、うーん、Bell-labo の人達もよほど臍曲がりなのか?
いやそうではなくて、
	print("%5.02x ",buf[i]);
あるいは
	print("%*.02x ",5,buf[i]);
と書くと5カラムで表示するのだそうです。
(ちなみに printf ではなく print としているのは、臍曲がりと言うのではなく
printf の UNICODE 拡張だからです)

補足 (1998/03/27)
キーコードを読む目的であれば、むしろ以下のプログラムの方が簡単でかつ完全です。
(先のプログラムは読めないキーが存在します)

#include <u.h>
#include <libc.h>

/*
 *  key: get key codes.
 */

main(){
	int n, i, fd;
	uchar buf[128];
	fprint(2,"Hit `q' to exit\n");
	fd = open("/dev/kbd", OREAD);
	do{
		n = read(fd, buf, sizeof(buf));
		for(i = 0; i < n; i++) print("%.02x ",buf[i]);
		print("\n");
	} while (buf[0] != 'q');
}