mirror of
https://github.com/Cateners/tiny_computer.git
synced 2026-05-20 16:35:47 +08:00
Update code to v1.0.14 (10)
This commit is contained in:
551
android/extern/libvncserver/examples/client/SDLvncviewer.c
vendored
Normal file
551
android/extern/libvncserver/examples/client/SDLvncviewer.c
vendored
Normal file
@@ -0,0 +1,551 @@
|
||||
/**
|
||||
* @example SDLvncviewer.c
|
||||
* Once built, you can run it via `SDLvncviewer <remote-host>`.
|
||||
*/
|
||||
|
||||
#include <SDL.h>
|
||||
#include <signal.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
struct { int sdl; int rfb; } buttonMapping[]={
|
||||
{1, rfbButton1Mask},
|
||||
{2, rfbButton2Mask},
|
||||
{3, rfbButton3Mask},
|
||||
{4, rfbButton4Mask},
|
||||
{5, rfbButton5Mask},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
struct { char mask; int bits_stored; } utf8Mapping[]= {
|
||||
{0b00111111, 6},
|
||||
{0b01111111, 7},
|
||||
{0b00011111, 5},
|
||||
{0b00001111, 4},
|
||||
{0b00000111, 3},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static int enableResizable = 1, viewOnly, listenLoop, buttonMask;
|
||||
int sdlFlags;
|
||||
SDL_Texture *sdlTexture;
|
||||
SDL_Renderer *sdlRenderer;
|
||||
SDL_Window *sdlWindow;
|
||||
/* client's pointer position */
|
||||
int x,y;
|
||||
|
||||
static int rightAltKeyDown, leftAltKeyDown;
|
||||
|
||||
static rfbBool resize(rfbClient* client) {
|
||||
int width=client->width,height=client->height,
|
||||
depth=client->format.bitsPerPixel;
|
||||
|
||||
if (enableResizable)
|
||||
sdlFlags |= SDL_WINDOW_RESIZABLE;
|
||||
|
||||
client->updateRect.x = client->updateRect.y = 0;
|
||||
client->updateRect.w = width; client->updateRect.h = height;
|
||||
|
||||
/* (re)create the surface used as the client's framebuffer */
|
||||
SDL_FreeSurface(rfbClientGetClientData(client, SDL_Init));
|
||||
SDL_Surface* sdl=SDL_CreateRGBSurface(0,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
0,0,0,0);
|
||||
if(!sdl)
|
||||
rfbClientErr("resize: error creating surface: %s\n", SDL_GetError());
|
||||
|
||||
rfbClientSetClientData(client, SDL_Init, sdl);
|
||||
client->width = sdl->pitch / (depth / 8);
|
||||
client->frameBuffer=sdl->pixels;
|
||||
|
||||
client->format.bitsPerPixel=depth;
|
||||
client->format.redShift=sdl->format->Rshift;
|
||||
client->format.greenShift=sdl->format->Gshift;
|
||||
client->format.blueShift=sdl->format->Bshift;
|
||||
client->format.redMax=sdl->format->Rmask>>client->format.redShift;
|
||||
client->format.greenMax=sdl->format->Gmask>>client->format.greenShift;
|
||||
client->format.blueMax=sdl->format->Bmask>>client->format.blueShift;
|
||||
SetFormatAndEncodings(client);
|
||||
|
||||
/* create or resize the window */
|
||||
if(!sdlWindow) {
|
||||
sdlWindow = SDL_CreateWindow(client->desktopName,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
width,
|
||||
height,
|
||||
sdlFlags);
|
||||
if(!sdlWindow)
|
||||
rfbClientErr("resize: error creating window: %s\n", SDL_GetError());
|
||||
} else {
|
||||
SDL_SetWindowSize(sdlWindow, width, height);
|
||||
}
|
||||
|
||||
/* create the renderer if it does not already exist */
|
||||
if(!sdlRenderer) {
|
||||
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
|
||||
if(!sdlRenderer)
|
||||
rfbClientErr("resize: error creating renderer: %s\n", SDL_GetError());
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); /* make the scaled rendering look smoother. */
|
||||
}
|
||||
SDL_RenderSetLogicalSize(sdlRenderer, width, height); /* this is a departure from the SDL1.2-based version, but more in the sense of a VNC viewer in keeeping aspect ratio */
|
||||
|
||||
/* (re)create the texture that sits in between the surface->pixels and the renderer */
|
||||
if(sdlTexture)
|
||||
SDL_DestroyTexture(sdlTexture);
|
||||
sdlTexture = SDL_CreateTexture(sdlRenderer,
|
||||
SDL_PIXELFORMAT_ARGB8888,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width, height);
|
||||
if(!sdlTexture)
|
||||
rfbClientErr("resize: error creating texture: %s\n", SDL_GetError());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
|
||||
rfbKeySym k = 0;
|
||||
SDL_Keycode sym = e->keysym.sym;
|
||||
|
||||
switch (sym) {
|
||||
case SDLK_BACKSPACE: k = XK_BackSpace; break;
|
||||
case SDLK_TAB: k = XK_Tab; break;
|
||||
case SDLK_CLEAR: k = XK_Clear; break;
|
||||
case SDLK_RETURN: k = XK_Return; break;
|
||||
case SDLK_PAUSE: k = XK_Pause; break;
|
||||
case SDLK_ESCAPE: k = XK_Escape; break;
|
||||
case SDLK_DELETE: k = XK_Delete; break;
|
||||
case SDLK_KP_0: k = XK_KP_0; break;
|
||||
case SDLK_KP_1: k = XK_KP_1; break;
|
||||
case SDLK_KP_2: k = XK_KP_2; break;
|
||||
case SDLK_KP_3: k = XK_KP_3; break;
|
||||
case SDLK_KP_4: k = XK_KP_4; break;
|
||||
case SDLK_KP_5: k = XK_KP_5; break;
|
||||
case SDLK_KP_6: k = XK_KP_6; break;
|
||||
case SDLK_KP_7: k = XK_KP_7; break;
|
||||
case SDLK_KP_8: k = XK_KP_8; break;
|
||||
case SDLK_KP_9: k = XK_KP_9; break;
|
||||
case SDLK_KP_PERIOD: k = XK_KP_Decimal; break;
|
||||
case SDLK_KP_DIVIDE: k = XK_KP_Divide; break;
|
||||
case SDLK_KP_MULTIPLY: k = XK_KP_Multiply; break;
|
||||
case SDLK_KP_MINUS: k = XK_KP_Subtract; break;
|
||||
case SDLK_KP_PLUS: k = XK_KP_Add; break;
|
||||
case SDLK_KP_ENTER: k = XK_KP_Enter; break;
|
||||
case SDLK_KP_EQUALS: k = XK_KP_Equal; break;
|
||||
case SDLK_UP: k = XK_Up; break;
|
||||
case SDLK_DOWN: k = XK_Down; break;
|
||||
case SDLK_RIGHT: k = XK_Right; break;
|
||||
case SDLK_LEFT: k = XK_Left; break;
|
||||
case SDLK_INSERT: k = XK_Insert; break;
|
||||
case SDLK_HOME: k = XK_Home; break;
|
||||
case SDLK_END: k = XK_End; break;
|
||||
case SDLK_PAGEUP: k = XK_Page_Up; break;
|
||||
case SDLK_PAGEDOWN: k = XK_Page_Down; break;
|
||||
case SDLK_F1: k = XK_F1; break;
|
||||
case SDLK_F2: k = XK_F2; break;
|
||||
case SDLK_F3: k = XK_F3; break;
|
||||
case SDLK_F4: k = XK_F4; break;
|
||||
case SDLK_F5: k = XK_F5; break;
|
||||
case SDLK_F6: k = XK_F6; break;
|
||||
case SDLK_F7: k = XK_F7; break;
|
||||
case SDLK_F8: k = XK_F8; break;
|
||||
case SDLK_F9: k = XK_F9; break;
|
||||
case SDLK_F10: k = XK_F10; break;
|
||||
case SDLK_F11: k = XK_F11; break;
|
||||
case SDLK_F12: k = XK_F12; break;
|
||||
case SDLK_F13: k = XK_F13; break;
|
||||
case SDLK_F14: k = XK_F14; break;
|
||||
case SDLK_F15: k = XK_F15; break;
|
||||
case SDLK_NUMLOCKCLEAR: k = XK_Num_Lock; break;
|
||||
case SDLK_CAPSLOCK: k = XK_Caps_Lock; break;
|
||||
case SDLK_SCROLLLOCK: k = XK_Scroll_Lock; break;
|
||||
case SDLK_RSHIFT: k = XK_Shift_R; break;
|
||||
case SDLK_LSHIFT: k = XK_Shift_L; break;
|
||||
case SDLK_RCTRL: k = XK_Control_R; break;
|
||||
case SDLK_LCTRL: k = XK_Control_L; break;
|
||||
case SDLK_RALT: k = XK_Alt_R; break;
|
||||
case SDLK_LALT: k = XK_Alt_L; break;
|
||||
case SDLK_LGUI: k = XK_Super_L; break;
|
||||
case SDLK_RGUI: k = XK_Super_R; break;
|
||||
#if 0
|
||||
case SDLK_COMPOSE: k = XK_Compose; break;
|
||||
#endif
|
||||
case SDLK_MODE: k = XK_Mode_switch; break;
|
||||
case SDLK_HELP: k = XK_Help; break;
|
||||
case SDLK_PRINTSCREEN: k = XK_Print; break;
|
||||
case SDLK_SYSREQ: k = XK_Sys_Req; break;
|
||||
default: break;
|
||||
}
|
||||
/* SDL_TEXTINPUT does not generate characters if ctrl is down, so handle those here */
|
||||
if (k == 0 && sym > 0x0 && sym < 0x100 && e->keysym.mod & KMOD_CTRL)
|
||||
k = sym;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/* UTF-8 decoding is from https://rosettacode.org/wiki/UTF-8_encode_and_decode which is under GFDL 1.2 */
|
||||
static rfbKeySym utf8char2rfbKeySym(const char chr[4]) {
|
||||
int bytes = strlen(chr);
|
||||
int shift = utf8Mapping[0].bits_stored * (bytes - 1);
|
||||
rfbKeySym codep = (*chr++ & utf8Mapping[bytes].mask) << shift;
|
||||
int i;
|
||||
for(i = 1; i < bytes; ++i, ++chr) {
|
||||
shift -= utf8Mapping[0].bits_stored;
|
||||
codep |= ((char)*chr & utf8Mapping[0].mask) << shift;
|
||||
}
|
||||
return codep;
|
||||
}
|
||||
|
||||
static void update(rfbClient* cl,int x,int y,int w,int h) {
|
||||
SDL_Surface *sdl = rfbClientGetClientData(cl, SDL_Init);
|
||||
/* update texture from surface->pixels */
|
||||
SDL_Rect r = {x,y,w,h};
|
||||
if(SDL_UpdateTexture(sdlTexture, &r, sdl->pixels + y*sdl->pitch + x*4, sdl->pitch) < 0)
|
||||
rfbClientErr("update: failed to update texture: %s\n", SDL_GetError());
|
||||
/* copy texture to renderer and show */
|
||||
if(SDL_RenderClear(sdlRenderer) < 0)
|
||||
rfbClientErr("update: failed to clear renderer: %s\n", SDL_GetError());
|
||||
if(SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL) < 0)
|
||||
rfbClientErr("update: failed to copy texture to renderer: %s\n", SDL_GetError());
|
||||
SDL_RenderPresent(sdlRenderer);
|
||||
}
|
||||
|
||||
static void kbd_leds(rfbClient* cl, int value, int pad) {
|
||||
/* note: pad is for future expansion 0=unused */
|
||||
fprintf(stderr,"Led State= 0x%02X\n", value);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/* trivial support for textchat */
|
||||
static void text_chat(rfbClient* cl, int value, char *text) {
|
||||
switch(value) {
|
||||
case rfbTextChatOpen:
|
||||
fprintf(stderr,"TextChat: We should open a textchat window!\n");
|
||||
TextChatOpen(cl);
|
||||
break;
|
||||
case rfbTextChatClose:
|
||||
fprintf(stderr,"TextChat: We should close our window!\n");
|
||||
break;
|
||||
case rfbTextChatFinished:
|
||||
fprintf(stderr,"TextChat: We should close our window!\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"TextChat: Received \"%s\"\n", text);
|
||||
break;
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define LOG_TO_FILE
|
||||
#endif
|
||||
|
||||
#ifdef LOG_TO_FILE
|
||||
#include <stdarg.h>
|
||||
static void
|
||||
log_to_file(const char *format, ...)
|
||||
{
|
||||
FILE* logfile;
|
||||
static char* logfile_str=0;
|
||||
va_list args;
|
||||
char buf[256];
|
||||
time_t log_clock;
|
||||
|
||||
if(!rfbEnableClientLogging)
|
||||
return;
|
||||
|
||||
if(logfile_str==0) {
|
||||
logfile_str=getenv("VNCLOG");
|
||||
if(logfile_str==0)
|
||||
logfile_str="vnc.log";
|
||||
}
|
||||
|
||||
logfile=fopen(logfile_str,"a");
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
time(&log_clock);
|
||||
strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
|
||||
fprintf(logfile,buf);
|
||||
|
||||
vfprintf(logfile, format, args);
|
||||
fflush(logfile);
|
||||
|
||||
va_end(args);
|
||||
fclose(logfile);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void cleanup(rfbClient* cl)
|
||||
{
|
||||
/*
|
||||
just in case we're running in listenLoop:
|
||||
close viewer window by restarting SDL video subsystem
|
||||
*/
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||
if(cl)
|
||||
rfbClientCleanup(cl);
|
||||
}
|
||||
|
||||
|
||||
static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
|
||||
{
|
||||
switch(e->type) {
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (e->window.event) {
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
SendFramebufferUpdateRequest(cl, 0, 0,
|
||||
cl->width, cl->height, FALSE);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
SendExtDesktopSize(cl, e->window.data1, e->window.data2);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
if (SDL_HasClipboardText()) {
|
||||
char *text = SDL_GetClipboardText();
|
||||
if(text) {
|
||||
rfbClientLog("sending clipboard text '%s'\n", text);
|
||||
if(!SendClientCutTextUTF8(cl, text, strlen(text)))
|
||||
SendClientCutText(cl, text, strlen(text));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
if (rightAltKeyDown) {
|
||||
SendKeyEvent(cl, XK_Alt_R, FALSE);
|
||||
rightAltKeyDown = FALSE;
|
||||
rfbClientLog("released right Alt key\n");
|
||||
}
|
||||
if (leftAltKeyDown) {
|
||||
SendKeyEvent(cl, XK_Alt_L, FALSE);
|
||||
leftAltKeyDown = FALSE;
|
||||
rfbClientLog("released left Alt key\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
int steps;
|
||||
if (viewOnly)
|
||||
break;
|
||||
|
||||
if(e->wheel.y > 0)
|
||||
for(steps = 0; steps < e->wheel.y; ++steps) {
|
||||
SendPointerEvent(cl, x, y, rfbButton4Mask);
|
||||
SendPointerEvent(cl, x, y, 0);
|
||||
}
|
||||
if(e->wheel.y < 0)
|
||||
for(steps = 0; steps > e->wheel.y; --steps) {
|
||||
SendPointerEvent(cl, x, y, rfbButton5Mask);
|
||||
SendPointerEvent(cl, x, y, 0);
|
||||
}
|
||||
if(e->wheel.x > 0)
|
||||
for(steps = 0; steps < e->wheel.x; ++steps) {
|
||||
SendPointerEvent(cl, x, y, 0b01000000);
|
||||
SendPointerEvent(cl, x, y, 0);
|
||||
}
|
||||
if(e->wheel.x < 0)
|
||||
for(steps = 0; steps > e->wheel.x; --steps) {
|
||||
SendPointerEvent(cl, x, y, 0b00100000);
|
||||
SendPointerEvent(cl, x, y, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
int state, i;
|
||||
if (viewOnly)
|
||||
break;
|
||||
|
||||
if (e->type == SDL_MOUSEMOTION) {
|
||||
x = e->motion.x;
|
||||
y = e->motion.y;
|
||||
state = e->motion.state;
|
||||
}
|
||||
else {
|
||||
x = e->button.x;
|
||||
y = e->button.y;
|
||||
state = e->button.button;
|
||||
for (i = 0; buttonMapping[i].sdl; i++)
|
||||
if (state == buttonMapping[i].sdl) {
|
||||
state = buttonMapping[i].rfb;
|
||||
if (e->type == SDL_MOUSEBUTTONDOWN)
|
||||
buttonMask |= state;
|
||||
else
|
||||
buttonMask &= ~state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SendPointerEvent(cl, x, y, buttonMask);
|
||||
buttonMask &= ~(rfbButton4Mask | rfbButton5Mask);
|
||||
break;
|
||||
}
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYDOWN:
|
||||
if (viewOnly)
|
||||
break;
|
||||
SendKeyEvent(cl, SDL_key2rfbKeySym(&e->key),
|
||||
e->type == SDL_KEYDOWN ? TRUE : FALSE);
|
||||
if (e->key.keysym.sym == SDLK_RALT)
|
||||
rightAltKeyDown = e->type == SDL_KEYDOWN;
|
||||
if (e->key.keysym.sym == SDLK_LALT)
|
||||
leftAltKeyDown = e->type == SDL_KEYDOWN;
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
if (viewOnly)
|
||||
break;
|
||||
rfbKeySym sym = utf8char2rfbKeySym(e->text.text);
|
||||
SendKeyEvent(cl, sym, TRUE);
|
||||
SendKeyEvent(cl, sym, FALSE);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
if(listenLoop)
|
||||
{
|
||||
cleanup(cl);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rfbClientCleanup(cl);
|
||||
exit(0);
|
||||
}
|
||||
default:
|
||||
rfbClientLog("ignore SDL event: 0x%x\n", e->type);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void got_selection_latin1(rfbClient *cl, const char *text, int len)
|
||||
{
|
||||
rfbClientLog("received latin1 clipboard text '%s'\n", text);
|
||||
if(SDL_SetClipboardText(text) != 0)
|
||||
rfbClientErr("could not set received latin1 clipboard text: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
static void got_selection_utf8(rfbClient *cl, const char *buf, int len)
|
||||
{
|
||||
rfbClientLog("received utf8 clipboard text '%s'\n", buf);
|
||||
if(SDL_SetClipboardText(buf) != 0)
|
||||
rfbClientErr("could not set received utf8 clipboard text: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
|
||||
static rfbCredential* get_credential(rfbClient* cl, int credentialType){
|
||||
rfbCredential *c = malloc(sizeof(rfbCredential));
|
||||
c->userCredential.username = malloc(RFB_BUF_SIZE);
|
||||
c->userCredential.password = malloc(RFB_BUF_SIZE);
|
||||
|
||||
if(credentialType != rfbCredentialTypeUser) {
|
||||
rfbClientErr("something else than username and password required for authentication\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rfbClientLog("username and password required for authentication!\n");
|
||||
printf("user: ");
|
||||
fgets(c->userCredential.username, RFB_BUF_SIZE, stdin);
|
||||
printf("pass: ");
|
||||
fgets(c->userCredential.password, RFB_BUF_SIZE, stdin);
|
||||
|
||||
/* remove trailing newlines */
|
||||
c->userCredential.username[strcspn(c->userCredential.username, "\n")] = 0;
|
||||
c->userCredential.password[strcspn(c->userCredential.password, "\n")] = 0;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
#ifdef mac
|
||||
#define main SDLmain
|
||||
#endif
|
||||
|
||||
int main(int argc,char** argv) {
|
||||
rfbClient* cl;
|
||||
int i, j;
|
||||
SDL_Event e;
|
||||
|
||||
#ifdef LOG_TO_FILE
|
||||
rfbClientLog=rfbClientErr=log_to_file;
|
||||
#endif
|
||||
|
||||
for (i = 1, j = 1; i < argc; i++)
|
||||
if (!strcmp(argv[i], "-viewonly"))
|
||||
viewOnly = 1;
|
||||
else if (!strcmp(argv[i], "-resizable"))
|
||||
enableResizable = 1;
|
||||
else if (!strcmp(argv[i], "-no-resizable"))
|
||||
enableResizable = 0;
|
||||
else if (!strcmp(argv[i], "-listen")) {
|
||||
listenLoop = 1;
|
||||
argv[i] = "-listennofork";
|
||||
++j;
|
||||
}
|
||||
else {
|
||||
if (i != j)
|
||||
argv[j] = argv[i];
|
||||
j++;
|
||||
}
|
||||
argc = j;
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
|
||||
atexit(SDL_Quit);
|
||||
signal(SIGINT, exit);
|
||||
|
||||
do {
|
||||
/* 16-bit: cl=rfbGetClient(5,3,2); */
|
||||
cl=rfbGetClient(8,3,4);
|
||||
cl->MallocFrameBuffer=resize;
|
||||
cl->canHandleNewFBSize = TRUE;
|
||||
cl->GotFrameBufferUpdate=update;
|
||||
cl->HandleKeyboardLedState=kbd_leds;
|
||||
cl->HandleTextChat=text_chat;
|
||||
/* two different cut text handlers here for demo purposes, you
|
||||
might as well use the same callback for both if it doesn't
|
||||
matter for your application */
|
||||
cl->GotXCutText = got_selection_latin1;
|
||||
cl->GotXCutTextUTF8 = got_selection_utf8;
|
||||
cl->GetCredential = get_credential;
|
||||
cl->listenPort = LISTEN_PORT_OFFSET;
|
||||
cl->listen6Port = LISTEN_PORT_OFFSET;
|
||||
if(!rfbInitClient(cl,&argc,argv))
|
||||
{
|
||||
cl = NULL; /* rfbInitClient has already freed the client struct */
|
||||
cleanup(cl);
|
||||
break;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(SDL_PollEvent(&e)) {
|
||||
/*
|
||||
handleSDLEvent() return 0 if user requested window close.
|
||||
In this case, handleSDLEvent() will have called cleanup().
|
||||
*/
|
||||
if(!handleSDLEvent(cl, &e))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
i=WaitForMessage(cl,500);
|
||||
if(i<0)
|
||||
{
|
||||
cleanup(cl);
|
||||
break;
|
||||
}
|
||||
if(i)
|
||||
if(!HandleRFBServerMessage(cl))
|
||||
{
|
||||
cleanup(cl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while(listenLoop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
104
android/extern/libvncserver/examples/client/backchannel.c
vendored
Normal file
104
android/extern/libvncserver/examples/client/backchannel.c
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @example backchannel-client.c
|
||||
* A simple example of an RFB client
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
static void HandleRect(rfbClient* client, int x, int y, int w, int h) {
|
||||
}
|
||||
|
||||
/*
|
||||
* The client part of the back channel extension example.
|
||||
*
|
||||
*/
|
||||
|
||||
#define rfbBackChannel 155
|
||||
|
||||
typedef struct backChannelMsg {
|
||||
uint8_t type;
|
||||
uint8_t pad1;
|
||||
uint16_t pad2;
|
||||
uint32_t size;
|
||||
} backChannelMsg;
|
||||
|
||||
static void sendMessage(rfbClient* client, char* text)
|
||||
{
|
||||
backChannelMsg msg;
|
||||
uint32_t length = strlen(text)+1;
|
||||
|
||||
msg.type = rfbBackChannel;
|
||||
msg.size = rfbClientSwap32IfLE(length);
|
||||
if(!WriteToRFBServer(client, (char*)&msg, sizeof(msg)) ||
|
||||
!WriteToRFBServer(client, text, length)) {
|
||||
rfbClientLog("enableBackChannel: write error (%d: %s)", errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static rfbBool handleBackChannelMessage(rfbClient* client,
|
||||
rfbServerToClientMsg* message)
|
||||
{
|
||||
backChannelMsg msg;
|
||||
char* text;
|
||||
|
||||
if(message->type != rfbBackChannel)
|
||||
return FALSE;
|
||||
|
||||
rfbClientSetClientData(client, sendMessage, sendMessage);
|
||||
|
||||
if(!ReadFromRFBServer(client, ((char*)&msg)+1, sizeof(msg)-1))
|
||||
return TRUE;
|
||||
msg.size = rfbClientSwap32IfLE(msg.size);
|
||||
text = malloc(msg.size);
|
||||
if(!ReadFromRFBServer(client, text, msg.size)) {
|
||||
free(text);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rfbClientLog("got back channel message: %s\n", text);
|
||||
free(text);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int backChannelEncodings[] = { rfbBackChannel, 0 };
|
||||
|
||||
static rfbClientProtocolExtension backChannel = {
|
||||
backChannelEncodings, /* encodings */
|
||||
NULL, /* handleEncoding */
|
||||
handleBackChannelMessage, /* handleMessage */
|
||||
NULL, /* next extension */
|
||||
NULL, /* securityTypes */
|
||||
NULL /* handleAuthentication */
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
rfbClient* client = rfbGetClient(8,3,4);
|
||||
|
||||
client->GotFrameBufferUpdate = HandleRect;
|
||||
rfbClientRegisterExtension(&backChannel);
|
||||
|
||||
if (!rfbInitClient(client,&argc,argv))
|
||||
return 1;
|
||||
|
||||
while (1) {
|
||||
/* After each idle second, send a message */
|
||||
if(WaitForMessage(client,1000000)>0)
|
||||
HandleRFBServerMessage(client);
|
||||
else if(rfbClientGetClientData(client, sendMessage))
|
||||
sendMessage(client, "Dear Server,\n"
|
||||
"thank you for understanding "
|
||||
"back channel messages!");
|
||||
}
|
||||
|
||||
rfbClientCleanup(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
677
android/extern/libvncserver/examples/client/gtkvncviewer.c
vendored
Normal file
677
android/extern/libvncserver/examples/client/gtkvncviewer.c
vendored
Normal file
@@ -0,0 +1,677 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2007 - Mateus Cesar Groess
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
static rfbClient *cl;
|
||||
static gchar *server_cut_text = NULL;
|
||||
static gboolean framebuffer_allocated = FALSE;
|
||||
static GtkWidget *window;
|
||||
static GtkWidget *dialog_connecting = NULL;
|
||||
|
||||
/* Redraw the screen from the backing pixmap */
|
||||
static gboolean expose_event (GtkWidget *widget,
|
||||
GdkEventExpose *event)
|
||||
{
|
||||
static GdkImage *image = NULL;
|
||||
|
||||
if (framebuffer_allocated == FALSE) {
|
||||
|
||||
rfbClientSetClientData (cl, gtk_init, widget);
|
||||
|
||||
image = gdk_drawable_get_image (widget->window, 0, 0,
|
||||
widget->allocation.width,
|
||||
widget->allocation.height);
|
||||
|
||||
cl->frameBuffer= image->mem;
|
||||
|
||||
cl->width = widget->allocation.width;
|
||||
cl->height = widget->allocation.height;
|
||||
|
||||
cl->format.bitsPerPixel = image->bits_per_pixel;
|
||||
cl->format.redShift = image->visual->red_shift;
|
||||
cl->format.greenShift = image->visual->green_shift;
|
||||
cl->format.blueShift = image->visual->blue_shift;
|
||||
|
||||
cl->format.redMax = (1 << image->visual->red_prec) - 1;
|
||||
cl->format.greenMax = (1 << image->visual->green_prec) - 1;
|
||||
cl->format.blueMax = (1 << image->visual->blue_prec) - 1;
|
||||
|
||||
SetFormatAndEncodings (cl);
|
||||
|
||||
framebuffer_allocated = TRUE;
|
||||
|
||||
/* Also disable local cursor */
|
||||
GdkCursor* cur = gdk_cursor_new( GDK_BLANK_CURSOR );
|
||||
gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)), cur);
|
||||
gdk_cursor_unref( cur );
|
||||
}
|
||||
|
||||
gdk_draw_image (GDK_DRAWABLE (widget->window),
|
||||
widget->style->fg_gc[gtk_widget_get_state(widget)],
|
||||
image,
|
||||
event->area.x, event->area.y,
|
||||
event->area.x, event->area.y,
|
||||
event->area.width, event->area.height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct { int gdk; int rfb; } buttonMapping[] = {
|
||||
{ GDK_BUTTON1_MASK, rfbButton1Mask },
|
||||
{ GDK_BUTTON2_MASK, rfbButton2Mask },
|
||||
{ GDK_BUTTON3_MASK, rfbButton3Mask },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static gboolean button_event (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
int x, y;
|
||||
GdkModifierType state;
|
||||
int i, buttonMask;
|
||||
|
||||
gdk_window_get_pointer (event->window, &x, &y, &state);
|
||||
|
||||
for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
|
||||
if (state & buttonMapping[i].gdk)
|
||||
buttonMask |= buttonMapping[i].rfb;
|
||||
SendPointerEvent (cl, x, y, buttonMask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean motion_notify_event (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
int x, y;
|
||||
GdkModifierType state;
|
||||
int i, buttonMask;
|
||||
|
||||
if (event->is_hint)
|
||||
gdk_window_get_pointer (event->window, &x, &y, &state);
|
||||
else {
|
||||
x = event->x;
|
||||
y = event->y;
|
||||
state = event->state;
|
||||
}
|
||||
|
||||
for (buttonMask = 0, i = 0; buttonMapping[i].gdk; i++)
|
||||
if (state & buttonMapping[i].gdk)
|
||||
buttonMask |= buttonMapping[i].rfb;
|
||||
SendPointerEvent (cl, x, y, buttonMask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void got_cut_text (rfbClient *cl, const char *text, int textlen)
|
||||
{
|
||||
if (server_cut_text != NULL) {
|
||||
g_free (server_cut_text);
|
||||
server_cut_text = NULL;
|
||||
}
|
||||
|
||||
server_cut_text = g_strdup (text);
|
||||
}
|
||||
|
||||
void received_text_from_clipboard (GtkClipboard *clipboard,
|
||||
const gchar *text,
|
||||
gpointer data)
|
||||
{
|
||||
if (text)
|
||||
SendClientCutText (cl, (char *) text, strlen (text));
|
||||
}
|
||||
|
||||
static void clipboard_local_to_remote (GtkMenuItem *menuitem,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkClipboard *clipboard;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
|
||||
GDK_SELECTION_CLIPBOARD);
|
||||
gtk_clipboard_request_text (clipboard, received_text_from_clipboard,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void clipboard_remote_to_local (GtkMenuItem *menuitem,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkClipboard *clipboard;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (menuitem),
|
||||
GDK_SELECTION_CLIPBOARD);
|
||||
|
||||
gtk_clipboard_set_text (clipboard, server_cut_text,
|
||||
strlen (server_cut_text));
|
||||
}
|
||||
|
||||
static void request_screen_refresh (GtkMenuItem *menuitem,
|
||||
gpointer user_data)
|
||||
{
|
||||
SendFramebufferUpdateRequest (cl, 0, 0, cl->width, cl->height, FALSE);
|
||||
}
|
||||
|
||||
static void send_f8 (GtkMenuItem *menuitem,
|
||||
gpointer user_data)
|
||||
{
|
||||
SendKeyEvent(cl, XK_F8, TRUE);
|
||||
SendKeyEvent(cl, XK_F8, FALSE);
|
||||
}
|
||||
|
||||
static void send_crtl_alt_del (GtkMenuItem *menuitem,
|
||||
gpointer user_data)
|
||||
{
|
||||
SendKeyEvent(cl, XK_Control_L, TRUE);
|
||||
SendKeyEvent(cl, XK_Alt_L, TRUE);
|
||||
SendKeyEvent(cl, XK_Delete, TRUE);
|
||||
SendKeyEvent(cl, XK_Alt_L, FALSE);
|
||||
SendKeyEvent(cl, XK_Control_L, FALSE);
|
||||
SendKeyEvent(cl, XK_Delete, FALSE);
|
||||
}
|
||||
|
||||
static void show_connect_window(int argc, char **argv)
|
||||
{
|
||||
GtkWidget *label;
|
||||
char buf[256];
|
||||
|
||||
dialog_connecting = gtk_dialog_new_with_buttons ("VNC Viewer",
|
||||
NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
/*GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL,*/
|
||||
NULL);
|
||||
|
||||
/* FIXME: this works only when address[:port] is at end of arg list */
|
||||
char *server;
|
||||
if(argc==1)
|
||||
server = "localhost";
|
||||
else
|
||||
server = argv[argc-1];
|
||||
snprintf(buf, 255, "Connecting to %s...", server);
|
||||
|
||||
label = gtk_label_new (buf);
|
||||
gtk_widget_show (label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog_connecting)->vbox),
|
||||
label);
|
||||
|
||||
gtk_widget_show (dialog_connecting);
|
||||
|
||||
while (gtk_events_pending ())
|
||||
gtk_main_iteration ();
|
||||
}
|
||||
|
||||
static void show_popup_menu()
|
||||
{
|
||||
GtkWidget *popup_menu;
|
||||
GtkWidget *menu_item;
|
||||
|
||||
popup_menu = gtk_menu_new ();
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Dismiss popup");
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Clipboard: local -> remote");
|
||||
g_signal_connect (G_OBJECT (menu_item), "activate",
|
||||
G_CALLBACK (clipboard_local_to_remote), NULL);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Clipboard: local <- remote");
|
||||
g_signal_connect (G_OBJECT (menu_item), "activate",
|
||||
G_CALLBACK (clipboard_remote_to_local), NULL);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Request refresh");
|
||||
g_signal_connect (G_OBJECT (menu_item), "activate",
|
||||
G_CALLBACK (request_screen_refresh), NULL);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Send ctrl-alt-del");
|
||||
g_signal_connect (G_OBJECT (menu_item), "activate",
|
||||
G_CALLBACK (send_crtl_alt_del), NULL);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_label ("Send F8");
|
||||
g_signal_connect (G_OBJECT (menu_item), "activate",
|
||||
G_CALLBACK (send_f8), NULL);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menu_item);
|
||||
|
||||
gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, NULL, NULL, 0,
|
||||
gtk_get_current_event_time());
|
||||
}
|
||||
|
||||
static rfbKeySym gdkKey2rfbKeySym(guint keyval)
|
||||
{
|
||||
rfbKeySym k = 0;
|
||||
switch(keyval) {
|
||||
case GDK_BackSpace: k = XK_BackSpace; break;
|
||||
case GDK_Tab: k = XK_Tab; break;
|
||||
case GDK_Clear: k = XK_Clear; break;
|
||||
case GDK_Return: k = XK_Return; break;
|
||||
case GDK_Pause: k = XK_Pause; break;
|
||||
case GDK_Escape: k = XK_Escape; break;
|
||||
case GDK_space: k = XK_space; break;
|
||||
case GDK_Delete: k = XK_Delete; break;
|
||||
case GDK_KP_0: k = XK_KP_0; break;
|
||||
case GDK_KP_1: k = XK_KP_1; break;
|
||||
case GDK_KP_2: k = XK_KP_2; break;
|
||||
case GDK_KP_3: k = XK_KP_3; break;
|
||||
case GDK_KP_4: k = XK_KP_4; break;
|
||||
case GDK_KP_5: k = XK_KP_5; break;
|
||||
case GDK_KP_6: k = XK_KP_6; break;
|
||||
case GDK_KP_7: k = XK_KP_7; break;
|
||||
case GDK_KP_8: k = XK_KP_8; break;
|
||||
case GDK_KP_9: k = XK_KP_9; break;
|
||||
case GDK_KP_Decimal: k = XK_KP_Decimal; break;
|
||||
case GDK_KP_Divide: k = XK_KP_Divide; break;
|
||||
case GDK_KP_Multiply: k = XK_KP_Multiply; break;
|
||||
case GDK_KP_Subtract: k = XK_KP_Subtract; break;
|
||||
case GDK_KP_Add: k = XK_KP_Add; break;
|
||||
case GDK_KP_Enter: k = XK_KP_Enter; break;
|
||||
case GDK_KP_Equal: k = XK_KP_Equal; break;
|
||||
case GDK_Up: k = XK_Up; break;
|
||||
case GDK_Down: k = XK_Down; break;
|
||||
case GDK_Right: k = XK_Right; break;
|
||||
case GDK_Left: k = XK_Left; break;
|
||||
case GDK_Insert: k = XK_Insert; break;
|
||||
case GDK_Home: k = XK_Home; break;
|
||||
case GDK_End: k = XK_End; break;
|
||||
case GDK_Page_Up: k = XK_Page_Up; break;
|
||||
case GDK_Page_Down: k = XK_Page_Down; break;
|
||||
case GDK_F1: k = XK_F1; break;
|
||||
case GDK_F2: k = XK_F2; break;
|
||||
case GDK_F3: k = XK_F3; break;
|
||||
case GDK_F4: k = XK_F4; break;
|
||||
case GDK_F5: k = XK_F5; break;
|
||||
case GDK_F6: k = XK_F6; break;
|
||||
case GDK_F7: k = XK_F7; break;
|
||||
case GDK_F8: k = XK_F8; break;
|
||||
case GDK_F9: k = XK_F9; break;
|
||||
case GDK_F10: k = XK_F10; break;
|
||||
case GDK_F11: k = XK_F11; break;
|
||||
case GDK_F12: k = XK_F12; break;
|
||||
case GDK_F13: k = XK_F13; break;
|
||||
case GDK_F14: k = XK_F14; break;
|
||||
case GDK_F15: k = XK_F15; break;
|
||||
case GDK_Num_Lock: k = XK_Num_Lock; break;
|
||||
case GDK_Caps_Lock: k = XK_Caps_Lock; break;
|
||||
case GDK_Scroll_Lock: k = XK_Scroll_Lock; break;
|
||||
case GDK_Shift_R: k = XK_Shift_R; break;
|
||||
case GDK_Shift_L: k = XK_Shift_L; break;
|
||||
case GDK_Control_R: k = XK_Control_R; break;
|
||||
case GDK_Control_L: k = XK_Control_L; break;
|
||||
case GDK_Alt_R: k = XK_Alt_R; break;
|
||||
case GDK_Alt_L: k = XK_Alt_L; break;
|
||||
case GDK_Meta_R: k = XK_Meta_R; break;
|
||||
case GDK_Meta_L: k = XK_Meta_L; break;
|
||||
#if 0
|
||||
/* TODO: find out keysyms */
|
||||
case GDK_Super_L: k = XK_LSuper; break; /* left "windows" key */
|
||||
case GDK_Super_R: k = XK_RSuper; break; /* right "windows" key */
|
||||
case GDK_Multi_key: k = XK_Compose; break;
|
||||
#endif
|
||||
case GDK_Mode_switch: k = XK_Mode_switch; break;
|
||||
case GDK_Help: k = XK_Help; break;
|
||||
case GDK_Print: k = XK_Print; break;
|
||||
case GDK_Sys_Req: k = XK_Sys_Req; break;
|
||||
case GDK_Break: k = XK_Break; break;
|
||||
default: break;
|
||||
}
|
||||
if (k == 0) {
|
||||
if (keyval < 0x100)
|
||||
k = keyval;
|
||||
else
|
||||
rfbClientLog ("Unknown keysym: %d\n", keyval);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static gboolean key_event (GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
if ((event->type == GDK_KEY_PRESS) && (event->keyval == GDK_F8))
|
||||
show_popup_menu();
|
||||
else
|
||||
SendKeyEvent(cl, gdkKey2rfbKeySym (event->keyval),
|
||||
(event->type == GDK_KEY_PRESS) ? TRUE : FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void quit ()
|
||||
{
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static rfbBool resize (rfbClient *client) {
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *drawing_area=NULL;
|
||||
static char first=TRUE;
|
||||
int tmp_width, tmp_height;
|
||||
|
||||
if (first) {
|
||||
first=FALSE;
|
||||
|
||||
/* Create the drawing area */
|
||||
|
||||
drawing_area = gtk_drawing_area_new ();
|
||||
gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
|
||||
client->width, client->height);
|
||||
|
||||
/* Signals used to handle backing pixmap */
|
||||
|
||||
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
|
||||
G_CALLBACK (expose_event), NULL);
|
||||
|
||||
/* Event signals */
|
||||
|
||||
g_signal_connect (G_OBJECT (drawing_area),
|
||||
"motion-notify-event",
|
||||
G_CALLBACK (motion_notify_event), NULL);
|
||||
g_signal_connect (G_OBJECT (drawing_area),
|
||||
"button-press-event",
|
||||
G_CALLBACK (button_event), NULL);
|
||||
g_signal_connect (G_OBJECT (drawing_area),
|
||||
"button-release-event",
|
||||
G_CALLBACK (button_event), NULL);
|
||||
|
||||
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
|
||||
| GDK_LEAVE_NOTIFY_MASK
|
||||
| GDK_BUTTON_PRESS_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_POINTER_MOTION_MASK
|
||||
| GDK_POINTER_MOTION_HINT_MASK);
|
||||
|
||||
gtk_widget_show (drawing_area);
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_add_with_viewport (
|
||||
GTK_SCROLLED_WINDOW (scrolled_window),
|
||||
drawing_area);
|
||||
g_signal_connect (G_OBJECT (scrolled_window),
|
||||
"key-press-event", G_CALLBACK (key_event),
|
||||
NULL);
|
||||
g_signal_connect (G_OBJECT (scrolled_window),
|
||||
"key-release-event", G_CALLBACK (key_event),
|
||||
NULL);
|
||||
gtk_widget_show (scrolled_window);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), client->desktopName);
|
||||
gtk_container_add (GTK_CONTAINER (window), scrolled_window);
|
||||
tmp_width = (int) (
|
||||
gdk_screen_get_width (gdk_screen_get_default ())
|
||||
* 0.85);
|
||||
if (client->width > tmp_width) {
|
||||
tmp_height = (int) (
|
||||
gdk_screen_get_height (
|
||||
gdk_screen_get_default ())
|
||||
* 0.85);
|
||||
gtk_widget_set_size_request (window,
|
||||
tmp_width, tmp_height);
|
||||
} else {
|
||||
gtk_widget_set_size_request (window,
|
||||
client->width + 2,
|
||||
client->height + 2);
|
||||
}
|
||||
|
||||
g_signal_connect (G_OBJECT (window), "destroy",
|
||||
G_CALLBACK (quit), NULL);
|
||||
|
||||
gtk_widget_show (window);
|
||||
} else {
|
||||
gtk_widget_set_size_request (GTK_WIDGET (drawing_area),
|
||||
client->width, client->height);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void update (rfbClient *cl, int x, int y, int w, int h) {
|
||||
if (dialog_connecting != NULL) {
|
||||
gtk_widget_destroy (dialog_connecting);
|
||||
dialog_connecting = NULL;
|
||||
}
|
||||
|
||||
GtkWidget *drawing_area = rfbClientGetClientData (cl, gtk_init);
|
||||
|
||||
if (drawing_area != NULL)
|
||||
gtk_widget_queue_draw_area (drawing_area, x, y, w, h);
|
||||
}
|
||||
|
||||
static void kbd_leds (rfbClient *cl, int value, int pad) {
|
||||
/* note: pad is for future expansion 0=unused */
|
||||
fprintf (stderr, "Led State= 0x%02X\n", value);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
/* trivial support for textchat */
|
||||
static void text_chat (rfbClient *cl, int value, char *text) {
|
||||
switch (value) {
|
||||
case rfbTextChatOpen:
|
||||
fprintf (stderr, "TextChat: We should open a textchat window!\n");
|
||||
TextChatOpen (cl);
|
||||
break;
|
||||
case rfbTextChatClose:
|
||||
fprintf (stderr, "TextChat: We should close our window!\n");
|
||||
break;
|
||||
case rfbTextChatFinished:
|
||||
fprintf (stderr, "TextChat: We should close our window!\n");
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "TextChat: Received \"%s\"\n", text);
|
||||
break;
|
||||
}
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
static gboolean on_entry_key_press_event (GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (event->keyval == GDK_Escape)
|
||||
gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_REJECT);
|
||||
else if (event->keyval == GDK_Return)
|
||||
gtk_dialog_response (GTK_DIALOG(user_data), GTK_RESPONSE_ACCEPT);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void GtkErrorLog (const char *format, ...)
|
||||
{
|
||||
GtkWidget *dialog, *label;
|
||||
va_list args;
|
||||
char buf[256];
|
||||
|
||||
if (dialog_connecting != NULL) {
|
||||
gtk_widget_destroy (dialog_connecting);
|
||||
dialog_connecting = NULL;
|
||||
}
|
||||
|
||||
va_start (args, format);
|
||||
vsnprintf (buf, 255, format, args);
|
||||
va_end (args);
|
||||
|
||||
if (g_utf8_validate (buf, strlen (buf), NULL)) {
|
||||
label = gtk_label_new (buf);
|
||||
} else {
|
||||
const gchar *charset;
|
||||
gchar *utf8;
|
||||
|
||||
(void) g_get_charset (&charset);
|
||||
utf8 = g_convert_with_fallback (buf, strlen (buf), "UTF-8",
|
||||
charset, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (utf8) {
|
||||
label = gtk_label_new (utf8);
|
||||
g_free (utf8);
|
||||
} else {
|
||||
label = gtk_label_new (buf);
|
||||
g_warning ("Message Output is not in UTF-8"
|
||||
"nor in locale charset.\n");
|
||||
}
|
||||
}
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons ("Error",
|
||||
NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_OK,
|
||||
GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
label = gtk_label_new (buf);
|
||||
gtk_widget_show (label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
||||
label);
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
|
||||
case GTK_RESPONSE_ACCEPT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void GtkDefaultLog (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[256];
|
||||
time_t log_clock;
|
||||
|
||||
va_start (args, format);
|
||||
|
||||
time (&log_clock);
|
||||
strftime (buf, 255, "%d/%m/%Y %X ", localtime (&log_clock));
|
||||
fprintf (stdout, "%s", buf);
|
||||
|
||||
vfprintf (stdout, format, args);
|
||||
fflush (stdout);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
static char * get_password (rfbClient *client)
|
||||
{
|
||||
GtkWidget *dialog, *entry;
|
||||
char *password;
|
||||
|
||||
gtk_widget_destroy (dialog_connecting);
|
||||
dialog_connecting = NULL;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons ("Password",
|
||||
NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_REJECT,
|
||||
GTK_STOCK_OK,
|
||||
GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_visibility (GTK_ENTRY (entry),
|
||||
FALSE);
|
||||
g_signal_connect (GTK_OBJECT(entry), "key-press-event",
|
||||
G_CALLBACK(on_entry_key_press_event),
|
||||
GTK_OBJECT (dialog));
|
||||
gtk_widget_show (entry);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
|
||||
entry);
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
|
||||
case GTK_RESPONSE_ACCEPT:
|
||||
password = strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||
break;
|
||||
default:
|
||||
password = NULL;
|
||||
break;
|
||||
}
|
||||
gtk_widget_destroy (dialog);
|
||||
return password;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
GdkImage *image;
|
||||
|
||||
rfbClientLog = GtkDefaultLog;
|
||||
rfbClientErr = GtkErrorLog;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
/* create a dummy image just to make use of its properties */
|
||||
image = gdk_image_new (GDK_IMAGE_FASTEST, gdk_visual_get_system(),
|
||||
200, 100);
|
||||
|
||||
cl = rfbGetClient (image->depth / 3, 3, image->bpp);
|
||||
|
||||
cl->format.redShift = image->visual->red_shift;
|
||||
cl->format.greenShift = image->visual->green_shift;
|
||||
cl->format.blueShift = image->visual->blue_shift;
|
||||
|
||||
cl->format.redMax = (1 << image->visual->red_prec) - 1;
|
||||
cl->format.greenMax = (1 << image->visual->green_prec) - 1;
|
||||
cl->format.blueMax = (1 << image->visual->blue_prec) - 1;
|
||||
|
||||
g_object_unref (image);
|
||||
|
||||
cl->MallocFrameBuffer = resize;
|
||||
cl->canHandleNewFBSize = TRUE;
|
||||
cl->GotFrameBufferUpdate = update;
|
||||
cl->GotXCutText = got_cut_text;
|
||||
cl->HandleKeyboardLedState = kbd_leds;
|
||||
cl->HandleTextChat = text_chat;
|
||||
cl->GetPassword = get_password;
|
||||
|
||||
show_connect_window (argc, argv);
|
||||
|
||||
if (!rfbInitClient (cl, &argc, argv))
|
||||
return 1;
|
||||
|
||||
while (1) {
|
||||
while (gtk_events_pending ())
|
||||
gtk_main_iteration ();
|
||||
i = WaitForMessage (cl, 500);
|
||||
if (i < 0)
|
||||
return 0;
|
||||
if (i && framebuffer_allocated == TRUE)
|
||||
if (!HandleRFBServerMessage(cl))
|
||||
return 0;
|
||||
}
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
117
android/extern/libvncserver/examples/client/ppmtest.c
vendored
Normal file
117
android/extern/libvncserver/examples/client/ppmtest.c
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @example ppmtest.c
|
||||
* A simple example of an RFB client
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
static void PrintRect(rfbClient* client, int x, int y, int w, int h) {
|
||||
rfbClientLog("Received an update for %d,%d,%d,%d.\n",x,y,w,h);
|
||||
}
|
||||
|
||||
static void SaveFramebufferAsPPM(rfbClient* client, int x, int y, int w, int h) {
|
||||
static time_t t=0,t1;
|
||||
FILE* f;
|
||||
int i,j;
|
||||
rfbPixelFormat* pf=&client->format;
|
||||
int bpp=pf->bitsPerPixel/8;
|
||||
int row_stride=client->width*bpp;
|
||||
|
||||
/* save one picture only if the last is older than 2 seconds */
|
||||
t1=time(NULL);
|
||||
if(t1-t>2)
|
||||
t=t1;
|
||||
else
|
||||
return;
|
||||
|
||||
/* assert bpp=4 */
|
||||
if(bpp!=4 && bpp!=2) {
|
||||
rfbClientLog("bpp = %d (!=4)\n",bpp);
|
||||
return;
|
||||
}
|
||||
|
||||
f=fopen("framebuffer.ppm","wb");
|
||||
if(!f) {
|
||||
rfbClientErr("Could not open framebuffer.ppm\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f,"P6\n# %s\n%d %d\n255\n",client->desktopName,client->width,client->height);
|
||||
for(j=0;j<client->height*row_stride;j+=row_stride)
|
||||
for(i=0;i<client->width*bpp;i+=bpp) {
|
||||
unsigned char* p=client->frameBuffer+j+i;
|
||||
unsigned int v;
|
||||
if(bpp==4)
|
||||
v=*(unsigned int*)p;
|
||||
else if(bpp==2)
|
||||
v=*(unsigned short*)p;
|
||||
else
|
||||
v=*(unsigned char*)p;
|
||||
fputc((v>>pf->redShift)*256/(pf->redMax+1),f);
|
||||
fputc((v>>pf->greenShift)*256/(pf->greenMax+1),f);
|
||||
fputc((v>>pf->blueShift)*256/(pf->blueMax+1),f);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
char * getuser(rfbClient *client)
|
||||
{
|
||||
return strdup("testuser@test");
|
||||
}
|
||||
|
||||
char * getpassword(rfbClient *client)
|
||||
{
|
||||
return strdup("Password");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
rfbClient* client = rfbGetClient(8,3,4);
|
||||
time_t t=time(NULL);
|
||||
|
||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||
client->GetUser = getuser;
|
||||
client->GetPassword = getpassword;
|
||||
#endif
|
||||
|
||||
if(argc>1 && !strcmp("-print",argv[1])) {
|
||||
client->GotFrameBufferUpdate = PrintRect;
|
||||
argv[1]=argv[0]; argv++; argc--;
|
||||
} else
|
||||
client->GotFrameBufferUpdate = SaveFramebufferAsPPM;
|
||||
|
||||
/* The -listen option is used to make us a daemon process which listens for
|
||||
incoming connections from servers, rather than actively connecting to a
|
||||
given server. The -tunnel and -via options are useful to create
|
||||
connections tunneled via SSH port forwarding. We must test for the
|
||||
-listen option before invoking any Xt functions - this is because we use
|
||||
forking, and Xt doesn't seem to cope with forking very well. For -listen
|
||||
option, when a successful incoming connection has been accepted,
|
||||
listenForIncomingConnections() returns, setting the listenSpecified
|
||||
flag. */
|
||||
|
||||
if (!rfbInitClient(client,&argc,argv))
|
||||
return 1;
|
||||
|
||||
/* TODO: better wait for update completion */
|
||||
while (time(NULL)-t<5) {
|
||||
static int i=0;
|
||||
fprintf(stderr,"\r%d",i++);
|
||||
int n = WaitForMessage(client,50);
|
||||
if(n < 0)
|
||||
break;
|
||||
if(n)
|
||||
if(!HandleRFBServerMessage(client))
|
||||
break;
|
||||
}
|
||||
|
||||
rfbClientCleanup(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
445
android/extern/libvncserver/examples/client/sshtunnel.c
vendored
Normal file
445
android/extern/libvncserver/examples/client/sshtunnel.c
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* @example sshtunnel.c
|
||||
* An example of an RFB client tunneled through SSH by using libssh2.
|
||||
* This is based on https://www.libssh2.org/examples/direct_tcpip.html
|
||||
* with the following changes:
|
||||
* - the listening is split out into a separate thread function
|
||||
* - the listener gets closed immediately once a connection was accepted
|
||||
* - the listening port is chosen by the OS, SO_REUSEADDR removed
|
||||
* - global variables moved into SshData helper structure
|
||||
* - added name resolution for the ssh host
|
||||
*/
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
#include <libssh2.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef LIBVNCSERVER_HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* The one global bool that's global so we can set it via
|
||||
a signal handler... */
|
||||
int maintain_connection = 1;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rfbClient *client;
|
||||
LIBSSH2_SESSION *session;
|
||||
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||||
pthread_t thread;
|
||||
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
|
||||
uintptr_t thread;
|
||||
#endif
|
||||
int ssh_sock;
|
||||
int local_listensock;
|
||||
int local_listenport;
|
||||
const char *remote_desthost;
|
||||
int remote_destport;
|
||||
} SshData;
|
||||
|
||||
|
||||
THREAD_ROUTINE_RETURN_TYPE ssh_proxy_loop(void *arg)
|
||||
{
|
||||
SshData *data = arg;
|
||||
int rc, i;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t sinlen;
|
||||
LIBSSH2_CHANNEL *channel = NULL;
|
||||
const char *shost;
|
||||
int sport;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
ssize_t len, wr;
|
||||
char buf[16384];
|
||||
int proxy_sock = RFB_INVALID_SOCKET;
|
||||
|
||||
proxy_sock = accept(data->local_listensock, (struct sockaddr *)&sin, &sinlen);
|
||||
if(proxy_sock == RFB_INVALID_SOCKET) {
|
||||
fprintf(stderr, "ssh_proxy_loop: accept: %s\n", strerror(errno));
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Close listener once a connection got accepted */
|
||||
rfbCloseSocket(data->local_listensock);
|
||||
|
||||
shost = inet_ntoa(sin.sin_addr);
|
||||
sport = ntohs(sin.sin_port);
|
||||
|
||||
printf("ssh_proxy_loop: forwarding connection from %s:%d here to remote %s:%d\n",
|
||||
shost, sport, data->remote_desthost, data->remote_destport);
|
||||
|
||||
channel = libssh2_channel_direct_tcpip_ex(data->session, data->remote_desthost,
|
||||
data->remote_destport, shost, sport);
|
||||
if(!channel) {
|
||||
fprintf(stderr, "ssh_proxy_loop: Could not open the direct-tcpip channel!\n"
|
||||
"(Note that this can be a problem at the server!"
|
||||
" Please review the server logs.)\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
/* Must use non-blocking IO hereafter due to the current libssh2 API */
|
||||
libssh2_session_set_blocking(data->session, 0);
|
||||
|
||||
while(1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(proxy_sock, &fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100000;
|
||||
rc = select(proxy_sock + 1, &fds, NULL, NULL, &tv);
|
||||
if(-1 == rc) {
|
||||
fprintf(stderr, "ssh_proxy_loop: select: %s\n", strerror(errno));
|
||||
goto shutdown;
|
||||
}
|
||||
if(rc && FD_ISSET(proxy_sock, &fds)) {
|
||||
len = recv(proxy_sock, buf, sizeof(buf), 0);
|
||||
if(len < 0) {
|
||||
fprintf(stderr, "read: %s\n", strerror(errno));
|
||||
goto shutdown;
|
||||
}
|
||||
else if(0 == len) {
|
||||
fprintf(stderr, "ssh_proxy_loop: the client at %s:%d disconnected!\n", shost,
|
||||
sport);
|
||||
goto shutdown;
|
||||
}
|
||||
wr = 0;
|
||||
while(wr < len) {
|
||||
i = libssh2_channel_write(channel, buf + wr, len - wr);
|
||||
if(LIBSSH2_ERROR_EAGAIN == i) {
|
||||
continue;
|
||||
}
|
||||
if(i < 0) {
|
||||
fprintf(stderr, "ssh_proxy_loop: libssh2_channel_write: %d\n", i);
|
||||
goto shutdown;
|
||||
}
|
||||
wr += i;
|
||||
}
|
||||
}
|
||||
while(1) {
|
||||
len = libssh2_channel_read(channel, buf, sizeof(buf));
|
||||
if(LIBSSH2_ERROR_EAGAIN == len)
|
||||
break;
|
||||
else if(len < 0) {
|
||||
fprintf(stderr, "ssh_proxy_loop: libssh2_channel_read: %d\n", (int)len);
|
||||
goto shutdown;
|
||||
}
|
||||
wr = 0;
|
||||
while(wr < len) {
|
||||
i = send(proxy_sock, buf + wr, len - wr, 0);
|
||||
if(i <= 0) {
|
||||
fprintf(stderr, "ssh_proxy_loop: write: %s\n", strerror(errno));
|
||||
goto shutdown;
|
||||
}
|
||||
wr += i;
|
||||
}
|
||||
if(libssh2_channel_eof(channel)) {
|
||||
fprintf(stderr, "ssh_proxy_loop: the server at %s:%d disconnected!\n",
|
||||
data->remote_desthost, data->remote_destport);
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shutdown:
|
||||
|
||||
printf("ssh_proxy_loop: shutting down\n");
|
||||
|
||||
rfbCloseSocket(proxy_sock);
|
||||
|
||||
if(channel)
|
||||
libssh2_channel_free(channel);
|
||||
|
||||
libssh2_session_disconnect(data->session, "Client disconnecting normally");
|
||||
libssh2_session_free(data->session);
|
||||
|
||||
rfbCloseSocket(data->ssh_sock);
|
||||
|
||||
return THREAD_ROUTINE_RETURN_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Decide whether or not the SSH tunnel setup should continue
|
||||
based on the current host and its fingerprint.
|
||||
Business logic is up to the implementer in a real app, i.e.
|
||||
compare keys, ask user etc...
|
||||
@return -1 if tunnel setup should be aborted
|
||||
0 if tunnel setup should continue
|
||||
*/
|
||||
int ssh_fingerprint_check(const char *fingerprint, size_t fingerprint_len,
|
||||
const char *host, rfbClient *client)
|
||||
{
|
||||
size_t i;
|
||||
fprintf(stderr, "ssh_fingerprint_check: host %s has ", host);
|
||||
for(i = 0; i < fingerprint_len; i++)
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Creates an SSH tunnel and a local proxy and returns the port the proxy is listening on.
|
||||
@return A pointer to an SshData structure or NULL on error.
|
||||
*/
|
||||
SshData* ssh_tunnel_open(const char *ssh_host,
|
||||
const char *ssh_user,
|
||||
const char *ssh_password,
|
||||
const char *ssh_pub_key_path,
|
||||
const char *ssh_priv_key_path,
|
||||
const char *ssh_priv_key_password,
|
||||
const char *rfb_host,
|
||||
int rfb_port,
|
||||
rfbClient *client)
|
||||
{
|
||||
int rc, i;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t sinlen;
|
||||
const char *fingerprint;
|
||||
char *userauthlist;
|
||||
struct addrinfo hints, *res;
|
||||
SshData *data;
|
||||
|
||||
/* Sanity checks */
|
||||
if(!ssh_host || !ssh_user || !rfb_host) /* these must be set */
|
||||
return NULL;
|
||||
|
||||
data = calloc(1, sizeof(SshData));
|
||||
|
||||
data->client = client;
|
||||
data->remote_desthost = rfb_host; /* resolved by the server */
|
||||
data->remote_destport = rfb_port;
|
||||
|
||||
/* Connect to SSH server */
|
||||
data->ssh_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(data->ssh_sock == RFB_INVALID_SOCKET) {
|
||||
fprintf(stderr, "ssh_tunnel_open: socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((rc = getaddrinfo(ssh_host, NULL, &hints, &res)) == 0) {
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = (((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr);
|
||||
freeaddrinfo(res);
|
||||
} else {
|
||||
fprintf(stderr, "ssh_tunnel_open: getaddrinfo: %s\n", gai_strerror(rc));
|
||||
goto error;
|
||||
}
|
||||
|
||||
sin.sin_port = htons(22);
|
||||
if(connect(data->ssh_sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "ssh_tunnel_open: failed to connect to SSH server!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create a session instance */
|
||||
data->session = libssh2_session_init();
|
||||
if(!data->session) {
|
||||
fprintf(stderr, "ssh_tunnel_open: could not initialize SSH session!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_handshake(data->session, data->ssh_sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "ssh_tunnel_open: error when starting up SSH session: %d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(data->session, LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
if(ssh_fingerprint_check(fingerprint, 32, ssh_host, data->client) == -1) {
|
||||
fprintf(stderr, "ssh_tunnel_open: fingerprint check indicated tunnel setup stop\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check what authentication methods are available */
|
||||
userauthlist = libssh2_userauth_list(data->session, ssh_user, strlen(ssh_user));
|
||||
printf("ssh_tunnel_open: authentication methods: %s\n", userauthlist);
|
||||
|
||||
if(ssh_password && strstr(userauthlist, "password")) {
|
||||
if(libssh2_userauth_password(data->session, ssh_user, ssh_password)) {
|
||||
fprintf(stderr, "ssh_tunnel_open: authentication by password failed.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if(ssh_priv_key_path && ssh_priv_key_password && strstr(userauthlist, "publickey")) {
|
||||
if(libssh2_userauth_publickey_fromfile(data->session, ssh_user, ssh_pub_key_path,
|
||||
ssh_priv_key_path, ssh_priv_key_password)) {
|
||||
fprintf(stderr, "ssh_tunnel_open: authentication by public key failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "ssh_tunnel_open: no supported authentication methods found!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create and bind the local listening socket */
|
||||
data->local_listensock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(data->local_listensock == RFB_INVALID_SOCKET) {
|
||||
fprintf(stderr, "ssh_tunnel_open: socket: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(0); /* let the OS choose the port */
|
||||
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
if(INADDR_NONE == sin.sin_addr.s_addr) {
|
||||
fprintf(stderr, "ssh_tunnel_open: inet_addr: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
sinlen = sizeof(sin);
|
||||
if(-1 == bind(data->local_listensock, (struct sockaddr *)&sin, sinlen)) {
|
||||
fprintf(stderr, "bind: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if(-1 == listen(data->local_listensock, 1)) {
|
||||
fprintf(stderr, "listen: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* get info back from OS */
|
||||
if (getsockname(data->local_listensock, (struct sockaddr *)&sin, &sinlen ) == -1){
|
||||
fprintf(stderr, "ssh_tunnel_open: getsockname: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
data->local_listenport = ntohs(sin.sin_port);
|
||||
|
||||
printf("ssh_tunnel_open: waiting for TCP connection on %s:%d...\n",
|
||||
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
|
||||
|
||||
/* Create the proxy thread */
|
||||
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD)
|
||||
if (pthread_create(&data->thread, NULL, ssh_proxy_loop, data) != 0) {
|
||||
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
|
||||
if(data->thread = _beginthread(proxy_loop, 0, data) == 0);
|
||||
#endif
|
||||
fprintf(stderr, "ssh_tunnel_open: proxy thread creation failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
error:
|
||||
if (data->session) {
|
||||
libssh2_session_disconnect(data->session, "Error in SSH tunnel setup");
|
||||
libssh2_session_free(data->session);
|
||||
}
|
||||
|
||||
rfbCloseSocket(data->local_listensock);
|
||||
rfbCloseSocket(data->ssh_sock);
|
||||
|
||||
free(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void ssh_tunnel_close(SshData *data) {
|
||||
if(!data)
|
||||
return;
|
||||
|
||||
/* the proxy thread does the internal cleanup as it can be
|
||||
ended due to external reasons */
|
||||
THREAD_JOIN(data->thread);
|
||||
|
||||
free(data);
|
||||
|
||||
printf("ssh_tunnel_close: done\n");
|
||||
}
|
||||
|
||||
|
||||
void intHandler(int dummy) {
|
||||
maintain_connection = 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
rfbClient *client = rfbGetClient(8,3,4);
|
||||
|
||||
/*
|
||||
Get args and create SSH tunnel
|
||||
*/
|
||||
int rc = libssh2_init(0);
|
||||
if(rc) {
|
||||
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SshData *data;
|
||||
if (argc == 6) {
|
||||
/* SSH tunnel w/ password */
|
||||
data = ssh_tunnel_open(argv[1], argv[2], argv[3], NULL, NULL, NULL, argv[4], atoi(argv[5]), client);
|
||||
} else if (argc == 8) {
|
||||
/* SSH tunnel w/ privkey */
|
||||
data = ssh_tunnel_open(argv[1], argv[2], NULL, argv[3], argv[4], argv[5], argv[6], atoi(argv[7]), client);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Usage (w/ password): %s <ssh-server-IP> <ssh-server-username> <ssh-server-password> <rfb-host> <rfb-port>\n"
|
||||
"Usage (w/ privkey): %s <ssh-server-IP> <ssh-server-username> <pubkey_filename> <privkey_filename> <privkey_password> <rfb-host> <rfb-port>\n",
|
||||
argv[0], argv[0]);
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The actual VNC connection setup.
|
||||
*/
|
||||
client->serverHost = strdup("127.0.0.1");
|
||||
if(data) // might be NULL if ssh setup failed
|
||||
client->serverPort = data->local_listenport;
|
||||
rfbClientSetClientData(client, (void*)42, data);
|
||||
|
||||
if (!data || !rfbInitClient(client,NULL,NULL))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
printf("Successfully connected to %s:%d - hit Ctrl-C to disconnect\n", client->serverHost, client->serverPort);
|
||||
|
||||
signal(SIGINT, intHandler);
|
||||
|
||||
while (maintain_connection) {
|
||||
int n = WaitForMessage(client,50);
|
||||
if(n < 0)
|
||||
break;
|
||||
if(n)
|
||||
if(!HandleRFBServerMessage(client))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disconnect client inside tunnel */
|
||||
if(client && client->sock != RFB_INVALID_SOCKET)
|
||||
rfbCloseSocket(client->sock);
|
||||
|
||||
/* Close the tunnel and clean up */
|
||||
ssh_tunnel_close(rfbClientGetClientData(client, (void*)42));
|
||||
|
||||
/* free client */
|
||||
rfbClientCleanup(client);
|
||||
|
||||
/* Teardown libssh2 */
|
||||
libssh2_exit();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
481
android/extern/libvncserver/examples/client/vnc2mpg.c
vendored
Normal file
481
android/extern/libvncserver/examples/client/vnc2mpg.c
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
/**
|
||||
* @example vnc2mpg.c
|
||||
* Simple movie writer for vnc; based on Libavformat API example from FFMPEG
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard, 2004 Johannes E. Schindelin
|
||||
* Updates copyright (c) 2017 Tyrel M. McQueen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
#define VNC_PIX_FMT AV_PIX_FMT_RGB565 /* pixel format generated by VNC client */
|
||||
#define OUTPUT_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
|
||||
|
||||
static int write_packet(AVFormatContext *oc, const AVRational *time_base, AVStream *st, AVPacket *pkt)
|
||||
{
|
||||
/* rescale output packet timestamp values from codec to stream timebase */
|
||||
av_packet_rescale_ts(pkt, *time_base, st->time_base);
|
||||
pkt->stream_index = st->index;
|
||||
/* Write the compressed frame to the media file. */
|
||||
return av_interleaved_write_frame(oc, pkt);
|
||||
}
|
||||
|
||||
/*************************************************/
|
||||
/* video functions */
|
||||
|
||||
/* a wrapper around a single output video stream */
|
||||
typedef struct {
|
||||
AVStream *st;
|
||||
AVCodec *codec;
|
||||
AVCodecContext *enc;
|
||||
int64_t pts;
|
||||
AVFrame *frame;
|
||||
AVFrame *tmp_frame;
|
||||
struct SwsContext *sws;
|
||||
} VideoOutputStream;
|
||||
|
||||
/* Add an output video stream. */
|
||||
int add_video_stream(VideoOutputStream *ost, AVFormatContext *oc,
|
||||
enum AVCodecID codec_id, int64_t br, int sr, int w, int h)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* find the encoder */
|
||||
ost->codec = avcodec_find_encoder(codec_id);
|
||||
if (!(ost->codec)) {
|
||||
fprintf(stderr, "Could not find encoder for '%s'\n",
|
||||
avcodec_get_name(codec_id));
|
||||
return -1;
|
||||
} // no extra memory allocation from this call
|
||||
if (ost->codec->type != AVMEDIA_TYPE_VIDEO) {
|
||||
fprintf(stderr, "Encoder for '%s' does not seem to be for video.\n",
|
||||
avcodec_get_name(codec_id));
|
||||
return -2;
|
||||
}
|
||||
ost->enc = avcodec_alloc_context3(ost->codec);
|
||||
if (!(ost->enc)) {
|
||||
fprintf(stderr, "Could not alloc an encoding context\n");
|
||||
return -3;
|
||||
} // from now on need to call avcodec_free_context(&(ost->enc)) on error
|
||||
|
||||
/* Set codec parameters */
|
||||
ost->enc->codec_id = codec_id;
|
||||
ost->enc->bit_rate = br;
|
||||
/* Resolution must be a multiple of two (round up to avoid buffer overflow). */
|
||||
ost->enc->width = w + (w % 2);
|
||||
ost->enc->height = h + (h % 2);
|
||||
/* timebase: This is the fundamental unit of time (in seconds) in terms
|
||||
* of which frame timestamps are represented. For fixed-fps content,
|
||||
* timebase should be 1/framerate and timestamp increments should be
|
||||
* identical to 1. */
|
||||
ost->enc->time_base = (AVRational){ 1, sr };
|
||||
ost->enc->gop_size = 12; /* emit one intra frame every twelve frames at most */
|
||||
ost->enc->pix_fmt = OUTPUT_PIX_FMT;
|
||||
if (ost->enc->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
|
||||
/* Needed to avoid using macroblocks in which some coeffs overflow.
|
||||
* This does not happen with normal video, it just happens here as
|
||||
* the motion of the chroma plane does not match the luma plane. */
|
||||
ost->enc->mb_decision = 2;
|
||||
}
|
||||
|
||||
ost->st = avformat_new_stream(oc, ost->codec);
|
||||
if (!ost->st) {
|
||||
fprintf(stderr, "Could not allocate stream\n");
|
||||
avcodec_free_context(&(ost->enc));
|
||||
return -4;
|
||||
} // stream memory cleared up when oc is freed, so no need to do so later in this function on error
|
||||
ost->st->id = oc->nb_streams-1;
|
||||
ost->st->time_base = ost->enc->time_base;
|
||||
ost->pts = 0;
|
||||
|
||||
/* Some formats want stream headers to be separate. */
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
ost->enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
||||
// must wait to allocate frame buffers until codec is opened (in case codec changes the PIX_FMT)
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
|
||||
{
|
||||
AVFrame *picture;
|
||||
int ret;
|
||||
picture = av_frame_alloc();
|
||||
if (!picture)
|
||||
return NULL;
|
||||
// from now on need to call av_frame_free(&picture) on error
|
||||
picture->format = pix_fmt;
|
||||
picture->width = width;
|
||||
picture->height = height;
|
||||
/* allocate the buffers for the frame data */
|
||||
ret = av_frame_get_buffer(picture, 64);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not allocate frame data.\n");
|
||||
av_frame_free(&picture);
|
||||
return NULL;
|
||||
}
|
||||
return picture;
|
||||
} // use av_frame_free(&picture) to free memory from this call
|
||||
|
||||
int open_video(AVFormatContext *oc, VideoOutputStream *ost)
|
||||
{
|
||||
int ret;
|
||||
/* open the codec */
|
||||
ret = avcodec_open2(ost->enc, ost->codec, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
} // memory from this call freed when oc is freed, no need to do it on error in this call
|
||||
/* copy the stream parameters to the muxer */
|
||||
ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not copy the stream parameters.\n");
|
||||
return ret;
|
||||
} // memory from this call is freed when oc (parent of ost->st) is freed, no need to do it on error in this call
|
||||
/* allocate and init a re-usable frame */
|
||||
ost->frame = alloc_picture(ost->enc->pix_fmt, ost->enc->width, ost->enc->height);
|
||||
if (!(ost->frame)) {
|
||||
fprintf(stderr, "Could not allocate video frame\n");
|
||||
return -1;
|
||||
} // from now on need to call av_frame_free(&(ost->frame)) on error
|
||||
/* If the output format is not the same as the VNC format, then a temporary VNC format
|
||||
* picture is needed too. It is then converted to the required
|
||||
* output format. */
|
||||
ost->tmp_frame = NULL;
|
||||
ost->sws = NULL;
|
||||
if (ost->enc->pix_fmt != VNC_PIX_FMT) {
|
||||
ost->tmp_frame = alloc_picture(VNC_PIX_FMT, ost->enc->width, ost->enc->height);
|
||||
if (!(ost->tmp_frame)) {
|
||||
fprintf(stderr, "Could not allocate temporary picture\n");
|
||||
av_frame_free(&(ost->frame));
|
||||
return -2;
|
||||
} // from now on need to call av_frame_free(&(ost->tmp_frame)) on error
|
||||
ost->sws = sws_getCachedContext(ost->sws, ost->enc->width, ost->enc->height, VNC_PIX_FMT, ost->enc->width, ost->enc->height, ost->enc->pix_fmt, 0, NULL, NULL, NULL);
|
||||
if (!(ost->sws)) {
|
||||
fprintf(stderr, "Could not get sws context\n");
|
||||
av_frame_free(&(ost->frame));
|
||||
av_frame_free(&(ost->tmp_frame));
|
||||
return -3;
|
||||
} // from now on need to call sws_freeContext(ost->sws); ost->sws = NULL; on error
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* encode current video frame and send it to the muxer
|
||||
* return 0 on success, negative on error
|
||||
*/
|
||||
int write_video_frame(AVFormatContext *oc, VideoOutputStream *ost, int64_t pts)
|
||||
{
|
||||
int ret, ret2;
|
||||
AVPacket pkt = { 0 };
|
||||
if (pts <= ost->pts) return 0; // nothing to do
|
||||
/* convert format if needed */
|
||||
if (ost->tmp_frame) {
|
||||
sws_scale(ost->sws, (const uint8_t * const *)ost->tmp_frame->data,
|
||||
ost->tmp_frame->linesize, 0, ost->enc->height, ost->frame->data, ost->frame->linesize);
|
||||
}
|
||||
|
||||
/* send the imager to encoder */
|
||||
ost->pts = pts;
|
||||
ost->frame->pts = ost->pts;
|
||||
ret = avcodec_send_frame(ost->enc, ost->frame);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error sending video frame to encoder: %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
/* read all available packets */
|
||||
ret2 = 0;
|
||||
for (ret = avcodec_receive_packet(ost->enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->enc, &pkt)) {
|
||||
ret2 = write_packet(oc, &(ost->enc->time_base), ost->st, &pkt);
|
||||
if (ret2 < 0) {
|
||||
fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret2));
|
||||
/* continue on this error to not gum up encoder */
|
||||
}
|
||||
}
|
||||
if (ret2 < 0) return ret2;
|
||||
if (!(ret == AVERROR(EAGAIN))) return ret; // if AVERROR(EAGAIN), means all available packets output, need more frames (i.e. success)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write final video frame (i.e. drain codec).
|
||||
*/
|
||||
int write_final_video_frame(AVFormatContext *oc, VideoOutputStream *ost)
|
||||
{
|
||||
int ret, ret2;
|
||||
AVPacket pkt = { 0 };
|
||||
|
||||
/* send NULL image to encoder */
|
||||
ret = avcodec_send_frame(ost->enc, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error sending final video frame to encoder: %s\n", av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
/* read all available packets */
|
||||
ret2 = 0;
|
||||
for (ret = avcodec_receive_packet(ost->enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->enc, &pkt)) {
|
||||
ret2 = write_packet(oc, &(ost->enc->time_base), ost->st, &pkt);
|
||||
if (ret2 < 0) {
|
||||
fprintf(stderr, "Error while writing final video frame: %s\n", av_err2str(ret2));
|
||||
/* continue on this error to not gum up encoder */
|
||||
}
|
||||
}
|
||||
if (ret2 < 0) return ret2;
|
||||
if (!(ret == AVERROR(EOF))) return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_video_stream(VideoOutputStream *ost)
|
||||
{
|
||||
avcodec_free_context(&(ost->enc));
|
||||
av_frame_free(&(ost->frame));
|
||||
av_frame_free(&(ost->tmp_frame));
|
||||
sws_freeContext(ost->sws); ost->sws = NULL;
|
||||
ost->codec = NULL; /* codec not an allocated item */
|
||||
ost->st = NULL; /* freeing parent oc will free this memory */
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* Output movie handling */
|
||||
AVFormatContext *movie_open(char *filename, VideoOutputStream *video_st, int br, int fr, int w, int h) {
|
||||
int ret;
|
||||
AVFormatContext *oc;
|
||||
|
||||
/* allocate the output media context. */
|
||||
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Warning: Could not deduce output format from file extension: using MP4.\n");
|
||||
ret = avformat_alloc_output_context2(&oc, NULL, "mp4", filename);
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: Could not allocate media context: %s.\n", av_err2str(ret));
|
||||
return NULL;
|
||||
} // from now on, need to call avformat_free_context(oc); oc=NULL; to free memory on error
|
||||
|
||||
/* Add the video stream using the default format codec and initialize the codec. */
|
||||
if (oc->oformat->video_codec != AV_CODEC_ID_NONE) {
|
||||
ret = add_video_stream(video_st, oc, oc->oformat->video_codec, br, fr, w, h);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: chosen output format does not have a video codec, or error %i\n", ret);
|
||||
avformat_free_context(oc); oc = NULL;
|
||||
return NULL;
|
||||
} // from now on, need to call close_video_stream(video_st) to free memory on error
|
||||
|
||||
/* Now that all the parameters are set, we can open the codecs and allocate the necessary encode buffers. */
|
||||
ret = open_video(oc, video_st);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error: error opening video codec, error %i\n", ret);
|
||||
close_video_stream(video_st);
|
||||
avformat_free_context(oc); oc = NULL;
|
||||
return NULL;
|
||||
} // no additional calls required to free memory, as close_video_stream(video_st) will do it
|
||||
|
||||
/* open the output file, if needed */
|
||||
if (!(oc->oformat->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not open '%s': %s\n", filename,
|
||||
av_err2str(ret));
|
||||
close_video_stream(video_st);
|
||||
avformat_free_context(oc); oc = NULL;
|
||||
return NULL;
|
||||
}
|
||||
} // will need to call avio_closep(&oc->pb) to free file handle on error
|
||||
|
||||
/* Write the stream header, if any. */
|
||||
ret = avformat_write_header(oc, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error occurred when writing to output file: %s\n",
|
||||
av_err2str(ret));
|
||||
if (!(oc->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&oc->pb);
|
||||
close_video_stream(video_st);
|
||||
avformat_free_context(oc); oc = NULL;
|
||||
} // no additional items to free
|
||||
|
||||
return oc;
|
||||
}
|
||||
|
||||
void movie_close(AVFormatContext **ocp, VideoOutputStream *video_st) {
|
||||
AVFormatContext *oc = *ocp;
|
||||
/* Write the trailer, if any. The trailer must be written before you
|
||||
* close the CodecContexts open when you wrote the header; otherwise
|
||||
* av_write_trailer() may try to use memory that was freed on
|
||||
* av_codec_close(). */
|
||||
if (oc) {
|
||||
if (video_st)
|
||||
write_final_video_frame(oc, video_st);
|
||||
|
||||
av_write_trailer(oc);
|
||||
|
||||
/* Close the video codec. */
|
||||
close_video_stream(video_st);
|
||||
|
||||
if (!(oc->oformat->flags & AVFMT_NOFILE))
|
||||
/* Close the output file. */
|
||||
avio_closep(&oc->pb);
|
||||
|
||||
/* free the stream */
|
||||
avformat_free_context(oc);
|
||||
ocp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* VNC globals */
|
||||
VideoOutputStream video_st = { 0 };
|
||||
rfbClient *client = NULL;
|
||||
rfbBool quit = FALSE;
|
||||
char *filename = NULL;
|
||||
AVFormatContext *oc = NULL;
|
||||
int bitrate = 1000000;
|
||||
int framerate = 5;
|
||||
long max_time = 0;
|
||||
struct timespec start_time, cur_time;
|
||||
|
||||
/* Signal handling */
|
||||
void signal_handler(int signal) {
|
||||
quit=TRUE;
|
||||
}
|
||||
|
||||
/* returns time since start in pts units */
|
||||
int64_t time_to_pts(int framerate, struct timespec *start_time, struct timespec *cur_time) {
|
||||
time_t ds = cur_time->tv_sec - start_time->tv_sec;
|
||||
long dns = cur_time->tv_nsec - start_time->tv_nsec;
|
||||
/* use usecs */
|
||||
int64_t dt = (int64_t)ds*(int64_t)1000000+(int64_t)dns/(int64_t)1000;
|
||||
/* compute rv in units of frame number (rounding to nearest, not truncating) */
|
||||
int64_t rv = (((int64_t)framerate)*dt + (int64_t)500000) / (int64_t)(1000000);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* VNC callback functions */
|
||||
rfbBool vnc_malloc_fb(rfbClient* client) {
|
||||
movie_close(&oc, &video_st);
|
||||
oc = movie_open(filename, &video_st, bitrate, framerate, client->width, client->height);
|
||||
if (!oc)
|
||||
return FALSE;
|
||||
signal(SIGINT,signal_handler);
|
||||
signal(SIGTERM,signal_handler);
|
||||
#ifdef SIGQUIT
|
||||
signal(SIGQUIT,signal_handler);
|
||||
#endif
|
||||
signal(SIGABRT,signal_handler);
|
||||
/* These assignments assumes the AVFrame buffer is contigous. This is true in current ffmpeg versions for
|
||||
* most non-HW accelerated bits, but may not be true globally. */
|
||||
if(video_st.tmp_frame)
|
||||
client->frameBuffer=video_st.tmp_frame->data[0];
|
||||
else
|
||||
client->frameBuffer=video_st.frame->data[0];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vnc_update(rfbClient* client,int x,int y,int w,int h) {
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* media file output */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
/* Initialize vnc client structure (don't connect yet). */
|
||||
client = rfbGetClient(5,3,2);
|
||||
client->format.redShift=11; client->format.redMax=31;
|
||||
client->format.greenShift=5; client->format.greenMax=63;
|
||||
client->format.blueShift=0; client->format.blueMax=31;
|
||||
|
||||
/* Initialize libavcodec, and register all codecs and formats. */
|
||||
#if LIBAVUTIL_VERSION_MAJOR < 56 /* deprecrated in FFMPEG 4.0 */
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
/* Parse command line. */
|
||||
for(i=1;i<argc;i++) {
|
||||
j=i;
|
||||
if(argc>i+1 && !strcmp("-o",argv[i])) {
|
||||
filename=argv[i+1];
|
||||
j+=2;
|
||||
} else if(argc>i+1 && !strcmp("-t",argv[i])) {
|
||||
max_time=atol(argv[i+1]);
|
||||
if (max_time < 10 || max_time > 100000000) {
|
||||
fprintf(stderr, "Warning: Nonsensical time-per-file %li, resetting to default.\n", max_time);
|
||||
max_time = 0;
|
||||
}
|
||||
j+=2;
|
||||
}
|
||||
/* This is so that argc/argv are ready for passing to rfbInitClient */
|
||||
if(j>i) {
|
||||
argc-=j-i;
|
||||
memmove(argv+i,argv+j,(argc-i)*sizeof(char*));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
/* default filename. */
|
||||
if (!filename) {
|
||||
fprintf(stderr, "Warning: No filename specified. Using output.mp4\n");
|
||||
filename = "output.mp4";
|
||||
}
|
||||
|
||||
/* open VNC connection. */
|
||||
client->MallocFrameBuffer=vnc_malloc_fb;
|
||||
client->GotFrameBufferUpdate=vnc_update;
|
||||
if(!rfbInitClient(client,&argc,argv)) {
|
||||
printf("usage: %s [-o output_file] [-t seconds-per-file] server:port\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* main loop */
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
while(!quit) {
|
||||
int i=WaitForMessage(client,10000/framerate); /* useful for timeout to be no more than 10 msec per second (=10000/framerate usec) */
|
||||
if (i>0) {
|
||||
if(!HandleRFBServerMessage(client))
|
||||
quit=TRUE;
|
||||
} else if (i<0) {
|
||||
quit=TRUE;
|
||||
}
|
||||
if (!quit) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
write_video_frame(oc, &video_st, time_to_pts(framerate, &start_time, &cur_time));
|
||||
if ((cur_time.tv_sec - start_time.tv_sec) > max_time && max_time > 0) {
|
||||
quit = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
movie_close(&oc,&video_st);
|
||||
return 0;
|
||||
}
|
||||
141
android/extern/libvncserver/examples/server/1instance.c
vendored
Normal file
141
android/extern/libvncserver/examples/server/1instance.c
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
char* filename; /* this file is the pipe (set by user) */
|
||||
char is_server; /* this is set by open_control_file */
|
||||
int fd; /* this is set by open_control_file */
|
||||
} single_instance_struct;
|
||||
|
||||
/* returns fd, is_server is set to -1 if server, 0 if client */
|
||||
int open_control_file(single_instance_struct* str)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if(stat(str->filename,&buf)) {
|
||||
mkfifo(str->filename,128|256);
|
||||
str->is_server=-1;
|
||||
str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
|
||||
} else {
|
||||
str->fd=open(str->filename,O_NONBLOCK|O_WRONLY);
|
||||
if(errno==ENXIO) {
|
||||
str->is_server=-1;
|
||||
str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
|
||||
} else
|
||||
str->is_server=0;
|
||||
}
|
||||
|
||||
return(str->fd);
|
||||
}
|
||||
|
||||
void delete_control_file(single_instance_struct* str)
|
||||
{
|
||||
remove(str->filename);
|
||||
}
|
||||
|
||||
void close_control_file(single_instance_struct* str)
|
||||
{
|
||||
close(str->fd);
|
||||
}
|
||||
|
||||
typedef void (*event_dispatcher)(char* message);
|
||||
|
||||
int get_next_message(char* buffer,int len,single_instance_struct* str,int usecs)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
int num_fds;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(str->fd,&fdset);
|
||||
tv.tv_sec=0;
|
||||
tv.tv_usec=usecs;
|
||||
|
||||
num_fds=select(str->fd+1,&fdset,NULL,NULL,&tv);
|
||||
if(num_fds) {
|
||||
int reallen;
|
||||
|
||||
reallen=read(str->fd,buffer,len);
|
||||
if(reallen==0) {
|
||||
close(str->fd);
|
||||
str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
|
||||
num_fds--;
|
||||
}
|
||||
buffer[reallen]=0;
|
||||
#ifdef DEBUG_1INSTANCE
|
||||
if(reallen!=0) rfbLog("message received: %s.\n",buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
return(num_fds);
|
||||
}
|
||||
|
||||
int dispatch_event(single_instance_struct* str,event_dispatcher dispatcher,int usecs)
|
||||
{
|
||||
char buffer[1024];
|
||||
int num_fds;
|
||||
|
||||
if((num_fds=get_next_message(buffer,1024,str,usecs)) && buffer[0])
|
||||
dispatcher(buffer);
|
||||
|
||||
return(num_fds);
|
||||
}
|
||||
|
||||
int loop_if_server(single_instance_struct* str,event_dispatcher dispatcher)
|
||||
{
|
||||
open_control_file(str);
|
||||
if(str->is_server) {
|
||||
while(1)
|
||||
dispatch_event(str,dispatcher,50);
|
||||
}
|
||||
|
||||
return(str->fd);
|
||||
}
|
||||
|
||||
void send_message(single_instance_struct* str,char* message)
|
||||
{
|
||||
#ifdef DEBUG_1INSTANCE
|
||||
int i=
|
||||
#endif
|
||||
write(str->fd,message,strlen(message));
|
||||
#ifdef DEBUG_1INSTANCE
|
||||
rfbLog("send: %s => %d(%d)\n",message,i,strlen(message));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MAIN
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
single_instance_struct str1 = { "/tmp/1instance" };
|
||||
|
||||
void my_dispatcher(char* message)
|
||||
{
|
||||
#ifdef DEBUG_1INSTANCE
|
||||
rfbLog("Message arrived: %s.\n",message);
|
||||
#endif
|
||||
if(!strcmp(message,"quit")) {
|
||||
delete_control_file(str1);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
loop_if_server(str1,my_dispatcher);
|
||||
|
||||
for(i=1;i<argc;i++)
|
||||
send_event(str1,argv[i]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
523
android/extern/libvncserver/examples/server/androidvncserver.c
vendored
Normal file
523
android/extern/libvncserver/examples/server/androidvncserver.c
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h> /* For makedev() */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* 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();
|
||||
}
|
||||
116
android/extern/libvncserver/examples/server/backchannel.c
vendored
Normal file
116
android/extern/libvncserver/examples/server/backchannel.c
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
/**
|
||||
* @example backchannel.c
|
||||
* This is a simple example demonstrating a protocol extension.
|
||||
*
|
||||
* The "back channel" permits sending commands between client and server.
|
||||
* It works by sending plain text messages.
|
||||
*
|
||||
* As suggested in the RFB protocol, the back channel is enabled by asking
|
||||
* for a "pseudo encoding", and enabling the back channel on the client side
|
||||
* as soon as it gets a back channel message from the server.
|
||||
*
|
||||
* This implements the server part.
|
||||
*
|
||||
* Note: If you design your own extension and want it to be useful for others,
|
||||
* too, you should make sure that
|
||||
*
|
||||
* - your server as well as your client can speak to other clients and
|
||||
* servers respectively (i.e. they are nice if they are talking to a
|
||||
* program which does not know about your extension).
|
||||
*
|
||||
* - if the machine is little endian, all 16-bit and 32-bit integers are
|
||||
* swapped before they are sent and after they are received.
|
||||
*
|
||||
*/
|
||||
|
||||
#define rfbBackChannel 155
|
||||
|
||||
typedef struct backChannelMsg {
|
||||
uint8_t type;
|
||||
uint8_t pad1;
|
||||
uint16_t pad2;
|
||||
uint32_t size;
|
||||
} backChannelMsg;
|
||||
|
||||
rfbBool enableBackChannel(rfbClientPtr cl, void** data, int encoding)
|
||||
{
|
||||
if(encoding == rfbBackChannel) {
|
||||
backChannelMsg msg;
|
||||
const char* text="Server acknowledges back channel encoding\n";
|
||||
uint32_t length = strlen(text)+1;
|
||||
int n;
|
||||
|
||||
rfbLog("Enabling the back channel\n");
|
||||
|
||||
msg.type = rfbBackChannel;
|
||||
msg.size = Swap32IfLE(length);
|
||||
if((n = rfbWriteExact(cl, (char*)&msg, sizeof(msg))) <= 0 ||
|
||||
(n = rfbWriteExact(cl, text, length)) <= 0) {
|
||||
rfbLogPerror("enableBackChannel: write");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static rfbBool handleBackChannelMessage(rfbClientPtr cl, void* data,
|
||||
const rfbClientToServerMsg* message)
|
||||
{
|
||||
if(message->type == rfbBackChannel) {
|
||||
backChannelMsg msg;
|
||||
char* text;
|
||||
int n;
|
||||
if((n = rfbReadExact(cl, ((char*)&msg)+1, sizeof(backChannelMsg)-1)) <= 0) {
|
||||
if(n != 0)
|
||||
rfbLogPerror("handleBackChannelMessage: read");
|
||||
rfbCloseClient(cl);
|
||||
return TRUE;
|
||||
}
|
||||
msg.size = Swap32IfLE(msg.size);
|
||||
if((text = malloc(msg.size)) == NULL) {
|
||||
rfbErr("Could not allocate %d bytes\n", msg.size);
|
||||
return TRUE;
|
||||
}
|
||||
if((n = rfbReadExact(cl, text, msg.size)) <= 0) {
|
||||
if(n != 0)
|
||||
rfbLogPerror("handleBackChannelMessage: read");
|
||||
rfbCloseClient(cl);
|
||||
return TRUE;
|
||||
}
|
||||
rfbLog("got message:\n%s\n", text);
|
||||
free(text);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int backChannelEncodings[] = {rfbBackChannel, 0};
|
||||
|
||||
static rfbProtocolExtension backChannelExtension = {
|
||||
NULL, /* newClient */
|
||||
NULL, /* init */
|
||||
backChannelEncodings, /* pseudoEncodings */
|
||||
enableBackChannel, /* enablePseudoEncoding */
|
||||
handleBackChannelMessage, /* handleMessage */
|
||||
NULL, /* close */
|
||||
NULL, /* usage */
|
||||
NULL, /* processArgument */
|
||||
NULL /* next extension */
|
||||
};
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbScreenInfoPtr server;
|
||||
|
||||
rfbRegisterProtocolExtension(&backChannelExtension);
|
||||
|
||||
server=rfbGetScreen(&argc,argv,400,300,8,3,4);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->frameBuffer=(char*)malloc(400*300*4);
|
||||
rfbInitServer(server);
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
return(0);
|
||||
}
|
||||
7
android/extern/libvncserver/examples/server/blooptest.c
vendored
Normal file
7
android/extern/libvncserver/examples/server/blooptest.c
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
@example blooptest.c
|
||||
blooptest is a test of pthreads. It is just the example, but with a background
|
||||
loop to hunt down thread lockups.
|
||||
*/
|
||||
#define BACKGROUND_LOOP_TEST
|
||||
#include "example.c"
|
||||
172
android/extern/libvncserver/examples/server/camera.c
vendored
Normal file
172
android/extern/libvncserver/examples/server/camera.c
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
/**
|
||||
* @example camera.c
|
||||
* Question: I need to display a live camera image via VNC. Until now I just
|
||||
* grab an image, set the rect to modified and do a 0.1 s sleep to give the
|
||||
* system time to transfer the data.
|
||||
* This is obviously a solution which doesn't scale very well to different
|
||||
* connection speeds/cpu horsepowers, so I wonder if there is a way for the
|
||||
* server application to determine if the updates have been sent. This would
|
||||
* cause the live image update rate to always be the maximum the connection
|
||||
* supports while avoiding excessive loads.
|
||||
*
|
||||
* Thanks in advance,
|
||||
*
|
||||
*
|
||||
* Christian Daschill
|
||||
*
|
||||
*
|
||||
* Answer: Originally, I thought about using separate threads and using a
|
||||
* mutex to determine when the frame buffer was being accessed by any client
|
||||
* so we could determine a safe time to take a picture. The probem is, we
|
||||
* are lock-stepping everything with framebuffer access. Why not be a
|
||||
* single-thread application and in-between rfbProcessEvents perform a
|
||||
* camera snapshot. And this is what I do here. It guarantees that the
|
||||
* clients have been serviced before taking another picture.
|
||||
*
|
||||
* The downside to this approach is that the more clients you have, there is
|
||||
* less time available for you to service the camera equating to reduced
|
||||
* frame rate. (or, your clients are on really slow links). Increasing your
|
||||
* systems ethernet transmit queues may help improve the overall performance
|
||||
* as the libvncserver should not stall on transmitting to any single
|
||||
* client.
|
||||
*
|
||||
* Another solution would be to provide a separate framebuffer for each
|
||||
* client and use mutexes to determine if any particular client is ready for
|
||||
* a snapshot. This way, your not updating a framebuffer for a slow client
|
||||
* while it is being transferred.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <rfb/rfb.h>
|
||||
#ifdef LIBVNCSERVER_HAVE_GETTIMEOFDAY
|
||||
/* if we have gettimeofday(), it is in this header */
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#if !defined LIBVNCSERVER_HAVE_GETTIMEOFDAY && defined WIN32
|
||||
#include <fcntl.h>
|
||||
#include <conio.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
static void gettimeofday(struct timeval* tv,char* dummy)
|
||||
{
|
||||
SYSTEMTIME t;
|
||||
GetSystemTime(&t);
|
||||
tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
|
||||
tv->tv_usec=t.wMilliseconds*1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define WIDTH 640
|
||||
#define HEIGHT 480
|
||||
#define BPP 4
|
||||
|
||||
/* 15 frames per second (if we can) */
|
||||
#define PICTURE_TIMEOUT (1.0/15.0)
|
||||
|
||||
|
||||
/*
|
||||
* throttle camera updates
|
||||
*/
|
||||
int TimeToTakePicture() {
|
||||
static struct timeval now={0,0}, then={0,0};
|
||||
double elapsed, dnow, dthen;
|
||||
|
||||
gettimeofday(&now,NULL);
|
||||
|
||||
dnow = now.tv_sec + (now.tv_usec /1000000.0);
|
||||
dthen = then.tv_sec + (then.tv_usec/1000000.0);
|
||||
elapsed = dnow - dthen;
|
||||
|
||||
if (elapsed > PICTURE_TIMEOUT)
|
||||
memcpy((char *)&then, (char *)&now, sizeof(struct timeval));
|
||||
return elapsed > PICTURE_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* simulate grabbing a picture from some device
|
||||
*/
|
||||
int TakePicture(unsigned char *buffer)
|
||||
{
|
||||
static int last_line=0, fps=0, fcount=0;
|
||||
int line=0;
|
||||
int i,j;
|
||||
struct timeval now;
|
||||
|
||||
/*
|
||||
* simulate grabbing data from a device by updating the entire framebuffer
|
||||
*/
|
||||
|
||||
for(j=0;j<HEIGHT;++j) {
|
||||
for(i=0;i<WIDTH;++i) {
|
||||
buffer[(j*WIDTH+i)*BPP+0]=(i+j)*128/(WIDTH+HEIGHT); /* red */
|
||||
buffer[(j*WIDTH+i)*BPP+1]=i*128/WIDTH; /* green */
|
||||
buffer[(j*WIDTH+i)*BPP+2]=j*256/HEIGHT; /* blue */
|
||||
}
|
||||
buffer[j*WIDTH*BPP+0]=0xff;
|
||||
buffer[j*WIDTH*BPP+1]=0xff;
|
||||
buffer[j*WIDTH*BPP+2]=0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* simulate the passage of time
|
||||
*
|
||||
* draw a simple black line that moves down the screen. The faster the
|
||||
* client, the more updates it will get, the smoother it will look!
|
||||
*/
|
||||
gettimeofday(&now,NULL);
|
||||
line = now.tv_usec / (1000000/HEIGHT);
|
||||
if (line>=HEIGHT) line=HEIGHT-1;
|
||||
memset(&buffer[(WIDTH * BPP) * line], 0, (WIDTH * BPP));
|
||||
|
||||
/* frames per second (informational only) */
|
||||
fcount++;
|
||||
if (last_line > line) {
|
||||
fps = fcount;
|
||||
fcount = 0;
|
||||
}
|
||||
last_line = line;
|
||||
fprintf(stderr,"%03d/%03d Picture (%03d fps)\r", line, HEIGHT, fps);
|
||||
|
||||
/* success! We have a new picture! */
|
||||
return (1==1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Single-threaded application that interleaves client servicing with taking
|
||||
* pictures from the camera. This way, we do not update the framebuffer
|
||||
* while an encoding is working on it too (banding, and image artifacts).
|
||||
*/
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
long usec;
|
||||
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,WIDTH,HEIGHT,8,3,BPP);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->desktopName = "Live Video Feed Example";
|
||||
server->frameBuffer=(char*)malloc(WIDTH*HEIGHT*BPP);
|
||||
server->alwaysShared=(1==1);
|
||||
|
||||
/* Initialize the server */
|
||||
rfbInitServer(server);
|
||||
|
||||
/* Loop, processing clients and taking pictures */
|
||||
while (rfbIsActive(server)) {
|
||||
if (TimeToTakePicture())
|
||||
if (TakePicture((unsigned char *)server->frameBuffer))
|
||||
rfbMarkRectAsModified(server,0,0,WIDTH,HEIGHT);
|
||||
|
||||
usec = server->deferUpdateTime*1000;
|
||||
rfbProcessEvents(server,usec);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
36
android/extern/libvncserver/examples/server/colourmaptest.c
vendored
Normal file
36
android/extern/libvncserver/examples/server/colourmaptest.c
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
int i;
|
||||
uint8_t bytes[256*3];
|
||||
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,256,256,8,1,1);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->serverFormat.trueColour=FALSE;
|
||||
server->colourMap.count=256;
|
||||
server->colourMap.is16=FALSE;
|
||||
for(i=0;i<256;i++) {
|
||||
bytes[i*3+0]=255-i; /* red */
|
||||
bytes[i*3+1]=0; /* green */
|
||||
bytes[i*3+2]=i; /* blue */
|
||||
}
|
||||
bytes[128*3+0]=0xff;
|
||||
bytes[128*3+1]=0;
|
||||
bytes[128*3+2]=0;
|
||||
server->colourMap.data.bytes=bytes;
|
||||
|
||||
server->frameBuffer=(char*)malloc(256*256);
|
||||
if(!server->frameBuffer)
|
||||
return 1;
|
||||
|
||||
for(i=0;i<256*256;i++)
|
||||
server->frameBuffer[i]=(i/256);
|
||||
|
||||
rfbInitServer(server);
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
359
android/extern/libvncserver/examples/server/cursors.c
vendored
Normal file
359
android/extern/libvncserver/examples/server/cursors.c
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
*
|
||||
* This is an example of how to use libvncserver.
|
||||
*
|
||||
* libvncserver example
|
||||
* Copyright (C) 2005 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>,
|
||||
* Karl Runge <runge@karlrunge.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
static const int bpp=4;
|
||||
static int maxx=800, maxy=600;
|
||||
|
||||
/* This initializes a nice (?) background */
|
||||
|
||||
static void initBuffer(unsigned char* buffer)
|
||||
{
|
||||
int i,j;
|
||||
for(j=0;j<maxy;++j) {
|
||||
for(i=0;i<maxx;++i) {
|
||||
buffer[(j*maxx+i)*bpp+0]=(i+j)*128/(maxx+maxy); /* red */
|
||||
buffer[(j*maxx+i)*bpp+1]=i*128/maxx; /* green */
|
||||
buffer[(j*maxx+i)*bpp+2]=j*256/maxy; /* blue */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Example for an XCursor (foreground/background only) */
|
||||
|
||||
static void SetXCursor(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int width=13,height=11;
|
||||
char cursor[]=
|
||||
" "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xxx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" ",
|
||||
mask[]=
|
||||
"xxxx xxxx"
|
||||
"xxxx xxxx"
|
||||
" xxxx xxxx "
|
||||
" xxxx xxxx "
|
||||
" xxxxxxx "
|
||||
" xxxxx "
|
||||
" xxxxxxx "
|
||||
" xxxx xxxx "
|
||||
" xxxx xxxx "
|
||||
"xxxx xxxx"
|
||||
"xxxx xxxx";
|
||||
rfbCursorPtr c;
|
||||
|
||||
c=rfbMakeXCursor(width,height,cursor,mask);
|
||||
c->xhot=width/2;c->yhot=height/2;
|
||||
|
||||
rfbSetCursor(rfbScreen, c);
|
||||
}
|
||||
|
||||
static void SetXCursor2(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int width=13,height=22;
|
||||
char cursor[]=
|
||||
" xx "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x xx x "
|
||||
" x x x xxx "
|
||||
" x xx x x "
|
||||
" xx x x "
|
||||
" xx x x "
|
||||
" x x x "
|
||||
" x x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" x x "
|
||||
" xx "
|
||||
" "
|
||||
" ",
|
||||
mask[]=
|
||||
"xxx "
|
||||
"xxxx "
|
||||
"xxxxx "
|
||||
"xxxxxx "
|
||||
"xxxxxxx "
|
||||
"xxxxxxxx "
|
||||
"xxxxxxxxx "
|
||||
"xxxxxxxxxx "
|
||||
"xxxxxxxxxxx "
|
||||
"xxxxxxxxxxxx "
|
||||
"xxxxxxxxxxxxx"
|
||||
"xxxxxxxxxxxxx"
|
||||
"xxxxxxxxxx x"
|
||||
"xxxxxxxxxx "
|
||||
"xxx xxxxxx "
|
||||
"xxx xxxxxx "
|
||||
"xx xxxxxx "
|
||||
" xxxxx "
|
||||
" xxxxxx"
|
||||
" xxxxx"
|
||||
" xxx "
|
||||
" ";
|
||||
rfbCursorPtr c;
|
||||
|
||||
c=rfbMakeXCursor(width,height,cursor,mask);
|
||||
c->xhot=0;c->yhot=0;
|
||||
|
||||
rfbSetCursor(rfbScreen, c);
|
||||
}
|
||||
|
||||
/* Example for a rich cursor (full-colour) */
|
||||
|
||||
static void SetRichCursor(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int i,j,w=32,h=32;
|
||||
/* runge */
|
||||
/* rfbCursorPtr c = rfbScreen->cursor; */
|
||||
rfbCursorPtr c;
|
||||
char bitmap[]=
|
||||
" "
|
||||
" xxxxxx "
|
||||
" xxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxx xxxxxxxx xxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxx xxxxxxxxxxx xxxxxxx "
|
||||
" xxxx xxxxxxxxx xxxxxx "
|
||||
" xxxxx xxxxxxxxxxx xxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxx xxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxx xxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxx xxxxxxxxxxxx "
|
||||
" xxxxxxxxx xxxxxxxxx "
|
||||
" xxxxxxxxxx xxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxx "
|
||||
" xxxx xxxxxxxxxxxxx "
|
||||
" xx x xxxxxxxxxxx "
|
||||
" xxx xxxxxxxxxxx "
|
||||
" xxxx xxxxxxxxxxx "
|
||||
" xxxxxx xxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxx "
|
||||
" ";
|
||||
|
||||
c=rfbMakeXCursor(w,h,bitmap,bitmap);
|
||||
c->xhot = 16; c->yhot = 24;
|
||||
|
||||
c->richSource = (unsigned char*)malloc(w*h*bpp);
|
||||
if (!c->richSource) return;
|
||||
|
||||
for(j=0;j<h;j++) {
|
||||
for(i=0;i<w;i++) {
|
||||
c->richSource[j*w*bpp+i*bpp+0]=i*0xff/w;
|
||||
c->richSource[j*w*bpp+i*bpp+1]=(i+j)*0xff/(w+h);
|
||||
c->richSource[j*w*bpp+i*bpp+2]=j*0xff/h;
|
||||
c->richSource[j*w*bpp+i*bpp+3]=0;
|
||||
}
|
||||
}
|
||||
rfbSetCursor(rfbScreen, c);
|
||||
}
|
||||
|
||||
/* runge */
|
||||
static void SetRichCursor2(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int i,j,w=17,h=16;
|
||||
/* rfbCursorPtr c = rfbScreen->cursor; */
|
||||
rfbCursorPtr c;
|
||||
char bitmap[]=
|
||||
" "
|
||||
"xxxx "
|
||||
"xxxxxxxx "
|
||||
"xxxxxxxxxxxx x"
|
||||
"xxx xxxxxxxx x"
|
||||
"xxxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxxxx x"
|
||||
"xxxxx xxxxxxx x"
|
||||
"xxxx xxxxxx x"
|
||||
"xxxxx xxxxxxx x"
|
||||
"xxxxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxx x"
|
||||
"xxxxxxxxxxxxx x";
|
||||
/* c=rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap); */
|
||||
c=rfbMakeXCursor(w,h,bitmap,bitmap);
|
||||
c->xhot = 5; c->yhot = 7;
|
||||
|
||||
c->richSource = (unsigned char*)malloc(w*h*bpp);
|
||||
if(!c->richSource) return;
|
||||
for(j=0;j<h;j++) {
|
||||
for(i=0;i<w;i++) {
|
||||
c->richSource[j*w*bpp+i*bpp+0]=0xff;
|
||||
c->richSource[j*w*bpp+i*bpp+1]=0x00;
|
||||
c->richSource[j*w*bpp+i*bpp+2]=0x7f;
|
||||
c->richSource[j*w*bpp+i*bpp+3]=0;
|
||||
}
|
||||
}
|
||||
rfbSetCursor(rfbScreen, c);
|
||||
}
|
||||
|
||||
/* alpha channel */
|
||||
|
||||
static void SetAlphaCursor(rfbScreenInfoPtr screen,int mode)
|
||||
{
|
||||
int i,j;
|
||||
rfbCursorPtr c = screen->cursor;
|
||||
int maskStride;
|
||||
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
maskStride = (c->width+7)/8;
|
||||
|
||||
if(c->alphaSource) {
|
||||
free(c->alphaSource);
|
||||
c->alphaSource=NULL;
|
||||
}
|
||||
|
||||
if(mode==0)
|
||||
return;
|
||||
|
||||
c->alphaSource = (unsigned char*)malloc(c->width*c->height);
|
||||
if (!c->alphaSource) return;
|
||||
|
||||
for(j=0;j<c->height;j++)
|
||||
for(i=0;i<c->width;i++) {
|
||||
unsigned char value=0x100*i/c->width;
|
||||
rfbBool masked=(c->mask[(i/8)+maskStride*j]<<(i&7))&0x80;
|
||||
c->alphaSource[i+c->width*j]=(masked?(mode==1?value:0xff-value):0);
|
||||
}
|
||||
if(c->cleanupMask)
|
||||
free(c->mask);
|
||||
c->mask=(unsigned char*)rfbMakeMaskFromAlphaSource(c->width,c->height,c->alphaSource);
|
||||
c->cleanupMask=TRUE;
|
||||
}
|
||||
|
||||
/* Here the pointer events are handled */
|
||||
|
||||
static void doptr(int buttonMask,int x,int y,rfbClientPtr cl)
|
||||
{
|
||||
static int oldButtonMask=0;
|
||||
static int counter=0;
|
||||
|
||||
if((oldButtonMask&1)==0 && (buttonMask&1)==1) {
|
||||
switch(++counter) {
|
||||
case 7:
|
||||
SetRichCursor(cl->screen);
|
||||
SetAlphaCursor(cl->screen,2);
|
||||
break;
|
||||
case 6:
|
||||
SetRichCursor(cl->screen);
|
||||
SetAlphaCursor(cl->screen,1);
|
||||
break;
|
||||
case 5:
|
||||
SetRichCursor2(cl->screen);
|
||||
SetAlphaCursor(cl->screen,0);
|
||||
break;
|
||||
case 4:
|
||||
SetXCursor(cl->screen);
|
||||
break;
|
||||
case 3:
|
||||
SetRichCursor2(cl->screen);
|
||||
SetAlphaCursor(cl->screen,2);
|
||||
break;
|
||||
case 2:
|
||||
SetXCursor(cl->screen);
|
||||
SetAlphaCursor(cl->screen,2);
|
||||
break;
|
||||
case 1:
|
||||
SetXCursor2(cl->screen);
|
||||
SetAlphaCursor(cl->screen,0);
|
||||
break;
|
||||
default:
|
||||
SetRichCursor(cl->screen);
|
||||
counter=0;
|
||||
}
|
||||
}
|
||||
if(buttonMask&2) {
|
||||
rfbScreenCleanup(cl->screen);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(buttonMask&4)
|
||||
rfbCloseClient(cl);
|
||||
|
||||
|
||||
oldButtonMask=buttonMask;
|
||||
|
||||
rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbScreenInfoPtr rfbScreen = rfbGetScreen(&argc,argv,maxx,maxy,8,3,bpp);
|
||||
if(!rfbScreen)
|
||||
return 1;
|
||||
|
||||
rfbScreen->desktopName = "Cursor Test";
|
||||
rfbScreen->frameBuffer = (char*)malloc(maxx*maxy*bpp);
|
||||
rfbScreen->ptrAddEvent = doptr;
|
||||
|
||||
initBuffer((unsigned char*)rfbScreen->frameBuffer);
|
||||
|
||||
|
||||
SetRichCursor(rfbScreen);
|
||||
|
||||
/* initialize the server */
|
||||
rfbInitServer(rfbScreen);
|
||||
|
||||
rfbLog("Change cursor shape with left mouse button,\n\t"
|
||||
"quit with right one (middle button quits server).\n");
|
||||
|
||||
/* this is the blocking event loop, i.e. it never returns */
|
||||
/* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */
|
||||
rfbRunEventLoop(rfbScreen,40000,FALSE);
|
||||
|
||||
free(rfbScreen->frameBuffer);
|
||||
rfbScreenCleanup(rfbScreen);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
354
android/extern/libvncserver/examples/server/example.c
vendored
Normal file
354
android/extern/libvncserver/examples/server/example.c
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* @example example.c
|
||||
* This is an example of how to use libvncserver.
|
||||
*
|
||||
* libvncserver example
|
||||
* Copyright (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#define sleep Sleep
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __IRIX__
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
|
||||
static const int bpp=4;
|
||||
static int maxx=800, maxy=600;
|
||||
/* TODO: odd maxx doesn't work (vncviewer bug) */
|
||||
|
||||
/* Flag used for threaded mode that's global so we can set it via
|
||||
a signal handler... */
|
||||
static int maintain_connection = 1;
|
||||
|
||||
/* This initializes a nice (?) background */
|
||||
|
||||
static void initBuffer(unsigned char* buffer)
|
||||
{
|
||||
int i,j;
|
||||
for(j=0;j<maxy;++j) {
|
||||
for(i=0;i<maxx;++i) {
|
||||
buffer[(j*maxx+i)*bpp+0]=(i+j)*128/(maxx+maxy); /* red */
|
||||
buffer[(j*maxx+i)*bpp+1]=i*128/maxx; /* green */
|
||||
buffer[(j*maxx+i)*bpp+2]=j*256/maxy; /* blue */
|
||||
}
|
||||
buffer[j*maxx*bpp+0]=0xff;
|
||||
buffer[j*maxx*bpp+1]=0xff;
|
||||
buffer[j*maxx*bpp+2]=0xff;
|
||||
buffer[j*maxx*bpp+3]=0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we create a structure so that every client has its own pointer */
|
||||
|
||||
typedef struct ClientData {
|
||||
rfbBool oldButton;
|
||||
int oldx,oldy;
|
||||
} ClientData;
|
||||
|
||||
static void clientgone(rfbClientPtr cl)
|
||||
{
|
||||
free(cl->clientData);
|
||||
cl->clientData = NULL;
|
||||
}
|
||||
|
||||
static enum rfbNewClientAction newclient(rfbClientPtr cl)
|
||||
{
|
||||
cl->clientData = (void*)calloc(sizeof(ClientData),1);
|
||||
cl->clientGoneHook = clientgone;
|
||||
return RFB_CLIENT_ACCEPT;
|
||||
}
|
||||
|
||||
/* switch to new framebuffer contents */
|
||||
|
||||
static void newframebuffer(rfbScreenInfoPtr screen, int width, int height)
|
||||
{
|
||||
unsigned char *oldfb, *newfb;
|
||||
|
||||
maxx = width;
|
||||
maxy = height;
|
||||
oldfb = (unsigned char*)screen->frameBuffer;
|
||||
newfb = (unsigned char*)malloc(maxx * maxy * bpp);
|
||||
initBuffer(newfb);
|
||||
rfbNewFramebuffer(screen, (char*)newfb, maxx, maxy, 8, 3, bpp);
|
||||
free(oldfb);
|
||||
|
||||
/*** FIXME: Re-install cursor. ***/
|
||||
}
|
||||
|
||||
/* aux function to draw a line */
|
||||
|
||||
static void drawline(unsigned char* buffer,int rowstride,int bpp,int x1,int y1,int x2,int y2)
|
||||
{
|
||||
int i,j;
|
||||
i=x1-x2; j=y1-y2;
|
||||
if(i==0 && j==0) {
|
||||
for(i=0;i<bpp;i++)
|
||||
buffer[y1*rowstride+x1*bpp+i]=0xff;
|
||||
return;
|
||||
}
|
||||
if(i<0) i=-i;
|
||||
if(j<0) j=-j;
|
||||
if(i<j) {
|
||||
if(y1>y2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; }
|
||||
for(j=y1;j<=y2;j++)
|
||||
for(i=0;i<bpp;i++)
|
||||
buffer[j*rowstride+(x1+(j-y1)*(x2-x1)/(y2-y1))*bpp+i]=0xff;
|
||||
} else {
|
||||
if(x1>x2) { i=y2; y2=y1; y1=i; i=x2; x2=x1; x1=i; }
|
||||
for(i=x1;i<=x2;i++)
|
||||
for(j=0;j<bpp;j++)
|
||||
buffer[(y1+(i-x1)*(y2-y1)/(x2-x1))*rowstride+i*bpp+j]=0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Here the pointer events are handled */
|
||||
|
||||
static void doptr(int buttonMask,int x,int y,rfbClientPtr cl)
|
||||
{
|
||||
ClientData* cd=cl->clientData;
|
||||
|
||||
if(x>=0 && y>=0 && x<maxx && y<maxy) {
|
||||
if(buttonMask) {
|
||||
int i,j,x1,x2,y1,y2;
|
||||
|
||||
if(cd->oldButton==buttonMask) { /* draw a line */
|
||||
drawline((unsigned char*)cl->screen->frameBuffer,cl->screen->paddedWidthInBytes,bpp,
|
||||
x,y,cd->oldx,cd->oldy);
|
||||
x1=x; y1=y;
|
||||
if(x1>cd->oldx) x1++; else cd->oldx++;
|
||||
if(y1>cd->oldy) y1++; else cd->oldy++;
|
||||
rfbMarkRectAsModified(cl->screen,x,y,cd->oldx,cd->oldy);
|
||||
} else { /* draw a point (diameter depends on button) */
|
||||
int w=cl->screen->paddedWidthInBytes;
|
||||
x1=x-buttonMask; if(x1<0) x1=0;
|
||||
x2=x+buttonMask; if(x2>maxx) x2=maxx;
|
||||
y1=y-buttonMask; if(y1<0) y1=0;
|
||||
y2=y+buttonMask; if(y2>maxy) y2=maxy;
|
||||
|
||||
for(i=x1*bpp;i<x2*bpp;i++)
|
||||
for(j=y1;j<y2;j++)
|
||||
cl->screen->frameBuffer[j*w+i]=(char)0xff;
|
||||
rfbMarkRectAsModified(cl->screen,x1,y1,x2,y2);
|
||||
}
|
||||
|
||||
/* we could get a selection like that:
|
||||
rfbGotXCutText(cl->screen,"Hallo",5);
|
||||
*/
|
||||
}
|
||||
|
||||
cd->oldx=x; cd->oldy=y; cd->oldButton=buttonMask;
|
||||
}
|
||||
rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
|
||||
}
|
||||
|
||||
/* aux function to draw a character to x, y */
|
||||
|
||||
#include "radon.h"
|
||||
|
||||
/* Here the key events are handled */
|
||||
|
||||
static void dokey(rfbBool down,rfbKeySym key,rfbClientPtr cl)
|
||||
{
|
||||
if(down) {
|
||||
if(key==XK_Escape)
|
||||
rfbCloseClient(cl);
|
||||
else if(key==XK_F12)
|
||||
/* close down server, disconnecting clients */
|
||||
rfbShutdownServer(cl->screen,TRUE);
|
||||
else if(key==XK_F11)
|
||||
/* close down server, but wait for all clients to disconnect */
|
||||
rfbShutdownServer(cl->screen,FALSE);
|
||||
else if(key==XK_Page_Up) {
|
||||
initBuffer((unsigned char*)cl->screen->frameBuffer);
|
||||
rfbMarkRectAsModified(cl->screen,0,0,maxx,maxy);
|
||||
} else if (key == XK_Up) {
|
||||
if (maxx < 1024) {
|
||||
if (maxx < 800) {
|
||||
newframebuffer(cl->screen, 800, 600);
|
||||
} else {
|
||||
newframebuffer(cl->screen, 1024, 768);
|
||||
}
|
||||
}
|
||||
} else if(key==XK_Down) {
|
||||
if (maxx > 640) {
|
||||
if (maxx > 800) {
|
||||
newframebuffer(cl->screen, 800, 600);
|
||||
} else {
|
||||
newframebuffer(cl->screen, 640, 480);
|
||||
}
|
||||
}
|
||||
} else if(key>=' ' && key<0x100) {
|
||||
ClientData* cd=cl->clientData;
|
||||
int x1=cd->oldx,y1=cd->oldy,x2,y2;
|
||||
cd->oldx+=rfbDrawCharWithClip(cl->screen,&radonFont,cd->oldx,cd->oldy,(char)key,0,0,cl->screen->width,cl->screen->height,0x00ffffff,0x00ffffff);
|
||||
rfbFontBBox(&radonFont,(char)key,&x1,&y1,&x2,&y2);
|
||||
rfbMarkRectAsModified(cl->screen,x1,y1,x2-1,y2-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Example for an XCursor (foreground/background only) */
|
||||
|
||||
#ifdef JUST_AN_EXAMPLE
|
||||
|
||||
static int exampleXCursorWidth=9,exampleXCursorHeight=7;
|
||||
static char exampleXCursor[]=
|
||||
" "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" xxx "
|
||||
" xx xx "
|
||||
" xx xx "
|
||||
" ";
|
||||
|
||||
#endif
|
||||
|
||||
/* Example for a rich cursor (full-colour) */
|
||||
|
||||
static void MakeRichCursor(rfbScreenInfoPtr rfbScreen)
|
||||
{
|
||||
int i,j,w=32,h=32;
|
||||
rfbCursorPtr c;
|
||||
char bitmap[]=
|
||||
" "
|
||||
" xxxxxx "
|
||||
" xxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxx xxxxxxxx xxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxx xxxxxxxxxxx xxxxxxx "
|
||||
" xxxx xxxxxxxxx xxxxxx "
|
||||
" xxxxx xxxxxxxxxxx xxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxx xxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxx xxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxx xxxxxxxxxxxx "
|
||||
" xxxxxxxxx xxxxxxxxx "
|
||||
" xxxxxxxxxx xxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxx "
|
||||
" xxxx xxxxxxxxxxxxx "
|
||||
" xx x xxxxxxxxxxx "
|
||||
" xxx xxxxxxxxxxx "
|
||||
" xxxx xxxxxxxxxxx "
|
||||
" xxxxxx xxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxxxxxxxx "
|
||||
" xxxxxxxxxxxxxxxx "
|
||||
" ";
|
||||
c=rfbScreen->cursor = rfbMakeXCursor(w,h,bitmap,bitmap);
|
||||
c->xhot = 16; c->yhot = 24;
|
||||
|
||||
c->richSource = (unsigned char*)malloc(w*h*bpp);
|
||||
if(!c->richSource)
|
||||
return;
|
||||
c->cleanupRichSource = TRUE;
|
||||
for(j=0;j<h;j++) {
|
||||
for(i=0;i<w;i++) {
|
||||
c->richSource[j*w*bpp+i*bpp+0]=i*0xff/w;
|
||||
c->richSource[j*w*bpp+i*bpp+1]=(i+j)*0xff/(w+h);
|
||||
c->richSource[j*w*bpp+i*bpp+2]=j*0xff/h;
|
||||
c->richSource[j*w*bpp+i*bpp+3]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void intHandler(int dummy) {
|
||||
maintain_connection = 0;
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbScreenInfoPtr rfbScreen = rfbGetScreen(&argc,argv,maxx,maxy,8,3,bpp);
|
||||
if(!rfbScreen)
|
||||
return 1;
|
||||
rfbScreen->desktopName = "LibVNCServer Example";
|
||||
rfbScreen->frameBuffer = (char*)malloc(maxx*maxy*bpp);
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
rfbScreen->ptrAddEvent = doptr;
|
||||
rfbScreen->kbdAddEvent = dokey;
|
||||
rfbScreen->newClientHook = newclient;
|
||||
rfbScreen->httpDir = "../webclients";
|
||||
rfbScreen->httpEnableProxyConnect = TRUE;
|
||||
|
||||
initBuffer((unsigned char*)rfbScreen->frameBuffer);
|
||||
rfbDrawString(rfbScreen,&radonFont,20,100,"Hello, World!",0xffffff);
|
||||
|
||||
/* This call creates a mask and then a cursor: */
|
||||
/* rfbScreen->defaultCursor =
|
||||
rfbMakeXCursor(exampleCursorWidth,exampleCursorHeight,exampleCursor,0);
|
||||
*/
|
||||
|
||||
MakeRichCursor(rfbScreen);
|
||||
|
||||
/* initialize the server */
|
||||
rfbInitServer(rfbScreen);
|
||||
|
||||
#ifndef BACKGROUND_LOOP_TEST
|
||||
#ifdef USE_OWN_LOOP
|
||||
{
|
||||
int i;
|
||||
for(i=0;rfbIsActive(rfbScreen);i++) {
|
||||
fprintf(stderr,"%d\r",i);
|
||||
rfbProcessEvents(rfbScreen,100000);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* this is the blocking event loop, i.e. it never returns */
|
||||
/* 40000 are the microseconds to wait on select(), i.e. 0.04 seconds */
|
||||
rfbRunEventLoop(rfbScreen,40000,FALSE);
|
||||
#endif /* OWN LOOP */
|
||||
#else
|
||||
#if !defined(LIBVNCSERVER_HAVE_LIBPTHREAD) && !defined(LIBVNCSERVER_HAVE_WIN32THREADS)
|
||||
#error "I need pthreads or win32 threads for that."
|
||||
#endif
|
||||
/* catch Ctrl-C to set a flag for the main thread */
|
||||
signal(SIGINT, intHandler);
|
||||
/* this is the non-blocking event loop; a background thread is started */
|
||||
rfbRunEventLoop(rfbScreen,-1,TRUE);
|
||||
fprintf(stderr, "Running background loop...\n");
|
||||
/* now we could do some cool things like rendering in idle time */
|
||||
while (maintain_connection) {
|
||||
sleep(5); /* render(); */
|
||||
}
|
||||
fprintf(stderr, "\nShutting down...\n");
|
||||
rfbShutdownServer(rfbScreen, TRUE);
|
||||
#endif /* BACKGROUND_LOOP */
|
||||
|
||||
free(rfbScreen->frameBuffer);
|
||||
rfbScreenCleanup(rfbScreen);
|
||||
|
||||
return(0);
|
||||
}
|
||||
19
android/extern/libvncserver/examples/server/filetransfer.c
vendored
Normal file
19
android/extern/libvncserver/examples/server/filetransfer.c
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @example filetransfer.c
|
||||
* Demonstrates a server capable of TightVNC-1.3.x file transfer.
|
||||
* NB That TightVNC-2.x uses a different, incompatible file transfer protocol.
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbRegisterTightVNCFileTransferExtension();
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,8,3,4);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->frameBuffer=(char*)malloc(400*300*4);
|
||||
rfbInitServer(server);
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
return(0);
|
||||
}
|
||||
86
android/extern/libvncserver/examples/server/fontsel.c
vendored
Normal file
86
android/extern/libvncserver/examples/server/fontsel.c
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
@example fontsel.c
|
||||
fontsel is a test for rfbSelectBox and rfbLoadConsoleFont. If you have Linux
|
||||
console fonts, you can browse them via VNC. Directory browsing not implemented
|
||||
yet :-(
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
#define FONTDIR "/usr/lib/kbd/consolefonts/"
|
||||
#define DEFAULTFONT FONTDIR "default8x16"
|
||||
|
||||
static char *fontlist[50]={
|
||||
"8x16alt", "b.fnt", "c.fnt", "default8x16", "m.fnt", "ml.fnt", "mod_d.fnt",
|
||||
"mod_s.fnt", "mr.fnt", "mu.fnt", "r.fnt", "rl.fnt", "ro.fnt", "s.fnt",
|
||||
"sc.fnt", "scrawl_s.fnt", "scrawl_w.fnt", "sd.fnt", "t.fnt",
|
||||
NULL
|
||||
};
|
||||
|
||||
static rfbScreenInfoPtr rfbScreen = NULL;
|
||||
static rfbFontDataPtr curFont = NULL;
|
||||
static void showFont(int index)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
if(!rfbScreen) return;
|
||||
|
||||
if(curFont)
|
||||
rfbFreeFont(curFont);
|
||||
|
||||
strcpy(buffer,FONTDIR);
|
||||
strcat(buffer,fontlist[index]);
|
||||
curFont = rfbLoadConsoleFont(buffer);
|
||||
|
||||
rfbFillRect(rfbScreen,210,30-20,210+10*16,30-20+256*20/16,0xb77797);
|
||||
if(curFont) {
|
||||
int i,j;
|
||||
for(j=0;j<256;j+=16)
|
||||
for(i=0;i<16;i++)
|
||||
rfbDrawCharWithClip(rfbScreen,curFont,210+10*i,30+j*20/16,j+i,
|
||||
0,0,640,480,0xffffff,0x000000);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbFontDataPtr font;
|
||||
rfbScreenInfoPtr s=rfbGetScreen(&argc,argv,640,480,8,3,3);
|
||||
int i,j;
|
||||
|
||||
if(!s)
|
||||
return 1;
|
||||
|
||||
s->frameBuffer=(char*)malloc(640*480*3);
|
||||
if(!s->frameBuffer)
|
||||
return 1;
|
||||
|
||||
rfbInitServer(s);
|
||||
|
||||
for(j=0;j<480;j++)
|
||||
for(i=0;i<640;i++) {
|
||||
s->frameBuffer[(j*640+i)*3+0]=j*256/480;
|
||||
s->frameBuffer[(j*640+i)*3+1]=i*256/640;
|
||||
s->frameBuffer[(j*640+i)*3+2]=(i+j)*256/(480+640);
|
||||
}
|
||||
|
||||
rfbScreen = s;
|
||||
font=rfbLoadConsoleFont(DEFAULTFONT);
|
||||
if(!font) {
|
||||
rfbErr("Couldn't find %s\n",DEFAULTFONT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(j=0;j<10 && rfbIsActive(s);j++)
|
||||
rfbProcessEvents(s,900000);
|
||||
|
||||
i = rfbSelectBox(s,font,fontlist,10,20,200,300,0xffdfdf,0x602040,2,showFont);
|
||||
rfbLog("Selection: %d: %s\n",i,(i>=0)?fontlist[i]:"cancelled");
|
||||
|
||||
rfbFreeFont(font);
|
||||
free(s->frameBuffer);
|
||||
rfbScreenCleanup(s);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
726
android/extern/libvncserver/examples/server/mac.c
vendored
Normal file
726
android/extern/libvncserver/examples/server/mac.c
vendored
Normal file
@@ -0,0 +1,726 @@
|
||||
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Cut in two parts by Johannes Schindelin (2001): libvncserver and OSXvnc.
|
||||
*
|
||||
* Completely revamped and adapted to work with contemporary APIs by Christian Beier (2020).
|
||||
*
|
||||
* This file implements every system specific function for Mac OS X.
|
||||
*
|
||||
* It includes the keyboard function:
|
||||
*
|
||||
void KbdAddEvent(down, keySym, cl)
|
||||
rfbBool down;
|
||||
rfbKeySym keySym;
|
||||
rfbClientPtr cl;
|
||||
*
|
||||
* the mouse function:
|
||||
*
|
||||
void PtrAddEvent(buttonMask, x, y, cl)
|
||||
int buttonMask;
|
||||
int x;
|
||||
int y;
|
||||
rfbClientPtr cl;
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <IOKit/pwr_mgt/IOPM.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* The main LibVNCServer screen object */
|
||||
rfbScreenInfoPtr rfbScreen;
|
||||
/* Operation modes set by CLI options */
|
||||
rfbBool viewOnly = FALSE, sharedMode = FALSE;
|
||||
|
||||
/* Two framebuffers. */
|
||||
void *frameBufferOne;
|
||||
void *frameBufferTwo;
|
||||
|
||||
/* Pointer to the current backbuffer. */
|
||||
void *backBuffer;
|
||||
|
||||
/* The multi-sceen display number chosen by the user */
|
||||
int displayNumber = -1;
|
||||
/* The corresponding multi-sceen display ID */
|
||||
CGDirectDisplayID displayID;
|
||||
|
||||
/* The server's private event source */
|
||||
CGEventSourceRef eventSource;
|
||||
|
||||
/* Screen (un)dimming machinery */
|
||||
rfbBool preventDimming = FALSE;
|
||||
rfbBool preventSleep = TRUE;
|
||||
static pthread_mutex_t dimming_mutex;
|
||||
static unsigned long dim_time;
|
||||
static unsigned long sleep_time;
|
||||
static mach_port_t master_dev_port;
|
||||
static io_connect_t power_mgt;
|
||||
static rfbBool initialized = FALSE;
|
||||
static rfbBool dim_time_saved = FALSE;
|
||||
static rfbBool sleep_time_saved = FALSE;
|
||||
|
||||
/* some variables to enable special behaviour */
|
||||
int startTime = -1, maxSecsToConnect = 0;
|
||||
rfbBool disconnectAfterFirstClient = TRUE;
|
||||
|
||||
/* a dictionary mapping characters to keycodes */
|
||||
CFMutableDictionaryRef charKeyMap;
|
||||
|
||||
/* a dictionary mapping characters obtained by Shift to keycodes */
|
||||
CFMutableDictionaryRef charShiftKeyMap;
|
||||
|
||||
/* a dictionary mapping characters obtained by Alt-Gr to keycodes */
|
||||
CFMutableDictionaryRef charAltGrKeyMap;
|
||||
|
||||
/* a dictionary mapping characters obtained by Shift+Alt-Gr to keycodes */
|
||||
CFMutableDictionaryRef charShiftAltGrKeyMap;
|
||||
|
||||
/* a table mapping special keys to keycodes. static as these are layout-independent */
|
||||
static int specialKeyMap[] = {
|
||||
/* "Special" keys */
|
||||
XK_space, 49, /* Space */
|
||||
XK_Return, 36, /* Return */
|
||||
XK_Delete, 117, /* Delete */
|
||||
XK_Tab, 48, /* Tab */
|
||||
XK_Escape, 53, /* Esc */
|
||||
XK_Caps_Lock, 57, /* Caps Lock */
|
||||
XK_Num_Lock, 71, /* Num Lock */
|
||||
XK_Scroll_Lock, 107, /* Scroll Lock */
|
||||
XK_Pause, 113, /* Pause */
|
||||
XK_BackSpace, 51, /* Backspace */
|
||||
XK_Insert, 114, /* Insert */
|
||||
|
||||
/* Cursor movement */
|
||||
XK_Up, 126, /* Cursor Up */
|
||||
XK_Down, 125, /* Cursor Down */
|
||||
XK_Left, 123, /* Cursor Left */
|
||||
XK_Right, 124, /* Cursor Right */
|
||||
XK_Page_Up, 116, /* Page Up */
|
||||
XK_Page_Down, 121, /* Page Down */
|
||||
XK_Home, 115, /* Home */
|
||||
XK_End, 119, /* End */
|
||||
|
||||
/* Numeric keypad */
|
||||
XK_KP_0, 82, /* KP 0 */
|
||||
XK_KP_1, 83, /* KP 1 */
|
||||
XK_KP_2, 84, /* KP 2 */
|
||||
XK_KP_3, 85, /* KP 3 */
|
||||
XK_KP_4, 86, /* KP 4 */
|
||||
XK_KP_5, 87, /* KP 5 */
|
||||
XK_KP_6, 88, /* KP 6 */
|
||||
XK_KP_7, 89, /* KP 7 */
|
||||
XK_KP_8, 91, /* KP 8 */
|
||||
XK_KP_9, 92, /* KP 9 */
|
||||
XK_KP_Enter, 76, /* KP Enter */
|
||||
XK_KP_Decimal, 65, /* KP . */
|
||||
XK_KP_Add, 69, /* KP + */
|
||||
XK_KP_Subtract, 78, /* KP - */
|
||||
XK_KP_Multiply, 67, /* KP * */
|
||||
XK_KP_Divide, 75, /* KP / */
|
||||
|
||||
/* Function keys */
|
||||
XK_F1, 122, /* F1 */
|
||||
XK_F2, 120, /* F2 */
|
||||
XK_F3, 99, /* F3 */
|
||||
XK_F4, 118, /* F4 */
|
||||
XK_F5, 96, /* F5 */
|
||||
XK_F6, 97, /* F6 */
|
||||
XK_F7, 98, /* F7 */
|
||||
XK_F8, 100, /* F8 */
|
||||
XK_F9, 101, /* F9 */
|
||||
XK_F10, 109, /* F10 */
|
||||
XK_F11, 103, /* F11 */
|
||||
XK_F12, 111, /* F12 */
|
||||
|
||||
/* Modifier keys */
|
||||
XK_Shift_L, 56, /* Shift Left */
|
||||
XK_Shift_R, 56, /* Shift Right */
|
||||
XK_Control_L, 59, /* Ctrl Left */
|
||||
XK_Control_R, 59, /* Ctrl Right */
|
||||
XK_Meta_L, 58, /* Logo Left (-> Option) */
|
||||
XK_Meta_R, 58, /* Logo Right (-> Option) */
|
||||
XK_Alt_L, 55, /* Alt Left (-> Command) */
|
||||
XK_Alt_R, 55, /* Alt Right (-> Command) */
|
||||
XK_ISO_Level3_Shift, 61, /* Alt-Gr (-> Option Right) */
|
||||
0x1008FF2B, 63, /* Fn */
|
||||
|
||||
/* Weirdness I can't figure out */
|
||||
#if 0
|
||||
XK_3270_PrintScreen, 105, /* PrintScrn */
|
||||
??? 94, 50, /* International */
|
||||
XK_Menu, 50, /* Menu (-> International) */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Global shifting modifier states */
|
||||
rfbBool isShiftDown;
|
||||
rfbBool isAltGrDown;
|
||||
|
||||
|
||||
static int
|
||||
saveDimSettings(void)
|
||||
{
|
||||
if (IOPMGetAggressiveness(power_mgt,
|
||||
kPMMinutesToDim,
|
||||
&dim_time) != kIOReturnSuccess)
|
||||
return -1;
|
||||
|
||||
dim_time_saved = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
restoreDimSettings(void)
|
||||
{
|
||||
if (!dim_time_saved)
|
||||
return -1;
|
||||
|
||||
if (IOPMSetAggressiveness(power_mgt,
|
||||
kPMMinutesToDim,
|
||||
dim_time) != kIOReturnSuccess)
|
||||
return -1;
|
||||
|
||||
dim_time_saved = FALSE;
|
||||
dim_time = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
saveSleepSettings(void)
|
||||
{
|
||||
if (IOPMGetAggressiveness(power_mgt,
|
||||
kPMMinutesToSleep,
|
||||
&sleep_time) != kIOReturnSuccess)
|
||||
return -1;
|
||||
|
||||
sleep_time_saved = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
restoreSleepSettings(void)
|
||||
{
|
||||
if (!sleep_time_saved)
|
||||
return -1;
|
||||
|
||||
if (IOPMSetAggressiveness(power_mgt,
|
||||
kPMMinutesToSleep,
|
||||
sleep_time) != kIOReturnSuccess)
|
||||
return -1;
|
||||
|
||||
sleep_time_saved = FALSE;
|
||||
sleep_time = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dimmingInit(void)
|
||||
{
|
||||
pthread_mutex_init(&dimming_mutex, NULL);
|
||||
|
||||
if (IOMasterPort(bootstrap_port, &master_dev_port) != kIOReturnSuccess)
|
||||
return -1;
|
||||
|
||||
if (!(power_mgt = IOPMFindPowerManagement(master_dev_port)))
|
||||
return -1;
|
||||
|
||||
if (preventDimming) {
|
||||
if (saveDimSettings() < 0)
|
||||
return -1;
|
||||
if (IOPMSetAggressiveness(power_mgt,
|
||||
kPMMinutesToDim, 0) != kIOReturnSuccess)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (preventSleep) {
|
||||
if (saveSleepSettings() < 0)
|
||||
return -1;
|
||||
if (IOPMSetAggressiveness(power_mgt,
|
||||
kPMMinutesToSleep, 0) != kIOReturnSuccess)
|
||||
return -1;
|
||||
}
|
||||
|
||||
initialized = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
undim(void)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
pthread_mutex_lock(&dimming_mutex);
|
||||
|
||||
if (!initialized)
|
||||
goto DONE;
|
||||
|
||||
if (!preventDimming) {
|
||||
if (saveDimSettings() < 0)
|
||||
goto DONE;
|
||||
if (IOPMSetAggressiveness(power_mgt, kPMMinutesToDim, 0) != kIOReturnSuccess)
|
||||
goto DONE;
|
||||
if (restoreDimSettings() < 0)
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (!preventSleep) {
|
||||
if (saveSleepSettings() < 0)
|
||||
goto DONE;
|
||||
if (IOPMSetAggressiveness(power_mgt, kPMMinutesToSleep, 0) != kIOReturnSuccess)
|
||||
goto DONE;
|
||||
if (restoreSleepSettings() < 0)
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
DONE:
|
||||
pthread_mutex_unlock(&dimming_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dimmingShutdown(void)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (!initialized)
|
||||
goto DONE;
|
||||
|
||||
pthread_mutex_lock(&dimming_mutex);
|
||||
if (dim_time_saved)
|
||||
if (restoreDimSettings() < 0)
|
||||
goto DONE;
|
||||
if (sleep_time_saved)
|
||||
if (restoreSleepSettings() < 0)
|
||||
goto DONE;
|
||||
|
||||
result = 0;
|
||||
|
||||
DONE:
|
||||
pthread_mutex_unlock(&dimming_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
void serverShutdown(rfbClientPtr cl);
|
||||
|
||||
/*
|
||||
Synthesize a keyboard event. This is not called on the main thread due to rfbRunEventLoop(..,..,TRUE), but it works.
|
||||
We first look up the incoming keysym in the keymap for special keys (and save state of the shifting modifiers).
|
||||
If the incoming keysym does not map to a special key, the char keymaps pertaining to the respective shifting modifier are used
|
||||
in order to allow for keyboard combos with other modifiers.
|
||||
As a last resort, the incoming keysym is simply used as a Unicode value. This way MacOS does not support any modifiers though.
|
||||
*/
|
||||
void
|
||||
KbdAddEvent(rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl)
|
||||
{
|
||||
int i;
|
||||
CGKeyCode keyCode = -1;
|
||||
CGEventRef keyboardEvent;
|
||||
int specialKeyFound = 0;
|
||||
|
||||
undim();
|
||||
|
||||
/* look for special key */
|
||||
for (i = 0; i < (sizeof(specialKeyMap) / sizeof(int)); i += 2) {
|
||||
if (specialKeyMap[i] == keySym) {
|
||||
keyCode = specialKeyMap[i+1];
|
||||
specialKeyFound = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(specialKeyFound) {
|
||||
/* keycode for special key found */
|
||||
keyboardEvent = CGEventCreateKeyboardEvent(eventSource, keyCode, down);
|
||||
/* save state of shifting modifiers */
|
||||
if(keySym == XK_ISO_Level3_Shift)
|
||||
isAltGrDown = down;
|
||||
if(keySym == XK_Shift_L || keySym == XK_Shift_R)
|
||||
isShiftDown = down;
|
||||
|
||||
} else {
|
||||
/* look for char key */
|
||||
size_t keyCodeFromDict;
|
||||
CFStringRef charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)&keySym, 1);
|
||||
CFMutableDictionaryRef keyMap = charKeyMap;
|
||||
if(isShiftDown && !isAltGrDown)
|
||||
keyMap = charShiftKeyMap;
|
||||
if(!isShiftDown && isAltGrDown)
|
||||
keyMap = charAltGrKeyMap;
|
||||
if(isShiftDown && isAltGrDown)
|
||||
keyMap = charShiftAltGrKeyMap;
|
||||
|
||||
if (CFDictionaryGetValueIfPresent(keyMap, charStr, (const void **)&keyCodeFromDict)) {
|
||||
/* keycode for ASCII key found */
|
||||
keyboardEvent = CGEventCreateKeyboardEvent(eventSource, keyCodeFromDict, down);
|
||||
} else {
|
||||
/* last resort: use the symbol's utf-16 value, does not support modifiers though */
|
||||
keyboardEvent = CGEventCreateKeyboardEvent(eventSource, 0, down);
|
||||
CGEventKeyboardSetUnicodeString(keyboardEvent, 1, (UniChar*)&keySym);
|
||||
}
|
||||
|
||||
CFRelease(charStr);
|
||||
}
|
||||
|
||||
/* Set the Shift modifier explicitly as MacOS sometimes gets internal state wrong and Shift stuck. */
|
||||
CGEventSetFlags(keyboardEvent, CGEventGetFlags(keyboardEvent) & (isShiftDown ? kCGEventFlagMaskShift : ~kCGEventFlagMaskShift));
|
||||
|
||||
CGEventPost(kCGSessionEventTap, keyboardEvent);
|
||||
CFRelease(keyboardEvent);
|
||||
}
|
||||
|
||||
/* Synthesize a mouse event. This is not called on the main thread due to rfbRunEventLoop(..,..,TRUE), but it works. */
|
||||
void
|
||||
PtrAddEvent(buttonMask, x, y, cl)
|
||||
int buttonMask;
|
||||
int x;
|
||||
int y;
|
||||
rfbClientPtr cl;
|
||||
{
|
||||
CGPoint position;
|
||||
CGRect displayBounds = CGDisplayBounds(displayID);
|
||||
CGEventRef mouseEvent = NULL;
|
||||
|
||||
undim();
|
||||
|
||||
position.x = x + displayBounds.origin.x;
|
||||
position.y = y + displayBounds.origin.y;
|
||||
|
||||
/* map buttons 4 5 6 7 to scroll events as per https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#745pointerevent */
|
||||
if(buttonMask & (1 << 3))
|
||||
mouseEvent = CGEventCreateScrollWheelEvent(eventSource, kCGScrollEventUnitLine, 2, 1, 0);
|
||||
if(buttonMask & (1 << 4))
|
||||
mouseEvent = CGEventCreateScrollWheelEvent(eventSource, kCGScrollEventUnitLine, 2, -1, 0);
|
||||
if(buttonMask & (1 << 5))
|
||||
mouseEvent = CGEventCreateScrollWheelEvent(eventSource, kCGScrollEventUnitLine, 2, 0, 1);
|
||||
if(buttonMask & (1 << 6))
|
||||
mouseEvent = CGEventCreateScrollWheelEvent(eventSource, kCGScrollEventUnitLine, 2, 0, -1);
|
||||
|
||||
if (mouseEvent) {
|
||||
CGEventPost(kCGSessionEventTap, mouseEvent);
|
||||
CFRelease(mouseEvent);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
Use the deprecated CGPostMouseEvent API here as we get a buttonmask plus position which is pretty low-level
|
||||
whereas CGEventCreateMouseEvent is expecting higher-level events. This allows for direct injection of
|
||||
double clicks and drags whereas we would need to synthesize these events for the high-level API.
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
CGPostMouseEvent(position, TRUE, 3,
|
||||
(buttonMask & (1 << 0)) ? TRUE : FALSE,
|
||||
(buttonMask & (1 << 2)) ? TRUE : FALSE,
|
||||
(buttonMask & (1 << 1)) ? TRUE : FALSE);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialises keyboard handling:
|
||||
This creates four keymaps mapping UniChars to keycodes for the current keyboard layout with no shifting modifiers, Shift, Alt-Gr and Shift+Alt-Gr applied, respectively.
|
||||
*/
|
||||
rfbBool keyboardInit()
|
||||
{
|
||||
size_t i, keyCodeCount=128;
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
||||
const UCKeyboardLayout *keyboardLayout;
|
||||
|
||||
if(!currentKeyboard) {
|
||||
fprintf(stderr, "Could not get current keyboard info\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData));
|
||||
|
||||
printf("Found keyboard layout '%s'\n", CFStringGetCStringPtr(TISGetInputSourceProperty(currentKeyboard, kTISPropertyInputSourceID), kCFStringEncodingUTF8));
|
||||
|
||||
charKeyMap = CFDictionaryCreateMutable(kCFAllocatorDefault, keyCodeCount, &kCFCopyStringDictionaryKeyCallBacks, NULL);
|
||||
charShiftKeyMap = CFDictionaryCreateMutable(kCFAllocatorDefault, keyCodeCount, &kCFCopyStringDictionaryKeyCallBacks, NULL);
|
||||
charAltGrKeyMap = CFDictionaryCreateMutable(kCFAllocatorDefault, keyCodeCount, &kCFCopyStringDictionaryKeyCallBacks, NULL);
|
||||
charShiftAltGrKeyMap = CFDictionaryCreateMutable(kCFAllocatorDefault, keyCodeCount, &kCFCopyStringDictionaryKeyCallBacks, NULL);
|
||||
|
||||
if(!charKeyMap || !charShiftKeyMap || !charAltGrKeyMap || !charShiftAltGrKeyMap) {
|
||||
fprintf(stderr, "Could not create keymaps\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Loop through every keycode to find the character it is mapping to. */
|
||||
for (i = 0; i < keyCodeCount; ++i) {
|
||||
UInt32 deadKeyState = 0;
|
||||
UniChar chars[4];
|
||||
UniCharCount realLength;
|
||||
UInt32 m, modifiers[] = {0, kCGEventFlagMaskShift, kCGEventFlagMaskAlternate, kCGEventFlagMaskShift|kCGEventFlagMaskAlternate};
|
||||
|
||||
/* do this for no modifier, shift and alt-gr applied */
|
||||
for(m = 0; m < sizeof(modifiers) / sizeof(modifiers[0]); ++m) {
|
||||
UCKeyTranslate(keyboardLayout,
|
||||
i,
|
||||
kUCKeyActionDisplay,
|
||||
(modifiers[m] >> 16) & 0xff,
|
||||
LMGetKbdType(),
|
||||
kUCKeyTranslateNoDeadKeysBit,
|
||||
&deadKeyState,
|
||||
sizeof(chars) / sizeof(chars[0]),
|
||||
&realLength,
|
||||
chars);
|
||||
|
||||
CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
|
||||
if(string) {
|
||||
switch(modifiers[m]) {
|
||||
case 0:
|
||||
CFDictionaryAddValue(charKeyMap, string, (const void *)i);
|
||||
break;
|
||||
case kCGEventFlagMaskShift:
|
||||
CFDictionaryAddValue(charShiftKeyMap, string, (const void *)i);
|
||||
break;
|
||||
case kCGEventFlagMaskAlternate:
|
||||
CFDictionaryAddValue(charAltGrKeyMap, string, (const void *)i);
|
||||
break;
|
||||
case kCGEventFlagMaskShift|kCGEventFlagMaskAlternate:
|
||||
CFDictionaryAddValue(charShiftAltGrKeyMap, string, (const void *)i);
|
||||
break;
|
||||
}
|
||||
|
||||
CFRelease(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(currentKeyboard);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
rfbBool
|
||||
ScreenInit(int argc, char**argv)
|
||||
{
|
||||
int bitsPerSample = 8;
|
||||
CGDisplayCount displayCount;
|
||||
CGDirectDisplayID displays[32];
|
||||
|
||||
/* grab the active displays */
|
||||
CGGetActiveDisplayList(32, displays, &displayCount);
|
||||
for (int i=0; i<displayCount; i++) {
|
||||
CGRect bounds = CGDisplayBounds(displays[i]);
|
||||
printf("Found %s display %d at (%d,%d) and a resolution of %dx%d\n", (CGDisplayIsMain(displays[i]) ? "primary" : "secondary"), i, (int)bounds.origin.x, (int)bounds.origin.y, (int)bounds.size.width, (int)bounds.size.height);
|
||||
}
|
||||
if(displayNumber < 0) {
|
||||
printf("Using primary display as a default\n");
|
||||
displayID = CGMainDisplayID();
|
||||
} else if (displayNumber < displayCount) {
|
||||
printf("Using specified display %d\n", displayNumber);
|
||||
displayID = displays[displayNumber];
|
||||
} else {
|
||||
fprintf(stderr, "Specified display %d does not exist\n", displayNumber);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
rfbScreen = rfbGetScreen(&argc,argv,
|
||||
CGDisplayPixelsWide(displayID),
|
||||
CGDisplayPixelsHigh(displayID),
|
||||
bitsPerSample,
|
||||
3,
|
||||
4);
|
||||
if(!rfbScreen) {
|
||||
rfbErr("Could not init rfbScreen.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbScreen->serverFormat.redShift = bitsPerSample*2;
|
||||
rfbScreen->serverFormat.greenShift = bitsPerSample*1;
|
||||
rfbScreen->serverFormat.blueShift = 0;
|
||||
|
||||
gethostname(rfbScreen->thisHost, 255);
|
||||
|
||||
frameBufferOne = malloc(CGDisplayPixelsWide(displayID) * CGDisplayPixelsHigh(displayID) * 4);
|
||||
frameBufferTwo = malloc(CGDisplayPixelsWide(displayID) * CGDisplayPixelsHigh(displayID) * 4);
|
||||
|
||||
/* back buffer */
|
||||
backBuffer = frameBufferOne;
|
||||
/* front buffer */
|
||||
rfbScreen->frameBuffer = frameBufferTwo;
|
||||
|
||||
/* we already capture the cursor in the framebuffer */
|
||||
rfbScreen->cursor = NULL;
|
||||
|
||||
rfbScreen->ptrAddEvent = PtrAddEvent;
|
||||
rfbScreen->kbdAddEvent = KbdAddEvent;
|
||||
|
||||
if(sharedMode) {
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
}
|
||||
|
||||
dispatch_queue_t dispatchQueue = dispatch_queue_create("libvncserver.examples.mac", NULL);
|
||||
CGDisplayStreamRef stream = CGDisplayStreamCreateWithDispatchQueue(displayID,
|
||||
CGDisplayPixelsWide(displayID),
|
||||
CGDisplayPixelsHigh(displayID),
|
||||
'BGRA',
|
||||
nil,
|
||||
dispatchQueue,
|
||||
^(CGDisplayStreamFrameStatus status,
|
||||
uint64_t displayTime,
|
||||
IOSurfaceRef frameSurface,
|
||||
CGDisplayStreamUpdateRef updateRef) {
|
||||
|
||||
if (status == kCGDisplayStreamFrameStatusFrameComplete && frameSurface != NULL) {
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
const CGRect *updatedRects;
|
||||
size_t updatedRectsCount;
|
||||
size_t r;
|
||||
|
||||
if(startTime>0 && time(0)>startTime+maxSecsToConnect)
|
||||
serverShutdown(0);
|
||||
|
||||
/*
|
||||
Copy new frame to back buffer.
|
||||
*/
|
||||
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
|
||||
|
||||
memcpy(backBuffer,
|
||||
IOSurfaceGetBaseAddress(frameSurface),
|
||||
CGDisplayPixelsWide(displayID) * CGDisplayPixelsHigh(displayID) * 4);
|
||||
|
||||
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
|
||||
|
||||
/* Lock out client reads. */
|
||||
iterator=rfbGetClientIterator(rfbScreen);
|
||||
while((cl=rfbClientIteratorNext(iterator))) {
|
||||
LOCK(cl->sendMutex);
|
||||
}
|
||||
rfbReleaseClientIterator(iterator);
|
||||
|
||||
/* Swap framebuffers. */
|
||||
if (backBuffer == frameBufferOne) {
|
||||
backBuffer = frameBufferTwo;
|
||||
rfbScreen->frameBuffer = frameBufferOne;
|
||||
} else {
|
||||
backBuffer = frameBufferOne;
|
||||
rfbScreen->frameBuffer = frameBufferTwo;
|
||||
}
|
||||
|
||||
/* Mark modified rects in new framebuffer. */
|
||||
updatedRects = CGDisplayStreamUpdateGetRects(updateRef, kCGDisplayStreamUpdateDirtyRects, &updatedRectsCount);
|
||||
for(r=0; r<updatedRectsCount; ++r) {
|
||||
rfbMarkRectAsModified(rfbScreen,
|
||||
updatedRects[r].origin.x,
|
||||
updatedRects[r].origin.y,
|
||||
updatedRects[r].origin.x + updatedRects[r].size.width,
|
||||
updatedRects[r].origin.y + updatedRects[r].size.height);
|
||||
}
|
||||
|
||||
/* Swapping framebuffers finished, reenable client reads. */
|
||||
iterator=rfbGetClientIterator(rfbScreen);
|
||||
while((cl=rfbClientIteratorNext(iterator))) {
|
||||
UNLOCK(cl->sendMutex);
|
||||
}
|
||||
rfbReleaseClientIterator(iterator);
|
||||
}
|
||||
|
||||
});
|
||||
if(stream) {
|
||||
CGDisplayStreamStart(stream);
|
||||
} else {
|
||||
rfbErr("Could not get screen contents. Check if the program has been given screen recording permissions in 'System Preferences'->'Security & Privacy'->'Privacy'->'Screen Recording'.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rfbInitServer(rfbScreen);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void clientGone(rfbClientPtr cl)
|
||||
{
|
||||
serverShutdown(cl);
|
||||
}
|
||||
|
||||
enum rfbNewClientAction newClient(rfbClientPtr cl)
|
||||
{
|
||||
if(startTime>0 && time(0)>startTime+maxSecsToConnect)
|
||||
serverShutdown(cl);
|
||||
|
||||
if(disconnectAfterFirstClient)
|
||||
cl->clientGoneHook = clientGone;
|
||||
|
||||
cl->viewOnly = viewOnly;
|
||||
|
||||
return(RFB_CLIENT_ACCEPT);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=argc-1;i>0;i--)
|
||||
if(i<argc-1 && strcmp(argv[i],"-wait4client")==0) {
|
||||
maxSecsToConnect = atoi(argv[i+1])/1000;
|
||||
startTime = time(0);
|
||||
} else if(strcmp(argv[i],"-runforever")==0) {
|
||||
disconnectAfterFirstClient = FALSE;
|
||||
} else if(strcmp(argv[i],"-viewonly")==0) {
|
||||
viewOnly=TRUE;
|
||||
} else if(strcmp(argv[i],"-shared")==0) {
|
||||
sharedMode=TRUE;
|
||||
} else if(strcmp(argv[i],"-display")==0) {
|
||||
displayNumber = atoi(argv[i+1]);
|
||||
}
|
||||
|
||||
if(!viewOnly && !AXIsProcessTrusted()) {
|
||||
fprintf(stderr, "You have configured the server to post input events, but it does not have the necessary system permission. Please check if the program has been given permission to control your computer in 'System Preferences'->'Security & Privacy'->'Privacy'->'Accessibility'.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dimmingInit();
|
||||
|
||||
/* Create a private event source for the server. This helps a lot with modifier keys getting stuck on the OS side
|
||||
(but does not completely mitigate the issue: For this, we keep track of modifier key state and set it specifically
|
||||
for the generated keyboard event in the keyboard event handler). */
|
||||
eventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);
|
||||
|
||||
if(!keyboardInit())
|
||||
exit(1);
|
||||
|
||||
if(!ScreenInit(argc,argv))
|
||||
exit(1);
|
||||
rfbScreen->newClientHook = newClient;
|
||||
|
||||
rfbRunEventLoop(rfbScreen,-1,TRUE);
|
||||
|
||||
/*
|
||||
The VNC machinery is in the background now and framebuffer updating happens on another thread as well.
|
||||
*/
|
||||
while(1) {
|
||||
/* Nothing left to do on the main thread. */
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
dimmingShutdown();
|
||||
|
||||
return(0); /* never ... */
|
||||
}
|
||||
|
||||
void serverShutdown(rfbClientPtr cl)
|
||||
{
|
||||
rfbScreenCleanup(rfbScreen);
|
||||
dimmingShutdown();
|
||||
exit(0);
|
||||
}
|
||||
130
android/extern/libvncserver/examples/server/pnmshow.c
vendored
Normal file
130
android/extern/libvncserver/examples/server/pnmshow.c
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @example pnmshow.c
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
|
||||
#ifndef HAVE_HANDLEKEY
|
||||
static void HandleKey(rfbBool down,rfbKeySym key,rfbClientPtr cl)
|
||||
{
|
||||
if(down && (key==XK_Escape || key=='q' || key=='Q'))
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
FILE* in=stdin;
|
||||
int i,j,k,l,width,height,paddedWidth;
|
||||
char buffer[1024];
|
||||
rfbScreenInfoPtr rfbScreen;
|
||||
enum { BW, GRAY, TRUECOLOUR } picType=TRUECOLOUR;
|
||||
int bytesPerPixel,bitsPerPixelInFile;
|
||||
|
||||
if(argc>1) {
|
||||
in=fopen(argv[1],"rb");
|
||||
if(!in) {
|
||||
printf("Couldn't find file %s.\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fgets(buffer,1024,in);
|
||||
if(!strncmp(buffer,"P6",2)) {
|
||||
picType=TRUECOLOUR;
|
||||
bytesPerPixel=4; bitsPerPixelInFile=3*8;
|
||||
} else if(!strncmp(buffer,"P5",2)) {
|
||||
picType=GRAY;
|
||||
bytesPerPixel=1; bitsPerPixelInFile=1*8;
|
||||
} else if(!strncmp(buffer,"P4",2)) {
|
||||
picType=BW;
|
||||
bytesPerPixel=1; bitsPerPixelInFile=1;
|
||||
} else {
|
||||
printf("Not a ppm.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* skip comments */
|
||||
do {
|
||||
fgets(buffer,1024,in);
|
||||
} while(buffer[0]=='#');
|
||||
|
||||
/* get width & height */
|
||||
sscanf(buffer,"%d %d",&width,&height);
|
||||
rfbLog("Got width %d and height %d.\n",width,height);
|
||||
if(picType!=BW)
|
||||
fgets(buffer,1024,in);
|
||||
else
|
||||
width=1+((width-1)|7);
|
||||
|
||||
/* vncviewers have problems with widths which are no multiple of 4. */
|
||||
paddedWidth = width;
|
||||
if(width&3)
|
||||
paddedWidth+=4-(width&3);
|
||||
|
||||
/* initialize data for vnc server */
|
||||
rfbScreen = rfbGetScreen(&argc,argv,paddedWidth,height,8,(bitsPerPixelInFile+7)/8,bytesPerPixel);
|
||||
if(!rfbScreen)
|
||||
return 1;
|
||||
if(argc>1)
|
||||
rfbScreen->desktopName = argv[1];
|
||||
else
|
||||
rfbScreen->desktopName = "Picture";
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
rfbScreen->kbdAddEvent = HandleKey;
|
||||
|
||||
/* enable http */
|
||||
rfbScreen->httpDir = "../webclients";
|
||||
|
||||
/* allocate picture and read it */
|
||||
rfbScreen->frameBuffer = (char*)malloc(paddedWidth*bytesPerPixel*height);
|
||||
if(!rfbScreen->frameBuffer)
|
||||
exit(1);
|
||||
fread(rfbScreen->frameBuffer,width*bitsPerPixelInFile/8,height,in);
|
||||
fclose(in);
|
||||
|
||||
if(picType!=TRUECOLOUR) {
|
||||
rfbScreen->serverFormat.trueColour=FALSE;
|
||||
rfbScreen->colourMap.count=256;
|
||||
rfbScreen->colourMap.is16=FALSE;
|
||||
rfbScreen->colourMap.data.bytes=malloc(256*3);
|
||||
if(!rfbScreen->colourMap.data.bytes)
|
||||
exit(1);
|
||||
for(i=0;i<256;i++)
|
||||
memset(rfbScreen->colourMap.data.bytes+3*i,i,3);
|
||||
}
|
||||
|
||||
switch(picType) {
|
||||
case TRUECOLOUR:
|
||||
/* correct the format to 4 bytes instead of 3 (and pad to paddedWidth) */
|
||||
for(j=height-1;j>=0;j--) {
|
||||
for(i=width-1;i>=0;i--)
|
||||
for(k=2;k>=0;k--)
|
||||
rfbScreen->frameBuffer[(j*paddedWidth+i)*4+k]=
|
||||
rfbScreen->frameBuffer[(j*width+i)*3+k];
|
||||
for(i=width*4;i<paddedWidth*4;i++)
|
||||
rfbScreen->frameBuffer[j*paddedWidth*4+i]=0;
|
||||
}
|
||||
break;
|
||||
case GRAY:
|
||||
break;
|
||||
case BW:
|
||||
/* correct the format from 1 bit to 8 bits */
|
||||
for(j=height-1;j>=0;j--)
|
||||
for(i=width-1;i>=0;i-=8) {
|
||||
l=(unsigned char)rfbScreen->frameBuffer[(j*width+i)/8];
|
||||
for(k=7;k>=0;k--)
|
||||
rfbScreen->frameBuffer[j*paddedWidth+i+7-k]=(l&(1<<k))?0:255;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* initialize server */
|
||||
rfbInitServer(rfbScreen);
|
||||
|
||||
/* run event loop */
|
||||
rfbRunEventLoop(rfbScreen,40000,FALSE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
106
android/extern/libvncserver/examples/server/pnmshow24.c
vendored
Normal file
106
android/extern/libvncserver/examples/server/pnmshow24.c
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
@example pnmshow24.c
|
||||
pnmshow24 is like pnmshow, but it uses 3 bytes/pixel internally, which is not
|
||||
as efficient as 4 bytes/pixel for translation, because there is no native data
|
||||
type of that size, so you have to memcpy pixels and be real cautious with
|
||||
endianness. Anyway, it works.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
|
||||
#ifndef LIBVNCSERVER_ALLOW24BPP
|
||||
int main() {
|
||||
printf("I need the ALLOW24BPP LibVNCServer flag to work\n");
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
|
||||
static void HandleKey(rfbBool down,rfbKeySym key,rfbClientPtr cl)
|
||||
{
|
||||
if(down && (key==XK_Escape || key=='q' || key=='Q'))
|
||||
rfbCloseClient(cl);
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
FILE* in=stdin;
|
||||
int j,width,height,paddedWidth;
|
||||
char buffer[1024];
|
||||
rfbScreenInfoPtr rfbScreen;
|
||||
|
||||
if(argc>1) {
|
||||
in=fopen(argv[1],"rb");
|
||||
if(!in) {
|
||||
printf("Couldn't find file %s.\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fgets(buffer,1024,in);
|
||||
if(strncmp(buffer,"P6",2)) {
|
||||
printf("Not a ppm.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* skip comments */
|
||||
do {
|
||||
fgets(buffer,1024,in);
|
||||
} while(buffer[0]=='#');
|
||||
|
||||
/* get width & height */
|
||||
sscanf(buffer,"%d %d",&width,&height);
|
||||
rfbLog("Got width %d and height %d.\n",width,height);
|
||||
fgets(buffer,1024,in);
|
||||
|
||||
/* vncviewers have problems with widths which are no multiple of 4. */
|
||||
paddedWidth = width;
|
||||
|
||||
/* if your vncviewer doesn't have problems with a width
|
||||
which is not a multiple of 4, you can comment this. */
|
||||
if(width&3)
|
||||
paddedWidth+=4-(width&3);
|
||||
|
||||
/* initialize data for vnc server */
|
||||
rfbScreen = rfbGetScreen(&argc,argv,paddedWidth,height,8,3,3);
|
||||
if(!rfbScreen)
|
||||
return 1;
|
||||
if(argc>1)
|
||||
rfbScreen->desktopName = argv[1];
|
||||
else
|
||||
rfbScreen->desktopName = "Picture";
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
rfbScreen->kbdAddEvent = HandleKey;
|
||||
|
||||
/* enable http */
|
||||
rfbScreen->httpDir = "../webclients";
|
||||
|
||||
/* allocate picture and read it */
|
||||
rfbScreen->frameBuffer = (char*)malloc(paddedWidth*3*height);
|
||||
if(!rfbScreen->frameBuffer)
|
||||
return 1;
|
||||
fread(rfbScreen->frameBuffer,width*3,height,in);
|
||||
fclose(in);
|
||||
|
||||
/* pad to paddedWidth */
|
||||
if(width != paddedWidth) {
|
||||
int padCount = 3*(paddedWidth - width);
|
||||
for(j=height-1;j>=0;j--) {
|
||||
memmove(rfbScreen->frameBuffer+3*paddedWidth*j,
|
||||
rfbScreen->frameBuffer+3*width*j,
|
||||
3*width);
|
||||
memset(rfbScreen->frameBuffer+3*paddedWidth*(j+1)-padCount,
|
||||
0,padCount);
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize server */
|
||||
rfbInitServer(rfbScreen);
|
||||
|
||||
/* run event loop */
|
||||
rfbRunEventLoop(rfbScreen,40000,FALSE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
195
android/extern/libvncserver/examples/server/radon.h
vendored
Normal file
195
android/extern/libvncserver/examples/server/radon.h
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
static unsigned char radonFontData[2280]={
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32 */
|
||||
0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x00,0x00, /* 33 */
|
||||
0x00,0x28,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 34 */
|
||||
0x00,0x44,0x44,0xba,0x44,0x44,0x44,0xba,0x44,0x44,0x00,0x00, /* 35 */
|
||||
0x10,0x7e,0x80,0x90,0x80,0x7c,0x02,0x12,0x02,0xfc,0x10,0x00, /* 36 */
|
||||
0x00,0x62,0x92,0x94,0x68,0x10,0x2c,0x52,0x92,0x8c,0x00,0x00, /* 37 */
|
||||
0x00,0x60,0x90,0x90,0x40,0x20,0x90,0x8a,0x84,0x7a,0x00,0x00, /* 38 */
|
||||
0x00,0x10,0x10,0x10,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 39 */
|
||||
0x00,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x00,0x00, /* 40 */
|
||||
0x00,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x00,0x00, /* 41 */
|
||||
0x00,0x10,0x92,0x54,0x10,0x10,0x54,0x92,0x10,0x00,0x00,0x00, /* 42 */
|
||||
0x00,0x00,0x10,0x10,0x10,0xd6,0x10,0x10,0x10,0x00,0x00,0x00, /* 43 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x30,0x00, /* 44 */
|
||||
0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00, /* 45 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00, /* 46 */
|
||||
0x00,0x02,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00,0x00, /* 47 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x82,0x7c,0x00,0x00, /* 48 */
|
||||
0x00,0x08,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00, /* 49 */
|
||||
0x00,0xfc,0x02,0x02,0x02,0x7c,0x80,0x80,0x00,0xfe,0x00,0x00, /* 50 */
|
||||
0x00,0xfc,0x02,0x02,0x02,0x3c,0x02,0x02,0x02,0xfc,0x00,0x00, /* 51 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x7a,0x02,0x02,0x02,0x02,0x00,0x00, /* 52 */
|
||||
0x00,0xfe,0x00,0x80,0x80,0x7c,0x02,0x02,0x02,0xfc,0x00,0x00, /* 53 */
|
||||
0x00,0x7c,0x80,0x80,0xbc,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 54 */
|
||||
0x00,0xfc,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00, /* 55 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x7c,0x82,0x82,0x82,0x7c,0x00,0x00, /* 56 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x82,0x7a,0x02,0x02,0xfc,0x00,0x00, /* 57 */
|
||||
0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00, /* 58 */
|
||||
0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x10,0x10,0x60,0x00,0x00, /* 59 */
|
||||
0x00,0x08,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x08,0x00,0x00, /* 60 */
|
||||
0x00,0x00,0x00,0x00,0xfe,0x00,0xfe,0x00,0x00,0x00,0x00,0x00, /* 61 */
|
||||
0x00,0x10,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x10,0x00,0x00, /* 62 */
|
||||
0x00,0xfc,0x02,0x02,0x02,0x1c,0x20,0x20,0x00,0x20,0x00,0x00, /* 63 */
|
||||
0x00,0x7c,0x82,0x8a,0x92,0x92,0x92,0x8c,0x80,0x7c,0x00,0x00, /* 64 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x82,0xba,0x82,0x82,0x82,0x00,0x00, /* 65 */
|
||||
0x00,0xbc,0x82,0x82,0x82,0xbc,0x82,0x82,0x82,0xbc,0x00,0x00, /* 66 */
|
||||
0x00,0x7c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7c,0x00,0x00, /* 67 */
|
||||
0x00,0xbc,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xbc,0x00,0x00, /* 68 */
|
||||
0x00,0x7c,0x80,0x80,0x80,0xb8,0x80,0x80,0x80,0x7c,0x00,0x00, /* 69 */
|
||||
0x00,0x7c,0x80,0x80,0x80,0xb8,0x80,0x80,0x80,0x80,0x00,0x00, /* 70 */
|
||||
0x00,0x7c,0x80,0x80,0x80,0x80,0x9a,0x82,0x82,0x7c,0x00,0x00, /* 71 */
|
||||
0x00,0x82,0x82,0x82,0x82,0xba,0x82,0x82,0x82,0x82,0x00,0x00, /* 72 */
|
||||
0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 73 */
|
||||
0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x78,0x00,0x00, /* 74 */
|
||||
0x00,0x82,0x82,0x82,0x82,0xbc,0x82,0x82,0x82,0x82,0x00,0x00, /* 75 */
|
||||
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7e,0x00,0x00, /* 76 */
|
||||
0x00,0x7c,0x82,0x92,0x92,0x92,0x92,0x82,0x82,0x82,0x00,0x00, /* 77 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x00,0x00, /* 78 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 79 */
|
||||
0x00,0xbc,0x82,0x82,0x82,0xbc,0x80,0x80,0x80,0x80,0x00,0x00, /* 80 */
|
||||
0x00,0x7c,0x82,0x82,0x82,0x82,0x8a,0x8a,0x82,0x7c,0x00,0x00, /* 81 */
|
||||
0x00,0xbc,0x82,0x82,0x82,0xbc,0x82,0x82,0x82,0x82,0x00,0x00, /* 82 */
|
||||
0x00,0x7e,0x80,0x80,0x80,0x7c,0x02,0x02,0x02,0xfc,0x00,0x00, /* 83 */
|
||||
0x00,0xfe,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 84 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 85 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x82,0x84,0x88,0x90,0xa0,0x00,0x00, /* 86 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x92,0x92,0x92,0x82,0x7c,0x00,0x00, /* 87 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x7c,0x82,0x82,0x82,0x82,0x00,0x00, /* 88 */
|
||||
0x00,0x82,0x82,0x82,0x82,0x7c,0x00,0x10,0x10,0x10,0x00,0x00, /* 89 */
|
||||
0x00,0xfc,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x7e,0x00,0x00, /* 90 */
|
||||
0x00,0x1c,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x1c,0x00,0x00, /* 91 */
|
||||
0x00,0x80,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00, /* 92 */
|
||||
0x00,0x38,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x38,0x00,0x00, /* 93 */
|
||||
0x00,0x38,0x44,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 94 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00, /* 95 */
|
||||
0x00,0x08,0x08,0x08,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 96 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 97 */
|
||||
0x00,0x00,0x40,0x40,0x5c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 98 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x40,0x40,0x40,0x40,0x3c,0x00,0x00, /* 99 */
|
||||
0x00,0x00,0x02,0x02,0x3a,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 100 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x5c,0x40,0x3c,0x00,0x00, /* 101 */
|
||||
0x00,0x00,0x0c,0x10,0x10,0x10,0x54,0x10,0x10,0x10,0x00,0x00, /* 102 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3a,0x02,0x3c, /* 103 */
|
||||
0x00,0x00,0x40,0x40,0x5c,0x42,0x42,0x42,0x42,0x42,0x00,0x00, /* 104 */
|
||||
0x00,0x00,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00, /* 105 */
|
||||
0x00,0x00,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x30, /* 106 */
|
||||
0x00,0x00,0x40,0x40,0x42,0x42,0x5c,0x42,0x42,0x42,0x00,0x00, /* 107 */
|
||||
0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00, /* 108 */
|
||||
0x00,0x00,0x00,0x00,0x7c,0x82,0x92,0x92,0x92,0x92,0x00,0x00, /* 109 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x00,0x00, /* 110 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 111 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x5c,0x40,0x40, /* 112 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3a,0x02,0x02, /* 113 */
|
||||
0x00,0x00,0x00,0x00,0x0c,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 114 */
|
||||
0x00,0x00,0x00,0x00,0x3e,0x40,0x3c,0x02,0x02,0x7c,0x00,0x00, /* 115 */
|
||||
0x00,0x00,0x10,0x10,0x10,0x54,0x10,0x10,0x10,0x0c,0x00,0x00, /* 116 */
|
||||
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 117 */
|
||||
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x44,0x48,0x50,0x00,0x00, /* 118 */
|
||||
0x00,0x00,0x00,0x00,0x92,0x92,0x92,0x92,0x82,0x7c,0x00,0x00, /* 119 */
|
||||
0x00,0x00,0x00,0x00,0x42,0x42,0x3c,0x42,0x42,0x42,0x00,0x00, /* 120 */
|
||||
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3a,0x02,0x3c, /* 121 */
|
||||
0x00,0x00,0x00,0x00,0x7c,0x02,0x0c,0x30,0x40,0x3e,0x00,0x00, /* 122 */
|
||||
0x00,0x1c,0x20,0x20,0x20,0x40,0x20,0x20,0x20,0x1c,0x00,0x00, /* 123 */
|
||||
0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x00,0x00, /* 124 */
|
||||
0x00,0x38,0x04,0x04,0x04,0x02,0x04,0x04,0x04,0x38,0x00,0x00, /* 125 */
|
||||
0x00,0x04,0x38,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 126 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160 */
|
||||
0x00,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 161 */
|
||||
0x00,0x00,0x08,0x3e,0x40,0x48,0x48,0x40,0x3e,0x08,0x00,0x00, /* 162 */
|
||||
0x00,0x1c,0x20,0x20,0x20,0xa8,0x20,0x20,0x42,0xbc,0x00,0x00, /* 163 */
|
||||
0x00,0x00,0x82,0x38,0x44,0x44,0x44,0x38,0x82,0x00,0x00,0x00, /* 164 */
|
||||
0x00,0x82,0x82,0x82,0x7c,0x00,0x54,0x10,0x54,0x10,0x00,0x00, /* 165 */
|
||||
0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x10,0x10,0x10,0x00,0x00, /* 166 */
|
||||
0x00,0x38,0x40,0x38,0x44,0x44,0x44,0x44,0x38,0x04,0x38,0x00, /* 167 */
|
||||
0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168 */
|
||||
0x00,0x7c,0x82,0x9a,0xa2,0xa2,0xa2,0x9a,0x82,0x7c,0x00,0x00, /* 169 */
|
||||
0x38,0x04,0x34,0x44,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00, /* 170 */
|
||||
0x00,0x00,0x00,0x24,0x48,0x00,0x48,0x24,0x00,0x00,0x00,0x00, /* 171 */
|
||||
0x00,0x00,0x00,0x00,0x00,0xfc,0x02,0x02,0x02,0x00,0x00,0x00, /* 172 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00, /* 173 */
|
||||
0x00,0x7c,0x82,0x92,0xaa,0xb2,0xaa,0xaa,0x82,0x7c,0x00,0x00, /* 174 */
|
||||
0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 175 */
|
||||
0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176 */
|
||||
0x00,0x10,0x10,0xd6,0x10,0x10,0x00,0xfe,0x00,0x00,0x00,0x00, /* 177 */
|
||||
0x38,0x04,0x18,0x20,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 178 */
|
||||
0x38,0x04,0x38,0x04,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 179 */
|
||||
0x18,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 180 */
|
||||
0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x58,0x40,0x40, /* 181 */
|
||||
0x00,0x79,0xfa,0xfa,0xfa,0x7a,0x02,0x0a,0x0a,0x0a,0x0a,0x00, /* 182 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00, /* 183 */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00, /* 184 */
|
||||
0x08,0x18,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 185 */
|
||||
0x38,0x44,0x44,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00, /* 186 */
|
||||
0x00,0x00,0x00,0x48,0x24,0x00,0x24,0x48,0x00,0x00,0x00,0x00, /* 187 */
|
||||
0x20,0xa2,0x22,0x22,0x24,0x08,0x10,0x29,0x49,0x85,0x01,0x01, /* 188 */
|
||||
0x20,0xa2,0x22,0x22,0x24,0x08,0x10,0x2e,0x41,0x86,0x08,0x0f, /* 189 */
|
||||
0xe0,0x12,0xe2,0x12,0xe4,0x08,0x10,0x29,0x49,0x85,0x01,0x01, /* 190 */
|
||||
0x00,0x08,0x00,0x08,0x08,0x70,0x80,0x80,0x80,0x7e,0x00,0x00, /* 191 */
|
||||
0x20,0x18,0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 192 */
|
||||
0x08,0x30,0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 193 */
|
||||
0x38,0x44,0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 194 */
|
||||
0x32,0x4c,0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 195 */
|
||||
0x6c,0x00,0x00,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 196 */
|
||||
0x38,0x44,0x38,0x7c,0x82,0x82,0x82,0xba,0x82,0x82,0x00,0x00, /* 197 */
|
||||
0x00,0x77,0x88,0x88,0x88,0x8b,0xa8,0x88,0x88,0x8b,0x00,0x00, /* 198 */
|
||||
0x00,0x7c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x6c,0x10,0x20, /* 199 */
|
||||
0x20,0x18,0x00,0x7c,0x80,0x80,0xb8,0x80,0x80,0x7c,0x00,0x00, /* 200 */
|
||||
0x08,0x30,0x00,0x7c,0x80,0x80,0xb8,0x80,0x80,0x7c,0x00,0x00, /* 201 */
|
||||
0x38,0x44,0x00,0x7c,0x80,0x80,0xb8,0x80,0x80,0x7c,0x00,0x00, /* 202 */
|
||||
0x6c,0x00,0x00,0x7c,0x80,0x80,0xb8,0x80,0x80,0x7c,0x00,0x00, /* 203 */
|
||||
0x20,0x18,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 204 */
|
||||
0x08,0x30,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 205 */
|
||||
0x38,0x44,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 206 */
|
||||
0x6c,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 207 */
|
||||
0x00,0xbc,0x82,0x82,0x82,0xb2,0x82,0x82,0x82,0xbc,0x00,0x00, /* 208 */
|
||||
0x32,0x4c,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x82,0x00,0x00, /* 209 */
|
||||
0x20,0x18,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 210 */
|
||||
0x08,0x30,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 211 */
|
||||
0x38,0x44,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 212 */
|
||||
0x32,0x4c,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 213 */
|
||||
0x6c,0x00,0x00,0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 214 */
|
||||
0x00,0x00,0x00,0x00,0x44,0x28,0x00,0x28,0x44,0x00,0x00,0x00, /* 215 */
|
||||
0x00,0x7a,0x84,0x82,0x8a,0x92,0xa2,0x82,0x42,0xbc,0x00,0x00, /* 216 */
|
||||
0x20,0x18,0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 217 */
|
||||
0x08,0x30,0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 218 */
|
||||
0x38,0x44,0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 219 */
|
||||
0x6c,0x00,0x00,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x00,0x00, /* 220 */
|
||||
0x08,0xb2,0x82,0x82,0x82,0x7c,0x00,0x10,0x10,0x10,0x00,0x00, /* 221 */
|
||||
0x00,0x80,0x80,0xbc,0x82,0x82,0x82,0xbc,0x80,0x80,0x00,0x00, /* 222 */
|
||||
0x00,0x3c,0x42,0x42,0x42,0x5c,0x42,0x42,0x42,0x9c,0x00,0x00, /* 223 */
|
||||
0x20,0x18,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 224 */
|
||||
0x08,0x30,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 225 */
|
||||
0x38,0x44,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 226 */
|
||||
0x32,0x4c,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 227 */
|
||||
0x6c,0x00,0x00,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 228 */
|
||||
0x18,0x24,0x18,0x00,0x3c,0x02,0x3a,0x42,0x42,0x3c,0x00,0x00, /* 229 */
|
||||
0x00,0x00,0x00,0x00,0x6c,0x12,0x52,0x94,0x90,0x6e,0x00,0x00, /* 230 */
|
||||
0x00,0x00,0x00,0x00,0x3c,0x40,0x40,0x40,0x40,0x34,0x08,0x10, /* 231 */
|
||||
0x20,0x18,0x00,0x00,0x3c,0x42,0x42,0x5c,0x40,0x3c,0x00,0x00, /* 232 */
|
||||
0x08,0x30,0x00,0x00,0x3c,0x42,0x42,0x5c,0x40,0x3c,0x00,0x00, /* 233 */
|
||||
0x38,0x44,0x00,0x00,0x3c,0x42,0x42,0x5c,0x40,0x3c,0x00,0x00, /* 234 */
|
||||
0x6c,0x00,0x00,0x00,0x3c,0x42,0x42,0x5c,0x40,0x3c,0x00,0x00, /* 235 */
|
||||
0x20,0x18,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 236 */
|
||||
0x08,0x30,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 237 */
|
||||
0x38,0x44,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 238 */
|
||||
0x6c,0x00,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, /* 239 */
|
||||
0x00,0x14,0x08,0x14,0x02,0x3a,0x42,0x42,0x42,0x3c,0x00,0x00, /* 240 */
|
||||
0x00,0x32,0x4c,0x00,0x3c,0x42,0x42,0x42,0x42,0x42,0x00,0x00, /* 241 */
|
||||
0x20,0x18,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 242 */
|
||||
0x08,0x30,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 243 */
|
||||
0x38,0x44,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 244 */
|
||||
0x32,0x4c,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 245 */
|
||||
0x6c,0x00,0x00,0x00,0x3c,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 246 */
|
||||
0x00,0x00,0x00,0x00,0x38,0x00,0xfe,0x00,0x38,0x00,0x00,0x00, /* 247 */
|
||||
0x00,0x00,0x00,0x00,0x3a,0x44,0x4a,0x52,0x22,0x5c,0x00,0x00, /* 248 */
|
||||
0x20,0x18,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 249 */
|
||||
0x08,0x30,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 250 */
|
||||
0x38,0x44,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 251 */
|
||||
0x6c,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3c,0x00,0x00, /* 252 */
|
||||
0x04,0x18,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x3a,0x02,0x3c, /* 253 */
|
||||
0x00,0x80,0x80,0x9c,0xa2,0x82,0xa2,0x9c,0x80,0x80,0x00,0x00, /* 254 */
|
||||
};
|
||||
static int radonFontMetaData[256*5]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,12,0,-2,12,8,12,0,-2,24,8,12,0,-2,36,8,12,0,-2,48,8,12,0,-2,60,8,12,0,-2,72,8,12,0,-2,84,8,12,0,-2,96,8,12,0,-2,108,8,12,0,-2,120,8,12,0,-2,132,8,12,0,-2,144,8,12,0,-2,156,8,12,0,-2,168,8,12,0,-2,180,8,12,0,-2,192,8,12,0,-2,204,8,12,0,-2,216,8,12,0,-2,228,8,12,0,-2,240,8,12,0,-2,252,8,12,0,-2,264,8,12,0,-2,276,8,12,0,-2,288,8,12,0,-2,300,8,12,0,-2,312,8,12,0,-2,324,8,12,0,-2,336,8,12,0,-2,348,8,12,0,-2,360,8,12,0,-2,372,8,12,0,-2,384,8,12,0,-2,396,8,12,0,-2,408,8,12,0,-2,420,8,12,0,-2,432,8,12,0,-2,444,8,12,0,-2,456,8,12,0,-2,468,8,12,0,-2,480,8,12,0,-2,492,8,12,0,-2,504,8,12,0,-2,516,8,12,0,-2,528,8,12,0,-2,540,8,12,0,-2,552,8,12,0,-2,564,8,12,0,-2,576,8,12,0,-2,588,8,12,0,-2,600,8,12,0,-2,612,8,12,0,-2,624,8,12,0,-2,636,8,12,0,-2,648,8,12,0,-2,660,8,12,0,-2,672,8,12,0,-2,684,8,12,0,-2,696,8,12,0,-2,708,8,12,0,-2,720,8,12,0,-2,732,8,12,0,-2,744,8,12,0,-2,756,8,12,0,-2,768,8,12,0,-2,780,8,12,0,-2,792,8,12,0,-2,804,8,12,0,-2,816,8,12,0,-2,828,8,12,0,-2,840,8,12,0,-2,852,8,12,0,-2,864,8,12,0,-2,876,8,12,0,-2,888,8,12,0,-2,900,8,12,0,-2,912,8,12,0,-2,924,8,12,0,-2,936,8,12,0,-2,948,8,12,0,-2,960,8,12,0,-2,972,8,12,0,-2,984,8,12,0,-2,996,8,12,0,-2,1008,8,12,0,-2,1020,8,12,0,-2,1032,8,12,0,-2,1044,8,12,0,-2,1056,8,12,0,-2,1068,8,12,0,-2,1080,8,12,0,-2,1092,8,12,0,-2,1104,8,12,0,-2,1116,8,12,0,-2,1128,8,12,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1140,8,12,0,-2,1152,8,12,0,-2,1164,8,12,0,-2,1176,8,12,0,-2,1188,8,12,0,-2,1200,8,12,0,-2,1212,8,12,0,-2,1224,8,12,0,-2,1236,8,12,0,-2,1248,8,12,0,-2,1260,8,12,0,-2,1272,8,12,0,-2,1284,8,12,0,-2,1296,8,12,0,-2,1308,8,12,0,-2,1320,8,12,0,-2,1332,8,12,0,-2,1344,8,12,0,-2,1356,8,12,0,-2,1368,8,12,0,-2,1380,8,12,0,-2,1392,8,12,0,-2,1404,8,12,0,-2,1416,8,12,0,-2,1428,8,12,0,-2,1440,8,12,0,-2,1452,8,12,0,-2,1464,8,12,0,-2,1476,8,12,0,-2,1488,8,12,0,-2,1500,8,12,0,-2,1512,8,12,0,-2,1524,8,12,0,-2,1536,8,12,0,-2,1548,8,12,0,-2,1560,8,12,0,-2,1572,8,12,0,-2,1584,8,12,0,-2,1596,8,12,0,-2,1608,8,12,0,-2,1620,8,12,0,-2,1632,8,12,0,-2,1644,8,12,0,-2,1656,8,12,0,-2,1668,8,12,0,-2,1680,8,12,0,-2,1692,8,12,0,-2,1704,8,12,0,-2,1716,8,12,0,-2,1728,8,12,0,-2,1740,8,12,0,-2,1752,8,12,0,-2,1764,8,12,0,-2,1776,8,12,0,-2,1788,8,12,0,-2,1800,8,12,0,-2,1812,8,12,0,-2,1824,8,12,0,-2,1836,8,12,0,-2,1848,8,12,0,-2,1860,8,12,0,-2,1872,8,12,0,-2,1884,8,12,0,-2,1896,8,12,0,-2,1908,8,12,0,-2,1920,8,12,0,-2,1932,8,12,0,-2,1944,8,12,0,-2,1956,8,12,0,-2,1968,8,12,0,-2,1980,8,12,0,-2,1992,8,12,0,-2,2004,8,12,0,-2,2016,8,12,0,-2,2028,8,12,0,-2,2040,8,12,0,-2,2052,8,12,0,-2,2064,8,12,0,-2,2076,8,12,0,-2,2088,8,12,0,-2,2100,8,12,0,-2,2112,8,12,0,-2,2124,8,12,0,-2,2136,8,12,0,-2,2148,8,12,0,-2,2160,8,12,0,-2,2172,8,12,0,-2,2184,8,12,0,-2,2196,8,12,0,-2,2208,8,12,0,-2,2220,8,12,0,-2,2232,8,12,0,-2,2244,8,12,0,-2,2256,8,12,0,-2,2268,8,12,0,-2,0,0,0,0,0,};
|
||||
static rfbFontData radonFont={radonFontData, radonFontMetaData};
|
||||
3
android/extern/libvncserver/examples/server/regiontest.c
vendored
Normal file
3
android/extern/libvncserver/examples/server/regiontest.c
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#define SRA_TEST
|
||||
#include "../libvncserver/rfbregion.c"
|
||||
|
||||
101
android/extern/libvncserver/examples/server/repeater.c
vendored
Normal file
101
android/extern/libvncserver/examples/server/repeater.c
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
This example shows how to connect to an UltraVNC repeater.
|
||||
|
||||
To get you started, you will need the actual repeater.
|
||||
Here's a non-exhaustive link list, some have install instructions,
|
||||
some don't:
|
||||
|
||||
* The official UltraVNC repeater for Windows: https://uvnc.com/downloads/repeater/83-repeater-downloads.html
|
||||
* The Linux port of the UltraVNC repeater, linked (but not made) by TurboVNC: https://turbovnc.org/Documentation/UltraVNCRepeater
|
||||
* An enhanced versions of x11vnc's Perl implementation: https://github.com/tomka/ultravnc-repeater
|
||||
|
||||
After installing and running, you simply connect this server example via
|
||||
`./repeater <id> <repeater-host> [<repeater-port>]`, where 'id' is a number.
|
||||
|
||||
For an UltraVNC repeater, the server will then show up in the
|
||||
"Waiting servers" list of the repeater's web interface.
|
||||
|
||||
To connect with say the example SDLvncviewer, run
|
||||
`./SDLvncviewer -repeaterdest ID:<id> <repeater-host>:[<repeater-port>]`
|
||||
where 'id' is the same number you used with the server example above.
|
||||
|
||||
If the ids match, the repeater will then forward packets in between
|
||||
the connected server and client. That's it!
|
||||
|
||||
*/
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
static void clientGone(rfbClientPtr cl)
|
||||
{
|
||||
rfbShutdownServer(cl->screen, TRUE);
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
char *repeaterHost;
|
||||
int repeaterPort, sock;
|
||||
char id[250];
|
||||
rfbClientPtr cl;
|
||||
|
||||
int i,j;
|
||||
uint16_t* f;
|
||||
|
||||
/* Parse command-line arguments */
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <id> <repeater-host> [<repeater-port>]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
memset(id, 0, sizeof(id));
|
||||
if(snprintf(id, sizeof(id), "ID:%s", argv[1]) >= (int)sizeof(id)) {
|
||||
/* truncated! */
|
||||
fprintf(stderr, "Error, given ID is too long.\n");
|
||||
return 1;
|
||||
}
|
||||
repeaterHost = argv[2];
|
||||
repeaterPort = argc < 4 ? 5500 : atoi(argv[3]);
|
||||
|
||||
/* The initialization is identical to simple15.c */
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,5,3,2);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->frameBuffer=(char*)malloc(400*300*2);
|
||||
if(!server->frameBuffer)
|
||||
return 1;
|
||||
f=(uint16_t*)server->frameBuffer;
|
||||
for(j=0;j<300;j++)
|
||||
for(i=0;i<400;i++)
|
||||
f[j*400+i]=/* red */ ((j*32/300) << 10) |
|
||||
/* green */ (((j+400-i)*32/700) << 5) |
|
||||
/* blue */ (i*32/400);
|
||||
|
||||
/* Now for the repeater-specific part: */
|
||||
server->port = -1; /* do not listen on any port */
|
||||
server->ipv6port = -1; /* do not listen on any port */
|
||||
|
||||
/* Make sure to call this _before_ connecting out to the repeater */
|
||||
rfbInitServer(server);
|
||||
|
||||
sock = rfbConnectToTcpAddr(repeaterHost, repeaterPort);
|
||||
if (sock == RFB_INVALID_SOCKET) {
|
||||
perror("connect to repeater");
|
||||
return 1;
|
||||
}
|
||||
if (send(sock, id, sizeof(id),0) != sizeof(id)) {
|
||||
perror("writing id");
|
||||
return 1;
|
||||
}
|
||||
cl = rfbNewClient(server, sock);
|
||||
if (!cl) {
|
||||
perror("new client");
|
||||
return 1;
|
||||
}
|
||||
cl->reverseConnection = 0;
|
||||
cl->clientGoneHook = clientGone;
|
||||
|
||||
/* Run the server */
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
85
android/extern/libvncserver/examples/server/rotate.c
vendored
Normal file
85
android/extern/libvncserver/examples/server/rotate.c
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
|
||||
#define CONCAT2(a,b) a##b
|
||||
#define CONCAT2E(a,b) CONCAT2(a,b)
|
||||
#define CONCAT3(a,b,c) a##b##c
|
||||
#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
|
||||
|
||||
#define FUNCNAME rfbRotate
|
||||
#define FUNC(i, j) (h - 1 - j + i * h)
|
||||
#define SWAPDIMENSIONS
|
||||
#define OUTBITS 8
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 16
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 32
|
||||
#include "rotatetemplate.c"
|
||||
#undef FUNCNAME
|
||||
#undef FUNC
|
||||
|
||||
#define FUNCNAME rfbRotateCounterClockwise
|
||||
#define FUNC(i, j) (j + (w - 1 - i) * h)
|
||||
#define OUTBITS 8
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 16
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 32
|
||||
#include "rotatetemplate.c"
|
||||
#undef FUNCNAME
|
||||
#undef FUNC
|
||||
#undef SWAPDIMENSIONS
|
||||
|
||||
#define FUNCNAME rfbFlipHorizontally
|
||||
#define FUNC(i, j) ((w - 1 - i) + j * w)
|
||||
#define OUTBITS 8
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 16
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 32
|
||||
#include "rotatetemplate.c"
|
||||
#undef FUNCNAME
|
||||
#undef FUNC
|
||||
|
||||
#define FUNCNAME rfbFlipVertically
|
||||
#define FUNC(i, j) (i + (h - 1 - j) * w)
|
||||
#define OUTBITS 8
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 16
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 32
|
||||
#include "rotatetemplate.c"
|
||||
#undef FUNCNAME
|
||||
#undef FUNC
|
||||
|
||||
#define FUNCNAME rfbRotateHundredAndEighty
|
||||
#define FUNC(i, j) ((w - 1 - i) + (h - 1 - j) * w)
|
||||
#define OUTBITS 8
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 16
|
||||
#include "rotatetemplate.c"
|
||||
#define OUTBITS 32
|
||||
#include "rotatetemplate.c"
|
||||
#undef FUNCNAME
|
||||
#undef FUNC
|
||||
|
||||
static void HandleKey(rfbBool down,rfbKeySym key,rfbClientPtr cl)
|
||||
{
|
||||
if(down) {
|
||||
if (key==XK_Escape || key=='q' || key=='Q')
|
||||
rfbCloseClient(cl);
|
||||
else if (key == 'r')
|
||||
rfbRotate(cl->screen);
|
||||
else if (key == 'R')
|
||||
rfbRotateCounterClockwise(cl->screen);
|
||||
else if (key == 'f')
|
||||
rfbFlipHorizontally(cl->screen);
|
||||
else if (key == 'F')
|
||||
rfbFlipVertically(cl->screen);
|
||||
}
|
||||
}
|
||||
|
||||
#define HAVE_HANDLEKEY
|
||||
#include "pnmshow.c"
|
||||
|
||||
53
android/extern/libvncserver/examples/server/rotatetemplate.c
vendored
Normal file
53
android/extern/libvncserver/examples/server/rotatetemplate.c
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
#define OUT_T CONCAT3E(uint,OUTBITS,_t)
|
||||
#define FUNCTION CONCAT2E(FUNCNAME,OUTBITS)
|
||||
|
||||
static void FUNCTION(rfbScreenInfoPtr screen)
|
||||
{
|
||||
OUT_T* buffer = (OUT_T*)screen->frameBuffer;
|
||||
int i, j, w = screen->width, h = screen->height;
|
||||
OUT_T* newBuffer = (OUT_T*)malloc(w * h * sizeof(OUT_T));
|
||||
if (!newBuffer) return;
|
||||
|
||||
for (j = 0; j < h; j++)
|
||||
for (i = 0; i < w; i++)
|
||||
newBuffer[FUNC(i, j)] = buffer[i + j * w];
|
||||
|
||||
memcpy(buffer, newBuffer, w * h * sizeof(OUT_T));
|
||||
free(newBuffer);
|
||||
|
||||
#ifdef SWAPDIMENSIONS
|
||||
screen->width = h;
|
||||
screen->paddedWidthInBytes = h * OUTBITS / 8;
|
||||
screen->height = w;
|
||||
|
||||
{
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
iterator = rfbGetClientIterator(screen);
|
||||
while ((cl = rfbClientIteratorNext(iterator)) != NULL)
|
||||
cl->newFBSizePending = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
rfbMarkRectAsModified(screen, 0, 0, screen->width, screen->height);
|
||||
}
|
||||
|
||||
#if OUTBITS == 32
|
||||
void FUNCNAME(rfbScreenInfoPtr screen) {
|
||||
if (screen->serverFormat.bitsPerPixel == 32)
|
||||
CONCAT2E(FUNCNAME,32)(screen);
|
||||
else if (screen->serverFormat.bitsPerPixel == 16)
|
||||
CONCAT2E(FUNCNAME,16)(screen);
|
||||
else if (screen->serverFormat.bitsPerPixel == 8)
|
||||
CONCAT2E(FUNCNAME,8)(screen);
|
||||
else {
|
||||
rfbErr("Unsupported pixel depth: %d\n",
|
||||
screen->serverFormat.bitsPerPixel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef FUNCTION
|
||||
#undef OUTBITS
|
||||
|
||||
12
android/extern/libvncserver/examples/server/simple.c
vendored
Normal file
12
android/extern/libvncserver/examples/server/simple.c
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,8,3,4);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->frameBuffer=(char*)malloc(400*300*4);
|
||||
rfbInitServer(server);
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
return(0);
|
||||
}
|
||||
27
android/extern/libvncserver/examples/server/simple15.c
vendored
Normal file
27
android/extern/libvncserver/examples/server/simple15.c
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/* This example shows how to use 15-bit (which is handled as 16-bit
|
||||
internally). */
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
int i,j;
|
||||
uint16_t* f;
|
||||
|
||||
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,5,3,2);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->frameBuffer=(char*)malloc(400*300*2);
|
||||
if(!server->frameBuffer)
|
||||
return 1;
|
||||
f=(uint16_t*)server->frameBuffer;
|
||||
for(j=0;j<300;j++)
|
||||
for(i=0;i<400;i++)
|
||||
f[j*400+i]=/* red */ ((j*32/300) << 10) |
|
||||
/* green */ (((j+400-i)*32/700) << 5) |
|
||||
/* blue */ (i*32/400);
|
||||
|
||||
rfbInitServer(server);
|
||||
rfbRunEventLoop(server,-1,FALSE);
|
||||
return(0);
|
||||
}
|
||||
54
android/extern/libvncserver/examples/server/storepasswd.c
vendored
Normal file
54
android/extern/libvncserver/examples/server/storepasswd.c
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||||
* Original Xvnc code 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
@example storepasswd.c
|
||||
storepasswd is the original program to save a vnc style password in a file.
|
||||
Unfortunately, authentication as every vncviewer speaks it means the server
|
||||
has to know the plain password. You really should tunnel via ssh or use
|
||||
your own PasswordCheck to build a PIN/TAN system.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("\nusage: storepasswd <password> <filename>\n\n");
|
||||
|
||||
printf("Stores a password in encrypted format.\n");
|
||||
printf("The resulting file can be used with the -rfbauth argument to OSXvnc.\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
usage();
|
||||
|
||||
if (rfbEncryptAndStorePasswd(argv[1], argv[2]) != 0) {
|
||||
printf("storing password failed.\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("storing password succeeded.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
140
android/extern/libvncserver/examples/server/vncev.c
vendored
Normal file
140
android/extern/libvncserver/examples/server/vncev.c
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @example vncev.c
|
||||
* This program is a simple server to show events coming from the client
|
||||
*/
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#include <rfb/rfbconfig.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#if LIBVNCSERVER_HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/default8x16.h>
|
||||
|
||||
#define width 100
|
||||
#define height 100
|
||||
static char f[width*height];
|
||||
static char* keys[0x400];
|
||||
|
||||
static int hex2number(unsigned char c)
|
||||
{
|
||||
if(c>'f') return(-1);
|
||||
else if(c>'F')
|
||||
return(10+c-'a');
|
||||
else if(c>'9')
|
||||
return(10+c-'A');
|
||||
else
|
||||
return(c-'0');
|
||||
}
|
||||
|
||||
static void read_keys(void)
|
||||
{
|
||||
int i,j,k;
|
||||
char buffer[1024];
|
||||
FILE* keysyms=fopen("keysym.h","r");
|
||||
|
||||
memset(keys,0,0x400*sizeof(char*));
|
||||
|
||||
if(!keysyms)
|
||||
return;
|
||||
|
||||
while(!feof(keysyms)) {
|
||||
fgets(buffer,1024,keysyms);
|
||||
if(!strncmp(buffer,"#define XK_",strlen("#define XK_"))) {
|
||||
for(i=strlen("#define XK_");buffer[i] && buffer[i]!=' '
|
||||
&& buffer[i]!='\t';i++);
|
||||
if(buffer[i]==0) /* don't support wrapped lines */
|
||||
continue;
|
||||
buffer[i]=0;
|
||||
for(i++;buffer[i] && buffer[i]!='0';i++);
|
||||
if(buffer[i]==0 || buffer[i+1]!='x') continue;
|
||||
for(j=0,i+=2;(k=hex2number(buffer[i]))>=0;i++)
|
||||
j=j*16+k;
|
||||
if(keys[j&0x3ff]) {
|
||||
char* x=(char*)malloc(1+strlen(keys[j&0x3ff])+1+strlen(buffer+strlen("#define ")));
|
||||
if(!x) {
|
||||
memset(keys,0,0x400*sizeof(char*));
|
||||
fclose(keysyms);
|
||||
return;
|
||||
}
|
||||
strcpy(x,keys[j&0x3ff]);
|
||||
strcat(x,",");
|
||||
strcat(x,buffer+strlen("#define "));
|
||||
free(keys[j&0x3ff]);
|
||||
keys[j&0x3ff]=x;
|
||||
} else
|
||||
keys[j&0x3ff] = strdup(buffer+strlen("#define "));
|
||||
}
|
||||
|
||||
}
|
||||
fclose(keysyms);
|
||||
}
|
||||
|
||||
static int lineHeight=16,lineY=height-16;
|
||||
static void output(rfbScreenInfoPtr s,char* line)
|
||||
{
|
||||
rfbDoCopyRect(s,0,0,width,height-lineHeight,0,-lineHeight);
|
||||
rfbDrawString(s,&default8x16Font,10,lineY,line,0x01);
|
||||
rfbLog("%s\n",line);
|
||||
}
|
||||
|
||||
static void dokey(rfbBool down,rfbKeySym k,rfbClientPtr cl)
|
||||
{
|
||||
char buffer[1024+32];
|
||||
|
||||
sprintf(buffer,"%s: %s (0x%x)",
|
||||
down?"down":"up",keys[k&0x3ff]?keys[k&0x3ff]:"",(unsigned int)k);
|
||||
output(cl->screen,buffer);
|
||||
}
|
||||
|
||||
static void doptr(int buttonMask,int x,int y,rfbClientPtr cl)
|
||||
{
|
||||
char buffer[1024];
|
||||
if(buttonMask) {
|
||||
sprintf(buffer,"Ptr: mouse button mask 0x%x at %d,%d",buttonMask,x,y);
|
||||
output(cl->screen,buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static enum rfbNewClientAction newclient(rfbClientPtr cl)
|
||||
{
|
||||
char buffer[1024];
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len=sizeof(addr);
|
||||
unsigned int ip;
|
||||
|
||||
getpeername(cl->sock,(struct sockaddr*)&addr,&len);
|
||||
ip=ntohl(addr.sin_addr.s_addr);
|
||||
sprintf(buffer,"Client connected from ip %d.%d.%d.%d",
|
||||
(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,ip&0xff);
|
||||
output(cl->screen,buffer);
|
||||
return RFB_CLIENT_ACCEPT;
|
||||
}
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
rfbScreenInfoPtr s=rfbGetScreen(&argc,argv,width,height,8,1,1);
|
||||
if(!s)
|
||||
return 1;
|
||||
s->colourMap.is16=FALSE;
|
||||
s->colourMap.count=2;
|
||||
s->colourMap.data.bytes=(unsigned char*)"\xd0\xd0\xd0\x30\x01\xe0";
|
||||
s->serverFormat.trueColour=FALSE;
|
||||
s->frameBuffer=f;
|
||||
s->kbdAddEvent=dokey;
|
||||
s->ptrAddEvent=doptr;
|
||||
s->newClientHook=newclient;
|
||||
|
||||
memset(f,0,width*height);
|
||||
read_keys();
|
||||
rfbInitServer(s);
|
||||
|
||||
while(1) {
|
||||
rfbProcessEvents(s,999999);
|
||||
}
|
||||
}
|
||||
180
android/extern/libvncserver/examples/server/x11.c
vendored
Normal file
180
android/extern/libvncserver/examples/server/x11.c
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
// Compile with LIBS := -lvncserver -lxcb -lxcb-xtest -lxcb-keysyms
|
||||
// Need CMake 3.24.0 to find these libraries. see https://cmake.org/cmake/help/v3.24/module/FindX11.html
|
||||
// XWayland not support to read screen, because wayland not allow it.
|
||||
// Read screen in wayland need use XDG desktop portals' interface `org.freedesktop.portal.Screenshot` and `org.freedesktop.portal.ScreenCast`
|
||||
// Under some environment, this code not work well, see https://github.com/LibVNC/libvncserver/pull/503#issuecomment-1064472566
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xtest.h>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
|
||||
void dirty_copy(rfbScreenInfoPtr rfbScreen, const uint8_t* data, int width, int height, int nbytes);
|
||||
void convert_bgrx_to_rgb(const uint8_t* in, uint16_t width, uint16_t height, uint8_t* buff);
|
||||
void get_window_size(xcb_connection_t* conn, xcb_window_t window, uint16_t* width, uint16_t* height);
|
||||
void get_window_image(xcb_connection_t* conn, xcb_window_t window, uint8_t* buff);
|
||||
void send_keycode(xcb_connection_t *conn, xcb_keycode_t keycode, int press);
|
||||
void send_keysym(xcb_connection_t *conn, xcb_keysym_t keysym, int press);
|
||||
void send_button(xcb_connection_t *conn, xcb_button_t button, int press);
|
||||
void send_motion(xcb_connection_t *conn, int16_t x, int16_t y);
|
||||
|
||||
// global
|
||||
xcb_connection_t* conn;
|
||||
|
||||
static void keyCallback(rfbBool down, rfbKeySym keySym, rfbClientPtr client)
|
||||
{
|
||||
(void)(client);
|
||||
send_keysym(conn, keySym, (int)down);
|
||||
}
|
||||
|
||||
#define VNC_BUTTON_MASK_LEFT rfbButton1Mask
|
||||
#define VNC_BUTTON_MASK_MIDDLE rfbButton2Mask
|
||||
#define VNC_BUTTON_MASK_RIGHT rfbButton3Mask
|
||||
#define VNC_BUTTON_MASK_UP rfbWheelUpMask
|
||||
#define VNC_BUTTON_MASK_DOWN rfbWheelDownMask
|
||||
|
||||
#define X11_BUTTON_LEFT XCB_BUTTON_INDEX_1
|
||||
#define X11_BUTTON_MIDDLE XCB_BUTTON_INDEX_2
|
||||
#define X11_BUTTON_RIGHT XCB_BUTTON_INDEX_3
|
||||
#define X11_BUTTON_UP XCB_BUTTON_INDEX_4
|
||||
#define X11_BUTTON_DOWN XCB_BUTTON_INDEX_5
|
||||
|
||||
static void mouseCallback(int buttonMask, int x, int y, rfbClientPtr client)
|
||||
{
|
||||
(void)(client);
|
||||
|
||||
send_button(conn, X11_BUTTON_LEFT, !!(buttonMask & VNC_BUTTON_MASK_LEFT));
|
||||
send_button(conn, X11_BUTTON_MIDDLE, !!(buttonMask & VNC_BUTTON_MASK_MIDDLE));
|
||||
send_button(conn, X11_BUTTON_RIGHT, !!(buttonMask & VNC_BUTTON_MASK_RIGHT));
|
||||
send_button(conn, X11_BUTTON_UP, !!(buttonMask & VNC_BUTTON_MASK_UP));
|
||||
send_button(conn, X11_BUTTON_DOWN, !!(buttonMask & VNC_BUTTON_MASK_DOWN));
|
||||
|
||||
send_motion(conn, (int16_t)x, (int16_t)y);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
conn = xcb_connect(NULL, NULL);
|
||||
const xcb_setup_t* setup = xcb_get_setup(conn);
|
||||
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
|
||||
xcb_screen_t* screen = iter.data;
|
||||
xcb_window_t root = screen->root;
|
||||
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
get_window_size(conn, root, &width, &height);
|
||||
void* frameBuffer = malloc(4UL * width * height);
|
||||
|
||||
rfbScreenInfoPtr rfbScreen = rfbGetScreen(&argc, argv, (int)width, (int)height, 8, 3, 4);
|
||||
rfbScreen->desktopName = "LibVNCServer X11 Example";
|
||||
rfbScreen->frameBuffer = (char*)malloc(4UL * width * height);
|
||||
rfbScreen->alwaysShared = TRUE;
|
||||
rfbScreen->kbdAddEvent = keyCallback;
|
||||
rfbScreen->ptrAddEvent = mouseCallback;
|
||||
rfbInitServer(rfbScreen);
|
||||
rfbRunEventLoop(rfbScreen, 10000, TRUE);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
get_window_image(conn, root, (uint8_t*)frameBuffer);
|
||||
dirty_copy(rfbScreen, (uint8_t*)frameBuffer, (int)width, (int)height, 4);
|
||||
}
|
||||
|
||||
free(rfbScreen->frameBuffer);
|
||||
free(frameBuffer);
|
||||
xcb_disconnect(conn);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void dirty_copy(rfbScreenInfoPtr rfbScreen, const uint8_t* data, int width, int height, int nbytes)
|
||||
{
|
||||
// check dirty by line, because it is convenient to copy
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
rfbBool dirty = FALSE;
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
const void* s1 = &rfbScreen->frameBuffer[(y*width+x)*nbytes];
|
||||
const void* s2 = &data[(y*width+x)*nbytes];
|
||||
if (memcmp(s1, s2, nbytes) != 0)
|
||||
{
|
||||
dirty = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
memcpy(&rfbScreen->frameBuffer[y*width*nbytes], &data[y*width*nbytes], width*nbytes);
|
||||
rfbMarkRectAsModified(rfbScreen, 0, y, width, y+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_bgrx_to_rgb(const uint8_t* in, uint16_t width, uint16_t height, uint8_t* buff)
|
||||
{
|
||||
for (uint16_t y = 0; y < height; y++)
|
||||
{
|
||||
for(uint16_t x = 0; x < width; x++)
|
||||
{
|
||||
buff[(y*width+x)*4] = in[(y*width+x)*4 + 2];
|
||||
buff[(y*width+x)*4 + 1] = in[(y*width+x)*4 + 1];
|
||||
buff[(y*width+x)*4 + 2] = in[(y*width+x)*4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_window_size(xcb_connection_t* conn, xcb_window_t window, uint16_t* width, uint16_t* height)
|
||||
{
|
||||
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, window);
|
||||
xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(conn, cookie, NULL);
|
||||
|
||||
*width = reply->width;
|
||||
*height = reply->height;
|
||||
free(reply);
|
||||
}
|
||||
|
||||
void get_window_image(xcb_connection_t* conn, xcb_window_t window, uint8_t* buff)
|
||||
{
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
get_window_size(conn, window, &width, &height);
|
||||
|
||||
// will failed in wayland, xcb_get_image_data will return NULL, convert_bgrx_to_rgb will abort
|
||||
xcb_get_image_cookie_t cookie = xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, window, 0, 0, width, height, UINT32_MAX);
|
||||
xcb_get_image_reply_t* reply = xcb_get_image_reply(conn, cookie, NULL);
|
||||
convert_bgrx_to_rgb(xcb_get_image_data(reply), width, height, buff);
|
||||
free(reply);
|
||||
}
|
||||
|
||||
|
||||
void send_keycode(xcb_connection_t *conn, xcb_keycode_t keycode, int press)
|
||||
{
|
||||
xcb_test_fake_input(conn, press ? XCB_KEY_PRESS : XCB_KEY_RELEASE, keycode, XCB_CURRENT_TIME, XCB_NONE, 0, 0, 0);
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
|
||||
void send_keysym(xcb_connection_t *conn, xcb_keysym_t keysym, int press)
|
||||
{
|
||||
xcb_key_symbols_t* symbols = xcb_key_symbols_alloc(conn);
|
||||
xcb_keycode_t* code = xcb_key_symbols_get_keycode(symbols, keysym);
|
||||
for (; code != NULL && *code != XCB_NO_SYMBOL; code++)
|
||||
{
|
||||
send_keycode(conn, *code, press);
|
||||
}
|
||||
xcb_key_symbols_free(symbols);
|
||||
}
|
||||
|
||||
void send_button(xcb_connection_t *conn, xcb_button_t button, int press)
|
||||
{
|
||||
xcb_test_fake_input(conn, press ? XCB_BUTTON_PRESS : XCB_BUTTON_RELEASE, button, XCB_CURRENT_TIME, XCB_NONE, 0, 0, 0);
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
void send_motion(xcb_connection_t *conn, int16_t x, int16_t y)
|
||||
{
|
||||
xcb_test_fake_input(conn, XCB_MOTION_NOTIFY, 0, XCB_CURRENT_TIME, XCB_NONE, x, y, 0);
|
||||
xcb_flush(conn);
|
||||
}
|
||||
183
android/extern/libvncserver/examples/server/zippy.c
vendored
Normal file
183
android/extern/libvncserver/examples/server/zippy.c
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <rfb/rfb.h>
|
||||
#include <rfb/keysym.h>
|
||||
#include <rfb/default8x16.h>
|
||||
|
||||
static int maxx=400, maxy=400, bpp=4;
|
||||
/* odd maxx doesn't work (vncviewer bug) */
|
||||
|
||||
/* Here we create a structure so that every client has its own pointer */
|
||||
|
||||
/* turns the framebuffer black */
|
||||
void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2);
|
||||
/* displays a red bar, a green bar, and a blue bar */
|
||||
void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2);
|
||||
void draw_primary_colours_generic(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2);
|
||||
void draw_primary_colours_generic_fast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2);
|
||||
void linecount (char* frame_buffer);
|
||||
/* handles mouse events */
|
||||
void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl);
|
||||
/* handles keyboard events */
|
||||
void on_key_press (rfbBool down,rfbKeySym key,rfbClientPtr cl);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
rfbScreenInfoPtr server;
|
||||
|
||||
if(!rfbProcessSizeArguments(&maxx,&maxy,&bpp,&argc,argv))
|
||||
return 1;
|
||||
|
||||
server = rfbGetScreen (&argc, argv, maxx, maxy, 8, 3, bpp);
|
||||
if(!server)
|
||||
return 1;
|
||||
server->desktopName = "Zippy das wundersquirrel\'s VNC server";
|
||||
server->frameBuffer = (char*)malloc(maxx*maxy*bpp);
|
||||
server->alwaysShared = TRUE;
|
||||
server->kbdAddEvent = on_key_press;
|
||||
server->ptrAddEvent = on_mouse_event;
|
||||
|
||||
rfbInitServer (server);
|
||||
|
||||
blank_framebuffer(server->frameBuffer, 0, 0, maxx, maxy);
|
||||
rfbRunEventLoop (server, -1, FALSE);
|
||||
free(server->frameBuffer);
|
||||
rfbScreenCleanup (server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < maxx * maxy * bpp; i++) frame_buffer[i]=(char) 0;
|
||||
}
|
||||
|
||||
void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int i, j, current_pixel;
|
||||
for (i=y1; i < y2; i++){
|
||||
for (j=x1; j < x2; j++) {
|
||||
current_pixel = (i*x2 + j) * bpp;
|
||||
if (i < y2 ) {
|
||||
frame_buffer[current_pixel+0] = (char) 128;
|
||||
frame_buffer[current_pixel+1] = (char) 0;
|
||||
frame_buffer[current_pixel+2] = (char) 0;
|
||||
}
|
||||
if (i < y2/3*2) {
|
||||
frame_buffer[current_pixel+0] = (char) 0;
|
||||
frame_buffer[current_pixel+1] = (char) 128;
|
||||
frame_buffer[current_pixel+2] = (char) 0;
|
||||
}
|
||||
if (i < y2/3) {
|
||||
frame_buffer[current_pixel+0] = (char) 0;
|
||||
frame_buffer[current_pixel+1] = (char) 0;
|
||||
frame_buffer[current_pixel+2] = (char) 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dscho's versions (slower, but works for bpp != 3 or 4) */
|
||||
void draw_primary_colours_generic(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
|
||||
{
|
||||
rfbPixelFormat f=s->serverFormat;
|
||||
int i,j;
|
||||
for(j=y1;j<y2;j++)
|
||||
for(i=x1;i<x2;i++)
|
||||
if(j<y1*2/3+y2/3)
|
||||
rfbDrawPixel(s,i,j,f.redMax<<f.redShift);
|
||||
else if(j<y1/3+y2*2/3)
|
||||
rfbDrawPixel(s,i,j,f.greenMax<<f.greenShift);
|
||||
else
|
||||
rfbDrawPixel(s,i,j,f.blueMax<<f.blueShift);
|
||||
}
|
||||
|
||||
void draw_primary_colours_generic_fast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
|
||||
{
|
||||
rfbPixelFormat f=s->serverFormat;
|
||||
int i,j,y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
|
||||
/* draw first pixel */
|
||||
rfbDrawPixel(s,x1,y1,f.redMax<<f.redShift);
|
||||
rfbDrawPixel(s,x1,y3,f.greenMax<<f.greenShift);
|
||||
rfbDrawPixel(s,x1,y4,f.blueMax<<f.blueShift);
|
||||
/* then copy stripes */
|
||||
for(j=0;j<y2-y4;j++)
|
||||
for(i=x1;i<x2;i++) {
|
||||
#define ADDR(x,y) s->frameBuffer+(x)*bpp+(y)*s->paddedWidthInBytes
|
||||
memcpy(ADDR(i,j+y1),ADDR(x1,y1),bpp);
|
||||
memcpy(ADDR(i,j+y3),ADDR(x1,y3),bpp);
|
||||
memcpy(ADDR(i,j+y4),ADDR(x1,y4),bpp);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_primary_colours_generic_ultrafast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
|
||||
{
|
||||
rfbPixelFormat f=s->serverFormat;
|
||||
int y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
|
||||
/* fill rectangles */
|
||||
rfbFillRect(s,x1,y1,x2,y3,f.redMax<<f.redShift);
|
||||
rfbFillRect(s,x1,y3,x2,y4,f.greenMax<<f.greenShift);
|
||||
rfbFillRect(s,x1,y4,x2,y2,f.blueMax<<f.blueShift);
|
||||
}
|
||||
|
||||
void linecount (char* frame_buffer)
|
||||
{
|
||||
int i,j,k, current_pixel;
|
||||
for (i=maxy-4; i>maxy-20; i-=4)
|
||||
for (j=0; j<4; j++) for (k=0; k < maxx; k++) {
|
||||
current_pixel = (i*j*maxx + k) * bpp;
|
||||
if (i%2 == 0) {
|
||||
frame_buffer[current_pixel+0] = (char) 0;
|
||||
frame_buffer[current_pixel+1] = (char) 0;
|
||||
frame_buffer[current_pixel+2] = (char) 128;
|
||||
}
|
||||
|
||||
if (i%2 == 1) {
|
||||
frame_buffer[current_pixel+0] = (char) 128;
|
||||
frame_buffer[current_pixel+1] = (char) 0;
|
||||
frame_buffer[current_pixel+2] = (char) 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void on_key_press (rfbBool down,rfbKeySym key,rfbClientPtr cl)
|
||||
{
|
||||
if (down) /* or else the action occurs on both the press and depress */
|
||||
switch (key) {
|
||||
|
||||
case XK_b:
|
||||
case XK_B:
|
||||
blank_framebuffer(cl->screen->frameBuffer, 0, 0, maxx, maxy);
|
||||
rfbDrawString(cl->screen,&default8x16Font,20,maxy-20,"Hello, World!",0xffffff);
|
||||
rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
|
||||
rfbLog("Framebuffer blanked\n");
|
||||
break;
|
||||
case XK_p:
|
||||
case XK_P:
|
||||
/* draw_primary_colors (cl->screen->frameBuffer, 0, 0, maxx, maxy); */
|
||||
draw_primary_colours_generic_ultrafast (cl->screen, 0, 0, maxx, maxy);
|
||||
rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
|
||||
rfbLog("Primary colors displayed\n");
|
||||
break;
|
||||
case XK_Q:
|
||||
case XK_q:
|
||||
rfbLog("Exiting now\n");
|
||||
exit(0);
|
||||
case XK_C:
|
||||
case XK_c:
|
||||
rfbDrawString(cl->screen,&default8x16Font,20,100,"Hello, World!",0xffffff);
|
||||
rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
|
||||
break;
|
||||
default:
|
||||
rfbLog("The %c key was pressed\n", (char) key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl)
|
||||
{
|
||||
printf("buttonMask: %i\n"
|
||||
"x: %i\n" "y: %i\n", buttonMask, x, y);
|
||||
}
|
||||
Reference in New Issue
Block a user