752 lines
23 KiB
C
Executable File
752 lines
23 KiB
C
Executable File
/*
|
|
* $Id$
|
|
*
|
|
* 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.
|
|
*
|
|
* This is a modification from letsgoustc source, to handle uinput events and more
|
|
*
|
|
*/
|
|
#include <dirent.h>
|
|
#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>
|
|
//android log
|
|
#include <android/log.h>
|
|
|
|
/* libvncserver */
|
|
#include "rfb/rfb.h"
|
|
#include "libvncserver/scale.h"
|
|
#include "rfb/keysym.h"
|
|
#include "suinput.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 BUS_VIRTUAL 0x06
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Android does not use /dev/fb0. */
|
|
#define FB_DEVICE "/dev/graphics/fb0"
|
|
static char VNC_PASSWORD[256] = "";
|
|
|
|
static struct fb_var_screeninfo scrinfo;
|
|
static struct fb_fix_screeninfo fscrinfo;
|
|
static int fbfd = -1;
|
|
static int inputfd = -1;
|
|
|
|
static unsigned int *fbmmap = MAP_FAILED;
|
|
static unsigned int *vncbuf;
|
|
static unsigned int *cmpbuf;
|
|
|
|
/* Android already has 5900 bound natively. */
|
|
#define VNC_PORT 5901
|
|
static rfbScreenInfoPtr vncscr;
|
|
|
|
int idle=0,standby=0,change=0;
|
|
static int rotation=0,scaling=0;
|
|
/*****************************************************************************/
|
|
|
|
static void (*update_screen)(void)=NULL;
|
|
static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl);
|
|
static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl);
|
|
static void rotate();
|
|
|
|
/*****************************************************************************/
|
|
|
|
void update_fb_info()
|
|
{
|
|
|
|
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &scrinfo) != 0)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","ioctl error\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
|
|
#define OUT 32
|
|
#include "update_screen.c"
|
|
#define OUT 8
|
|
#include "update_screen.c"
|
|
#define OUT 16
|
|
#include "update_screen.c"
|
|
|
|
static void init_fb(void)
|
|
{
|
|
size_t pixels;
|
|
size_t bytespp;
|
|
|
|
if ((fbfd = open(FB_DEVICE, O_RDWR)) == -1)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","cannot open fb device %s\n", FB_DEVICE);
|
|
return;
|
|
// exit(EXIT_FAILURE);
|
|
}
|
|
|
|
update_fb_info();
|
|
|
|
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &fscrinfo) != 0)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","ioctl error\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
pixels = scrinfo.xres * scrinfo.yres;
|
|
bytespp = scrinfo.bits_per_pixel /CHAR_BIT;
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC", "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);
|
|
|
|
// off_t o=0;
|
|
|
|
//now handled with double buffer detection
|
|
// if (scrinfo.xres==480 && scrinfo.yres==854 && scrinfo.xres_virtual==480
|
|
// && scrinfo.yres_virtual==854 && scrinfo.xoffset==448 && scrinfo.yoffset==1710)
|
|
/*if (scrinfo.bits_per_pixel==32)
|
|
// tweak for motorola droid
|
|
{
|
|
int off=scrinfo.xres*scrinfo.yres*scrinfo.bits_per_pixel/CHAR_BIT;
|
|
|
|
int resto= off % sysconf(_SC_PAGE_SIZE);
|
|
o= off / sysconf(_SC_PAGE_SIZE);
|
|
if (resto)
|
|
o+=1;
|
|
|
|
} */
|
|
|
|
// __android_log_print(ANDROID_LOG_INFO,"VNC","buffer offset=%d * %d\n",o,(int)sysconf(_SC_PAGE_SIZE));
|
|
//
|
|
// fbmmap = mmap(NULL, (scrinfo.xres_virtual*scrinfo.yres_virtual)* bytespp , PROT_READ|PROT_READ , MAP_PRIVATE , fbfd, o*sysconf(_SC_PAGE_SIZE));
|
|
fbmmap = mmap(NULL, (scrinfo.xres_virtual*scrinfo.yres_virtual)* bytespp , PROT_READ|PROT_READ , MAP_PRIVATE , fbfd, 0);
|
|
|
|
|
|
if (fbmmap == MAP_FAILED)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","mmap failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static void cleanup_fb(void)
|
|
{
|
|
if(fbfd != -1)
|
|
{
|
|
close(fbfd);
|
|
}
|
|
}
|
|
|
|
static void init_input()
|
|
{
|
|
struct input_id id = {
|
|
BUS_VIRTUAL, /* Bus type. */
|
|
1, /* Vendor id. */
|
|
1, /* Product id. */
|
|
1 /* Version id. */
|
|
};
|
|
|
|
if((inputfd = suinput_open("qwerty", &id)) == -1)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","cannot create virtual kbd device.\n");
|
|
// exit(EXIT_FAILURE); do not exit, so we still can see the framebuffer
|
|
}
|
|
}
|
|
|
|
static void cleanup_kbd()
|
|
{
|
|
if(inputfd != -1)
|
|
{
|
|
suinput_close(inputfd);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static rfbNewClientHookPtr clientHook(rfbClientPtr cl)
|
|
{
|
|
if (scaling!=0 && scaling!=100)
|
|
{
|
|
rfbScalingSetup(cl, vncscr->width*scaling/100.0, vncscr->height*scaling/100.0);
|
|
|
|
}
|
|
|
|
return RFB_CLIENT_ACCEPT;
|
|
}
|
|
|
|
|
|
static void init_fb_server(int argc, char **argv)
|
|
{
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Initializing server...\n");
|
|
|
|
vncbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
cmpbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
|
|
assert(vncbuf != NULL);
|
|
assert(cmpbuf != NULL);
|
|
|
|
|
|
|
|
if (rotation==0 || rotation==180)
|
|
vncscr = rfbGetScreen(&argc, argv, scrinfo.xres, scrinfo.yres, 0 /* not used */ , 3, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
else
|
|
vncscr = rfbGetScreen(&argc, argv, scrinfo.yres, scrinfo.xres, 0 /* not used */ , 3, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
|
|
assert(vncscr != NULL);
|
|
|
|
vncscr->desktopName = "Android";
|
|
vncscr->frameBuffer =(char *)vncbuf;
|
|
vncscr->port = VNC_PORT;
|
|
|
|
vncscr->kbdAddEvent = keyevent;
|
|
vncscr->ptrAddEvent = ptrevent;
|
|
vncscr->newClientHook = clientHook;
|
|
|
|
if (strcmp(VNC_PASSWORD,"")!=0)
|
|
{
|
|
char **passwords = (char **)malloc(2 * sizeof(char **));
|
|
passwords[0] = VNC_PASSWORD;
|
|
passwords[1] = NULL;
|
|
vncscr->authPasswdData = passwords;
|
|
vncscr->passwordCheck = rfbCheckPasswordByList;
|
|
}
|
|
|
|
#ifdef DONATE_VERSION
|
|
vncscr->httpDir="/data/data/org.onaips.vnc_donate/";
|
|
#else
|
|
vncscr->httpDir="/data/data/org.onaips.vnc/";
|
|
#endif
|
|
vncscr->serverFormat.redShift=scrinfo.red.offset;
|
|
vncscr->serverFormat.greenShift=scrinfo.green.offset;
|
|
vncscr->serverFormat.blueShift=scrinfo.blue.offset;
|
|
|
|
vncscr->serverFormat.redMax=((1<<scrinfo.red.length)-1);
|
|
vncscr->serverFormat.greenMax=((1<<scrinfo.green.length)-1);
|
|
vncscr->serverFormat.blueMax=((1<<scrinfo.blue.length)-1);
|
|
|
|
vncscr->alwaysShared = TRUE;
|
|
vncscr->handleEventsEagerly = TRUE;
|
|
vncscr->deferUpdateTime = 5;
|
|
|
|
rfbInitServer(vncscr);
|
|
|
|
//assign update_screen depending on bpp
|
|
if (vncscr->serverFormat.bitsPerPixel == 32)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","I'm on update_screen_32");
|
|
update_screen=&CONCAT2E(update_screen_,32);
|
|
}
|
|
else if (vncscr->serverFormat.bitsPerPixel == 16)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","I'm on update_screen_16");
|
|
update_screen=&CONCAT2E(update_screen_,16);
|
|
}
|
|
else if (vncscr->serverFormat.bitsPerPixel == 8)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","I'm on update_screen_8");
|
|
update_screen=&CONCAT2E(update_screen_,8);
|
|
}
|
|
else {
|
|
rfbErr("Unsupported pixel depth: %d\n",
|
|
vncscr->serverFormat.bitsPerPixel);
|
|
return;
|
|
}
|
|
|
|
|
|
/* Mark as dirty since we haven't sent any updates at all yet. */
|
|
|
|
rfbMarkRectAsModified(vncscr, 0, 0, scrinfo.xres, scrinfo.yres);
|
|
rfbProcessEvents(vncscr, 100000);
|
|
|
|
}
|
|
|
|
static int keysym2scancode(rfbBool down, rfbKeySym c, rfbClientPtr cl, int *sh, int *alt);
|
|
|
|
|
|
static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
|
|
{
|
|
int code;
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Got keysym: %04x (down=%d)\n", (unsigned int)key, (int)down);
|
|
|
|
int sh = 0;
|
|
int alt = 0;
|
|
|
|
if ((code = keysym2scancode(down, key, cl,&sh,&alt)))
|
|
{
|
|
|
|
int ret;
|
|
|
|
if (key && down)
|
|
{
|
|
if (sh) suinput_press(inputfd, 42); //left shift
|
|
if (alt) suinput_press(inputfd, 56); //left alt
|
|
|
|
ret=suinput_press(inputfd,code);
|
|
ret=suinput_release(inputfd,code);
|
|
|
|
if (alt) suinput_release(inputfd, 56); //left alt
|
|
if (sh) suinput_release(inputfd, 42); //left shift
|
|
}
|
|
else
|
|
;//ret=suinput_release(inputfd,code);
|
|
|
|
//__android_log_print(ANDROID_LOG_INFO,"VNC","injectKey (%d, %d) ret=%d\n", code , down,ret);
|
|
}
|
|
}
|
|
|
|
// keyboard code modified from remote input by http://www.math.bme.hu/~morap/RemoteInput/
|
|
|
|
// q,w,e,r,t,y,u,i,o,p,a,s,d,f,g,h,j,k,l,z,x,c,v,b,n,m
|
|
int qwerty[] = {30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,16,19,31,20,22,47,17,45,21,44};
|
|
// ,!,",#,$,%,&,',(,),*,+,,,-,.,/
|
|
int spec1[] = {57,2,40,4,5,6,8,40,10,11,9,13,51,12,52,52};
|
|
int spec1sh[] = {0,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1};
|
|
// :,;,<,=,>,?,@
|
|
int spec2[] = {39,39,227,13,228,53,215};
|
|
int spec2sh[] = {1,0,1,1,1,1,0};
|
|
// [,\,],^,_,`
|
|
int spec3[] = {26,43,27,7,12,399};
|
|
int spec3sh[] = {0,0,0,1,1,0};
|
|
// {,|,},~
|
|
int spec4[] = {26,43,27,215,14};
|
|
int spec4sh[] = {1,1,1,1,0};
|
|
|
|
static int keysym2scancode(rfbBool down, rfbKeySym c, rfbClientPtr cl, int *sh, int *alt)
|
|
{
|
|
int real=1;
|
|
if ('a' <= c && c <= 'z')
|
|
return qwerty[c-'a'];
|
|
if ('A' <= c && c <= 'Z')
|
|
{
|
|
(*sh)=1;
|
|
return qwerty[c-'A'];
|
|
}
|
|
if ('1' <= c && c <= '9')
|
|
return c-'1'+2;
|
|
if (c == '0')
|
|
return 11;
|
|
if (32 <= c && c <= 47)
|
|
{
|
|
(*sh) = spec1sh[c-32];
|
|
return spec1[c-32];
|
|
}
|
|
if (58 <= c && c <= 64)
|
|
{
|
|
(*sh) = spec2sh[c-58];
|
|
return spec2[c-58];
|
|
}
|
|
if (91 <= c && c <= 96)
|
|
{
|
|
(*sh) = spec3sh[c-91];
|
|
return spec3[c-91];
|
|
}
|
|
if (123 <= c && c <= 127)
|
|
{
|
|
(*sh) = spec4sh[c-123];
|
|
return spec4[c-123];
|
|
}
|
|
switch(c)
|
|
{
|
|
case 0xff08: return 14;// backspace
|
|
case 0xff09: return 15;// tab
|
|
case 1: (*alt)=1; return 34;// ctrl+a
|
|
case 3: (*alt)=1; return 46;// ctrl+c
|
|
case 4: (*alt)=1; return 32;// ctrl+d
|
|
case 18: (*alt)=1; return 31;// ctrl+r
|
|
case 0xff0D: return 28;// enter
|
|
case 0xff1B: return 158;// esc -> back
|
|
case 0xFF51: return 105;// left -> DPAD_LEFT
|
|
case 0xFF53: return 106;// right -> DPAD_RIGHT
|
|
case 0xFF54: return 108;// down -> DPAD_DOWN
|
|
case 0xFF52: return 103;// up -> DPAD_UP
|
|
// case 360: return 232;// end -> DPAD_CENTER (ball click)
|
|
case 0xff50: return KEY_HOME;// home
|
|
case 0xFFC8: rfbShutdownServer(cl->screen,TRUE); return 0; //F11 disconnect
|
|
case 0xFFC9:
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","F12 closing...");
|
|
exit(0); //F10 closes daemon
|
|
break;
|
|
case 0xffc1: down?rotate():0; return 0; // F4 rotate
|
|
case 0xffff: return 158;// del -> back
|
|
case 0xff55: return 229;// PgUp -> menu
|
|
case 0xffcf: return 127;// F2 -> search
|
|
case 0xff56: return 61;// PgUp -> call
|
|
case 0xff57: return 107;// End -> endcall
|
|
case 0xffc2: return 211;// F5 -> focus
|
|
case 0xffc3: return 212;// F6 -> camera
|
|
case 0xffc4: return 150;// F7 -> explorer
|
|
case 0xffc5: return 155;// F8 -> envelope
|
|
|
|
case 50081:
|
|
case 225: (*alt)=1;
|
|
if (real) return 48; //a with acute
|
|
return 30; //a with acute -> a with ring above
|
|
case 50049:
|
|
case 193:(*sh)=1; (*alt)=1;
|
|
if (real) return 48; //A with acute
|
|
return 30; //A with acute -> a with ring above
|
|
case 50089:
|
|
case 233: (*alt)=1; return 18; //e with acute
|
|
case 50057:
|
|
case 201:(*sh)=1; (*alt)=1; return 18; //E with acute
|
|
case 50093:
|
|
case 0xffbf: (*alt)=1;
|
|
if (real) return 36; //i with acute
|
|
return 23; //i with acute -> i with grave
|
|
case 50061:
|
|
case 205: (*sh)=1; (*alt)=1;
|
|
if (real) return 36; //I with acute
|
|
return 23; //I with acute -> i with grave
|
|
case 50099:
|
|
case 243:(*alt)=1;
|
|
if (real) return 16; //o with acute
|
|
return 24; //o with acute -> o with grave
|
|
case 50067:
|
|
case 211:(*sh)=1; (*alt)=1;
|
|
if (real) return 16; //O with acute
|
|
return 24; //O with acute -> o with grave
|
|
case 50102:
|
|
case 246: (*alt)=1; return 25; //o with diaeresis
|
|
case 50070:
|
|
case 214: (*sh)=1; (*alt)=1; return 25; //O with diaeresis
|
|
case 50577:
|
|
case 245:(*alt)=1;
|
|
if (real) return 19; //Hungarian o
|
|
return 25; //Hungarian o -> o with diaeresis
|
|
case 50576:
|
|
case 213: (*sh)=1; (*alt)=1;
|
|
if (real) return 19; //Hungarian O
|
|
return 25; //Hungarian O -> O with diaeresis
|
|
case 50106:
|
|
// case 0xffbe: (*alt)=1;
|
|
// if (real) return 17; //u with acute
|
|
// return 22; //u with acute -> u with grave
|
|
case 50074:
|
|
case 218: (*sh)=1; (*alt)=1;
|
|
if (real) return 17; //U with acute
|
|
return 22; //U with acute -> u with grave
|
|
case 50108:
|
|
case 252: (*alt)=1; return 47; //u with diaeresis
|
|
case 50076:
|
|
case 220:(*sh)=1; (*alt)=1; return 47; //U with diaeresis
|
|
case 50609:
|
|
case 251: (*alt)=1;
|
|
if (real) return 45; //Hungarian u
|
|
return 47; //Hungarian u -> u with diaeresis
|
|
case 50608:
|
|
case 219: (*sh)=1; (*alt)=1;
|
|
if (real) return 45; //Hungarian U
|
|
return 47; //Hungarian U -> U with diaeresis
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// old key code, i'll need it for some missing things
|
|
/*
|
|
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_SOFT1, KEY_SOFT2, 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 0x0003: scancode = KEY_CENTER; break;
|
|
case 0x0020: scancode = KEY_SPACE; break;
|
|
case 0x0023: scancode = KEY_SHARP; break;
|
|
case 0x0033: scancode = KEY_SHARP; 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 0xFE51: scancode = 399; break;
|
|
case 0x002A: scancode = KEY_STAR; break;
|
|
case 0xFFBE: scancode = KEY_F1; break; // F1
|
|
case 0xFFBF: scancode = KEY_F2; break; // F2
|
|
case 0xFFC0: scancode = KEY_F3; break; // F3
|
|
case 0xFFC1: down?rotate():0; break; // F4 rotate
|
|
case 0xFFC5: scancode = KEY_F4; break; // F8
|
|
case 0xFFC8: rfbShutdownServer(cl->screen,TRUE); break; // F11
|
|
}
|
|
}
|
|
|
|
return scancode;
|
|
}
|
|
*/
|
|
|
|
|
|
inline void transform_touch_coordinates(int *x, int *y)
|
|
{
|
|
int scale=4096.0;
|
|
int old_x=*x,old_y=*y;
|
|
|
|
if (rotation==0)
|
|
{
|
|
*x = old_x*scale/scrinfo.xres-scale/2.0;
|
|
*y = old_y*scale/scrinfo.yres-scale/2.0;
|
|
}
|
|
else if (rotation==90)
|
|
{
|
|
*x =old_y*scale/scrinfo.xres-scale/2.0;
|
|
*y = (scrinfo.yres - old_x)*scale/scrinfo.yres-scale/2.0;
|
|
}
|
|
else if (rotation==180)
|
|
{
|
|
*x =(scrinfo.xres - old_x)*scale/scrinfo.xres-scale/2.0;
|
|
*y =(scrinfo.yres - old_y)*scale/scrinfo.yres-scale/2.0;
|
|
}
|
|
else if (rotation==270)
|
|
{
|
|
*y =old_x*scale/scrinfo.yres-scale/2.0;
|
|
*x =(scrinfo.xres - old_y)*scale/scrinfo.xres-scale/2.0;
|
|
}
|
|
|
|
}
|
|
|
|
static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl)
|
|
{
|
|
static int leftClicked=0,rightClicked=0,middleClicked=0;
|
|
|
|
transform_touch_coordinates(&x,&y);
|
|
|
|
if((buttonMask & 1)&& leftClicked) {//left btn clicked and moving
|
|
static int i=0;
|
|
i=i+1;
|
|
|
|
if (i%10==1)//some tweak to not report every move event
|
|
{
|
|
suinput_write(inputfd, EV_ABS, ABS_X, x);
|
|
suinput_write(inputfd, EV_ABS, ABS_Y, y);
|
|
suinput_write(inputfd, EV_SYN, SYN_REPORT, 0);
|
|
}
|
|
}
|
|
else if (buttonMask & 1)//left btn clicked
|
|
{
|
|
leftClicked=1;
|
|
|
|
suinput_write(inputfd, EV_ABS, ABS_X, x);
|
|
suinput_write(inputfd, EV_ABS, ABS_Y, y);
|
|
suinput_write(inputfd,EV_KEY,BTN_TOUCH,1);
|
|
suinput_write(inputfd, EV_SYN, SYN_REPORT, 0);
|
|
|
|
|
|
}
|
|
else if (leftClicked)//left btn released
|
|
{
|
|
leftClicked=0;
|
|
suinput_write(inputfd, EV_ABS, ABS_X, x);
|
|
suinput_write(inputfd, EV_ABS, ABS_Y, y);
|
|
suinput_write(inputfd,EV_KEY,BTN_TOUCH,0);
|
|
suinput_write(inputfd, EV_SYN, SYN_REPORT, 0);
|
|
}
|
|
|
|
if (buttonMask & 4)//right btn clicked
|
|
{
|
|
rightClicked=1;
|
|
suinput_press(inputfd,158); //back key
|
|
}
|
|
else if (rightClicked)//right button released
|
|
{
|
|
rightClicked=0;
|
|
suinput_release(inputfd,158);
|
|
}
|
|
|
|
if (buttonMask & 2)//mid btn clicked
|
|
{
|
|
middleClicked=1;
|
|
suinput_press( inputfd,KEY_END);
|
|
}
|
|
else if (middleClicked)// mid btn released
|
|
{
|
|
middleClicked=0;
|
|
suinput_release( inputfd,KEY_END);
|
|
}
|
|
}
|
|
|
|
void sigproc()
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Cleaning up...\n");
|
|
cleanup_fb();
|
|
cleanup_kbd();
|
|
exit(0); /* normal exit status */
|
|
}
|
|
|
|
|
|
|
|
static void rotate()
|
|
{
|
|
rotation+=90;
|
|
rotation=rotation%360;
|
|
|
|
|
|
if (rotation==90 || rotation==270)
|
|
rfbNewFramebuffer(vncscr,(char*)vncbuf, scrinfo.yres, scrinfo.xres,0 /* not used */ , 3, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
else
|
|
rfbNewFramebuffer(vncscr,(char*)vncbuf, scrinfo.xres, scrinfo.yres,0 /* not used */ , 3, scrinfo.bits_per_pixel/CHAR_BIT);
|
|
|
|
vncscr->serverFormat.redShift=scrinfo.red.offset;
|
|
vncscr->serverFormat.greenShift=scrinfo.green.offset;
|
|
vncscr->serverFormat.blueShift=scrinfo.blue.offset;
|
|
|
|
vncscr->serverFormat.redMax=((1<<scrinfo.red.length)-1);
|
|
vncscr->serverFormat.greenMax=((1<<scrinfo.green.length)-1);
|
|
vncscr->serverFormat.blueMax=((1<<scrinfo.blue.length)-1);
|
|
|
|
rfbMarkRectAsModified(vncscr, 0, 0, vncscr->width, vncscr->height);
|
|
|
|
}
|
|
|
|
void print_usage(char **argv)
|
|
{
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","androidvncserver [-p password] [-h]\n"
|
|
"-p password: Password to access server\n"
|
|
"-r rotation: Screen rotation (degrees) (0,90,180,270)\n"
|
|
"-s screen scale: percentage (20,30,50,100,150)\n"
|
|
"-h : print this help\n");
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
signal(SIGINT, sigproc);//pipe signals
|
|
signal(SIGKILL, sigproc);
|
|
signal(SIGILL, sigproc);
|
|
|
|
if(argc > 1)
|
|
{
|
|
int i=1;
|
|
int r;
|
|
while(i < argc)
|
|
{
|
|
if(*argv[i] == '-')
|
|
{
|
|
switch(*(argv[i] + 1))
|
|
{
|
|
case 'h':
|
|
print_usage(argv);
|
|
exit(0);
|
|
break;
|
|
case 'p':
|
|
i++;
|
|
strcpy(VNC_PASSWORD,argv[i]);
|
|
break;
|
|
case 'r':
|
|
i++;
|
|
r=atoi(argv[i]);
|
|
if (r==0 || r==90 || r==180 || r==270)
|
|
rotation=r;
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","rotating to %d degrees\n",rotation);
|
|
break;
|
|
case 's':
|
|
i++;
|
|
r=atoi(argv[i]);
|
|
if (r>=1 && r <= 150)
|
|
scaling=r;
|
|
else
|
|
scaling=100;
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","scaling to %d percent\n",scaling);
|
|
break;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Initializing framebuffer device " FB_DEVICE "...\n");
|
|
init_fb();
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Initializing virtual keyboard and touch device...\n");
|
|
init_input();
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Initializing VNC server:\n");
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC"," width: %d\n", (int)scrinfo.xres);
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC"," height: %d\n", (int)scrinfo.yres);
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC"," bpp: %d\n", (int)scrinfo.bits_per_pixel);
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC"," port: %d\n", (int)VNC_PORT);
|
|
init_fb_server(argc, argv);
|
|
|
|
while (1)
|
|
{
|
|
|
|
while (vncscr->clientHead == NULL)
|
|
rfbProcessEvents(vncscr, 100000);
|
|
|
|
update_screen();
|
|
}
|
|
|
|
__android_log_print(ANDROID_LOG_INFO,"VNC","Cleaning up...\n");
|
|
cleanup_fb();
|
|
cleanup_kbd();
|
|
}
|