Greasemonkey Mouse Gestures

Just a Mouse Gestures script

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

Bạn sẽ cần cài đặt một tiện ích mở rộng như Tampermonkey hoặc Violentmonkey để cài đặt kịch bản này.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name               Greasemonkey Mouse Gestures
// @name:zh-CN         油猴鼠标手势
// @name:zh-TW         油猴滑鼠手勢
// @namespace          hoothin
// @version            0.70
// @description        Just a Mouse Gestures script
// @description:zh-CN  就是个鼠标手势脚本
// @description:zh-TW  就是個滑鼠手勢脚本
// @author             hoothin
// @include            *
// @grant              GM_openInTab
// @grant              GM_setValue
// @grant              GM_getValue
// @grant              GM_registerMenuCommand
// @grant              unsafeWindow
// @grant              GM_info
// @license            MIT License
// @compatible        chrome
// @compatible        firefox
// ==/UserScript==

var lastX,lastY,lastSign,afterGestures,gesturesWords,gesturesContent,gestures,signs;
const defaultFun={
    close:()=>{unsafeWindow.opener=null;unsafeWindow.open('', '_self', '');unsafeWindow.close();},
    openNew:()=>{GM_openInTab('about:newtab', false)},
    scrollToTop:()=>{unsafeWindow.scrollTo(0, 0)},
    scrollToBottom:()=>{unsafeWindow.scrollTo(0, 1073741824)},
    back:()=>{unsafeWindow.history.back()},
    forward:()=>{unsafeWindow.history.forward()},
    reload:()=>{unsafeWindow.location.reload()}
};
function initEventListener(start,move,end,tracer,clientX,clientY,startBool){
    var isMouse=start=="mousedown";
    var moveFun=function(e){
        tracer(clientX(e),clientY(e),isMouse);
        gesturesWords.innerHTML=signs;
        var gesturesWidth=signs.length*51+40;
        gesturesContent.style.width=gesturesWidth+"px";
        gesturesContent.style.marginLeft=-gesturesWidth/2+"px";
    };
    document.addEventListener(start, function(e) {
        if(!startBool || startBool(e)){
            lastX=clientX(e);
            lastY=clientY(e);
            lastSign=signs="";
            document.addEventListener(move, moveFun, false);
        }
    }, false);
    var endFun=function(e) {
        document.removeEventListener(move, moveFun, false);
        setTimeout(function(){if(gesturesContent.parentNode)gesturesContent.parentNode.removeChild(gesturesContent);},500);
        if(signs){
            if(afterGestures)afterGestures();
            for(var g of gestures){
                var gSign=g.gesture;
                if(signs==gSign){
                    if(!isMouse)document.body.appendChild(gesturesContent);
                    var fun=defaultFun[g.fun];
                    if(fun===undefined || !fun){
                        eval(g.fun);
                    }else {
                        fun();
                    }
                    e.stopPropagation();
                    e.preventDefault();
                    e.returnValue=false;
                    e.cancelBubble=true;
                    return false;
                }
            }
            signs="";
        }
    };
    document.addEventListener(end, endFun, false);
    document.addEventListener("mouseup", endFun, false);
}
(function() {
    'use strict';
    var i18n;
    var lang = navigator.appName=="Netscape"?navigator.language:navigator.userLanguage;
    const minLength=256,tg=0.5;
    switch (lang){
        case "zh-CN":
            i18n={
                close:"关闭页面",
                openNew:"新建标签页",
                scrollToTop:"滚动至最上",
                scrollToBottom:"滚动至最下",
                back:"后退",
                forward:"前进",
                reload:"刷新",
                addListener:"点击监听鼠标手势",
                listening:"正在监听鼠标手势",
                bind:"绑定功能",
                custom:"自定义代码",
                ok:"确定",
                del:"删除",
                saved:"已设定的手势",
                alert1:"请先监听手势",
                alert2:"还没有绑定功能",
                alert3:"请输入自定义代码",
                configure:"鼠标手势设置",
                update:"鼠标手势脚本已更新,是否覆盖脚本设置?"
            };
            break;
        default:
            i18n={
                close:"Close tab",
                openNew:"Open new tab",
                scrollToTop:"Scroll to top",
                scrollToBottom:"Scroll to bottom",
                back:"Back",
                forward:"Forward",
                reload:"Reload",
                addListener:"Click to add gesture listener",
                listening:"Listening",
                bind:"Bind function",
                custom:"Custom code",
                ok:"Ok",
                del:"Delete",
                saved:"Saved gestures",
                alert1:"Please add gesture first",
                alert2:"Nothing bind",
                alert3:"Input custom code please",
                configure:"Mouse Gestures - Configure",
                update:"Greasemonkey Mouse Gestures has updated, recover config?"
            };
            break;
    }
    gestures=GM_getValue("gestures");
    if(GM_info.script.version != GM_getValue("gmMouseGestureVersion")){
        if(!gestures || window.confirm(i18n.update))
            gestures=[{gesture:"↓→",fun:"close"},
                  {gesture:"→↑",fun:"openNew"},
                  {gesture:"←↑",fun:"scrollToTop"},
                  {gesture:"←↓",fun:"scrollToBottom"},
                  {gesture:"→↑←",fun:"back"},
                  {gesture:"←↑→",fun:"forward"},
                  {gesture:"↑↓",fun:"reload"},
                  {gesture:"↓↑↓",fun:"var t=((unsafeWindow.getSelection&&unsafeWindow.getSelection())||(document.getSelection&&document.getSelection())||(document.selection&&document.selection.createRange&&document.selection.createRange().text));var e=(document.charset||document.characterSet);if(t!=''){GM_openInTab('http://translate.google.cn/?text='+t+'&hl=zh-CN&langpair=auto|zh-CN&tbb=1&ie='+e,false);}else{GM_openInTab('http://translate.google.cn/translate?u='+encodeURIComponent(location.href)+'&hl=zh-CN&langpair=auto|zh-CN&tbb=1&ie='+e,false);}"},
                  {gesture:"↓↑↓←",fun:'var d=document,b=d.body;with(b.onselectstart=b.oncopy=b.onpaste=b.onkeydown=b.oncontextmenu=b.onmousemove=b.ondragstart=d.oncopy=d.onpaste=null,d.onselectstart=d.oncontextmenu=d.onmousedown=d.onkeydown=function(){return!0},d.wrappedJSObject||d)onmouseup=null,onmousedown=null,oncontextmenu=null;for(var a=d.getElementsByTagName("*"),i=a.length-1;i>=0;i--){var o=a[i];with(o.wrappedJSObject||o)onmouseup=null,onmousedown=null}var h=d.getElementsByTagName("head")[0];if(h){var s=d.createElement("style");s.innerHTML="html,*{user-select:text!important;-moz-user-select:text!important;-webkit-user-select:text!important;-webkit-user-drag:text!important;-khtml-user-select:text!important;-khtml-user-drag:text!important;pointer-events:auto!important;}",h.appendChild(s)}unsafeWindow.Event.prototype.preventDefault=function(){};'},
                  {gesture:"↓↑↓↑",fun:"var d = document, e = d.getElementById('wappalyzer-container') ; if ( e !== null ) { d.body.removeChild(e); } var u = 'https://wappalyzer.com/', t = new Date().getTime(), c = d.createElement('div'), p = d.createElement('div'), l = d.createElement('link'), s = d.createElement('script') ; c.setAttribute('id', 'wappalyzer-container'); l.setAttribute('rel', 'stylesheet'); l.setAttribute('href', u + 'css/bookmarklet.css'); d.head.appendChild(l); p.setAttribute('id', 'wappalyzer-pending'); p.setAttribute('style', 'background-image: url(' + u + 'images/spinner.gif) !important'); c.appendChild(p); s.setAttribute('src', u + 'bookmarklet/wappalyzer.js'); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'bookmarklet/apps.js'); s.onload = function() { s = d.createElement('script'); s.setAttribute('src', u + 'bookmarklet/driver.js'); c.appendChild(s); }; c.appendChild(s); }; c.appendChild(s); d.body.appendChild(c);"}
                 ];
        GM_setValue("gestures",gestures);
        GM_setValue("gmMouseGestureVersion",GM_info.script.version);
    }
    function tracer(curX,curY,showSign) {
        let distanceX=curX-lastX,distanceY=curY-lastY;
        let distance=distanceX*distanceX+distanceY*distanceY;
        if (distance>minLength) {
            lastX=curX;
            lastY=curY;
            let direction="";
            let slope=Math.abs(distanceY/distanceX);
            if(slope>tg){
                if(distanceY>0) {
                    direction="↓";
                }else{
                    direction="↑";
                }
            }else if(slope<=1/tg) {
                if(distanceX>0) {
                    direction="→";
                }else{
                    direction="←";
                }
            }
            if(lastSign!=direction) {
                signs+=direction;
                lastSign=direction;
                if(showSign)document.body.appendChild(gesturesContent);
            }
        }
    }
    gesturesContent=document.createElement("div");
    gesturesContent.id="gesturesContent";
    gesturesContent.style.cssText="width:300px;height:70px;position:fixed;left:50%;top:50%;margin-top:-25px;margin-left:-150px;z-index:999999999;background-color:#000;border:1px solid;border-radius:10px;opacity:0.65;filter:alpha(opacity=65);box-shadow:5px 5px 20px 0px #000;";
    gesturesContent.innerHTML='<div id="gesturesWords" style="position:absolute;left:20px;top:5px;font:bold 50px \'黑体\';color:#ffffff"></div>';
    gesturesWords=gesturesContent.querySelector("#gesturesWords");
    initEventListener("touchstart","touchmove","touchend",tracer,e=>{return e.changedTouches[0].clientX},e=>{return e.changedTouches[0].clientY});
    initEventListener("mousedown","mousemove","contextmenu",tracer,e=>{return e.clientX},e=>{return e.clientY},e=>{return e.which === 3});
    if(location.href=="https://github.com/hoothin/UserScripts/tree/master/Mouse%20Gestures"){
        var entryContent=document.querySelector("article.entry-content"),mobile=false;
        if(!entryContent){
            mobile=true;
            entryContent=document.querySelector(".files-list");
        }
        var configBody=document.createElement("div");
        configBody.id="configBody";
        configBody.style.cssText="opacity:0.65;filter:alpha(opacity=65);box-shadow:5px 5px 20px 0px #000;height:160px";
        configBody.innerHTML='<div id="configContent" style="position:relative;left:20px;top:5px;"></div>';
        var configContent=configBody.querySelector("#configContent");
        var newOrEdit=document.createElement("div");
        configContent.appendChild(newOrEdit);
        var newOrEditSign=document.createElement("div");
        newOrEditSign.innerHTML="";
        newOrEditSign.style.float="left";
        newOrEdit.appendChild(newOrEditSign);
        var newOrEditBtn=document.createElement("input");
        newOrEditBtn.type="button";
        newOrEditBtn.value=i18n.addListener;
        newOrEdit.appendChild(newOrEditBtn);
        var functionArea=document.createElement("p");
        newOrEdit.appendChild(functionArea);
        var functionSelect=document.createElement("select");
        functionSelect.innerHTML="<option>"+i18n.bind+"</option><option value='custom'>"+i18n.custom+"</option>";
        for(var key in defaultFun){
            var optionStr="<option value='"+key+"'>"+i18n[key]+"</option>";
            functionSelect.innerHTML+=optionStr;
        }
        functionArea.appendChild(functionSelect);
        var newOrEditEval=document.createElement("input");
        newOrEditEval.style.width=(mobile?"230":"750")+"px";
        newOrEditEval.style.display="none";
        functionArea.appendChild(newOrEditEval);
        var newOrEditOkBtn=document.createElement("input");
        newOrEditOkBtn.type="button";
        newOrEditOkBtn.value=i18n.ok;
        newOrEdit.appendChild(newOrEditOkBtn);
        var gesturesHas=document.createElement("p");
        newOrEdit.appendChild(gesturesHas);
        var gesturesSelect=document.createElement("select");
        var refreshGestures=function(){
            gesturesSelect.innerHTML="<option>"+i18n.saved+"</option>";
            gestures.forEach(function(item){
                var optionStr="<option value='"+item.gesture+"'>"+item.gesture+"</option>";
                gesturesSelect.innerHTML+=optionStr;
            });
        };
        refreshGestures();
        gesturesHas.appendChild(gesturesSelect);
        var newOrEditDelBtn=document.createElement("input");
        newOrEditDelBtn.type="button";
        newOrEditDelBtn.value=i18n.del;
        gesturesHas.appendChild(newOrEditDelBtn);
        entryContent.insertBefore(configBody,entryContent.firstChild);
        functionSelect.onchange=function(){
            if(functionSelect.options.selectedIndex===0)return;
            var value=functionSelect.options[functionSelect.options.selectedIndex].value;
            newOrEditEval.style.display=(value=="custom"?"initial":"none");
        };
        gesturesSelect.onchange=function(){
            if(gesturesSelect.options.selectedIndex===0)return;
            var value=gesturesSelect.options[gesturesSelect.options.selectedIndex].value;
            newOrEditSign.innerHTML=value;
            gestures.every(function(item){
                if(item.gesture==value){
                    functionSelect.options[1].selected = true;
                    for (var i=2;i<functionSelect.options.length;i++) {
                        if (functionSelect.options[i].value == item.fun) {
                            functionSelect.options[i].selected = true;
                            break;
                        }
                    }
                    functionSelect.onchange();
                    newOrEditEval.value=item.fun;
                    return false;
                }
                return true;
            });
        };
        newOrEditBtn.onclick=function(e){
            newOrEditBtn.value=i18n.listening;
            newOrEditBtn.setAttribute("disabled","disabled");
            afterGestures=function(){
                newOrEditBtn.removeAttribute("disabled");
                afterGestures=null;
                newOrEditSign.innerHTML=signs;
                newOrEditBtn.value=i18n.addListener;
            };
        };
        newOrEditOkBtn.onclick=function(e){
            if(!newOrEditSign.innerHTML){
                alert(i18n.alert1);
            }else if(functionSelect.options.selectedIndex===0){
                alert(i18n.alert2);
            }else {
                var op=functionSelect.options;
                var selIndex=op.selectedIndex;
                if(selIndex===1 && !newOrEditEval.value){
                    alert(i18n.alert3);
                }else{
                    var code=op[selIndex].value;
                    if(selIndex===1){
                        code=newOrEditEval.value;
                    }
                    for(var index in gestures){
                        if(gestures[index].gesture==newOrEditSign.innerHTML){
                            gestures.splice(index,1);
                            break;
                        }
                    }
                    gestures.push({gesture:newOrEditSign.innerHTML,fun:code});
                    GM_setValue("gestures",gestures);
                    refreshGestures();
                }
            }
        };
        newOrEditDelBtn.onclick=function(e){
            var value=gesturesSelect.options[gesturesSelect.options.selectedIndex].value;
            for(var index in gestures){
                if(gestures[index].gesture==value){
                    gestures.splice(index,1);
                    GM_setValue("gestures",gestures);
                    break;
                }
            }
            refreshGestures();
        };
    }
    function goSetting(){
        GM_openInTab("https://github.com/hoothin/UserScripts/tree/master/Mouse%20Gestures", false);
    }
    GM_registerMenuCommand(i18n.configure, goSetting);
})();