/// <summary> /// Decodes a <see cref="VncPixelFormat"/> from a <see cref="byte"/> array. /// </summary> /// <param name="buffer"> /// The <see cref="byte"/> array which contains the <see cref="VncPixelFormat"/> data. /// </param> /// <param name="offset"> /// The first index in the <paramref name="buffer"/> which contains the <see cref="VncPixelFormat"/> /// data. /// </param> /// <returns> /// A <see cref="VncPixelFormat"/> object. /// </returns> internal static VncPixelFormat Decode(byte[] buffer, int offset) { var bitsPerPixel = buffer[offset + 0]; var depth = buffer[offset + 1]; var isLittleEndian = buffer[offset + 2] == 0; var isPalettized = buffer[offset + 3] == 0; var redBits = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 4)); var greenBits = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 6)); var blueBits = BitsFromMax(VncUtility.DecodeUInt16BE(buffer, offset + 8)); var redShift = buffer[offset + 10]; var greenShift = buffer[offset + 11]; var blueShift = buffer[offset + 12]; return(new VncPixelFormat( bitsPerPixel, depth, redBits, redShift, greenBits, greenShift, blueBits, blueShift, isLittleEndian, isPalettized)); }
/// <summary> /// Writes a <see cref="VncRectangle"/> to the current position in the stream and advances the position within the stream by 8 bytes. /// </summary> /// <param name="region"> /// The <see cref="VncRectangle"/> to write to the stream. /// </param> public void SendRectangle(VncRectangle region) { var buffer = new byte[8]; VncUtility.EncodeUInt16BE(buffer, 0, (ushort)region.X); VncUtility.EncodeUInt16BE(buffer, 2, (ushort)region.Y); VncUtility.EncodeUInt16BE(buffer, 4, (ushort)region.Width); VncUtility.EncodeUInt16BE(buffer, 6, (ushort)region.Height); this.Send(buffer); }
void SendFramebufferUpdateRequest(bool incremental) { var p = new byte[10]; p[0] = (byte)3; p[1] = (byte)(incremental ? 1 : 0); VncUtility.EncodeUInt16BE(p, 2, (ushort)0); VncUtility.EncodeUInt16BE(p, 4, (ushort)0); VncUtility.EncodeUInt16BE(p, 6, (ushort)Framebuffer.Width); VncUtility.EncodeUInt16BE(p, 8, (ushort)Framebuffer.Height); _c.Send(p); }
/// <summary> /// 发送一个按键事件到VNC服务器,以指示已按下或释放了键。 /// </summary> /// <param name="keysym">The X11 keysym of the key. 按键对应的 ASCII。</param> /// <param name="pressed"><c>true</c> for a key press event, or <c>false</c> for a key release event.</param> public void SendKeyEvent(int keysym, bool pressed) { var p = new byte[8]; p[0] = (byte)4; p[1] = (byte)(pressed ? 1 : 0); VncUtility.EncodeUInt32BE(p, 4, (uint)keysym); if (IsConnected) { _c.Send(p); } }
private void SendFramebufferUpdateRequest(bool incremental, int x, int y, int width, int height) { var p = new byte[10]; p[0] = (byte)3; p[1] = (byte)(incremental ? 1 : 0); VncUtility.EncodeUInt16BE(p, 2, (ushort)x); VncUtility.EncodeUInt16BE(p, 4, (ushort)y); VncUtility.EncodeUInt16BE(p, 6, (ushort)width); VncUtility.EncodeUInt16BE(p, 8, (ushort)height); this.c.Send(p); }
/// <summary> /// Serializes this <see cref="VncPixelFormat"/> to a <see cref="byte"/> array. /// </summary> /// <param name="buffer"> /// The <see cref="byte"/> array to which to encode the <see cref="VncPixelFormat"/> object. /// </param> /// <param name="offset"> /// The first <see cref="byte"/> at which to store the <see cref="VncPixelFormat"/> data. /// </param> internal void Encode(byte[] buffer, int offset) { buffer[offset + 0] = (byte)this.BitsPerPixel; buffer[offset + 1] = (byte)this.BitDepth; buffer[offset + 2] = (byte)(this.IsLittleEndian ? 0 : 1); buffer[offset + 3] = (byte)(this.IsPalettized ? 0 : 1); VncUtility.EncodeUInt16BE(buffer, offset + 4, this.RedMax); VncUtility.EncodeUInt16BE(buffer, offset + 6, this.GreenMax); VncUtility.EncodeUInt16BE(buffer, offset + 8, this.BlueMax); buffer[offset + 10] = (byte)this.RedShift; buffer[offset + 11] = (byte)this.GreenShift; buffer[offset + 12] = (byte)this.BlueShift; }
internal void Encode(byte[] buffer, int offset) { buffer[offset + 0] = (byte)BitsPerPixel; buffer[offset + 1] = (byte)BitDepth; buffer[offset + 2] = (byte)(IsLittleEndian ? 0 : 1); buffer[offset + 3] = (byte)(IsPalettized ? 0 : 1); VncUtility.EncodeUInt16BE(buffer, offset + 4, (ushort)((1 << RedBits) - 1)); VncUtility.EncodeUInt16BE(buffer, offset + 6, (ushort)((1 << GreenBits) - 1)); VncUtility.EncodeUInt16BE(buffer, offset + 8, (ushort)((1 << BlueBits) - 1)); buffer[offset + 10] = (byte)RedShift; buffer[offset + 11] = (byte)GreenShift; buffer[offset + 12] = (byte)BlueShift; }
/// <summary> /// 向VNC服务端发送一个鼠标动作,点击鼠标按钮等 /// </summary> /// <param name="x">鼠标的X坐标。</param> /// <param name="y">鼠标的Y坐标。</param> /// <param name="pressedButtons"> /// A bit mask of pressed mouse buttons, in X11 convention: 1 is left, 2 is middle, and 4 is right. /// Mouse wheel scrolling is treated as a button event: 8 for up and 16 for down. /// </param> public void SendPointerEvent(int x, int y, int pressedButtons) { var p = new byte[6]; p[0] = (byte)5; p[1] = (byte)pressedButtons; VncUtility.EncodeUInt16BE(p, 2, (ushort)x); VncUtility.EncodeUInt16BE(p, 4, (ushort)y); if (IsConnected) { _c.Send(p); } }
/// <summary> /// Notifies the server that the local clipboard has changed. /// If you are implementing clipboard integration, use this to set the remote clipboard. /// </summary> /// <param name="data">The contents of the local clipboard.</param> public void SendLocalClipboardChange(string data) { Throw.If.Null(data, "data"); var bytes = VncStream.EncodeString(data); var p = new byte[8 + bytes.Length]; p[0] = (byte)6; VncUtility.EncodeUInt32BE(p, 4, (uint)bytes.Length); Array.Copy(bytes, 0, p, 8, bytes.Length); if (this.IsConnected) { this.c.Send(p); } }
/// <summary> /// Notifies the server that the local clipboard has changed. /// If you are implementing clipboard integration, use this to set the remote clipboard. /// </summary> /// <param name="data">The contents of the local clipboard.</param> public void SendLocalClipboardChange(string data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var bytes = VncStream.EncodeString(data); var p = new byte[8 + bytes.Length]; p[0] = (byte)6; VncUtility.EncodeUInt32BE(p, 4, (uint)bytes.Length); Array.Copy(bytes, 0, p, 8, bytes.Length); if (this.IsConnected) { this.c.Send(p); } }
/// <summary> /// Writes a <see cref="uint"/> in big endian encoding to the current position in the stream and advances the position within the stream by four bytes. /// </summary> /// <param name="value"> /// The <see cref="uint"/> to write to the stream. /// </param> public void SendUInt32BE(uint value) { this.Send(VncUtility.EncodeUInt32BE(value)); }
/// <summary> /// Writes a <see cref="ushort"/> in big endian encoding to the current position in the stream and advances the position within the stream by two bytes. /// </summary> /// <param name="value"> /// The <see cref="ushort"/> to write to the stream. /// </param> public void SendUInt16BE(ushort value) { this.Send(VncUtility.EncodeUInt16BE(value)); }
/// <summary> /// Reads a <see cref="uint"/> in big-endian encoding from the stream and advances the /// position within the stream by two bytes. /// </summary> /// <returns> /// The <see cref="uint"/> which was read from the stream. /// </returns> public uint ReceiveUInt32BE() { return(VncUtility.DecodeUInt32BE(this.Receive(4), 0)); }
/// <summary> /// Reads a <see cref="ushort"/> in big-endian encoding from the stream and advances the /// position within the stream by two bytes. /// </summary> /// <returns> /// The <see cref="ushort"/> which was read from the stream. /// </returns> public ushort ReceiveUInt16BE() { return(VncUtility.DecodeUInt16BE(this.Receive(2), 0)); }
void HandleFramebufferUpdate() { _c.ReceiveByte(); // padding var numRects = _c.ReceiveUInt16BE(); var rects = new List <VncRectangle>(); for (int i = 0; i < numRects; i++) { var r = _c.ReceiveRectangle(); int x = r.X, y = r.Y, w = r.Width, h = r.Height; VncStream.SanityCheck(w > 0 && w < 0x8000); VncStream.SanityCheck(h > 0 && h < 0x8000); int fbW = Framebuffer.Width, fbH = Framebuffer.Height, bpp = Framebuffer.PixelFormat.BytesPerPixel; var inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h; byte[] pixels; var encoding = (VncEncoding)_c.ReceiveUInt32BE(); switch (encoding) { case VncEncoding.Hextile: // KVM seems to avoid this now that I support Zlib. var background = new byte[bpp]; var foreground = new byte[bpp]; for (int ty = 0; ty < h; ty += 16) { int th = Math.Min(16, h - ty); for (int tx = 0; tx < w; tx += 16) { int tw = Math.Min(16, w - tx); var subencoding = _c.ReceiveByte(); pixels = AllocateFramebufferScratch(tw * th * bpp); if (0 != (subencoding & 1)) // raw { _c.Receive(pixels, 0, tw * th * bpp); if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } else { pixels = AllocateFramebufferScratch(tw * th * bpp); if (0 != (subencoding & 2)) { background = _c.Receive(bpp); } if (0 != (subencoding & 4)) { foreground = _c.Receive(bpp); } int ptr = 0; for (int pp = 0; pp < tw * th; pp++) { for (int pe = 0; pe < bpp; pe++) { pixels[ptr++] = background[pe]; } } int nsubrects = 0 != (subencoding & 8) ? _c.ReceiveByte() : 0; if (nsubrects > 0) { var subrectsColored = 0 != (subencoding & 16); for (int subrect = 0; subrect < nsubrects; subrect++) { var color = subrectsColored ? _c.Receive(bpp) : foreground; var srxy = _c.ReceiveByte(); var srwh = _c.ReceiveByte(); int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1; int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1; if (srx + srw > tw || sry + srh > th) { continue; } for (int py = 0; py < srh; py++) { for (int px = 0; px < srw; px++) { int off = bpp * ((py + sry) * tw + (px + srx)); for (int pe = 0; pe < bpp; pe++) { pixels[off + pe] = color[pe]; } } } } } lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } } break; case VncEncoding.CopyRect: var srcx = (int)_c.ReceiveUInt16BE(); var srcy = (int)_c.ReceiveUInt16BE(); if (srcx + w > fbW) { w = fbW - srcx; } if (srcy + h > fbH) { h = fbH - srcy; } if (w < 1 || h < 1) { continue; } pixels = AllocateFramebufferScratch(w * h * bpp); lock (Framebuffer.SyncRoot) { CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, Framebuffer.GetBuffer(), w, h); CopyToFramebuffer(x, y, w, h, pixels); } break; case VncEncoding.Raw: pixels = AllocateFramebufferScratch(w * h * bpp); _c.Receive(pixels, 0, w * h * bpp); if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.Zlib: int bytesDesired = w * h * bpp; int size = (int)_c.ReceiveUInt32BE(); VncStream.SanityCheck(size >= 0 && size < 0x10000000); VncUtility.AllocateScratch(size, ref _zlibScratch); _c.Receive(_zlibScratch, 0, size); _zlibMemoryStream.Position = 0; _zlibMemoryStream.Write(_zlibScratch, 0, size); _zlibMemoryStream.SetLength(size); _zlibMemoryStream.Position = 0; if (_zlibInflater == null) // Zlib has a two-byte header. { VncStream.SanityCheck(size >= 2); _zlibMemoryStream.Position = 2; _zlibInflater = new DeflateStream(_zlibMemoryStream, CompressionMode.Decompress, false); } pixels = AllocateFramebufferScratch(bytesDesired); for (int j = 0; j < bytesDesired;) { int count = 0; try { count = _zlibInflater.Read(pixels, j, bytesDesired - j); } catch (InvalidDataException) { VncStream.Require(false, "Bad data compressed.", VncFailureReason.UnrecognizedProtocolElement); } VncStream.Require(count > 0, "No data compressed.", VncFailureReason.UnrecognizedProtocolElement); j += count; } if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.PseudoDesktopSize: Framebuffer = new VncFramebuffer(Framebuffer.Name, w, h, Framebuffer.PixelFormat); continue; // Don't call OnFramebufferChanged for this one. default: VncStream.Require(false, "Unsupported encoding.", VncFailureReason.UnrecognizedProtocolElement); break; } rects.Add(new VncRectangle(x, y, w, h)); } if (rects.Count > 0) { OnFramebufferChanged(new FramebufferChangedEventArgs(rects)); } }
private byte[] AllocateFramebufferScratch(int bytes) { return(VncUtility.AllocateScratch(bytes, ref this.framebufferScratch)); }
private bool HandleFramebufferUpdate() { this.c.ReceiveByte(); // padding var numRects = this.c.ReceiveUInt16BE(); var rects = new List <VncRectangle>(); var encoding = VncEncoding.DesktopSize; for (int i = 0; i < numRects; i++) { var r = this.c.ReceiveRectangle(); int x = r.X, y = r.Y, w = r.Width, h = r.Height; VncStream.SanityCheck(w > 0 && w < 0x8000); VncStream.SanityCheck(h > 0 && h < 0x8000); int fbW = this.Framebuffer.Width, fbH = this.Framebuffer.Height, bpp = this.Framebuffer.PixelFormat.BytesPerPixel; var inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h; byte[] pixels; encoding = (VncEncoding)this.c.ReceiveUInt32BE(); switch (encoding) { case VncEncoding.Hextile: // KVM seems to avoid this now that I support Zlib. var background = new byte[bpp]; var foreground = new byte[bpp]; for (int ty = 0; ty < h; ty += 16) { int th = Math.Min(16, h - ty); for (int tx = 0; tx < w; tx += 16) { int tw = Math.Min(16, w - tx); var subencoding = this.c.ReceiveByte(); pixels = this.AllocateFramebufferScratch(tw * th * bpp); if ((subencoding & 1) != 0) { // raw this.c.Receive(pixels, 0, tw * th * bpp); if (inRange) { lock (this.Framebuffer.SyncRoot) { this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } else { pixels = this.AllocateFramebufferScratch(tw * th * bpp); if ((subencoding & 2) != 0) { background = this.c.Receive(bpp); } if ((subencoding & 4) != 0) { foreground = this.c.Receive(bpp); } int ptr = 0; for (int pp = 0; pp < tw * th; pp++) { for (int pe = 0; pe < bpp; pe++) { pixels[ptr++] = background[pe]; } } int nsubrects = (subencoding & 8) != 0 ? this.c.ReceiveByte() : 0; if (nsubrects > 0) { var subrectsColored = (subencoding & 16) != 0; for (int subrect = 0; subrect < nsubrects; subrect++) { var color = subrectsColored ? this.c.Receive(bpp) : foreground; var srxy = this.c.ReceiveByte(); var srwh = this.c.ReceiveByte(); int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1; int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1; if (srx + srw > tw || sry + srh > th) { continue; } for (int py = 0; py < srh; py++) { for (int px = 0; px < srw; px++) { int off = bpp * (((py + sry) * tw) + (px + srx)); for (int pe = 0; pe < bpp; pe++) { pixels[off + pe] = color[pe]; } } } } } lock (this.Framebuffer.SyncRoot) { this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } } break; case VncEncoding.CopyRect: var srcx = (int)this.c.ReceiveUInt16BE(); var srcy = (int)this.c.ReceiveUInt16BE(); if (srcx + w > fbW) { w = fbW - srcx; } if (srcy + h > fbH) { h = fbH - srcy; } if (w < 1 || h < 1) { continue; } pixels = this.AllocateFramebufferScratch(w * h * bpp); lock (this.Framebuffer.SyncRoot) { this.CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, this.Framebuffer.GetBuffer(), w, h); this.CopyToFramebuffer(x, y, w, h, pixels); } break; case VncEncoding.Raw: pixels = this.AllocateFramebufferScratch(w * h * bpp); this.c.Receive(pixels, 0, w * h * bpp); if (inRange) { lock (this.Framebuffer.SyncRoot) { this.CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.Zlib: int bytesDesired = w * h * bpp; int size = (int)this.c.ReceiveUInt32BE(); VncStream.SanityCheck(size >= 0 && size < 0x10000000); VncUtility.AllocateScratch(size, ref this.zlibScratch); this.c.Receive(this.zlibScratch, 0, size); pixels = Decompress(zlibScratch); if (inRange) { lock (this.Framebuffer.SyncRoot) { this.CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.PseudoDesktopSize: this.Framebuffer = new VncFramebuffer(this.Framebuffer.Name, w, h, this.Framebuffer.PixelFormat); continue; // Don't call OnFramebufferChanged for this one. default: VncStream.Require( false, "Unsupported encoding.", VncFailureReason.UnrecognizedProtocolElement); break; } rects.Add(new VncRectangle(x, y, w, h)); } if (rects.Count > 0) { this.OnFramebufferChanged(new FramebufferChangedEventArgs(rects)); } return(encoding != VncEncoding.DesktopSize); }
void NegotiateSecurity() { int count = ReceiveByte(); if (count == 0) { string message = ReceiveString().Trim('\0'); Require(false, message, VncFailureReason.ServerOfferedNoAuthenticationMethods); } var types = new List <VncSecurityType>(); for (int i = 0; i < count; i++) { types.Add((VncSecurityType)ReceiveByte()); } if (types.Contains(VncSecurityType.None)) { Send(new[] { (byte)VncSecurityType.None }); } else if (types.Contains(VncSecurityType.Vnc)) { if (_options.Password == null) { OnPasswordRequired(new PasswordRequiredEventArgs(_options)); Require(_options.Password != null, "Password required.", VncFailureReason.PasswordRequired); } Send(new[] { (byte)VncSecurityType.Vnc }); var challenge = Receive(16); var response = new byte[16]; var password = _options.Password; var key = new byte[8]; var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(password); try { Array.Copy(bytes, 0, key, 0, Math.Min(bytes.Length, key.Length)); for (int i = 0; i < key.Length; i++) { key[i] = ReverseBits(key[i]); } using (var des = new DESCryptoServiceProvider() { Key = key, Mode = CipherMode.ECB }) using (var encryptor = des.CreateEncryptor()) { encryptor.TransformBlock(challenge, 0, 16, response, 0); Send(response); } } finally { Array.Clear(bytes, 0, bytes.Length); Array.Clear(key, 0, key.Length); Array.Clear(response, 0, response.Length); } } else { Require(false, "No supported authentication methods.", VncFailureReason.NoSupportedAuthenticationMethods); } uint status = VncUtility.DecodeUInt32BE(Receive(4), 0); if (status != 0) { string message = ReceiveString().Trim('\0'); Require(false, message, VncFailureReason.AuthenticationFailed); } }