// ==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.9.0 // @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.9.0 2022-08-22 - 修复一些视频相关的问题 (()=>{ /*手势数据模块*/ 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(50vh);}to{transform:translateY(0);}}");}else{gestureData.halfScreen=addStyle("html,body{height:43vh !important;overflow-x:hidden !important;}html{transform:translateY(50vh);animation:halfScreen 0.5s;}@keyframes halfScreen{from{transform:translateY(0);}to{transform:translateY(50vh);}}");}', '视频解析':'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){videoPlayer.muted=false;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){videoPlayer.muted=false;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=GM_getValue('gesture',gesture); pathFn=GM_getValue('pathFn',pathFn); settings=GM_getValue('settings',settings); //脚本常量 const gestureData={},limit=(((window.screen.width>window.screen.height) ? window.screen.height : window.screen.width)*0.5*settings['滑动距离'])**2/3; /*手势功能模块*/ //手指滑动变量 let _startX=0,_startY=0,timeSpan=0,pressTime=0,raiseTime=0,slideTime=0,lastTime=0,_sumXY=0,slideLimit=0,path='',fingersNum=0,gestureTimer=0,noClick=null,isOK=0; //修改Trusted-Types策略 if(window.trustedTypes?.createPolicy){ let TTP={createHTML:string=>string,createScript:string=>string,createScriptURL:string=>string};//创建策略 window.trustedTypes.createPolicy('default',TTP); } //手势执行 function runCode(runPath){ try{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.innerHTML='try{'+js+'}catch(error){alert("“"+path+"” 手势执行脚本错误:\\n"+error+" !");}'; document.body.appendChild(script); } })(); window.evalTool('window.addEventListener("popstate",()=>{clearTimeout(gestureData.backTimer);},true);window.addEventListener("beforeunload",()=>{clearTimeout(gestureData.backTimer);},true);'); } window.evalTool(pathFn[gesture[runPath]]); } else{alert('“'+runPath+'” 手势执行脚本错误:\n'+error+' !');} } } function runGesture(pathStr=''){ let nowSelect=window.getSelection().toString(); if(nowSelect && gestureData.selectWords!=nowSelect){path='';return;} let firstIcon=path.slice(0,1); if(gesture[path]){ if(top.location==location || 'TIV'.indexOfNull(firstIcon)>-1){runCode(path);} else{GM_setValue('gestureIfr',path);} path=pathStr; }else if(gesture[path.slice(1)] && 'TIV'.indexOfNull(firstIcon)>-1){ if(top.location==location){runCode(path.slice(1));} else{GM_setValue('gestureIfr',path.slice(1));} path=pathStr; } } //手指按下 function touchStart(e){ clearTimeout(gestureTimer); fingersNum=e.touches.length;if(fingersNum>1){return;} let _X=e.changedTouches[0].screenX,_Y=e.changedTouches[0].screenY, calcX=(_X-gestureData.endX)**2,calcY=(_Y-gestureData.endY)**2,sumXY=calcX+calcY, nowTime=Date.now();timeSpan=nowTime-raiseTime; if(timeSpan>50 || sumXY>2500){//断触判断 pressTime=slideTime=nowTime;_sumXY=0; _startX=gestureData.startX=_X;_startY=gestureData.startY=_Y; if(timeSpan>200 || sumXY>10000){ path='';slideLimit=limit*2;gestureData.touchEle=e.target; gestureData.selectWords=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(),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;} } } 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((nowTime-lastTime)<16 || fingersNum>1){return;} clearTimeout(gestureTimer); gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY; let calcX=(gestureData.endX-_startX)**2,calcY=(gestureData.endY-_startY)**2, sumXY=calcX+calcY,lastIcon=path.slice(-1), diffXY=(sumXY>_sumXY) ? sumXY-_sumXY : _sumXY-sumXY; lastTime=nowTime;_sumXY=sumXY; if(diffXY>50 && lastIcon!='○'){ isOK=0;slideTime=nowTime; let direction=(calcX>calcY) ? ((gestureData.endX>_startX) ? '→' : '←') : ((gestureData.endY>_startY) ? '↓' : '↑'); if(lastIcon==direction || sumXY>(slideLimit+limit)){ if(lastIcon!=direction && (timeSpan>200 || timeSpan<84 || '↑→↓←●'.indexOfNull(lastIcon)<0)){path+=direction;slideLimit=slideLimit/2;timeSpan=0;} _startX=gestureData.endX;_startY=gestureData.endY; isOK=1;_sumXY=0; } } gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(lastIcon)<0){isOK=1;let _path=path;path+='●';if(gesture[_path+'○']){_path+='○';}else{_path+='●';}runGesture(_path);slideTime=Date.now();}},(400+slideTime-nowTime)); } //手指抬起 function touchEnd(e){ clearTimeout(gestureTimer); gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY; raiseTime=Date.now();setTimeout(videoEvent,16); if(path.slice(-1)=='○'){raiseTime-=200;runGesture();return;} if(fingersNum>1){raiseTime-=200;return;} let calcX=(gestureData.endX-gestureData.startX)**2,calcY=(gestureData.endY-gestureData.startY)**2; if((raiseTime-pressTime)<200 && (calcX+calcY)<100){path+='◆';isOK=1;} if(isOK){gestureTimer=setTimeout(runGesture,199);} if(/^V◆◆$|T/.test(path) && !noClick){e.stopPropagation();noClick=addStyle('*{pointer-events:none;}');} } /*视频功能模块*/ //video标签变量 let videoEle=document.getElementsByTagName('video'),_videoEle=[],videoPlayer=null,oriType='portrait-primary',lockOriType='landscape-primary',isLock=0; //video判定 function setVideo(){videoPlayer=this;videoOriLock();} function videoOriLock(){ if(!videoPlayer.videoWidth){if(!videoPlayer.error && videoPlayer.offsetWidth){setTimeout(videoOriLock,500);}return;} videoPlayer.parentNode.appendChild(gestureData.tipBox); if(videoPlayer.videoWidth>videoPlayer.videoHeight){isLock=1;} else{isLock=0;screen.orientation.unlock();} if(top.location!=location){window.isShow=1;GM_setValue('isLock',isLock);} } function videoFullScreen(){ if(document.webkitIsFullScreen){document.webkitExitFullscreen();} else if(document.mozFullScreen){document.mozCancelFullScreen();} else if(videoPlayer){ GM_setClipboard(videoPlayer.src); if(videoPlayer.webkitRequestFullscreen){findVideoBox().webkitRequestFullscreen();} else if(videoPlayer.mozRequestFullScreen){findVideoBox().mozRequestFullScreen();} }else if(document.getElementsByTagName('iframe').length){GM_setValue('fullscreen',Date());} } //获取video全屏样式容器 function findVideoBox(){ if(!videoPlayer.offsetWidth){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 videoBind(){ _videoEle=[]; for(let Ti=0,len=videoEle.length;Ti video){height:100%;}video{width:100% !important;height:100% !important;}'); //视频方向锁定 window.addEventListener('webkitfullscreenchange',(e)=>{ if(document.webkitIsFullScreen){ let srcFindVideo=e.target.getElementsByTagName('video'),srcVideo=(e.target.nodeName=='VIDEO') ? e.target : srcFindVideo[0]; if(!srcVideo || srcFindVideo.length>1){isLock=0;screen.orientation.unlock();return;} srcVideo.play();if(isLock && oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);} }else{oriType='portrait-primary';} },true); window.addEventListener('mozfullscreenchange',(e)=>{ if(document.mozFullScreen){ let srcFindVideo=e.target.getElementsByTagName('video'),srcVideo=(e.target.nodeName=='VIDEO') ? e.target : srcFindVideo[0]; if(!srcVideo || srcFindVideo.length>1){isLock=0;screen.orientation.unlock();return;} srcVideo.play();if(isLock && oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);} }else{oriType='portrait-primary';} },true); } videoBind(); } } //注册陀螺仪 let regGYRO=()=>{ let runTime=0; window.addEventListener('deviceorientation',(e)=>{ let nowTime=Date.now(); if((nowTime-runTime)<500 || !isLock){return;} 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){if(oriType!=lockOriType){oriType=lockOriType;screen.orientation.lock(lockOriType);}} else{oriType='portrait-primary';} runTime=nowTime; },true); } /*工具方法模块*/ String.prototype.indexOfNull=function(str=null){if(str){return this.indexOf(str);}return -1;} function addStyle(css){ let style=document.createElement('style'); style.innerHTML=css; document.head.appendChild(style); return style; } //手势操作设置UI function openSet(){ let gestureName='',gesturePath='',clickTime=0,clickTimer=0; //页面生成 addStyle('html{font-size:62.5% !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 !important;z-index:2147483640;}'+ '#gestureBox *{font-family:"Microsoft YaHei";margin:0;padding:0;text-align:center;font-size:2rem;line-height:4rem;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.1rem solid #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;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;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.7);width:100%;height:100%;position:fixed;top:0;left:0;z-index:2147483641;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;z-index:2147483641;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;}'+ '#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;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:2147483642;}'+ '#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:2147483643;}'+ '#gestureBox #editGesture #pathFn{overflow-y:auto !important;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{overflow-y:auto !important;background-color:#fff;width:100%;height:100%;position:fixed;top:0;left:0;z-index:2147483641;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{overflow:initial !important;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='

