無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

キーバインド

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();
    }
}