vnc.c

来自「winNT技术操作系统,国外开放的原代码和LIUX一样」· C语言 代码 · 共 1,377 行 · 第 1/3 页

C
1,377
字号
/*
   rdesktop: A Remote Desktop Protocol client.
   User interface services - VNC target
   Copyright (C) Matthew Chapman 1999-2000
   Copyright (C) 2000 Tim Edmonds
   Copyright (C) 2001 James "Wez" Weatherall
   Copyright (C) 2001 Johannes E. Schindelin
   
   This program 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 program 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 program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


#include <stdio.h>
#include <time.h>

#ifdef WIN32
#define close closesocket
#define strcasecmp _strcmpi
#else
#include <unistd.h>
#include <sys/time.h>		/* timeval */
#include <sys/socket.h>
#endif

#include "../rdesktop.h"
#undef VERSION

#ifdef WIN32
#define HBITMAP R_HBITMAP
#define HCURSOR R_HCURSOR
#define WORD R_WORD
#endif
#include "vnc.h"
#ifdef WIN32
#undef HBITMAP
#undef HCURSOR
#undef WORD
#endif

#include <errno.h>
#include <sys/socket.h>
extern int ListenOnTCPPort(int port);
extern int rfbClientSocket;

#include <rfb/rfbregion.h>

#define BITSPERBYTES 8
#define TOBYTES(bits) ((bits)/BITSPERBYTES)

extern int g_width;
extern int g_height;
extern int keylayout;
extern BOOL sendmotion;
#ifdef ENABLE_SHADOW
extern int client_counter;
#endif


int rfb_port = 5923;
int defer_time = 5;
int rfbClientSocket = 0;
static rfbScreenInfoPtr server = NULL;
static vncBuffer *frameBuffer = NULL;
static uint8_t reverseByte[0x100];
BOOL g_enable_compose = False;
int g_display = 0;

/* ignored */
BOOL owncolmap = False;
BOOL enable_compose = False;

void
vncHideCursor()
{
	if (server->clientHead)
		rfbUndrawCursor(server);
}

/* -=- mouseLookup
 * Table converting mouse button number (0-2) to flag
 */

int mouseLookup[3] = {
	MOUSE_FLAG_BUTTON1, MOUSE_FLAG_BUTTON3, MOUSE_FLAG_BUTTON2
};

int clipX, clipY, clipW, clipH;

BOOL
vncwinClipRect(int *x, int *y, int *cx, int *cy)
{
	if (*x + *cx > clipX + clipW)
		*cx = clipX + clipW - *x;
	if (*y + *cy > clipY + clipH)
		*cy = clipY + clipH - *y;
	if (*x < clipX)
	{
		*cx -= clipX - *x;
		*x = clipX;
	}
	if (*y < clipY)
	{
		*cy -= clipY - *y;
		*y = clipY;
	}
	if (*cx < 0 || *cy < 0)
		*cx = *cy = 0;
	return (*cx > 0 && *cy > 0 && *x < server->width && *y < server->height);
}

void
xwin_toggle_fullscreen(void)
{
}

static int lastbuttons = 0;

#define FIRST_MODIFIER XK_Shift_L
#define LAST_MODIFIER XK_Hyper_R

static BOOL keystate[LAST_MODIFIER - FIRST_MODIFIER];

void
init_keyboard()
{
	int i;
	for (i = 0; i < LAST_MODIFIER - FIRST_MODIFIER; i++)
		keystate[i] = 0;

	xkeymap_init();
}

BOOL
get_key_state(unsigned int state, uint32 keysym)
{
	if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER)
		return keystate[keysym - FIRST_MODIFIER];
	return 0;
}

void
vncKey(rfbBool down, rfbKeySym keysym, struct _rfbClientRec *cl)
{
	uint32 ev_time = time(NULL);
	key_translation tr = { 0, 0 };

	if (keysym >= FIRST_MODIFIER && keysym <= LAST_MODIFIER)
	{
		/* TODO: fake local state */
		keystate[keysym - FIRST_MODIFIER] = down;
	}

	if (down)
	{
		/* TODO: fake local state */
		if (handle_special_keys(keysym, 0, ev_time, True))
			return;

		/* TODO: fake local state */
		tr = xkeymap_translate_key(keysym, 0, 0);

		if (tr.scancode == 0)
			return;

		ensure_remote_modifiers(ev_time, tr);

		rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
	}
	else
	{
		/* todO: fake local state */
		if (handle_special_keys(keysym, 0, ev_time, False))
			return;

		/* todO: fake local state */
		tr = xkeymap_translate_key(keysym, 0, 0);

		if (tr.scancode == 0)
			return;

		rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
	}
}

