/**
 * ちょうど{@link Ext.dom.Element}がネイティブのDOMノードをラップするように、{@link Ext.event.Event}は、ブラウザ間の差異を正規化する、ブラウザのネイティブのイベントオブジェクトをラップします。これは、デフォルトのアクションが入れ替わることを防止するためのメソッドを使って、イベントの伝播を停止させるのと同様の仕組みです。
 *
 * 以下は、使用方法の簡単な例です。
 *
 *     @example preview
 *     Ext.Viewport.add({
 *         layout: 'fit',
 *         items: [
 *             {
 *                 docked: 'top',
 *                 xtype: 'toolbar',
 *                 title: 'Ext.event.Event example!'
 *             },
 *             {
 *                 id: 'logger',
 *                 styleHtmlContent: true,
 *                 html: 'Tap somewhere!',
 *                 padding: 5
 *             }
 *         ]
 *     });
 *
 *     Ext.Viewport.element.on({
 *         tap: function(e, node) {
 *             var string = '';
 *
 *             string += 'You tapped at: <strong>{ x: ' + e.pageX + ', y: ' + e.pageY + ' }</strong> <i>(e.pageX & e.pageY)</i>';
 *             string += '<hr />';
 *             string += 'The HTMLElement you tapped has the className of: <strong>' + e.target.className + '</strong> <i>(e.target)</i>';
 *             string += '<hr />';
 *             string += 'The HTMLElement which has the listener has a className of: <strong>' + e.currentTarget.className + '</strong> <i>(e.currentTarget)</i>';
 *
 *             Ext.getCmp('logger').setHtml(string);
 *         }
 *     });
 *
 * ## レコグナイザー
 *
 * Sencha Touchには、デフォルトで、ユーザーがタップしたりスワイプしたりした際に、それを検知するイベントレコグナイザー一式が含まれています。
 *
 * デフォルトのレコグナイザーの全リストと、その詳細情報については、{@link Ext.event.gesture.Recognizer}マニュアルを参照してください。
 * 
 * このクラスでは、キーイベントで使用する一連の定数も提供します。これは、特定のキーが押されたか、またインスタンス上で使用でき、かつクラスの静的プロパティとしても使用可能かどうかを識別するのに便利です。次の2つの文は同じものです。
 * 
 *     if (e.getKey() === Ext.event.Event.TAB) {
 *         // tab key was pressed
 *     }
 * 
 *     if (e.getKey() === e.TAB) {
 *         // tab key was pressed
 *     }
 */
