var _screen={
sock:null,
imgURL:null,
sWidth:0,
sHeight:0,
lastMessageTime:0,
mouseDown:0,
clickCount:1,
lastClickTime:0,
metaKeyDown:0,
interval:null,
canvas:null,
formats:['png','gif','jpeg']
};
function ScreenLoad(){
const sidebar=document.getElementById('screenSidebar');
const content=document.getElementById('screenContent');
sidebar.style.display='block';
content.style.display='block';
_screen.canvas=document.getElementById("screenCanvas");
document.addEventListener("keydown",ScreenKeyDown);
document.addEventListener("keyup",ScreenKeyUp);
window.addEventListener("beforeunload",ScreenBeforeUnload);
_screen.interval=setInterval(ScreenConnect,5000);
ScreenConnect();
}
function ScreenUnload(){
const sidebar=document.getElementById('screenSidebar');
const content=document.getElementById('screenContent');
sidebar.style.display='none';
content.style.display='none';
if(_screen.sock)_screen.sock.close();
if(_screen.interval)clearInterval(_screen.interval);
document.removeEventListener("keydown",ScreenKeyDown);
document.removeEventListener("keyup",ScreenKeyUp);
window.removeEventListener("beforeunload",ScreenBeforeUnload);
_screen.sock=null;
_screen.imgURL=null;
_screen.sWidth=0;
_screen.sHeight=0;
_screen.lastMessageTime=0;
_screen.mouseDown=0;
_screen.clickCount=0;
_screen.lastClickTime=0;
_screen.metaKeyDown=0;
_screen.interval=null;
}
function ScreenConnect(){
if(_screen.sock){
if(Date.now()>_screen.lastMessageTime+10000)_screen.sock.close();
return;
}
const location=window.location;
const url=((location.protocol=='http:')?'ws://':'wss://')+location.hostname+':'+location.port+'/screenControl?quality='+(document.getElementById('screenQualityCheck').checked?'1':'0');
_screen.sock=new WebSocket(url);
_screen.sock.binaryType='arraybuffer';
_screen.sock.onmessage=ScreenMessage;
_screen.sock.onclose=function(msg){_screen.sock=null;}
_screen.sock.onerror=function(error){_screen.sock.close();};
_screen.lastMessageTime=Date.now();
}
function ScreenMessage(msg){
const bytes=new Uint8Array(msg.data);
const id=ToInt16(bytes[0],bytes[1]);
if(id==0x7369)ScreenVideoFrame(bytes);
else if(id==0x208a)ScreenFileList(bytes.slice(2));
_screen.lastMessageTime=Date.now();
}
function ScreenVideoFrame(bytes){
if(!_screen.sWidth){
_screen.sWidth=ToInt16(bytes[2],bytes[3]);
_screen.sHeight=ToInt16(bytes[4],bytes[5]);
ScreenSetUpCanvas(_screen.sWidth,_screen.sHeight);
}
if(!_screen.imgURL){
const x=ToInt16(bytes[6],bytes[7]);
const y=ToInt16(bytes[8],bytes[9]);
const w=ToInt16(bytes[10],bytes[11]);
const h=ToInt16(bytes[12],bytes[13]);
const format=bytes[14];
const blob=new Blob([bytes.slice(19)],{type:'image/'+_screen.formats[format]});
_screen.imgURL=URL.createObjectURL(blob);
const img=new Image(w,h);
img.onload=function(){
_screen.canvas.getContext('2d').drawImage(img,0,0,w,h,x,y,w,h);
URL.revokeObjectURL(_screen.imgURL);
_screen.imgURL=null;
}
img.src=_screen.imgURL;
}
}
function ScreenFileList(bytes){
const sel=document.getElementById('screenDownloadSelect');
const val=sel.value;
sel.innerHTML=String.fromCharCode.apply(null,bytes);
const optionElements=sel.getElementsByTagName('option');
for(let i=0;i<optionElements.length;i++)optionElements[i].innerHTML=optionElements[i].value;
if(SelectValueIsValid(sel,val))sel.value=val;
else sel.selectedIndex=0;
}
function ScreenSetUpCanvas(width,height){
_screen.canvas.oncontextmenu=ScreenMouseContext;
_screen.canvas.onmousemove=ScreenMouseMove;
_screen.canvas.onmousedown=ScreenMouseDown;
_screen.canvas.onmouseup=ScreenMouseUp;
_screen.canvas.onwheel=ScreenWheel;
_screen.canvas.width=width;
_screen.canvas.height=height;
}
function ScreenMouseContext(event){
event.preventDefault();
return false;
}
function ScreenMouseMove(event){
ScreenSendMessageMouse(_screen.mouseDown?1:0,0,event);
return false;
}
function ScreenMouseDown(event){
const ms=Date.now();
if(ms<_screen.lastClickTime+500)_screen.clickCount=2;
_screen.lastClickTime=ms;
ScreenSendMessageMouse(2,_screen.clickCount,event);
_screen.mouseDown=1;
return false;
}
function ScreenMouseUp(event){
ScreenSendMessageMouse(3,_screen.clickCount,event);
_screen.mouseDown=0;
_screen.clickCount=1;
return false;
}
function ScreenCoordinatesFromEvent(event){
const r=_screen.canvas.getBoundingClientRect();
const x=(event.clientX-r.left)*_screen.sWidth/r.width;
const y=(event.clientY-r.top)*_screen.sHeight/r.height;
return{'x':Math.round(x),'y':Math.round(y)}
}
function GetModifiersFromEvent(event){
const shift=event.shiftKey?1:0;
const ctrl=event.ctrlKey?1:0;
const alt=event.altKey?1:0;
const cmd=event.metaKey?1:0;
return shift<<3 | ctrl<<2 | alt<<1 | cmd;
}
function ScreenSendMessageMouse(type,count,event){
if(!_screen.sock)return;
const buffer=new ArrayBuffer(8);
const bytes=new Uint8Array(buffer);
const coords=ScreenCoordinatesFromEvent(event);
if(coords.x>=0 && coords.x<_screen.sWidth && coords.y>=0 && coords.y<_screen.sHeight){
bytes[0]=type;
bytes[1]=(event.button==0)?0:1;
bytes[2]=count;
bytes[3]=coords.x&0xff;
bytes[4]=(coords.x&0xff00)>>8;
bytes[5]=coords.y&0xff;
bytes[6]=(coords.y&0xff00)>>8;
bytes[7]=GetModifiersFromEvent(event);
}
_screen.sock.send(buffer);
}
function ScreenWheel(event){
if(!_screen.sock)return;
const buffer=new ArrayBuffer(5);
const bytes=new Uint8Array(buffer);
let directionY=0,magnitudeY=event.deltaY;
let directionX=0,magnitudeX=event.deltaX;
if(magnitudeY<0){magnitudeY*=-1;directionY=1;}
if(magnitudeX<0){magnitudeX*=-1;directionX=1;}
bytes[0]=7;
bytes[1]=directionY;
bytes[2]=(magnitudeY>255)?255:magnitudeY;
bytes[3]=directionX;
bytes[4]=(magnitudeX>255)?255:magnitudeX;
_screen.sock.send(buffer);
event.preventDefault();
return false;
}
function ScreenKeyDown(event){
if(event.key=='Meta')_screen.metaKeyDown=1;
ScreenSendMessageKey(4,event);
event.preventDefault();
event.stopPropagation();
}
function ScreenKeyUp(event){
if(event.key=='Meta')_screen.metaKeyDown=0;
ScreenSendMessageKey(5,event);
event.preventDefault();
event.stopPropagation();
}
function ScreenSendMessageKey(type,event){
if(!_screen.sock)return;
const buffer=new ArrayBuffer(4);
const bytes=new Uint8Array(buffer);
const keyCode=keyToMacVirtualKeycode[event.key];
if(keyCode!=undefined){
bytes[0]=type;
bytes[1]=(event.key.length==1)?event.key.charCodeAt(0):0;
bytes[2]=keyCode;
bytes[3]=GetModifiersFromEvent(event);
_screen.sock.send(buffer);
}
}
function ScreenBeforeUnload(event){
if(_screen.metaKeyDown){
const message=Loc('screen_control_active');
event.preventDefault();
event.returnValue=message;
return message;
}
}
function ScreenSendMessageQuality(value){
if(!_screen.sock)return;
const buffer=new ArrayBuffer(2);
const bytes=new Uint8Array(buffer);
bytes[0]=6;
bytes[1]=value;
_screen.sock.send(buffer);
}
function ScreenDownload(){
window.location='ftDownload?file='+document.getElementById('screenDownloadSelect').value;
}
function ScreenUpload(){
const form=document.getElementById('screenUploadForm');
const feedbackSpan=document.getElementById('screenUploadFeedback');
const fileInput=document.getElementById('fileInput');
const file=fileInput.files[0];
if(file){
const formData=new FormData(form);
const xhr=new XMLHttpRequest();
xhr.open('POST','ftUpload',true);
xhr.onload=function(){
if(xhr.status===200){
feedbackSpan.innerHTML=Loc('Upload successful');
}else{
feedbackSpan.innerHTML=Loc('Upload failed with status {0}',xhr.status);
}
};
feedbackSpan.innerHTML=Loc('Uploading…');
xhr.send(formData);
}else{
feedbackSpan.innerHTML=Loc('Please choose a file');
}
}
