/** * A user script for userChrome.js extension. * @name Mouse Gestures * @description Lightweight customizable mouse gestures. * @compatibility Firefox 2.0 * @author Gomita * @lastupdated 2007.6.3 * @permalink http://www.xuldev.org/blog/?p=74 */ var ucjsMouseGestures = { _lastX: 0, _lastY: 0, _directionChain: "", init: function() { gBrowser.mPanelContainer.addEventListener("mousedown", this, false); gBrowser.mPanelContainer.addEventListener("mousemove", this, false); gBrowser.mPanelContainer.addEventListener("mouseup", this, false); gBrowser.mPanelContainer.addEventListener("contextmenu", this, true); }, uninit: function() { gBrowser.mPanelContainer.removeEventListener("mousedown", this, false); gBrowser.mPanelContainer.removeEventListener("mousemove", this, false); gBrowser.mPanelContainer.removeEventListener("mouseup", this, false); gBrowser.mPanelContainer.removeEventListener("contextmenu", this, true); }, _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); }, _startGesture: function(event) { this._lastX = event.screenX; this._lastY = event.screenY; this._directionChain = ""; }, _progressGesture: function(event) { var x = event.screenX; var y = event.screenY; var distanceX = Math.abs(x - this._lastX); var distanceY = Math.abs(y - this._lastY); // 認識する最小のマウスの動き const tolerance = 10; if (distanceX < tolerance && distanceY < tolerance) return; // 方向の決定 var direction; if (distanceX > distanceY) direction = x < this._lastX ? "L" : "R"; else direction = y < this._lastY ? "U" : "D"; // 前回の方向と比較 var lastDirection = this._directionChain.charAt(this._directionChain.length - 1); if (direction != lastDirection) { this._directionChain += direction; XULBrowserWindow.statusTextField.label = "Gesture: " + this._directionChain; } // 今回の位置を保存 this._lastX = x; this._lastY = y; }, _stopGesture: function(event) { try { if (this._directionChain) this._performAction(event); XULBrowserWindow.statusTextField.label = ""; } catch(ex) { XULBrowserWindow.statusTextField.label = ex; } this._directionChain = ""; }, _performAction: function(event) { // ここからがジェスチャへの機能割り当てです // 自由にカスタマイズしてください switch (this._directionChain) { // 戻る case "L": document.getElementById("Browser:Back").doCommand(); break; // 進む case "R": document.getElementById("Browser:Forward").doCommand(); break; // 更新 case "UD": document.getElementById("Browser:Reload").doCommand(); break; // キャッシュを無視して更新 case "UDU": document.getElementById("Browser:ReloadSkipCache").doCommand(); break; // ウィンドウを最小化 case "RUD": window.minimize(); break; // ウィンドウを最大化 または ウィンドウを元のサイズに戻す case "RDU": window.windowState == 1 ? window.restore() : window.maximize(); break; // 新しいタブを開く case "LR": document.getElementById("cmd_newNavigatorTab").doCommand(); break; // タブを閉じる case "DR": document.getElementById("cmd_close").doCommand(); break; // 閉じたタブを元に戻す case "DL": document.getElementById("History:UndoCloseTab").doCommand(); break; // 閉じたタブを元に戻す (Tab Mix Plus の セッションマネージャを使用している場合) // case "DL": gBrowser.undoRemoveTab(); break; // 前のタブへ case "UL": gBrowser.mTabContainer.advanceSelectedTab(-1, true); break; // 次のタブへ case "UR": gBrowser.mTabContainer.advanceSelectedTab(+1, true); break; // ページ先頭へスクロール case "LU": goDoCommand("cmd_scrollTop"); break; // ページ末尾へスクロール case "LD": goDoCommand("cmd_scrollBottom"); break; // ページアップ case "U": goDoCommand("cmd_scrollPageUp"); break; // ページダウン case "D": goDoCommand("cmd_scrollPageDown"); break; // 文字サイズを小さく case "LRD": document.getElementById("cmd_textZoomReduce").doCommand(); break; // 文字サイズを大きく case "LRU": document.getElementById("cmd_textZoomEnlarge").doCommand(); break; // 全画面表示 case "LDRU": document.getElementById("View:FullScreen").doCommand(); break; // 未定義のジェスチャ default: throw "Unknown Gesture: " + this._directionChain; } } }; // エントリポイント ucjsMouseGestures.init(); window.addEventListener("unload", function(){ ucjsMouseGestures.uninit(); }, false);