// ==UserScript== // @name 手机浏览器触摸手势 // @name:en Mobile browser touch gestures // @description 为手机浏览器添加触摸手势功能,例如↓↑回到顶部,↑↓回到底部,→←后退,←→前进,→↓关闭标签页,→↑恢复刚关闭的页面等。还有特殊的文字手势、图片手势和视频手势,还可自定义你的手势功能。推荐使用Kiwi浏览器、Yandex浏览器和火狐浏览器。 // @description:en Add touch gestures to mobile browsers. For example, ↓↑: go to the top, ↑↓: go to the bottom, →←: go back, ←→: go forward, →↓: closes the tab, →↑: restores just closed page, etc. There are also special text gestures, picture gestures and video gestures, and you can customize your gesture functions. Recommend using Kiwi browser, Yandex browser and Firefox browser. // @version 7.8.5 // @author L.Xavier // @namespace https://greasyfork.org/zh-CN/users/128493 // @match *://*/* // @license MIT // @grant GM_setValue // @grant GM_getValue // @grant window.close // @grant GM_openInTab // @grant GM_setClipboard // @grant GM_addValueChangeListener // @run-at document-body // @downloadURL none // ==/UserScript== // v7.8.5 2022-07-31 - 优化手势滑动识别方法 (async ()=>{ /*手势数据模块*/ let gesture={ '↑→↓←':'打开设置', '◆◆':'视频全屏', '●':'手势穿透', '→←':'后退', '←→':'前进', '↓↑':'回到顶部', '↑↓':'回到底部', '←↓':'刷新页面', '←↑':'新建页面', '→↓':'关闭页面', '→↑':'恢复页面', '↓↑●':'新页面打开', '↑↓●':'隐藏元素', '↑→':'复制页面', '→←→':'半屏模式', '→↓↑←':'视频解析', 'T→↑':'百度翻译', 'T←↑':'有道翻译', 'T◆◆':'双击搜索', 'I↓↑●':'打开图片', 'I→↑●':'百度搜图', 'V→':'前进10s', 'V←':'后退10s', 'V↑':'增加倍速', 'V↓':'减小倍速', 'V→●':'快进播放', 'V→○':'停止快进', 'V←●':'快退播放', 'V←○':'停止快退', 'V↑●':'增加音量', 'V↑○':'关闭增加音量', 'V↓●':'减少音量', 'V↓○':'关闭减少音量' }, pathFn={ '打开设置':'openSet();', '视频全屏':'videoFullScreen();', '手势穿透':'setTimeout(()=>{if(gestureData.touchEle.tagName=="IMG" && settings["图片手势"]){path="I";}else{path="";}});', '后退':'history.go(-1);gestureData.backTimer=setTimeout(()=>{window.close();},500);', '前进':'history.go(1);', '回到顶部':'let boxNode=gestureData.touchEle.parentNode;while(boxNode.nodeName!="#document"){boxNode.scrollTop=0;boxNode=boxNode.parentNode;}', '回到底部':'let boxNode=gestureData.touchEle.parentNode;while(boxNode.nodeName!="#document"){boxNode.scrollTop=boxNode.scrollHeight;boxNode=boxNode.parentNode;}', '刷新页面':'document.documentElement.style.cssText="filter:grayscale(100%)";history.go(0);', '新建页面':'GM_openInTab("https://limestart.cn");', '关闭页面':'window.close();', '恢复页面':'GM_openInTab("chrome-native://recent-tabs");', '新页面打开':'let linkNode=gestureData.touchEle;while(true){if(linkNode.href){GM_openInTab(linkNode.href);break;}linkNode=linkNode.parentNode;if(linkNode.nodeName=="#document"){gestureData.touchEle.click();break;}}', '隐藏元素':'gestureData.touchEle.style.display="none";', '复制页面':'GM_openInTab(location.href);', '半屏模式':'if(gestureData.halfScreen){setTimeout(()=>{gestureData.halfScreen.remove();halfClose.remove();gestureData.halfScreen=null;},500);let halfClose=addStyle("html{animation:halfClose 0.5s;}@keyframes halfClose{from{transform:translateY(43vh);}to{transform:translateY(0);}}");}else{gestureData.halfScreen=addStyle("html,body{height:50vh !important;overflow-x:hidden !important;}html{transform:translateY(43vh);animation:halfScreen 0.5s;}@keyframes halfScreen{from{transform:translateY(0);}to{transform:translateY(43vh);}}");}', '视频解析':'GM_openInTab("https://jx.parwix.com:4433/player/?url="+location.href);', '百度翻译':'GM_openInTab("https://fanyi.baidu.com/#auto/auto/"+gestureData.selectWords);', '有道翻译':'GM_openInTab("https://dict.youdao.com/w/eng/"+gestureData.selectWords);', '双击搜索':'GM_setClipboard(gestureData.selectWords);let regURL=/^(https?:\\/\\/)?([\\w\\-]+\\.)+\\w{2,4}(\\/\\S*)?$/;if(!regURL.test(gestureData.selectWords.replace(/\\s+$/,""))){gestureData.selectWords="https://bing.com/search?q="+encodeURIComponent(gestureData.selectWords);}else if(gestureData.selectWords.indexOf("http")<0){gestureData.selectWords="//"+gestureData.selectWords;}GM_openInTab(gestureData.selectWords);', '打开图片':'GM_openInTab(gestureData.touchEle.src);', '百度搜图':'GM_openInTab("https://graph.baidu.com/details?isfromtusoupc=1&tn=pc&carousel=0&promotion_name=pc_image_shituindex&extUiData%5bisLogoShow%5d=1&image="+gestureData.touchEle.src);', '前进10s':'videoPlayer.currentTime+=10;gestureData.tipBox.innerHTML="+10s ";gestureData.tipBox.style.display="block";setTimeout(()=>{gestureData.tipBox.style.display="none";},500);', '后退10s':'videoPlayer.currentTime-=10;gestureData.tipBox.innerHTML="-10s ";gestureData.tipBox.style.display="block";setTimeout(()=>{gestureData.tipBox.style.display="none";},500);', '增加倍速':'if(document.webkitIsFullScreen || document.mozFullScreen){let playSpeed=videoPlayer.playbackRate;playSpeed=(playSpeed<1.5) ? playSpeed+0.25 : playSpeed+0.5;gestureData.tipBox.innerHTML="x"+playSpeed+" ∞ ";gestureData.tipBox.style.display="block";videoPlayer.playbackRate=playSpeed;setTimeout(()=>{gestureData.tipBox.style.display="none";},500)}', '减小倍速':'if(document.webkitIsFullScreen || document.mozFullScreen){let playSpeed=videoPlayer.playbackRate;playSpeed=(playSpeed>1.5) ? playSpeed-0.5 : ((playSpeed>0.25) ? playSpeed-0.25 : 0.25);gestureData.tipBox.innerHTML="x"+playSpeed+" ∞ ";gestureData.tipBox.style.display="block";videoPlayer.playbackRate=playSpeed;setTimeout(()=>{gestureData.tipBox.style.display="none";},500)}', '快进播放':'gestureData.playSpeed=videoPlayer.playbackRate;videoPlayer.playbackRate=10;gestureData.tipBox.innerHTML="x10 ";gestureData.tipBox.style.display="block";', '停止快进':'videoPlayer.playbackRate=gestureData.playSpeed;gestureData.tipBox.style.display="none";', '快退播放':'gestureData.backTimer=setInterval(()=>{videoPlayer.currentTime-=1;},100);gestureData.tipBox.innerHTML="- x10 ";gestureData.tipBox.style.display="block";', '停止快退':'clearInterval(gestureData.backTimer);gestureData.tipBox.style.display="none";', '增加音量':'if(document.webkitIsFullScreen || document.mozFullScreen){gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";gestureData.tipBox.style.display="block";let lastY=gestureData.endY;gestureData.volumeTimer=setInterval(()=>{let tempVolume=videoPlayer.volume+(lastY-gestureData.endY)/100;videoPlayer.volume=(tempVolume>1) ? 1 : ((tempVolume<0) ? 0 : tempVolume);gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";lastY=gestureData.endY;},50);}', '关闭增加音量':'clearInterval(gestureData.volumeTimer);gestureData.tipBox.style.display="none";', '减少音量':'if(document.webkitIsFullScreen || document.mozFullScreen){gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";gestureData.tipBox.style.display="block";let lastY=gestureData.endY;gestureData.volumeTimer=setInterval(()=>{let tempVolume=videoPlayer.volume-(gestureData.endY-lastY)/100;videoPlayer.volume=(tempVolume>1) ? 1 : ((tempVolume<0) ? 0 : tempVolume);gestureData.tipBox.innerHTML=parseInt(videoPlayer.volume*100)+"%";lastY=gestureData.endY;},50);}', '关闭减少音量':'clearInterval(gestureData.volumeTimer);gestureData.tipBox.style.display="none";' }, settings={ '滑动距离':0.5, '文字手势':true, '图片手势':true, '视频手势':true }; //存储数据读取 gesture=await GM_getValue('gesture',gesture); pathFn=await GM_getValue('pathFn',pathFn); settings=await GM_getValue('settings',settings); //脚本常量 const gestureData={},limit=(((window.screen.width>window.screen.height) ? window.screen.height : window.screen.width)*(0.5*settings['滑动距离']+0.05))**2; /*手势功能模块*/ //手指滑动变量 let lastX=0,lastY=0,timeSpan=0,pressTime=0,raiseTime=0,slideTime=0,lastTime=0,lastSumXY=0,slideLimit=0,path='',fingersNum=0,gestureTimer=0,noClick=null,isFail=0; //修改Trusted-Types策略 if(window.isSecureContext && window.trustedTypes?.createPolicy){ let TTP={createHTML:string=>string,createScript:string=>string,createScriptURL:string=>string};//创建策略 window.trustedTypes.createPolicy('default',TTP); } //手势执行 async function runCode(runPath){ try{await eval(pathFn[gesture[runPath]]);} catch(error){ if(error.toString().indexOf('unsafe-eval')>-1){ if(!window.evalTool){ window.evalTool=(()=>{ let script=document.createElement('script'); function thisParams(){ this.window.close=window.close; this.GM_setValue=GM_setValue; this.GM_getValue=GM_getValue; this.GM_openInTab=GM_openInTab; this.GM_setClipboard=GM_setClipboard; this.runCode=runCode; this.runGesture=runGesture; this.videoFullScreen=videoFullScreen; this.findVideoBox=findVideoBox; this.addStyle=addStyle; this.openSet=openSet; this.gestureData=gestureData; this.path=path; this.videoPlayer=videoPlayer; } return (js)=>{ thisParams(); script.remove(); script=document.createElement('script'); script.appendChild(document.createTextNode('try{'+js+'}catch(error){alert("“"+path+"” 手势执行脚本错误:\\n"+error+" !");}')); document.body.appendChild(script); } })(); window.evalTool('window.addEventListener("popstate",()=>{clearTimeout(gestureData.backTimer);});window.addEventListener("beforeunload",()=>{clearTimeout(gestureData.backTimer);});'); } window.evalTool(pathFn[gesture[runPath]]); } else{alert('“'+runPath+'” 手势执行脚本错误:\n'+error+' !');} } } async function runGesture(pathStr=''){ let nowSelect=await window.getSelection().toString(); if(nowSelect && gestureData.selectWords!=nowSelect){path='';return;} let firstMark=path.slice(0,1); if(gesture[path]){ if(top.location==location || 'TIV'.indexOfNull(firstMark)>-1){runCode(path);} else{await GM_setValue('gestureIfr',path);} path=pathStr; }else if(gesture[path.slice(1)] && 'TIV'.indexOfNull(firstMark)>-1){ if(top.location==location){runCode(path.slice(1));} else{await GM_setValue('gestureIfr',path.slice(1));} path=pathStr; } } //手指按下 async function touchStart(e){ clearTimeout(gestureTimer); let lastIcon=path.slice(-1);if(lastIcon=='○'){runGesture();} fingersNum=e.touches.length;if(fingersNum>1){return;} let nowTime=Date.now();timeSpan=nowTime-raiseTime; let calcX=(e.changedTouches[0].screenX-gestureData.endX)**2,calcY=(e.changedTouches[0].screenY-gestureData.endY)**2,sumXY=calcX+calcY; if(timeSpan>50 || sumXY>2500){//断触判断 pressTime=slideTime=nowTime; lastX=gestureData.startX=e.changedTouches[0].screenX;lastY=gestureData.startY=e.changedTouches[0].screenY; if(timeSpan>200 || sumXY>10000){ path='';slideLimit=limit;gestureData.touchEle=e.srcElement; gestureData.selectWords=await window.getSelection().toString(); if(gestureData.selectWords && settings['文字手势']){path='T';} else if(videoPlayer && settings['视频手势']){ let touchX=e.changedTouches[0].clientX,touchY=e.changedTouches[0].clientY, videoRect=videoPlayer.getBoundingClientRect(); let offsetX=0,offsetY=0;if(document.webkitIsFullScreen || document.mozFullScreen){offsetX=videoRect.x;offsetY=videoRect.y-30;} if(touchX>(videoRect.x-offsetX) && touchX<(videoRect.x+videoRect.width+offsetX) && touchY>(videoRect.y-offsetY) && touchY<(videoRect.y+videoRect.height+offsetY)){path='V';} } if(noClick){noClick.remove();noClick=null;} } }else if(lastIcon=='◆'){path=path.slice(0,-1);} gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(path.slice(-1))<0){let _path=path;path+='●';if(gesture[_path+'○']){_path+='○';}else{_path+='●';}runGesture(_path);slideTime=Date.now();}},(400+slideTime-nowTime)); } //手指滑动 function touchMove(e){ let nowTime=Date.now(); if(fingersNum>1 || (nowTime-lastTime)<16){return;} clearTimeout(gestureTimer); gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY; let calcX=(gestureData.endX-lastX)**2,calcY=(gestureData.endY-lastY)**2, sumXY=calcX+calcY,lastIcon=path.slice(-1), diffXY=(sumXY>lastSumXY) ? sumXY-lastSumXY : lastSumXY-sumXY; lastTime=nowTime;lastSumXY=sumXY; if(diffXY>80 && lastIcon!='○'){ isFail=1;slideTime=nowTime; let direction=(calcX>calcY) ? ((gestureData.endX>lastX) ? '→' : '←') : ((gestureData.endY>lastY) ? '↓' : '↑'); if(lastIcon==direction || sumXY>slideLimit){ if(lastIcon!=direction && (timeSpan>200 || timeSpan<80 || '↑→↓←'.indexOfNull(lastIcon)<0)){path+=direction;slideLimit=limit/(1+settings['滑动距离']);} lastX=gestureData.endX;lastY=gestureData.endY; isFail=0;lastSumXY=0; } } gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(path.slice(-1))<0){isFail=0;let _path=path;path+='●';if(gesture[_path+'○']){_path+='○';}else{_path+='●';}runGesture(_path);slideTime=Date.now();}},(400+slideTime-nowTime)); } //手指抬起 function touchEnd(e){ clearTimeout(gestureTimer); if(fingersNum>1 || isFail){isFail=0;return;} gestureTimer=setTimeout(runGesture,200); raiseTime=Date.now(); gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY; let calcX=(gestureData.endX-gestureData.startX)**2,calcY=(gestureData.endY-gestureData.startY)**2; if((raiseTime-pressTime)<200 && (calcX+calcY)<100 && path.slice(-1)!='○'){path+='◆';} if(path=='V◆◆'){e.stopPropagation();e.preventDefault();} if(window.getSelection().toString() && !noClick){noClick=addStyle('*{pointer-events:none;}');} setTimeout(videoEvent); } //手势事件注册 window.addEventListener('touchstart',touchStart,{capture:true,passive:true}); window.addEventListener('touchmove',touchMove,{capture:true,passive:true}); window.addEventListener('touchend',touchEnd,true); /*视频功能模块*/ //video标签变量 let videoEle=document.getElementsByTagName('video'),_videoEle=[],videoPlayer=null,oriType='portrait-primary',lockOriType='landscape-primary',isLock=0; //video判定 function setVideo(){videoPlayer=this;videoOriLock();} async function videoOriLock(){ if(!videoPlayer.videoWidth){setTimeout(videoOriLock,100);return;} if(videoPlayer.parentNode.clientHeight<1){addStyle('.tipBox_parent{height:100%};');videoPlayer.parentNode.classList.add('tipBox_parent');} videoPlayer.parentNode.appendChild(gestureData.tipBox); if(videoPlayer.videoWidth>videoPlayer.videoHeight){isLock=1;} else{isLock=0;await screen.orientation.unlock();} if(top.location!=location){window.isShow=1;await GM_setValue('isLock',isLock);} } async function videoFullScreen(){ if(document.webkitIsFullScreen){await document.webkitExitFullscreen();} else if(document.mozFullScreen){await document.mozCancelFullScreen();} else if(videoPlayer){ GM_setClipboard(videoPlayer.src); if(videoPlayer.webkitRequestFullscreen){await findVideoBox().webkitRequestFullscreen();} else if(videoPlayer.mozRequestFullScreen){await findVideoBox().mozRequestFullScreen();} }else if(iframeEle.length){await GM_setValue('fullscreen',Date());} } //获取video全屏样式容器 function findVideoBox(){ if(!videoPlayer?.parentNode){return videoPlayer;} let videoBox=videoPlayer.parentNode, _videoBox=videoBox, parentEle=videoBox.parentNode, videoWidth=Math.round(parseFloat(getComputedStyle(videoPlayer).width)), videoHeight=Math.round(parseFloat(getComputedStyle(videoPlayer).height)), parentWidth=Math.round(parseFloat(getComputedStyle(parentEle).width)), parentHeight=Math.round(parseFloat(getComputedStyle(parentEle).height)), childWidth=Math.round(videoBox.offsetWidth+parseFloat(getComputedStyle(videoBox).marginLeft)+parseFloat(getComputedStyle(videoBox).marginRight)), childHeight=Math.round(videoBox.offsetHeight+parseFloat(getComputedStyle(videoBox).marginTop)+parseFloat(getComputedStyle(videoBox).marginBottom)) || Math.round(videoPlayer.offsetHeight+parseFloat(getComputedStyle(videoPlayer).marginTop)+parseFloat(getComputedStyle(videoPlayer).marginBottom)); while(parentWidth>=videoWidth && parentHeight>=videoHeight && childWidth==parentEle.clientWidth && childHeight==parentEle.clientHeight && parentEle.nodeName!='BODY'){ _videoBox=videoBox;videoBox=parentEle; childWidth=Math.round(parentEle.offsetWidth+parseFloat(getComputedStyle(parentEle).marginLeft)+parseFloat(getComputedStyle(parentEle).marginRight)); childHeight=Math.round(parentEle.offsetHeight+parseFloat(getComputedStyle(parentEle).marginTop)+parseFloat(getComputedStyle(parentEle).marginBottom)) || childHeight; parentEle=parentEle.parentNode; parentWidth=Math.round(parseFloat(getComputedStyle(parentEle).width)); parentHeight=Math.round(parseFloat(getComputedStyle(parentEle).height)) || parentHeight; } if(!Math.round(parseFloat(getComputedStyle(videoBox).height))){videoBox=_videoBox;} return videoBox; } //video标签事件绑定 function videoEvent(){ if(_videoEle.length && videoEle.length<=_videoEle.length){ for(let Ti=0,len=_videoEle.length;Ti_videoEle.length){ if(!_videoEle.length){ //重力感应事件 if(regGYRO){regGYRO();regGYRO=null;} //tip操作提示 gestureData.tipBox=document.createElement('div'); gestureData.tipBox.style.cssText='width:100px;height:50px;position:absolute;text-align:center;top:calc(50% - 25px);left:calc(50% - 50px);display:none;color:#1e87f0;font-size:24px;line-height:50px;background-color:#fff;border-radius:20px;font-family:"Microsoft YaHei" !important;z-index:2147483647;'; //视频方向锁定 document.addEventListener('webkitfullscreenchange',()=>{ if(document.webkitIsFullScreen){videoOriLock();if(isLock && oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);}} else{oriType='portrait-primary';} }); document.addEventListener('mozfullscreenchange',()=>{ if(document.mozFullScreen){videoOriLock();if(isLock && oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);}} else{oriType='portrait-primary';} }); } //播放video标签查找 for(let Ti=_videoEle.length,len=videoEle.length;Ti{ let runTime=0; window.addEventListener('deviceorientation',(e)=>{ let nowTime=Date.now(); if(document.hidden || (nowTime-runTime)<100){return;} if(isLock){ let oriHgamma=e.gamma, oriHbeta=(e.beta>0) ? e.beta : -e.beta; if((oriHbeta<60 || oriHbeta>120) && (oriHgamma<-30 || oriHgamma>30)){ lockOriType=((oriHbeta<60 && oriHgamma<-30) || (oriHbeta>120 && oriHgamma>30)) ? 'landscape-primary' : 'landscape-secondary'; } if(document.webkitIsFullScreen || document.mozFullScreen){if(oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);}} else{oriType='portrait-primary';} } runTime=nowTime; }); } /*工具方法模块*/ String.prototype.indexOfNull=function(str=null){if(str){return this.indexOf(str);}return -1;} function addStyle(css){ let style=document.createElement('style'); style.appendChild(document.createTextNode(css)); document.head.appendChild(style); return style; } //手势操作设置UI function openSet(){ let gestureName='',gesturePath='',clickTime=0,clickTimer=0; //页面生成 addStyle('html{font-size:62.5% !important;}body{height:100% !important;overflow:hidden !important;}'+ '#gestureBox{background-color:#fff;width:100%;height:100%;position:fixed;padding:0;margin:0;top:0;left:0;overflow-y:auto;overflow-x:hidden;z-index:999990;}'+ '#gestureBox *{font-family:"Microsoft YaHei" !important;margin:0;padding:0;text-align:center;font-size:2rem;line-height:4rem;overflow:initial;user-select:none !important;}'+ '#gestureBox ::placeholder{color:#999;font-size:1rem;line-height:2rem;}'+ '#gestureBox h1{width:60%;height:4rem;color:#0074d9;background-color:#dee6ef;margin:1rem auto;border-radius:4rem;box-shadow:0.3rem 0.3rem 1rem #dfdfdf;}'+ '#gestureBox #addGesture{width:5rem;height:5rem;margin:1rem auto;line-height:4.8rem;background-color:#dee6ef;color:#032e58;font-size:3rem;border-radius:5rem;box-shadow:0.1rem 0.1rem 0.5rem #dfdfdf;}'+ '#gestureBox .gestureLi{height:6rem;width:100%;border-bottom:0.3rem dashed #dfdfdf;}'+ '#gestureBox .gestureLi p{margin:1rem 0 0 1%;width:38%;height:4rem;border-left:0.6rem solid;color:#ffb400;background-color:#fff1cf;float:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:0.1rem 0.1rem 1rem #ffcb56;}'+ '#gestureBox .gestureLi .gesturePath{margin:1rem 0 0 3%;float:left;width:38%;height:4rem;background-color:#f3f3f3;color:#000;box-shadow:0.1rem 0.1rem 0.5rem #ccc9c9;border-radius:1rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}'+ '#gestureBox .gestureLi .delGesture{margin:1rem 2% 0 0;width:5rem;height:4rem;float:right;color:#f00;text-decoration:line-through;}'+ '#gestureBox #revisePath{background-color:rgba(0,0,0,0.5);width:100%;height:100%;position:fixed;top:0;left:0;overflow:hidden;z-index:999991;display:none;color:#000;}'+ '#gestureBox #revisePath span{width:5rem;height:5rem;font-size:5rem;line-height:5rem;position:absolute;}'+ '#gestureBox #revisePath div{color:#3339f9;position:absolute;width:30%;height:4rem;font-size:4rem;bottom:15%;}'+ '#gestureBox #revisePath p{color:#3ba5d8;position:absolute;top:15%;font-size:4rem;height:4rem;width:100%;}'+ '#gestureBox #revisePath #path{top:40%;color:#ffee03;height:100%;word-wrap:break-word;font-size:6rem;line-height:6rem;}'+ '#gestureBox #editGesture{background-color:#fff;width:100%;height:100%;position:fixed;top:0;left:0;overflow:hidden;z-index:999991;display:none;color:#000;}'+ '#gestureBox #editGesture p{color:#3339f9;font-size:3rem;text-align:left;margin:3rem 0 0 3rem;width:100%;height:3rem;line-height:3rem;}'+ '#gestureBox #editGesture #gestureName{margin-top:2rem;width:80%;height:4rem;color:#000;border:0.1rem solid #dadada;border-radius:1rem;text-align:left;padding:0 1rem;}'+ '#gestureBox #editGesture .label_box>label{display:inline-block;margin-top:2rem;position:relative;overflow:hidden;}'+ '#gestureBox #editGesture .label_box>label>input{position:absolute;top:0;left:-2rem;}'+ '#gestureBox #editGesture .label_box>label>div{width:8rem;border:#ddd solid 1px;height:4rem;color:#666;overflow:hidden;position:relative;}'+ '#gestureBox #editGesture .label_box>label>input:checked + div{border:#d51917 solid 1px;color:#d51917;}'+ '#gestureBox #editGesture .label_box>label>input:checked + div:after{content:"";display:block;width:2rem;height:2rem;background-color:#d51917;transform:skewY(-45deg);position:absolute;bottom:-1rem;right:0;z-index:999992;}'+ '#gestureBox #editGesture .label_box>label>input:checked + div:before{content:"";display:block;width:3px;height:8px;border-right:#fff solid 2px;border-bottom:#fff solid 2px;transform:rotate(35deg);position:absolute;bottom:2px;right:4px;z-index:999993;}'+ '#gestureBox #editGesture #pathFn{width:80%;margin-top:2rem;height:40%;text-align:left;line-height:2.2rem;padding:1rem;border:0.1rem solid #dadada;border-radius:1rem;}'+ '#gestureBox #editGesture button{width:10rem;height:5rem;font-size:3rem;line-height:5rem;display:inline-block;color:#fff;background-color:#2866bd;margin:3rem 1rem 0rem 1rem;border:none;}'+ '#gestureBox #settingsBox{background-color:#fff;width:100%;height:100%;position:fixed;top:0;left:0;overflow:hidden;z-index:999991;display:none;color:#000;}'+ '#gestureBox #settingsBox p{color:#3339f9;text-align:left;margin:3rem 0 0 3rem;float:left;height:2rem;line-height:2rem;clear:both;}'+ '#gestureBox #settingsBox .slideRail{width:20rem;background-color:#a8a8a8;float:left;margin:4rem 0 0 1rem;height:0.2rem;position:relative;}'+ '#gestureBox #settingsBox .slideRail .slideButton{line-height:3rem;color:#fff;background-color:#2196f3;width:3rem;height:3rem;border-radius:3rem;font-size:1.5rem;position:absolute;top:-1.5rem;left:-15px;box-shadow:1px 1px 6px #5e8aee;}'+ '#gestureBox #settingsBox .switch{position:relative;display:inline-block;width:6rem;height:3rem;float:left;margin:2.5rem 42% 0 1rem;}'+ '#gestureBox #settingsBox .switch input{display:none;}'+ '#gestureBox #settingsBox .slider{border-radius:3rem;position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:0.4s;}'+ '#gestureBox #settingsBox .slider:before{border-radius:50%;position:absolute;content:"";height:2.6rem;width:2.6rem;left:0.2rem;bottom:0.2rem;background-color:white;transition:0.4s;}'+ '#gestureBox #settingsBox input:checked + .slider{background-color:#2196F3;}'+ '#gestureBox #settingsBox input:checked + .slider:before{transform:translateX(3rem);}'+ '#gestureBox #settingsBox #saveSettings{display:block;clear:both;width:10rem;height:5rem;font-size:3rem;line-height:5rem;color:#fff;background-color:#2866bd;border:none;margin:4rem 0 0 calc(50% - 5rem);float:left;}'); let gestureBox=document.createElement('div'); gestureBox.id='gestureBox'; document.body.appendChild(gestureBox); gestureBox.innerHTML='

