当前位置: 首页 > 工具软件 > LibVNCServer > 使用案例 >

vnc android github,libvncserver/androidvncserver.c at master · LibVNC/libvncserver · GitHub

金亦
2023-12-01

/*

* This example VNC server for Android is adopted from

* http://code.google.com/p/android-vnc-server/ with some additional

* fixes applied.

*

* To build, you'll need the Android Native Development Kit from

* http://developer.android.com/sdk/ndk/.

*

* 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, 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.

*

* This project is an adaptation of the original fbvncserver for the iPAQ

* and Zaurus.

*/

#include

#include

#include

#include

#include

#include

#include

#include /* For makedev() */

#include

#include

#include

#include

#include

/* libvncserver */

#include "rfb/rfb.h"

#include "rfb/keysym.h"

/*****************************************************************************/

/* Android does not use /dev/fb0. */

#define FB_DEVICE "/dev/graphics/fb0"

static char KBD_DEVICE[256] = "/dev/input/event3";

static char TOUCH_DEVICE[256] = "/dev/input/event1";

static struct fb_var_screeninfo scrinfo;

static int fbfd = -1;

static int kbdfd = -1;

static int touchfd = -1;

static unsigned short int *fbmmap = MAP_FAILED;

static unsigned short int *vncbuf;

static unsigned short int *fbbuf;

/* Android already has 5900 bound natively. */

#define VNC_PORT 5901

static rfbScreenInfoPtr vncscr;

static int xmin, xmax;

static int ymin, ymax;

/* No idea, just copied from fbvncserver as part of the frame differerencing

* algorithm. I will probably be later rewriting all of this. */

static struct varblock_t

{

int min_i;

int min_j;

int max_i;

int max_j;

int r_offset;

int g_offset;

int b_offset;

int rfb_xres;

int rfb_maxy;

} varblock;

/*****************************************************************************/

static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl);

static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl);

/*****************************************************************************/

static void init_fb(void)

{

size_t pixels;

size_t bytespp;

if ((fbfd = open(FB_DEVICE, O_RDONLY)) == -1)

{

printf("cannot open fb device %s\n", FB_DEVICE);

exit(EXIT_FAILURE);

}

if (ioctl(fbfd, FBIOGET_VSCREENINFO, &scrinfo) != 0)

{

printf("ioctl error\n");

exit(EXIT_FAILURE);

}

pixels = scrinfo.xres * scrinfo.yres;

bytespp = scrinfo.bits_per_pixel / 8;

fprintf(stderr, "xres=%d, yres=%d, xresv=%d, yresv=%d, xoffs=%d, yoffs=%d, bpp=%d\n",

(int)scrinfo.xres, (int)scrinfo.yres,

(int)scrinfo.xres_virtual, (int)scrinfo.yres_virtual,

(int)scrinfo.xoffset, (int)scrinfo.yoffset,

(int)scrinfo.bits_per_pixel);

fbmmap = mmap(NULL, pixels * bytespp, PROT_READ, MAP_SHARED, fbfd, 0);

if (fbmmap == MAP_FAILED)

{

printf("mmap failed\n");

exit(EXIT_FAILURE);

}

}

static void cleanup_fb(void)

{

if(fbfd != -1)

{

close(fbfd);

}

}

static void init_kbd()

{

if((kbdfd = open(KBD_DEVICE, O_RDWR)) == -1)

{

printf("cannot open kbd device %s\n", KBD_DEVICE);

exit(EXIT_FAILURE);

}

}

static void cleanup_kbd()

{

if(kbdfd != -1)

{

close(kbdfd);

}

}

static void init_touch()

