1 #include <stdarg.h> 2 #include <rfb/keysym.h> 3 #include "VNConsole.h" 4 5 #define DEBUG(x) 6 7 unsigned char colourMap16[16*3]={ 8 /* 0 black #000000 */ 0x00,0x00,0x00, 9 /* 1 maroon #800000 */ 0x80,0x00,0x00, 10 /* 2 green #008000 */ 0x00,0x80,0x00, 11 /* 3 khaki #808000 */ 0x80,0x80,0x00, 12 /* 4 navy #000080 */ 0x00,0x00,0x80, 13 /* 5 purple #800080 */ 0x80,0x00,0x80, 14 /* 6 aqua-green #008080 */ 0x00,0x80,0x80, 15 /* 7 light grey #c0c0c0 */ 0xc0,0xc0,0xc0, 16 /* 8 dark grey #808080 */ 0x80,0x80,0x80, 17 /* 9 red #ff0000 */ 0xff,0x00,0x00, 18 /* a light green #00ff00 */ 0x00,0xff,0x00, 19 /* b yellow #ffff00 */ 0xff,0xff,0x00, 20 /* c blue #0000ff */ 0x00,0x00,0xff, 21 /* d pink #ff00ff */ 0xff,0x00,0xff, 22 /* e light blue #00ffff */ 0x00,0xff,0xff, 23 /* f white #ffffff */ 0xff,0xff,0xff 24 }; 25 26 void MakeColourMap16(vncConsolePtr c) 27 { 28 rfbColourMap* colourMap=&(c->screen->colourMap); 29 if(colourMap->count) 30 free(colourMap->data.bytes); 31 colourMap->data.bytes=malloc(16*3); 32 memcpy(colourMap->data.bytes,colourMap16,16*3); 33 colourMap->count=16; 34 colourMap->is16=FALSE; 35 c->screen->serverFormat.trueColour=FALSE; 36 } 37 38 void vcDrawOrHideCursor(vncConsolePtr c) 39 { 40 int i,j,w=c->screen->paddedWidthInBytes; 41 char *b=c->screen->frameBuffer+c->y*c->cHeight*w+c->x*c->cWidth; 42 for(j=c->cy1;j<c->cy2;j++) 43 for(i=c->cx1;i<c->cx2;i++) 44 b[j*w+i]^=0x0f; 45 rfbMarkRectAsModified(c->screen, 46 c->x*c->cWidth+c->cx1,c->y*c->cHeight+c->cy1, 47 c->x*c->cWidth+c->cx2,c->y*c->cHeight+c->cy2); 48 c->cursorIsDrawn=c->cursorIsDrawn?FALSE:TRUE; 49 } 50 51 void vcDrawCursor(vncConsolePtr c) 52 { 53 if(c->cursorActive && c->y<c->height && c->x<c->width) { 54 /* rfbLog("DrawCursor: %d,%d\n",c->x,c->y); */ 55 vcDrawOrHideCursor(c); 56 } 57 } 58 59 void vcHideCursor(vncConsolePtr c) 60 { 61 if(c->currentlyMarking) 62 vcUnmark(c); 63 vcDrawOrHideCursor(c); 64 } 65 66 void vcMakeSureCursorIsDrawn(rfbClientPtr cl) 67 { 68 vncConsolePtr c=(vncConsolePtr)cl->screen->screenData; 69 if(!c->dontDrawCursor) 70 vcDrawCursor(c); 71 } 72 73 vncConsolePtr vcGetConsole(int *argc,char **argv, 74 int width,int height,rfbFontDataPtr font 75 #ifdef USE_ATTRIBUTE_BUFFER 76 ,rfbBool withAttributes 77 #endif 78 ) 79 { 80 vncConsolePtr c=(vncConsolePtr)malloc(sizeof(vncConsole)); 81 82 c->font=font; 83 c->width=width; 84 c->height=height; 85 c->screenBuffer=(char*)malloc(width*height); 86 memset(c->screenBuffer,' ',width*height); 87 #ifdef USE_ATTRIBUTE_BUFFER 88 if(withAttributes) { 89 c->attributeBuffer=(char*)malloc(width*height); 90 memset(c->attributeBuffer,0x07,width*height); 91 } else 92 c->attributeBuffer=NULL; 93 #endif 94 c->x=0; 95 c->y=0; 96 c->wrapBottomToTop=FALSE; 97 c->cursorActive=TRUE; 98 c->cursorIsDrawn=FALSE; 99 c->dontDrawCursor=FALSE; 100 c->inputBuffer=(char*)malloc(1024); 101 c->inputSize=1024; 102 c->inputCount=0; 103 c->selection=0; 104 c->selectTimeOut=40000; /* 40 ms */ 105 c->doEcho=TRUE; 106 107 c->wasRightButtonDown=FALSE; 108 c->currentlyMarking=FALSE; 109 110 rfbWholeFontBBox(font,&c->xhot,&c->cHeight,&c->cWidth,&c->yhot); 111 c->cWidth-=c->xhot; 112 c->cHeight=-c->cHeight-c->yhot; 113 114 /* text cursor */ 115 c->cx1=c->cWidth/8; 116 c->cx2=c->cWidth*7/8; 117 c->cy2=c->cHeight-1-c->yhot+c->cHeight/16; 118 if(c->cy2>=c->cHeight) 119 c->cy2=c->cHeight-1; 120 c->cy1=c->cy2-c->cHeight/8; 121 if(c->cy1<0) 122 c->cy2=0; 123 124 if(!(c->screen = rfbGetScreen(argc,argv,c->cWidth*c->width,c->cHeight*c->height,8,1,1))) 125 return NULL; 126 c->screen->screenData=(void*)c; 127 c->screen->displayHook=vcMakeSureCursorIsDrawn; 128 c->screen->frameBuffer= 129 (char*)malloc(c->screen->width*c->screen->height); 130 memset(c->screen->frameBuffer,c->backColour, 131 c->screen->width*c->screen->height); 132 c->screen->kbdAddEvent=vcKbdAddEventProc; 133 c->screen->ptrAddEvent=vcPtrAddEventProc; 134 c->screen->setXCutText=vcSetXCutTextProc; 135 136 MakeColourMap16(c); 137 c->foreColour=0x7; 138 c->backColour=0; 139 140 rfbInitServer(c->screen); 141 142 return(c); 143 } 144 145 #include <rfb/rfbregion.h> 146 147 /* before using this function, hide the cursor */ 148 void vcScroll(vncConsolePtr c,int lineCount) 149 { 150 int y1,y2; 151 rfbScreenInfoPtr s=c->screen; 152 153 if(lineCount==0) 154 return; 155 156 /* rfbLog("begin scroll\n"); */ 157 vcHideCursor(c); 158 c->dontDrawCursor=TRUE; 159 160 if(lineCount>=c->height || lineCount<=-c->height) { 161 y1=0; y2=s->height; 162 } else if(lineCount>0) { 163 y1=s->height-lineCount*c->cHeight; y2=s->height; 164 rfbDoCopyRect(s,0,0,s->width,y1,0,-lineCount*c->cHeight); 165 memmove(c->screenBuffer, 166 c->screenBuffer+(c->height-lineCount)*c->width, 167 (c->height-lineCount)*c->width); 168 #ifdef USE_ATTRIBUTE_BUFFER 169 if(c->attributeBuffer) 170 memmove(c->attributeBuffer, 171 c->attributeBuffer+(c->height-lineCount)*c->width, 172 (c->height-lineCount)*c->width); 173 #endif 174 } else { 175 y1=0; y2=-lineCount*c->cHeight; 176 rfbDoCopyRect(s,0,y2,s->width,s->height,0,-lineCount*c->cHeight); 177 memmove(c->screenBuffer-lineCount*c->width, 178 c->screenBuffer, 179 (c->height+lineCount)*c->width); 180 #ifdef USE_ATTRIBUTE_BUFFER 181 if(c->attributeBuffer) 182 memmove(c->attributeBuffer-lineCount*c->width, 183 c->attributeBuffer, 184 (c->height+lineCount)*c->width); 185 #endif 186 } 187 188 c->dontDrawCursor=FALSE; 189 memset(s->frameBuffer+y1*s->width,c->backColour,(y2-y1)*s->width); 190 rfbMarkRectAsModified(s,0,y1-c->cHeight,s->width,y2); 191 memset(c->screenBuffer+y1/c->cHeight*c->width,' ', 192 (y2-y1)/c->cHeight*c->width); 193 #ifdef USE_ATTRIBUTE_BUFFER 194 if(c->attributeBuffer) 195 memset(c->attributeBuffer+y1/c->cHeight*c->width,0x07, 196 (y2-y1)/c->cHeight*c->width); 197 #endif 198 /* rfbLog("end scroll\n"); */ 199 } 200 201 void vcCheckCoordinates(vncConsolePtr c) 202 { 203 if(c->x>=c->width) { 204 c->x=0; 205 c->y++; 206 } 207 if(c->y>=c->height) { 208 if(c->wrapBottomToTop) 209 c->y=0; 210 else { 211 vcScroll(c,c->y+1-c->height); 212 c->y=c->height-1; 213 } 214 } 215 } 216 217 void vcPutChar(vncConsolePtr c,unsigned char ch) 218 { 219 #ifdef USE_ATTRIBUTE_BUFFER 220 if(c->attributeBuffer) { 221 unsigned char colour=c->attributeBuffer[c->x+c->y*c->width]; 222 vcPutCharColour(c,ch,colour&0x7,colour>>4); 223 } else 224 #endif 225 vcPutCharColour(c,ch,c->foreColour,c->backColour); 226 } 227 228 void vcPutCharColour(vncConsolePtr c,unsigned char ch,unsigned char foreColour,unsigned char backColour) 229 { 230 rfbScreenInfoPtr s=c->screen; 231 int j,x,y; 232 233 vcHideCursor(c); 234 if(ch<' ') { 235 switch(ch) { 236 case 7: 237 case 13: 238 break; 239 case 8: /* BackSpace */ 240 if(c->x>0) { 241 c->x--; 242 vcPutChar(c,' '); 243 c->x--; 244 } 245 break; 246 case 10: /* return */ 247 c->x=0; 248 c->y++; 249 vcCheckCoordinates(c); 250 break; 251 case 9: /* tabulator */ 252 do { 253 vcPutChar(c,' '); 254 } while(c->x%8); 255 break; 256 default: 257 rfbLog("putchar of unknown character: %c(%d).\n",ch,ch); 258 vcPutChar(c,' '); 259 } 260 } else { 261 #ifdef USE_ATTRIBUTE_BUFFER 262 if(c->attributeBuffer) 263 c->attributeBuffer[c->x+c->y*c->width]=foreColour|(backColour<<4); 264 #endif 265 x=c->x*c->cWidth; 266 y=c->y*c->cHeight; 267 for(j=y+c->cHeight-1;j>=y;j--) 268 memset(s->frameBuffer+j*s->width+x,backColour,c->cWidth); 269 rfbDrawChar(s,c->font, 270 x-c->xhot+(c->cWidth-rfbWidthOfChar(c->font,ch))/2, 271 y+c->cHeight-c->yhot-1, 272 ch,foreColour); 273 c->screenBuffer[c->y*c->width+c->x]=ch; 274 c->x++; 275 rfbMarkRectAsModified(s,x,y-c->cHeight+1,x+c->cWidth,y+c->cHeight+1); 276 vcCheckCoordinates(c); 277 } 278 } 279 280 void vcPrint(vncConsolePtr c,unsigned char* str) 281 { 282 while(*str) { 283 vcPutChar(c,*str); 284 str++; 285 } 286 } 287 288 void vcPrintColour(vncConsolePtr c,unsigned char* str,unsigned char foreColour,unsigned char backColour) 289 { 290 while(*str) { 291 vcPutCharColour(c,*str,foreColour,backColour); 292 str++; 293 } 294 } 295 296 void vcPrintF(vncConsolePtr c,char* format,...) 297 { 298 va_list args; 299 char buf[4096]; 300 va_start(args, format); 301 vsprintf(buf, format, args); 302 vcPrint(c,(unsigned char*)buf); 303 va_end(args); 304 } 305 306 void vcPrintFColour(vncConsolePtr c,unsigned char foreColour,unsigned char backColour,char* format,...) 307 { 308 va_list args; 309 char buf[4096]; 310 va_start(args, format); 311 vsprintf(buf, format, args); 312 vcPrintColour(c,(unsigned char*)buf,foreColour,backColour); 313 va_end(args); 314 } 315 316 char vcGetCh(vncConsolePtr c) 317 { 318 if(c->inputCount>0) { 319 char ch; 320 ch=c->inputBuffer[0]; 321 c->inputCount--; 322 if(c->inputCount>0) 323 memmove(c->inputBuffer,c->inputBuffer+1,c->inputCount); 324 return(ch); 325 } else 326 return(0); 327 } 328 329 char vcGetChar(vncConsolePtr c) 330 { 331 while(rfbIsActive(c->screen) && c->inputCount==0) 332 vcProcessEvents(c); 333 return(vcGetCh(c)); 334 } 335 336 char *vcGetString(vncConsolePtr c,char *buffer,int bufferSize) 337 { 338 char *bufferBackup=c->inputBuffer; 339 int i,count=bufferSize-1; 340 341 if(count>c->inputCount) 342 count=c->inputCount; 343 for(i=1;i<count && bufferBackup[i-1]!='\n';i++); 344 if(i<count || i==bufferSize-1) { 345 memcpy(buffer,bufferBackup,i); 346 buffer[i+1]=0; 347 c->inputCount-=i; 348 memmove(bufferBackup,bufferBackup+i+2,c->inputCount); 349 return(buffer); 350 } 351 memcpy(buffer,bufferBackup,c->inputCount); 352 count=c->inputSize; 353 c->inputSize=bufferSize; 354 c->inputBuffer=buffer; 355 while(rfbIsActive(c->screen) 356 && c->inputCount<bufferSize-1 && buffer[c->inputCount-1]!='\n') 357 vcProcessEvents(c); 358 buffer[c->inputCount]=0; 359 c->inputBuffer=bufferBackup; 360 c->inputSize=count; 361 c->inputCount=0; 362 return(buffer); 363 } 364 365 void vcKbdAddEventProc(rfbBool down,rfbKeySym keySym,rfbClientPtr cl) 366 { 367 vncConsolePtr c=(vncConsolePtr)cl->screen->screenData; 368 if(down) { 369 if(c->inputCount<c->inputSize) { 370 if(keySym<0 || keySym>0xff) { 371 if(keySym==XK_Return) keySym='\n'; 372 else if(keySym==XK_BackSpace) keySym=8; 373 else if(keySym==XK_Tab) keySym=9; 374 else keySym=0; 375 } 376 if(keySym>0) { 377 if(keySym==8) { 378 if(c->inputCount>0) 379 c->inputCount--; 380 } else 381 c->inputBuffer[c->inputCount++]=(char)keySym; 382 if(c->doEcho) 383 vcPutChar(c,(unsigned char)keySym); 384 } 385 } 386 } 387 } 388 389 void vcPtrAddEventProc(int buttonMask,int x,int y,rfbClientPtr cl) 390 { 391 vncConsolePtr c=(vncConsolePtr)cl->screen->screenData; 392 393 if(c->wasRightButtonDown) { 394 if((buttonMask&4)==0) { 395 if(c->selection) { 396 char* s; 397 for(s=c->selection;*s;s++) { 398 c->screen->kbdAddEvent(1,*s,cl); 399 c->screen->kbdAddEvent(0,*s,cl); 400 } 401 } 402 c->wasRightButtonDown=0; 403 } 404 } else if(buttonMask&4) 405 c->wasRightButtonDown=1; 406 407 if(buttonMask&1) { 408 int cx=x/c->cWidth,cy=y/c->cHeight,pos; 409 if(cx<0) cx=0; else if(cx>=c->width) cx=c->width-1; 410 if(cy<0) cy=0; else if(cy>=c->height) cy=c->height-1; 411 pos=cy*c->width+cx; 412 413 /* mark */ 414 if(!c->currentlyMarking) { 415 c->currentlyMarking=TRUE; 416 c->markStart=pos; 417 c->markEnd=pos; 418 vcToggleMarkCell(c,pos); 419 } else { 420 DEBUG(rfbLog("markStart: %d, markEnd: %d, pos: %d\n", 421 c->markStart,c->markEnd,pos)); 422 if(c->markEnd!=pos) { 423 if(c->markEnd<pos) { 424 cx=c->markEnd; cy=pos; 425 } else { 426 cx=pos; cy=c->markEnd; 427 } 428 if(cx<c->markStart) { 429 if(cy<c->markStart) 430 cy--; 431 } else 432 cx++; 433 while(cx<=cy) { 434 vcToggleMarkCell(c,cx); 435 cx++; 436 } 437 c->markEnd=pos; 438 } 439 } 440 } else if(c->currentlyMarking) { 441 int i,j; 442 if(c->markStart<c->markEnd) { 443 i=c->markStart; j=c->markEnd+1; 444 } else { 445 i=c->markEnd; j=c->markStart; 446 } 447 if(c->selection) free(c->selection); 448 c->selection=(char*)malloc(j-i+1); 449 memcpy(c->selection,c->screenBuffer+i,j-i); 450 c->selection[j-i]=0; 451 vcUnmark(c); 452 rfbGotXCutText(c->screen,c->selection,j-i); 453 } 454 rfbDefaultPtrAddEvent(buttonMask,x,y,cl); 455 } 456 457 void vcSetXCutTextProc(char* str,int len, struct _rfbClientRec* cl) 458 { 459 vncConsolePtr c=(vncConsolePtr)cl->screen->screenData; 460 461 if(c->selection) free(c->selection); 462 c->selection=(char*)malloc(len+1); 463 memcpy(c->selection,str,len); 464 c->selection[len]=0; 465 } 466 467 void vcToggleMarkCell(vncConsolePtr c,int pos) 468 { 469 int x=(pos%c->width)*c->cWidth, 470 y=(pos/c->width)*c->cHeight; 471 int i,j; 472 rfbScreenInfoPtr s=c->screen; 473 char *b=s->frameBuffer+y*s->width+x; 474 for(j=0;j<c->cHeight;j++) 475 for(i=0;i<c->cWidth;i++) 476 b[j*s->width+i]^=0x0f; 477 rfbMarkRectAsModified(c->screen,x,y,x+c->cWidth,y+c->cHeight); 478 } 479 480 void vcUnmark(vncConsolePtr c) 481 { 482 int i,j; 483 c->currentlyMarking=FALSE; 484 if(c->markStart<c->markEnd) { 485 i=c->markStart; j=c->markEnd+1; 486 } else { 487 i=c->markEnd; j=c->markStart; 488 } 489 for(;i<j;i++) 490 vcToggleMarkCell(c,i); 491 } 492 493 void vcProcessEvents(vncConsolePtr c) 494 { 495 rfbProcessEvents(c->screen,c->selectTimeOut); 496 } 497 498