手势轨迹设置

+
'+ '
'+ '

请滑动手指

Clear
Cancle
'+ '

手势名称:

'+ '

手势类型:

'+ '

手势执行脚本:

'+ '
'+ '

功能开关设置

'; let pathEle=document.getElementById('path'); //编辑手势 function editGesture(){ gestureName=this.parentNode.getAttribute('name'); if(['打开设置','视频全屏','手势穿透'].indexOf(gestureName)>-1){alert('该手势脚本无法修改!');return;} gesturePath=this.parentNode.getAttribute('path'); let selectType=('TIV'.indexOfNull(gesturePath.slice(0,1))>-1) ? gesturePath.slice(0,1) : 'GG'; document.getElementById(selectType).click(); document.getElementById('gestureName').value=gestureName; document.getElementById('pathFn').value=pathFn[gestureName]; document.getElementById('editGesture').style.display='block'; } //修改路径 function revisePath(){ gestureName=this.parentNode.getAttribute('name'); gesturePath=this.parentNode.getAttribute('path'); pathEle.innerHTML=''; window.removeEventListener('touchmove',touchMove,true); window.removeEventListener('touchend',touchEnd,true); gestureBox.style.cssText='overflow:hidden;'; document.getElementById('revisePath').style.display='block'; } //删除手势 function delGesture(){ gestureName=this.parentNode.getAttribute('name'); if(['打开设置','视频全屏','手势穿透'].indexOf(gestureName)>-1){alert('该手势无法删除!');return;} gesturePath=this.parentNode.getAttribute('path'); delete pathFn[gestureName]; delete gesture[gesturePath]; GM_setValue('pathFn',pathFn); GM_setValue('gesture',gesture); init(); } //滑动条 function silideBar(e){ if(fingersNum>1){return;}path=''; let endX=e.changedTouches[0].screenX, diffX=endX-lastX, leftPX=parseFloat(this.style.left)+diffX; if(leftPX>=-15 && leftPX<=(this.parentNode.offsetWidth-15)){ this.style.left=leftPX+'px'; leftPX=(leftPX+15)/this.parentNode.offsetWidth; this.innerHTML=leftPX.toFixed(1); lastX=endX; } } //界面初始化 function init(){ document.getElementById('gestureUL').innerHTML=''; for(gestureName in pathFn){ gesturePath=''; for(let Ti in gesture){ if(gesture[Ti]==gestureName){gesturePath=Ti;break;} } document.getElementById('gestureUL').innerHTML+='