{

struct input_absinfo info;

if((touchfd = open(TOUCH_DEVICE, O_RDWR)) == -1)

{

printf("cannot open touch device %s\n", TOUCH_DEVICE);

exit(EXIT_FAILURE);

}

// Get the Range of X and Y

if(ioctl(touchfd, EVIOCGABS(ABS_X), &info)) {

printf("cannot get ABS_X info, %s\n", strerror(errno));

exit(EXIT_FAILURE);

}

xmin = info.minimum;

xmax = info.maximum;

if(ioctl(touchfd, EVIOCGABS(ABS_Y), &info)) {

printf("cannot get ABS_Y, %s\n", strerror(errno));

exit(EXIT_FAILURE);

}

ymin = info.minimum;

ymax = info.maximum;

}

static void cleanup_touch()

{

if(touchfd != -1)

{

close(touchfd);

}

}

/*****************************************************************************/

static void init_fb_server(int argc, char **argv)

{

printf("Initializing server...\n");

/* Allocate the VNC server buffer to be managed (not manipulated) by

* libvncserver. */

vncbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel / 8);

assert(vncbuf != NULL);

/* Allocate the comparison buffer for detecting drawing updates from frame

* to frame. */

fbbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel / 8);

assert(fbbuf != NULL);

/* TODO: This assumes scrinfo.bits_per_pixel is 16. */

vncscr = rfbGetScreen(&argc, argv, scrinfo.xres, scrinfo.yres, 5, 2, (scrinfo.bits_per_pixel / 8));

assert(vncscr != NULL);

vncscr->desktopName = "Android";

vncscr->frameBuffer = (char *)vncbuf;

vncscr->alwaysShared = TRUE;

vncscr->httpDir = NULL;

vncscr->port = VNC_PORT;

vncscr->kbdAddEvent = keyevent;

vncscr->ptrAddEvent = ptrevent;

rfbInitServer(vncscr);

/* Mark as dirty since we haven't sent any updates at all yet. */

rfbMarkRectAsModified(vncscr, 0, 0, scrinfo.xres, scrinfo.yres);

/* No idea. */

varblock.r_offset = scrinfo.red.offset + scrinfo.red.length - 5;

varblock.g_offset = scrinfo.green.offset + scrinfo.green.length - 5;

varblock.b_offset = scrinfo.blue.offset + scrinfo.blue.length - 5;

varblock.rfb_xres = scrinfo.yres;

varblock.rfb_maxy = scrinfo.xres - 1;

}

/*****************************************************************************/

void injectKeyEvent(uint16_t code, uint16_t value)

{

struct input_event ev;

memset(&ev, 0, sizeof(ev));

gettimeofday(&ev.time,0);

ev.type = EV_KEY;

ev.code = code;

ev.value = value;

if(write(kbdfd, &ev, sizeof(ev)) < 0)

{

printf("write event failed, %s\n", strerror(errno));

}

printf("injectKey (%d, %d)\n", code , value);

}

static int keysym2scancode(rfbBool down, rfbKeySym key, rfbClientPtr cl)

{

int scancode = 0;

int code = (int)key;

if (code>='0' && code<='9') {

scancode = (code & 0xF) - 1;

if (scancode<0) scancode += 10;

scancode += KEY_1;

} else if (code>=0xFF50 && code<=0xFF58) {

static const uint16_t map[] =

{ KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,

KEY_END, 0 };

scancode = map[code & 0xF];

} else if (code>=0xFFE1 && code<=0xFFEE) {

static const uint16_t map[] =

{ KEY_LEFTSHIFT, KEY_LEFTSHIFT,

KEY_COMPOSE, KEY_COMPOSE,

KEY_LEFTSHIFT, KEY_LEFTSHIFT,

0,0,

KEY_LEFTALT, KEY_RIGHTALT,

0, 0, 0, 0 };

scancode = map[code & 0xF];

} else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {

static const uint16_t map[] = {

KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,

KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,

KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,

KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,

KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };

scancode = map[(code & 0x5F) - 'A'];

} else {

switch (code) {

case 0x0020: scancode = KEY_SPACE; break;

case 0x002C: scancode = KEY_COMMA; break;

case 0x003C: scancode = KEY_COMMA; break;

case 0x002E: scancode = KEY_DOT; break;

case 0x003E: scancode = KEY_DOT; break;

case 0x002F: scancode = KEY_SLASH; break;

case 0x003F: scancode = KEY_SLASH; break;

case 0x0032: scancode = KEY_EMAIL; break;

case 0x0040: scancode = KEY_EMAIL; break;

case 0xFF08: scancode = KEY_BACKSPACE; break;

case 0xFF1B: scancode = KEY_BACK; break;

case 0xFF09: scancode = KEY_TAB; break;

case 0xFF0D: scancode = KEY_ENTER; break;

case 0xFFBE: scancode = KEY_F1; break; // F1

case 0xFFBF: scancode = KEY_F2; break; // F2

case 0xFFC0: scancode = KEY_F3; break; // F3

case 0xFFC5: scancode = KEY_F4; break; // F8

case 0xFFC8: rfbShutdownServer(cl->screen,TRUE); break; // F11

}

}

return scancode;

}

