キーバインド
Miiで使っているキーバインドクラスを手直しして、PrototypeJSに依存しないようにした。使い方は次のような感じで、引数で「リスナを設定する要素」と「キー&処理のペア」を指定してnewするだけ。
// キーバインド // 第一引数で、キーとそれが押された場合の処理を指定する。 // 第二引数で、リスナの追加先要素を指定。 var k = new KeyBind( { "Space" : function() { document.getElementById("stdout").innerHTML += "Space!<br/>" }, "A" : function() { document.getElementById("stdout").innerHTML += "A!<br/>" }, "B" : function() { document.getElementById("stdout").innerHTML += "B!<br/>" }, "C" : function() { document.getElementById("stdout").innerHTML += "C!<br/>" }, // Shiftキーとか。 "C+Shift" : function() { document.getElementById("stdout").innerHTML += "C+Shift!<br/>" }, "C+Ctrl" : function() { document.getElementById("stdout").innerHTML += "C+Ctrl!<br/>" }, "C+Ctrl+Alt" : function() { document.getElementById("stdout").innerHTML += "C+Ctrl+Alt!<br/>" } }, document );
実装
次の通り。「e.onkeydown」とかはやっぱまずいかな。
/** * キーバインド * @param {Object} キーバインド * @param {Element} リスナを設定する要素 */ KeyBind = function ( binding, e ) { this.binding = binding; var thiz = this; e.onkeydown = function(ev) { thiz.handleKeyEvent(ev); } } KeyBind.prototype = { /** * キーイベントを処理する。 */ handleKeyEvent: function (e) { var keycode, modifier = ""; // Mozilla(Firefox, NN) and Opera if (e != null) { keycode = e.which; modifier = this.resolvModifier(e); // Internet Explorer } else { keycode = event.keyCode; modifier = this.resolvModifierIE(e); } // キーコードの文字を取得 var keyStr = this.resolvKeyChar(keycode); keyStr = keyStr + modifier; // 処理を実行 //log( "keyStr:" + keyStr ); if ( this.binding[keyStr] && typeof this.binding[keyStr] == "function" ) { this.binding[keyStr](); // イベントの上位伝播を防止 if (e != null) { e.preventDefault(); e.stopPropagation(); } else { event.returnValue = false; event.cancelBubble = true; } } }, /** * モディファイアを示す文字列を生成する。 * @param {Object} e イベント */ resolvModifier: function(e){ var str = "" if (this.isModified(e, "ctrlKey", Event.CONTROL_MASK)) { str = str + "+Ctrl"; } if (this.isModified(e, "shiftKey", Event.SHIFT_MASK)) { str = str + "+Shift"; } if (this.isModified(e, "altKey", Event.ALT_MASK)) { str = str + "+Alt"; } if (this.isModified(e, "metaKey", Event.META_MASK)) { str = str + "+Meta"; } return str; }, /** * モディファイアを示す文字列を生成する。IE用 * @param {Object} e イベント */ resolvModifierIE: function(e){ var str = "" if (event.ctrlKey) { str = str + "+Ctrl"; } if (event.shiftKey) { str = str + "+Shift"; } if (event.altKey) { str = str + "+Alt"; } if (event.metaKey) { str = str + "+Meta"; } return str; }, /** * モディファイアが押されているか評価する。 * @param {Object} e イベント * @param {Object} key フィールド名 * @param {Object} mask マスク */ isModified: function( e, key, mask ){ var m = false; if (e != null) { m = typeof e.modifiers == 'undefined' ? e[key] : e.modifiers & mask; } else { m = event[key]; } return m; }, /** * キー文字列を取得する。 */ resolvKeyChar: function (keycode) { switch( keycode ) { case 13: return "Enter"; case 27: return "Esc"; case 8: return "BackSpace"; case 9: return "Tab"; case 32: return "Space"; case 45: return "Insert"; case 46: return "Delete"; case 35: return "End"; case 36: return "Home"; case 33: return "PageUp"; case 34: return "PageDown"; case 38: return "↑"; case 40: return "↓"; case 37: return "←"; case 39: return "→"; } return String.fromCharCode(keycode).toUpperCase(); } }