OSDN Git Service

ui/console: fix default VC when there are no display
[qmiga/qemu.git] / ui / curses.c
1 /*
2  * QEMU curses/ncurses display driver
3  * 
4  * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "qemu/osdep.h"
26
27 #ifndef _WIN32
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #endif
31 #include <locale.h>
32 #include <wchar.h>
33 #include <iconv.h>
34
35 #include "qapi/error.h"
36 #include "qemu/module.h"
37 #include "ui/console.h"
38 #include "ui/input.h"
39 #include "sysemu/sysemu.h"
40
41 #if defined(__APPLE__) || defined(__OpenBSD__)
42 #define _XOPEN_SOURCE_EXTENDED 1
43 #endif
44
45 /* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */
46 #undef KEY_EVENT
47 #include <curses.h>
48 #undef KEY_EVENT
49
50 #define FONT_HEIGHT 16
51 #define FONT_WIDTH 8
52
53 enum maybe_keycode {
54     CURSES_KEYCODE,
55     CURSES_CHAR,
56     CURSES_CHAR_OR_KEYCODE,
57 };
58
59 static DisplayChangeListener *dcl;
60 static console_ch_t *screen;
61 static WINDOW *screenpad = NULL;
62 static int width, height, gwidth, gheight, invalidate;
63 static int px, py, sminx, sminy, smaxx, smaxy;
64
65 static const char *font_charset = "CP437";
66 static cchar_t *vga_to_curses;
67
68 static void curses_update(DisplayChangeListener *dcl,
69                           int x, int y, int w, int h)
70 {
71     console_ch_t *line;
72     g_autofree cchar_t *curses_line = g_new(cchar_t, width);
73     wchar_t wch[CCHARW_MAX];
74     attr_t attrs;
75     short colors;
76     int ret;
77
78     line = screen + y * width;
79     for (h += y; y < h; y ++, line += width) {
80         for (x = 0; x < width; x++) {
81             chtype ch = line[x] & A_CHARTEXT;
82             chtype at = line[x] & A_ATTRIBUTES;
83             short color_pair = PAIR_NUMBER(line[x]);
84
85             ret = getcchar(&vga_to_curses[ch], wch, &attrs, &colors, NULL);
86             if (ret == ERR || wch[0] == 0) {
87                 wch[0] = ch;
88                 wch[1] = 0;
89             }
90             setcchar(&curses_line[x], wch, at, color_pair, NULL);
91         }
92         mvwadd_wchnstr(screenpad, y, 0, curses_line, width);
93     }
94
95     pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
96     refresh();
97 }
98
99 static void curses_calc_pad(void)
100 {
101     if (qemu_console_is_fixedsize(NULL)) {
102         width = gwidth;
103         height = gheight;
104     } else {
105         width = COLS;
106         height = LINES;
107     }
108
109     if (screenpad)
110         delwin(screenpad);
111
112     clear();
113     refresh();
114
115     screenpad = newpad(height, width);
116
117     if (width > COLS) {
118         px = (width - COLS) / 2;
119         sminx = 0;
120         smaxx = COLS;
121     } else {
122         px = 0;
123         sminx = (COLS - width) / 2;
124         smaxx = sminx + width;
125     }
126
127     if (height > LINES) {
128         py = (height - LINES) / 2;
129         sminy = 0;
130         smaxy = LINES;
131     } else {
132         py = 0;
133         sminy = (LINES - height) / 2;
134         smaxy = sminy + height;
135     }
136 }
137
138 static void curses_resize(DisplayChangeListener *dcl,
139                           int width, int height)
140 {
141     if (width == gwidth && height == gheight) {
142         return;
143     }
144
145     gwidth = width;
146     gheight = height;
147
148     curses_calc_pad();
149 }
150
151 #if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE)
152 static volatile sig_atomic_t got_sigwinch;
153 static void curses_winch_check(void)
154 {
155     struct winsize {
156         unsigned short ws_row;
157         unsigned short ws_col;
158         unsigned short ws_xpixel;   /* unused */
159         unsigned short ws_ypixel;   /* unused */
160     } ws;
161
162     if (!got_sigwinch) {
163         return;
164     }
165     got_sigwinch = false;
166
167     if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
168         return;
169     }
170
171     resize_term(ws.ws_row, ws.ws_col);
172     invalidate = 1;
173 }
174
175 static void curses_winch_handler(int signum)
176 {
177     got_sigwinch = true;
178 }
179
180 static void curses_winch_init(void)
181 {
182     struct sigaction old, winch = {
183         .sa_handler  = curses_winch_handler,
184     };
185     sigaction(SIGWINCH, &winch, &old);
186 }
187 #else
188 static void curses_winch_check(void) {}
189 static void curses_winch_init(void) {}
190 #endif
191
192 static void curses_cursor_position(DisplayChangeListener *dcl,
193                                    int x, int y)
194 {
195     if (x >= 0) {
196         x = sminx + x - px;
197         y = sminy + y - py;
198
199         if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
200             move(y, x);
201             curs_set(1);
202             /* it seems that curs_set(1) must always be called before
203              * curs_set(2) for the latter to have effect */
204             if (!qemu_console_is_graphic(NULL)) {
205                 curs_set(2);
206             }
207             return;
208         }
209     }
210
211     curs_set(0);
212 }
213
214 /* generic keyboard conversion */
215
216 #include "curses_keys.h"
217
218 static kbd_layout_t *kbd_layout = NULL;
219
220 static wint_t console_getch(enum maybe_keycode *maybe_keycode)
221 {
222     wint_t ret;
223     switch (get_wch(&ret)) {
224     case KEY_CODE_YES:
225         *maybe_keycode = CURSES_KEYCODE;
226         break;
227     case OK:
228         *maybe_keycode = CURSES_CHAR;
229         break;
230     case ERR:
231         ret = -1;
232         break;
233     default:
234         abort();
235     }
236     return ret;
237 }
238
239 static int curses2foo(const int _curses2foo[], const int _curseskey2foo[],
240                       int chr, enum maybe_keycode maybe_keycode)
241 {
242     int ret = -1;
243     if (maybe_keycode == CURSES_CHAR) {
244         if (chr < CURSES_CHARS) {
245             ret = _curses2foo[chr];
246         }
247     } else {
248         if (chr < CURSES_KEYS) {
249             ret = _curseskey2foo[chr];
250         }
251         if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE &&
252             chr < CURSES_CHARS) {
253             ret = _curses2foo[chr];
254         }
255     }
256     return ret;
257 }
258
259 #define curses2keycode(chr, maybe_keycode) \
260     curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode)
261 #define curses2keysym(chr, maybe_keycode) \
262     curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode)
263 #define curses2qemu(chr, maybe_keycode) \
264     curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode)
265
266 static void curses_refresh(DisplayChangeListener *dcl)
267 {
268     int chr, keysym, keycode, keycode_alt;
269     enum maybe_keycode maybe_keycode = CURSES_KEYCODE;
270
271     curses_winch_check();
272
273     if (invalidate) {
274         clear();
275         refresh();
276         curses_calc_pad();
277         graphic_hw_invalidate(NULL);
278         invalidate = 0;
279     }
280
281     graphic_hw_text_update(NULL, screen);
282
283     while (1) {
284         /* while there are any pending key strokes to process */
285         chr = console_getch(&maybe_keycode);
286
287         if (chr == -1)
288             break;
289
290 #ifdef KEY_RESIZE
291         /* this shouldn't occur when we use a custom SIGWINCH handler */
292         if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) {
293             clear();
294             refresh();
295             curses_calc_pad();
296             curses_update(dcl, 0, 0, width, height);
297             continue;
298         }
299 #endif
300
301         keycode = curses2keycode(chr, maybe_keycode);
302         keycode_alt = 0;
303
304         /* alt or esc key */
305         if (keycode == 1) {
306             enum maybe_keycode next_maybe_keycode = CURSES_KEYCODE;
307             int nextchr = console_getch(&next_maybe_keycode);
308
309             if (nextchr != -1) {
310                 chr = nextchr;
311                 maybe_keycode = next_maybe_keycode;
312                 keycode_alt = ALT;
313                 keycode = curses2keycode(chr, maybe_keycode);
314
315                 if (keycode != -1) {
316                     keycode |= ALT;
317
318                     /* process keys reserved for qemu */
319                     if (keycode >= QEMU_KEY_CONSOLE0 &&
320                             keycode < QEMU_KEY_CONSOLE0 + 9) {
321                         erase();
322                         wnoutrefresh(stdscr);
323                         console_select(keycode - QEMU_KEY_CONSOLE0);
324
325                         invalidate = 1;
326                         continue;
327                     }
328                 }
329             }
330         }
331
332         if (kbd_layout) {
333             keysym = curses2keysym(chr, maybe_keycode);
334
335             if (keysym == -1) {
336                 if (chr < ' ') {
337                     keysym = chr + '@';
338                     if (keysym >= 'A' && keysym <= 'Z')
339                         keysym += 'a' - 'A';
340                     keysym |= KEYSYM_CNTRL;
341                 } else
342                     keysym = chr;
343             }
344
345             keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK,
346                                       NULL, false);
347             if (keycode == 0)
348                 continue;
349
350             keycode |= (keysym & ~KEYSYM_MASK) >> 16;
351             keycode |= keycode_alt;
352         }
353
354         if (keycode == -1)
355             continue;
356
357         if (qemu_console_is_graphic(NULL)) {
358             /* since terminals don't know about key press and release
359              * events, we need to emit both for each key received */
360             if (keycode & SHIFT) {
361                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
362                 qemu_input_event_send_key_delay(0);
363             }
364             if (keycode & CNTRL) {
365                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
366                 qemu_input_event_send_key_delay(0);
367             }
368             if (keycode & ALT) {
369                 qemu_input_event_send_key_number(NULL, ALT_CODE, true);
370                 qemu_input_event_send_key_delay(0);
371             }
372             if (keycode & ALTGR) {
373                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
374                 qemu_input_event_send_key_delay(0);
375             }
376
377             qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
378             qemu_input_event_send_key_delay(0);
379             qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
380             qemu_input_event_send_key_delay(0);
381
382             if (keycode & ALTGR) {
383                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
384                 qemu_input_event_send_key_delay(0);
385             }
386             if (keycode & ALT) {
387                 qemu_input_event_send_key_number(NULL, ALT_CODE, false);
388                 qemu_input_event_send_key_delay(0);
389             }
390             if (keycode & CNTRL) {
391                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
392                 qemu_input_event_send_key_delay(0);
393             }
394             if (keycode & SHIFT) {
395                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
396                 qemu_input_event_send_key_delay(0);
397             }
398         } else {
399             keysym = curses2qemu(chr, maybe_keycode);
400             if (keysym == -1)
401                 keysym = chr;
402
403             qemu_text_console_put_keysym(NULL, keysym);
404         }
405     }
406 }
407
408 static void curses_atexit(void)
409 {
410     endwin();
411     g_free(vga_to_curses);
412     g_free(screen);
413 }
414
415 /*
416  * In the following:
417  * - fch is the font glyph number
418  * - uch is the unicode value
419  * - wch is the wchar_t value (may not be unicode, e.g. on BSD/solaris)
420  * - mbch is the native local-dependent multibyte representation
421  */
422
423 /* Setup wchar glyph for one UCS-2 char */
424 static void convert_ucs(unsigned char fch, uint16_t uch, iconv_t conv)
425 {
426     char mbch[MB_LEN_MAX];
427     wchar_t wch[2];
428     char *puch, *pmbch;
429     size_t such, smbch;
430     mbstate_t ps;
431
432     puch = (char *) &uch;
433     pmbch = (char *) mbch;
434     such = sizeof(uch);
435     smbch = sizeof(mbch);
436
437     if (iconv(conv, &puch, &such, &pmbch, &smbch) == (size_t) -1) {
438         fprintf(stderr, "Could not convert 0x%04x "
439                         "from UCS-2 to a multibyte character: %s\n",
440                         uch, strerror(errno));
441         return;
442     }
443
444     memset(&ps, 0, sizeof(ps));
445     if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
446         fprintf(stderr, "Could not convert 0x%04x "
447                         "from a multibyte character to wchar_t: %s\n",
448                         uch, strerror(errno));
449         return;
450     }
451
452     wch[1] = 0;
453     setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
454 }
455
456 /* Setup wchar glyph for one font character */
457 static void convert_font(unsigned char fch, iconv_t conv)
458 {
459     char mbch[MB_LEN_MAX];
460     wchar_t wch[2];
461     char *pfch, *pmbch;
462     size_t sfch, smbch;
463     mbstate_t ps;
464
465     pfch = (char *) &fch;
466     pmbch = (char *) &mbch;
467     sfch = sizeof(fch);
468     smbch = sizeof(mbch);
469
470     if (iconv(conv, &pfch, &sfch, &pmbch, &smbch) == (size_t) -1) {
471         fprintf(stderr, "Could not convert font glyph 0x%02x "
472                         "from %s to a multibyte character: %s\n",
473                         fch, font_charset, strerror(errno));
474         return;
475     }
476
477     memset(&ps, 0, sizeof(ps));
478     if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
479         fprintf(stderr, "Could not convert font glyph 0x%02x "
480                         "from a multibyte character to wchar_t: %s\n",
481                         fch, strerror(errno));
482         return;
483     }
484
485     wch[1] = 0;
486     setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
487 }
488
489 /* Convert one wchar to UCS-2 */
490 static uint16_t get_ucs(wchar_t wch, iconv_t conv)
491 {
492     char mbch[MB_LEN_MAX];
493     uint16_t uch;
494     char *pmbch, *puch;
495     size_t smbch, such;
496     mbstate_t ps;
497     int ret;
498
499     memset(&ps, 0, sizeof(ps));
500     ret = wcrtomb(mbch, wch, &ps);
501     if (ret == -1) {
502         fprintf(stderr, "Could not convert 0x%04lx "
503                         "from wchar_t to a multibyte character: %s\n",
504                         (unsigned long)wch, strerror(errno));
505         return 0xFFFD;
506     }
507
508     pmbch = (char *) mbch;
509     puch = (char *) &uch;
510     smbch = ret;
511     such = sizeof(uch);
512
513     if (iconv(conv, &pmbch, &smbch, &puch, &such) == (size_t) -1) {
514         fprintf(stderr, "Could not convert 0x%04lx "
515                         "from a multibyte character to UCS-2 : %s\n",
516                         (unsigned long)wch, strerror(errno));
517         return 0xFFFD;
518     }
519
520     return uch;
521 }
522
523 /*
524  * Setup mapping for vga to curses line graphics.
525  */
526 static void font_setup(void)
527 {
528     iconv_t ucs2_to_nativecharset;
529     iconv_t nativecharset_to_ucs2;
530     iconv_t font_conv;
531     int i;
532     g_autofree gchar *local_codeset = g_get_codeset();
533
534     /*
535      * Control characters are normally non-printable, but VGA does have
536      * well-known glyphs for them.
537      */
538     static const uint16_t control_characters[0x20] = {
539       0x0020,
540       0x263a,
541       0x263b,
542       0x2665,
543       0x2666,
544       0x2663,
545       0x2660,
546       0x2022,
547       0x25d8,
548       0x25cb,
549       0x25d9,
550       0x2642,
551       0x2640,
552       0x266a,
553       0x266b,
554       0x263c,
555       0x25ba,
556       0x25c4,
557       0x2195,
558       0x203c,
559       0x00b6,
560       0x00a7,
561       0x25ac,
562       0x21a8,
563       0x2191,
564       0x2193,
565       0x2192,
566       0x2190,
567       0x221f,
568       0x2194,
569       0x25b2,
570       0x25bc
571     };
572
573     ucs2_to_nativecharset = iconv_open(local_codeset, "UCS-2");
574     if (ucs2_to_nativecharset == (iconv_t) -1) {
575         fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n",
576                         strerror(errno));
577         exit(1);
578     }
579
580     nativecharset_to_ucs2 = iconv_open("UCS-2", local_codeset);
581     if (nativecharset_to_ucs2 == (iconv_t) -1) {
582         iconv_close(ucs2_to_nativecharset);
583         fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n",
584                         strerror(errno));
585         exit(1);
586     }
587
588     font_conv = iconv_open(local_codeset, font_charset);
589     if (font_conv == (iconv_t) -1) {
590         iconv_close(ucs2_to_nativecharset);
591         iconv_close(nativecharset_to_ucs2);
592         fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n",
593                         font_charset, strerror(errno));
594         exit(1);
595     }
596
597     /* Control characters */
598     for (i = 0; i <= 0x1F; i++) {
599         convert_ucs(i, control_characters[i], ucs2_to_nativecharset);
600     }
601
602     for (i = 0x20; i <= 0xFF; i++) {
603         convert_font(i, font_conv);
604     }
605
606     /* DEL */
607     convert_ucs(0x7F, 0x2302, ucs2_to_nativecharset);
608
609     if (strcmp(local_codeset, "UTF-8")) {
610         /* Non-Unicode capable, use termcap equivalents for those available */
611         for (i = 0; i <= 0xFF; i++) {
612             wchar_t wch[CCHARW_MAX];
613             attr_t attr;
614             short color;
615             int ret;
616
617             ret = getcchar(&vga_to_curses[i], wch, &attr, &color, NULL);
618             if (ret == ERR)
619                 continue;
620
621             switch (get_ucs(wch[0], nativecharset_to_ucs2)) {
622             case 0x00a3:
623                 vga_to_curses[i] = *WACS_STERLING;
624                 break;
625             case 0x2591:
626                 vga_to_curses[i] = *WACS_BOARD;
627                 break;
628             case 0x2592:
629                 vga_to_curses[i] = *WACS_CKBOARD;
630                 break;
631             case 0x2502:
632                 vga_to_curses[i] = *WACS_VLINE;
633                 break;
634             case 0x2524:
635                 vga_to_curses[i] = *WACS_RTEE;
636                 break;
637             case 0x2510:
638                 vga_to_curses[i] = *WACS_URCORNER;
639                 break;
640             case 0x2514:
641                 vga_to_curses[i] = *WACS_LLCORNER;
642                 break;
643             case 0x2534:
644                 vga_to_curses[i] = *WACS_BTEE;
645                 break;
646             case 0x252c:
647                 vga_to_curses[i] = *WACS_TTEE;
648                 break;
649             case 0x251c:
650                 vga_to_curses[i] = *WACS_LTEE;
651                 break;
652             case 0x2500:
653                 vga_to_curses[i] = *WACS_HLINE;
654                 break;
655             case 0x253c:
656                 vga_to_curses[i] = *WACS_PLUS;
657                 break;
658             case 0x256c:
659                 vga_to_curses[i] = *WACS_LANTERN;
660                 break;
661             case 0x256a:
662                 vga_to_curses[i] = *WACS_NEQUAL;
663                 break;
664             case 0x2518:
665                 vga_to_curses[i] = *WACS_LRCORNER;
666                 break;
667             case 0x250c:
668                 vga_to_curses[i] = *WACS_ULCORNER;
669                 break;
670             case 0x2588:
671                 vga_to_curses[i] = *WACS_BLOCK;
672                 break;
673             case 0x03c0:
674                 vga_to_curses[i] = *WACS_PI;
675                 break;
676             case 0x00b1:
677                 vga_to_curses[i] = *WACS_PLMINUS;
678                 break;
679             case 0x2265:
680                 vga_to_curses[i] = *WACS_GEQUAL;
681                 break;
682             case 0x2264:
683                 vga_to_curses[i] = *WACS_LEQUAL;
684                 break;
685             case 0x00b0:
686                 vga_to_curses[i] = *WACS_DEGREE;
687                 break;
688             case 0x25a0:
689                 vga_to_curses[i] = *WACS_BULLET;
690                 break;
691             case 0x2666:
692                 vga_to_curses[i] = *WACS_DIAMOND;
693                 break;
694             case 0x2192:
695                 vga_to_curses[i] = *WACS_RARROW;
696                 break;
697             case 0x2190:
698                 vga_to_curses[i] = *WACS_LARROW;
699                 break;
700             case 0x2191:
701                 vga_to_curses[i] = *WACS_UARROW;
702                 break;
703             case 0x2193:
704                 vga_to_curses[i] = *WACS_DARROW;
705                 break;
706             case 0x23ba:
707                 vga_to_curses[i] = *WACS_S1;
708                 break;
709             case 0x23bb:
710                 vga_to_curses[i] = *WACS_S3;
711                 break;
712             case 0x23bc:
713                 vga_to_curses[i] = *WACS_S7;
714                 break;
715             case 0x23bd:
716                 vga_to_curses[i] = *WACS_S9;
717                 break;
718             }
719         }
720     }
721     iconv_close(ucs2_to_nativecharset);
722     iconv_close(nativecharset_to_ucs2);
723     iconv_close(font_conv);
724 }
725
726 static void curses_setup(void)
727 {
728     int i, colour_default[8] = {
729         [QEMU_COLOR_BLACK]   = COLOR_BLACK,
730         [QEMU_COLOR_BLUE]    = COLOR_BLUE,
731         [QEMU_COLOR_GREEN]   = COLOR_GREEN,
732         [QEMU_COLOR_CYAN]    = COLOR_CYAN,
733         [QEMU_COLOR_RED]     = COLOR_RED,
734         [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA,
735         [QEMU_COLOR_YELLOW]  = COLOR_YELLOW,
736         [QEMU_COLOR_WHITE]   = COLOR_WHITE,
737     };
738
739     /* input as raw as possible, let everything be interpreted
740      * by the guest system */
741     initscr(); noecho(); intrflush(stdscr, FALSE);
742     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
743     start_color(); raw(); scrollok(stdscr, FALSE);
744     set_escdelay(25);
745
746     /* Make color pair to match color format (3bits bg:3bits fg) */
747     for (i = 0; i < 64; i++) {
748         init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
749     }
750     /* Set default color for more than 64 for safety. */
751     for (i = 64; i < COLOR_PAIRS; i++) {
752         init_pair(i, COLOR_WHITE, COLOR_BLACK);
753     }
754
755     font_setup();
756 }
757
758 static void curses_keyboard_setup(void)
759 {
760 #if defined(__APPLE__)
761     /* always use generic keymaps */
762     if (!keyboard_layout)
763         keyboard_layout = "en-us";
764 #endif
765     if(keyboard_layout) {
766         kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
767                                           &error_fatal);
768     }
769 }
770
771 static const DisplayChangeListenerOps dcl_ops = {
772     .dpy_name        = "curses",
773     .dpy_text_update = curses_update,
774     .dpy_text_resize = curses_resize,
775     .dpy_refresh     = curses_refresh,
776     .dpy_text_cursor = curses_cursor_position,
777 };
778
779 static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
780 {
781 #ifndef _WIN32
782     if (!isatty(1)) {
783         fprintf(stderr, "We need a terminal output\n");
784         exit(1);
785     }
786 #endif
787
788     setlocale(LC_CTYPE, "");
789     if (opts->u.curses.charset) {
790         font_charset = opts->u.curses.charset;
791     }
792     screen = g_new0(console_ch_t, 160 * 100);
793     vga_to_curses = g_new0(cchar_t, 256);
794     curses_setup();
795     curses_keyboard_setup();
796     atexit(curses_atexit);
797
798     curses_winch_init();
799
800     dcl = g_new0(DisplayChangeListener, 1);
801     dcl->ops = &dcl_ops;
802     register_displaychangelistener(dcl);
803
804     invalidate = 1;
805 }
806
807 static QemuDisplay qemu_display_curses = {
808     .type       = DISPLAY_TYPE_CURSES,
809     .init       = curses_display_init,
810 };
811
812 static void register_curses(void)
813 {
814     qemu_display_register(&qemu_display_curses);
815 }
816
817 type_init(register_curses);