'+gestureName+'

'+gesturePath+'
删除
'; } //操作绑定 let gestureEle=document.querySelectorAll('#gestureBox .gestureLi p'); for(let Ti=0,len=gestureEle.length;Ti{ gestureName=gesturePath=''; document.getElementById('GG').click(); document.getElementById('gestureName').value=''; document.getElementById('pathFn').value=''; document.getElementById('editGesture').style.display='block'; }); //保存手势 document.getElementById('saveGesture').addEventListener('click',()=>{ if(!document.getElementById('gestureName').value){alert('请输入手势名称!');return;} else if(pathFn[document.getElementById('gestureName').value] && gestureName!=document.getElementById('gestureName').value){alert('该手势名称已被占用!');return;} delete pathFn[gestureName]; delete gesture[gesturePath]; let typeEle=document.getElementsByName('gestureType'); for(let Ti=0,len=typeEle.length;Ti-1) ? typeEle[Ti].value+gesturePath.slice(1) : typeEle[Ti].value+gesturePath) : (typeEle[Ti].value+'['+document.getElementById('gestureName').value+']'); break; } } gesture[gesturePath]=document.getElementById('gestureName').value; pathFn[document.getElementById('gestureName').value]=document.getElementById('pathFn').value; GM_setValue('pathFn',pathFn); GM_setValue('gesture',gesture); init(); document.getElementById('editGesture').style.display='none'; }); //关闭编辑 document.getElementById('closeEdit').addEventListener('click',()=>{ document.getElementById('editGesture').style.display='none'; }); //路径修改事件 document.getElementById('revisePath').addEventListener('touchstart',()=>{ if(fingersNum>1){return;} clearTimeout(gestureTimer); gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(pathEle.innerHTML.slice(-1))<0){pathEle.innerHTML+='●';slideTime=Date.now();}},(400+slideTime-Date.now())); },{passive:true}); document.getElementById('revisePath').addEventListener('touchmove',(e)=>{ let nowTime=Date.now(); if(fingersNum>1 || (nowTime-lastTime)<16){return;} clearTimeout(gestureTimer); let endX=e.changedTouches[0].screenX,endY=e.changedTouches[0].screenY, calcX=(endX-lastX)**2,calcY=(endY-lastY)**2, sumXY=calcX+calcY,lastIcon=pathEle.innerHTML.slice(-1), diffXY=(sumXY>lastSumXY) ? sumXY-lastSumXY : lastSumXY-sumXY; lastTime=nowTime;lastSumXY=sumXY; if(diffXY>80 && lastIcon!='○'){ slideTime=nowTime; let direction=(calcX>calcY) ? ((endX>lastX) ? '→' : '←') : ((endY>lastY) ? '↓' : '↑'); if(lastIcon==direction || sumXY>limit){ if(lastIcon!=direction){pathEle.innerHTML+=direction;} lastX=endX;lastY=endY;lastSumXY=0; } } gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(pathEle.innerHTML.slice(-1))<0){pathEle.innerHTML+='●';slideTime=Date.now();}},(400+slideTime-nowTime)); },{passive:true}); document.getElementById('revisePath').addEventListener('touchend',()=>{ clearTimeout(gestureTimer); if(fingersNum>1){return;} raiseTime=Date.now(); let lastIcon=pathEle.innerHTML.slice(-1); if((raiseTime-clickTime)<400 && (pressTime-clickTime)<200){ if(lastIcon=='●'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'○';} else if(lastIcon=='○'){clearTimeout(clickTimer);pathEle.innerHTML=pathEle.innerHTML.slice(0,-1)+'●';} else{pathEle.innerHTML+='◆';} }else if((raiseTime-pressTime)<200){ clickTimer=setTimeout(()=>{if(lastIcon!='○'){pathEle.innerHTML+='◆';}},400); clickTime=raiseTime; } }); //清除路径 document.getElementById('clearPath').addEventListener('touchend',(e)=>{ e.stopPropagation();e.preventDefault(); clearTimeout(gestureTimer); raiseTime=Date.now(); if((raiseTime-clickTime)<400 && (pressTime-clickTime)<200){ pathEle.innerHTML=''; }else if((raiseTime-pressTime)<200){ pathEle.innerHTML=pathEle.innerHTML.slice(0,-1); clickTime=raiseTime; } }); //保存修改路径 document.getElementById('cancleRevise').addEventListener('touchend',(e)=>{ e.stopPropagation();e.preventDefault(); clearTimeout(gestureTimer); raiseTime=Date.now(); if((raiseTime-pressTime)<200){ if(pathEle.innerHTML){ if(gestureName=='视频全屏' && pathEle.innerHTML.slice(-1)!='◆'){alert('视频全屏需要以◆结尾!');return;} if(gesture[pathEle.innerHTML]=='手势穿透'){alert('路径与"手势穿透"功能冲突!');return;} if('TIV'.indexOfNull(gesturePath.slice(0,1))>-1){pathEle.innerHTML=gesturePath.slice(0,1)+pathEle.innerHTML;} delete gesture[gesturePath]; if(gesture[pathEle.innerHTML]){ let pathTXT=(('TIV'.indexOfNull(gesturePath.slice(0,1))>-1) ? gesturePath.slice(0,1) : '')+'['+gesture[pathEle.innerHTML]+']'; gesture[pathTXT]=gesture[pathEle.innerHTML]; } gesture[pathEle.innerHTML]=gestureName; GM_setValue('gesture',gesture); init(); } window.addEventListener('touchmove',touchMove,{capture:true,passive:true}); window.addEventListener('touchend',touchEnd,true); gestureBox.style.cssText='overflow-y:auto'; document.getElementById('revisePath').style.display='none'; } }); //打开功能开关设置 document.getElementById('openSettings').addEventListener('dblclick',()=>{ document.getElementById('settingsBox').style.display='block'; let settingList=document.getElementById('settingList'); settingList.innerHTML=''; for(let Ti in settings){ settingList.innerHTML+='

