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
MakeColourMap16(vncConsolePtr c)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
vcDrawOrHideCursor(vncConsolePtr c)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
vcDrawCursor(vncConsolePtr c)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
vcHideCursor(vncConsolePtr c)59 void vcHideCursor(vncConsolePtr c)
60 {
61 if(c->currentlyMarking)
62 vcUnmark(c);
63 vcDrawOrHideCursor(c);
64 }
65
vcMakeSureCursorIsDrawn(rfbClientPtr cl)66 void vcMakeSureCursorIsDrawn(rfbClientPtr cl)
67 {
68 vncConsolePtr c=(vncConsolePtr)cl->screen->screenData;
69 if(!c->dontDrawCursor)
70 vcDrawCursor(c);
71 }
72
vcGetConsole(int * argc,char ** argv,int width,int height,rfbFontDataPtr font,rfbBool withAttributes)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 */
vcScroll(vncConsolePtr c,int lineCount)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
vcCheckCoordinates(vncConsolePtr c)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
vcPutChar(vncConsolePtr c,unsigned char ch)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
vcPutCharColour(vncConsolePtr c,unsigned char ch,unsigned char foreColour,unsigned char backColour)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
vcPrint(vncConsolePtr c,unsigned char * str)280 void vcPrint(vncConsolePtr c,unsigned char* str)
281 {
282 while(*str) {
283 vcPutChar(c,*str);
284 str++;
285 }
286 }
287
vcPrintColour(vncConsolePtr c,unsigned char * str,unsigned char foreColour,unsigned char backColour)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
vcPrintF(vncConsolePtr c,char * format,...)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
vcPrintFColour(vncConsolePtr c,unsigned char foreColour,unsigned char backColour,char * format,...)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
vcGetCh(vncConsolePtr c)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
vcGetChar(vncConsolePtr c)329 char vcGetChar(vncConsolePtr c)
330 {
331 while(rfbIsActive(c->screen) && c->inputCount==0)
332 vcProcessEvents(c);
333 return(vcGetCh(c));
334 }
335
vcGetString(vncConsolePtr c,char * buffer,int bufferSize)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
vcKbdAddEventProc(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)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
vcPtrAddEventProc(int buttonMask,int x,int y,rfbClientPtr cl)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
vcSetXCutTextProc(char * str,int len,struct _rfbClientRec * cl)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
vcToggleMarkCell(vncConsolePtr c,int pos)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
vcUnmark(vncConsolePtr c)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
vcProcessEvents(vncConsolePtr c)493 void vcProcessEvents(vncConsolePtr c)
494 {
495 rfbProcessEvents(c->screen,c->selectTimeOut);
496 }
497
498