Just a Mouse Gestures script
// ==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); })();