comparison VNCServer/VNCServer.cs @ 23:644a923bca98

Added FBGUI and VNCServer
author Ivo Smits <Ivo@UCIS.nl>
date Mon, 15 Apr 2013 02:04:36 +0200
parents
children 2ecb82eea559
comparison
equal deleted inserted replaced
22:5b14fed54a89 23:644a923bca98
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Drawing;
5 using System.Drawing.Drawing2D;
6 using System.Drawing.Imaging;
7 using System.IO;
8 using System.Net;
9 using System.Net.Sockets;
10 using System.Security.Cryptography;
11 using System.Text;
12 using System.Threading;
13 using System.Windows.Forms;
14 using UCIS.Net.HTTP;
15
16 namespace UCIS.VNCServer {
17 public class VNCServerManager : IFramebuffer {
18 private VNCFramebuffer fb;
19 private List<VNCServerConnection> clients = new List<VNCServerConnection>();
20 private VNCServer server;
21
22 public event MouseEventHandler MouseDown;
23 public event MouseEventHandler MouseMove;
24 public event MouseEventHandler MouseUp;
25 public event KeyEventHandler KeyDown;
26 public event KeyEventHandler KeyUp;
27
28 public VNCServerManager(int w, int h) : this(w, h, 5901) { }
29 public VNCServerManager(int w, int h, int p) {
30 fb = new VNCFramebuffer(w, h);
31 server = new VNCServer(p);
32 server.ClientConnected += delegate(object sender, VNCClientConnectedEventArgs e) {
33 e.Client.Framebuffer = fb;
34 e.Client.MouseDown += MouseDown;
35 e.Client.MouseMove += MouseMove;
36 e.Client.MouseUp += MouseUp;
37 e.Client.KeyDown += KeyDown;
38 e.Client.KeyUp += KeyUp;
39 e.Client.Disconnected += ClientDisconnected;
40 lock (clients) clients.Add(e.Client);
41 };
42 server.Listen();
43 }
44
45 private void ClientDisconnected(Object sender, EventArgs e) {
46 lock (clients) clients.Remove((VNCServerConnection)sender);
47 }
48
49 public void Close() {
50 server.Close();
51 foreach (VNCServerConnection c in clients.ToArray()) c.Close();
52 }
53
54 public int Width {
55 get { return fb.Width; }
56 }
57 public int Height {
58 get { return fb.Height; }
59 }
60 public void Clear() {
61 fb.Clear();
62 }
63 public void DrawImage(Image image, Rectangle srcrect, Point dest) {
64 fb.DrawImage(image, srcrect, dest);
65 }
66 public void DrawPixels(int[] bitmap, int bmwidth, Rectangle srcrect, Point dest) {
67 fb.DrawPixels(bitmap, bmwidth, srcrect, dest);
68 }
69 public void DrawPixels(IntPtr bitmap, int bmwidth, Rectangle srcrect, Point dest) {
70 fb.DrawPixels(bitmap, bmwidth, srcrect, dest);
71 }
72 public void CopyRectangle(Rectangle srcrect, Point dest) {
73 fb.CopyRectangle(srcrect, dest);
74 }
75 public void CopyRectangleTo(Rectangle srcrect, IFramebuffer destbuffer, Point destposition) {
76 fb.CopyRectangleTo(srcrect, destbuffer, destposition);
77 }
78
79 public void Resize(int w, int h) {
80 fb = new VNCFramebuffer(w, h);
81 foreach (VNCServerConnection c in clients) c.Framebuffer = fb;
82 }
83 }
84 public class VNCFramebufferUpdateEventArgs : EventArgs {
85 public VNCFramebuffer Framebuffer { get; private set; }
86 public Rectangle Area { get; private set; }
87 internal VNCFramebufferUpdateEventArgs(VNCFramebuffer fb, Rectangle a) {
88 this.Framebuffer = fb;
89 this.Area = a;
90 }
91 }
92 public class VNCFramebuffer : IFramebuffer {
93 public event EventHandler<VNCFramebufferUpdateEventArgs> Update;
94 internal Int32[] Framebuffer { get; private set; }
95 public int Width { get; private set; }
96 public int Height { get; private set; }
97 public VNCFramebuffer(int width, int height) {
98 if (width <= 0) throw new ArgumentOutOfRangeException("width");
99 if (height <= 0) throw new ArgumentOutOfRangeException("height");
100 this.Width = width;
101 this.Height = height;
102 this.Framebuffer = new Int32[width * height];
103 }
104 public void Clear() {
105 for (int i = 0; i < Width * Height; i++) Framebuffer[i] = 0;
106 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update;
107 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(0, 0, Width, Height)));
108 }
109 public unsafe void DrawImage(Image image, Rectangle srcrect, Point dest) {
110 if (srcrect.Width == 0 || srcrect.Height == 0) return;
111 fixed (int* fbptr = Framebuffer) {
112 using (Bitmap b = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppRgb, (IntPtr)fbptr)) {
113 using (Graphics g = Graphics.FromImage(b)) {
114 g.CompositingMode = CompositingMode.SourceCopy;
115 g.DrawImage(image, new Rectangle(dest, srcrect.Size), srcrect, GraphicsUnit.Pixel);
116 }
117 }
118 }
119 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update;
120 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(dest, srcrect.Size)));
121 }
122 public void DrawBitmap(Bitmap bitmap, Rectangle srcrect, Point dest) {
123 DrawImage(bitmap, srcrect, dest);
124 }
125 public unsafe void DrawPixels(int[] bitmap, int bmwidth, Rectangle srcrect, Point dest) {
126 fixed (int* bmp = bitmap) DrawPixels(bmp, bmwidth, srcrect, dest);
127 }
128 public unsafe void DrawPixels(IntPtr bitmap, int bmwidth, Rectangle srcrect, Point dest) {
129 DrawPixels((int*)bitmap, bmwidth, srcrect, dest);
130 }
131 public unsafe void DrawPixels(int* bitmap, int bmwidth, Rectangle srcrect, Point dest) {
132 if (srcrect.X < 0 || srcrect.Y < 0 || srcrect.Width < 0 || srcrect.Height < 0) throw new ArgumentOutOfRangeException("srcrect");
133 if (dest.X < 0 || dest.Y < 0 || dest.X + srcrect.Width > Width || dest.Y + srcrect.Height > Height) throw new ArgumentOutOfRangeException("dest");
134 if (srcrect.Width == 0 || srcrect.Height == 0) return;
135 int* bmin = bitmap + srcrect.Y * bmwidth + srcrect.X;
136 //Optionally detect regions that have actually changed. This produces many small regions which may slow down the Tight JPEG encoder (and ZLib based codecs)
137 //DrawChangedPixels(Framebuffer, dest.Y * Width + dest.X, bmin, srcrect.Width, srcrect.Height, bmwidth, dest.X, dest.Y);
138 //return;
139 fixed (int* fbptr = Framebuffer) {
140 int* bmout = fbptr + dest.Y * Width + dest.X;
141 for (int y = 0; y < srcrect.Height; y++) {
142 int* bminl = bmin + y * bmwidth;
143 int* bmoutl = bmout + y * Width;
144 for (int x = 0; x < srcrect.Width; x++) {
145 bmoutl[x] = bminl[x];
146 }
147 }
148 }
149 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update;
150 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(dest, srcrect.Size)));
151 }
152 private unsafe void DrawChangedPixels(int[] shadow, int shadowoffset, int* pixels, int width, int height, int bmwidth, int xoffset, int yoffset) {
153 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update;
154 if (eh == null) return;
155 int firstx = -1, lastx = -1, firsty = -1, lasty = -1;
156 for (int y = 0; y < height; y++) {
157 int firstxline = -1, lastxline = -1;
158 for (int x = 0; x < width; x++) {
159 if (shadow[shadowoffset] != *pixels) {
160 if (firstxline == -1) firstxline = x;
161 lastxline = x;
162 shadow[shadowoffset] = *pixels;
163 }
164 shadowoffset++;
165 pixels++;
166 }
167 shadowoffset += Width - width;
168 pixels += bmwidth - width;
169 if (firsty != -1 && firstxline == -1) {
170 eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(firstx + xoffset, firsty + yoffset, lastx - firstx + 1, lasty - firsty + 1)));
171 firsty = lasty = -1;
172 } else if (firstxline != -1) {
173 if (firsty == -1) {
174 firsty = y;
175 firstx = firstxline;
176 lastx = lastxline;
177 } else {
178 if (firstxline < firstx) firstx = firstxline;
179 if (lastxline > lastx) lastx = lastxline;
180 }
181 lasty = y;
182 }
183 }
184 if (firsty != -1) {
185 eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(firstx + xoffset, firsty + yoffset, lastx - firstx + 1, lasty - firsty + 1)));
186 }
187 }
188 public void CopyRectangle(Rectangle srcrect, Point dest) {
189 DrawPixels(Framebuffer, Width, srcrect, dest);
190 }
191 public void CopyRectangleTo(Rectangle srcrect, IFramebuffer destbuffer, Point destposition) {
192 destbuffer.DrawPixels(Framebuffer, Width, srcrect, destposition);
193 }
194 }
195 struct RFBPixelFormat {
196 public Byte BitsPerPixel { get; set; }
197 public Byte ColorDepth { get; set; }
198 public Boolean BigEndian { get; set; }
199 public Boolean TrueColor { get; set; }
200 public UInt16 RedMax { get; set; }
201 public UInt16 GreenMax { get; set; }
202 public UInt16 BlueMax { get; set; }
203 public Byte RedShift { get; set; }
204 public Byte GreenShift { get; set; }
205 public Byte BlueShift { get; set; }
206 }
207 public class VNCClientConnectedEventArgs : EventArgs {
208 public VNCServer Server { get; private set; }
209 public EndPoint RemoteEndPoint { get; private set; }
210 public VNCServerConnection Client { get; private set; }
211 public Boolean Drop { get; set; }
212 public Boolean AllowNoAuthentication { get; set; }
213 public Boolean AllowPasswordAuthentication { get; set; }
214 public VNCClientConnectedEventArgs(VNCServer serv, VNCServerConnection c, EndPoint ep) {
215 this.Server = serv;
216 this.RemoteEndPoint = ep;
217 this.Client = c;
218 this.Drop = false;
219 this.AllowNoAuthentication = true;
220 this.AllowPasswordAuthentication = false;
221 }
222 }
223 public class VNCClientAuthenticationEventArgs : EventArgs {
224 public VNCServerConnection Client { get; private set; }
225 public Boolean Drop { get; set; }
226 public Boolean UsedPasswordAuthentication { get; internal set; }
227 public String DesktopName { get; set; }
228 internal Byte[] VNCAuthChallenge { private get; set; }
229 internal Byte[] VNCAuthResponse { private get; set; }
230 internal VNCClientAuthenticationEventArgs(VNCServerConnection c) {
231 this.Client = c;
232 this.Drop = false;
233 }
234 public Boolean CheckPassword(String password) {
235 return CheckPassword(Encoding.ASCII.GetBytes(password));
236 }
237 public Boolean CheckPassword(Byte[] password) {
238 Byte[] passwordtransform = new Byte[8];
239 for (int i = 0; i < 8 && i < password.Length; i++) {
240 Byte a = password[i], b = 0;
241 for (int j = 0; j < 8; j++) b |= (Byte)(((a >> (7 - j)) & 1) << j);
242 passwordtransform[i] = b;
243 }
244 byte[] check;
245 using (DES des = new DESCryptoServiceProvider()) {
246 des.Mode = CipherMode.ECB;
247 des.Padding = PaddingMode.None;
248 using (ICryptoTransform transform = des.CreateEncryptor(passwordtransform, null)) {
249 check = transform.TransformFinalBlock(VNCAuthChallenge, 0, 16);
250 }
251 }
252 for (int i = 0; i < 16; i++) if (VNCAuthResponse[i] != check[i]) return false;
253 return true;
254 }
255 }
256 public class VNCServer {
257 public event EventHandler<VNCClientConnectedEventArgs> ClientConnected;
258 public EndPoint LocalEndPoint { get; protected set; }
259 public Boolean Listening { get; protected set; }
260 private Socket socket = null;
261 public VNCServer() : this(null) { }
262 public VNCServer(int port) : this(new IPEndPoint(IPAddress.Any, port)) { }
263 public VNCServer(EndPoint ep) {
264 LocalEndPoint = ep;
265 }
266 public void Listen() {
267 if (LocalEndPoint == null) throw new ArgumentNullException("LocalEndPoint");
268 Listen(LocalEndPoint);
269 }
270 public void Listen(int port) {
271 Listen(new IPEndPoint(IPAddress.Any, port));
272 }
273 public virtual void Listen(EndPoint ep) {
274 if (Listening) throw new InvalidOperationException("The server is already listening");
275 socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Unspecified);
276 socket.Bind(ep);
277 socket.Listen(5);
278 LocalEndPoint = ep;
279 Listening = true;
280 socket.BeginAccept(AcceptCallback, socket);
281 }
282 public virtual void Close() {
283 if (!Listening) throw new InvalidOperationException("The server is not listening");
284 Listening = false;
285 socket.Close();
286 }
287 private void AcceptCallback(IAsyncResult ar) {
288 Socket socket = ar.AsyncState as Socket;
289 try {
290 Socket clientsock = socket.EndAccept(ar);
291 if (clientsock.ProtocolType == ProtocolType.Tcp) clientsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
292 ClientAccepted(new VNCServerConnection(clientsock));
293 } catch (SocketException ex) {
294 Debug.WriteLine(ex);
295 } catch (ObjectDisposedException ex) {
296 Debug.WriteLine(ex);
297 }
298 if (Listening) socket.BeginAccept(AcceptCallback, socket);
299 }
300 protected void ClientAccepted(VNCServerConnection client) {
301 VNCClientConnectedEventArgs clientargs = new VNCClientConnectedEventArgs(this, client, client.RemoteEndPoint);
302 if (ClientConnected != null) ClientConnected(this, clientargs);
303 if (clientargs.Drop) {
304 client.Close();
305 } else {
306 client.RunAsync(clientargs);
307 }
308 }
309 }
310 public class WebVNCServer : VNCServer {
311 private HTTPServer httpserver;
312 public WebVNCServer() : this(null) { }
313 public WebVNCServer(int port) : this(new IPEndPoint(IPAddress.Any, port)) { }
314 public WebVNCServer(EndPoint ep) : base(ep) {
315 httpserver = new HTTPServer();
316 httpserver.ContentProvider = new HTTPContentProviderFunction(HandleClient);
317 httpserver.ServeFlashPolicyFile = true;
318 }
319 public override void Listen(EndPoint ep) {
320 httpserver.Listen(ep);
321 }
322 public override void Close() {
323 httpserver.Dispose();
324 }
325 public void HandleClient(HTTPContext context) {
326 WebSocketPacketStream stream = new WebSocketPacketStream(context);
327 ClientAccepted(new VNCServerConnection(stream, context.Socket));
328 }
329 }
330 public interface IZLibCompressor {
331 byte[] Compress(Byte[] data, int offset, int count);
332 }
333 public delegate IZLibCompressor ZLibCompressorFactory();
334 public class VNCServerConnection {
335 VNCFramebuffer framebuffer = null;
336 List<Rectangle> dirtyrects = new List<Rectangle>();
337 int waitingforupdate = 0;
338 Rectangle waitingforupdaterect = Rectangle.Empty;
339 Int32[] SupportedEncodings = new Int32[] { };
340 MouseButtons mousebuttons = MouseButtons.None;
341 Boolean resized = false;
342 Thread worker = null;
343 Keys modifierKeys = Keys.None;
344 MemoryStream SendBuffer = null;
345 Stream socket;
346 Socket realsocket;
347 Int32 protover;
348 RFBPixelFormat pixelformat;
349 int jpegCounter = 0;
350 Rectangle blurryrect = Rectangle.Empty;
351 int blurryrecoveryline = 0;
352 Point mousePosition = new Point(-1, -1);
353 ZLibCompressorFactory ZLibFactory = null;
354
355 public int Width { get; private set; }
356 public int Height { get; private set; }
357 public Object Tag { get; set; }
358
359 public EndPoint RemoteEndPoint { get { return realsocket == null ? null : realsocket.RemoteEndPoint; } }
360 public VNCFramebuffer Framebuffer {
361 get { return framebuffer; }
362 set {
363 if (framebuffer != null) {
364 framebuffer.Update -= FBUpdate;
365 }
366 framebuffer = value;
367 if (value == null) return;
368 lock (dirtyrects) {
369 resized = true;
370 dirtyrects.Clear();
371 framebuffer.Update += FBUpdate;
372 }
373 FBUpdate(this, new VNCFramebufferUpdateEventArgs(value, new Rectangle(0, 0, framebuffer.Width, framebuffer.Height)));
374 }
375 }
376
377 public event MouseEventHandler MouseDown;
378 public event MouseEventHandler MouseMove;
379 public event MouseEventHandler MouseUp;
380 public event KeyEventHandler KeyDown;
381 public event KeyEventHandler KeyUp;
382
383 public event EventHandler Disconnected;
384
385 public event EventHandler UpdateRequested;
386 public event EventHandler WaitingForUpdate;
387
388 public event EventHandler<VNCClientAuthenticationEventArgs> ClientAuthentication;
389 public event EventHandler ConnectionComplete;
390
391 public VNCServerConnection(Socket client) : this(new NetworkStream(client, true), client) {
392 realsocket.SendBufferSize = 1024 * 1024;
393 }
394 public VNCServerConnection(Stream client) : this(client, null) { }
395 public VNCServerConnection(Stream client, Socket socket) {
396 this.socket = client;
397 this.realsocket = socket;
398 pixelformat = new RFBPixelFormat() {
399 BigEndian = false, BitsPerPixel = 32, ColorDepth = 24, TrueColor = true,
400 BlueMax = 255, BlueShift = 0, GreenMax = 255, GreenShift = 8, RedMax = 255, RedShift = 16
401 };
402 }
403
404 public void Close() {
405 socket.Close();
406 }
407
408 public void RunAsync(VNCClientConnectedEventArgs args) {
409 worker = new Thread(RunSafe);
410 worker.Start(args);
411 }
412 private void RunSafe(Object state) {
413 try {
414 RunProc((VNCClientConnectedEventArgs)state);
415 } catch (Exception ex) {
416 Console.Error.WriteLine(ex);
417 } finally {
418 try { socket.Close(); } catch (Exception ex) { Console.Error.WriteLine(ex); }
419 if (Disconnected != null) Disconnected(this, new EventArgs());
420 }
421 }
422 private void RunProc(VNCClientConnectedEventArgs connargs) {
423 Initialisation(connargs);
424 ReceiveLoop();
425 }
426
427 private void Initialisation(VNCClientConnectedEventArgs connargs) {
428 {
429 Byte[] protovbuf = Encoding.ASCII.GetBytes("RFB 003.008\n");
430 SendAll(protovbuf);
431 FlushSendBuffer();
432 protovbuf = ReceiveAll(12);
433 String protovs = Encoding.ASCII.GetString(protovbuf);
434 protover = int.Parse(protovs.Substring(4, 3)) * 1000 + int.Parse(protovs.Substring(8, 3));
435 }
436 //Console.WriteLine("Client protocol is {0} = {1}", protovs.TrimEnd('\n'), protover);
437 if (protover < 3003) throw new InvalidOperationException("Unsupported protocol version");
438 VNCClientAuthenticationEventArgs authargs = new VNCClientAuthenticationEventArgs(this);
439 if (protover >= 3007) {
440 if (connargs.AllowNoAuthentication && connargs.AllowPasswordAuthentication) {
441 SendAll(new Byte[] { 2, 1, 2 }); //2 security types, no security, VNC security
442 } else if (connargs.AllowNoAuthentication) {
443 SendAll(new Byte[] { 1, 1 }); //1 security type, none security
444 } else if (connargs.AllowPasswordAuthentication) {
445 SendAll(new Byte[] { 1, 2 }); //1 security type, VNC security
446 } else {
447 SendAll(new Byte[] { 0 }); //no security types, drop connection
448 throw new InvalidOperationException("No security types allowed");
449 }
450 FlushSendBuffer();
451 Byte[] sectype = ReceiveAll(1);
452 if (sectype[0] == 1 && connargs.AllowNoAuthentication) {
453 authargs.UsedPasswordAuthentication = false;
454 } else if (sectype[0] == 2 && connargs.AllowPasswordAuthentication) {
455 authargs.UsedPasswordAuthentication = true;
456 } else throw new InvalidOperationException("Unsupported security type");
457 } else if (protover == 3003) {
458 if (connargs.AllowNoAuthentication) {
459 SendUInt32(1); //Security type is none
460 authargs.UsedPasswordAuthentication = false;
461 } else if (connargs.AllowPasswordAuthentication) {
462 SendUInt32(2); //Security type is VNC security
463 authargs.UsedPasswordAuthentication = true;
464 } else {
465 SendUInt32(0); //no security types, drop connection
466 throw new InvalidOperationException("No security types allowed");
467 }
468 FlushSendBuffer();
469 } else {
470 throw new InvalidOperationException("Unsupported protocol version");
471 }
472 if (authargs.UsedPasswordAuthentication) {
473 Byte[] challenge = new Byte[16];
474 (new RNGCryptoServiceProvider()).GetBytes(challenge);
475 SendAll(challenge);
476 FlushSendBuffer();
477 authargs.VNCAuthChallenge = challenge;
478 authargs.VNCAuthResponse = ReceiveAll(16);
479 }
480 if (ClientAuthentication != null) ClientAuthentication(this, authargs);
481 if (authargs.Drop) {
482 SendUInt32(1); //Security not OK
483 FlushSendBuffer();
484 throw new Exception("Authentication rejected");
485 }
486 if (authargs.UsedPasswordAuthentication || protover >= 3008) SendUInt32(0); //Security OK
487 FlushSendBuffer();
488 Byte[] clientinit = ReceiveAll(1);
489 //Console.WriteLine("Shared = {0}", clientinit[0]);
490 {
491 VNCFramebuffer fb = framebuffer;
492 if (fb != null) {
493 Width = fb.Width;
494 Height = fb.Height;
495 } else {
496 Width = 1024;
497 Height = 768;
498 }
499 }
500 resized = false;
501 SendUInt16((UInt16)Width);
502 SendUInt16((UInt16)Height);
503 SendPixelFormat(pixelformat);
504 {
505 Byte[] desknamestr;
506 if (authargs.DesktopName == null) desknamestr = new Byte[0];
507 else desknamestr = Encoding.ASCII.GetBytes(authargs.DesktopName);
508 SendUInt32((UInt32)desknamestr.Length);
509 SendAll(desknamestr);
510 }
511 FlushSendBuffer();
512 if (ConnectionComplete != null) ConnectionComplete(this, new EventArgs());
513 }
514
515 private void ReceiveLoop() {
516 while (true) {
517 Byte mtype = ReceiveByte();
518 switch (mtype) {
519 case 0: //SetPixelFormat
520 ReceiveMessageSetPixelFormat();
521 break;
522 case 2: //SetEncodings
523 Byte[] b = ReceiveAll(3);
524 b = ReceiveAll(4 * ((b[1] << 8) | b[2]));
525 SupportedEncodings = new Int32[b.Length / 4];
526 for (int i = 0; i < b.Length; i += 4) SupportedEncodings[i / 4] = (b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3];
527 break;
528 case 3: //FramebufferUpdateRequest
529 b = ReceiveAll(9);
530 Rectangle r = new Rectangle((b[1] << 8) | b[2], (b[3] << 8) | b[4], (b[5] << 8) | b[6], (b[7] << 8) | b[8]);
531 SendQueuedRectangles(r, b[0] != 0);
532 break;
533 case 4: //KeyEvent
534 ReceiveMessageKeyboard();
535 break;
536 case 5: //PointerEvent
537 ReceiveMessageMouse();
538 break;
539 case 6: //ClientCutText
540 b = ReceiveAll(7);
541 ReceiveAll((b[3] << 24) | (b[4] << 16) | (b[5] << 8) | b[6]);
542 break;
543 default:
544 throw new InvalidOperationException("Received unknown message type, synchronization is lost");
545 }
546 }
547 }
548 private void ReceiveMessageSetPixelFormat() {
549 Byte[] b = ReceiveAll(3);
550 pixelformat = ReceivePixelFormat();
551 if (!pixelformat.TrueColor) {
552 //I don't want to use a pallette, so I cheat by sending a 8bpp "true color" pallette
553 pixelformat.TrueColor = true;
554 pixelformat.BigEndian = false;
555 pixelformat.RedShift = 0;
556 pixelformat.RedMax = 3;
557 pixelformat.GreenShift = 2;
558 pixelformat.GreenMax = 7;
559 pixelformat.BlueShift = 5;
560 pixelformat.BlueMax = 7;
561 lock (socket) {
562 SendUInt8(1); //SetColourMapEntries
563 SendUInt8(0); //Padding
564 SendUInt16(0); //First colour
565 SendUInt16(256); //Number of colours
566 for (UInt16 blue = 0; blue < 256; blue += 32) {
567 for (UInt16 green = 0; green < 256; green += 32) {
568 for (UInt16 red = 0; red < 256; red += 64) {
569 SendUInt16((UInt16)(red << 8));
570 SendUInt16((UInt16)(green << 8));
571 SendUInt16((UInt16)(blue << 8));
572 }
573 }
574 }
575 FlushSendBuffer();
576 }
577 }
578 }
579 private void ReceiveMessageKeyboard() {
580 Byte[] b = ReceiveAll(7);
581 Boolean down = b[0] != 0;
582 uint key = (uint)((b[3] << 24) | (b[4] << 16) | (b[5] << 8) | b[6]);
583 //Console.WriteLine("KeyEvent code=0x{0:x} down={1}", key, down);
584 Keys keyval = Keys.None;
585 //see: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
586 if (key >= 'A' && key <= 'Z') keyval = (Keys)(key + (int)Keys.A - 'A') | Keys.Shift;
587 else if (key >= 'a' && key <= 'z') keyval = (Keys)(key + (int)Keys.A - 'a');
588 else if (key >= '0' && key <= '9') keyval = (Keys)(key + (int)Keys.D0 - '0');
589 else if (key >= 0xffb0 && key <= 0xffb9) keyval = (Keys)(key + (int)Keys.NumPad0 - 0xffb0);
590 else if (key >= 0xffbe && key <= 0xffd5) keyval = (Keys)(key + (int)Keys.F1 - 0xffbe); //all the way to F35...
591 else switch (key) {
592 case 0xff08: keyval = Keys.Back; break;
593 case 0xff09: keyval = Keys.Tab; break;
594 case 0xff0a: keyval = Keys.LineFeed; break;
595 case 0xff0b: keyval = Keys.Clear; break;
596 case 0xff0d: keyval = Keys.Return; break;
597 case 0xff13: keyval = Keys.Pause; break;
598 case 0xff14: keyval = Keys.Scroll; break;
599 case 0xff15: keyval = Keys.None; break; //Sys req
600 case 0xff1b: keyval = Keys.Escape; break;
601 case 0xffff: keyval = Keys.Delete; break;
602 case 0xff50: keyval = Keys.Home; break;
603 case 0xff51: keyval = Keys.Left; break;
604 case 0xff52: keyval = Keys.Up; break;
605 case 0xff53: keyval = Keys.Right; break;
606 case 0xff54: keyval = Keys.Down; break;
607 case 0xff55: keyval = Keys.PageUp; break;
608 case 0xff56: keyval = Keys.PageDown; break;
609 case 0xff57: keyval = Keys.End; break;
610 case 0xff58: keyval = Keys.Home; break;
611 case 0xff60: keyval = Keys.Select; break;
612 case 0xff61: keyval = Keys.Print; break;
613 case 0xff62: keyval = Keys.Execute; break;
614 case 0xff63: keyval = Keys.Insert; break;
615 case 0xff65: keyval = Keys.None; break; //Undo
616 case 0xff66: keyval = Keys.None; break; //Redo
617 case 0xff67: keyval = Keys.Apps; break;
618 case 0xff68: keyval = Keys.BrowserSearch; break;
619 case 0xff69: keyval = Keys.Cancel; break;
620 case 0xff6a: keyval = Keys.Help; break;
621 case 0xff6b: keyval = Keys.Pause; break;
622 case 0xff7e: keyval = Keys.None; break; //Character set switch
623 case 0xff7f: keyval = Keys.NumLock; break;
624 case 0xff80: keyval = Keys.Space; break;
625 case 0xff89: keyval = Keys.Tab; break;
626 case 0xff8d: keyval = Keys.Enter; break;
627 case 0xff91: keyval = Keys.F1; break;
628 case 0xff92: keyval = Keys.F2; break;
629 case 0xff93: keyval = Keys.F3; break;
630 case 0xff94: keyval = Keys.F4; break;
631 case 0xff95: keyval = Keys.Home; break;
632 case 0xff96: keyval = Keys.Left; break;
633 case 0xff97: keyval = Keys.Up; break;
634 case 0xff98: keyval = Keys.Right; break;
635 case 0xff99: keyval = Keys.Down; break;
636 case 0xff9a: keyval = Keys.PageUp; break;
637 case 0xff9b: keyval = Keys.PageDown; break;
638 case 0xff9c: keyval = Keys.End; break;
639 case 0xff9d: keyval = Keys.Home; break;
640 case 0xff9e: keyval = Keys.Insert; break;
641 case 0xff9f: keyval = Keys.Delete; break;
642 case 0xffbd: keyval = Keys.None; break; //keypad equals
643 case 0xffaa: keyval = Keys.Multiply; break;
644 case 0xffab: keyval = Keys.Add; break;
645 case 0xffac: keyval = Keys.Separator; break;
646 case 0xffad: keyval = Keys.Subtract; break;
647 case 0xffae: keyval = Keys.Decimal; break;
648 case 0xffaf: keyval = Keys.Divide; break;
649 case 0xffe1: keyval = Keys.LShiftKey; break;
650 case 0xffe2: keyval = Keys.RShiftKey; break;
651 case 0xffe3: keyval = Keys.LControlKey; break;
652 case 0xffe4: keyval = Keys.RControlKey; break;
653 case 0xffe5: keyval = Keys.CapsLock; break;
654 case 0xffe6: keyval = Keys.CapsLock; break; //shift lock!?
655 case 0xffe7: keyval = Keys.None; break; //Left meta!?
656 case 0xffe8: keyval = Keys.None; break; //Right meta!?
657 case 0xffe9: keyval = Keys.LMenu; break;
658 case 0xffea: keyval = Keys.Menu; break; //right alt
659 case 0xffeb: keyval = Keys.LWin; break;
660 case 0xffec: keyval = Keys.RWin; break;
661 case 0xffed: keyval = Keys.None; break; //Left hyper
662 case 0xffee: keyval = Keys.None; break; //Right hyper
663 //Some X11 specific stuff
664 case 0x20: keyval = Keys.Space; break;
665 case 0x21: keyval = Keys.D1 | Keys.Shift; break; //!
666 case 0x22: keyval = Keys.OemQuotes | Keys.Shift; break; //double quotes
667 case 0x23: keyval = Keys.D3 | Keys.Shift; break; //number sign? #
668 case 0x24: keyval = Keys.D4 | Keys.Shift; break; //dollar
669 case 0x25: keyval = Keys.D5 | Keys.Shift; break; //percent
670 case 0x26: keyval = Keys.D7 | Keys.Shift; break; //ampersand
671 case 0x27: keyval = Keys.OemQuotes; break; //apostrophe
672 case 0x28: keyval = Keys.D9 | Keys.Shift; break; //parenleft
673 case 0x29: keyval = Keys.D0 | Keys.Shift; break; //parenright
674 case 0x2a: keyval = Keys.D8 | Keys.Shift; break; //askerisk
675 case 0x2b: keyval = Keys.Oemplus | Keys.Shift; break; //plus
676 case 0x2c: keyval = Keys.Oemcomma; break; //comma
677 case 0x2d: keyval = Keys.OemMinus; break; //minus
678 case 0x2e: keyval = Keys.OemPeriod; break; //period
679 case 0x2f: keyval = Keys.OemQuestion; break; //slash
680 //digits handled above
681 case 0x3a: keyval = Keys.OemSemicolon | Keys.Shift; break; //colon
682 case 0x3b: keyval = Keys.OemSemicolon; break; //semicolon
683 case 0x3c: keyval = Keys.Oemcomma | Keys.Shift; break; //less than
684 case 0x3d: keyval = Keys.Oemplus; break; //equals
685 case 0x3e: keyval = Keys.OemPeriod | Keys.Shift; break; //greater than
686 case 0x3f: keyval = Keys.OemQuestion | Keys.Shift; break; //question mark
687 case 0x40: keyval = Keys.D2 | Keys.Shift; break; //commercial at
688 //capital letters handled above
689 case 0x5b: keyval = Keys.OemOpenBrackets; break; //left square bracker
690 case 0x5c: keyval = Keys.OemBackslash; break; //backslash
691 case 0x5d: keyval = Keys.OemCloseBrackets; break; //right square bracker
692 case 0x5e: keyval = Keys.D6 | Keys.Shift; break; //CIRCUMFLEX ACCENT
693 case 0x5f: keyval = Keys.OemMinus | Keys.Shift; break; //underscore
694 case 0x60: keyval = Keys.Oemtilde; break; //grave accent
695 //small letters handled above
696 case 0x7b: keyval = Keys.OemOpenBrackets | Keys.Shift; break; //left curly bracket
697 case 0x7c: keyval = Keys.OemBackslash | Keys.Shift; break; //vertical line
698 case 0x7d: keyval = Keys.OemCloseBrackets | Keys.Shift; break; //right curly bracket
699 case 0x7e: keyval = Keys.Oemtilde | Keys.Shift; break; //tilde
700 //blah blah
701 //experimental:
702 case 0xfe03: keyval = Keys.RMenu; break; //Alt gr or XK_ISO_Level3_Shift
703 }
704 switch (keyval) {
705 case Keys.LShiftKey:
706 case Keys.RShiftKey:
707 case Keys.ShiftKey:
708 if (down) modifierKeys |= Keys.Shift; else modifierKeys &= ~Keys.Shift;
709 break;
710 case Keys.LControlKey:
711 case Keys.RControlKey:
712 case Keys.ControlKey:
713 if (down) modifierKeys |= Keys.Control; else modifierKeys &= ~Keys.Control;
714 break;
715 case Keys.LMenu:
716 case Keys.RMenu:
717 case Keys.Menu:
718 if (down) modifierKeys |= Keys.Alt; else modifierKeys &= ~Keys.Alt;
719 break;
720 }
721 keyval |= modifierKeys;
722 if (down && KeyDown != null) KeyDown(this, new KeyEventArgs(keyval));
723 else if (!down && KeyUp != null) KeyUp(this, new KeyEventArgs(keyval));
724 }
725 private void ReceiveMessageMouse() {
726 Byte[] b = ReceiveAll(5);
727 Point p = new Point((b[1] << 8) | b[2], (b[3] << 8) | b[4]);
728 MouseButtons mb = MouseButtons.None;
729 if ((b[0] & 1) != 0) mb |= MouseButtons.Left;
730 if ((b[0] & 2) != 0) mb |= MouseButtons.Middle;
731 if ((b[0] & 4) != 0) mb |= MouseButtons.Right;
732 if ((b[0] & 32) != 0) mb |= MouseButtons.XButton1;
733 if ((b[0] & 64) != 0) mb |= MouseButtons.XButton2;
734 int dd = 0;
735 if ((b[0] & 8) != 0) dd = 120;
736 if ((b[0] & 16) != 0) dd = -120;
737 //Console.WriteLine("PointerEvent x={0} y={1} buttons={2} delta={3}", p.X, p.Y, mb, dd);
738 foreach (MouseButtons mbi in Enum.GetValues(typeof(MouseButtons))) if ((mousebuttons & mbi) != 0 && (mb & mbi) == 0) if (MouseUp != null) MouseUp(this, new MouseEventArgs(mbi, 0, p.X, p.Y, 0));
739 if ((dd != 0 || mousePosition != p) && MouseMove != null) MouseMove(this, new MouseEventArgs(mb & mousebuttons, 0, p.X, p.Y, dd));
740 foreach (MouseButtons mbi in Enum.GetValues(typeof(MouseButtons))) if ((mousebuttons & mbi) == 0 && (mb & mbi) != 0) if (MouseDown != null) MouseDown(this, new MouseEventArgs(mbi, 0, p.X, p.Y, 0));
741 mousePosition = p;
742 mousebuttons = mb;
743 }
744
745 private void FBUpdate(Object sender, VNCFramebufferUpdateEventArgs e) {
746 if (e.Framebuffer != framebuffer) return;
747 Rectangle r = e.Area;
748 r.Intersect(new Rectangle(0, 0, e.Framebuffer.Width, e.Framebuffer.Height));
749 if (r.Width == 0 || r.Height == 0) return;
750 Boolean send;
751 lock (dirtyrects) {
752 for (int i = 0; i < dirtyrects.Count; i++) {
753 Rectangle r2 = dirtyrects[i];
754 if (r.IntersectsWith(r2)) {
755 dirtyrects.RemoveAt(i);
756 i = -1;
757 r = Rectangle.Union(r, r2);
758 }
759 }
760 dirtyrects.Add(r);
761 send = waitingforupdate > 0;
762 }
763 if (send) {
764 Interlocked.Decrement(ref waitingforupdate);
765 SendQueuedRectangles(waitingforupdaterect, false);
766 }
767 }
768
769 private void ClearIntersectingQueuedRectangles(Rectangle r) {
770 lock (dirtyrects) {
771 for (int i = 0; i < dirtyrects.Count; i++) {
772 Rectangle r2 = dirtyrects[i];
773 if (!r2.IntersectsWith(r)) continue;
774 dirtyrects.RemoveAt(i);
775 i--;
776 }
777 dirtyrects.TrimExcess();
778 }
779 }
780 private void SendQueuedRectangles(Rectangle r, Boolean incremental) {
781 lock (socket) {
782 if (resized) {
783 resized = false;
784 jpegCounter = 0;
785 VNCFramebuffer fb = framebuffer;
786 SendUInt8(0); //FramebufferUpdate
787 SendUInt8(0); //Padding
788 if (Array.IndexOf(SupportedEncodings, -223) == -1) {
789 Console.Error.WriteLine("VNC: Desktop size update not supported");
790 SendUInt16(fb == null ? (UInt16)1 : (UInt16)2); //Number of rectangles
791 int[] empty = new int[r.Width * r.Height];
792 SendFBRectangle(empty, new Rectangle(0, 0, r.Width, r.Height), r.Width);
793 ClearIntersectingQueuedRectangles(r);
794 blurryrect = Rectangle.Empty;
795 if (fb != null) SendFBRectangle(fb.Framebuffer, r, fb.Width);
796 } else {
797 if (fb != null) {
798 Width = fb.Width;
799 Height = fb.Height;
800 }
801 Console.Error.WriteLine("VNC: Sending desktop size update {0}x{1}", Width, Height);
802 SendUInt16(1); //Number of rectangles
803 SendUInt16(0);
804 SendUInt16(0);
805 SendUInt16((UInt16)Width);
806 SendUInt16((UInt16)Height);
807 SendUInt32(unchecked((UInt32)(-223))); //Encoding type
808 }
809 FlushSendBuffer();
810 } else {
811 if (UpdateRequested != null) UpdateRequested(this, new EventArgs());
812 VNCFramebuffer fb = framebuffer;
813 if (!incremental) {
814 jpegCounter = 0;
815 ClearIntersectingQueuedRectangles(r);
816 blurryrect = Rectangle.Empty;
817 SendUInt8(0); //FramebufferUpdate
818 SendUInt8(0); //Padding
819 SendUInt16(1); //Number of rectangles
820 SendFBRectangle(fb.Framebuffer, r, fb.Width);
821 } else { //incremental
822 List<Rectangle> sending = new List<Rectangle>();
823 lock (dirtyrects) {
824 if (dirtyrects.Count == 0) {
825 if (jpegCounter > 0) jpegCounter--;
826 } else {
827 if (jpegCounter < 10) jpegCounter++;
828 }
829 for (int i = 0; i < dirtyrects.Count; i++) {
830 Rectangle r2 = dirtyrects[i];
831 if (!r2.IntersectsWith(r)) continue;
832 dirtyrects.RemoveAt(i);
833 i--;
834 r2.Intersect(r);
835 sending.Add(r2);
836 }
837 dirtyrects.TrimExcess();
838 if (sending.Count == 0 && blurryrect.IsEmpty) {
839 Interlocked.Increment(ref waitingforupdate);
840 waitingforupdaterect = r;
841 }
842 }
843 if (sending.Count > 0 || !blurryrect.IsEmpty) {
844 SendUInt8(0); //FramebufferUpdate
845 SendUInt8(0); //Padding
846 SendUInt16((UInt16)(sending.Count + (blurryrect.IsEmpty ? 0 : 1))); //Number of rectangles
847 if (!blurryrect.IsEmpty) {
848 //The idea here is to use a lossless compression for a small area to "recover" textual/static content from the JPEG artifacts
849 //Only a small area is updated here each time because compressing a full frame takes too much CPU time
850 Rectangle fixrect = blurryrect;
851 if (blurryrecoveryline < fixrect.Top) blurryrecoveryline = fixrect.Top;
852 else if (blurryrecoveryline >= fixrect.Bottom) blurryrecoveryline = fixrect.Top;
853 fixrect.Intersect(new Rectangle(0, blurryrecoveryline, Int16.MaxValue, 10));
854 if (fixrect.IsEmpty) fixrect = blurryrect;
855 int oldjpeg = jpegCounter;
856 jpegCounter = 0;
857 SendFBRectangle(fb.Framebuffer, Rectangle.Intersect(fixrect, r), fb.Width);
858 jpegCounter = oldjpeg;
859 blurryrecoveryline = fixrect.Bottom;
860 if (fixrect.Top <= blurryrect.Top && fixrect.Bottom >= blurryrect.Top) {
861 blurryrect.Intersect(new Rectangle(0, fixrect.Bottom, Int16.MaxValue, Int16.MaxValue));
862 } else if (fixrect.Top <= blurryrect.Bottom && fixrect.Bottom >= blurryrect.Bottom) {
863 blurryrect.Intersect(new Rectangle(0, 0, fixrect.Top, Int16.MaxValue));
864 }
865 if (blurryrect.Height == 0) blurryrect = Rectangle.Empty;
866 }
867 foreach (Rectangle r2 in sending) {
868 SendFBRectangle(fb.Framebuffer, r2, fb.Width);
869 }
870 } else {
871 if (WaitingForUpdate != null) WaitingForUpdate(this, new EventArgs());
872 }
873 }
874 }
875 FlushSendBuffer();
876 }
877 }
878
879 private void SendFBRectangle(Int32[] fb, Rectangle r, Int32 fbwidth) {
880 r.Intersect(new Rectangle(0, 0, fbwidth, fb.Length / fbwidth));
881 r.Intersect(new Rectangle(0, 0, Width, Height));
882 Boolean sent = false;
883 foreach (Int32 enc in SupportedEncodings) {
884 switch (enc) {
885 case 0:
886 SendFBRectangleRaw(fb, r, fbwidth); sent = true; break;
887 case 2:
888 if (r.Height < 8) break;
889 SendFBRectangleRRE(fb, r, fbwidth); sent = true; break;
890 case 5:
891 if (r.Width < 16 || r.Height < 16) break;
892 SendFBRectangleHextile(fb, r, fbwidth); sent = true; break;
893 case 6:
894 sent = SendFBRectangleZLib(fb, r, fbwidth);
895 break;
896 case 7:
897 sent = SendFBRectangleTight(fb, r, fbwidth);
898 break;
899 }
900 if (sent) break;
901 }
902 if (!sent) SendFBRectangleRaw(fb, r, fbwidth);
903 }
904 private void SendFBRectangleHeader(Rectangle r, UInt32 encoding) {
905 SendUInt16((UInt16)r.X);
906 SendUInt16((UInt16)r.Y);
907 SendUInt16((UInt16)r.Width);
908 SendUInt16((UInt16)r.Height);
909 SendUInt32(encoding);
910 }
911 IZLibCompressor TightZLib = null;
912 private unsafe Boolean SendFBRectangleTight(Int32[] framebuffer, Rectangle r, Int32 fbwidth) {
913 if (jpegCounter > 3 && r.Width * r.Height > 100 * 100) {
914 SendFBRectangleHeader(r, 7);
915 SendUInt8(0x90); //Jpeg encoding
916 MemoryStream jpeg = new MemoryStream();
917 if (r.Width > 0 && r.Height > 0) {
918 fixed (int* fbptr = framebuffer) {
919 using (Bitmap bmp = new Bitmap(r.Width, r.Height, fbwidth * 4, PixelFormat.Format32bppRgb, (IntPtr)(fbptr + (r.Top * fbwidth + r.Left)))) {
920 ImageCodecInfo ici = Array.Find(ImageCodecInfo.GetImageEncoders(), delegate(ImageCodecInfo item) { return item.FormatID == ImageFormat.Jpeg.Guid; });
921 EncoderParameters ep = new EncoderParameters(1);
922 ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 50L);
923 bmp.Save(jpeg, ici, ep);
924 //bmp.Save(jpeg, ImageFormat.Jpeg);
925 }
926 }
927 }
928 jpeg.Seek(0, SeekOrigin.Begin);
929 int length = (int)jpeg.Length;
930 Byte b1 = (Byte)(length & 0x7F);
931 Byte b2 = (Byte)((length >> 7) & 0x7F);
932 Byte b3 = (Byte)((length >> 14) & 0x7F);
933 if (b3 != 0) b2 |= 0x80;
934 if (b2 != 0) b1 |= 0x80;
935 SendUInt8(b1);
936 if (b2 != 0) SendUInt8(b2);
937 if (b3 != 0) SendUInt8(b3);
938 SendAll(jpeg.ToArray());
939 blurryrect = blurryrect.IsEmpty ? r : Rectangle.Union(blurryrect, r);
940 } else {
941 if (TightZLib == null && ZLibFactory == null) return false;
942 SendFBRectangleHeader(r, 7);
943 SendUInt8(0x00); //Basic encoding, copy filter (raw), zlib stream 0
944 Byte[] row;
945 int i = 0;
946 if (pixelformat.BitsPerPixel == 32 && pixelformat.ColorDepth == 24) {
947 row = new Byte[r.Width * r.Height * 3];
948 for (int y = r.Top; y < r.Bottom; y++) {
949 for (int x = r.Left; x < r.Right; x++) {
950 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x];
951 row[i++] = (Byte)(pixel >> 16);
952 row[i++] = (Byte)(pixel >> 8);
953 row[i++] = (Byte)(pixel >> 0);
954 }
955 }
956 } else {
957 row = new Byte[r.Width * r.Height * pixelformat.BitsPerPixel / 8];
958 for (int y = r.Top; y < r.Bottom; y++) {
959 for (int x = r.Left; x < r.Right; x++) {
960 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x];
961 UInt32 encoded = 0;
962 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift;
963 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift;
964 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift;
965 if (pixelformat.BigEndian) {
966 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b);
967 } else {
968 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b);
969 }
970 }
971 }
972 }
973 if (i >= 12) {
974 if (TightZLib == null) TightZLib = ZLibFactory();
975 Byte[] compressed = TightZLib.Compress(row, 0, i);
976 int length = compressed.Length;
977 Byte b1 = (Byte)(length & 0x7F);
978 Byte b2 = (Byte)((length >> 7) & 0x7F);
979 Byte b3 = (Byte)((length >> 14) & 0x7F);
980 if (b3 != 0) b2 |= 0x80;
981 if (b2 != 0) b1 |= 0x80;
982 SendUInt8(b1);
983 if (b2 != 0) SendUInt8(b2);
984 if (b3 != 0) SendUInt8(b3);
985 SendAll(compressed);
986 } else {
987 SendAll(row, 0, i);
988 }
989 }
990 return true;
991 }
992 private void SendFBRectangleRaw(Int32[] framebuffer, Rectangle r, int fbwidth) {
993 SendFBRectangleHeader(r, 0);
994 for (int y = r.Top; y < r.Bottom; y++) {
995 Byte[] row = new Byte[r.Width * pixelformat.BitsPerPixel / 8];
996 int i = 0;
997 for (int x = r.Left; x < r.Right; x++) {
998 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x];
999 UInt32 encoded = 0;
1000 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift;
1001 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift;
1002 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift;
1003 if (pixelformat.BigEndian) {
1004 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b);
1005 } else {
1006 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b);
1007 }
1008 }
1009 SendAll(row);
1010 }
1011 }
1012
1013 IZLibCompressor ZLibStream = null;
1014 private Boolean SendFBRectangleZLib(Int32[] framebuffer, Rectangle r, int fbwidth) {
1015 if (ZLibStream == null && ZLibFactory == null) return false;
1016 SendFBRectangleHeader(r, 6);
1017 Byte[] row = new Byte[r.Width * r.Height * pixelformat.BitsPerPixel / 8];
1018 int i = 0;
1019 for (int y = r.Top; y < r.Bottom; y++) {
1020 for (int x = r.Left; x < r.Right; x++) {
1021 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x];
1022 UInt32 encoded = 0;
1023 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift;
1024 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift;
1025 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift;
1026 if (pixelformat.BigEndian) {
1027 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b);
1028 } else {
1029 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b);
1030 }
1031 }
1032 }
1033 if (ZLibStream == null) ZLibStream = ZLibFactory();
1034 Byte[] compressed = ZLibStream.Compress(row, 0, i);
1035 SendUInt32((UInt32)compressed.Length);
1036 SendAll(compressed);
1037 return true;
1038 }
1039
1040
1041 private void SendFBRectangleRRE(Int32[] framebuffer, Rectangle r, int fbwidth) {
1042 SendFBRectangleHeader(r, 2);
1043 int basecolor = framebuffer[r.Y * fbwidth + r.X];
1044 List<Rectangle> subrects = new List<Rectangle>();
1045 if (false) {
1046 for (int y = r.Top; y < r.Bottom; y++) {
1047 int color = basecolor;
1048 int runstart = r.Left;
1049 int runlength = 0;
1050 for (int x = r.Left; x < r.Right; x++) {
1051 int newcolor = framebuffer[y * fbwidth + x];
1052 if (color != newcolor) {
1053 if (color != basecolor && runlength > 0) {
1054 Rectangle r2 = new Rectangle(runstart, y, runlength, 1);
1055 if (r2.Y > 0 && framebuffer[(r2.Y - 1) * fbwidth + r2.X] == color) {
1056 Boolean hasadjacent = false;
1057 Rectangle adjacent = r2;
1058 foreach (Rectangle r3 in subrects) {
1059 if (r3.Left == r2.Left && r3.Width == r2.Width && r3.Top + r3.Height == r2.Top) {
1060 adjacent = r3;
1061 hasadjacent = true;
1062 break;
1063 }
1064 }
1065 if (hasadjacent) {
1066 subrects.Remove(adjacent);
1067 r2 = Rectangle.Union(r2, adjacent);
1068 }
1069 }
1070 subrects.Add(r2);
1071 }
1072 runstart = x;
1073 runlength = 0;
1074 color = newcolor;
1075 }
1076 runlength++;
1077 }
1078 if (color != basecolor && runlength > 0) subrects.Add(new Rectangle(runstart, y, runlength, 1));
1079 }
1080 } else {
1081 Queue<Rectangle> remaining = new Queue<Rectangle>();
1082 remaining.Enqueue(r);
1083 while (remaining.Count > 0) {
1084 Rectangle r2 = remaining.Dequeue();
1085 int color = framebuffer[r2.Y * fbwidth + r2.X];
1086 int rw = -1, rh = -1;
1087 for (int x = r2.Left; x < r2.Right && rw == -1; x++) {
1088 if (color != framebuffer[r2.Y * fbwidth + x]) rw = x - r2.Left;
1089 }
1090 if (rw == -1) rw = r2.Width;
1091 for (int y = r2.Top + 1; y < r2.Bottom && rh == -1; y++) {
1092 Boolean success = true;
1093 for (int x = r2.Left; x < r2.Left + rw && success; x++) {
1094 if (color != framebuffer[y * fbwidth + x]) success = false;
1095 }
1096 if (!success) rh = y - r2.Top;
1097 }
1098 if (rh == -1) rh = r2.Height;
1099 if (rw != 0 && rh != 0) subrects.Add(new Rectangle(r2.X, r2.Y, rw, rh));
1100 //if (r2.Width - rw > 0 && rh != 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y, r2.Width - rw, rh));
1101 if (r2.Height - rh > 0 && rw != 0) remaining.Enqueue(new Rectangle(r2.X, r2.Y + rh, rw, r2.Height - rh));
1102 //if (r2.Width - rw > 0 && r2.Height - rh > 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y + rh, r2.Width - rw, r2.Height - rh));
1103 //if (r2.Height - rh > 0) remaining.Enqueue(new Rectangle(r2.X, r2.Y + rh, r2.Width, r2.Height - rh));
1104 if (r2.Width - rw > 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y, r2.Width - rw, r2.Height));
1105 }
1106 }
1107 SendUInt32((UInt32)subrects.Count);
1108 SendPixel(basecolor);
1109 foreach (Rectangle r2 in subrects) {
1110 SendPixel(framebuffer[r2.Y * fbwidth + r2.X]);
1111 SendUInt16((UInt16)(r2.Left - r.Left));
1112 SendUInt16((UInt16)(r2.Top - r.Top));
1113 SendUInt16((UInt16)r2.Width);
1114 SendUInt16((UInt16)r2.Height);
1115 }
1116 }
1117 private void SendFBRectangleHextile(Int32[] framebuffer, Rectangle r, int fbwidth) {
1118 SendFBRectangleHeader(r, 5);
1119 const int hextileRaw = 1;
1120 const int hextileBgSpecified = 2;
1121 const int hextileFgSpecified = 4;
1122 const int hextileAnySubrects = 8;
1123 const int hextileSubrectsColoured = 16;
1124 int oldBg = 0, oldFg = 0;
1125 bool oldBgValid = false;
1126 bool oldFgValid = false;
1127 Rectangle t = new Rectangle();
1128 for (t.Y = r.Top; t.Top < r.Bottom; t.Y += 16) {
1129 t.Height = Math.Min(r.Bottom, t.Top + 16) - t.Top;
1130 for (t.X = r.Left; t.Left < r.Right; t.X += 16) {
1131 t.Width = Math.Min(r.Right, t.Left + 16) - t.Left;
1132 int tileType = 0;
1133 int bg = framebuffer[t.Y * fbwidth + t.X];
1134 int fg = 0;
1135 if (!oldBgValid || oldBg != bg) {
1136 tileType |= hextileBgSpecified;
1137 oldBg = bg;
1138 oldBgValid = true;
1139 }
1140 Boolean foundfg = false;
1141 Boolean foundcol = false;
1142 int subrects = 0;
1143 for (int y = t.Top; y < t.Bottom; y++) {
1144 int color = bg;
1145 int length = 0;
1146 for (int x = t.Left; x < t.Right; x++) {
1147 int pixel = framebuffer[y * fbwidth + x];
1148 if (pixel == bg) {
1149 } else if (!foundfg) {
1150 fg = pixel;
1151 foundfg = true;
1152 } else if (pixel == fg) {
1153 } else {
1154 foundcol = true;
1155 }
1156 if (color != pixel && length > 0) {
1157 if (color != bg) subrects++;
1158 length = 0;
1159 }
1160 length++;
1161 color = pixel;
1162 }
1163 if (length > 0 && color != bg) subrects++;
1164 }
1165 if (foundcol) {
1166 tileType |= hextileSubrectsColoured | hextileAnySubrects;
1167 oldFgValid = false;
1168 } else if (foundfg) {
1169 tileType |= hextileAnySubrects;
1170 if (!oldFgValid || oldFg != fg) {
1171 tileType |= hextileFgSpecified;
1172 oldFg = fg;
1173 oldFgValid = true;
1174 }
1175 }
1176 int encbytes = 0;
1177 if ((tileType & hextileBgSpecified) != 0) encbytes += pixelformat.BitsPerPixel / 8;
1178 if ((tileType & hextileFgSpecified) != 0) encbytes += pixelformat.BitsPerPixel / 8;
1179 if ((tileType & hextileAnySubrects) != 0) {
1180 int pertile = 2;
1181 if ((tileType & hextileSubrectsColoured) != 0) pertile += pixelformat.BitsPerPixel / 8;
1182 encbytes += pertile * subrects;
1183 }
1184 if (t.Width * t.Height * pixelformat.BitsPerPixel / 8 <= encbytes) {
1185 SendUInt8(hextileRaw);
1186 for (int y = t.Top; y < t.Bottom; y++) for (int x = t.Left; x < t.Right; x++) SendPixel(framebuffer[y * fbwidth + x]);
1187 oldBgValid = oldFgValid = false;
1188 continue;
1189 }
1190 SendUInt8((Byte)tileType);
1191 if ((tileType & hextileBgSpecified) != 0) SendPixel(bg);
1192 if ((tileType & hextileFgSpecified) != 0) SendPixel(fg);
1193 if ((tileType & hextileAnySubrects) != 0) {
1194 SendUInt8((Byte)subrects);
1195 int subrectsa = 0;
1196 for (int y = t.Top; y < t.Bottom; y++) {
1197 int color = bg;
1198 int length = 0;
1199 int start = 0;
1200 for (int x = t.Left; x < t.Right; x++) {
1201 int newcolor = framebuffer[y * fbwidth + x];
1202 if (color != newcolor && length > 0) {
1203 if (color != bg && subrectsa < subrects) {
1204 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(color);
1205 SendUInt8((Byte)(((start & 0xF) << 4) | ((y - t.Top) & 0xF)));
1206 SendUInt8((Byte)((((length - 1) & 0xF) << 4) | (0 & 0xF)));
1207 subrectsa++;
1208 }
1209 length = 0;
1210 start = x - t.Left;
1211 }
1212 length++;
1213 color = newcolor;
1214 }
1215 if (length > 0 && color != bg && subrectsa < subrects) {
1216 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(color);
1217 SendUInt8((Byte)(((start & 0xF) << 4) | ((y - t.Top) & 0xF)));
1218 SendUInt8((Byte)((((length - 1) & 0xF) << 4) | (0 & 0xF)));
1219 subrectsa++;
1220 }
1221 }
1222 for (int i = subrectsa; i < subrects; i++) {
1223 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(0);
1224 SendUInt16(0);
1225 subrectsa++;
1226 }
1227 if (subrects != subrectsa) throw new Exception("subrects != subrectsa");
1228 }
1229 }
1230 //Flush();
1231 }
1232 }
1233
1234 private void SendPixel(int pixeli) {
1235 UInt32 encoded = 0;
1236 UInt32 pixel = (UInt32)pixeli;
1237 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift;
1238 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift;
1239 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift;
1240 byte[] row = new Byte[pixelformat.BitsPerPixel / 8];
1241 int i = 0;
1242 if (pixelformat.BigEndian) {
1243 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b);
1244 } else {
1245 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b);
1246 }
1247 SendAll(row);
1248 }
1249
1250 private void SendPixelFormat(RFBPixelFormat pf) {
1251 SendUInt8(pf.BitsPerPixel); //bits per pixel
1252 SendUInt8(pf.ColorDepth); //depth
1253 SendUInt8(pf.BigEndian ? (Byte)1 : (Byte)0); //big endian
1254 SendUInt8(pf.TrueColor ? (Byte)1 : (Byte)0); //true color
1255 SendUInt16(pf.RedMax); //red max
1256 SendUInt16(pf.GreenMax); //green max
1257 SendUInt16(pf.BlueMax); //blue max
1258 SendUInt8(pf.RedShift); //red shift
1259 SendUInt8(pf.GreenShift); //green shift
1260 SendUInt8(pf.BlueShift); //blue shift
1261 SendUInt8(0); //padding
1262 SendUInt8(0); //padding
1263 SendUInt8(0); //padding
1264 }
1265 private RFBPixelFormat ReceivePixelFormat() {
1266 Byte[] b = ReceiveAll(16);
1267 RFBPixelFormat pf = new RFBPixelFormat();
1268 pf.BitsPerPixel = b[0];
1269 pf.ColorDepth = b[1];
1270 pf.BigEndian = b[2] != 0;
1271 pf.TrueColor = b[3] != 0;
1272 pf.RedMax = (UInt16)((b[4] << 8) | b[5]);
1273 pf.GreenMax = (UInt16)((b[6] << 8) | b[7]);
1274 pf.BlueMax = (UInt16)((b[8] << 8) | b[9]);
1275 pf.RedShift = b[10];
1276 pf.GreenShift = b[11];
1277 pf.BlueShift = b[12];
1278 return pf;
1279 }
1280
1281 private void SendUInt32(UInt32 value) {
1282 SendAll(new Byte[] { (Byte)(value >> 24), (Byte)(value >> 16), (Byte)(value >> 8), (Byte)value });
1283 }
1284 private void SendUInt16(UInt16 value) {
1285 SendAll(new Byte[] { (Byte)(value >> 8), (Byte)value });
1286 }
1287 private void SendUInt8(Byte value) {
1288 SendAll(new Byte[] { value });
1289 }
1290 private void SendAll(Byte[] buffer) {
1291 SendAll(buffer, 0, buffer.Length);
1292 }
1293
1294 private void SendAll(Byte[] buffer, int off, int len) {
1295 if (SendBuffer == null) SendBuffer = new MemoryStream();
1296 SendBuffer.Write(buffer, off, len);
1297 if (SendBuffer.Length > 102400) FlushSendBuffer();
1298 }
1299 private void FlushSendBuffer() {
1300 if (SendBuffer == null) return;
1301 SendBuffer.Seek(0, SeekOrigin.Begin);
1302 SendBuffer.WriteTo(socket);
1303 SendBuffer.SetLength(0);
1304 }
1305
1306 private Byte ReceiveByte() {
1307 Byte[] buffer = new Byte[1];
1308 ReceiveAll(buffer, 0, 1);
1309 return buffer[0];
1310 }
1311 private Byte[] ReceiveAll(int len) {
1312 Byte[] buffer = new Byte[len];
1313 ReceiveAll(buffer, 0, len);
1314 return buffer;
1315 }
1316 private void ReceiveAll(Byte[] buffer, int off, int len) {
1317 while (len > 0) {
1318 int sent = socket.Read(buffer, off, len);
1319 if (sent == 0) throw new EndOfStreamException();
1320 len -= sent;
1321 off += sent;
1322 }
1323 }
1324 }
1325 }