⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vnccanvas.java

📁 一个远程登陆器的原代码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
//
//  Copyright (C) 2001,2002 HorizonLive.com, Inc.  All Rights Reserved.
//  Copyright (C) 2001,2002 Constantin Kaplinsky.  All Rights Reserved.
//  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
//  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
//
//  This is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This software is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this software; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
//  USA.
//

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.lang.*;
import java.util.zip.*;


//
// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
//

class VncCanvas
	extends Canvas
	implements KeyListener, MouseListener, MouseMotionListener {

	VncViewer viewer;
	RfbProto rfb;
	ColorModel cm8_256c, cm8_64c, cm8_8c, cm24;
	Color[] colors;
	int bytesPixel;

	Image memImage;
	Graphics memGraphics;

	Image rawPixelsImage;
	MemoryImageSource pixelsSource;
	byte[] pixels8;
	int[] pixels24;

	// Zlib encoder's data.
	byte[] zlibBuf;
	int zlibBufLen = 0;
	Inflater zlibInflater;

	// Tight encoder's data.
	final static int tightZlibBufferSize = 512;
	Inflater[] tightInflaters;

	// Since JPEG images are loaded asynchronously, we have to remember
	// their position in the framebuffer. Also, this jpegRect object is
	// used for synchronization between the rfbThread and a JVM's thread
	// which decodes and loads JPEG images.
	Rectangle jpegRect;

	// True if we process keyboard and mouse events.
	boolean inputEnabled;
	
	//
	// The constructor.
	//

	VncCanvas(VncViewer v) throws IOException {
		viewer = v;
		rfb = viewer.rfb;

		tightInflaters = new Inflater[4];

		// sf@2005 - Adding more color modes
		cm8_256c = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
		cm8_64c = new DirectColorModel(8, (3 << 4), (3 << 2), (3 << 0));
		cm8_8c = new DirectColorModel(8, (1 << 2), (1 << 1), (1 << 0));
		
		cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);

		colors = new Color[256];
		// sf@2005 - Now Default
		for (int i = 0; i < 256; i++)
			colors[i] = new Color(cm8_256c.getRGB(i));

		setPixelFormat();

		inputEnabled = false;
		if (!viewer.options.viewOnly)
			enableInput(true);

		// Keyboard listener is enabled even in view-only mode, to catch
		// 'r' or 'R' key presses used to request screen update.
		addKeyListener(this);
	}

	//
	// Callback methods to determine geometry of our Component.
	//

	public Dimension getPreferredSize() {
		return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
	}

	public Dimension getMinimumSize() {
		return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
	}

	public Dimension getMaximumSize() {
		return new Dimension(rfb.framebufferWidth, rfb.framebufferHeight);
	}

	//
	// All painting is performed here.
	//

	public void update(Graphics g) {
		paint(g);
	}

	public void paint(Graphics g) {
		synchronized (memImage) {
			g.drawImage(memImage, 0, 0, null);
		}
		if (showSoftCursor) {
			int x0 = cursorX - hotX, y0 = cursorY - hotY;
			Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
			if (r.intersects(g.getClipBounds())) {
				g.drawImage(softCursor, x0, y0, null);
			}
		}
	}

	//
	// Override the ImageObserver interface method to handle drawing of
	// JPEG-encoded data.
	//

	public boolean imageUpdate(
		Image img,
		int infoflags,
		int x,
		int y,
		int width,
		int height) {
		if ((infoflags & (ALLBITS | ABORT)) == 0) {
			return true; // We need more image data.
		} else {
			// If the whole image is available, draw it now.
			if ((infoflags & ALLBITS) != 0) {
				if (jpegRect != null) {
					synchronized (jpegRect) {
						memGraphics.drawImage(
							img,
							jpegRect.x,
							jpegRect.y,
							null);
						scheduleRepaint(
							jpegRect.x,
							jpegRect.y,
							jpegRect.width,
							jpegRect.height);
						jpegRect.notify();
					}
				}
			}
			return false; // All image data was processed.
		}
	}

	//
	// Start/stop receiving mouse events. Keyboard events are received
	// even in view-only mode, because we want to map the 'r' key to the
	// screen refreshing function.
	//

	public synchronized void enableInput(boolean enable) {
		if (enable && !inputEnabled) {
			inputEnabled = true;
			addMouseListener(this);
			addMouseMotionListener(this);
			if (viewer.showControls) {
				viewer.buttonPanel.enableRemoteAccessControls(true);
			}
		} else if (!enable && inputEnabled) {
			inputEnabled = false;
			removeMouseListener(this);
			removeMouseMotionListener(this);
			if (viewer.showControls) {
				viewer.buttonPanel.enableRemoteAccessControls(false);
			}
		}
	}

	
	public void setPixelFormat() throws IOException {
		// sf@2005 - Adding more color modes
		if (viewer.options.eightBitColors > 0)
		{
			viewer.options.oldEightBitColors = viewer.options.eightBitColors;
			switch (viewer.options.eightBitColors)
			{
				case 1: // 256
					for (int i = 0; i < 256; i++)
						colors[i] = new Color(cm8_256c.getRGB(i));					
					rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6, false);
					break;
				case 2: // 64
					for (int i = 0; i < 256; i++)
						colors[i] = new Color(cm8_64c.getRGB(i));					
					rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, false);
					break;
				case 3: // 8
					for (int i = 0; i < 256; i++)
						colors[i] = new Color(cm8_8c.getRGB(i));					
					rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, false);
					break;
				case 4: // 4 (Grey)
					for (int i = 0; i < 256; i++)
						colors[i] = new Color(cm8_64c.getRGB(i));					
					rfb.writeSetPixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0, true);
					break;
				case 5: // 2 (B&W)
					for (int i = 0; i < 256; i++)
						colors[i] = new Color(cm8_8c.getRGB(i));					
					rfb.writeSetPixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0, true);
					break;
			}
			bytesPixel = 1;
		}
		else 
		{
			rfb.writeSetPixelFormat(
				32,
				24,
				false,
				true,
				255,
				255,
				255,
				16,
				8,
				0,
				false);
			bytesPixel = 4;
		}
		updateFramebufferSize();
	}

	void updateFramebufferSize() {

		// Useful shortcuts.
		int fbWidth = rfb.framebufferWidth;
		int fbHeight = rfb.framebufferHeight;

		// Create new off-screen image either if it does not exist, or if
		// its geometry should be changed. It's not necessary to replace
		// existing image if only pixel format should be changed.
		if (memImage == null) {
			memImage = viewer.createImage(fbWidth, fbHeight);
			memGraphics = memImage.getGraphics();
		} else if (
			memImage.getWidth(null) != fbWidth
				|| memImage.getHeight(null) != fbHeight) {
			synchronized (memImage) {
				memImage = viewer.createImage(fbWidth, fbHeight);
				memGraphics = memImage.getGraphics();
			}
		}

		// Images with raw pixels should be re-allocated on every change
		// of geometry or pixel format.
		if (bytesPixel == 1) {
			pixels24 = null;
			pixels8 = new byte[fbWidth * fbHeight];

			// sf@2005
			ColorModel cml = cm8_8c;
			
			//	 sf@2005
			switch (viewer.options.eightBitColors)
			{
				case 1:
					cml = cm8_256c;
					break;
					
				case 2:
				case 4:
					cml = cm8_64c;
					break;
				case 3:
				case 5:
					cml = cm8_8c;
					break;
			}
			
			pixelsSource =
				new MemoryImageSource(
					fbWidth,
					fbHeight,
					cml,
					pixels8,
					0,
					fbWidth);
		} else {
			pixels8 = null;
			pixels24 = new int[fbWidth * fbHeight];

			pixelsSource =
				new MemoryImageSource(
					fbWidth,
					fbHeight,
					cm24,
					pixels24,
					0,
					fbWidth);
		}
		pixelsSource.setAnimated(true);
		rawPixelsImage = createImage(pixelsSource);

		// Update the size of desktop containers.
		if (viewer.inSeparateFrame) {
			if (viewer.desktopScrollPane != null)
				resizeDesktopFrame();
		} else {
			setSize(fbWidth, fbHeight);
		}
	}

	void resizeDesktopFrame() {
		setSize(rfb.framebufferWidth, rfb.framebufferHeight);

		// FIXME: Find a better way to determine correct size of a
		// ScrollPane.  -- const
		Insets insets = viewer.desktopScrollPane.getInsets();
		viewer.desktopScrollPane.setSize(
			rfb.framebufferWidth + 2 * Math.min(insets.left, insets.right),
			rfb.framebufferHeight + 2 * Math.min(insets.top, insets.bottom));

		viewer.vncFrame.pack();

		// Try to limit the frame size to the screen size.
		Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
		Dimension frameSize = viewer.vncFrame.getSize();
		Dimension newSize = frameSize;
		boolean needToResizeFrame = false;
		if (frameSize.height > screenSize.height) {
			newSize.height = screenSize.height;
			needToResizeFrame = true;
		}
		if (frameSize.width > screenSize.width) {
			newSize.width = screenSize.width;
			needToResizeFrame = true;
		}
		if (needToResizeFrame) {
			viewer.vncFrame.setSize(newSize);
		}

		viewer.desktopScrollPane.doLayout();
	}

	//
	// processNormalProtocol() - executed by the rfbThread to deal with the
	// RFB socket.
	//

	public void processNormalProtocol() throws Exception {

		// Start/stop session recording if necessary.
		viewer.checkRecordingStatus();

		rfb.writeFramebufferUpdateRequest(
			0,
			0,
			rfb.framebufferWidth,
			rfb.framebufferHeight,
			false);

		//
		// main dispatch loop
		//

		while (true) {
			// Read message type from the server.
			int msgType = rfb.readServerMessageType();

			// Process the message depending on its type.
			switch (msgType) {
				case RfbProto.FramebufferUpdate :
					rfb.readFramebufferUpdate();

					for (int i = 0; i < rfb.updateNRects; i++) {
						rfb.readFramebufferUpdateRectHdr();
						int rx = rfb.updateRectX, ry = rfb.updateRectY;
						int rw = rfb.updateRectW, rh = rfb.updateRectH;

						if (rfb.updateRectEncoding == rfb.EncodingLastRect)
							break;

						if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
							rfb.setFramebufferSize(rw, rh);
							updateFramebufferSize();
							break;
						}

						if (rfb.updateRectEncoding == rfb.EncodingXCursor
							|| rfb.updateRectEncoding == rfb.EncodingRichCursor) {
							handleCursorShapeUpdate(
								rfb.updateRectEncoding,
								rx,
								ry,
								rw,
								rh);
							continue;
						}

						switch (rfb.updateRectEncoding) {
							case RfbProto.EncodingRaw :
								handleRawRect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingCopyRect :
								handleCopyRect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingRRE :
								handleRRERect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingCoRRE :
								handleCoRRERect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingHextile :
								handleHextileRect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingZlib :
								handleZlibRect(rx, ry, rw, rh);
								break;
							case RfbProto.EncodingTight :
								handleTightRect(rx, ry, rw, rh);
								break;
							// marscha - PointerPos
							case RfbProto.EncodingPointerPos :
								handleCursorPosUpdate(rx, ry);
								break;
							default :
								throw new Exception(
									"Unknown RFB rectangle encoding "
										+ rfb.updateRectEncoding);
						}
					}

					boolean fullUpdateNeeded = false;

					// Start/stop session recording if necessary. Request full
					// update if a new session file was opened.
					if (viewer.checkRecordingStatus())
						fullUpdateNeeded = true;

					// Defer framebuffer update request if necessary. But wake up
					// immediately on keyboard or mouse event.
					if (viewer.deferUpdateRequests > 0) {
						synchronized (rfb) {
							try {
								rfb.wait(viewer.deferUpdateRequests);
							} catch (InterruptedException e) {
							}
						}
					}

					// Before requesting framebuffer update, check if the pixel
					// format should be changed. If it should, request full update
					// instead of an incremental one.
					if ((viewer.options.eightBitColors > 0) && (bytesPixel != 1)
						||
						(viewer.options.eightBitColors == 0) && (bytesPixel == 1)
						||
						(viewer.options.eightBitColors != viewer.options.oldEightBitColors)
						)
					{
						setPixelFormat();
						fullUpdateNeeded = true;
					}

					rfb.writeFramebufferUpdateRequest(
						0,
						0,
						rfb.framebufferWidth,
						rfb.framebufferHeight,
						!fullUpdateNeeded);

					break;

				case RfbProto.SetColourMapEntries :
					throw new Exception("Can't handle SetColourMapEntries message");

				case RfbProto.Bell :
					Toolkit.getDefaultToolkit().beep();
					break;

				case RfbProto.ServerCutText :
					String s = rfb.readServerCutText();
					viewer.clipboard.setCutText(s);
					break;

				case RfbProto.rfbFileTransfer :
					viewer.rfb.readRfbFileTransferMsg();
					break;

				default :
					throw new Exception("Unknown RFB message type " + msgType);
			}
		}
	}

	//
	// Handle a raw rectangle. The second form with paint==false is used
	// by the Hextile decoder for raw-encoded tiles.
	//

	void handleRawRect(int x, int y, int w, int h) throws IOException {
		handleRawRect(x, y, w, h, true);
	}

	void handleRawRect(int x, int y, int w, int h, boolean paint)
		throws IOException {

		if (bytesPixel == 1) {
			for (int dy = y; dy < y + h; dy++) {
				rfb.is.readFully(pixels8, dy * rfb.framebufferWidth + x, w);
				if (rfb.rec != null) {
					rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w);
				}
			}
		} else {
			byte[] buf = new byte[w * 4];
			int i, offset;
			for (int dy = y; dy < y + h; dy++) {
				rfb.is.readFully(buf);
				if (rfb.rec != null) {
					rfb.rec.write(buf);
				}
				offset = dy * rfb.framebufferWidth + x;
				for (i = 0; i < w; i++) {
					pixels24[offset + i] =
						(buf[i * 4 + 2] & 0xFF)
							<< 16 | (buf[i * 4 + 1] & 0xFF)
							<< 8 | (buf[i * 4] & 0xFF);
				}
			}
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -