canvas で矢印キーを受け取るサンプル - フォーカスが当たっているときにキーの動作を奪ってページがスクロールしないように

canvas で矢印キーを受け取るサンプルです。矢印キーに対応して四角が動きます。

window.addEventListener('load', function() {
	var canvas = document.getElementById('game-screen');
	var x = 50, y = 50;
	var ctx = canvas.getContext('2d');
	var keyFlags = 0;
	setInterval(function(){
		if(keyFlags & 1) x -= 5;
		if(keyFlags & 2) y -= 5;
		if(keyFlags & 4) x += 5;
		if(keyFlags & 8) y += 5;
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.fillRect(x, y, 20, 20);
	}, 33);
	document.addEventListener('keydown', function(e) {
		var keyCode = e.keyCode;
		if(37 <= keyCode && keyCode <= 40) {
			keyFlags |= 1 << (keyCode - 37);
		}
	}, false);
	document.addEventListener('keyup', function(e) {
		var keyCode = e.keyCode;
		if(37 <= keyCode && keyCode <= 40) {
			keyFlags &= ~(1 << (keyCode - 37));
		}
	}, false);
}, false);

さて、これには問題があって...。上下キーを押したときにページがスクロールしてしまうんです。FlashJavaアプレットのようにフォーカスしていたらキーの動作を奪ってページがスクロールしてしまわないようにしたいので、方法を探ってみています。

追記 (2008-11-13T17:57:13+09:00)

iframe を作成してその中に canvas を突っ込んでみました。

Firefox では問題なく動作しますが、Safari, Google ChromeOpera では親ウィンドウがスクロールされてしまいます。また、なぜか Opera では表示されるのが 1 秒くらい遅くなってしまいます。

追記 (2008-11-13T18:46:40+09:00)

Safari, Google Chrome で親ウィンドウがスクロールされてしまう問題は、iframe内のdocumentのkeydownイベントでe.preventDefault();を実行し、iframe内のtextareaのkeydownイベントでe.stopPropagation();を実行することで解決しました。
Firefox で iframe 内のカーソルが progress になっていたのが気になっていたのですが、 doc.write(""); の後で doc.close(); を実行することで解決しました。
Opera で親ウィンドウがスクロールされてしまう問題と、なぜか表示が 1 秒くらい遅れる問題は未解決です。

追記 (2008-11-13T20:26:02+09:00)

Opera で表示が 1 秒くらい遅れる問題は、 doc.close(); を追加したことにより解決したみたいです。あとは Opera で親ウィンドウがスクロールされてしまう問題だけ。むー。

追記 (2008-11-13T21:29:46+09:00)

Opera で親ウィンドウがスクロールされてしまう問題も解決しました!
opera スクロール keydown preventDefault」みたいにググって以下の記事にたどりつきました。

両ブラウザで共通させるためには keypress を用いる。
document.addEventListener( 'keypress', function(e){
e.preventDefault();
}, false);

ultra blue:JavaScript : Opera と Firefox でのキーイベントの違い

ということで、keypressイベントでpreventDefaultを呼べばよかったようです。
これでOperaでも親ウィンドウがスクロールしないようになりました。