void
vncMouse(int buttonMask, int x, int y, struct _rfbClientRec *cl)
{
	int b;
	uint32 ev_time = time(NULL);

	rdp_send_input(ev_time, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, x, y);

	for (b = 0; b < 3; b++)
	{
		int bb = 1 << (b);
		if (!(lastbuttons & bb) && (buttonMask & bb))
		{
			rdp_send_input(ev_time, RDP_INPUT_MOUSE,
				       (mouseLookup[b]) | MOUSE_FLAG_DOWN, x, y);
		}
		else if ((lastbuttons & bb) && !(buttonMask & bb))
		{
			rdp_send_input(ev_time, RDP_INPUT_MOUSE, (mouseLookup[b]), x, y);
		}
	}
	lastbuttons = buttonMask;

	/* handle cursor */
	rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
}


void
rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password,
		char *shell, char *directory)
{
	struct sockaddr addr;
	fd_set fdset;
	struct timeval tv;
	int rfbListenSock, addrlen = sizeof(addr);

	rfbListenSock = rfbListenOnTCPPort(rfb_port);
	fprintf(stderr, "Listening on VNC port %d\n", rfb_port);
	if (rfbListenSock <= 0)
		error("Cannot listen on port %d", rfb_port);
	else
		while (1)
		{
			FD_ZERO(&fdset);
			FD_SET(rfbListenSock, &fdset);
			tv.tv_sec = 5;
			tv.tv_usec = 0;
			if (select(rfbListenSock + 1, &fdset, NULL, NULL, &tv) > 0)
			{
				rfbClientSocket = accept(rfbListenSock, &addr, &addrlen);
				if (rfbClientSocket < 0)
				{
					error("Error accepting client (%d: %s.\n",
					      errno, strerror(errno));
					continue;
				}
				ui_create_window();
				if (!rdp_connect(server, flags, domain, password, shell, directory))
				{
					error("Error connecting to RDP server.\n");
					continue;
				}
				if (!fork())
				{
					BOOL deactivated;
					uint32_t ext_disc_reason;
					printf("Connection successful.\n");
					rdp_main_loop(&deactivated, &ext_disc_reason);
					printf("Disconnecting...\n");
					rdp_disconnect();
					ui_destroy_window();
					exit(0);
				}
			}
		}
}





extern char g_title[];
BOOL
ui_create_window()
{
	int i;

	for (i = 0; i < 0x100; i++)
		reverseByte[i] =
			(((i >> 7) & 1)) | (((i >> 6) & 1) << 1) | (((i >> 5) & 1) << 2) |
			(((i >> 4) & 1) << 3) | (((i >> 3) & 1) << 4) | (((i >> 2) & 1) << 5) |
			(((i >> 1) & 1) << 6) | (((i >> 0) & 1) << 7);

	server = rfbGetScreen(0, NULL, g_width, g_height, 8, 1, 1);
	server->desktopName = g_title;
	server->frameBuffer = (char *) malloc(g_width * g_height);
	server->ptrAddEvent = vncMouse;
	server->kbdAddEvent = vncKey;
#ifdef ENABLE_SHADOW
	server->httpPort = 6124 + client_counter;
	server->port = 5924 + client_counter;
	rfbInitSockets(server);
	server->alwaysShared = TRUE;
	server->neverShared = FALSE;
#else
	server->port = -1;
	server->alwaysShared = FALSE;
	server->neverShared = FALSE;
#endif
	server->inetdSock = rfbClientSocket;
	server->serverFormat.trueColour = FALSE;	/* activate colour maps */
	server->deferUpdateTime = defer_time;

	frameBuffer = (vncBuffer *) malloc(sizeof(vncBuffer));
	frameBuffer->w = g_width;
	frameBuffer->h = g_height;
	frameBuffer->linew = g_width;
	frameBuffer->data = server->frameBuffer;
	frameBuffer->owner = FALSE;
	frameBuffer->format = &server->serverFormat;

	ui_set_clip(0, 0, g_width, g_height);

	rfbInitServer(server);
#ifndef ENABLE_SHADOW
	server->port = rfb_port;
#else
	fprintf(stderr, "server listening on port %d (socket %d)\n", server->port,
		server->listenSock);
#endif

	init_keyboard();

	return (server != NULL);
}