手势轨迹设置

+
'+ '
'+ '

请滑动手指

清除
保存
'+ '

手势名称:

'+ '

手势类型:

'+ '

手势执行脚本:

'+ '
'+ '

功能开关设置

'; 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); 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-_startX, 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); _startX=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'; },true); //保存手势 document.getElementById('saveGesture').addEventListener('click',()=>{ if(!document.getElementById('gestureName').value){alert('请输入手势名称!');return;} 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'; },true); //关闭编辑 document.getElementById('closeEdit').addEventListener('click',()=>{ document.getElementById('editGesture').style.display='none'; },true); //路径修改事件 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())); },true); document.getElementById('revisePath').addEventListener('touchmove',(e)=>{ let nowTime=Date.now(); if((nowTime-lastTime)<16 || fingersNum>1){return;} clearTimeout(gestureTimer); gestureData.endX=e.changedTouches[0].screenX;gestureData.endY=e.changedTouches[0].screenY; let calcX=(gestureData.endX-_startX)**2,calcY=(gestureData.endY-_startY)**2, sumXY=calcX+calcY,lastIcon=pathEle.innerHTML.slice(-1), diffXY=(sumXY>_sumXY) ? sumXY-_sumXY : _sumXY-sumXY; lastTime=nowTime;_sumXY=sumXY; if(diffXY>50 && lastIcon!='○'){ slideTime=nowTime; let direction=(calcX>calcY) ? ((gestureData.endX>_startX) ? '→' : '←') : ((gestureData.endY>_startY) ? '↓' : '↑'); if(lastIcon==direction || sumXY>limit*3){ if(lastIcon!=direction){pathEle.innerHTML+=direction;} _startX=gestureData.endX;_startY=gestureData.endY;_sumXY=0; } } gestureTimer=setTimeout(()=>{if('●○'.indexOfNull(lastIcon)<0){pathEle.innerHTML+='●';slideTime=Date.now();}},(400+slideTime-nowTime)); },true); document.getElementById('revisePath').addEventListener('touchend',(e)=>{ clearTimeout(gestureTimer); if(fingersNum>1){return;} 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,lastIcon=pathEle.innerHTML.slice(-1); if((calcX+calcY)>100){return;} 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();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((calcX+calcY)>100){return;} 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();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((calcX+calcY)>100){return;} 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,{capture:true,passive:true}); 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'; },true); } /*功能补充模块*/ //*检测事件是否添加 gestureTimer=setInterval(()=>{if(!isOK){ if(top.location==location){ //清除后退关闭定时器 window.addEventListener('popstate',()=>{clearTimeout(gestureData.backTimer);},true); window.addEventListener('beforeunload',()=>{clearTimeout(gestureData.backTimer);},true); //iframe手势执行 GM_addValueChangeListener('gestureIfr',(name,old_value,new_value,remote)=>{ if(remote && !document.hidden && new_value){ runCode(new_value); GM_setValue('gestureIfr',''); } }); }else{ //iframe视频全屏 GM_addValueChangeListener('fullscreen',(name,old_value,new_value,remote)=>{ if(remote && !document.hidden){ videoEvent(); if(videoPlayer && window.isShow){ GM_setClipboard(videoPlayer.src); if(videoPlayer.webkitRequestFullscreen){findVideoBox().webkitRequestFullscreen();} else if(videoPlayer.mozRequestFullScreen){findVideoBox().mozRequestFullScreen();} } } }); } //iframe陀螺仪 GM_addValueChangeListener('isLock',(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){screen.orientation.unlock();} GM_setValue('isLock',-1); }else{window.isShow=0;} } }); //解除选中限制 addStyle('html,*{user-select:text !important;}'); //手势事件注册 window.addEventListener('touchstart',touchStart,{capture:true,passive:true}); window.addEventListener('touchmove',touchMove,{capture:true,passive:true}); window.addEventListener('touchend',touchEnd,{capture:true,passive:true});} //*3次检测后销毁定时器 if(getComputedStyle(document.documentElement).userSelect=='text'){isOK+=1;}else{isOK=0;}if(isOK>3){clearInterval(gestureTimer);}},16); })();