Ext.define('Ext.event.Event', {
    alternateClassName: 'Ext.EventObjectImpl',

    requires: [
        'Ext.util.Point'
    ],

    /**
     * @property {Number} distance
     * イベントの間隔。
     *
     * **これはイベントのタイプが`swipe`と`pinch`の場合にのみ使用可能です。**
     */

    /**
     * @property {HTMLElement} target
     * このイベントを発火する要素。現在処理中のハンドラを持つ要素、たとえばイベントハンドラが添付された要素には、`currentTarget`を使用します
     */

    /**
     * @property {HTMLElement} currentTarget
     * イベントハンドラが添付された要素`target`を参照します。これはイベントを発火した実際の要素です。たとえば、イベントがバブリングする場合、このイベントは`target`上でトリガーされ、その後操作が行われた`currentTarget`へとバブルアップされた可能性があるため、`target`要素は`currentTarget`の子孫であることがあります。
     */

    /**
     * @property {HTMLElement} delegatedTarget
     * `currentTarget`と同じです。
     * @deprecated 5.0.0では代わりに{@link #currentTarget}を使用します。
     */

    /**
     * @property {Number} pageX イベントのブラウザのx座標。注意:これはネイティブのブラウザイベントオブジェクトでpageXがサポートされているブラウザでのみ機能します(IE9以前では、pageXのネイティブサポートは行われていません)。Ext JSでは、クロスブラウザに対して正規化されたx座標で{@link #getX}を使用します。
     */

    /**
     * @property {Number} pageY イベントのブラウザのy座標。注意:これはネイティブのブラウザイベントオブジェクトでpageYがサポートされているブラウザでのみ機能します(IE9以前では、pageYのネイティブサポートは行われていません)。Ext JSでは、クロスブラウザに対して正規化されたy座標で{@link #getY}を使用します。
     */

    /**
     * @property {Boolean} ctrlKey
     * Ctrlキーがイベント中に押されていた場合は、true。Macでも、メタキーが押されていた場合は、trueになります。
     */
    /**
     * @property {Boolean} altKey
     * altキーがイベント中に押されていた場合はtrue。
     */
    /**
     * @property {Boolean} shiftKey
     * shiftキーがイベント中に押されていた場合はtrue。
     */

    /**
     * @property {Event} browserEvent
     * このオブジェクトによりラッピングされる生のブラウザイベント。
     */

    isStopped: false,

    isEvent: true,

    statics: {
        resolveTextNode: function(node) {
            return (node && node.nodeType === 3) ? node.parentNode : node;
        },

        // private
        pointerEvents: {
            pointerdown: 1,
            pointermove: 1,
            pointerup: 1,
            pointercancel: 1,
            pointerover: 1,
            pointerout: 1,
            pointerenter: 1,
            pointerleave: 1,
            MSPointerDown: 1,
            MSPointerMove: 1,
            MSPointerUp: 1,
            MSPointerOver: 1,
            MSPointerOut: 1,
            MSPointerCancel: 1,
            MSPointerEnter: 1,
            MSPointerLeave: 1
        },

        // private
        mouseEvents: {
            mousedown: 1,
            mousemove: 1,
            mouseup: 1,
            mouseover: 1,
            mouseout: 1,
            mouseenter: 1,
            mouseleave: 1
        },

        // private
        touchEvents: {
            touchstart: 1,
            touchmove: 1,
            touchend: 1,
            touchcancel: 1
        },
        
        // private
        focusEvents: {
            focus: 1,
            blur: 1,
            focusin: 1,
            focusout: 1,
            focusenter: 1,
            focusleave: 1
        },

        // msPointerTypes in IE10 are numbers, in the w3c spec they are strings.
        // this map allows us to normalize the pointerType for an event
        // http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
        // http://msdn.microsoft.com/en-us/library/ie/hh772359(v=vs.85).aspx
        pointerTypes: {
            2: 'touch',
            3: 'pen',
            4: 'mouse',
            touch: 'touch',
            pen: 'pen',
            mouse: 'mouse'
        }
    },

    constructor: function(event) {
        var me = this,
            self = me.self,
            resolveTextNode = me.self.resolveTextNode,
            changedTouches = event.changedTouches,
            // The target object from which to obtain the coordinates (pageX, pageY). For
            // mouse and pointer events this is simply the event object itself, but touch
            // events have their coordinates on the "Touch" object(s) instead.
            coordinateOwner = changedTouches ? changedTouches[0] : event,
            type = event.type,
            pointerType, relatedTarget;

        me.pageX = coordinateOwner.pageX;
        me.pageY = coordinateOwner.pageY;

        me.target = me.delegatedTarget = resolveTextNode(event.target);
        relatedTarget = event.relatedTarget;
        if (relatedTarget) {
            me.relatedTarget = resolveTextNode(relatedTarget);
        }

        me.browserEvent = me.event = event;
        me.type = type;
        // set button to 0 if undefined so that touchstart, touchend, and tap will quack
        // like left mouse button mousedown mouseup, and click
        me.button = event.button || 0;
        me.shiftKey = event.shiftKey;
        // mac metaKey behaves like ctrlKey
        me.ctrlKey = event.ctrlKey || event.metaKey || false;
        me.altKey = event.altKey;
        me.charCode = event.charCode;
        me.keyCode = event.keyCode;
        
        if (self.forwardTab !== undefined && self.focusEvents[type]) {
            me.forwardTab = self.forwardTab;
        }

        if (self.mouseEvents[type]) {
            pointerType = 'mouse';
        } else if (self.pointerEvents[type]) {
            pointerType = self.pointerTypes[event.pointerType];
        } else if (self.touchEvents[type]) {
            pointerType = 'touch';
        }

        if (pointerType) {
            me.pointerType = pointerType;
        }

        me.timeStamp = me.time = +(event.timeStamp || new Date());
    },

    /**
     * このイベントに対するプロトタイプチェーンを構成するイベントオブジェクトを作成します。同一のイベントを作成するのに役立ちます。これにより、特定のプロパティを元のイベントに影響を与えずに変更できます。たとえば、変換されたイベントではこの方法で「type」が変更されます。
     * @param {Object} props チェーン内のイベントにセットするプロパティ
     * @private
     */
    chain: function(props) {
        var e = Ext.Object.chain(this);
        e.parentEvent = this; // needed for stopPropagation
        return Ext.apply(e, props);
    },

    /**
     * 与えられたホイールのデルタの正しいスケール。
     * @param {Number} delta デルタ値。
     * @private
     */
    correctWheelDelta: function (delta) {
        var scale = this.WHEEL_SCALE,
            ret = Math.round(delta / scale);

        if (!ret && delta) {
            ret = (delta < 0) ? -1 : 1; // don't allow non-zero deltas to go to zero!
        }

        return ret;
    },

    /**
     * イベントの文字コードを取得します。
     * @return {Number}

     */
    getCharCode: function(){
        return this.charCode || this.keyCode;
    },

    /**
     * 正規化されたイベントのキーコードを返します。
     * @return {Number} キーコード
     */
    getKey: function(){
        return this.keyCode || this.charCode;
    },

    /**
     * オブジェクトの座標から構成されるポイントオブジェクトを返します。
     * @return {Ext.util.Point} ポイント
     */
    getPoint: function(){
        var xy = this.getXY();
        return new Ext.util.Point(xy[0], xy[1]);
    },

    /**
     * 関連ターゲットを取得します。
     * @param {String} [selector] ターゲットをフィルタリングする、またはターゲットの祖先を検索するためのシンプルなセレクタ。シンプルセレクタについては、{@link Ext.dom.Query}を参照してください。
     * @param {Number/HTMLElement} [maxDepth] 検索される最大の深さを数値または要素で指定(デフォルトは10またはdocument.body)。
     * @param {Boolean} [returnEl] `true`に設定すると、DOMノードの代わりにExt.Elementオブジェクトを返します。
     * @return {HTMLElement}

     */
    getRelatedTarget: function(selector, maxDepth, returnEl){
        var relatedTarget = this.relatedTarget,
            target = null;

        if (relatedTarget) {
            if (selector) {
                target = Ext.fly(relatedTarget).findParent(selector, maxDepth, returnEl);
            } else {
                target = returnEl ? Ext.get(relatedTarget) : relatedTarget;
            }
        }
        return target;
    },

    /**
     * イベントのターゲットを取得します。
     * @param {String} selector (optional) ターゲットをフィルタリングする、またはターゲットの祖先を検索するためのシンプルなセレクタ。
     * @param {Number/Mixed} [maxDepth=10||document.body] (optional) 検索される最大の深さを数値または要素で指定(デフォルトは10またはdocument.body)。
     * @param {Boolean} returnEl (optional) `true`に設定すると、DOMノードの代わりにExt.Elementオブジェクトを返します。
     * @return {HTMLElement}

     */
    getTarget: function(selector, maxDepth, returnEl) {
        return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) :
            (returnEl ? Ext.get(this.target) : this.target);
    },

    /**
     * イベントの時刻を返します。
     * @return {Date}

     */
    getTime: function() {
        return this.time;
    },

    /**
     * ブラウザ間でマウスホイールのyデルタを正規化します。xデルタの情報を取得する場合は、{@link #getWheelDeltas}を代わりに使用します。
     * @return {Number} マウスホイールのyデルタ
     */
    getWheelDelta: function(){
        var deltas = this.getWheelDeltas();

        return deltas.y;
    },

    /**
     * このイベントのマウスホイールのデルタを返します。
     * @return {Object} マウスホイールのデルタを保持する「x」プロパティと「y」プロパティを持つオブジェクト。
     */
    getWheelDeltas: function () {
        var me = this,
            event = me.browserEvent,
            dx = 0, dy = 0; // the deltas

        if (Ext.isDefined(event.wheelDeltaX)) { // WebKit has both dimensions
            dx = event.wheelDeltaX;
            dy = event.wheelDeltaY;
        } else if (event.wheelDelta) { // old WebKit and IE
            dy = event.wheelDelta;
        } else if (event.detail) { // Gecko
            dy = -event.detail; // gecko is backwards

            // Gecko sometimes returns really big values if the user changes settings to
            // scroll a whole page per scroll
            if (dy > 100) {
                dy = 3;
            } else if (dy < -100) {
                dy = -3;
            }

            // Firefox 3.1 adds an axis field to the event to indicate direction of
            // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
            if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
                dx = dy;
                dy = 0;
            }
        }

        return {
            x: me.correctWheelDelta(dx),
            y: me.correctWheelDelta(dy)
        };
    },

    /**
     * イベントのx座標を取得します。
     * @return {Number}

     */
    getX: function() {
        return this.getXY()[0];
    },

    /**
     * イベントのXとY座標を取得します。
     * @return {Number[]} [x, y]のようなxy値
     */
    getXY: function() {
        var me = this,
            xy = me.xy;

        if (!xy) {
            xy = me.xy = [me.pageX, me.pageY];
            //<feature legacyBrowser>
            var x = xy[0],
                browserEvent, doc, docEl, body;

            // pageX/pageY not available (undefined, not null), use clientX/clientY instead
            if (!x && x !== 0) {
                browserEvent = me.browserEvent;
                doc = document;
                docEl = doc.documentElement;
                body = doc.body;
                xy[0] = browserEvent.clientX +
                    (docEl && docEl.scrollLeft || body && body.scrollLeft || 0) -
                    (docEl && docEl.clientLeft || body && body.clientLeft || 0);
                xy[1] = browserEvent.clientY +
                    (docEl && docEl.scrollTop  || body && body.scrollTop  || 0) -
                    (docEl && docEl.clientTop  || body && body.clientTop  || 0);
            }
            //</feature>
        }

        return xy;
    },

    /**
     * イベントのy座標を取得します。
     * @return {Number}

     */
    getY: function() {
        return this.getXY()[1];
    },

   /**
    * このイベント中に、Ctrlキー、メタキー、Shiftキー、またはAitキーが押されていた場合、trueを返します。
    * @return {Boolean}

    */
    hasModifier: function() {
        var me = this;
        return !!(me.ctrlKey || me.altKey || me.shiftKey || me.metaKey);
    },

    /**
     * 「ナビゲーション」キーが押されたかをチェックします。ナビゲーションキーは以下のキーで定義されます。
     *
     *  - Page Up
     *  - Page Down
     *  - End
     *  - Home
     *  - Left
     *  - Up
     *  - Right
     *  - Down
     *  - Return
     *  - Tab
     *  - Esc
     *
     * @return {Boolean} ナビゲーションキーが押される場合は、`true`
     */
    isNavKeyPress: function(){
        var me = this,
            k = me.keyCode;

       return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
       k === me.RETURN ||
       k === me.TAB ||
       k === me.ESC;
    },

    /**
     * 「特殊」キーが押されたかをチェックします。特殊キーは以下のキーの1つとして定義されます。
     *
     *  - Page Up
     *  - Page Down
     *  - End
     *  - Home
     *  - Left arrow
     *  - Up arrow
     *  - Right arrow
     *  - Down arrow
     *  - Return
     *  - Tab
     *  - Esc
     *  - Backspace
     *  - Delete
     *  - Shift
     *  - Ctrl
     *  - Alt
     *  - Pause
     *  - Caps Lock
     *  - Print Screen
     *  - Insert
     *
     * @return {Boolean} specialキーが押される場合は、`true`
     */
    isSpecialKey: function(){
        var k = this.keyCode;
        return (this.type === 'keypress' && this.ctrlKey) ||
        this.isNavKeyPress() ||
        (k === this.BACKSPACE) || // Backspace
        (k >= 16 && k <= 20) ||   // Shift, Ctrl, Alt, Pause, Caps Lock
        (k >= 44 && k <= 46);     // Print Screen, Insert, Delete
    },

    makeUnpreventable: function() {
        this.browserEvent.preventDefault = Ext.emptyFn;
    },

    /**
     * ブラウザのデフォルトのイベント処理を防止します。
     * @chainable
     */
    preventDefault: function() {
        this.browserEvent.preventDefault();
        return this;
    },

    setCurrentTarget: function(target) {
        this.currentTarget = this.delegatedTarget = target;
    },

    /**
     * イベントを中止します(`{@link #preventDefault}`と`{@link #stopPropagation}`)。
     * @chainable
     */
    stopEvent: function() {
        return this.preventDefault().stopPropagation();
    },

    /**
     * イベントのバブリングをキャンセルします。
     * @chainable
     */
    stopPropagation: function() {
        var me = this,
            browserEvent = me.browserEvent,
            parentEvent = me.parentEvent;

        // Set isStopped for delegated event listeners.  Dom publisher will check this
        // property during its emulated propagation phase (see doPublish)
        me.isStopped = true;

        // if the event was created by prototype-chaining a new object to an existing event
        // instance, we need to make sure the parent event is stopped.  This feature most
        // likely comes into play when dealing with event translation.  For example on touch
        // browsers addListener('mousedown') actually attaches a 'touchstart' listener behind
        // the scenes.  When the 'touchstart' event is dispatched, the event system will
        // create a "chained" copy of the event object before correcting its type back to
        // 'mousedown' and calling the handler.  When propagating the event we look at the
        // original event, not the chained one to determine if propagation should continue,
        // so the isStopped property must be set on the parentEvent or stopPropagation
        // will not work.
        if (parentEvent) {
            parentEvent.isStopped = true;
        }

        //<feature legacyBrowser>
        if (!browserEvent.stopPropagation) {
            // IE < 10 does not have stopPropagation()
            browserEvent.cancelBubble = true;
            return me;
        }
        //</feature>

        // For non-delegated event listeners (those that are directly attached to the
        // DOM element) we need to call the browserEvent's stopPropagation() method.
        browserEvent.stopPropagation();

        return me;
    },

    /**
     * このイベントのターゲットが`el`の子要素である場合はtrueを返します。allowElパラメータが設定されない限り、ターゲットが`el`であってもfalseを返します。使用例:
     * 
     *     // Handle click on any child of an element
     *     Ext.getBody().on('click', function(e){
     *         if(e.within('some-el')){
     *             alert('Clicked on a child of some-el!');
     *         }
     *     });
     * 
     *     // Handle click directly on an element, ignoring clicks on child nodes
     *     Ext.getBody().on('click', function(e,t){
     *         if((t.id == 'some-el') && !e.within(t, true)){
     *             alert('Clicked directly on some-el!');
     *         }
     *     });
     * 
     * @param {String/HTMLElement/Ext.dom.Element} el チェックするid、DOM要素、またはExt.Element
     * @param {Boolean} [related] 関連するターゲットがそのターゲットの代わりにel内に存在している場合は、`true`
     * @param {Boolean} [allowEl] 渡された要素がターゲットまたは関連するターゲットであるかをチェックする場合も、`true`。
     * @return {Boolean}

     */
    within: function(el, related, allowEl){
        if (el) {
            var t = related ? this.getRelatedTarget() : this.getTarget();
        }

        return t ? Ext.fly(el).contains(t) || !!(allowEl && t === Ext.getDom(el)) : false;
    },

    deprecated: {
        '4.0': {
            methods: {

                /**
                 * イベントのx座標を取得します。
                 * @return {Number}

                 * @deprecated 4.0では代わりに{@link #getX}を使用します。
                 */
                getPageX: 'getX',
                
                /**
                 * イベントのy座標を取得します。
                 * @return {Number}

                 * @deprecated 4.0では代わりに{@link #getY}を使用します。
                 */
                getPageY: 'getY'
            }
        }
    }
}, function(Event) {
    var prototype = Event.prototype,
        constants = {
        /** Key constant @type Number */
        BACKSPACE: 8,
        /** Key constant @type Number */
        TAB: 9,
        /** Key constant @type Number */
        NUM_CENTER: 12,
        /** Key constant @type Number */
        ENTER: 13,
        /** Key constant @type Number */
        RETURN: 13,
        /** Key constant @type Number */
        SHIFT: 16,
        /** Key constant @type Number */
        CTRL: 17,
        /** Key constant @type Number */
        ALT: 18,
        /** Key constant @type Number */
        PAUSE: 19,
        /** Key constant @type Number */
        CAPS_LOCK: 20,
        /** Key constant @type Number */
        ESC: 27,
        /** Key constant @type Number */
        SPACE: 32,
        /** Key constant @type Number */
        PAGE_UP: 33,
        /** Key constant @type Number */
        PAGE_DOWN: 34,
        /** Key constant @type Number */
        END: 35,
        /** Key constant @type Number */
        HOME: 36,
        /** Key constant @type Number */
        LEFT: 37,
        /** Key constant @type Number */
        UP: 38,
        /** Key constant @type Number */
        RIGHT: 39,
        /** Key constant @type Number */
        DOWN: 40,
        /** Key constant @type Number */
        PRINT_SCREEN: 44,
        /** Key constant @type Number */
        INSERT: 45,
        /** Key constant @type Number */
        DELETE: 46,
        /** Key constant @type Number */
        ZERO: 48,
        /** Key constant @type Number */
        ONE: 49,
        /** Key constant @type Number */
        TWO: 50,
        /** Key constant @type Number */
        THREE: 51,
        /** Key constant @type Number */
        FOUR: 52,
        /** Key constant @type Number */
        FIVE: 53,
        /** Key constant @type Number */
        SIX: 54,
        /** Key constant @type Number */
        SEVEN: 55,
        /** Key constant @type Number */
        EIGHT: 56,
        /** Key constant @type Number */
        NINE: 57,
        /** Key constant @type Number */
        A: 65,
        /** Key constant @type Number */
        B: 66,
        /** Key constant @type Number */
        C: 67,
        /** Key constant @type Number */
        D: 68,
        /** Key constant @type Number */
        E: 69,
        /** Key constant @type Number */
        F: 70,
        /** Key constant @type Number */
        G: 71,
        /** Key constant @type Number */
        H: 72,
        /** Key constant @type Number */
        I: 73,
        /** Key constant @type Number */
        J: 74,
        /** Key constant @type Number */
        K: 75,
        /** Key constant @type Number */
        L: 76,
        /** Key constant @type Number */
        M: 77,
        /** Key constant @type Number */
        N: 78,
        /** Key constant @type Number */
        O: 79,
        /** Key constant @type Number */
        P: 80,
        /** Key constant @type Number */
        Q: 81,
        /** Key constant @type Number */
        R: 82,
        /** Key constant @type Number */
        S: 83,
        /** Key constant @type Number */
        T: 84,
        /** Key constant @type Number */
        U: 85,
        /** Key constant @type Number */
        V: 86,
        /** Key constant @type Number */
        W: 87,
        /** Key constant @type Number */
        X: 88,
        /** Key constant @type Number */
        Y: 89,
        /** Key constant @type Number */
        Z: 90,
        /** Key constant @type Number */
        CONTEXT_MENU: 93,
        /** Key constant @type Number */
        NUM_ZERO: 96,
        /** Key constant @type Number */
        NUM_ONE: 97,
        /** Key constant @type Number */
        NUM_TWO: 98,
        /** Key constant @type Number */
        NUM_THREE: 99,
        /** Key constant @type Number */
        NUM_FOUR: 100,
        /** Key constant @type Number */
        NUM_FIVE: 101,
        /** Key constant @type Number */
        NUM_SIX: 102,
        /** Key constant @type Number */
        NUM_SEVEN: 103,
        /** Key constant @type Number */
        NUM_EIGHT: 104,
        /** Key constant @type Number */
        NUM_NINE: 105,
        /** Key constant @type Number */
        NUM_MULTIPLY: 106,
        /** Key constant @type Number */
        NUM_PLUS: 107,
        /** Key constant @type Number */
        NUM_MINUS: 109,
        /** Key constant @type Number */
        NUM_PERIOD: 110,
        /** Key constant @type Number */
        NUM_DIVISION: 111,
        /** Key constant @type Number */
        F1: 112,
        /** Key constant @type Number */
        F2: 113,
        /** Key constant @type Number */
        F3: 114,
        /** Key constant @type Number */
        F4: 115,
        /** Key constant @type Number */
        F5: 116,
        /** Key constant @type Number */
        F6: 117,
        /** Key constant @type Number */
        F7: 118,
        /** Key constant @type Number */
        F8: 119,
        /** Key constant @type Number */
        F9: 120,
        /** Key constant @type Number */
        F10: 121,
        /** Key constant @type Number */
        F11: 122,
        /** Key constant @type Number */
        F12: 123,

        /**
         * マウスホイールのデルタ値を測定します。この値は、使用するブラウザやOSにより異なりますが、すべてのプラットフォームやブラウザを通して近い値になります。
         *
         * この値を変更するには、以下のように設定します。
         *
         *      Ext.event.Event.prototype.WHEEL_SCALE = 72;
         *
         * @type Number
         * @property
         */
        WHEEL_SCALE: (function () {
            var scale;

            if (Ext.isGecko) {
                // Firefox uses 3 on all platforms
                scale = 3;
            } else if (Ext.isMac) {
                // Continuous scrolling devices have momentum and produce much more scroll than
                // discrete devices on the same OS and browser. To make things exciting, Safari
                // (and not Chrome) changed from small values to 120 (like IE).

                if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
                    // Safari changed the scrolling factor to match IE (for details see
                    // https://bugs.webkit.org/show_bug.cgi?id=24368). The WebKit version where this
                    // change was introduced was 532.0
                    //      Detailed discussion:
                    //      https://bugs.webkit.org/show_bug.cgi?id=29601
                    //      http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
                    scale = 120;
                } else {
                    // MS optical wheel mouse produces multiples of 12 which is close enough
                    // to help tame the speed of the continuous mice...
                    scale = 12;
                }

                // Momentum scrolling produces very fast scrolling, so increase the scale factor
                // to help produce similar results cross platform. This could be even larger and
                // it would help those mice, but other mice would become almost unusable as a
                // result (since we cannot tell which device type is in use).
                scale *= 3;
            } else {
                // IE, Opera and other Windows browsers use 120.
                scale = 120;
            }

            return scale;
        }())
    };

    Ext.apply(Event, constants);
    Ext.apply(prototype, constants);

    /**
     * @private
     * RTL方向設定に関係なく、このイベントのXおよびYの位置を返します。
     */
    prototype.getTrueXY = prototype.getXY;
});