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