void
ui_destroy_window()
{
	rfbCloseClient(server->clientHead);
}


int
ui_select(int rdpSocket)
{
	fd_set fds;
	struct timeval tv;
	int n, m = server->maxFd;

	if (rdpSocket > m)
		m = rdpSocket;
	while (1)
	{
		fds = server->allFds;
		FD_SET(rdpSocket, &fds);
		tv.tv_sec = defer_time / 1000;
		tv.tv_usec = (defer_time % 1000) * 1000;
		n = select(m + 1, &fds, NULL, NULL, &tv);
		rfbProcessEvents(server, 0);
		/* if client is gone, close connection */
		if (!server->clientHead)
			close(rdpSocket);
		if (FD_ISSET(rdpSocket, &fds))
			return 1;
	}
	return 0;
}

void
ui_move_pointer(int x, int y)
{
	// TODO: Is there a way to send x,y even if cursor encoding is active?
	rfbUndrawCursor(server);
	server->cursorX = x;
	server->cursorY = y;
}

HBITMAP
ui_create_bitmap(int width, int height, uint8 * data)
{
	vncBuffer *buf;

	buf = vncNewBuffer(width, height, 8);
	memcpy(buf->data, data, width * height);

	return (HBITMAP) buf;
}

void
ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
{
	vncBuffer *buf;
	buf = ui_create_bitmap(width, height, data);
	vncCopyBlitFrom(server, x, y, cx, cy, buf, 0, 0);
	vncDeleteBuffer(buf);
}

void
ui_destroy_bitmap(HBITMAP bmp)
{
	vncDeleteBuffer((vncBuffer *) bmp);
}

uint8_t
vncLookupColour(rfbColourMap * colourMap, uint8_t * p)
{
	uint8_t i, i1 = 0;
	uint8_t *cm = colourMap->data.bytes;
	uint32_t m, m1 = abs(cm[0] - p[0]) + abs(cm[1] - p[1]) + abs(cm[2] - p[2]);
	for (i = 1; i < 255; i++)
	{
		m = abs(cm[i * 3] - p[0]) + abs(cm[i * 3 + 1] - p[1]) + abs(cm[i * 3 + 2] - p[2]);
		if (m < m1)
		{
			m1 = m;
			i1 = i;
		}
	}
	return (i1);
}

HCURSOR
ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * mask, uint8 * data)
{
	int i, j;
	uint8_t *d0, *d1;
	uint8_t *cdata;
	uint8_t white[3] = { 0xff, 0xff, 0xff };
	uint8_t black[3] = { 0, 0, 0 };
	uint8_t *cur;
	rfbCursorPtr cursor;
	rfbColourMap *colourMap = &server->colourMap;

	cdata = xmalloc(sizeof(uint8_t) * width * height);
	d0 = xmalloc(sizeof(uint32_t) * width * height / 4);
	d1 = (uint8_t *) mask;
	for (j = 0; j < height; j++)
		for (i = 0; i < width / 8; i++)
		{
			d0[j * width / 8 + i] = d1[(height - 1 - j) * width / 8 + i] ^ 0xffffffff;
		}
	for (j = 0; j < height; j++)
	{
		for (i = 0; i < width; i++)
		{
			//strange that the pointer is in 24bit depth when everything
			//else is in 8bit palletized.
			cur = data + ((height - 1 - j) * width + i) * 3;
			if (cur[0] > 0x80 || cur[1] > 0x80 || cur[2] > 0x80)
			{
				if (!(d0[(j * width + i) / 8] & (0x80 >> (i & 7))))
				{
					/* text cursor! */
					cdata[j * width + i] = vncLookupColour(colourMap, black);
					d0[(j * width + i) / 8] |= 0x80 >> (i & 7);
				}
				else
					cdata[j * width + i] = vncLookupColour(colourMap, white);
			}
			else
				cdata[j * width + i] = vncLookupColour(colourMap, cur);

⌨️ 快捷键说明

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