From cc3f33db7a8d3c4ad373e646b199808e01bc5d9b Mon Sep 17 00:00:00 2001 From: sss Date: Tue, 17 Jan 2023 00:38:19 +0300 Subject: added webrdp public code --- www/js/webrdp-debug.js | 1707 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1707 insertions(+) create mode 100644 www/js/webrdp-debug.js (limited to 'www/js/webrdp-debug.js') diff --git a/www/js/webrdp-debug.js b/www/js/webrdp-debug.js new file mode 100644 index 0000000..12c7e52 --- /dev/null +++ b/www/js/webrdp-debug.js @@ -0,0 +1,1707 @@ +/** BSD-2-Clause license + * + * Copyright (c) 2018-2023 wsgate devs, NST , sss . + * + */ + +var webrdp = webrdp || {} + +webrdp.hasconsole = (typeof console !== 'undefined' && 'debug' in console && 'info' in console && 'warn' in console && 'error' in console); + +webrdp.WSrunner = new Class( { + Implements: Events, + initialize: function(url) { + this.url = url; + this.log = new webrdp.Log(); + }, + Run: function() { + try { + this.sock = new WebSocket(this.url); + } catch (err) { } + this.sock.binaryType = 'arraybuffer'; + this.sock.onopen = this.onWSopen.bind(this); + this.sock.onclose = this.onWSclose.bind(this); + this.sock.onmessage = this.onWSmsg.bind(this); + this.sock.onerror = this.onWSerr.bind(this); + this.sock.sendd = this.sock.send; + this.sock.send = (data) => { + this.log.debug('wsout', data); + this.sock.sendd(data); + } + + } +}); + +webrdp.RDP = new Class( { + Extends: webrdp.WSrunner, + initialize: function(url, canvas, controls, cssCursor, useTouch, vkbd) { + this.canvas = canvas; + this.cctx = canvas.getContext('2d'); + this.cctx.strokeStyle = 'rgba(255,255,255,0)'; + this.cctx.FillStyle = 'rgba(255,255,255,0)'; + this.bstore = new Element('canvas', { + 'width':this.canvas.width, + 'height':this.canvas.height, + }); + this.bctx = this.bstore.getContext('2d'); + this.aMF = 0; + this.Tcool = true; + this.pTe = null; + this.ccnt = 0; + this.clx = 0; + this.cly = 0; + this.clw = 0; + this.clh = 0; + this.mX = 0; + this.mY = 0; + this.chx = 10; + this.chy = 10; + this.modkeys = [144, ]; + this.cursors = new Array(); + this.sid = null; + this.open = false; + this.cssC = cssCursor; + this.uT = useTouch; + this.controls = controls; + if (!cssCursor) { + this.cI = new Element('img', { + 'src': '/c_default.png', + 'styles': { + 'position': 'absolute', + 'z-index': 998, + 'left': this.mX - this.chx, + 'top': this.mY - this.chy + } + }).inject(document.body); + } + if (vkbd) { + vkbd.addEvent('vkpress', this.onKv.bind(this)); + } + //browser identiying variables + this.msie = window.navigator.userAgent.indexOf('MSIE '); + this.trident = window.navigator.userAgent.indexOf('Trident/'); + this.parent(url); + //add the toggle function to the keyboard language button + $('keyboardlanguage').addEvent('click', this.ToggleLanguageButton.bind(this)); + }, + Disconnect: function() { + this._reset(); + }, + SendKey: function(comb) { + //code 0 : ctrl+alt+delete + //code 1 : alt+tab + //code 2 : alt+tab release + + if (this.sock.readyState == this.sock.OPEN) { + this.log.debug('send special combination', comb); + buf = new ArrayBuffer(12); + a = new Uint32Array(buf); + a[0] = 3; // WSOP_CS_SPECIALCOMB + a[1] = comb; + this.sock.send(buf); + }; + }, + SendCredentials: function() { + var infoJSONstring = JSON.stringify(settingsGetJSON()); + var len = infoJSONstring.length; + var buf = new ArrayBuffer((len + 1)*4); // 4 bytes for each char + var bufView = new Uint32Array(buf); + bufView[0] = 4; // WSOP_CS_CREDENTIAL_JSON + for(var i = 0; i= this.clx) && + (x <= (this.clx + this.clw)) && + (y >= this.cly) && + (y <= (this.cly + this.clh)) + ); + } + // No clipping region + return true; + }, + /** + * Main message loop. + */ + _pmsg: function(data) { // process a binary RDP message from our queue + // 0-12 code is WSGATE protocol with a little tuning + // 13-XXX codes is our own protocol draft implementation + var op, hdr, count, rects, bmdata, rgba, compressed, i, offs, x, y, sx, sy, w, h, dw, dh, bpp, color, len; + op = new Uint32Array(data, 0, 1); + switch (op[0]) { + case 0x0: + // BeginPaint + // this.log.debug('BeginPaint'); + this._ctxS(); + break; + case 0x01: + // EndPaint + // this.log.debug('EndPaint'); + this._ctxR(); + break; + case 0x02: + // Single bitmap + // + // 0 uint32 Destination X + // 1 uint32 Destination Y + // 2 uint32 Width + // 3 uint32 Height + // 4 uint32 Destination Width + // 5 uint32 Destination Height + // 6 uint32 Bits per Pixel + // 7 uint32 Flag: Compressed + // 8 uint32 DataSize + // + hdr = new Uint32Array(data, 4, 9); + bmdata = new Uint8Array(data, 40); + x = hdr[0]; + y = hdr[1]; + w = hdr[2]; + h = hdr[3]; + dw = hdr[4]; + dh = hdr[5]; + bpp = hdr[6]; + compressed = (hdr[7] != 0); + len = hdr[8]; + if ((bpp == 16) || (bpp == 15)) { + if (this._ckclp(x, y) && this._ckclp(x + dw, y + dh)) { + // this.log.debug('BMi:',(compressed ? ' C ' : ' U '),' x=',x,'y=',y,' w=',w,' h=',h,' l=',len); + var outB = this.cctx.createImageData(w, h); + if (compressed) { + webrdp.dRLE16_RGBA(bmdata, len, w, outB.data); + webrdp.flipV(outB.data, w, h); + } else { + webrdp.dRGB162RGBA(bmdata, len, outB.data); + } + this.cctx.putImageData(outB, x, y, 0, 0, dw, dh); + } else { + // this.log.debug('BMc:',(compressed ? ' C ' : ' U '),' x=',x,'y=',y,' w=',w,' h=',h,' bpp=',bpp); + // putImageData ignores the clipping region, so we must + // clip ourselves: We first paint into a second canvas, + // then use drawImage (which honors clipping). + + var outB = this.bctx.createImageData(w, h); + if (compressed) { + webrdp.dRLE16_RGBA(bmdata, len, w, outB.data); + webrdp.flipV(outB.data, w, h); + } else { + webrdp.dRGB162RGBA(bmdata, len, outB.data); + } + this.bctx.putImageData(outB, 0, 0, 0, 0, dw, dh); + this.cctx.drawImage(this.bstore, 0, 0, dw, dh, x, y, dw, dh); + } + } else { + this.log.warn('BPP <> 15/16 not yet implemented'); + } + break; + case 0x03: + // Primary: OPAQUE_RECT_ORDER + // x, y , w, h, color + hdr = new Int32Array(data, 4, 4); + rgba = new Uint8Array(data, 20, 4); + // this.log.debug('Fill:',hdr[0], hdr[1], hdr[2], hdr[3], this._c2s(rgba)); + this.cctx.fillStyle = this._c2s(rgba); + this.cctx.fillRect(hdr[0], hdr[1], hdr[2], hdr[3]); + break; + case 0x04: + // SetBounds + // left, top, right, bottom + hdr = new Int32Array(data, 4, 4); + this._cR(hdr[0], hdr[1], hdr[2] - hdr[0], hdr[3] - hdr[1], true); + break; + case 0x05: + // PatBlt + if (28 == data.byteLength) { + // Solid brush style + // x, y, width, height, fgcolor, rop3 + hdr = new Int32Array(data, 4, 4); + x = hdr[0]; + y = hdr[1]; + w = hdr[2]; + h = hdr[3]; + rgba = new Uint8Array(data, 20, 4); + this._ctxS(); + this._cR(x, y, w, h, false); + if (this._sROP(new Uint32Array(data, 24, 1)[0])) { + this.cctx.fillStyle = this._c2s(rgba); + this.cctx.fillRect(x, y, w, h); + } + this._ctxR(); + } else { + this.log.warn('PatBlt: Patterned brush not yet implemented'); + } + break; + case 0x06: + // Multi Opaque rect + // color, nrects + // rect1.x,rect1.y,rect1.w,rect1.h ... rectn.x,rectn.y,rectn.w,rectn.h + rgba = new Uint8Array(data, 4, 4); + count = new Uint32Array(data, 8, 1); + rects = new Uint32Array(data, 12, count[0] * 4); + // this.log.debug('MultiFill: ', count[0], " ", this._c2s(rgba)); + this.cctx.fillStyle = this._c2s(rgba); + offs = 0; + // var c = this._c2s(rgba); + for (i = 0; i < count[0]; ++i) { + this.cctx.fillRect(rects[offs], rects[offs+1], rects[offs+2], rects[offs+3]); + // this._fR(rects[offs], rects[offs+1], rects[offs+2], rects[offs+3], c); + offs += 4; + } + break; + case 0x07: + // ScrBlt + // rop3, x, y, w, h, sx, sy + hdr = new Int32Array(data, 8, 6); + x = hdr[0]; + y = hdr[1]; + w = hdr[2]; + h = hdr[3]; + sx = hdr[4]; + sy = hdr[5]; + if ((w > 0) && (h > 0)) { + if (this._sROP(new Uint32Array(data, 4, 1)[0])) { + if (this._ckclp(x, y) && this._ckclp(x + w, y + h)) { + // No clipping necessary + this.cctx.putImageData(this.cctx.getImageData(sx, sy, w, h), x, y); + } else { + // Clipping necessary + this.bctx.putImageData(this.cctx.getImageData(sx, sy, w, h), 0, 0); + this.cctx.drawImage(this.bstore, 0, 0, w, h, x, y, w, h); + } + } + } else { + this.log.warn('ScrBlt: width and/or height is zero'); + } + break; + case 0x08: + // PTR_NEW + // id, xhot, yhot + hdr = new Uint32Array(data, 4, 3); + var inline_cursor_base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(data, 16))); + if (this.cssC) { + this.cursors[hdr[0]] = (this.msie > 0 || this.trident > 0) ? 'url(/cur/' + this.sid + '/' + hdr[0] + '), none' : //IE is not suporting given hot spots + 'url(data:image/vnd.microsoft.icon;base64,' + inline_cursor_base64 + ') ' + hdr[1] + ' ' + hdr[2] + ',default'; + } else { + this.cursors[hdr[0]] = (this.msie > 0 || this.trident > 0) ? { u: '/cur/' + this.sid + '/' + hdr[0] } : + { u: inline_cursor_base64, x: hdr[1], y: hdr[2] }; + } + break; + case 0x09: + // PTR_FREE + // id + this.cursors[new Uint32Array(data, 4, 1)[0]] = undefined; + break; + case 0x0a: + // PTR_SET + // id + // this.log.debug('PS:', this.cursors[new Uint32Array(data, 4, 1)[0]]); + if (this.cssC) { + if(this.textAreaInput) + this.textAreaInput.setStyle('cursor', this.cursors[new Uint32Array(data, 4, 1)[0]]); + } else { + var cobj = this.cursors[new Uint32Array(data, 4, 1)[0]]; + this.chx = cobj.x; + this.chy = cobj.y; + this.cI.src = cobj.u; + } + break; + case 0x0b: + // PTR_SETNULL + if (this.cssC) { + if(this.textAreaInput) + this.textAreaInput.setStyle('cursor', 'none'); + } else { + this.cI.src = '/c_none.png'; + } + break; + case 0x0c: + // PTR_SETDEFAULT + if (this.cssC) { + if(this.textAreaInput) + this.textAreaInput.setStyle('cursor', 'default'); + } else { + this.chx = 10; + this.chy = 10; + this.cI.src = '/c_default.png'; + } + break; + + // our draft protocol implementation follows + case 0x0d: + /* clipboard_send_formats_available + * this message contain list of clipboard format on server + * available for fetching + * + * typedef enum + * { + * clip_format_unsupported = -1, + * clip_format_raw, + * clip_format_text, + * clip_format_FileGroupDescriptorW + * }wrdp_enum_clip_format; + * NOTE: "wrdp_enum_clip_format" must be kept in sync with + * core api + * + */ + { + // console.log(data.toHexdump()); + var fmts = new Uint8Array(data, 4); + this.cbd.ClipbrdInfoParse(fmts); + } + break; + case 0x0e: + // clipboard_send_data + // this message contain actual clipboard data + // NOTE: not all clipboard formats will support data + // fetching + { + // console.log(data.toHexdump()); + this.cbd.reciveClipboardInfo(data); + } + break; + case 0x0f: + // clipboard_request_data + // local clipboard data requested + { + // console.log(data.toHexdump()); + var type = new Uint8Array(data, 4, 1); + this.cbd.sendClipboardInfo(type[0]); + } + break; + case 0x10: + /* ft_request + * this is filetransfer request + * must contain file id from cached list + */ + { + // console.log(data.toHexdump()); + var file_id = new Uint32Array(data, 4, 1)[0]; + var req_size = new BigUint64Array(data, 4 + 4, 1)[0]; + var file_offset = new BigUint64Array(data, 4 + 4 + 8, 1)[0]; + file = this.cbd.filelistOut[file_id]; + if (!file) { + console.log("Can`t find file for transfer") + return; + } + + file.sendChunk(req_size, file_offset); + } + break; + case 0x11: + // ft_chunk + // this message contain transfer id and chunk of file data + { + // console.log(data.toHexdump()) + var transfer_id = new Uint32Array(data,0,2)[1]; + var file = null; + this.cbd.filelistIn.forEach(function(f) { + if (transfer_id == f.transfer_id) { + file = f + } + }); + if (!file) { + this.cbd.filelistIn.forEach(function(f) { + if (f.status == 2) { + file = f + } + }); + } + if (file) { + file.newChunk(data); + } + } + break; + case 0x12: + // ft_finish + // this message indicate what filetransfer is finished + { + // console.log(data.toHexdump()); + this.cbd.update(); + } + break; + default: + this.log.warn('Unknown BINRESP: ', data.byteLength); + } + }, + _cR: function(x, y, w, h, save) { + if (save) { + this.clx = x; + this.cly = y; + this.clw = w; + this.clh = h; + } + // Replace clipping region, NO intersection. + this.cctx.beginPath(); + this.cctx.rect(0, 0, this.canvas.width, this.canvas.height); + this.cctx.clip(); + if (x == y == 0) { + // All zero means: reset to full canvas size + if ((w == h == 0) || ((w == this.canvas.width) && (h == this.canvas.height))) { + return; + } + } + // New clipping region + this.cctx.beginPath(); + this.cctx.rect(x, y, w, h); + this.cctx.clip(); + }, + _fR: function(x, y, w, h, color) { + return; + if ((w < 2) || (h < 2)) { + this.cctx.strokeStyle = color; + this.cctx.beginPath(); + this.cctx.moveTo(x, y); + if (w > h) { + this.cctx.lineWidth = h; + this.cctx.lineTo(x + w, y); + } else { + this.cctx.lineWidth = w; + this.cctx.lineTo(x, y + h); + } + this.cctx.stroke(); + } else { + this.cctx.fillStyle = color; + this.cctx.fillRect(x, y, w, h); + } + }, + _sROP: function(rop) { + switch (rop) { + case 0x005A0049: + // GDI_PATINVERT: D = P ^ D + this.cctx.globalCompositeOperation = 'xor'; + return true; + break; + case 0x00F00021: + // GDI_PATCOPY: D = P + this.cctx.globalCompositeOperation = 'copy'; + return true; + break; + case 0x00CC0020: + // GDI_SRCCOPY: D = S + this.cctx.globalCompositeOperation = 'source-over'; + return true; + break; + default: + this.log.warn('Unsupported raster op: ', rop.toString(16)); + break; + } + return false; + /* + case 0x00EE0086: + // GDI_SRCPAINT: D = S | D + break; + case 0x008800C6: + // GDI_SRCAND: D = S & D + break; + case 0x00660046: + // GDI_SRCINVERT: D = S ^ D + break; + case 0x00440328: + // GDI_SRCERASE: D = S & ~D + break; + case 0x00330008: + // GDI_NOTSRCCOPY: D = ~S + break; + case 0x001100A6: + // GDI_NOTSRCERASE: D = ~S & ~D + break; + case 0x00C000CA: + // GDI_MERGECOPY: D = S & P + break; + case 0x00BB0226: + // GDI_MERGEPAINT: D = ~S | D + break; + case 0x00FB0A09: + // GDI_PATPAINT: D = D | (P | ~S) + break; + case 0x00550009: + // GDI_DSTINVERT: D = ~D + break; + case 0x00000042: + // GDI_BLACKNESS: D = 0 + break; + case 0x00FF0062: + // GDI_WHITENESS: D = 1 + break; + case 0x00E20746: + // GDI_DSPDxax: D = (S & P) | (~S & D) + break; + case 0x00B8074A: + // GDI_PSDPxax: D = (S & D) | (~S & P) + break; + case 0x000C0324: + // GDI_SPna: D = S & ~P + break; + case 0x00220326: + // GDI_DSna D = D & ~S + break; + case 0x00220326: + // GDI_DSna: D = D & ~S + break; + case 0x00A000C9: + // GDI_DPa: D = D & P + break; + case 0x00A50065: + // GDI_PDxn: D = D ^ ~P + break; + */ + }, + /** + * Reset our state to disconnected + */ + _reset: function() { + this.log.setWS(null); + this.fireEvent('disconnected'); + if (this.sock.readyState == this.sock.OPEN) { + this.sock.close(); + } + this.clx = 0; + this.cly = 0; + this.clw = 0; + this.clh = 0; + this.canvas.removeEvents(); + document.removeEvents(); + var drop_zone = document.getElementById('drop_zone'); + if (drop_zone) { + document.body.removeChild(drop_zone); + } + + try{ + this.textAreaInput.remove(); + } + catch(err){ + } + this.textAreaInput = null; + while (this.ccnt > 0) { + this.cctx.restore(); + this.ccnt -= 1; + } + this.cctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + document.title = document.title.replace(/:.*/, ': offline'); + if (this.cssC) { + this.canvas.setStyle('cursor','default'); + } else { + this.cI.src = '/c_default.png'; + } + if (!this.cssC) { + this.cI.removeEvents(); + this.cI.destroy(); + } + }, + fT: function() { + delete this.fTid; + if (this.pT) { + this.fireEvent('touch' + this.pT); + this.pT = 0; + return; + } + if (this.pTe) { + this.onMd(this.pTe); + this.pTe = null; + } + }, + cT: function() { + this.log.debug('cT'); + this.Tcool = true; + }, + /** + * Event handler for touch start + */ + onTs: function(evt) { + var tn = evt.targetTouches.length; + this.log.debug('Ts:', tn); + switch (tn) { + default: + break; + case 1: + this.pTe = evt; + evt.preventDefault(); + if ('number' == typeof(this.fTid)) { + clearTimeout(this.fTid); + } + this.fTid = this.fT.delay(50, this); + break; + case 2: + this.pT = 2; + this.Tcool = false; + evt.preventDefault(); + if ('number' == typeof(this.fTid)) { + clearTimeout(this.fTid); + } + this.cT.delay(500, this) + this.fTid = this.fT.delay(50, this); + break; + case 3: + this.pT = 3; + this.Tcool = false; + evt.preventDefault(); + if ('number' == typeof(this.fTid)) { + clearTimeout(this.fTid); + } + this.cT.delay(500, this) + this.fTid = this.fT.delay(50, this); + break; + case 4: + this.pT = 4; + this.Tcool = false; + evt.preventDefault(); + if ('number' == typeof(this.fTid)) { + clearTimeout(this.fTid); + } + this.cT.delay(500, this) + this.fTid = this.fT.delay(50, this); + break; + } + return true; + }, + /** + * Event handler for touch start + */ + onTe: function(evt) { + if ((0 == evt.targetTouches.length) && this.Tcool) { + evt.preventDefault(); + this.onMu(evt, evt.changedTouches[0].pageX, evt.changedTouches[0].pageY); + } + }, + /** + * Event handler for touch move + */ + onTm: function(evt) { + // this.log.debug('Tm:', evt); + if (1 == evt.targetTouches.length) { + this.onMm(evt); + } + }, + /** + * Event handler for mouse move events + */ + onMm: function(evt) { + var buf, a, x, y; + evt.preventDefault(); + x = (this.msie > 0 || this.trident > 0) ? evt.event.layerX - evt.event.currentTarget.offsetLeft : evt.event.layerX; + y = (this.msie > 0 || this.trident > 0) ? evt.event.layerY - evt.event.currentTarget.offsetTop : evt.event.layerY; + if (!this.cssC) { + this.mX = x; + this.mY = y; + this.cP(); + } + // this.log.debug('mM x: ', x, ' y: ', y); + if (this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(16); + a = new Uint32Array(buf); + a[0] = 0; // WSOP_CS_MOUSE + a[1] = 0x0800; // PTR_FLAGS_MOVE + a[2] = x; + a[3] = y; + this.sock.send(buf); + } + }, + /** + * Event handler for mouse down events + */ + onMd: function(evt) { + var buf, a, x, y, which; + this.textAreaInput.focus(); + this.cbd.update(); + if (this.Tcool) { + if(evt.preventDefault) evt.preventDefault(); + if(evt.stopPropagation) evt.stopPropagation(); + if (evt.rightClick && evt.control && evt.alt) { + this.fireEvent('touch3'); + return; + } + x = (this.msie > 0 || this.trident > 0) ? evt.event.layerX - evt.event.currentTarget.offsetLeft : evt.event.layerX; + y = (this.msie > 0 || this.trident > 0) ? evt.event.layerY - evt.event.currentTarget.offsetTop : evt.event.layerY; + which = this._mB(evt); + //this.log.debug('mD b: ', which, ' x: ', x, ' y: ', y); + if (this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(16); + a = new Uint32Array(buf); + a[0] = 0; // WSOP_CS_MOUSE + a[1] = 0x8000 | which; + a[2] = x; + a[3] = y; + this.sock.send(buf); + this.mouseDownStatus[which] = true; + } + } + }, + /** + * Event handler for mouse up events + */ + onMu: function(evt, x, y) { + var buf, a, x, y, which; + if (this.Tcool) { + evt.preventDefault(); + x = (this.msie > 0 || this.trident > 0) ? evt.event.layerX - evt.event.currentTarget.offsetLeft : evt.event.layerX; + y = (this.msie > 0 || this.trident > 0) ? evt.event.layerY - evt.event.currentTarget.offsetTop : evt.event.layerY; + which = this._mB(evt); + this.log.debug('mU b: ', which, ' x: ', x, ' y: ', y); + if (this.aMF) { + this.fireEvent('mouserelease'); + } + if (this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(16); + a = new Uint32Array(buf); + a[0] = 0; // WSOP_CS_MOUSE + a[1] = which; + a[2] = x; + a[3] = y; + this.sock.send(buf); + this.mouseDownStatus[which] = false; + } + } + }, + /** + * Event handler for mouse wheel events + */ + onMw: function(evt) { + var buf, a, x, y; + evt.preventDefault(); + x = (this.msie > 0 || this.trident > 0) ? evt.event.layerX - evt.event.currentTarget.offsetLeft : evt.event.layerX; + y = (this.msie > 0 || this.trident > 0) ? evt.event.layerY - evt.event.currentTarget.offsetTop : evt.event.layerY; + // this.log.debug('mW d: ', evt.wheel, ' x: ', x, ' y: ', y); + if (this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(16); + a = new Uint32Array(buf); + a[0] = 0; // WSOP_CS_MOUSE + a[1] = 0x200 | ((evt.wheel > 0) ? 0x087 : 0x188); + a[2] = 0; + a[3] = 0; + this.sock.send(buf); + } + }, + /** + * Field used to keep the states of the sent mouse events + */ + mouseDownStatus: {}, + /** + * Event handler for mouse leaving the canvas area + * used to send mouse release for any unsent mouse releases + */ + onMouseLeave: function(evt){ + for(var button in this.mouseDownStatus){ + if(this.mouseDownStatus[button]){ + var x = (this.msie > 0 || this.trident > 0) ? evt.event.layerX - evt.event.currentTarget.offsetLeft : evt.event.layerX; + var y = (this.msie > 0 || this.trident > 0) ? evt.event.layerY - evt.event.currentTarget.offsetTop : evt.event.layerY; + var maxX = $('textareainput').getStyle('width').toInt(); + var maxY = $('textareainput').getStyle('height').toInt(); + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x > maxX) x = maxX; + if (y > maxY) y = maxY; + var which = button; + if (this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(16); + a = new Uint32Array(buf); + a[0] = 0; // WSOP_CS_MOUSE + a[1] = which; + a[2] = x; + a[3] = y; + this.sock.send(buf); + this.mouseDownStatus[which] = false; + } + } + } + }, + /** + * Event handler for sending array of keys to be pressed + */ + sendKeys: function(codes) { + // var myStringArray = ["Hello","World"]; + for (var i = 0; i < codes.length; i++) { + alert(codes[i]); + if(this.sock.readyState == this.sock.OPEN) { + buf = new ArrayBuffer(12); + + } + } + }, + /** + * Sends a unicode char or string + */ + SendUnicodeString: function(str){ + var len = str.length; + buf = new ArrayBuffer(4 * len + 4); + a = new Uint32Array(buf); + a[0] = 5; // WSOP_CS_UNICODE + for(var i = 0; i> 11; + var pelG = (pel & 0x7E0) >> 5; + var pelB = pel & 0x1F; + // 656 -> 888 + pelR = (pelR << 3 & ~0x7) | (pelR >> 2); + pelG = (pelG << 2 & ~0x3) | (pelG >> 4); + pelB = (pelB << 3 & ~0x7) | (pelB >> 2); + + outA[outI++] = inA[inI++] ^ pelR; + outA[outI++] = inA[inI++] ^ pelG; + outA[outI++] = inA[inI] ^ pelB; + outA[outI] = 255; // alpha +} +webrdp.buf2RGBA = function(inA, inI, outA, outI) { + var pel = inA[inI] | (inA[inI + 1] << 8); + var pelR = (pel & 0xF800) >> 11; + var pelG = (pel & 0x7E0) >> 5; + var pelB = pel & 0x1F; + // 656 -> 888 + pelR = (pelR << 3 & ~0x7) | (pelR >> 2); + pelG = (pelG << 2 & ~0x3) | (pelG >> 4); + pelB = (pelB << 3 & ~0x7) | (pelB >> 2); + + outA[outI++] = pelR; + outA[outI++] = pelG; + outA[outI++] = pelB; + outA[outI] = 255; // alpha +} +webrdp.pel2RGBA = function (pel, outA, outI) { + var pelR = (pel & 0xF800) >> 11; + var pelG = (pel & 0x7E0) >> 5; + var pelB = pel & 0x1F; + // 656 -> 888 + pelR = (pelR << 3 & ~0x7) | (pelR >> 2); + pelG = (pelG << 2 & ~0x3) | (pelG >> 4); + pelB = (pelB << 3 & ~0x7) | (pelB >> 2); + + outA[outI++] = pelR; + outA[outI++] = pelG; + outA[outI++] = pelB; + outA[outI] = 255; // alpha +} + +webrdp.flipV = function(inA, width, height) { + var sll = width * 4; + var half = height / 2; + var lbot = sll * (height - 1); + var ltop = 0; + var tmp = new Uint8Array(sll); + var i, j; + if ('subarray' in inA) { + for (i = 0; i < half ; ++i) { + tmp.set(inA.subarray(ltop, ltop + sll)); + inA.set(inA.subarray(lbot, lbot + sll), ltop); + inA.set(tmp, lbot); + ltop += sll; + lbot -= sll; + } + } else { + for (i = 0; i < half ; ++i) { + for (j = 0; j < sll; ++j) { + tmp[j] = inA[ltop + j]; + inA[ltop + j] = inA[lbot + j]; + inA[lbot + j] = tmp[j]; + } + ltop += sll; + lbot -= sll; + } + } +} + +webrdp.dRGB162RGBA = function(inA, inLength, outA) { + var inI = 0; + var outI = 0; + while (inI < inLength) { + webrdp.buf2RGBA(inA, inI, outA, outI); + inI += 2; + outI += 4; + } +} + +webrdp.ExtractCodeId = function(bOrderHdr) { + var code; + switch (bOrderHdr) { + case 0xF0: + case 0xF1: + case 0xF6: + case 0xF8: + case 0xF3: + case 0xF2: + case 0xF7: + case 0xF4: + case 0xF9: + case 0xFA: + case 0xFD: + case 0xFE: + return bOrderHdr; + } + code = bOrderHdr >> 5; + switch (code) { + case 0x00: + case 0x01: + case 0x03: + case 0x02: + case 0x04: + return code; + } + return bOrderHdr >> 4; +} +webrdp.ExtractRunLength = function(code, inA, inI, advance) { + var runLength = 0; + var ladvance = 1; + switch (code) { + case 0x02: + runLength = inA[inI] & 0x1F; + if (0 == runLength) { + runLength = inA[inI + 1] + 1; + ladvance += 1; + } else { + runLength *= 8; + } + break; + case 0x0D: + runLength = inA[inI] & 0x0F; + if (0 == runLength) { + runLength = inA[inI + 1] + 1; + ladvance += 1; + } else { + runLength *= 8; + } + break; + case 0x00: + case 0x01: + case 0x03: + case 0x04: + runLength = inA[inI] & 0x1F; + if (0 == runLength) { + runLength = inA[inI + 1] + 32; + ladvance += 1; + } + break; + case 0x0C: + case 0x0E: + runLength = inA[inI] & 0x0F; + if (0 == runLength) { + runLength = inA[inI + 1] + 16; + ladvance += 1; + } + break; + case 0xF0: + case 0xF1: + case 0xF6: + case 0xF8: + case 0xF3: + case 0xF2: + case 0xF7: + case 0xF4: + runLength = inA[inI + 1] | (inA[inI + 2] << 8); + ladvance += 2; + break; + } + advance.val = ladvance; + return runLength; +} + +webrdp.WriteFgBgImage16toRGBA = function(outA, outI, rowDelta, bitmask, fgPel, cBits) { + var cmpMask = 0x01; + + while (cBits-- > 0) { + if (bitmask & cmpMask) { + webrdp.xorbufRGBAPel16(outA, outI - rowDelta, outA, outI, fgPel); + } else { + webrdp.copyRGBA(outA, outI - rowDelta, outA, outI); + } + outI += 4; + cmpMask <<= 1; + } + return outI; +} + +webrdp.WriteFirstLineFgBgImage16toRGBA = function(outA, outI, bitmask, fgPel, cBits) { + var cmpMask = 0x01; + + while (cBits-- > 0) { + if (bitmask & cmpMask) { + webrdp.pel2RGBA(fgPel, outA, outI); + } else { + webrdp.pel2RGBA(0, outA, outI); + } + outI += 4; + cmpMask <<= 1; + } + return outI; +} + +webrdp.dRLE16_RGBA = function(inA, inLength, width, outA) { + var runLength; + var code, pixelA, pixelB, bitmask; + var inI = 0; + var outI = 0; + var fInsertFgPel = false; + var fFirstLine = true; + var fgPel = 0xFFFFFF; + var rowDelta = width * 4; + var advance = {val: 0}; + + while (inI < inLength) { + if (fFirstLine) { + if (outI >= rowDelta) { + fFirstLine = false; + fInsertFgPel = false; + } + } + code = webrdp.ExtractCodeId(inA[inI]); + if (code == 0x00 || code == 0xF0) { + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + if (fFirstLine) { + if (fInsertFgPel) { + webrdp.pel2RGBA(fgPel, outA, outI); + outI += 4; + runLength -= 1; + } + while (runLength > 0) { + webrdp.pel2RGBA(0, outA, outI); + runLength -= 1; + outI += 4; + } + } else { + if (fInsertFgPel) { + webrdp.xorbufRGBAPel16(outA, outI - rowDelta, outA, outI, fgPel); + outI += 4; + runLength -= 1; + } + while (runLength > 0) { + webrdp.copyRGBA(outA, outI - rowDelta, outA, outI); + runLength -= 1; + outI += 4; + } + } + fInsertFgPel = true; + continue; + } + fInsertFgPel = false; + switch (code) { + case 0x01: + case 0xF1: + case 0x0C: + case 0xF6: + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + if (code == 0x0C || code == 0xF6) { + fgPel = inA[inI] | (inA[inI + 1] << 8); + inI += 2; + } + if (fFirstLine) { + while (runLength > 0) { + webrdp.pel2RGBA(fgPel, outA, outI); + runLength -= 1; + outI += 4; + } + } else { + while (runLength > 0) { + webrdp.xorbufRGBAPel16(outA, outI - rowDelta, outA, outI, fgPel); + runLength -= 1; + outI += 4; + } + } + break; + case 0x0E: + case 0xF8: + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + pixelA = inA[inI] | (inA[inI + 1] << 8); + inI += 2; + pixelB = inA[inI] | (inA[inI + 1] << 8); + inI += 2; + while (runLength > 0) { + webrdp.pel2RGBA(pixelA, outA, outI); + outI += 4; + webrdp.pel2RGBA(pixelB, outA, outI); + outI += 4; + runLength -= 1; + } + break; + case 0x03: + case 0xF3: + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + pixelA = inA[inI] | (inA[inI + 1] << 8); + inI += 2; + while (runLength > 0) { + webrdp.pel2RGBA(pixelA, outA, outI); + outI += 4; + runLength -= 1; + } + break; + case 0x02: + case 0xF2: + case 0x0D: + case 0xF7: + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + if (code == 0x0D || code == 0xF7) { + fgPel = inA[inI] | (inA[inI + 1] << 8); + inI += 2; + } + if (fFirstLine) { + while (runLength >= 8) { + bitmask = inA[inI++]; + outI = webrdp.WriteFirstLineFgBgImage16toRGBA(outA, outI, bitmask, fgPel, 8); + runLength -= 8; + } + } else { + while (runLength >= 8) { + bitmask = inA[inI++]; + outI = webrdp.WriteFgBgImage16toRGBA(outA, outI, rowDelta, bitmask, fgPel, 8); + runLength -= 8; + } + } + if (runLength > 0) { + bitmask = inA[inI++]; + if (fFirstLine) { + outI = webrdp.WriteFirstLineFgBgImage16toRGBA(outA, outI, bitmask, fgPel, runLength); + } else { + outI = webrdp.WriteFgBgImage16toRGBA(outA, outI, rowDelta, bitmask, fgPel, runLength); + } + } + break; + case 0x04: + case 0xF4: + runLength = webrdp.ExtractRunLength(code, inA, inI, advance); + inI += advance.val; + while (runLength > 0) { + webrdp.pel2RGBA(inA[inI] | (inA[inI + 1] << 8), outA, outI); + inI += 2; + outI += 4; + runLength -= 1; + } + break; + case 0xF9: + inI += 1; + if (fFirstLine) { + outI = webrdp.WriteFirstLineFgBgImage16toRGBA(outA, outI, 0x03, fgPel, 8); + } else { + outI = webrdp.WriteFgBgImage16toRGBA(outA, outI, rowDelta, 0x03, fgPel, 8); + } + break; + case 0xFA: + inI += 1; + if (fFirstLine) { + outI = webrdp.WriteFirstLineFgBgImage16toRGBA(outA, outI, 0x05, fgPel, 8); + } else { + outI = webrdp.WriteFgBgImage16toRGBA(outA, outI, rowDelta, 0x05, fgPel, 8); + } + break; + case 0xFD: + inI += 1; + webrdp.pel2RGBA(0xFFFF, outA, outI); + outI += 4; + break; + case 0xFE: + inI += 1; + webrdp.pel2RGBA(0, outA, outI); + outI += 4; + break; + } + } +} +/** + * Continuos refresh for the IMEhelper + */ +function refreshIMEhelper(){ + setTimeout(this.refreshIMEhelper,20); + //IME helper div + if(rdp.IMEon){ + $('IMEhelper').setStyle('visibility','visible'); + $('IMEhelper').set('html',$('textareainput').get('value')); + }else{ + $('IMEhelper').setStyle('visibility','hidden'); + } +} -- cgit v1.2.3