static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl)

{

int scancode;

printf("Got keysym: %04x (down=%d)\n", (unsigned int)key, (int)down);

if ((scancode = keysym2scancode(down, key, cl)))

{

injectKeyEvent(scancode, down);

}

}

void injectTouchEvent(int down, int x, int y)

{

struct input_event ev;

// Calculate the final x and y

/* Fake touch screen always reports zero */

if (xmin != 0 && xmax != 0 && ymin != 0 && ymax != 0)

{

x = xmin + (x * (xmax - xmin)) / (scrinfo.xres);

y = ymin + (y * (ymax - ymin)) / (scrinfo.yres);

}

memset(&ev, 0, sizeof(ev));

// Then send a BTN_TOUCH

gettimeofday(&ev.time,0);

ev.type = EV_KEY;

ev.code = BTN_TOUCH;

ev.value = down;

if(write(touchfd, &ev, sizeof(ev)) < 0)

{

printf("write event failed, %s\n", strerror(errno));

}

// Then send the X

gettimeofday(&ev.time,0);

ev.type = EV_ABS;

ev.code = ABS_X;

ev.value = x;

if(write(touchfd, &ev, sizeof(ev)) < 0)

{

printf("write event failed, %s\n", strerror(errno));

}

// Then send the Y

gettimeofday(&ev.time,0);

ev.type = EV_ABS;

ev.code = ABS_Y;

ev.value = y;

if(write(touchfd, &ev, sizeof(ev)) < 0)

{

printf("write event failed, %s\n", strerror(errno));

}

// Finally send the SYN

gettimeofday(&ev.time,0);

ev.type = EV_SYN;

ev.code = 0;

ev.value = 0;

if(write(touchfd, &ev, sizeof(ev)) < 0)

{

printf("write event failed, %s\n", strerror(errno));

}

printf("injectTouchEvent (x=%d, y=%d, down=%d)\n", x , y, down);

}

static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl)

{

/* Indicates either pointer movement or a pointer button press or release. The pointer is

now at (x-position, y-position), and the current state of buttons 1 to 8 are represented

by bits 0 to 7 of button-mask respectively, 0 meaning up, 1 meaning down (pressed).

On a conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and right

buttons on the mouse. On a wheel mouse, each step of the wheel upwards is represented

by a press and release of button 4, and each step downwards is represented by

a press and release of button 5.

From: http://www.vislab.usyd.edu.au/blogs/index.php/2009/05/22/an-headerless-indexed-protocol-for-input-1?blog=61 */

//printf("Got ptrevent: %04x (x=%d, y=%d)\n", buttonMask, x, y);

if(buttonMask & 1) {

// Simulate left mouse event as touch event

injectTouchEvent(1, x, y);

injectTouchEvent(0, x, y);

}

}

