2020-06-10 04:17:15 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Sylvain Peyrefitte
|
|
|
|
*
|
|
|
|
* This file is part of mstsc.js.
|
|
|
|
*
|
|
|
|
* mstsc.js is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2024-01-14 19:56:13 +03:00
|
|
|
/*
|
|
|
|
* added get clipboard from remote RDP - Simon Smith 2024
|
2024-01-14 20:42:43 +03:00
|
|
|
* added set clipboard to remote RDP - Simon Smith 2024
|
2024-01-14 19:56:13 +03:00
|
|
|
*/
|
2020-06-10 04:17:15 +03:00
|
|
|
|
|
|
|
(function() {
|
|
|
|
/**
|
|
|
|
* Mouse button mapping
|
|
|
|
* @param button {integer} client button number
|
|
|
|
*/
|
|
|
|
function mouseButtonMap(button) {
|
|
|
|
switch(button) {
|
|
|
|
case 0: return 1;
|
|
|
|
case 2: return 2;
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mstsc client
|
|
|
|
* Input client connection (mouse and keyboard)
|
|
|
|
* bitmap processing
|
|
|
|
* @param canvas {canvas} rendering element
|
|
|
|
*/
|
|
|
|
function Client(canvas) {
|
|
|
|
this.canvas = canvas;
|
|
|
|
// create renderer
|
|
|
|
this.render = new Mstsc.Canvas.create(this.canvas);
|
|
|
|
this.socket = null;
|
2020-06-11 20:25:29 +03:00
|
|
|
this.activeSession = false;
|
|
|
|
this.mouseNagleTimer = null;
|
|
|
|
this.mouseNagleData = null;
|
2020-06-10 04:17:15 +03:00
|
|
|
this.install();
|
|
|
|
}
|
2020-06-11 20:25:29 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
obj.mNagleTimer = setTimeout(function () {
|
|
|
|
obj.send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
|
|
|
|
obj.mNagleTimer = null;
|
|
|
|
}, 50);
|
|
|
|
*/
|
|
|
|
|
2020-06-10 04:17:15 +03:00
|
|
|
Client.prototype = {
|
|
|
|
install : function () {
|
2020-06-11 01:25:46 +03:00
|
|
|
var self = this;
|
2020-06-10 04:17:15 +03:00
|
|
|
|
|
|
|
// Bind mouse move event
|
|
|
|
this.canvas.addEventListener('mousemove', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
2020-06-11 20:25:29 +03:00
|
|
|
self.mouseNagleData = ['mouse', e.clientX - rect.left, e.clientY - rect.top, 0, false];
|
|
|
|
if (self.mouseNagleTimer == null) {
|
|
|
|
//console.log('sending', self.mouseNagleData);
|
|
|
|
self.mouseNagleTimer = setTimeout(function () { self.socket.send(JSON.stringify(self.mouseNagleData)); self.mouseNagleTimer = null; }, 50);
|
|
|
|
}
|
|
|
|
//self.socket.send(JSON.stringify(this.mouseNagleData));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
this.canvas.addEventListener('mousedown', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 20:25:29 +03:00
|
|
|
if (self.mouseNagleTimer != null) { clearTimeout(self.mouseNagleTimer); self.mouseNagleTimer = null; }
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
|
|
|
self.socket.send(JSON.stringify(['mouse', e.clientX - rect.left, e.clientY - rect.top, mouseButtonMap(e.button), true]));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
this.canvas.addEventListener('mouseup', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 20:25:29 +03:00
|
|
|
if (self.mouseNagleTimer != null) { clearTimeout(self.mouseNagleTimer); self.mouseNagleTimer = null; }
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
|
|
|
self.socket.send(JSON.stringify(['mouse', e.clientX - rect.left, e.clientY - rect.top, mouseButtonMap(e.button), false]));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
this.canvas.addEventListener('contextmenu', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 20:25:29 +03:00
|
|
|
if (self.mouseNagleTimer != null) { clearTimeout(self.mouseNagleTimer); self.mouseNagleTimer = null; }
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
|
|
|
self.socket.send(JSON.stringify(['mouse', e.clientX - rect.left, e.clientY - rect.top, mouseButtonMap(e.button), false]));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
this.canvas.addEventListener('DOMMouseScroll', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 20:25:29 +03:00
|
|
|
if (self.mouseNagleTimer != null) { clearTimeout(self.mouseNagleTimer); self.mouseNagleTimer = null; }
|
2020-06-10 04:17:15 +03:00
|
|
|
var isHorizontal = false;
|
|
|
|
var delta = e.detail;
|
2020-06-11 22:15:18 +03:00
|
|
|
//var step = Math.round(Math.abs(delta) * 15 / 8);
|
|
|
|
//var step = Math.abs(e.detail);
|
|
|
|
var step = 128;
|
|
|
|
//console.log('DOMMouseScroll', delta, step, e.detail);
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
|
|
|
self.socket.send(JSON.stringify(['wheel', e.clientX - rect.left, e.clientY - rect.top, step, delta > 0, isHorizontal]));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
this.canvas.addEventListener('mousewheel', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
2020-06-11 20:25:29 +03:00
|
|
|
if (self.mouseNagleTimer != null) { clearTimeout(self.mouseNagleTimer); self.mouseNagleTimer = null; }
|
2020-06-10 04:17:15 +03:00
|
|
|
var isHorizontal = Math.abs(e.deltaX) > Math.abs(e.deltaY);
|
|
|
|
var delta = isHorizontal?e.deltaX:e.deltaY;
|
2020-06-11 22:15:18 +03:00
|
|
|
//var step = Math.round(Math.abs(delta) * 15 / 8);
|
|
|
|
var step = 128;
|
|
|
|
//console.log('mousewheel', delta, step, e);
|
2020-06-11 01:25:46 +03:00
|
|
|
var rect = e.target.getBoundingClientRect();
|
|
|
|
self.socket.send(JSON.stringify(['wheel', e.clientX - rect.left, e.clientY - rect.top, step, delta > 0, isHorizontal]));
|
2020-06-10 04:17:15 +03:00
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Bind keyboard event
|
|
|
|
window.addEventListener('keydown', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
|
|
|
self.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), true]));
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
window.addEventListener('keyup', function (e) {
|
|
|
|
if (!self.socket || !self.activeSession) return;
|
|
|
|
self.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), false]));
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
return this;
|
2022-05-03 07:06:32 +03:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* disconnect
|
|
|
|
*/
|
|
|
|
disconnect: function () {
|
|
|
|
if (this.socket) { this.socket.close(); }
|
|
|
|
},
|
2020-06-10 04:17:15 +03:00
|
|
|
/**
|
|
|
|
* connect
|
|
|
|
* @param ip {string} ip target for rdp
|
|
|
|
* @param domain {string} microsoft domain
|
|
|
|
* @param username {string} session username
|
|
|
|
* @param password {string} session password
|
|
|
|
* @param next {function} asynchrone end callback
|
|
|
|
*/
|
2021-06-30 03:13:18 +03:00
|
|
|
connect : function (ip, domain, username, password, options, next) {
|
2020-06-11 01:25:46 +03:00
|
|
|
// Start connection
|
2020-06-10 04:17:15 +03:00
|
|
|
var self = this;
|
2021-05-09 04:09:49 +03:00
|
|
|
this.socket = new WebSocket('wss://' + window.location.host + '/mstscrelay.ashx');
|
2020-06-10 22:10:32 +03:00
|
|
|
this.socket.binaryType = 'arraybuffer';
|
2020-06-10 04:17:15 +03:00
|
|
|
this.socket.onopen = function () {
|
2020-06-11 01:25:46 +03:00
|
|
|
//console.log("WS-OPEN");
|
2020-06-10 04:17:15 +03:00
|
|
|
self.socket.send(JSON.stringify(['infos', {
|
|
|
|
ip: ip,
|
|
|
|
port: 3389,
|
|
|
|
screen: {
|
|
|
|
width: self.canvas.width,
|
|
|
|
height: self.canvas.height
|
|
|
|
},
|
|
|
|
domain: domain,
|
|
|
|
username: username,
|
|
|
|
password: password,
|
2021-06-30 03:13:18 +03:00
|
|
|
options: options,
|
2020-06-10 04:17:15 +03:00
|
|
|
locale: Mstsc.locale()
|
|
|
|
}]));
|
2024-01-14 20:42:43 +03:00
|
|
|
self.prevClipboardText = null;
|
|
|
|
self.clipboardReadTimer = setInterval(function(){
|
|
|
|
if(navigator.clipboard.readText != null){
|
|
|
|
navigator.clipboard.readText()
|
|
|
|
.then(function(data){
|
|
|
|
if(data != self.prevClipboard){
|
|
|
|
self.prevClipboard = data;
|
|
|
|
if (self.socket) { self.socket.send(JSON.stringify(['clipboard', data])); }
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(function(){ });
|
|
|
|
}
|
|
|
|
}, 1000);
|
2020-06-10 04:17:15 +03:00
|
|
|
};
|
|
|
|
this.socket.onmessage = function (evt) {
|
2020-06-10 22:10:32 +03:00
|
|
|
if (typeof evt.data == 'string') {
|
|
|
|
// This is a JSON text string, parse it.
|
|
|
|
var msg = JSON.parse(evt.data);
|
|
|
|
switch (msg[0]) {
|
|
|
|
case 'rdp-connect': {
|
|
|
|
//console.log('[mstsc.js] connected');
|
|
|
|
self.activeSession = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'rdp-bitmap': {
|
|
|
|
if (self.bitmapData == null) break;
|
|
|
|
var bitmap = msg[1];
|
|
|
|
bitmap.data = self.bitmapData; // Use the binary data that was sent earlier.
|
|
|
|
delete self.bitmapData;
|
|
|
|
//console.log('[mstsc.js] bitmap update bpp : ' + bitmap.bitsPerPixel);
|
|
|
|
self.render.update(bitmap);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'rdp-close': {
|
|
|
|
//console.log('[mstsc.js] close');
|
|
|
|
self.activeSession = false;
|
|
|
|
next(null);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'rdp-error': {
|
|
|
|
var err = msg[1];
|
|
|
|
console.log('[mstsc.js] error : ' + err.code + '(' + err.message + ')');
|
|
|
|
self.activeSession = false;
|
|
|
|
next(err);
|
|
|
|
break;
|
|
|
|
}
|
2024-01-14 19:56:13 +03:00
|
|
|
case 'rdp-clipboard': {
|
|
|
|
if ((msg[1] != null) && (navigator.clipboard.writeText != null)) {
|
|
|
|
navigator.clipboard.writeText(msg[1]) // Put remote clipboard data into our clipboard
|
|
|
|
.then(function() { })
|
|
|
|
.catch(function(err) { console.log('clipboard.writeText Error', err); });
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-06-10 04:17:15 +03:00
|
|
|
}
|
2020-06-10 22:10:32 +03:00
|
|
|
} else {
|
|
|
|
// This is binary bitmap data, store it.
|
|
|
|
self.bitmapData = evt.data;
|
2020-06-10 04:17:15 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
this.socket.onclose = function () {
|
2020-06-11 01:25:46 +03:00
|
|
|
//console.log("WS-CLOSE");
|
2020-06-10 04:17:15 +03:00
|
|
|
self.activeSession = false;
|
2024-01-14 20:42:43 +03:00
|
|
|
clearInterval(self.clipboardReadTimer);
|
|
|
|
self.prevClipboardText = null;
|
2020-06-10 04:17:15 +03:00
|
|
|
next(null);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 01:25:46 +03:00
|
|
|
MstscClient = { create : function (canvas) { return new Client(canvas); } }
|
2020-06-10 04:17:15 +03:00
|
|
|
})();
|