[userChrome.js] 軽量マウスジェスチャをWindows/Linuxに対応させる

通りすがりさんによるパッチをベースに、[userChrome.js] 軽量マウスジェスチャを Windows/Linux に対応させました。以下は今回修正した内容についてメモです。

以前はマウスジェスチャ中の状態遷移を数値型のフラグ _state を使って以下のように制御していた。

イベント _state フラグの変化 意味
mousedown 0 → 1 右クリック開始
mousemove (1のまま変化なし) 右クリックしたままマウス移動中
mouseup 1 → 2 ジェスチャ認識あり
1 → 3 ジェスチャ認識なし(マウスの移動量が微小)
contextmenu 2 → 0 コンテキストメニューの表示を抑止する
3 → 0 コンテキストメニューの表示を抑止しない

しかしながら、 Windows では上記のように mousedown→mousemove→mouseup→contextmenu という順序でイベントが発生するものの、 Linux では mousedown→contextmenu→mousemove→mouseup という順序で発生するため、制御がうまくいかなかった。そこで、数値型のフラグを廃止し、代わりに以下のような3つの真偽値フラグを使うようにした。

フラグ 意味
_isMouseDown 右クリックが押されているかどうか。
mousedown イベントで true になり、 mouseup イベントで false になる。
_suppressContext この後の contextmenu イベントを抑止するかどうか。
mouseup イベント発生時にジェスチャの認識があれば true にし、その後の contextmenu イベントを抑止する。
_shouldFireContext 後で contextmenu イベントを擬似的に発生させる必要があるかどうか。 Linux 専用。
Linux の場合は mousedown イベント直後に contextmenu イベントが発生するが、これを抑止した際にフラグを true にしておき、その後の mouseup イベント発生時にフラグが立っていれば擬似的に contextmenu を発生させる。

これによってスクリプトの一部は以下のように変更された。青色の部分が Linux 専用となる処理である。

    _isMouseDown: false,
    _suppressContext: false,
    _shouldFireContext: false,

    handleEvent: function(event)
    {
        switch (event.type) {
            case "mousedown": 
                // [1] ジェスチャ開始
                if (event.button == 2) {
                    this._isMouseDown = true;
                    this._startGesture(event);
                }
                break;
            case "mousemove": 
                // [2] ジェスチャ継続中
                if (this._isMouseDown) {
                    this._progressGesture(event);
                }
                break;
            case "mouseup": 
                // [3] ジェスチャ終了~アクション実行
                if (this._isMouseDown) {
                    this._isMouseDown = false;
                    this._suppressContext = !!this._directionChain;
                    this._stopGesture(event);
                    // [Linux] Win32を真似てmouseup後にcontextmenuを発生させる
                    if (this._shouldFireContext) {
                        this._shouldFireContext = false;
                        this._displayContextMenu(event);
                    }
                }
                break;
            case "contextmenu": 
                // [4-1] アクション実行後のコンテキストメニュー表示を抑止する
                // [4-2] 方向が認識されない微小な動きの場合は抑止しない
                // [Linux] mousedown直後のcontextmenuを抑止して...
                if (this._suppressContext || this._isMouseDown) {
                    this._suppressContext = false;
                    event.preventDefault();
                    event.stopPropagation();
                    // [Linux] ...代わりにmouseup後にcontextmenuを発生させる
                    if (this._isMouseDown) {
                        this._shouldFireContext = true;
                    }
                }
                break;
        }
    },

    _displayContextMenu: function(event)
    {
        var evt = event.originalTarget.ownerDocument.createEvent("MouseEvents");
        evt.initMouseEvent(
            "contextmenu", true, true, event.originalTarget.defaultView, 0,
            event.screenX, event.screenY, event.clientX, event.clientY,
            false, false, false, false, 2, null
        );
        event.originalTarget.dispatchEvent(evt);
    },

TOP

5 Comments to “[userChrome.js] 軽量マウスジェスチャをWindows/Linuxに対応させる”

Mac での動作確認ついでに、
Windows と同じく mousedown→mousemove→mouseup→contextmenu か、
Linux と同じく mousedown→contextmenu→mousemove→mouseup かを教えていただけると幸いです。

Mac は Linux と同じく mousedown→contextmenu→mousemove→mouseup のようです.

noriさん、ありがとうございました。

ロッカージェスチャーに対応してください><

ロッカージェスチャ機能追加を試みたのですが、残念ながら右クリックしながら連続左クリックで連続して戻る機能が実装できませんでした。右クリックしながら左クリック1回のみであれば可能ですが、それでも良いですか?

TOP

TOP