00001
00007 #include "fbvncserver.h"
00008
00009 #include <sys/ioctl.h>
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <sys/time.h>
00013
00014 #include <fcntl.h>
00015 #include <linux/fb.h>
00016 #include <signal.h>
00017
00018
00019 #include "keysym2scancode.h"
00020
00021
00022 struct ClientData {
00023 rfbBool oldButton;
00024 int oldx,oldy;
00025 };
00026
00027 typedef struct {
00028 long x;
00029 long y;
00030 long pressure;
00031 } ARTIFICIAL_TS_EVENT;
00032
00033
00034 static int last_pen_down = 0;
00035
00036 struct kbd_layout_t *kbd_layout = NULL;
00037 struct fb_var_screeninfo vscrinfo;
00038
00039 unsigned short int
00040 *fbbuf = NULL,
00041 *cmpfbbuf = NULL,
00042 *rfbbuf = NULL;
00043
00047 void emit_scancode (unsigned int s, rfbBool down) {
00049 unsigned short keycode = s;
00050
00051 if (uinput_fd_kbd && uinput) {
00052 TRACE3("emitting keycode ... %d (%#x) [down: %d] \n", keycode, keycode, down);
00053 dev_uinput_key(uinput_fd_kbd,keycode,down);
00054 } else {
00055 TRACE2(" [W]: unable to emit keycode - uinput not ready ... (uinput: %d, fd: %d)", uinput, uinput_fd_kbd);
00056 }
00057 }
00058
00059
00071 int emit_touchscreen_sequence(ARTIFICIAL_TS_EVENT *s) {
00072 int fd;
00073 int ret;
00074 ret = 0;
00075
00076 if((fd=open("/dev/tssim",O_WRONLY))>=0) {
00077 while(s->x!=-1) {
00078 write(fd,s,sizeof(ARTIFICIAL_TS_EVENT));
00079 s++;
00080 }
00081 close(fd);
00082 } else {
00083 fprintf(stderr, " unable to open /dev/tssim for write-only access \n");
00084 ret=-1;
00085 }
00086 return(ret);
00087 }
00088
00092 void ptrevent( int buttonMask, int x, int y, rfbClientPtr cl)
00093 {
00094
00095 ARTIFICIAL_TS_EVENT touchscreen_sequence[5];
00096 int i, buffer = 0;
00097 if ((x < 0 ) ||
00098 (y < 0 ) ||
00099 (x > cl -> screen -> width) ||
00100 (y > cl -> screen -> height)) {
00101 TRACE4(" [W] ptrevent() - invalid ts event (x: %d, y: %d [%3d,%3d]) \n",
00102 cl -> screen -> width,
00103 cl -> screen -> height,
00104 x,y);
00105 return;
00106 };
00107
00108 switch (rotate) {
00109 case 0: break;
00110 case 1: break;
00111 case 2: break;
00112 case 3:
00113 buffer = x;
00114 x = -y + (cl -> screen -> height);
00115 y = buffer;
00116 break;
00117 default: ;
00118 }
00119
00120 if(buttonMask!=0) {
00121 for(i=0;i<(last_pen_down?1:5);i++) {
00122 touchscreen_sequence[i].x=x;
00123 touchscreen_sequence[i].y=y;
00124 touchscreen_sequence[i].pressure=1;
00125 }
00126 touchscreen_sequence[i].x=-1;
00127 rfbLog ( " pointer event @ x: %d, y:%d (down) \n", x, y);
00128 if (uinput_fd_mouse && uinput) {
00129 ptr_abs(uinput_fd_mouse,x,y);
00130 button_click(uinput_fd_mouse,1);
00131 dev_uinput_sync(uinput_fd_mouse);
00132 rfbLog (" => sent to uinput. \n");
00133
00134 } else {
00135 emit_touchscreen_sequence(touchscreen_sequence);
00136 };
00137 } else {
00138 if(last_pen_down) {
00139 touchscreen_sequence[0].x=x;
00140 touchscreen_sequence[0].y=y;
00141 touchscreen_sequence[0].pressure=0;
00142 touchscreen_sequence[1].x=-1;
00143
00144 rfbLog (" pointer event @ x: %d, y:%d (up) \n", x, y);
00145 if (uinput_fd_mouse && uinput) {
00146 ptr_abs(uinput_fd_mouse,x,y);
00147 button_click(uinput_fd_mouse,0);
00148 dev_uinput_sync(uinput_fd_mouse);
00149 rfbLog (" => sent to uinput. \n");
00150
00151 } else {
00152 emit_touchscreen_sequence(touchscreen_sequence);
00153 };
00154 };
00155 };
00156 last_pen_down=(buttonMask!=0);
00157 return;
00158 }
00159
00160
00164 void keyevent(rfbBool down,rfbKeySym key,rfbClientPtr cl)
00165 {
00166 unsigned int scancode;
00167
00168 scancode = keysym2scancode(kbd_layout, key);
00169 TRACE2 (" [I]: KeyEvent: Key %#x - %d \n",key,down);
00170 TRACE1 (" => Scancode: %#x \n",scancode);
00171 emit_scancode(scancode, down);
00172 return;
00173 }
00174
00178 void clientleft(rfbClientPtr cl) { free(cl->clientData); }
00179
00183 static enum rfbNewClientAction newclient(rfbClientPtr cl) {
00184 cl->clientData = (void*)calloc(sizeof(struct ClientData),1);
00185 cl->clientGoneHook = clientleft;
00186
00187 return RFB_CLIENT_ACCEPT;
00188 }
00189 static int getFileTransferPermission (rfbClientPtr cl) { return TRUE; }
00193
00194 void print_usage(char *arg0) {
00195 printf("Usage: %s [options] \n", arg0);
00196 #ifdef DEBUG
00197 printf(" -debug\n");
00198 #endif
00199 printf("\n");
00200 printf(" -cw rotate 90 \n");
00201 printf(" -cw -cw rotate 180 \n");
00202 printf(" -cw -cw -cw | -ccw rotate 270 \n");
00203 printf("\n");
00204 printf(" -keymap <map> name of the keymap to be used for event \n");
00205 printf(" translation (default: %s) \n", DEFAULT_KBD_LAYOUT);
00206 printf("\n");
00207 printf("# *** \n");
00208 printf("# * libVNCServer options (excerpt) \n");
00209 printf("# **** \n");
00210 printf(" -rfbport port TCP port for RFB protocol\n");
00211 printf(" -rfbwait time max time in ms to wait for RFB client\n");
00212 printf(" -rfbauth passwd-file use authentication on RFB protocol\n");
00213 printf(" (use 'storepasswd' to create a password file)\n");
00214
00215 #ifndef HAVE_STRUCT_RFBSCREEN_PERMITFILETRANSFER
00216
00218 #endif
00219 printf(" -passwd plain-password use authentication\n");
00220 printf(" (use plain-password as password, USE AT YOUR RISK)\n");
00221 printf(" -deferupdate time time in ms to defer updates (default 40)\n");
00222 printf(" -deferptrupdate time time in ms to defer pointer updates (default none)\n");
00223
00224
00225
00226
00227
00228
00229
00230
00231 printf(" -progressive height enable progressive updating for slow links\n");
00232 printf("\n");
00233 #ifndef HAVE_STRUCT_RFBSCREEN_PERMITFILETRANSFER
00234 printf(" -disablefiletransfer disable file transfer (tight)\n");
00235 printf(" -ftproot string set ftp root (tight)\n");
00236 printf("\n");
00237 #endif
00238 printf("# *** \n");
00239 printf("# * additional info (build option(s) used) \n");
00240 printf("# **** \n");
00241 #ifndef DEBUG
00242 printf(" [I]: release build (-debug not supported)\n");
00243 #endif
00244 #ifdef HTTP
00245 printf(" [I]: http connections to port 5800 supported\n");
00246 #else
00247 printf(" [I]: http connections NOT supported \n");
00248 #endif
00249
00250 #ifndef HAVE_STRUCT_RFBSCREEN_PERMITFILETRANSFER
00251 printf(" [I]: ultra-file transfer NOT supported \n");
00252 #else
00253 printf(" [I]: ultra-file transfer supported \n");
00254 #endif
00255
00256 #ifndef HAVE_RFBREGISTERTIGHTVNCFILETRANSFEREXTENSION
00257 printf(" [I]: tight-file transfer NOT supported \n ");
00258 #else
00259 printf(" [I]: tight-file transfer supported \n ");
00260 #endif
00261 printf("\n");
00262 }
00263
00264
00265
00266
00267 int main(int argc,char **argv) {
00268 int
00269 i,fbfd;
00270
00271 rfbScreenInfoPtr
00272 rfbScreen;
00273
00274 unsigned long int
00275 compareBufferSize = 0,
00276 remoteBufferSize = 0,
00277 bytesPerPixel = 0;
00278
00279 char
00280 keyboard_layout[10] = DEFAULT_KBD_LAYOUT;
00281
00282 div_t
00283 divresult;
00284
00285 printf("%s (%s %s) \n",PACKAGE_STRING,__DATE__, __TIME__ );
00288
00289 for(i=1;i<argc;i++) {
00290 if ( !strcmp(argv[i],"-h")
00291 || !strcmp(argv[i],"-help")
00292 || !strcmp(argv[i],"--help")
00293 || !strcmp(argv[i],"-?") ) {
00294 print_usage(argv[0]);
00295 exit(1);
00296 } else if(!strcmp(argv[i],"-debug")) debug = 1;
00297 else if(!strcmp(argv[i],"-keymap")) {
00298 if (argc > i++) {
00299 if ( strlen(argv[i]) < sizeof(keyboard_layout) ) {
00300 strcpy(&keyboard_layout[0], argv[i]);
00301 } else {
00302 printf(" [W] invalid argument for -keymap: %s => I will use [%s] \n",argv[i], keyboard_layout[0]);
00303 }
00304 }
00305 }
00306 else if(!strcmp(argv[i],"-ccw")) rotate = 3;
00307 else if(!strcmp(argv[i],"-cw")) {
00308 if (++rotate > 3) {
00309 fprintf(stderr," [F]: only 0,90,180 & 270 rotations are supported\n");
00310 fprintf(stderr," => 0 will be used. \n ");
00311 rotate = 0;
00312 }
00313 }
00314 }
00315
00316 #ifdef DEBUG
00317 if (debug) rfbLogEnable(1);
00318 else rfbLogEnable(0);
00319 #else
00320 rfbLogEnable(0);
00321 #endif
00322
00323
00324 TRACE(" [I]: open framebuffer (/dev/fb0) ... \n");
00325
00326 if((fbfd=open("/dev/fb0",O_RDONLY))<0) {
00327 perror("Opening /dev/fb0");
00328 return(-1);
00329 }
00330
00331 TRACE(" [I]: requesting fb info via ioctl ...\n");
00332
00333
00334 if (ioctl(fbfd,FBIOGET_VSCREENINFO,&vscrinfo) <0 ) {
00335 close(fbfd);
00336 perror("ioctl(FBIOGET_VSCREENINFO)");
00337 return(-1);
00338 }
00339
00340 TRACE1(" visible resolution [x]: %d px \n", vscrinfo.xres );
00341 TRACE1(" [y]: %d px \n", vscrinfo.yres );
00342 TRACE1(" virtual resolution [x]: %d px \n", vscrinfo.xres_virtual);
00343 TRACE1(" [y]: %d px \n", vscrinfo.yres_virtual);
00344 TRACE (" offset from virtual to visible resolution \n");
00345 TRACE1(" [x]: %d px \n", vscrinfo.xoffset);
00346 TRACE1(" [y]: %d px \n", vscrinfo.yoffset);
00347 TRACE1(" grayscale (0 = false) : %d \n", vscrinfo.grayscale);
00348 TRACE1(" bits per pixel : %d \n", vscrinfo.bits_per_pixel);
00349 if (!vscrinfo.grayscale) {
00350 TRACE2 (" color offsets red : %2d length : %d \n", vscrinfo.red.offset, vscrinfo.red.length);
00351 TRACE2 (" green : %2d length : %d \n", vscrinfo.green.offset, vscrinfo.green.length);
00352 TRACE2 (" blue : %2d length : %d \n", vscrinfo.blue.offset, vscrinfo.blue.length);
00353 }
00354 if (!vscrinfo.nonstd) {
00355 TRACE (" standard pixel format \n");
00356 } else {
00357 TRACE (" [W]: using non standard pixel format \n");
00358 };
00359
00360 if (vscrinfo.height > 0) TRACE1 (" height of picture : %d mm\n", vscrinfo.height);
00361 if (vscrinfo.width > 0) TRACE1 (" width : %d mm\n", vscrinfo.width);
00362
00363
00364 if ((rotate == 1) ||
00365 (rotate == 3)) {
00366 vscrinfo.xres = vscrinfo.xres + vscrinfo.yres;
00367 vscrinfo.yres = vscrinfo.xres - vscrinfo.yres;
00368 vscrinfo.xres = vscrinfo.xres - vscrinfo.yres;
00369 TRACE (" [I]: swap'ed width vs. height to adjust dimensions \n");
00370 };
00371
00372
00373 divresult = div(vscrinfo.bits_per_pixel,8);
00374
00375 if (divresult.rem != 0) bytesPerPixel = divresult.quot + 1;
00376 else bytesPerPixel = divresult.quot;
00377
00378 compareBufferSize = vscrinfo.xres * vscrinfo.yres * bytesPerPixel;
00379 TRACE2(" [I]: %d bytes per pixel => I will allocate %d bytes \n", bytesPerPixel, compareBufferSize);
00380 TRACE (" [I]: allocate memory for compare-buffer ... \n");
00381
00382 if((cmpfbbuf=(unsigned short int *)malloc(compareBufferSize)) == NULL) {
00383 close(fbfd);
00384 perror("malloc");
00385 return(-1);
00386 }
00387 memset(cmpfbbuf,0x00,compareBufferSize);
00388
00389
00390 TRACE (" [I]: allocate and initialize the remote framebuffer ... \n");
00391
00392 remoteBufferSize = vscrinfo.xres * vscrinfo.yres * bytesPerPixel;
00393 if((rfbbuf=(unsigned short int *)malloc(remoteBufferSize))==NULL) {
00394 close(fbfd);
00395 free(cmpfbbuf);
00396 perror("malloc");
00397 return(-1);
00398 }
00399
00400 TRACE (" [I]: mapping fb to memory ... \n");
00401 if((fbbuf=(unsigned short int *)mmap(0,
00402 compareBufferSize,
00403 PROT_READ,
00404 MAP_SHARED,
00405 fbfd,
00406 0)
00407
00408
00409
00410
00411 ) <0
00412 ) {
00413 close(fbfd);
00414 free(cmpfbbuf);
00415 free(rfbbuf);
00416 perror("mmap");
00417 return(-1);
00418 }
00419
00420
00421
00422
00423 if (uinput) {
00424 TRACE (" [I]: check if we have uinput device nodes ... \n");
00425 uinput_fd_kbd = dev_uinput_init_kbd(UINPUT_KBD_NAME);
00426 uinput_fd_mouse = dev_uinput_init_mouse(UINPUT_TS_NAME);
00427
00428 if ((uinput_fd_kbd > 0) &
00429 (uinput_fd_mouse > 0)) {
00430 TRACE1(" => Keyboard OK (fd=%d). \n",uinput_fd_kbd);
00431 TRACE1(" => Mouse OK (fd=%d). \n",uinput_fd_mouse);
00432
00433 kbd_layout = init_keyboard_layout(keyboard_layout);
00434 if (kbd_layout) {
00435 TRACE1(" [I]: keyboard [%s] loaded \n", keyboard_layout);
00436 } else {
00437 TRACE1(" [W]: keyboard layout [%s] NOT loaded \n", keyboard_layout);
00438 dev_uinput_close(uinput_fd_kbd);
00439 uinput_fd_kbd = 0;
00440 TRACE (" [W]: ... => keyboard event source released. \n")
00441 }
00442 } else {
00443 uinput = 0;
00444 TRACE(" [W]: => unable to initialize uinput \n ");
00445 }
00446 }
00447
00448
00449
00450
00451 rfbScreen = rfbGetScreen(&argc,
00452 argv,
00453 vscrinfo.xres,
00454 vscrinfo.yres,
00455 5,
00456 2,
00457 bytesPerPixel);
00458
00459 #ifdef HAVE_RFBSETPROTOCOLVERSION
00460 #ifdef HAVE_STRUCT_RFBSCREEN_PERMITFILETRANSFER
00461
00462
00463
00464
00465
00466
00467
00468
00469 rfbSetProtocolVersion(rfbScreen, 3, 6);
00470 #endif
00471 #endif
00472
00473 rfbScreen -> desktopName = DESKTOP_NAME;
00474 rfbScreen -> frameBuffer = (char *)rfbbuf;
00475 rfbScreen -> alwaysShared = TRUE;
00476 rfbScreen -> serverFormat.bitsPerPixel = vscrinfo.bits_per_pixel;
00477
00478
00479 rfbScreen -> ptrAddEvent = ptrevent;
00480 rfbScreen -> kbdAddEvent = keyevent;
00481 rfbScreen -> newClientHook = newclient;
00482
00483 #ifdef HAVE_STRUCT_RFBSCREEN_GETFILETRANSFERPERMISSION
00484 rfbScreen -> getFileTransferPermission = getFileTransferPermission;
00485 #endif
00486 #ifdef HAVE_STRUCT_RFBSCREEN_PERMITFILETRANSFER
00487 rfbScreen -> permitFileTransfer = TRUE;
00488 #endif
00489 #ifdef HAVE_RFBREGISTERTIGHTVNCFILETRANSFEREXTENSION
00490 rfbRegisterTightVNCFileTransferExtension();
00491 #endif
00492
00493 rfbScreen -> ignoreSIGPIPE = TRUE;
00494
00495
00496
00497 rfbScreen -> progressiveSliceHeight = 0;
00498
00499 if (!vscrinfo.grayscale) {
00500 rfbScreen -> serverFormat.redMax = pow(2,vscrinfo.red.length) -1;
00501 rfbScreen -> serverFormat.greenMax = pow(2,vscrinfo.green.length)-1;
00502 rfbScreen -> serverFormat.blueMax = pow(2,vscrinfo.blue.length) -1;
00503 rfbScreen -> serverFormat.redShift = vscrinfo.red.offset;
00504 rfbScreen -> serverFormat.greenShift = vscrinfo.green.offset;
00505 rfbScreen -> serverFormat.blueShift = vscrinfo.blue.offset;
00506
00507 }
00508 #ifdef HTTP
00509 rfbScreen->httpDir = HTTP;
00510 #endif
00511
00512 rfbInitServer(rfbScreen);
00513 rfbRunEventLoop(rfbScreen,-1,TRUE);
00514
00515 while (1) {
00516 if (rfbScreen -> clientHead != NULL) {
00517 if (notEqual(fbbuf,cmpfbbuf,compareBufferSize) == 1) {
00518 if (rotate == 0) { rotate0 (rfbScreen,fbbuf,cmpfbbuf); };
00519 if (rotate == 1) { rotate90 (rfbScreen,fbbuf,cmpfbbuf); };
00520 if (rotate == 2) { rotate180(rfbScreen,fbbuf,cmpfbbuf); };
00521 if (rotate == 3) { rotate270(rfbScreen,fbbuf,cmpfbbuf); };
00522 usleep(5000);
00523 } else {
00524 usleep(50000);
00525 };
00526 } else {
00527 sleep(1);
00528 };
00529 };
00530
00531 rfbScreenCleanup(rfbScreen);
00532
00533 free(fbbuf);
00534 free(cmpfbbuf);
00535
00536 if (uinput_fd_kbd) dev_uinput_close(uinput_fd_kbd);
00537 if (uinput_fd_mouse) dev_uinput_close(uinput_fd_mouse);
00538
00539 exit (0);
00540 }