13e230dd2SCorentin Chary /* 23e230dd2SCorentin Chary * QEMU curses/ncurses display driver 33e230dd2SCorentin Chary * 43e230dd2SCorentin Chary * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org> 53e230dd2SCorentin Chary * 63e230dd2SCorentin Chary * Permission is hereby granted, free of charge, to any person obtaining a copy 73e230dd2SCorentin Chary * of this software and associated documentation files (the "Software"), to deal 83e230dd2SCorentin Chary * in the Software without restriction, including without limitation the rights 93e230dd2SCorentin Chary * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 103e230dd2SCorentin Chary * copies of the Software, and to permit persons to whom the Software is 113e230dd2SCorentin Chary * furnished to do so, subject to the following conditions: 123e230dd2SCorentin Chary * 133e230dd2SCorentin Chary * The above copyright notice and this permission notice shall be included in 143e230dd2SCorentin Chary * all copies or substantial portions of the Software. 153e230dd2SCorentin Chary * 163e230dd2SCorentin Chary * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 173e230dd2SCorentin Chary * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 183e230dd2SCorentin Chary * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 193e230dd2SCorentin Chary * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 203e230dd2SCorentin Chary * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 213e230dd2SCorentin Chary * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 223e230dd2SCorentin Chary * THE SOFTWARE. 233e230dd2SCorentin Chary */ 240b8fa32fSMarkus Armbruster 25e16f4c87SPeter Maydell #include "qemu/osdep.h" 263e230dd2SCorentin Chary 273e230dd2SCorentin Chary #ifndef _WIN32 283e230dd2SCorentin Chary #include <sys/ioctl.h> 293e230dd2SCorentin Chary #include <termios.h> 303e230dd2SCorentin Chary #endif 312f8b7cd5SSamuel Thibault #include <locale.h> 322f8b7cd5SSamuel Thibault #include <wchar.h> 332f8b7cd5SSamuel Thibault #include <langinfo.h> 342f8b7cd5SSamuel Thibault #include <iconv.h> 353e230dd2SCorentin Chary 36ab4f931eSFei Li #include "qapi/error.h" 370b8fa32fSMarkus Armbruster #include "qemu/module.h" 3828ecbaeeSPaolo Bonzini #include "ui/console.h" 39cd100328SGerd Hoffmann #include "ui/input.h" 409c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 413e230dd2SCorentin Chary 42e2f82e92SGerd Hoffmann /* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */ 43e2f82e92SGerd Hoffmann #undef KEY_EVENT 44e2f82e92SGerd Hoffmann #include <curses.h> 45e2f82e92SGerd Hoffmann #undef KEY_EVENT 46e2f82e92SGerd Hoffmann 473e230dd2SCorentin Chary #define FONT_HEIGHT 16 483e230dd2SCorentin Chary #define FONT_WIDTH 8 493e230dd2SCorentin Chary 50459a707eSSamuel Thibault enum maybe_keycode { 51459a707eSSamuel Thibault CURSES_KEYCODE, 52459a707eSSamuel Thibault CURSES_CHAR, 53459a707eSSamuel Thibault CURSES_CHAR_OR_KEYCODE, 54459a707eSSamuel Thibault }; 55459a707eSSamuel Thibault 567c20b4a3SGerd Hoffmann static DisplayChangeListener *dcl; 57*76c51fc3SPhilippe Mathieu-Daudé static console_ch_t *screen; 583e230dd2SCorentin Chary static WINDOW *screenpad = NULL; 593e230dd2SCorentin Chary static int width, height, gwidth, gheight, invalidate; 603e230dd2SCorentin Chary static int px, py, sminx, sminy, smaxx, smaxy; 613e230dd2SCorentin Chary 622f8b7cd5SSamuel Thibault static const char *font_charset = "CP437"; 63*76c51fc3SPhilippe Mathieu-Daudé static cchar_t *vga_to_curses; 64e2368dc9SOGAWA Hirofumi 657c20b4a3SGerd Hoffmann static void curses_update(DisplayChangeListener *dcl, 667c20b4a3SGerd Hoffmann int x, int y, int w, int h) 673e230dd2SCorentin Chary { 68e2f82e92SGerd Hoffmann console_ch_t *line; 692f8b7cd5SSamuel Thibault cchar_t curses_line[width]; 70962cf8fdSSamuel Thibault wchar_t wch[CCHARW_MAX]; 71962cf8fdSSamuel Thibault attr_t attrs; 72962cf8fdSSamuel Thibault short colors; 73962cf8fdSSamuel Thibault int ret; 743e230dd2SCorentin Chary 75e2f82e92SGerd Hoffmann line = screen + y * width; 76e2f82e92SGerd Hoffmann for (h += y; y < h; y ++, line += width) { 77e2f82e92SGerd Hoffmann for (x = 0; x < width; x++) { 78cd54ea45SMatthew Kilgore chtype ch = line[x] & A_CHARTEXT; 79cd54ea45SMatthew Kilgore chtype at = line[x] & A_ATTRIBUTES; 8030f5a9ddSMatthew Kilgore short color_pair = PAIR_NUMBER(line[x]); 8130f5a9ddSMatthew Kilgore 82962cf8fdSSamuel Thibault ret = getcchar(&vga_to_curses[ch], wch, &attrs, &colors, NULL); 83962cf8fdSSamuel Thibault if (ret == ERR || wch[0] == 0) { 84962cf8fdSSamuel Thibault wch[0] = ch; 85962cf8fdSSamuel Thibault wch[1] = 0; 86e2f82e92SGerd Hoffmann } 8730f5a9ddSMatthew Kilgore setcchar(&curses_line[x], wch, at, color_pair, NULL); 88e2f82e92SGerd Hoffmann } 892f8b7cd5SSamuel Thibault mvwadd_wchnstr(screenpad, y, 0, curses_line, width); 90e2f82e92SGerd Hoffmann } 913e230dd2SCorentin Chary 923e230dd2SCorentin Chary pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); 933e230dd2SCorentin Chary refresh(); 943e230dd2SCorentin Chary } 953e230dd2SCorentin Chary 963e230dd2SCorentin Chary static void curses_calc_pad(void) 973e230dd2SCorentin Chary { 9881c0d5a6SGerd Hoffmann if (qemu_console_is_fixedsize(NULL)) { 993e230dd2SCorentin Chary width = gwidth; 1003e230dd2SCorentin Chary height = gheight; 1013e230dd2SCorentin Chary } else { 1023e230dd2SCorentin Chary width = COLS; 1033e230dd2SCorentin Chary height = LINES; 1043e230dd2SCorentin Chary } 1053e230dd2SCorentin Chary 1063e230dd2SCorentin Chary if (screenpad) 1073e230dd2SCorentin Chary delwin(screenpad); 1083e230dd2SCorentin Chary 1093e230dd2SCorentin Chary clear(); 1103e230dd2SCorentin Chary refresh(); 1113e230dd2SCorentin Chary 1123e230dd2SCorentin Chary screenpad = newpad(height, width); 1133e230dd2SCorentin Chary 1143e230dd2SCorentin Chary if (width > COLS) { 1153e230dd2SCorentin Chary px = (width - COLS) / 2; 1163e230dd2SCorentin Chary sminx = 0; 1173e230dd2SCorentin Chary smaxx = COLS; 1183e230dd2SCorentin Chary } else { 1193e230dd2SCorentin Chary px = 0; 1203e230dd2SCorentin Chary sminx = (COLS - width) / 2; 1213e230dd2SCorentin Chary smaxx = sminx + width; 1223e230dd2SCorentin Chary } 1233e230dd2SCorentin Chary 1243e230dd2SCorentin Chary if (height > LINES) { 1253e230dd2SCorentin Chary py = (height - LINES) / 2; 1263e230dd2SCorentin Chary sminy = 0; 1273e230dd2SCorentin Chary smaxy = LINES; 1283e230dd2SCorentin Chary } else { 1293e230dd2SCorentin Chary py = 0; 1303e230dd2SCorentin Chary sminy = (LINES - height) / 2; 1313e230dd2SCorentin Chary smaxy = sminy + height; 1323e230dd2SCorentin Chary } 1333e230dd2SCorentin Chary } 1343e230dd2SCorentin Chary 1357c20b4a3SGerd Hoffmann static void curses_resize(DisplayChangeListener *dcl, 1367c20b4a3SGerd Hoffmann int width, int height) 1373e230dd2SCorentin Chary { 138a93a4a22SGerd Hoffmann if (width == gwidth && height == gheight) { 1393e230dd2SCorentin Chary return; 140a93a4a22SGerd Hoffmann } 1413e230dd2SCorentin Chary 142a93a4a22SGerd Hoffmann gwidth = width; 143a93a4a22SGerd Hoffmann gheight = height; 1443e230dd2SCorentin Chary 1453e230dd2SCorentin Chary curses_calc_pad(); 1463e230dd2SCorentin Chary } 1473e230dd2SCorentin Chary 148032ac6f8SGerd Hoffmann #if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE) 149032ac6f8SGerd Hoffmann static volatile sig_atomic_t got_sigwinch; 150032ac6f8SGerd Hoffmann static void curses_winch_check(void) 1513e230dd2SCorentin Chary { 1523e230dd2SCorentin Chary struct winsize { 1533e230dd2SCorentin Chary unsigned short ws_row; 1543e230dd2SCorentin Chary unsigned short ws_col; 1553e230dd2SCorentin Chary unsigned short ws_xpixel; /* unused */ 1563e230dd2SCorentin Chary unsigned short ws_ypixel; /* unused */ 1573e230dd2SCorentin Chary } ws; 1583e230dd2SCorentin Chary 159032ac6f8SGerd Hoffmann if (!got_sigwinch) { 1603e230dd2SCorentin Chary return; 161032ac6f8SGerd Hoffmann } 162032ac6f8SGerd Hoffmann got_sigwinch = false; 163032ac6f8SGerd Hoffmann 164032ac6f8SGerd Hoffmann if (ioctl(1, TIOCGWINSZ, &ws) == -1) { 165032ac6f8SGerd Hoffmann return; 166032ac6f8SGerd Hoffmann } 1673e230dd2SCorentin Chary 1683e230dd2SCorentin Chary resize_term(ws.ws_row, ws.ws_col); 1693e230dd2SCorentin Chary invalidate = 1; 1703e230dd2SCorentin Chary } 171032ac6f8SGerd Hoffmann 172032ac6f8SGerd Hoffmann static void curses_winch_handler(int signum) 173032ac6f8SGerd Hoffmann { 174032ac6f8SGerd Hoffmann got_sigwinch = true; 175032ac6f8SGerd Hoffmann } 176032ac6f8SGerd Hoffmann 177032ac6f8SGerd Hoffmann static void curses_winch_init(void) 178032ac6f8SGerd Hoffmann { 179032ac6f8SGerd Hoffmann struct sigaction old, winch = { 180032ac6f8SGerd Hoffmann .sa_handler = curses_winch_handler, 181032ac6f8SGerd Hoffmann }; 182032ac6f8SGerd Hoffmann sigaction(SIGWINCH, &winch, &old); 183032ac6f8SGerd Hoffmann } 184032ac6f8SGerd Hoffmann #else 185032ac6f8SGerd Hoffmann static void curses_winch_check(void) {} 186032ac6f8SGerd Hoffmann static void curses_winch_init(void) {} 1873e230dd2SCorentin Chary #endif 1883e230dd2SCorentin Chary 1897c20b4a3SGerd Hoffmann static void curses_cursor_position(DisplayChangeListener *dcl, 1907c20b4a3SGerd Hoffmann int x, int y) 1913e230dd2SCorentin Chary { 1923e230dd2SCorentin Chary if (x >= 0) { 1933e230dd2SCorentin Chary x = sminx + x - px; 1943e230dd2SCorentin Chary y = sminy + y - py; 1953e230dd2SCorentin Chary 1963e230dd2SCorentin Chary if (x >= 0 && y >= 0 && x < COLS && y < LINES) { 1973e230dd2SCorentin Chary move(y, x); 1983e230dd2SCorentin Chary curs_set(1); 1993e230dd2SCorentin Chary /* it seems that curs_set(1) must always be called before 2003e230dd2SCorentin Chary * curs_set(2) for the latter to have effect */ 20181c0d5a6SGerd Hoffmann if (!qemu_console_is_graphic(NULL)) { 2023e230dd2SCorentin Chary curs_set(2); 20381c0d5a6SGerd Hoffmann } 2043e230dd2SCorentin Chary return; 2053e230dd2SCorentin Chary } 2063e230dd2SCorentin Chary } 2073e230dd2SCorentin Chary 2083e230dd2SCorentin Chary curs_set(0); 2093e230dd2SCorentin Chary } 2103e230dd2SCorentin Chary 2113e230dd2SCorentin Chary /* generic keyboard conversion */ 2123e230dd2SCorentin Chary 2133e230dd2SCorentin Chary #include "curses_keys.h" 2143e230dd2SCorentin Chary 2153e230dd2SCorentin Chary static kbd_layout_t *kbd_layout = NULL; 2163e230dd2SCorentin Chary 217459a707eSSamuel Thibault static wint_t console_getch(enum maybe_keycode *maybe_keycode) 218459a707eSSamuel Thibault { 219459a707eSSamuel Thibault wint_t ret; 220459a707eSSamuel Thibault switch (get_wch(&ret)) { 221459a707eSSamuel Thibault case KEY_CODE_YES: 222459a707eSSamuel Thibault *maybe_keycode = CURSES_KEYCODE; 223459a707eSSamuel Thibault break; 224459a707eSSamuel Thibault case OK: 225459a707eSSamuel Thibault *maybe_keycode = CURSES_CHAR; 226459a707eSSamuel Thibault break; 227459a707eSSamuel Thibault case ERR: 228459a707eSSamuel Thibault ret = -1; 229459a707eSSamuel Thibault break; 23068097ed5SPaolo Bonzini default: 23168097ed5SPaolo Bonzini abort(); 232459a707eSSamuel Thibault } 233459a707eSSamuel Thibault return ret; 234459a707eSSamuel Thibault } 235459a707eSSamuel Thibault 236459a707eSSamuel Thibault static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], 237459a707eSSamuel Thibault int chr, enum maybe_keycode maybe_keycode) 238459a707eSSamuel Thibault { 239459a707eSSamuel Thibault int ret = -1; 240459a707eSSamuel Thibault if (maybe_keycode == CURSES_CHAR) { 241459a707eSSamuel Thibault if (chr < CURSES_CHARS) { 242459a707eSSamuel Thibault ret = _curses2foo[chr]; 243459a707eSSamuel Thibault } 244459a707eSSamuel Thibault } else { 245459a707eSSamuel Thibault if (chr < CURSES_KEYS) { 246459a707eSSamuel Thibault ret = _curseskey2foo[chr]; 247459a707eSSamuel Thibault } 248459a707eSSamuel Thibault if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE && 249459a707eSSamuel Thibault chr < CURSES_CHARS) { 250459a707eSSamuel Thibault ret = _curses2foo[chr]; 251459a707eSSamuel Thibault } 252459a707eSSamuel Thibault } 253459a707eSSamuel Thibault return ret; 254459a707eSSamuel Thibault } 255459a707eSSamuel Thibault 256459a707eSSamuel Thibault #define curses2keycode(chr, maybe_keycode) \ 257459a707eSSamuel Thibault curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) 258459a707eSSamuel Thibault #define curses2keysym(chr, maybe_keycode) \ 259459a707eSSamuel Thibault curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode) 260459a707eSSamuel Thibault #define curses2qemu(chr, maybe_keycode) \ 261459a707eSSamuel Thibault curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode) 262459a707eSSamuel Thibault 263bc2ed970SGerd Hoffmann static void curses_refresh(DisplayChangeListener *dcl) 2643e230dd2SCorentin Chary { 26599a9ef44SPeter Maydell int chr, keysym, keycode, keycode_alt; 266459a707eSSamuel Thibault enum maybe_keycode maybe_keycode; 2673e230dd2SCorentin Chary 268032ac6f8SGerd Hoffmann curses_winch_check(); 269032ac6f8SGerd Hoffmann 2703e230dd2SCorentin Chary if (invalidate) { 2713e230dd2SCorentin Chary clear(); 2723e230dd2SCorentin Chary refresh(); 2733e230dd2SCorentin Chary curses_calc_pad(); 2741dbfa005SGerd Hoffmann graphic_hw_invalidate(NULL); 2753e230dd2SCorentin Chary invalidate = 0; 2763e230dd2SCorentin Chary } 2773e230dd2SCorentin Chary 2781dbfa005SGerd Hoffmann graphic_hw_text_update(NULL, screen); 2793e230dd2SCorentin Chary 2803e230dd2SCorentin Chary while (1) { 2813e230dd2SCorentin Chary /* while there are any pending key strokes to process */ 282459a707eSSamuel Thibault chr = console_getch(&maybe_keycode); 2833e230dd2SCorentin Chary 284459a707eSSamuel Thibault if (chr == -1) 2853e230dd2SCorentin Chary break; 2863e230dd2SCorentin Chary 2873e230dd2SCorentin Chary #ifdef KEY_RESIZE 2883e230dd2SCorentin Chary /* this shouldn't occur when we use a custom SIGWINCH handler */ 289459a707eSSamuel Thibault if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) { 2903e230dd2SCorentin Chary clear(); 2913e230dd2SCorentin Chary refresh(); 2923e230dd2SCorentin Chary curses_calc_pad(); 293bc2ed970SGerd Hoffmann curses_update(dcl, 0, 0, width, height); 2943e230dd2SCorentin Chary continue; 2953e230dd2SCorentin Chary } 2963e230dd2SCorentin Chary #endif 2973e230dd2SCorentin Chary 298459a707eSSamuel Thibault keycode = curses2keycode(chr, maybe_keycode); 2993e230dd2SCorentin Chary keycode_alt = 0; 3003e230dd2SCorentin Chary 301633786feSSamuel Thibault /* alt or esc key */ 3023e230dd2SCorentin Chary if (keycode == 1) { 303459a707eSSamuel Thibault enum maybe_keycode next_maybe_keycode; 304459a707eSSamuel Thibault int nextchr = console_getch(&next_maybe_keycode); 3053e230dd2SCorentin Chary 306459a707eSSamuel Thibault if (nextchr != -1) { 3073e230dd2SCorentin Chary chr = nextchr; 308459a707eSSamuel Thibault maybe_keycode = next_maybe_keycode; 3093e230dd2SCorentin Chary keycode_alt = ALT; 310459a707eSSamuel Thibault keycode = curses2keycode(chr, maybe_keycode); 3113e230dd2SCorentin Chary 3123e230dd2SCorentin Chary if (keycode != -1) { 3133e230dd2SCorentin Chary keycode |= ALT; 3143e230dd2SCorentin Chary 3153e230dd2SCorentin Chary /* process keys reserved for qemu */ 3163e230dd2SCorentin Chary if (keycode >= QEMU_KEY_CONSOLE0 && 3173e230dd2SCorentin Chary keycode < QEMU_KEY_CONSOLE0 + 9) { 3183e230dd2SCorentin Chary erase(); 3193e230dd2SCorentin Chary wnoutrefresh(stdscr); 3203e230dd2SCorentin Chary console_select(keycode - QEMU_KEY_CONSOLE0); 3213e230dd2SCorentin Chary 3223e230dd2SCorentin Chary invalidate = 1; 3233e230dd2SCorentin Chary continue; 3243e230dd2SCorentin Chary } 3253e230dd2SCorentin Chary } 3263e230dd2SCorentin Chary } 3273e230dd2SCorentin Chary } 3283e230dd2SCorentin Chary 3293e230dd2SCorentin Chary if (kbd_layout) { 330459a707eSSamuel Thibault keysym = curses2keysym(chr, maybe_keycode); 3313e230dd2SCorentin Chary 3323e230dd2SCorentin Chary if (keysym == -1) { 333d03703c8SSamuel Thibault if (chr < ' ') { 334d03703c8SSamuel Thibault keysym = chr + '@'; 335d03703c8SSamuel Thibault if (keysym >= 'A' && keysym <= 'Z') 336d03703c8SSamuel Thibault keysym += 'a' - 'A'; 337d03703c8SSamuel Thibault keysym |= KEYSYM_CNTRL; 338d03703c8SSamuel Thibault } else 3393e230dd2SCorentin Chary keysym = chr; 3403e230dd2SCorentin Chary } 3413e230dd2SCorentin Chary 342abb4f2c9SGerd Hoffmann keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK, 34319c1b9fdSGerd Hoffmann NULL, false); 3443e230dd2SCorentin Chary if (keycode == 0) 3453e230dd2SCorentin Chary continue; 3463e230dd2SCorentin Chary 3473e230dd2SCorentin Chary keycode |= (keysym & ~KEYSYM_MASK) >> 16; 3483e230dd2SCorentin Chary keycode |= keycode_alt; 3493e230dd2SCorentin Chary } 3503e230dd2SCorentin Chary 3513e230dd2SCorentin Chary if (keycode == -1) 3523e230dd2SCorentin Chary continue; 3533e230dd2SCorentin Chary 35481c0d5a6SGerd Hoffmann if (qemu_console_is_graphic(NULL)) { 3553e230dd2SCorentin Chary /* since terminals don't know about key press and release 3563e230dd2SCorentin Chary * events, we need to emit both for each key received */ 357cd100328SGerd Hoffmann if (keycode & SHIFT) { 358cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, SHIFT_CODE, true); 3595a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 3603e230dd2SCorentin Chary } 361cd100328SGerd Hoffmann if (keycode & CNTRL) { 362cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, CNTRL_CODE, true); 3635a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 3643e230dd2SCorentin Chary } 365cd100328SGerd Hoffmann if (keycode & ALT) { 366cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, ALT_CODE, true); 3675a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 368cd100328SGerd Hoffmann } 369cd100328SGerd Hoffmann if (keycode & ALTGR) { 370cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); 3715a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 372cd100328SGerd Hoffmann } 373cd100328SGerd Hoffmann 374f5c0ab13SAndrew Oates qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true); 3755a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 376f5c0ab13SAndrew Oates qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false); 3775a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 378cd100328SGerd Hoffmann 379cd100328SGerd Hoffmann if (keycode & ALTGR) { 380cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); 3815a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 382cd100328SGerd Hoffmann } 383cd100328SGerd Hoffmann if (keycode & ALT) { 384cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, ALT_CODE, false); 3855a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 386cd100328SGerd Hoffmann } 387cd100328SGerd Hoffmann if (keycode & CNTRL) { 388cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, CNTRL_CODE, false); 3895a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 390cd100328SGerd Hoffmann } 391cd100328SGerd Hoffmann if (keycode & SHIFT) { 392cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, SHIFT_CODE, false); 3935a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 394cd100328SGerd Hoffmann } 3953e230dd2SCorentin Chary } else { 396459a707eSSamuel Thibault keysym = curses2qemu(chr, maybe_keycode); 3973e230dd2SCorentin Chary if (keysym == -1) 3983e230dd2SCorentin Chary keysym = chr; 3993e230dd2SCorentin Chary 4003e230dd2SCorentin Chary kbd_put_keysym(keysym); 4013e230dd2SCorentin Chary } 4023e230dd2SCorentin Chary } 4033e230dd2SCorentin Chary } 4043e230dd2SCorentin Chary 4053e230dd2SCorentin Chary static void curses_atexit(void) 4063e230dd2SCorentin Chary { 4073e230dd2SCorentin Chary endwin(); 408*76c51fc3SPhilippe Mathieu-Daudé g_free(vga_to_curses); 409*76c51fc3SPhilippe Mathieu-Daudé g_free(screen); 4103e230dd2SCorentin Chary } 4113e230dd2SCorentin Chary 412b7b664a4SSamuel Thibault /* 413b7b664a4SSamuel Thibault * In the following: 414b7b664a4SSamuel Thibault * - fch is the font glyph number 415b7b664a4SSamuel Thibault * - uch is the unicode value 416b7b664a4SSamuel Thibault * - wch is the wchar_t value (may not be unicode, e.g. on BSD/solaris) 417b7b664a4SSamuel Thibault * - mbch is the native local-dependent multibyte representation 418b7b664a4SSamuel Thibault */ 419b7b664a4SSamuel Thibault 4202f8b7cd5SSamuel Thibault /* Setup wchar glyph for one UCS-2 char */ 421b7b664a4SSamuel Thibault static void convert_ucs(unsigned char fch, uint16_t uch, iconv_t conv) 4222f8b7cd5SSamuel Thibault { 423b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 424962cf8fdSSamuel Thibault wchar_t wch[2]; 425b7b664a4SSamuel Thibault char *puch, *pmbch; 426b7b664a4SSamuel Thibault size_t such, smbch; 427b7b664a4SSamuel Thibault mbstate_t ps; 4282f8b7cd5SSamuel Thibault 429b7b664a4SSamuel Thibault puch = (char *) &uch; 430b7b664a4SSamuel Thibault pmbch = (char *) mbch; 431b7b664a4SSamuel Thibault such = sizeof(uch); 432b7b664a4SSamuel Thibault smbch = sizeof(mbch); 4332f8b7cd5SSamuel Thibault 434b7b664a4SSamuel Thibault if (iconv(conv, &puch, &such, &pmbch, &smbch) == (size_t) -1) { 435b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 436b7b664a4SSamuel Thibault "from UCS-2 to a multibyte character: %s\n", 437b7b664a4SSamuel Thibault uch, strerror(errno)); 438b7b664a4SSamuel Thibault return; 4392f8b7cd5SSamuel Thibault } 440b7b664a4SSamuel Thibault 441b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 442962cf8fdSSamuel Thibault if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) { 443b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 444b7b664a4SSamuel Thibault "from a multibyte character to wchar_t: %s\n", 445b7b664a4SSamuel Thibault uch, strerror(errno)); 446b7b664a4SSamuel Thibault return; 447b7b664a4SSamuel Thibault } 448962cf8fdSSamuel Thibault 449962cf8fdSSamuel Thibault wch[1] = 0; 450962cf8fdSSamuel Thibault setcchar(&vga_to_curses[fch], wch, 0, 0, NULL); 4512f8b7cd5SSamuel Thibault } 4522f8b7cd5SSamuel Thibault 4532f8b7cd5SSamuel Thibault /* Setup wchar glyph for one font character */ 454b7b664a4SSamuel Thibault static void convert_font(unsigned char fch, iconv_t conv) 4552f8b7cd5SSamuel Thibault { 456b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 457962cf8fdSSamuel Thibault wchar_t wch[2]; 458b7b664a4SSamuel Thibault char *pfch, *pmbch; 459b7b664a4SSamuel Thibault size_t sfch, smbch; 460b7b664a4SSamuel Thibault mbstate_t ps; 4612f8b7cd5SSamuel Thibault 462b7b664a4SSamuel Thibault pfch = (char *) &fch; 463b7b664a4SSamuel Thibault pmbch = (char *) &mbch; 464b7b664a4SSamuel Thibault sfch = sizeof(fch); 465b7b664a4SSamuel Thibault smbch = sizeof(mbch); 4662f8b7cd5SSamuel Thibault 467b7b664a4SSamuel Thibault if (iconv(conv, &pfch, &sfch, &pmbch, &smbch) == (size_t) -1) { 468b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert font glyph 0x%02x " 469b7b664a4SSamuel Thibault "from %s to a multibyte character: %s\n", 470b7b664a4SSamuel Thibault fch, font_charset, strerror(errno)); 471b7b664a4SSamuel Thibault return; 4722f8b7cd5SSamuel Thibault } 473b7b664a4SSamuel Thibault 474b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 475962cf8fdSSamuel Thibault if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) { 476b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert font glyph 0x%02x " 477b7b664a4SSamuel Thibault "from a multibyte character to wchar_t: %s\n", 478b7b664a4SSamuel Thibault fch, strerror(errno)); 479b7b664a4SSamuel Thibault return; 480b7b664a4SSamuel Thibault } 481962cf8fdSSamuel Thibault 482962cf8fdSSamuel Thibault wch[1] = 0; 483962cf8fdSSamuel Thibault setcchar(&vga_to_curses[fch], wch, 0, 0, NULL); 4842f8b7cd5SSamuel Thibault } 4852f8b7cd5SSamuel Thibault 4862f8b7cd5SSamuel Thibault /* Convert one wchar to UCS-2 */ 4872f8b7cd5SSamuel Thibault static uint16_t get_ucs(wchar_t wch, iconv_t conv) 4882f8b7cd5SSamuel Thibault { 489b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 490b7b664a4SSamuel Thibault uint16_t uch; 491b7b664a4SSamuel Thibault char *pmbch, *puch; 492b7b664a4SSamuel Thibault size_t smbch, such; 493b7b664a4SSamuel Thibault mbstate_t ps; 494b7b664a4SSamuel Thibault int ret; 4952f8b7cd5SSamuel Thibault 496b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 497b7b664a4SSamuel Thibault ret = wcrtomb(mbch, wch, &ps); 498b7b664a4SSamuel Thibault if (ret == -1) { 499dc3c871aSMax Reitz fprintf(stderr, "Could not convert 0x%04lx " 500b7b664a4SSamuel Thibault "from wchar_t to a multibyte character: %s\n", 501dc3c871aSMax Reitz (unsigned long)wch, strerror(errno)); 5022f8b7cd5SSamuel Thibault return 0xFFFD; 5032f8b7cd5SSamuel Thibault } 5042f8b7cd5SSamuel Thibault 505b7b664a4SSamuel Thibault pmbch = (char *) mbch; 506b7b664a4SSamuel Thibault puch = (char *) &uch; 507b7b664a4SSamuel Thibault smbch = ret; 508b7b664a4SSamuel Thibault such = sizeof(uch); 509b7b664a4SSamuel Thibault 510b7b664a4SSamuel Thibault if (iconv(conv, &pmbch, &smbch, &puch, &such) == (size_t) -1) { 511dc3c871aSMax Reitz fprintf(stderr, "Could not convert 0x%04lx " 512b7b664a4SSamuel Thibault "from a multibyte character to UCS-2 : %s\n", 513dc3c871aSMax Reitz (unsigned long)wch, strerror(errno)); 514b7b664a4SSamuel Thibault return 0xFFFD; 515b7b664a4SSamuel Thibault } 516b7b664a4SSamuel Thibault 517b7b664a4SSamuel Thibault return uch; 5182f8b7cd5SSamuel Thibault } 5192f8b7cd5SSamuel Thibault 5202f8b7cd5SSamuel Thibault /* 5212f8b7cd5SSamuel Thibault * Setup mapping for vga to curses line graphics. 5222f8b7cd5SSamuel Thibault */ 5232f8b7cd5SSamuel Thibault static void font_setup(void) 5242f8b7cd5SSamuel Thibault { 525b7b664a4SSamuel Thibault iconv_t ucs2_to_nativecharset; 526b7b664a4SSamuel Thibault iconv_t nativecharset_to_ucs2; 527b7b664a4SSamuel Thibault iconv_t font_conv; 528b7b664a4SSamuel Thibault int i; 529b7b664a4SSamuel Thibault 5302f8b7cd5SSamuel Thibault /* 5312f8b7cd5SSamuel Thibault * Control characters are normally non-printable, but VGA does have 5322f8b7cd5SSamuel Thibault * well-known glyphs for them. 5332f8b7cd5SSamuel Thibault */ 53480e8c2edSPhilippe Mathieu-Daudé static const uint16_t control_characters[0x20] = { 5352f8b7cd5SSamuel Thibault 0x0020, 5362f8b7cd5SSamuel Thibault 0x263a, 5372f8b7cd5SSamuel Thibault 0x263b, 5382f8b7cd5SSamuel Thibault 0x2665, 5392f8b7cd5SSamuel Thibault 0x2666, 5402f8b7cd5SSamuel Thibault 0x2663, 5412f8b7cd5SSamuel Thibault 0x2660, 5422f8b7cd5SSamuel Thibault 0x2022, 5432f8b7cd5SSamuel Thibault 0x25d8, 5442f8b7cd5SSamuel Thibault 0x25cb, 5452f8b7cd5SSamuel Thibault 0x25d9, 5462f8b7cd5SSamuel Thibault 0x2642, 5472f8b7cd5SSamuel Thibault 0x2640, 5482f8b7cd5SSamuel Thibault 0x266a, 5492f8b7cd5SSamuel Thibault 0x266b, 5502f8b7cd5SSamuel Thibault 0x263c, 5512f8b7cd5SSamuel Thibault 0x25ba, 5522f8b7cd5SSamuel Thibault 0x25c4, 5532f8b7cd5SSamuel Thibault 0x2195, 5542f8b7cd5SSamuel Thibault 0x203c, 5552f8b7cd5SSamuel Thibault 0x00b6, 5562f8b7cd5SSamuel Thibault 0x00a7, 5572f8b7cd5SSamuel Thibault 0x25ac, 5582f8b7cd5SSamuel Thibault 0x21a8, 5592f8b7cd5SSamuel Thibault 0x2191, 5602f8b7cd5SSamuel Thibault 0x2193, 5612f8b7cd5SSamuel Thibault 0x2192, 5622f8b7cd5SSamuel Thibault 0x2190, 5632f8b7cd5SSamuel Thibault 0x221f, 5642f8b7cd5SSamuel Thibault 0x2194, 5652f8b7cd5SSamuel Thibault 0x25b2, 5662f8b7cd5SSamuel Thibault 0x25bc 5672f8b7cd5SSamuel Thibault }; 5682f8b7cd5SSamuel Thibault 569b7b664a4SSamuel Thibault ucs2_to_nativecharset = iconv_open(nl_langinfo(CODESET), "UCS-2"); 570b7b664a4SSamuel Thibault if (ucs2_to_nativecharset == (iconv_t) -1) { 5712f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n", 5722f8b7cd5SSamuel Thibault strerror(errno)); 5732f8b7cd5SSamuel Thibault exit(1); 5742f8b7cd5SSamuel Thibault } 5752f8b7cd5SSamuel Thibault 576b7b664a4SSamuel Thibault nativecharset_to_ucs2 = iconv_open("UCS-2", nl_langinfo(CODESET)); 577b7b664a4SSamuel Thibault if (nativecharset_to_ucs2 == (iconv_t) -1) { 578b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 5792f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n", 5802f8b7cd5SSamuel Thibault strerror(errno)); 5812f8b7cd5SSamuel Thibault exit(1); 5822f8b7cd5SSamuel Thibault } 5832f8b7cd5SSamuel Thibault 584b7b664a4SSamuel Thibault font_conv = iconv_open(nl_langinfo(CODESET), font_charset); 5852f8b7cd5SSamuel Thibault if (font_conv == (iconv_t) -1) { 586b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 587b7b664a4SSamuel Thibault iconv_close(nativecharset_to_ucs2); 5882f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n", 5892f8b7cd5SSamuel Thibault font_charset, strerror(errno)); 5902f8b7cd5SSamuel Thibault exit(1); 5912f8b7cd5SSamuel Thibault } 5922f8b7cd5SSamuel Thibault 5932f8b7cd5SSamuel Thibault /* Control characters */ 5942f8b7cd5SSamuel Thibault for (i = 0; i <= 0x1F; i++) { 595b7b664a4SSamuel Thibault convert_ucs(i, control_characters[i], ucs2_to_nativecharset); 5962f8b7cd5SSamuel Thibault } 5972f8b7cd5SSamuel Thibault 5982f8b7cd5SSamuel Thibault for (i = 0x20; i <= 0xFF; i++) { 5992f8b7cd5SSamuel Thibault convert_font(i, font_conv); 6002f8b7cd5SSamuel Thibault } 6012f8b7cd5SSamuel Thibault 6022f8b7cd5SSamuel Thibault /* DEL */ 603b7b664a4SSamuel Thibault convert_ucs(0x7F, 0x2302, ucs2_to_nativecharset); 6042f8b7cd5SSamuel Thibault 6052f8b7cd5SSamuel Thibault if (strcmp(nl_langinfo(CODESET), "UTF-8")) { 6062f8b7cd5SSamuel Thibault /* Non-Unicode capable, use termcap equivalents for those available */ 6072f8b7cd5SSamuel Thibault for (i = 0; i <= 0xFF; i++) { 608962cf8fdSSamuel Thibault wchar_t wch[CCHARW_MAX]; 609962cf8fdSSamuel Thibault attr_t attr; 610962cf8fdSSamuel Thibault short color; 611962cf8fdSSamuel Thibault int ret; 612962cf8fdSSamuel Thibault 613962cf8fdSSamuel Thibault ret = getcchar(&vga_to_curses[i], wch, &attr, &color, NULL); 614962cf8fdSSamuel Thibault if (ret == ERR) 615962cf8fdSSamuel Thibault continue; 616962cf8fdSSamuel Thibault 617962cf8fdSSamuel Thibault switch (get_ucs(wch[0], nativecharset_to_ucs2)) { 6182f8b7cd5SSamuel Thibault case 0x00a3: 6192f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_STERLING; 6202f8b7cd5SSamuel Thibault break; 6212f8b7cd5SSamuel Thibault case 0x2591: 6222f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BOARD; 6232f8b7cd5SSamuel Thibault break; 6242f8b7cd5SSamuel Thibault case 0x2592: 6252f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_CKBOARD; 6262f8b7cd5SSamuel Thibault break; 6272f8b7cd5SSamuel Thibault case 0x2502: 6282f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_VLINE; 6292f8b7cd5SSamuel Thibault break; 6302f8b7cd5SSamuel Thibault case 0x2524: 6312f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_RTEE; 6322f8b7cd5SSamuel Thibault break; 6332f8b7cd5SSamuel Thibault case 0x2510: 6342f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_URCORNER; 6352f8b7cd5SSamuel Thibault break; 6362f8b7cd5SSamuel Thibault case 0x2514: 6372f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LLCORNER; 6382f8b7cd5SSamuel Thibault break; 6392f8b7cd5SSamuel Thibault case 0x2534: 6402f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BTEE; 6412f8b7cd5SSamuel Thibault break; 6422f8b7cd5SSamuel Thibault case 0x252c: 6432f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_TTEE; 6442f8b7cd5SSamuel Thibault break; 6452f8b7cd5SSamuel Thibault case 0x251c: 6462f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LTEE; 6472f8b7cd5SSamuel Thibault break; 6482f8b7cd5SSamuel Thibault case 0x2500: 6492f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_HLINE; 6502f8b7cd5SSamuel Thibault break; 6512f8b7cd5SSamuel Thibault case 0x253c: 6522f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PLUS; 6532f8b7cd5SSamuel Thibault break; 6542f8b7cd5SSamuel Thibault case 0x256c: 6552f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LANTERN; 6562f8b7cd5SSamuel Thibault break; 6572f8b7cd5SSamuel Thibault case 0x256a: 6582f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_NEQUAL; 6592f8b7cd5SSamuel Thibault break; 6602f8b7cd5SSamuel Thibault case 0x2518: 6612f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LRCORNER; 6622f8b7cd5SSamuel Thibault break; 6632f8b7cd5SSamuel Thibault case 0x250c: 6642f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_ULCORNER; 6652f8b7cd5SSamuel Thibault break; 6662f8b7cd5SSamuel Thibault case 0x2588: 6672f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BLOCK; 6682f8b7cd5SSamuel Thibault break; 6692f8b7cd5SSamuel Thibault case 0x03c0: 6702f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PI; 6712f8b7cd5SSamuel Thibault break; 6722f8b7cd5SSamuel Thibault case 0x00b1: 6732f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PLMINUS; 6742f8b7cd5SSamuel Thibault break; 6752f8b7cd5SSamuel Thibault case 0x2265: 6762f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_GEQUAL; 6772f8b7cd5SSamuel Thibault break; 6782f8b7cd5SSamuel Thibault case 0x2264: 6792f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LEQUAL; 6802f8b7cd5SSamuel Thibault break; 6812f8b7cd5SSamuel Thibault case 0x00b0: 6822f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DEGREE; 6832f8b7cd5SSamuel Thibault break; 6842f8b7cd5SSamuel Thibault case 0x25a0: 6852f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BULLET; 6862f8b7cd5SSamuel Thibault break; 6872f8b7cd5SSamuel Thibault case 0x2666: 6882f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DIAMOND; 6892f8b7cd5SSamuel Thibault break; 6902f8b7cd5SSamuel Thibault case 0x2192: 6912f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_RARROW; 6922f8b7cd5SSamuel Thibault break; 6932f8b7cd5SSamuel Thibault case 0x2190: 6942f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LARROW; 6952f8b7cd5SSamuel Thibault break; 6962f8b7cd5SSamuel Thibault case 0x2191: 6972f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_UARROW; 6982f8b7cd5SSamuel Thibault break; 6992f8b7cd5SSamuel Thibault case 0x2193: 7002f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DARROW; 7012f8b7cd5SSamuel Thibault break; 7022f8b7cd5SSamuel Thibault case 0x23ba: 7032f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S1; 7042f8b7cd5SSamuel Thibault break; 7052f8b7cd5SSamuel Thibault case 0x23bb: 7062f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S3; 7072f8b7cd5SSamuel Thibault break; 7082f8b7cd5SSamuel Thibault case 0x23bc: 7092f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S7; 7102f8b7cd5SSamuel Thibault break; 7112f8b7cd5SSamuel Thibault case 0x23bd: 7122f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S9; 7132f8b7cd5SSamuel Thibault break; 7142f8b7cd5SSamuel Thibault } 7152f8b7cd5SSamuel Thibault } 7162f8b7cd5SSamuel Thibault } 717b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 718b7b664a4SSamuel Thibault iconv_close(nativecharset_to_ucs2); 719a9fda247SSamuel Thibault iconv_close(font_conv); 7202f8b7cd5SSamuel Thibault } 7212f8b7cd5SSamuel Thibault 7223e230dd2SCorentin Chary static void curses_setup(void) 7233e230dd2SCorentin Chary { 7243e230dd2SCorentin Chary int i, colour_default[8] = { 7254083733dSOGAWA Hirofumi [QEMU_COLOR_BLACK] = COLOR_BLACK, 7264083733dSOGAWA Hirofumi [QEMU_COLOR_BLUE] = COLOR_BLUE, 7274083733dSOGAWA Hirofumi [QEMU_COLOR_GREEN] = COLOR_GREEN, 7284083733dSOGAWA Hirofumi [QEMU_COLOR_CYAN] = COLOR_CYAN, 7294083733dSOGAWA Hirofumi [QEMU_COLOR_RED] = COLOR_RED, 7304083733dSOGAWA Hirofumi [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA, 7314083733dSOGAWA Hirofumi [QEMU_COLOR_YELLOW] = COLOR_YELLOW, 7324083733dSOGAWA Hirofumi [QEMU_COLOR_WHITE] = COLOR_WHITE, 7333e230dd2SCorentin Chary }; 7343e230dd2SCorentin Chary 7353e230dd2SCorentin Chary /* input as raw as possible, let everything be interpreted 7363e230dd2SCorentin Chary * by the guest system */ 7373e230dd2SCorentin Chary initscr(); noecho(); intrflush(stdscr, FALSE); 7383e230dd2SCorentin Chary nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); 7393e230dd2SCorentin Chary start_color(); raw(); scrollok(stdscr, FALSE); 740633786feSSamuel Thibault set_escdelay(25); 7413e230dd2SCorentin Chary 7424083733dSOGAWA Hirofumi /* Make color pair to match color format (3bits bg:3bits fg) */ 743615220ddSOGAWA Hirofumi for (i = 0; i < 64; i++) { 7443e230dd2SCorentin Chary init_pair(i, colour_default[i & 7], colour_default[i >> 3]); 7453e230dd2SCorentin Chary } 7464083733dSOGAWA Hirofumi /* Set default color for more than 64 for safety. */ 747615220ddSOGAWA Hirofumi for (i = 64; i < COLOR_PAIRS; i++) { 748615220ddSOGAWA Hirofumi init_pair(i, COLOR_WHITE, COLOR_BLACK); 749615220ddSOGAWA Hirofumi } 750e2368dc9SOGAWA Hirofumi 7512f8b7cd5SSamuel Thibault font_setup(); 752615220ddSOGAWA Hirofumi } 7533e230dd2SCorentin Chary 7543e230dd2SCorentin Chary static void curses_keyboard_setup(void) 7553e230dd2SCorentin Chary { 7563e230dd2SCorentin Chary #if defined(__APPLE__) 7573e230dd2SCorentin Chary /* always use generic keymaps */ 7583e230dd2SCorentin Chary if (!keyboard_layout) 7593e230dd2SCorentin Chary keyboard_layout = "en-us"; 7603e230dd2SCorentin Chary #endif 7613e230dd2SCorentin Chary if(keyboard_layout) { 762ab4f931eSFei Li kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, 763ab4f931eSFei Li &error_fatal); 7643e230dd2SCorentin Chary } 7653e230dd2SCorentin Chary } 7663e230dd2SCorentin Chary 7677c20b4a3SGerd Hoffmann static const DisplayChangeListenerOps dcl_ops = { 7687c20b4a3SGerd Hoffmann .dpy_name = "curses", 7697c20b4a3SGerd Hoffmann .dpy_text_update = curses_update, 7707c20b4a3SGerd Hoffmann .dpy_text_resize = curses_resize, 7717c20b4a3SGerd Hoffmann .dpy_refresh = curses_refresh, 7727c20b4a3SGerd Hoffmann .dpy_text_cursor = curses_cursor_position, 7737c20b4a3SGerd Hoffmann }; 7747c20b4a3SGerd Hoffmann 775b0766612SGerd Hoffmann static void curses_display_init(DisplayState *ds, DisplayOptions *opts) 7763e230dd2SCorentin Chary { 7773e230dd2SCorentin Chary #ifndef _WIN32 7783e230dd2SCorentin Chary if (!isatty(1)) { 7793e230dd2SCorentin Chary fprintf(stderr, "We need a terminal output\n"); 7803e230dd2SCorentin Chary exit(1); 7813e230dd2SCorentin Chary } 7823e230dd2SCorentin Chary #endif 7833e230dd2SCorentin Chary 7842f8b7cd5SSamuel Thibault setlocale(LC_CTYPE, ""); 7852f8b7cd5SSamuel Thibault if (opts->u.curses.charset) { 7862f8b7cd5SSamuel Thibault font_charset = opts->u.curses.charset; 7872f8b7cd5SSamuel Thibault } 788*76c51fc3SPhilippe Mathieu-Daudé screen = g_new0(console_ch_t, 160 * 100); 789*76c51fc3SPhilippe Mathieu-Daudé vga_to_curses = g_new0(cchar_t, 256); 7903e230dd2SCorentin Chary curses_setup(); 7913e230dd2SCorentin Chary curses_keyboard_setup(); 7923e230dd2SCorentin Chary atexit(curses_atexit); 7933e230dd2SCorentin Chary 794032ac6f8SGerd Hoffmann curses_winch_init(); 7953e230dd2SCorentin Chary 796fedf0d35SMarkus Armbruster dcl = g_new0(DisplayChangeListener, 1); 7977c20b4a3SGerd Hoffmann dcl->ops = &dcl_ops; 7985209089fSGerd Hoffmann register_displaychangelistener(dcl); 7993e230dd2SCorentin Chary 8003e230dd2SCorentin Chary invalidate = 1; 8013e230dd2SCorentin Chary } 802b0766612SGerd Hoffmann 803b0766612SGerd Hoffmann static QemuDisplay qemu_display_curses = { 804b0766612SGerd Hoffmann .type = DISPLAY_TYPE_CURSES, 805b0766612SGerd Hoffmann .init = curses_display_init, 806b0766612SGerd Hoffmann }; 807b0766612SGerd Hoffmann 808b0766612SGerd Hoffmann static void register_curses(void) 809b0766612SGerd Hoffmann { 810b0766612SGerd Hoffmann qemu_display_register(&qemu_display_curses); 811b0766612SGerd Hoffmann } 812b0766612SGerd Hoffmann 813b0766612SGerd Hoffmann type_init(register_curses); 814