3 * Taken from Palacios console display in MINIX ( by Erik Van der Kouwe )
5 * (c) Peter Dinda, 2011 (Scan code encoding)
11 #include <sys/ioctl.h>
20 #include <linux/keyboard.h>
25 static int in_color = 0;
26 static int color8 = 0;
27 #define TRANS_STYLE(x) ( !color8 ? (x) : ((x)&0x7)|(((x)&0x70)>>1))
29 static int use_curses = 0;
30 static int debug_enable = 0;
32 static int ctrlc_count = 0;
37 typedef enum { CONSOLE_CURS_SET = 1,
41 CONSOLE_RESOLUTION = 5 } console_op_t;
51 struct termios termios_old;
52 unsigned char old_kbd_mode;
61 } __attribute__((packed));
63 struct character_msg {
68 } __attribute__((packed));
72 } __attribute__((packed));
74 struct resolution_msg {
77 } __attribute__((packed));
83 struct cursor_msg cursor;
84 struct character_msg character;
85 struct scroll_msg scroll;
86 struct resolution_msg resolution;
88 } __attribute__((packed));
93 static int handle_char_set(struct character_msg * msg) {
97 fprintf(stderr, "setting char (%c), at (x=%d, y=%d)\n", c, msg->x, msg->y);
105 if ((c < ' ') || (c >= 127)) {
107 fprintf(stderr, "unexpected control character %d\n", c);
113 /* clip whatever falls outside the visible area to avoid errors */
114 if ((msg->x < 0) || (msg->y < 0) ||
115 (msg->x > console.win->_maxx) ||
116 (msg->y > console.win->_maxy)) {
119 fprintf(stderr, "Char out of range (x=%d,y=%d) MAX:(x=%d,y=%d)\n",
120 msg->x, msg->y, console.win->_maxx, console.win->_maxy);
126 if ((msg->x == console.win->_maxx) &&
127 (msg->y == console.win->_maxy)) {
131 if (in_color) {wattron(console.win, COLOR_PAIR(TRANS_STYLE(msg->style)));}
132 mvwaddch(console.win, msg->y, msg->x, c);
133 if (in_color) {wattroff(console.win, COLOR_PAIR(TRANS_STYLE(msg->style)));}
136 //stdout text display
137 while (console.y < msg->y) {
143 while (console.x < msg->x) {
151 assert(console.x <= console.cols);
153 if (console.x == console.cols) {
163 int handle_curs_set(struct cursor_msg * msg) {
165 fprintf(stderr, "cursor set: (x=%d, y=%d)\n", msg->x, msg->y);
169 /* nothing to do now, cursor is set before update to make sure it isn't
170 * affected by character_set
181 int handle_scroll(struct scroll_msg * msg) {
182 int lines = msg->lines;
185 fprintf(stderr, "scroll: %d lines\n", lines);
201 int handle_text_resolution(struct resolution_msg * msg) {
203 fprintf(stderr, "text resolution: rows=%d, cols=%d\n", msg->rows, msg->cols);
207 console.rows = msg->rows;
208 console.cols = msg->cols;
213 int handle_update( void ) {
215 fprintf(stderr, "update\n");
220 if ( (console.x >= 0) && (console.y >= 0) &&
221 (console.x <= console.win->_maxx) &&
222 (console.y <= console.win->_maxy) ) {
224 wmove(console.win, console.y, console.x);
228 wrefresh(console.win);
235 int handle_console_msg(int cons_fd) {
239 ret = read(cons_fd, &msg, sizeof(struct cons_msg));
242 case CONSOLE_CURS_SET:
243 // printf("Console cursor set (x=%d, y=%d)\n", msg.cursor.x, msg.cursor.y);
244 handle_curs_set(&(msg.cursor));
246 case CONSOLE_CHAR_SET:
247 handle_char_set(&(msg.character));
248 /* printf("Console character set (x=%d, y=%d, c=%c, style=%c)\n",
249 msg.character.x, msg.character.y, msg.character.c, msg.character.style);*/
252 // printf("Console scroll (lines=%d)\n", msg.scroll.lines);
253 handle_scroll(&(msg.scroll));
256 // printf("Console update\n");
259 case CONSOLE_RESOLUTION:
260 handle_text_resolution(&(msg.resolution));
263 printf("Invalid console message operation (%d)\n", msg.op);
272 void handle_exit(void) {
273 if ( debug_enable ) {
274 fprintf(stderr, "Exiting from console terminal\n");
282 // tcsetattr(STDIN_FILENO, TCSANOW, &console.termios_old);
284 // ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
288 #define NO_KEY { 0, 0 }
291 unsigned char scan_code;
292 unsigned char capital;
295 static const struct key_code ascii_to_key_code[] = { // ASCII Value Serves as Index
296 NO_KEY, NO_KEY, {0x50, 0}, {0x48, 0}, // 0x00 - 0x03
297 {0x4B, 0}, {0x4D, 0}, NO_KEY, { 0x0E, 0 }, // 0x04 - 0x07
298 { 0x0E, 0 }, { 0x0F, 0 }, { 0x1C, 0 }, NO_KEY, // 0x08 - 0x0B
299 NO_KEY, { 0x1C, 0 }, NO_KEY, NO_KEY, // 0x0C - 0x0F
300 NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x10 - 0x13
301 NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x14 - 0x17
302 NO_KEY, NO_KEY, NO_KEY, { 0x01, 0 }, // 0x18 - 0x1B
303 NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x1C - 0x1F
304 { 0x39, 0 }, { 0x02, 1 }, { 0x28, 1 }, { 0x04, 1 }, // 0x20 - 0x23
305 { 0x05, 1 }, { 0x06, 1 }, { 0x08, 1 }, { 0x28, 0 }, // 0x24 - 0x27
306 { 0x0A, 1 }, { 0x0B, 1 }, { 0x09, 1 }, { 0x0D, 1 }, // 0x28 - 0x2B
307 { 0x33, 0 }, { 0x0C, 0 }, { 0x34, 0 }, { 0x35, 0 }, // 0x2C - 0x2F
308 { 0x0B, 0 }, { 0x02, 0 }, { 0x03, 0 }, { 0x04, 0 }, // 0x30 - 0x33
309 { 0x05, 0 }, { 0x06, 0 }, { 0x07, 0 }, { 0x08, 0 }, // 0x34 - 0x37
310 { 0x09, 0 }, { 0x0A, 0 }, { 0x27, 1 }, { 0x27, 0 }, // 0x38 - 0x3B
311 { 0x33, 1 }, { 0x0D, 0 }, { 0x34, 1 }, { 0x35, 1 }, // 0x3C - 0x3F
312 { 0x03, 1 }, { 0x1E, 1 }, { 0x30, 1 }, { 0x2E, 1 }, // 0x40 - 0x43
313 { 0x20, 1 }, { 0x12, 1 }, { 0x21, 1 }, { 0x22, 1 }, // 0x44 - 0x47
314 { 0x23, 1 }, { 0x17, 1 }, { 0x24, 1 }, { 0x25, 1 }, // 0x48 - 0x4B
315 { 0x26, 1 }, { 0x32, 1 }, { 0x31, 1 }, { 0x18, 1 }, // 0x4C - 0x4F
316 { 0x19, 1 }, { 0x10, 1 }, { 0x13, 1 }, { 0x1F, 1 }, // 0x50 - 0x53
317 { 0x14, 1 }, { 0x16, 1 }, { 0x2F, 1 }, { 0x11, 1 }, // 0x54 - 0x57
318 { 0x2D, 1 }, { 0x15, 1 }, { 0x2C, 1 }, { 0x1A, 0 }, // 0x58 - 0x5B
319 { 0x2B, 0 }, { 0x1B, 0 }, { 0x07, 1 }, { 0x0C, 1 }, // 0x5C - 0x5F
320 { 0x29, 0 }, { 0x1E, 0 }, { 0x30, 0 }, { 0x2E, 0 }, // 0x60 - 0x63
321 { 0x20, 0 }, { 0x12, 0 }, { 0x21, 0 }, { 0x22, 0 }, // 0x64 - 0x67
322 { 0x23, 0 }, { 0x17, 0 }, { 0x24, 0 }, { 0x25, 0 }, // 0x68 - 0x6B
323 { 0x26, 0 }, { 0x32, 0 }, { 0x31, 0 }, { 0x18, 0 }, // 0x6C - 0x6F
324 { 0x19, 0 }, { 0x10, 0 }, { 0x13, 0 }, { 0x1F, 0 }, // 0x70 - 0x73
325 { 0x14, 0 }, { 0x16, 0 }, { 0x2F, 0 }, { 0x11, 0 }, // 0x74 - 0x77
326 { 0x2D, 0 }, { 0x15, 0 }, { 0x2C, 0 }, { 0x1A, 1 }, // 0x78 - 0x7B
327 { 0x2B, 1 }, { 0x1B, 1 }, { 0x29, 1 }, { 0x0E, 0 } // 0x7C - 0x7F
332 #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)
335 int send_scancode_group_to_palacios(int fd, TermKeyKey * kc, struct key_code *k)
339 if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
345 if (kc->modifiers & TERMKEY_KEYMOD_ALT) {
359 writeit(fd,sc); // key down
361 sc |= 0x80; // key up
371 if (kc->modifiers & TERMKEY_KEYMOD_CTRL) {
377 if (kc->modifiers & TERMKEY_KEYMOD_ALT) {
386 int handle_key(int fd, TermKeyKey * kc)
391 fprintf(stderr,"key '%c'\n",kc->code.number);
395 if (kc->code.number<0x80) {
396 struct key_code k = ascii_to_key_code[kc->code.number];
398 if (k.scan_code==0 && k.capital==0) {
400 fprintf(stderr,"Cannot send key '%c' to palacios as it maps to no scancode\n",kc->code.number);
404 return send_scancode_group_to_palacios(fd,kc,&k);
408 fprintf(stderr,"Cannot send key '%c' to palacios because it is >=0x80\n",kc->code.number);
415 static int handle_fnkey (int fd, TermKeyKey * kc) {
419 switch (kc->code.number) {
457 fprintf(stderr, "Unknown function key <%x>\n", kc->code.number);
461 struct key_code k = { sc, kc->modifiers & TERMKEY_KEYMOD_SHIFT };
463 return send_scancode_group_to_palacios(fd,kc,&k);
467 static int handle_symkey (int fd, TermKeyKey * kc) {
470 switch (kc->code.sym) {
471 case TERMKEY_SYM_BACKSPACE:
474 case TERMKEY_SYM_TAB:
477 case TERMKEY_SYM_ENTER:
480 case TERMKEY_SYM_ESCAPE:
483 case TERMKEY_SYM_SPACE:
486 case TERMKEY_SYM_INSERT:
489 case TERMKEY_SYM_DEL:
495 case TERMKEY_SYM_DOWN:
498 case TERMKEY_SYM_LEFT:
501 case TERMKEY_SYM_RIGHT:
504 case TERMKEY_SYM_PAGEUP:
507 case TERMKEY_SYM_PAGEDOWN:
510 case TERMKEY_SYM_HOME:
513 case TERMKEY_SYM_END:
516 case TERMKEY_SYM_KP0:
519 case TERMKEY_SYM_KP1:
522 case TERMKEY_SYM_KP2:
525 case TERMKEY_SYM_KP3:
528 case TERMKEY_SYM_KP4:
531 case TERMKEY_SYM_KP5:
534 case TERMKEY_SYM_KP6:
537 case TERMKEY_SYM_KP7:
540 case TERMKEY_SYM_KP8:
543 case TERMKEY_SYM_KP9:
546 case TERMKEY_SYM_KPENTER:
549 case TERMKEY_SYM_KPPLUS:
552 case TERMKEY_SYM_KPMINUS:
555 case TERMKEY_SYM_KPMULT:
558 case TERMKEY_SYM_KPDIV:
562 fprintf(stderr, "Unknown sym key\n");
567 struct key_code k = { sc, kc->modifiers & TERMKEY_KEYMOD_SHIFT };
569 return send_scancode_group_to_palacios(fd,kc,&k);
575 #define MIN_TTY_COLS 80
576 #define MIN_TTY_ROWS 25
577 int check_terminal_size (void)
579 unsigned short n_cols = 0;
580 unsigned short n_rows = 0;
581 struct winsize winsz;
583 ioctl (fileno(stdin), TIOCGWINSZ, &winsz);
584 n_cols = winsz.ws_col;
585 n_rows = winsz.ws_row;
587 if (n_cols < MIN_TTY_COLS || n_rows < MIN_TTY_ROWS) {
588 printf ("Your window is not large enough.\n");
589 printf ("It must be at least %dx%d, but yours is %dx%d\n",
590 MIN_TTY_COLS, MIN_TTY_ROWS, n_cols, n_rows);
606 fprintf(stderr,"No color support\n");
614 if (can_change_color() && COLORS>=16 && COLOR_PAIRS>=256) {
615 fprintf(stderr, "Modifyable color support with enough colors available\n");
616 // initialize first 16 colors to be the PC colors
617 // then create all the pairings
619 unsigned short red, green, blue, intens;
625 init_color(i, 500*(red+intens), 500*(blue+intens), 500*(green+intens));
627 for (i=0;i<256;i++) {
628 init_pair(i, i & 0xf, (i >> 4) & 0xf);
634 if (COLORS!=8 || COLOR_PAIRS<64) {
635 fprintf(stderr,"Insufficient number of fixed colors (%d) or color pairs (%d)\n",COLORS,COLOR_PAIRS);
640 // We have only the low-intensity colors available, so
642 fprintf(stderr,"Only 8 color standard palette available\n");
644 // VGA color order: black, blue, green, cyan, red, magenta, brown, gray
645 // curses color order: black, red, green, yellow, blue, magenta, cyan, white
646 short map[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
647 unsigned short fg, bg;
648 // discard intensity bit
651 init_pair(i, map[fg], map[bg]);
660 int main(int argc, char* argv[]) {
666 char * vm_dev = NULL;
667 struct termios termios;
668 TERMKEY_CHECK_VERSION;
669 TermKeyFormat format = TERMKEY_FORMAT_VIM;
670 tk = termkey_new(0, TERMKEY_FLAG_SPACESYMBOL|TERMKEY_FLAG_CTRLC);
673 fprintf(stderr, "Could not allocate termkey instance\n");
677 if (termkey_get_flags(tk) & TERMKEY_FLAG_UTF8) {
679 printf("Termkey in UTF-8 mode\n");
681 } else if (termkey_get_flags(tk) & TERMKEY_FLAG_RAW) {
683 printf("Termkey in RAW mode\n");
691 printf("\033[?%dhMouse mode active\n", mouse);
693 printf("\033[?%dh", mouse_proto);
699 printf("usage: v3_cons_tc <vm_device>\n\n"
700 "NOTE: to exit the terminal, use CTRL-ALT-\\\n\n");
704 /* Check for minimum Terminal size at start */
705 if (0 != check_terminal_size()) {
706 printf ("Error: terminal too small!\n");
712 vm_fd = open(vm_dev, O_RDONLY);
715 printf("Error opening VM device: %s\n", vm_dev);
719 cons_fd = ioctl(vm_fd, V3_VM_CONSOLE_CONNECT, NULL);
721 /* Close the file descriptor. */
725 printf("Error opening stream Console\n");
738 console.win = initscr();
740 if (console.win == NULL) {
741 fprintf(stderr, "Error initialization curses screen\n");
745 scrollok(console.win, 1);
754 keypad(console.win, TRUE);
764 FD_SET(cons_fd, &rset);
765 FD_SET(STDIN_FILENO, &rset);
767 ret = select(cons_fd + 1, &rset, NULL, NULL, NULL);
771 } else if (ret == -1) {
772 perror("Select returned error...\n");
776 if (FD_ISSET(cons_fd, &rset)) {
777 if (handle_console_msg(cons_fd) == -1) {
778 printf("Console Error\n");
783 if (FD_ISSET(STDIN_FILENO, &rset)) {
785 ret = termkey_waitkey(tk, &key);
787 if(ret == TERMKEY_RES_KEY) {
789 termkey_strfkey(tk, buffer, sizeof buffer, &key, format);
793 case TERMKEY_TYPE_UNICODE: {
795 if (key.code.number == '\\' &&
796 key.modifiers & TERMKEY_KEYMOD_CTRL &&
797 key.modifiers & TERMKEY_KEYMOD_ALT) {
800 int ret = handle_key(cons_fd, &key);
803 printf("Error sending key to console\n");
809 case TERMKEY_TYPE_FUNCTION:
810 handle_fnkey(cons_fd, &key);
812 case TERMKEY_TYPE_KEYSYM:
813 handle_symkey(cons_fd, &key);
816 fprintf(stderr, "Unknown key type\n");
825 printf("Console terminated\n");