]> git.proxmox.com Git - mirror_qemu.git/blame - ui/curses.c
curses: fix wchar_t printf warning
[mirror_qemu.git] / ui / curses.c
CommitLineData
4d3b6f6e
AZ
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 */
e16f4c87 24#include "qemu/osdep.h"
4d3b6f6e
AZ
25
26#ifndef _WIN32
4d3b6f6e
AZ
27#include <sys/ioctl.h>
28#include <termios.h>
29#endif
2f8b7cd5
ST
30#include <locale.h>
31#include <wchar.h>
32#include <langinfo.h>
33#include <iconv.h>
4d3b6f6e 34
ab4f931e 35#include "qapi/error.h"
511d2b14 36#include "qemu-common.h"
28ecbaee 37#include "ui/console.h"
cd100328 38#include "ui/input.h"
9c17d615 39#include "sysemu/sysemu.h"
511d2b14 40
e2f82e92
GH
41/* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */
42#undef KEY_EVENT
43#include <curses.h>
44#undef KEY_EVENT
45
4d3b6f6e
AZ
46#define FONT_HEIGHT 16
47#define FONT_WIDTH 8
48
459a707e
ST
49enum maybe_keycode {
50 CURSES_KEYCODE,
51 CURSES_CHAR,
52 CURSES_CHAR_OR_KEYCODE,
53};
54
7c20b4a3 55static DisplayChangeListener *dcl;
c227f099 56static console_ch_t screen[160 * 100];
4d3b6f6e
AZ
57static WINDOW *screenpad = NULL;
58static int width, height, gwidth, gheight, invalidate;
59static int px, py, sminx, sminy, smaxx, smaxy;
60
2f8b7cd5
ST
61static const char *font_charset = "CP437";
62static cchar_t vga_to_curses[256];
e2368dc9 63
7c20b4a3 64static void curses_update(DisplayChangeListener *dcl,
7c20b4a3 65 int x, int y, int w, int h)
4d3b6f6e 66{
e2f82e92 67 console_ch_t *line;
2f8b7cd5 68 cchar_t curses_line[width];
4d3b6f6e 69
e2f82e92
GH
70 line = screen + y * width;
71 for (h += y; y < h; y ++, line += width) {
72 for (x = 0; x < width; x++) {
73 chtype ch = line[x] & 0xff;
74 chtype at = line[x] & ~0xff;
2f8b7cd5
ST
75 if (vga_to_curses[ch].chars[0]) {
76 curses_line[x] = vga_to_curses[ch];
77 } else {
a5489ae5
ST
78 curses_line[x] = (cchar_t) {
79 .chars[0] = ch,
80 };
e2f82e92 81 }
2f8b7cd5 82 curses_line[x].attr |= at;
e2f82e92 83 }
2f8b7cd5 84 mvwadd_wchnstr(screenpad, y, 0, curses_line, width);
e2f82e92 85 }
4d3b6f6e
AZ
86
87 pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
88 refresh();
89}
90
91static void curses_calc_pad(void)
92{
81c0d5a6 93 if (qemu_console_is_fixedsize(NULL)) {
4d3b6f6e
AZ
94 width = gwidth;
95 height = gheight;
96 } else {
97 width = COLS;
98 height = LINES;
99 }
100
101 if (screenpad)
102 delwin(screenpad);
103
104 clear();
105 refresh();
106
107 screenpad = newpad(height, width);
108
109 if (width > COLS) {
110 px = (width - COLS) / 2;
111 sminx = 0;
112 smaxx = COLS;
113 } else {
114 px = 0;
115 sminx = (COLS - width) / 2;
116 smaxx = sminx + width;
117 }
118
119 if (height > LINES) {
120 py = (height - LINES) / 2;
121 sminy = 0;
122 smaxy = LINES;
123 } else {
124 py = 0;
125 sminy = (LINES - height) / 2;
126 smaxy = sminy + height;
127 }
128}
129
7c20b4a3 130static void curses_resize(DisplayChangeListener *dcl,
7c20b4a3 131 int width, int height)
4d3b6f6e 132{
a93a4a22 133 if (width == gwidth && height == gheight) {
4d3b6f6e 134 return;
a93a4a22 135 }
4d3b6f6e 136
a93a4a22
GH
137 gwidth = width;
138 gheight = height;
4d3b6f6e
AZ
139
140 curses_calc_pad();
141}
142
032ac6f8
GH
143#if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE)
144static volatile sig_atomic_t got_sigwinch;
145static void curses_winch_check(void)
4d3b6f6e
AZ
146{
147 struct winsize {
148 unsigned short ws_row;
149 unsigned short ws_col;
150 unsigned short ws_xpixel; /* unused */
151 unsigned short ws_ypixel; /* unused */
152 } ws;
153
032ac6f8
GH
154 if (!got_sigwinch) {
155 return;
156 }
157 got_sigwinch = false;
158
159 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
4d3b6f6e 160 return;
032ac6f8 161 }
4d3b6f6e
AZ
162
163 resize_term(ws.ws_row, ws.ws_col);
4d3b6f6e 164 invalidate = 1;
032ac6f8 165}
4d3b6f6e 166
032ac6f8
GH
167static void curses_winch_handler(int signum)
168{
169 got_sigwinch = true;
4d3b6f6e 170}
032ac6f8
GH
171
172static void curses_winch_init(void)
173{
174 struct sigaction old, winch = {
175 .sa_handler = curses_winch_handler,
176 };
177 sigaction(SIGWINCH, &winch, &old);
178}
179#else
180static void curses_winch_check(void) {}
181static void curses_winch_init(void) {}
4d3b6f6e
AZ
182#endif
183
7c20b4a3 184static void curses_cursor_position(DisplayChangeListener *dcl,
7c20b4a3 185 int x, int y)
4d3b6f6e
AZ
186{
187 if (x >= 0) {
188 x = sminx + x - px;
189 y = sminy + y - py;
190
191 if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
192 move(y, x);
193 curs_set(1);
194 /* it seems that curs_set(1) must always be called before
195 * curs_set(2) for the latter to have effect */
81c0d5a6 196 if (!qemu_console_is_graphic(NULL)) {
4d3b6f6e 197 curs_set(2);
81c0d5a6 198 }
4d3b6f6e
AZ
199 return;
200 }
201 }
202
203 curs_set(0);
204}
205
206/* generic keyboard conversion */
207
208#include "curses_keys.h"
4d3b6f6e 209
c227f099 210static kbd_layout_t *kbd_layout = NULL;
4d3b6f6e 211
459a707e
ST
212static wint_t console_getch(enum maybe_keycode *maybe_keycode)
213{
214 wint_t ret;
215 switch (get_wch(&ret)) {
216 case KEY_CODE_YES:
217 *maybe_keycode = CURSES_KEYCODE;
218 break;
219 case OK:
220 *maybe_keycode = CURSES_CHAR;
221 break;
222 case ERR:
223 ret = -1;
224 break;
225 }
226 return ret;
227}
228
229static int curses2foo(const int _curses2foo[], const int _curseskey2foo[],
230 int chr, enum maybe_keycode maybe_keycode)
231{
232 int ret = -1;
233 if (maybe_keycode == CURSES_CHAR) {
234 if (chr < CURSES_CHARS) {
235 ret = _curses2foo[chr];
236 }
237 } else {
238 if (chr < CURSES_KEYS) {
239 ret = _curseskey2foo[chr];
240 }
241 if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE &&
242 chr < CURSES_CHARS) {
243 ret = _curses2foo[chr];
244 }
245 }
246 return ret;
247}
248
249#define curses2keycode(chr, maybe_keycode) \
250 curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode)
251#define curses2keysym(chr, maybe_keycode) \
252 curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode)
253#define curses2qemu(chr, maybe_keycode) \
254 curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode)
255
bc2ed970 256static void curses_refresh(DisplayChangeListener *dcl)
4d3b6f6e 257{
99a9ef44 258 int chr, keysym, keycode, keycode_alt;
459a707e 259 enum maybe_keycode maybe_keycode;
4d3b6f6e 260
032ac6f8
GH
261 curses_winch_check();
262
4d3b6f6e
AZ
263 if (invalidate) {
264 clear();
265 refresh();
266 curses_calc_pad();
1dbfa005 267 graphic_hw_invalidate(NULL);
4d3b6f6e
AZ
268 invalidate = 0;
269 }
270
1dbfa005 271 graphic_hw_text_update(NULL, screen);
4d3b6f6e 272
4d3b6f6e
AZ
273 while (1) {
274 /* while there are any pending key strokes to process */
459a707e 275 chr = console_getch(&maybe_keycode);
4d3b6f6e 276
459a707e 277 if (chr == -1)
4d3b6f6e
AZ
278 break;
279
b1314cf9 280#ifdef KEY_RESIZE
4d3b6f6e 281 /* this shouldn't occur when we use a custom SIGWINCH handler */
459a707e 282 if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) {
4d3b6f6e
AZ
283 clear();
284 refresh();
285 curses_calc_pad();
bc2ed970 286 curses_update(dcl, 0, 0, width, height);
4d3b6f6e
AZ
287 continue;
288 }
b1314cf9 289#endif
4d3b6f6e 290
459a707e 291 keycode = curses2keycode(chr, maybe_keycode);
44bb61c8 292 keycode_alt = 0;
4d3b6f6e 293
633786fe 294 /* alt or esc key */
4d3b6f6e 295 if (keycode == 1) {
459a707e
ST
296 enum maybe_keycode next_maybe_keycode;
297 int nextchr = console_getch(&next_maybe_keycode);
4d3b6f6e 298
459a707e 299 if (nextchr != -1) {
44bb61c8 300 chr = nextchr;
459a707e 301 maybe_keycode = next_maybe_keycode;
44bb61c8 302 keycode_alt = ALT;
459a707e 303 keycode = curses2keycode(chr, maybe_keycode);
4d3b6f6e 304
44bb61c8
ST
305 if (keycode != -1) {
306 keycode |= ALT;
4d3b6f6e 307
44bb61c8
ST
308 /* process keys reserved for qemu */
309 if (keycode >= QEMU_KEY_CONSOLE0 &&
310 keycode < QEMU_KEY_CONSOLE0 + 9) {
311 erase();
312 wnoutrefresh(stdscr);
313 console_select(keycode - QEMU_KEY_CONSOLE0);
4d3b6f6e 314
44bb61c8
ST
315 invalidate = 1;
316 continue;
317 }
4d3b6f6e
AZ
318 }
319 }
320 }
321
44bb61c8 322 if (kbd_layout) {
459a707e 323 keysym = curses2keysym(chr, maybe_keycode);
44bb61c8
ST
324
325 if (keysym == -1) {
d03703c8
ST
326 if (chr < ' ') {
327 keysym = chr + '@';
328 if (keysym >= 'A' && keysym <= 'Z')
329 keysym += 'a' - 'A';
330 keysym |= KEYSYM_CNTRL;
331 } else
44bb61c8
ST
332 keysym = chr;
333 }
4d3b6f6e 334
abb4f2c9 335 keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK,
19c1b9fd 336 NULL, false);
44bb61c8
ST
337 if (keycode == 0)
338 continue;
339
340 keycode |= (keysym & ~KEYSYM_MASK) >> 16;
341 keycode |= keycode_alt;
4d3b6f6e
AZ
342 }
343
44bb61c8
ST
344 if (keycode == -1)
345 continue;
346
81c0d5a6 347 if (qemu_console_is_graphic(NULL)) {
4d3b6f6e
AZ
348 /* since terminals don't know about key press and release
349 * events, we need to emit both for each key received */
cd100328
GH
350 if (keycode & SHIFT) {
351 qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
5a165668 352 qemu_input_event_send_key_delay(0);
cd100328
GH
353 }
354 if (keycode & CNTRL) {
355 qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
5a165668 356 qemu_input_event_send_key_delay(0);
cd100328
GH
357 }
358 if (keycode & ALT) {
359 qemu_input_event_send_key_number(NULL, ALT_CODE, true);
5a165668 360 qemu_input_event_send_key_delay(0);
cd100328 361 }
44bb61c8 362 if (keycode & ALTGR) {
cd100328 363 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
5a165668 364 qemu_input_event_send_key_delay(0);
44bb61c8 365 }
cd100328 366
f5c0ab13 367 qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
5a165668 368 qemu_input_event_send_key_delay(0);
f5c0ab13 369 qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
5a165668 370 qemu_input_event_send_key_delay(0);
cd100328 371
44bb61c8 372 if (keycode & ALTGR) {
cd100328 373 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
5a165668 374 qemu_input_event_send_key_delay(0);
cd100328
GH
375 }
376 if (keycode & ALT) {
377 qemu_input_event_send_key_number(NULL, ALT_CODE, false);
5a165668 378 qemu_input_event_send_key_delay(0);
cd100328
GH
379 }
380 if (keycode & CNTRL) {
381 qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
5a165668 382 qemu_input_event_send_key_delay(0);
cd100328
GH
383 }
384 if (keycode & SHIFT) {
385 qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
5a165668 386 qemu_input_event_send_key_delay(0);
44bb61c8 387 }
4d3b6f6e 388 } else {
459a707e 389 keysym = curses2qemu(chr, maybe_keycode);
4d3b6f6e
AZ
390 if (keysym == -1)
391 keysym = chr;
392
393 kbd_put_keysym(keysym);
394 }
395 }
396}
397
aaf12c25 398static void curses_atexit(void)
4d3b6f6e
AZ
399{
400 endwin();
401}
402
2f8b7cd5
ST
403/* Setup wchar glyph for one UCS-2 char */
404static void convert_ucs(int glyph, uint16_t ch, iconv_t conv)
405{
406 wchar_t wch;
407 char *pch, *pwch;
408 size_t sch, swch;
409
410 pch = (char *) &ch;
411 pwch = (char *) &wch;
412 sch = sizeof(ch);
413 swch = sizeof(wch);
414
415 if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
416 fprintf(stderr, "Could not convert 0x%04x from UCS-2 to WCHAR_T: %s\n",
417 ch, strerror(errno));
418 } else {
419 vga_to_curses[glyph].chars[0] = wch;
420 }
421}
422
423/* Setup wchar glyph for one font character */
424static void convert_font(unsigned char ch, iconv_t conv)
425{
426 wchar_t wch;
427 char *pch, *pwch;
428 size_t sch, swch;
429
430 pch = (char *) &ch;
431 pwch = (char *) &wch;
432 sch = sizeof(ch);
433 swch = sizeof(wch);
434
435 if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
436 fprintf(stderr, "Could not convert 0x%02x from %s to WCHAR_T: %s\n",
437 ch, font_charset, strerror(errno));
438 } else {
439 vga_to_curses[ch].chars[0] = wch;
440 }
441}
442
443/* Convert one wchar to UCS-2 */
444static uint16_t get_ucs(wchar_t wch, iconv_t conv)
445{
446 uint16_t ch;
447 char *pch, *pwch;
448 size_t sch, swch;
449
450 pch = (char *) &ch;
451 pwch = (char *) &wch;
452 sch = sizeof(ch);
453 swch = sizeof(wch);
454
455 if (iconv(conv, &pwch, &swch, &pch, &sch) == (size_t) -1) {
e1be9854
GH
456 fprintf(stderr, "Could not convert 0x%02lx from WCHAR_T to UCS-2: %s\n",
457 (unsigned long)wch, strerror(errno));
2f8b7cd5
ST
458 return 0xFFFD;
459 }
460
461 return ch;
462}
463
464/*
465 * Setup mapping for vga to curses line graphics.
466 */
467static void font_setup(void)
468{
469 /*
470 * Control characters are normally non-printable, but VGA does have
471 * well-known glyphs for them.
472 */
473 static uint16_t control_characters[0x20] = {
474 0x0020,
475 0x263a,
476 0x263b,
477 0x2665,
478 0x2666,
479 0x2663,
480 0x2660,
481 0x2022,
482 0x25d8,
483 0x25cb,
484 0x25d9,
485 0x2642,
486 0x2640,
487 0x266a,
488 0x266b,
489 0x263c,
490 0x25ba,
491 0x25c4,
492 0x2195,
493 0x203c,
494 0x00b6,
495 0x00a7,
496 0x25ac,
497 0x21a8,
498 0x2191,
499 0x2193,
500 0x2192,
501 0x2190,
502 0x221f,
503 0x2194,
504 0x25b2,
505 0x25bc
506 };
507
508 iconv_t ucs_to_wchar_conv;
509 iconv_t wchar_to_ucs_conv;
510 iconv_t font_conv;
511 int i;
512
513 ucs_to_wchar_conv = iconv_open("WCHAR_T", "UCS-2");
514 if (ucs_to_wchar_conv == (iconv_t) -1) {
515 fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n",
516 strerror(errno));
517 exit(1);
518 }
519
520 wchar_to_ucs_conv = iconv_open("UCS-2", "WCHAR_T");
521 if (wchar_to_ucs_conv == (iconv_t) -1) {
a9fda247 522 iconv_close(ucs_to_wchar_conv);
2f8b7cd5
ST
523 fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n",
524 strerror(errno));
525 exit(1);
526 }
527
528 font_conv = iconv_open("WCHAR_T", font_charset);
529 if (font_conv == (iconv_t) -1) {
a9fda247
ST
530 iconv_close(ucs_to_wchar_conv);
531 iconv_close(wchar_to_ucs_conv);
2f8b7cd5
ST
532 fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n",
533 font_charset, strerror(errno));
534 exit(1);
535 }
536
537 /* Control characters */
538 for (i = 0; i <= 0x1F; i++) {
539 convert_ucs(i, control_characters[i], ucs_to_wchar_conv);
540 }
541
542 for (i = 0x20; i <= 0xFF; i++) {
543 convert_font(i, font_conv);
544 }
545
546 /* DEL */
547 convert_ucs(0x7F, 0x2302, ucs_to_wchar_conv);
548
549 if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
550 /* Non-Unicode capable, use termcap equivalents for those available */
551 for (i = 0; i <= 0xFF; i++) {
552 switch (get_ucs(vga_to_curses[i].chars[0], wchar_to_ucs_conv)) {
553 case 0x00a3:
554 vga_to_curses[i] = *WACS_STERLING;
555 break;
556 case 0x2591:
557 vga_to_curses[i] = *WACS_BOARD;
558 break;
559 case 0x2592:
560 vga_to_curses[i] = *WACS_CKBOARD;
561 break;
562 case 0x2502:
563 vga_to_curses[i] = *WACS_VLINE;
564 break;
565 case 0x2524:
566 vga_to_curses[i] = *WACS_RTEE;
567 break;
568 case 0x2510:
569 vga_to_curses[i] = *WACS_URCORNER;
570 break;
571 case 0x2514:
572 vga_to_curses[i] = *WACS_LLCORNER;
573 break;
574 case 0x2534:
575 vga_to_curses[i] = *WACS_BTEE;
576 break;
577 case 0x252c:
578 vga_to_curses[i] = *WACS_TTEE;
579 break;
580 case 0x251c:
581 vga_to_curses[i] = *WACS_LTEE;
582 break;
583 case 0x2500:
584 vga_to_curses[i] = *WACS_HLINE;
585 break;
586 case 0x253c:
587 vga_to_curses[i] = *WACS_PLUS;
588 break;
589 case 0x256c:
590 vga_to_curses[i] = *WACS_LANTERN;
591 break;
592 case 0x256a:
593 vga_to_curses[i] = *WACS_NEQUAL;
594 break;
595 case 0x2518:
596 vga_to_curses[i] = *WACS_LRCORNER;
597 break;
598 case 0x250c:
599 vga_to_curses[i] = *WACS_ULCORNER;
600 break;
601 case 0x2588:
602 vga_to_curses[i] = *WACS_BLOCK;
603 break;
604 case 0x03c0:
605 vga_to_curses[i] = *WACS_PI;
606 break;
607 case 0x00b1:
608 vga_to_curses[i] = *WACS_PLMINUS;
609 break;
610 case 0x2265:
611 vga_to_curses[i] = *WACS_GEQUAL;
612 break;
613 case 0x2264:
614 vga_to_curses[i] = *WACS_LEQUAL;
615 break;
616 case 0x00b0:
617 vga_to_curses[i] = *WACS_DEGREE;
618 break;
619 case 0x25a0:
620 vga_to_curses[i] = *WACS_BULLET;
621 break;
622 case 0x2666:
623 vga_to_curses[i] = *WACS_DIAMOND;
624 break;
625 case 0x2192:
626 vga_to_curses[i] = *WACS_RARROW;
627 break;
628 case 0x2190:
629 vga_to_curses[i] = *WACS_LARROW;
630 break;
631 case 0x2191:
632 vga_to_curses[i] = *WACS_UARROW;
633 break;
634 case 0x2193:
635 vga_to_curses[i] = *WACS_DARROW;
636 break;
637 case 0x23ba:
638 vga_to_curses[i] = *WACS_S1;
639 break;
640 case 0x23bb:
641 vga_to_curses[i] = *WACS_S3;
642 break;
643 case 0x23bc:
644 vga_to_curses[i] = *WACS_S7;
645 break;
646 case 0x23bd:
647 vga_to_curses[i] = *WACS_S9;
648 break;
649 }
650 }
651 }
a9fda247
ST
652 iconv_close(ucs_to_wchar_conv);
653 iconv_close(wchar_to_ucs_conv);
654 iconv_close(font_conv);
2f8b7cd5
ST
655}
656
4d3b6f6e
AZ
657static void curses_setup(void)
658{
659 int i, colour_default[8] = {
4083733d
OH
660 [QEMU_COLOR_BLACK] = COLOR_BLACK,
661 [QEMU_COLOR_BLUE] = COLOR_BLUE,
662 [QEMU_COLOR_GREEN] = COLOR_GREEN,
663 [QEMU_COLOR_CYAN] = COLOR_CYAN,
664 [QEMU_COLOR_RED] = COLOR_RED,
665 [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA,
666 [QEMU_COLOR_YELLOW] = COLOR_YELLOW,
667 [QEMU_COLOR_WHITE] = COLOR_WHITE,
4d3b6f6e
AZ
668 };
669
670 /* input as raw as possible, let everything be interpreted
671 * by the guest system */
672 initscr(); noecho(); intrflush(stdscr, FALSE);
673 nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
674 start_color(); raw(); scrollok(stdscr, FALSE);
633786fe 675 set_escdelay(25);
4d3b6f6e 676
4083733d 677 /* Make color pair to match color format (3bits bg:3bits fg) */
615220dd 678 for (i = 0; i < 64; i++) {
4d3b6f6e 679 init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
615220dd 680 }
4083733d 681 /* Set default color for more than 64 for safety. */
615220dd
OH
682 for (i = 64; i < COLOR_PAIRS; i++) {
683 init_pair(i, COLOR_WHITE, COLOR_BLACK);
684 }
e2368dc9 685
2f8b7cd5 686 font_setup();
4d3b6f6e
AZ
687}
688
689static void curses_keyboard_setup(void)
690{
4d3b6f6e
AZ
691#if defined(__APPLE__)
692 /* always use generic keymaps */
693 if (!keyboard_layout)
694 keyboard_layout = "en-us";
695#endif
696 if(keyboard_layout) {
ab4f931e
FL
697 kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
698 &error_fatal);
4d3b6f6e 699 }
4d3b6f6e
AZ
700}
701
7c20b4a3
GH
702static const DisplayChangeListenerOps dcl_ops = {
703 .dpy_name = "curses",
704 .dpy_text_update = curses_update,
705 .dpy_text_resize = curses_resize,
706 .dpy_refresh = curses_refresh,
707 .dpy_text_cursor = curses_cursor_position,
708};
709
b0766612 710static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
4d3b6f6e
AZ
711{
712#ifndef _WIN32
713 if (!isatty(1)) {
714 fprintf(stderr, "We need a terminal output\n");
715 exit(1);
716 }
717#endif
718
2f8b7cd5
ST
719 setlocale(LC_CTYPE, "");
720 if (opts->u.curses.charset) {
721 font_charset = opts->u.curses.charset;
722 }
4d3b6f6e
AZ
723 curses_setup();
724 curses_keyboard_setup();
28695489 725 atexit(curses_atexit);
4d3b6f6e 726
032ac6f8 727 curses_winch_init();
4d3b6f6e 728
fedf0d35 729 dcl = g_new0(DisplayChangeListener, 1);
7c20b4a3 730 dcl->ops = &dcl_ops;
5209089f 731 register_displaychangelistener(dcl);
4d3b6f6e
AZ
732
733 invalidate = 1;
4d3b6f6e 734}
b0766612
GH
735
736static QemuDisplay qemu_display_curses = {
737 .type = DISPLAY_TYPE_CURSES,
738 .init = curses_display_init,
739};
740
741static void register_curses(void)
742{
743 qemu_display_register(&qemu_display_curses);
744}
745
746type_init(register_curses);