#define PIXEL_FB_TO_RFB(p,r,g,b) ((p>>r)&0x1f001f)|(((p>>g)&0x1f001f)<<5)|(((p>>b)&0x1f001f)<<10)

static void update_screen(void)

{

unsigned int *f, *c, *r;

int x, y;

varblock.min_i = varblock.min_j = 9999;

varblock.max_i = varblock.max_j = -1;

f = (unsigned int *)fbmmap; /* -> framebuffer */

c = (unsigned int *)fbbuf; /* -> compare framebuffer */

r = (unsigned int *)vncbuf; /* -> remote framebuffer */

for (y = 0; y < scrinfo.yres; y++)

{

/* Compare every 2 pixels at a time, assuming that changes are likely

* in pairs. */

for (x = 0; x < scrinfo.xres; x += 2)

{

unsigned int pixel = *f;

if (pixel != *c)

{

*c = pixel;

/* XXX: Undo the checkered pattern to test the efficiency

* gain using hextile encoding. */

if (pixel == 0x18e320e4 || pixel == 0x20e418e3)

pixel = 0x18e318e3;

*r = PIXEL_FB_TO_RFB(pixel,

varblock.r_offset, varblock.g_offset, varblock.b_offset);

if (x < varblock.min_i)

varblock.min_i = x;

else

{

if (x > varblock.max_i)

varblock.max_i = x;

if (y > varblock.max_j)

varblock.max_j = y;

else if (y < varblock.min_j)

varblock.min_j = y;

}

}

f++, c++;

r++;

}

}

if (varblock.min_i < 9999)

{

if (varblock.max_i < 0)

varblock.max_i = varblock.min_i;

if (varblock.max_j < 0)

varblock.max_j = varblock.min_j;

fprintf(stderr, "Dirty page: %dx%d+%d+%d...\n",

(varblock.max_i+2) - varblock.min_i, (varblock.max_j+1) - varblock.min_j,

varblock.min_i, varblock.min_j);

rfbMarkRectAsModified(vncscr, varblock.min_i, varblock.min_j,

varblock.max_i + 2, varblock.max_j + 1);

rfbProcessEvents(vncscr, 10000);

}

}

/*****************************************************************************/

void print_usage(char **argv)

{

printf("%s [-k device] [-t device] [-h]\n"

"-k device: keyboard device node, default is /dev/input/event3\n"

"-t device: touch device node, default is /dev/input/event1\n"

"-h : print this help\n", argv[0]);

}

int main(int argc, char **argv)

{

if(argc > 1)

{

int i=1;

while(i < argc)

{

if(*argv[i] == '-')

{

switch(*(argv[i] + 1))

{

case 'h':

print_usage(argv);

exit(0);

break;

case 'k':

i++;

strcpy(KBD_DEVICE, argv[i]);

break;

case 't':

i++;

strcpy(TOUCH_DEVICE, argv[i]);

break;

}

}

i++;

}

}

printf("Initializing framebuffer device " FB_DEVICE "...\n");

init_fb();

printf("Initializing keyboard device %s ...\n", KBD_DEVICE);

init_kbd();

printf("Initializing touch device %s ...\n", TOUCH_DEVICE);

init_touch();

printf("Initializing VNC server:\n");

printf("width: %d\n", (int)scrinfo.xres);

printf("height: %d\n", (int)scrinfo.yres);

printf("bpp: %d\n", (int)scrinfo.bits_per_pixel);

printf("port: %d\n", (int)VNC_PORT);

init_fb_server(argc, argv);

/* Implement our own event loop to detect changes in the framebuffer. */

while (1)

{

while (vncscr->clientHead == NULL)

rfbProcessEvents(vncscr, 100000);

rfbProcessEvents(vncscr, 100000);

update_screen();

}

printf("Cleaning up...\n");

cleanup_fb();

cleanup_kbd();

cleanup_touch();

}

相关阅读

相关文章

相关问答