'+Ti+':

'; if(typeof(settings[Ti])=='boolean'){ settingList.innerHTML=(settings[Ti]) ? (settingList.innerHTML+'') : (settingList.innerHTML+''); }else if(typeof(settings[Ti])=='number'){ settingList.innerHTML+='
'; let slideButton=document.getElementById(Ti), leftPX=slideButton.parentNode.offsetWidth*settings[Ti]-15; slideButton.style.left=leftPX+'px'; slideButton.innerHTML=settings[Ti].toFixed(1); } } let slideList=document.getElementsByClassName('slideButton'); for(let Ti=0,len=slideList.length;Ti{ for(let Ti in settings){ if(typeof(settings[Ti])=='boolean'){ settings[Ti]=document.getElementById(Ti).checked; }else if(typeof(settings[Ti])=='number'){ settings[Ti]=parseFloat(document.getElementById(Ti).innerHTML); } } GM_setValue('settings',settings); document.getElementById('settingsBox').style.display='none'; }); } /*功能补充模块*/ //iframe相关 let iframeEle=document.getElementsByTagName('iframe'); if(top.location==location){ //清除后退关闭定时器 window.addEventListener('popstate',()=>{clearTimeout(gestureData.backTimer);}); window.addEventListener('beforeunload',()=>{clearTimeout(gestureData.backTimer);}); //iframe手势执行 GM_addValueChangeListener('gestureIfr',async (name,old_value,new_value,remote)=>{ if(remote && !document.hidden && new_value){ runCode(new_value); await GM_setValue('gestureIfr',''); } }); }else{ //iframe视频全屏 GM_addValueChangeListener('fullscreen',async (name,old_value,new_value,remote)=>{ if(remote && !document.hidden){ videoEvent(); if(videoPlayer && window.isShow){ GM_setClipboard(videoPlayer.src); if(videoPlayer.webkitRequestFullscreen){await findVideoBox().webkitRequestFullscreen();} else if(videoPlayer.mozRequestFullScreen){await findVideoBox().mozRequestFullScreen();} } } }); } //iframe陀螺仪 GM_addValueChangeListener('isLock',async (name,old_value,new_value,remote)=>{ if(remote && !document.hidden && new_value>-1){ if(top.location==location){ if(regGYRO){regGYRO();regGYRO=null;} isLock=new_value; if(!isLock){await screen.orientation.unlock();} await GM_setValue('isLock',-1); }else{window.isShow=0;} } }); //解除选中限制 addStyle('html,*{user-select:text !important;}'); })();