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 + -
显示快捷键?