mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Added Web-RDP mouse cursor support.
This commit is contained in:
		
							parent
							
								
									339e3efbef
								
							
						
					
					
						commit
						6dbae08c40
					
				
					 6 changed files with 109 additions and 17 deletions
				
			
		
							
								
								
									
										12
									
								
								apprelays.js
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								apprelays.js
									
										
									
									
									
								
							| 
						 | 
					@ -202,10 +202,16 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
 | 
				
			||||||
                delete bitmap.data;
 | 
					                delete bitmap.data;
 | 
				
			||||||
                send(['rdp-bitmap', bitmap]); // Send the bitmap metadata seperately, without bitmap data.
 | 
					                send(['rdp-bitmap', bitmap]); // Send the bitmap metadata seperately, without bitmap data.
 | 
				
			||||||
            }).on('clipboard', function (content) {
 | 
					            }).on('clipboard', function (content) {
 | 
				
			||||||
                // Clipboard data changed
 | 
					                send(['rdp-clipboard', content]); // The clipboard data has changed
 | 
				
			||||||
                send(['rdp-clipboard', content]);
 | 
					            }).on('pointer', function (cursorId, cursorStr) {
 | 
				
			||||||
 | 
					                if (cursorStr == null) { cursorStr = 'default'; }
 | 
				
			||||||
 | 
					                if (obj.lastCursorStrSent != cursorStr) {
 | 
				
			||||||
 | 
					                    obj.lastCursorStrSent = cursorStr;
 | 
				
			||||||
 | 
					                    //console.log('pointer', cursorStr);
 | 
				
			||||||
 | 
					                    send(['rdp-pointer', cursorStr]); // The mouse pointer has changed
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }).on('close', function () {
 | 
					            }).on('close', function () {
 | 
				
			||||||
                send(['rdp-close']);
 | 
					                send(['rdp-close']); // This RDP session has closed
 | 
				
			||||||
            }).on('error', function (err) {
 | 
					            }).on('error', function (err) {
 | 
				
			||||||
                if (typeof err == 'string') { send(['rdp-error', err]); }
 | 
					                if (typeof err == 'string') { send(['rdp-error', err]); }
 | 
				
			||||||
                if ((typeof err == 'object') && (err.err) && (err.code)) { send(['rdp-error', err.err, err.code]); }
 | 
					                if ((typeof err == 'object') && (err.err) && (err.code)) { send(['rdp-error', err.err, err.code]); }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,10 @@ var CreateRDPDesktop = function (canvasid) {
 | 
				
			||||||
    obj.m.onClipboardChanged = null;
 | 
					    obj.m.onClipboardChanged = null;
 | 
				
			||||||
    obj.onConsoleMessageChange = null;
 | 
					    obj.onConsoleMessageChange = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var xMouseCursorActive = true;
 | 
				
			||||||
 | 
					    var xMouseCursorCurrent = 'default';
 | 
				
			||||||
 | 
					    obj.mouseCursorActive = function (x) { if (xMouseCursorActive == x) return; xMouseCursorActive = x; obj.CanvasId.style.cursor = ((x == true) ? xMouseCursorCurrent : 'default'); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function mouseButtonMap(button) {
 | 
					    function mouseButtonMap(button) {
 | 
				
			||||||
        // Swap mouse buttons if needed
 | 
					        // Swap mouse buttons if needed
 | 
				
			||||||
        if (obj.m.SwapMouse === true) return [2, 0, 1, 0, 0][button];
 | 
					        if (obj.m.SwapMouse === true) return [2, 0, 1, 0, 0][button];
 | 
				
			||||||
| 
						 | 
					@ -75,6 +79,12 @@ var CreateRDPDesktop = function (canvasid) {
 | 
				
			||||||
                        obj.render.update(bitmap);
 | 
					                        obj.render.update(bitmap);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    case 'rdp-pointer': {
 | 
				
			||||||
 | 
					                        var pointer = msg[1];
 | 
				
			||||||
 | 
					                        xMouseCursorCurrent = pointer;
 | 
				
			||||||
 | 
					                        if (xMouseCursorActive) { obj.CanvasId.style.cursor = pointer; }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    case 'rdp-close': {
 | 
					                    case 'rdp-close': {
 | 
				
			||||||
                        obj.Stop();
 | 
					                        obj.Stop();
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ var fs = require('fs');
 | 
				
			||||||
var type = require('./type');
 | 
					var type = require('./type');
 | 
				
			||||||
var log = require('./log');
 | 
					var log = require('./log');
 | 
				
			||||||
var tls = require('tls');
 | 
					var tls = require('tls');
 | 
				
			||||||
var crypto = require('crypto');
 | 
					//var crypto = require('crypto');
 | 
				
			||||||
var events = require('events');
 | 
					var events = require('events');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,7 +186,7 @@ var FastPathUpdateType = {
 | 
				
			||||||
    FASTPATH_UPDATETYPE_PTR_NULL : 0x5,
 | 
					    FASTPATH_UPDATETYPE_PTR_NULL : 0x5,
 | 
				
			||||||
    FASTPATH_UPDATETYPE_PTR_DEFAULT : 0x6,
 | 
					    FASTPATH_UPDATETYPE_PTR_DEFAULT : 0x6,
 | 
				
			||||||
    FASTPATH_UPDATETYPE_PTR_POSITION : 0x8,
 | 
					    FASTPATH_UPDATETYPE_PTR_POSITION : 0x8,
 | 
				
			||||||
    FASTPATH_UPDATETYPE_COLOR : 0x9,
 | 
					    FASTPATH_UPDATETYPE_COLOR : 0x9, // Mouse cursor
 | 
				
			||||||
    FASTPATH_UPDATETYPE_CACHED : 0xA,
 | 
					    FASTPATH_UPDATETYPE_CACHED : 0xA,
 | 
				
			||||||
    FASTPATH_UPDATETYPE_POINTER : 0xB
 | 
					    FASTPATH_UPDATETYPE_POINTER : 0xB
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1075,7 +1075,7 @@ function clipPDU() {
 | 
				
			||||||
 * @param opt {object} type option
 | 
					 * @param opt {object} type option
 | 
				
			||||||
 * @returns {type.Component}
 | 
					 * @returns {type.Component}
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function fastPathBitmapUpdateDataPDU (opt) {
 | 
					function fastPathBitmapUpdateDataPDU(opt) {
 | 
				
			||||||
	var self = {
 | 
						var self = {
 | 
				
			||||||
		__FASTPATH_UPDATE_TYPE__ : FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP,
 | 
							__FASTPATH_UPDATE_TYPE__ : FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP,
 | 
				
			||||||
		header : new type.UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, { constant : true }),
 | 
							header : new type.UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, { constant : true }),
 | 
				
			||||||
| 
						 | 
					@ -1093,13 +1093,67 @@ function fastPathBitmapUpdateDataPDU (opt) {
 | 
				
			||||||
	return new type.Component(self, opt);
 | 
						return new type.Component(self, opt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is a table of cursorid to cursor name.
 | 
				
			||||||
 | 
					// Created by movering the mouse over this page: https://www.w3schools.com/csSref/tryit.asp?filename=trycss_cursor
 | 
				
			||||||
 | 
					const cursorIdTable = {
 | 
				
			||||||
 | 
					    // Normal style mouse cursor
 | 
				
			||||||
 | 
					    903013897: 'alias',
 | 
				
			||||||
 | 
					    370524792: 'all-scroll',
 | 
				
			||||||
 | 
					    853046751: 'cell',
 | 
				
			||||||
 | 
					    2101250798: 'col-resize',
 | 
				
			||||||
 | 
					    703681364: 'copy',
 | 
				
			||||||
 | 
					    992638936: 'crosshair',
 | 
				
			||||||
 | 
					    1539083673: 'ew-resize',
 | 
				
			||||||
 | 
					    1919796298: 'grab',
 | 
				
			||||||
 | 
					    1010243511: 'grabbing',
 | 
				
			||||||
 | 
					    1247283057: 'help',
 | 
				
			||||||
 | 
					    1390892051: 'none',
 | 
				
			||||||
 | 
					    885751489: 'not-allowed',
 | 
				
			||||||
 | 
					    1732952247: 'row-resize',
 | 
				
			||||||
 | 
					    747144997: 'url',
 | 
				
			||||||
 | 
					    2018345610: 'zoom-in',
 | 
				
			||||||
 | 
					    347367048: 'zoom-out',
 | 
				
			||||||
 | 
					    1872942890: 'default',
 | 
				
			||||||
 | 
					    1737852989: 'text',
 | 
				
			||||||
 | 
					    1932827019: 'ns-resize',
 | 
				
			||||||
 | 
					    1884471290: 'nesw-resize',
 | 
				
			||||||
 | 
					    1204065391: 'nwse-resize',
 | 
				
			||||||
 | 
					    2030531519: 'progress',
 | 
				
			||||||
 | 
					    1050842114: 'pointer',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Black style cursors
 | 
				
			||||||
 | 
					    1258195498: 'default',
 | 
				
			||||||
 | 
					    219484254: 'all-scroll',
 | 
				
			||||||
 | 
					    399295089: 'text',
 | 
				
			||||||
 | 
					    1912613597: 'wait',
 | 
				
			||||||
 | 
					    864127801: 'ew-resize',
 | 
				
			||||||
 | 
					    23245044: 'nesw-resize',
 | 
				
			||||||
 | 
					    1966995494: 'not-allowed',
 | 
				
			||||||
 | 
					    1873216615: 'help',
 | 
				
			||||||
 | 
					    255126408: 'nesw-resize',
 | 
				
			||||||
 | 
					    157191894: 'ns-resize',
 | 
				
			||||||
 | 
					    1768446509: 'pointer',
 | 
				
			||||||
 | 
					    1032011501: 'crosshair'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fastPathPointerUpdateDataPDU(opt, cursorId, cursorStr) {
 | 
				
			||||||
 | 
					    var self = {
 | 
				
			||||||
 | 
					        __FASTPATH_UPDATE_TYPE__: FastPathUpdateType.FASTPATH_UPDATETYPE_COLOR,
 | 
				
			||||||
 | 
					        header: new type.UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_COLOR, { constant: true }),
 | 
				
			||||||
 | 
					        cursorId: cursorId,
 | 
				
			||||||
 | 
					        cursorStr: cursorStr
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new type.Component(self, opt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
 | 
					 * @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
 | 
				
			||||||
 * @param updateData {type.Component}
 | 
					 * @param updateData {type.Component}
 | 
				
			||||||
 * @param opt {object} type option
 | 
					 * @param opt {object} type option
 | 
				
			||||||
 * @returns {type.Component}
 | 
					 * @returns {type.Component}
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function fastPathUpdatePDU (updateData, opt) {
 | 
					function fastPathUpdatePDU(updateData, opt) {
 | 
				
			||||||
	var self = {
 | 
						var self = {
 | 
				
			||||||
		updateHeader : new type.UInt8( function () {
 | 
							updateHeader : new type.UInt8( function () {
 | 
				
			||||||
			return self.updateData.obj.__FASTPATH_UPDATE_TYPE__;
 | 
								return self.updateData.obj.__FASTPATH_UPDATE_TYPE__;
 | 
				
			||||||
| 
						 | 
					@ -1116,13 +1170,28 @@ function fastPathUpdatePDU (updateData, opt) {
 | 
				
			||||||
			}) };
 | 
								}) };
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			switch (self.updateHeader.value & 0xf) {
 | 
								switch (self.updateHeader.value & 0xf) {
 | 
				
			||||||
			case FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
 | 
					                case FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: {
 | 
				
			||||||
                    self.updateData = fastPathBitmapUpdateDataPDU(options).read(s);
 | 
					                    self.updateData = fastPathBitmapUpdateDataPDU(options).read(s);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
			default:
 | 
					                }
 | 
				
			||||||
 | 
					                case FastPathUpdateType.FASTPATH_UPDATETYPE_COLOR: {
 | 
				
			||||||
 | 
					                    var data = new type.BinaryString(null, options).read(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Hash the data to get a cursor id.
 | 
				
			||||||
 | 
					                    // This is a hack since the cursor bitmap is sent but we can't use that, we has hash the bitmap and use that as a hint as to what cursor we need to display
 | 
				
			||||||
 | 
					                    const hasher = require('crypto').createHash('sha384');
 | 
				
			||||||
 | 
					                    hasher.update(data.value);
 | 
				
			||||||
 | 
					                    const cursorid = Math.abs(hasher.digest().readInt32BE(0));
 | 
				
			||||||
 | 
					                    const cursorStr = cursorIdTable[cursorid];
 | 
				
			||||||
 | 
					                    //if (cursorStr == null) { console.log('Unknown cursorId: ' + cursorid); }
 | 
				
			||||||
 | 
					                    self.updateData = fastPathPointerUpdateDataPDU(options, cursorid, cursorStr);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                default: {
 | 
				
			||||||
                    self.updateData = new type.BinaryString(null, options).read(s);
 | 
					                    self.updateData = new type.BinaryString(null, options).read(s);
 | 
				
			||||||
                    log.debug('unknown fast path pdu type ' + (self.updateHeader.value & 0xf));
 | 
					                    log.debug('unknown fast path pdu type ' + (self.updateHeader.value & 0xf));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,9 +270,14 @@ Client.prototype.recvFastPath = function (secFlag, s) {
 | 
				
			||||||
	while (s.availableLength() > 0) {
 | 
						while (s.availableLength() > 0) {
 | 
				
			||||||
        var pdu = data.fastPathUpdatePDU().read(s);
 | 
					        var pdu = data.fastPathUpdatePDU().read(s);
 | 
				
			||||||
		switch (pdu.obj.updateHeader.value & 0xf) {
 | 
							switch (pdu.obj.updateHeader.value & 0xf) {
 | 
				
			||||||
		case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
 | 
					            case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: {
 | 
				
			||||||
                this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
 | 
					                this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case data.FastPathUpdateType.FASTPATH_UPDATETYPE_COLOR: {
 | 
				
			||||||
 | 
					                this.emit('pointer', pdu.obj.updateData.obj.cursorId, pdu.obj.updateData.obj.cursorStr);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,6 +160,8 @@ function RdpClient(config) {
 | 
				
			||||||
    }).on('close', function () {
 | 
					    }).on('close', function () {
 | 
				
			||||||
        self.connected = false;
 | 
					        self.connected = false;
 | 
				
			||||||
        self.emit('close');
 | 
					        self.emit('close');
 | 
				
			||||||
 | 
					    }).on('pointer', function (cursorId, cursorStr) {
 | 
				
			||||||
 | 
					        self.emit('pointer', cursorId, cursorStr);
 | 
				
			||||||
    }).on('bitmap', function (bitmaps) {
 | 
					    }).on('bitmap', function (bitmaps) {
 | 
				
			||||||
        for (var bitmap in bitmaps) {
 | 
					        for (var bitmap in bitmaps) {
 | 
				
			||||||
            var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
 | 
					            var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue