Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


5171a6a7de60ab610674a158bcfdd62ef1a50ebc
[palacios.git] / linux_usr / v3_cons_tc.c
1 /* 
2  * V3 Console utility
3  * Taken from Palacios console display in MINIX ( by Erik Van der Kouwe )
4  * (c) Jack lange, 2010
5  * (c) Peter Dinda, 2011 (Scan code encoding)
6  */
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/ioctl.h> 
12 #include <errno.h>
13 #include <assert.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <curses.h>
18 #include <termios.h>
19 #include <linux/kd.h>
20 #include <linux/keyboard.h>
21
22 #include "v3_ctrl.h"
23 #include "termkey.h"
24
25 static int use_curses = 0;
26 static int debug_enable = 0;
27
28
29 #define VCONS_EXIT  2
30 #define VCONS_CTRLC 3
31
32 typedef enum { CONSOLE_CURS_SET = 1,
33                CONSOLE_CHAR_SET = 2,
34                CONSOLE_SCROLL = 3,
35                CONSOLE_UPDATE = 4,
36                CONSOLE_RESOLUTION = 5 } console_op_t;
37
38
39
40 static struct {
41     WINDOW * win;
42     int x;
43     int y;
44     int rows;
45     int cols;
46     struct termios termios_old;
47     unsigned char old_kbd_mode;
48 } console;
49
50 static TermKey * tk;
51
52
53 struct cursor_msg {
54     int x;
55     int y;
56 } __attribute__((packed));
57
58 struct character_msg {
59     int x;
60     int y;
61     char c;
62     unsigned char style;
63 } __attribute__((packed));
64
65 struct scroll_msg {
66     int lines;
67 } __attribute__((packed));
68
69 struct resolution_msg {
70     int cols;
71     int rows;
72 } __attribute__((packed));
73
74
75 struct cons_msg {
76     unsigned char op;
77     union {
78         struct cursor_msg cursor;
79         struct character_msg  character;
80         struct scroll_msg scroll;
81         struct resolution_msg resolution;
82     };
83 } __attribute__((packed)); 
84
85
86
87
88 static int handle_char_set(struct character_msg * msg) {
89     char c = msg->c;
90
91     if (debug_enable) {
92         fprintf(stderr, "setting char (%c), at (x=%d, y=%d)\n", c, msg->x, msg->y);
93     }
94
95     if (c == 0) {
96         c = ' ';
97     }
98
99
100     if ((c < ' ') || (c >= 127)) {
101         if (debug_enable) { 
102             fprintf(stderr, "unexpected control character %d\n", c);
103         }
104         c = '?';
105     }
106
107     if (use_curses) {
108         /* clip whatever falls outside the visible area to avoid errors */
109         if ((msg->x < 0) || (msg->y < 0) ||
110             (msg->x > console.win->_maxx) || 
111             (msg->y > console.win->_maxy)) {
112
113             if (debug_enable) { 
114                 fprintf(stderr, "Char out of range (x=%d,y=%d) MAX:(x=%d,y=%d)\n",
115                         msg->x, msg->y, console.win->_maxx, console.win->_maxy);
116             }
117
118             return -1;
119         }
120
121         if ((msg->x == console.win->_maxx) &&
122             (msg->y == console.win->_maxy)) {
123             return -1;
124         }
125
126     wattron(console.win, COLOR_PAIR(msg->style));
127         mvwaddch(console.win, msg->y, msg->x, c);
128     wattroff(console.win, COLOR_PAIR(msg->style));
129
130     } else {
131         //stdout text display
132         while (console.y < msg->y) {
133             printf("\n");
134             console.x = 0;
135             console.y++;
136         }
137
138         while (console.x < msg->x) {
139             printf(" ");
140             console.x++;
141         }
142
143         printf("%c", c);
144         console.x++;
145
146         assert(console.x <= console.cols); 
147
148         if (console.x == console.cols) {
149             printf("\n");
150             console.x = 0;
151             console.y++;
152         }
153     }
154
155     return 0;
156 }
157
158 int handle_curs_set(struct cursor_msg * msg) {
159     if (debug_enable) {
160         fprintf(stderr, "cursor set: (x=%d, y=%d)\n", msg->x, msg->y);
161     }
162
163     if (use_curses) {
164         /* nothing to do now, cursor is set before update to make sure it isn't 
165          * affected by character_set
166          */
167
168         console.x = msg->x;
169         console.y = msg->y;
170     }
171     
172     return 0;
173 }
174
175
176 int handle_scroll(struct scroll_msg * msg) {
177     int lines = msg->lines;
178
179     if (debug_enable) {
180         fprintf(stderr, "scroll: %d lines\n", lines);
181     }
182
183
184     assert(lines >= 0);
185
186     if (use_curses) {
187         while (lines > 0) {
188             scroll(console.win);
189             lines--;
190         }
191     } else {
192         console.y -= lines;     
193     }
194 }
195
196 int handle_text_resolution(struct resolution_msg * msg) {
197     if (debug_enable) {
198         fprintf(stderr, "text resolution: rows=%d, cols=%d\n", msg->rows, msg->cols);
199     }
200
201
202     console.rows = msg->rows;
203     console.cols = msg->cols;
204
205     return 0;
206 }
207
208 int handle_update( void ) {
209     if (debug_enable) {
210         fprintf(stderr, "update\n");
211     }    
212
213     if (use_curses) {
214
215         if ( (console.x >= 0) && (console.y >= 0) &&
216              (console.x <= console.win->_maxx) &&
217              (console.y <= console.win->_maxy) ) {
218
219             wmove(console.win, console.y, console.x);
220
221         }
222
223         wrefresh(console.win);
224     } else {
225         fflush(stdout);
226     }
227 }
228
229
230 int handle_console_msg(int cons_fd) {
231     int ret = 0;
232     struct cons_msg msg;
233
234     ret = read(cons_fd, &msg, sizeof(struct cons_msg));
235
236     switch (msg.op) {
237         case CONSOLE_CURS_SET:
238             //      printf("Console cursor set (x=%d, y=%d)\n", msg.cursor.x, msg.cursor.y);
239             handle_curs_set(&(msg.cursor));
240             break;
241         case CONSOLE_CHAR_SET:
242             handle_char_set(&(msg.character));
243             /*      printf("Console character set (x=%d, y=%d, c=%c, style=%c)\n", 
244               msg.character.x, msg.character.y, msg.character.c, msg.character.style);*/
245             break;
246         case CONSOLE_SCROLL:
247             //  printf("Console scroll (lines=%d)\n", msg.scroll.lines);
248             handle_scroll(&(msg.scroll));
249             break;
250         case CONSOLE_UPDATE:
251             // printf("Console update\n");
252             handle_update();
253             break;
254         case CONSOLE_RESOLUTION:
255             handle_text_resolution(&(msg.resolution));
256             break;
257         default:
258             printf("Invalid console message operation (%d)\n", msg.op);
259             break;
260     }
261
262     return 0;
263 }
264
265
266 int send_key(int cons_fd, char can_code) {
267
268     return 0;
269 }
270
271
272
273 void handle_exit(void) {
274     if ( debug_enable ) {
275         fprintf(stderr, "Exiting from console terminal\n");
276     }
277
278     if (use_curses) {
279         endwin();
280     }
281
282     termkey_destroy(tk);
283     //    tcsetattr(STDIN_FILENO, TCSANOW, &console.termios_old);
284
285     // ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
286 }
287
288
289 #define NO_KEY { 0, 0 }
290
291 struct key_code {
292     unsigned char scan_code;
293     unsigned char capital;
294 };
295
296 static const struct key_code ascii_to_key_code[] = {             // ASCII Value Serves as Index
297     NO_KEY,         NO_KEY,         {0x50, 0},         {0x48, 0},      // 0x00 - 0x03
298     {0x4B, 0},         {0x4D, 0},         NO_KEY,         { 0x0E, 0 }, // 0x04 - 0x07
299     { 0x0E, 0 },    { 0x0F, 0 },    { 0x1C, 0 },    NO_KEY,      // 0x08 - 0x0B
300     NO_KEY,         { 0x1C, 0 },    NO_KEY,         NO_KEY,      // 0x0C - 0x0F
301     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x10 - 0x13
302     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x14 - 0x17
303     NO_KEY,         NO_KEY,         NO_KEY,         { 0x01, 0 }, // 0x18 - 0x1B
304     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x1C - 0x1F
305     { 0x39, 0 },    { 0x02, 1 },    { 0x28, 1 },    { 0x04, 1 }, // 0x20 - 0x23
306     { 0x05, 1 },    { 0x06, 1 },    { 0x08, 1 },    { 0x28, 0 }, // 0x24 - 0x27
307     { 0x0A, 1 },    { 0x0B, 1 },    { 0x09, 1 },    { 0x0D, 1 }, // 0x28 - 0x2B
308     { 0x33, 0 },    { 0x0C, 0 },    { 0x34, 0 },    { 0x35, 0 }, // 0x2C - 0x2F
309     { 0x0B, 0 },    { 0x02, 0 },    { 0x03, 0 },    { 0x04, 0 }, // 0x30 - 0x33
310     { 0x05, 0 },    { 0x06, 0 },    { 0x07, 0 },    { 0x08, 0 }, // 0x34 - 0x37
311     { 0x09, 0 },    { 0x0A, 0 },    { 0x27, 1 },    { 0x27, 0 }, // 0x38 - 0x3B
312     { 0x33, 1 },    { 0x0D, 0 },    { 0x34, 1 },    { 0x35, 1 }, // 0x3C - 0x3F
313     { 0x03, 1 },    { 0x1E, 1 },    { 0x30, 1 },    { 0x2E, 1 }, // 0x40 - 0x43
314     { 0x20, 1 },    { 0x12, 1 },    { 0x21, 1 },    { 0x22, 1 }, // 0x44 - 0x47
315     { 0x23, 1 },    { 0x17, 1 },    { 0x24, 1 },    { 0x25, 1 }, // 0x48 - 0x4B
316     { 0x26, 1 },    { 0x32, 1 },    { 0x31, 1 },    { 0x18, 1 }, // 0x4C - 0x4F
317     { 0x19, 1 },    { 0x10, 1 },    { 0x13, 1 },    { 0x1F, 1 }, // 0x50 - 0x53
318     { 0x14, 1 },    { 0x16, 1 },    { 0x2F, 1 },    { 0x11, 1 }, // 0x54 - 0x57
319     { 0x2D, 1 },    { 0x15, 1 },    { 0x2C, 1 },    { 0x1A, 0 }, // 0x58 - 0x5B
320     { 0x2B, 0 },    { 0x1B, 0 },    { 0x07, 1 },    { 0x0C, 1 }, // 0x5C - 0x5F
321     { 0x29, 0 },    { 0x1E, 0 },    { 0x30, 0 },    { 0x2E, 0 }, // 0x60 - 0x63
322     { 0x20, 0 },    { 0x12, 0 },    { 0x21, 0 },    { 0x22, 0 }, // 0x64 - 0x67
323     { 0x23, 0 },    { 0x17, 0 },    { 0x24, 0 },    { 0x25, 0 }, // 0x68 - 0x6B
324     { 0x26, 0 },    { 0x32, 0 },    { 0x31, 0 },    { 0x18, 0 }, // 0x6C - 0x6F
325     { 0x19, 0 },    { 0x10, 0 },    { 0x13, 0 },    { 0x1F, 0 }, // 0x70 - 0x73
326     { 0x14, 0 },    { 0x16, 0 },    { 0x2F, 0 },    { 0x11, 0 }, // 0x74 - 0x77
327     { 0x2D, 0 },    { 0x15, 0 },    { 0x2C, 0 },    { 0x1A, 1 }, // 0x78 - 0x7B
328     { 0x2B, 1 },    { 0x1B, 1 },    { 0x29, 1 },    { 0x0E, 0 }  // 0x7C - 0x7F
329 };
330
331
332
333 #define writeit(fd,c)  do { if (debug_enable) { fprintf(stderr,"scancode 0x%x\n",(c));} if (write((fd),&(c),1)!=1) { return -1; } } while (0)
334
335 int send_char_to_palacios_as_scancodes(int fd, TermKeyKey * kc)
336 {
337     unsigned char sc;
338
339     if (debug_enable) {
340         fprintf(stderr,"key '%c'\n",kc->code.number);
341     }
342
343     if (kc->code.number == 'x' && 
344         kc->modifiers & TERMKEY_KEYMOD_CTRL && 
345         kc->modifiers & TERMKEY_KEYMOD_ALT) {
346         return VCONS_EXIT;
347     } else if (kc->code.number == 'c' && 
348                //kc->modifiers & TERMKEY_KEYMOD_CTRL && 
349                kc->modifiers & TERMKEY_KEYMOD_ALT) {
350         return VCONS_CTRLC;
351     }
352
353     if (kc->code.number<0x80) { 
354         struct key_code k = ascii_to_key_code[kc->code.number];
355
356         if (k.scan_code==0 && k.capital==0) { 
357             if (debug_enable) { 
358                 fprintf(stderr,"Cannot send key '%c' to palacios as it maps to no scancode\n",kc->code.number);
359             }
360         } else {
361
362             if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
363                 sc = 0x1d;
364                 writeit(fd, sc);
365             }
366
367             if (kc->modifiers & TERMKEY_KEYMOD_ALT) {
368                 sc = 0x38;
369                 writeit(fd, sc);
370             }
371
372             if (k.capital) { 
373                 //shift down
374                 sc = 0x2a ; // left shift down
375                 writeit(fd,sc);
376             }
377
378             sc = k.scan_code;
379
380             writeit(fd,sc);  // key down
381
382             sc |= 0x80;      // key up
383
384             writeit(fd,sc);
385
386             if (k.capital) { 
387                 sc = 0x2a | 0x80;
388                 writeit(fd,sc);
389             }
390
391             if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
392                 sc = 0x1d | 0x80;   // left ctrl up
393                 writeit(fd,sc);
394             }
395
396             if (kc->modifiers & TERMKEY_KEYMOD_ALT) {
397                 sc = 0x38 | 0x80; // left alt up
398                 writeit(fd, sc);
399             }
400         }
401
402     } else {
403
404
405         if (debug_enable) { 
406             fprintf(stderr,"Cannot send key '%c' to palacios because it is >=0x80\n",kc->code.number);
407         }
408
409
410     }
411     return 0;
412 }
413
414
415 static int handle_fnkey (int fd, TermKeyKey * kc) {
416
417     unsigned char sc;
418
419     switch (kc->code.number) {
420         case 0x1:
421             sc = 0x3b;
422             break;
423         case 0x2:
424             sc = 0x3c;
425             break;
426         case 0x3:
427             sc = 0x3d;
428             break;
429         case 0x4:
430             sc = 0x3e;
431             break;
432         case 0x5:
433             sc = 0x3f;
434             break;
435         case 0x6:
436             sc = 0x40;
437             break;
438         case 0x7:
439             sc = 0x41;
440             break;
441         case 0x8:
442             sc = 0x42;
443             break;
444         case 0x9:
445             sc = 0x43;
446             break;
447         case 0xa:
448             sc = 0x44;
449             break;
450         case 0xb:
451             // this is a ctrl+c sequence
452             if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
453                 return VCONS_CTRLC;
454             }
455             sc = 0x57;
456             break;
457         case 0xc:
458             // this is an exit sequence
459             if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
460                 return VCONS_EXIT;
461             }
462             sc = 0x58;
463             break;
464         default:
465             fprintf(stderr, "Unknown function key <%x>\n", kc->code.number);
466             break;
467     }
468
469     writeit(fd, sc);
470
471     sc |= 0x80;
472
473     writeit(fd, sc);
474
475     return 0;
476 }
477
478 static int handle_symkey (int fd, TermKeyKey * kc) {
479     unsigned char sc;
480
481     switch (kc->code.sym) {
482         case TERMKEY_SYM_BACKSPACE:
483             sc = 0xe;
484             break;
485         case TERMKEY_SYM_TAB:
486             sc = 0xf;
487             break;
488         case TERMKEY_SYM_ENTER:
489             sc = 0x1c;
490             break;
491         case TERMKEY_SYM_ESCAPE:
492             sc = 0x1;
493             break;
494         case TERMKEY_SYM_SPACE:
495             sc = 0x39;
496             break;
497         case TERMKEY_SYM_INSERT:
498             sc = 0x52;
499             break;
500         case TERMKEY_SYM_DEL:
501             sc = 0x53;
502             break;
503         case TERMKEY_SYM_UP:
504             sc = 0x48;
505             break;
506         case TERMKEY_SYM_DOWN:
507             sc = 0x50;
508             break;
509         case TERMKEY_SYM_LEFT:
510             sc = 0x4b;
511             break;
512         case TERMKEY_SYM_RIGHT:
513             sc = 0x4d;
514             break;
515         case TERMKEY_SYM_PAGEUP:
516             sc = 0x49;
517             break;
518         case TERMKEY_SYM_PAGEDOWN:
519             sc = 0x51;
520             break;
521         case TERMKEY_SYM_HOME:
522             sc = 0x47;
523             break;
524         case TERMKEY_SYM_END:
525             sc = 0x4f;
526             break;
527         case TERMKEY_SYM_KP0:
528             sc = 0x70;
529             break;
530         case TERMKEY_SYM_KP1:
531             sc = 0x69;
532             break;
533         case TERMKEY_SYM_KP2:
534             sc = 0x72;
535             break;
536         case TERMKEY_SYM_KP3:
537             sc = 0x7a;
538             break;
539         case TERMKEY_SYM_KP4:
540             sc = 0x6b;
541             break;
542         case TERMKEY_SYM_KP5:
543             sc = 0x73;
544             break;
545         case TERMKEY_SYM_KP6:
546             sc = 0x74;
547             break;
548         case TERMKEY_SYM_KP7:
549             sc = 0x6c;
550             break;
551         case TERMKEY_SYM_KP8:
552             sc = 0x75;
553             break;
554         case TERMKEY_SYM_KP9:
555             sc = 0x7d;
556             break;
557         case TERMKEY_SYM_KPENTER:
558             sc = 0x5a;
559             break;
560         case TERMKEY_SYM_KPPLUS:
561             sc = 0x79;
562             break;
563         case TERMKEY_SYM_KPMINUS:
564             sc = 0x7b;
565             break;
566         case TERMKEY_SYM_KPMULT:
567             sc = 0x7c;
568             break;
569         case TERMKEY_SYM_KPDIV:
570             sc = 0x4a;
571             break;
572         default:
573             fprintf(stderr, "Unknown sym key\n");
574             return;
575     }
576
577     writeit(fd, sc);
578
579     sc |= 0x80;
580
581     writeit(fd, sc);
582
583     return 0;
584
585 }
586
587
588 #define MIN_TTY_COLS  80
589 #define MIN_TTY_ROWS  25
590 int check_terminal_size (void)
591 {
592     unsigned short n_cols = 0;
593     unsigned short n_rows = 0;
594     struct winsize winsz; 
595
596     ioctl (fileno(stdin), TIOCGWINSZ, &winsz);
597     n_cols = winsz.ws_col;
598     n_rows = winsz.ws_row;
599
600     if (n_cols < MIN_TTY_COLS || n_rows < MIN_TTY_ROWS) {
601         printf ("Your window is not large enough.\n");
602         printf ("It must be at least %dx%d, but yours is %dx%d\n",
603                 MIN_TTY_COLS, MIN_TTY_ROWS, n_cols, n_rows);
604     return (-1);
605     }
606
607     /* SUCCESS */
608     return (0);
609 }
610
611
612
613 static void
614 init_colors (void)
615 {
616     start_color();
617     int i;
618     for (i = 0; i < 0x100; i++) {
619         init_pair(i, i & 0xf, (i >> 4) & 0xf);
620     }
621 }
622
623
624
625 int main(int argc, char* argv[]) {
626     int vm_fd;
627     int cons_fd;
628     int mouse = 0;
629     int mouse_proto = 0;
630     char buffer[50];
631     char * vm_dev = NULL;
632     struct termios termios;
633     TERMKEY_CHECK_VERSION;
634     TermKeyFormat format = TERMKEY_FORMAT_VIM;
635     tk = termkey_new(0, TERMKEY_FLAG_SPACESYMBOL|TERMKEY_FLAG_CTRLC);
636
637     if (!tk) {
638         fprintf(stderr, "Could not allocate termkey instance\n");
639         exit(EXIT_FAILURE);
640     }
641
642     if (termkey_get_flags(tk) & TERMKEY_FLAG_UTF8) {
643         if (debug_enable) {
644             printf("Termkey in UTF-8 mode\n");
645         }
646     } else if (termkey_get_flags(tk) & TERMKEY_FLAG_RAW) {
647         if (debug_enable) {
648             printf("Termkey in RAW mode\n");
649         }
650     }
651
652     TermKeyResult ret;
653     TermKeyKey key;
654
655     if(mouse) {
656         printf("\033[?%dhMouse mode active\n", mouse);
657         if(mouse_proto)
658             printf("\033[?%dh", mouse_proto);
659     }
660
661     use_curses = 1;
662
663     if (argc < 2) {
664         printf("usage: v3_cons_sc <vm_device>\n\n"
665                "NOTE: to use CTRL-C within the terminal, use Alt-C\n"
666                "      to exit the terminal, use CTRL-ALT-x\n\n");
667         goto exit_err;
668     }
669
670     /* Check for minimum Terminal size at start */
671     if (0 != check_terminal_size()) {
672         printf ("Error: terminal too small!\n");
673         goto exit_err;
674     }
675
676     vm_dev = argv[1];
677
678     vm_fd = open(vm_dev, O_RDONLY);
679
680     if (vm_fd == -1) {
681         printf("Error opening VM device: %s\n", vm_dev);
682         goto exit_err;
683     }
684
685     cons_fd = ioctl(vm_fd, V3_VM_CONSOLE_CONNECT, NULL); 
686
687     /* Close the file descriptor.  */ 
688     close(vm_fd); 
689
690     if (cons_fd < 0) {
691         printf("Error opening stream Console\n");
692         goto exit_err;
693     }
694
695     atexit(handle_exit);
696
697     console.x = 0;
698     console.y = 0;
699
700
701     if (use_curses) {
702
703         gettmode();
704         console.win = initscr();
705
706         if (console.win == NULL) {
707             fprintf(stderr, "Error initialization curses screen\n");
708             exit(-1);
709         }
710
711         scrollok(console.win, 1);
712
713         erase();
714         init_colors();
715     }
716
717
718     raw();
719     cbreak();
720     noecho();
721     keypad(console.win, TRUE);
722
723     while (1) {
724
725         int ret; 
726         int bytes_read = 0;
727         fd_set rset;
728
729         FD_ZERO(&rset);
730         FD_SET(cons_fd, &rset);
731         FD_SET(STDIN_FILENO, &rset);
732
733         ret = select(cons_fd + 1, &rset, NULL, NULL, NULL);
734
735         if (ret == 0) {
736             continue;
737         } else if (ret == -1) {
738             perror("Select returned error...\n");
739             return -1;
740         }
741
742         if (FD_ISSET(cons_fd, &rset)) {
743             if (handle_console_msg(cons_fd) == -1) {
744                 printf("Console Error\n");
745                 return -1;
746             }
747         }
748
749         if (FD_ISSET(STDIN_FILENO, &rset)) {
750
751             ret = termkey_waitkey(tk, &key);
752
753             if(ret == TERMKEY_RES_KEY) {
754
755                 termkey_strfkey(tk, buffer, sizeof buffer, &key, format);
756
757                 switch (key.type) {
758
759                     case TERMKEY_TYPE_UNICODE: {
760
761                            int ret = send_char_to_palacios_as_scancodes(cons_fd, &key);
762
763                            if (ret < 0) {
764                                printf("Error sending key to console\n");
765                                return -1;
766                            } else if (ret == VCONS_CTRLC) {
767
768                                unsigned char sc;
769                                sc = 0x1d;  // left ctrl down
770                                writeit(cons_fd,sc);
771                                sc = 0x2e; // c down
772                                writeit(cons_fd,sc);
773                                sc = 0x2e | 0x80;   // c up
774                                writeit(cons_fd,sc);
775                                sc = 0x1d | 0x80;   // left ctrl up
776                                writeit(cons_fd,sc);
777
778                            } else if (ret == VCONS_EXIT) {
779                                exit(1);
780                            }
781
782                            break;
783                                                }
784                     case TERMKEY_TYPE_FUNCTION:
785                            handle_fnkey(cons_fd, &key);
786                            break;
787                     case TERMKEY_TYPE_KEYSYM:
788                            handle_symkey(cons_fd, &key);
789                            break;
790                     default:
791                            fprintf(stderr, "Unknown key type\n");
792                 }
793             }
794
795         }
796     }
797
798     erase();
799
800     printf("Console terminated\n");
801
802     close(cons_fd);
803
804     return 0; 
805
806 exit_err:
807     termkey_destroy(tk);
808     return -1;
809 }
810
811