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 */ 24e16f4c87SPeter Maydell #include "qemu/osdep.h" 253e230dd2SCorentin Chary 263e230dd2SCorentin Chary #ifndef _WIN32 273e230dd2SCorentin Chary #include <sys/ioctl.h> 283e230dd2SCorentin Chary #include <termios.h> 293e230dd2SCorentin Chary #endif 302f8b7cd5SSamuel Thibault #include <locale.h> 312f8b7cd5SSamuel Thibault #include <wchar.h> 322f8b7cd5SSamuel Thibault #include <langinfo.h> 332f8b7cd5SSamuel Thibault #include <iconv.h> 343e230dd2SCorentin Chary 35ab4f931eSFei Li #include "qapi/error.h" 363e230dd2SCorentin Chary #include "qemu-common.h" 3728ecbaeeSPaolo Bonzini #include "ui/console.h" 38cd100328SGerd Hoffmann #include "ui/input.h" 399c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 403e230dd2SCorentin Chary 41e2f82e92SGerd Hoffmann /* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */ 42e2f82e92SGerd Hoffmann #undef KEY_EVENT 43e2f82e92SGerd Hoffmann #include <curses.h> 44e2f82e92SGerd Hoffmann #undef KEY_EVENT 45e2f82e92SGerd Hoffmann 463e230dd2SCorentin Chary #define FONT_HEIGHT 16 473e230dd2SCorentin Chary #define FONT_WIDTH 8 483e230dd2SCorentin Chary 49459a707eSSamuel Thibault enum maybe_keycode { 50459a707eSSamuel Thibault CURSES_KEYCODE, 51459a707eSSamuel Thibault CURSES_CHAR, 52459a707eSSamuel Thibault CURSES_CHAR_OR_KEYCODE, 53459a707eSSamuel Thibault }; 54459a707eSSamuel Thibault 557c20b4a3SGerd Hoffmann static DisplayChangeListener *dcl; 563e230dd2SCorentin Chary static console_ch_t screen[160 * 100]; 573e230dd2SCorentin Chary static WINDOW *screenpad = NULL; 583e230dd2SCorentin Chary static int width, height, gwidth, gheight, invalidate; 593e230dd2SCorentin Chary static int px, py, sminx, sminy, smaxx, smaxy; 603e230dd2SCorentin Chary 612f8b7cd5SSamuel Thibault static const char *font_charset = "CP437"; 622f8b7cd5SSamuel Thibault static cchar_t vga_to_curses[256]; 63e2368dc9SOGAWA Hirofumi 647c20b4a3SGerd Hoffmann static void curses_update(DisplayChangeListener *dcl, 657c20b4a3SGerd Hoffmann int x, int y, int w, int h) 663e230dd2SCorentin Chary { 67e2f82e92SGerd Hoffmann console_ch_t *line; 682f8b7cd5SSamuel Thibault cchar_t curses_line[width]; 693e230dd2SCorentin Chary 70e2f82e92SGerd Hoffmann line = screen + y * width; 71e2f82e92SGerd Hoffmann for (h += y; y < h; y ++, line += width) { 72e2f82e92SGerd Hoffmann for (x = 0; x < width; x++) { 73e2f82e92SGerd Hoffmann chtype ch = line[x] & 0xff; 74e2f82e92SGerd Hoffmann chtype at = line[x] & ~0xff; 752f8b7cd5SSamuel Thibault if (vga_to_curses[ch].chars[0]) { 762f8b7cd5SSamuel Thibault curses_line[x] = vga_to_curses[ch]; 772f8b7cd5SSamuel Thibault } else { 78a5489ae5SSamuel Thibault curses_line[x] = (cchar_t) { 79a5489ae5SSamuel Thibault .chars[0] = ch, 80a5489ae5SSamuel Thibault }; 81e2f82e92SGerd Hoffmann } 822f8b7cd5SSamuel Thibault curses_line[x].attr |= at; 83e2f82e92SGerd Hoffmann } 842f8b7cd5SSamuel Thibault mvwadd_wchnstr(screenpad, y, 0, curses_line, width); 85e2f82e92SGerd Hoffmann } 863e230dd2SCorentin Chary 873e230dd2SCorentin Chary pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); 883e230dd2SCorentin Chary refresh(); 893e230dd2SCorentin Chary } 903e230dd2SCorentin Chary 913e230dd2SCorentin Chary static void curses_calc_pad(void) 923e230dd2SCorentin Chary { 9381c0d5a6SGerd Hoffmann if (qemu_console_is_fixedsize(NULL)) { 943e230dd2SCorentin Chary width = gwidth; 953e230dd2SCorentin Chary height = gheight; 963e230dd2SCorentin Chary } else { 973e230dd2SCorentin Chary width = COLS; 983e230dd2SCorentin Chary height = LINES; 993e230dd2SCorentin Chary } 1003e230dd2SCorentin Chary 1013e230dd2SCorentin Chary if (screenpad) 1023e230dd2SCorentin Chary delwin(screenpad); 1033e230dd2SCorentin Chary 1043e230dd2SCorentin Chary clear(); 1053e230dd2SCorentin Chary refresh(); 1063e230dd2SCorentin Chary 1073e230dd2SCorentin Chary screenpad = newpad(height, width); 1083e230dd2SCorentin Chary 1093e230dd2SCorentin Chary if (width > COLS) { 1103e230dd2SCorentin Chary px = (width - COLS) / 2; 1113e230dd2SCorentin Chary sminx = 0; 1123e230dd2SCorentin Chary smaxx = COLS; 1133e230dd2SCorentin Chary } else { 1143e230dd2SCorentin Chary px = 0; 1153e230dd2SCorentin Chary sminx = (COLS - width) / 2; 1163e230dd2SCorentin Chary smaxx = sminx + width; 1173e230dd2SCorentin Chary } 1183e230dd2SCorentin Chary 1193e230dd2SCorentin Chary if (height > LINES) { 1203e230dd2SCorentin Chary py = (height - LINES) / 2; 1213e230dd2SCorentin Chary sminy = 0; 1223e230dd2SCorentin Chary smaxy = LINES; 1233e230dd2SCorentin Chary } else { 1243e230dd2SCorentin Chary py = 0; 1253e230dd2SCorentin Chary sminy = (LINES - height) / 2; 1263e230dd2SCorentin Chary smaxy = sminy + height; 1273e230dd2SCorentin Chary } 1283e230dd2SCorentin Chary } 1293e230dd2SCorentin Chary 1307c20b4a3SGerd Hoffmann static void curses_resize(DisplayChangeListener *dcl, 1317c20b4a3SGerd Hoffmann int width, int height) 1323e230dd2SCorentin Chary { 133a93a4a22SGerd Hoffmann if (width == gwidth && height == gheight) { 1343e230dd2SCorentin Chary return; 135a93a4a22SGerd Hoffmann } 1363e230dd2SCorentin Chary 137a93a4a22SGerd Hoffmann gwidth = width; 138a93a4a22SGerd Hoffmann gheight = height; 1393e230dd2SCorentin Chary 1403e230dd2SCorentin Chary curses_calc_pad(); 1413e230dd2SCorentin Chary } 1423e230dd2SCorentin Chary 143032ac6f8SGerd Hoffmann #if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE) 144032ac6f8SGerd Hoffmann static volatile sig_atomic_t got_sigwinch; 145032ac6f8SGerd Hoffmann static void curses_winch_check(void) 1463e230dd2SCorentin Chary { 1473e230dd2SCorentin Chary struct winsize { 1483e230dd2SCorentin Chary unsigned short ws_row; 1493e230dd2SCorentin Chary unsigned short ws_col; 1503e230dd2SCorentin Chary unsigned short ws_xpixel; /* unused */ 1513e230dd2SCorentin Chary unsigned short ws_ypixel; /* unused */ 1523e230dd2SCorentin Chary } ws; 1533e230dd2SCorentin Chary 154032ac6f8SGerd Hoffmann if (!got_sigwinch) { 1553e230dd2SCorentin Chary return; 156032ac6f8SGerd Hoffmann } 157032ac6f8SGerd Hoffmann got_sigwinch = false; 158032ac6f8SGerd Hoffmann 159032ac6f8SGerd Hoffmann if (ioctl(1, TIOCGWINSZ, &ws) == -1) { 160032ac6f8SGerd Hoffmann return; 161032ac6f8SGerd Hoffmann } 1623e230dd2SCorentin Chary 1633e230dd2SCorentin Chary resize_term(ws.ws_row, ws.ws_col); 1643e230dd2SCorentin Chary invalidate = 1; 1653e230dd2SCorentin Chary } 166032ac6f8SGerd Hoffmann 167032ac6f8SGerd Hoffmann static void curses_winch_handler(int signum) 168032ac6f8SGerd Hoffmann { 169032ac6f8SGerd Hoffmann got_sigwinch = true; 170032ac6f8SGerd Hoffmann } 171032ac6f8SGerd Hoffmann 172032ac6f8SGerd Hoffmann static void curses_winch_init(void) 173032ac6f8SGerd Hoffmann { 174032ac6f8SGerd Hoffmann struct sigaction old, winch = { 175032ac6f8SGerd Hoffmann .sa_handler = curses_winch_handler, 176032ac6f8SGerd Hoffmann }; 177032ac6f8SGerd Hoffmann sigaction(SIGWINCH, &winch, &old); 178032ac6f8SGerd Hoffmann } 179032ac6f8SGerd Hoffmann #else 180032ac6f8SGerd Hoffmann static void curses_winch_check(void) {} 181032ac6f8SGerd Hoffmann static void curses_winch_init(void) {} 1823e230dd2SCorentin Chary #endif 1833e230dd2SCorentin Chary 1847c20b4a3SGerd Hoffmann static void curses_cursor_position(DisplayChangeListener *dcl, 1857c20b4a3SGerd Hoffmann int x, int y) 1863e230dd2SCorentin Chary { 1873e230dd2SCorentin Chary if (x >= 0) { 1883e230dd2SCorentin Chary x = sminx + x - px; 1893e230dd2SCorentin Chary y = sminy + y - py; 1903e230dd2SCorentin Chary 1913e230dd2SCorentin Chary if (x >= 0 && y >= 0 && x < COLS && y < LINES) { 1923e230dd2SCorentin Chary move(y, x); 1933e230dd2SCorentin Chary curs_set(1); 1943e230dd2SCorentin Chary /* it seems that curs_set(1) must always be called before 1953e230dd2SCorentin Chary * curs_set(2) for the latter to have effect */ 19681c0d5a6SGerd Hoffmann if (!qemu_console_is_graphic(NULL)) { 1973e230dd2SCorentin Chary curs_set(2); 19881c0d5a6SGerd Hoffmann } 1993e230dd2SCorentin Chary return; 2003e230dd2SCorentin Chary } 2013e230dd2SCorentin Chary } 2023e230dd2SCorentin Chary 2033e230dd2SCorentin Chary curs_set(0); 2043e230dd2SCorentin Chary } 2053e230dd2SCorentin Chary 2063e230dd2SCorentin Chary /* generic keyboard conversion */ 2073e230dd2SCorentin Chary 2083e230dd2SCorentin Chary #include "curses_keys.h" 2093e230dd2SCorentin Chary 2103e230dd2SCorentin Chary static kbd_layout_t *kbd_layout = NULL; 2113e230dd2SCorentin Chary 212459a707eSSamuel Thibault static wint_t console_getch(enum maybe_keycode *maybe_keycode) 213459a707eSSamuel Thibault { 214459a707eSSamuel Thibault wint_t ret; 215459a707eSSamuel Thibault switch (get_wch(&ret)) { 216459a707eSSamuel Thibault case KEY_CODE_YES: 217459a707eSSamuel Thibault *maybe_keycode = CURSES_KEYCODE; 218459a707eSSamuel Thibault break; 219459a707eSSamuel Thibault case OK: 220459a707eSSamuel Thibault *maybe_keycode = CURSES_CHAR; 221459a707eSSamuel Thibault break; 222459a707eSSamuel Thibault case ERR: 223459a707eSSamuel Thibault ret = -1; 224459a707eSSamuel Thibault break; 225459a707eSSamuel Thibault } 226459a707eSSamuel Thibault return ret; 227459a707eSSamuel Thibault } 228459a707eSSamuel Thibault 229459a707eSSamuel Thibault static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], 230459a707eSSamuel Thibault int chr, enum maybe_keycode maybe_keycode) 231459a707eSSamuel Thibault { 232459a707eSSamuel Thibault int ret = -1; 233459a707eSSamuel Thibault if (maybe_keycode == CURSES_CHAR) { 234459a707eSSamuel Thibault if (chr < CURSES_CHARS) { 235459a707eSSamuel Thibault ret = _curses2foo[chr]; 236459a707eSSamuel Thibault } 237459a707eSSamuel Thibault } else { 238459a707eSSamuel Thibault if (chr < CURSES_KEYS) { 239459a707eSSamuel Thibault ret = _curseskey2foo[chr]; 240459a707eSSamuel Thibault } 241459a707eSSamuel Thibault if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE && 242459a707eSSamuel Thibault chr < CURSES_CHARS) { 243459a707eSSamuel Thibault ret = _curses2foo[chr]; 244459a707eSSamuel Thibault } 245459a707eSSamuel Thibault } 246459a707eSSamuel Thibault return ret; 247459a707eSSamuel Thibault } 248459a707eSSamuel Thibault 249459a707eSSamuel Thibault #define curses2keycode(chr, maybe_keycode) \ 250459a707eSSamuel Thibault curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) 251459a707eSSamuel Thibault #define curses2keysym(chr, maybe_keycode) \ 252459a707eSSamuel Thibault curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode) 253459a707eSSamuel Thibault #define curses2qemu(chr, maybe_keycode) \ 254459a707eSSamuel Thibault curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode) 255459a707eSSamuel Thibault 256bc2ed970SGerd Hoffmann static void curses_refresh(DisplayChangeListener *dcl) 2573e230dd2SCorentin Chary { 25899a9ef44SPeter Maydell int chr, keysym, keycode, keycode_alt; 259459a707eSSamuel Thibault enum maybe_keycode maybe_keycode; 2603e230dd2SCorentin Chary 261032ac6f8SGerd Hoffmann curses_winch_check(); 262032ac6f8SGerd Hoffmann 2633e230dd2SCorentin Chary if (invalidate) { 2643e230dd2SCorentin Chary clear(); 2653e230dd2SCorentin Chary refresh(); 2663e230dd2SCorentin Chary curses_calc_pad(); 2671dbfa005SGerd Hoffmann graphic_hw_invalidate(NULL); 2683e230dd2SCorentin Chary invalidate = 0; 2693e230dd2SCorentin Chary } 2703e230dd2SCorentin Chary 2711dbfa005SGerd Hoffmann graphic_hw_text_update(NULL, screen); 2723e230dd2SCorentin Chary 2733e230dd2SCorentin Chary while (1) { 2743e230dd2SCorentin Chary /* while there are any pending key strokes to process */ 275459a707eSSamuel Thibault chr = console_getch(&maybe_keycode); 2763e230dd2SCorentin Chary 277459a707eSSamuel Thibault if (chr == -1) 2783e230dd2SCorentin Chary break; 2793e230dd2SCorentin Chary 2803e230dd2SCorentin Chary #ifdef KEY_RESIZE 2813e230dd2SCorentin Chary /* this shouldn't occur when we use a custom SIGWINCH handler */ 282459a707eSSamuel Thibault if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) { 2833e230dd2SCorentin Chary clear(); 2843e230dd2SCorentin Chary refresh(); 2853e230dd2SCorentin Chary curses_calc_pad(); 286bc2ed970SGerd Hoffmann curses_update(dcl, 0, 0, width, height); 2873e230dd2SCorentin Chary continue; 2883e230dd2SCorentin Chary } 2893e230dd2SCorentin Chary #endif 2903e230dd2SCorentin Chary 291459a707eSSamuel Thibault keycode = curses2keycode(chr, maybe_keycode); 2923e230dd2SCorentin Chary keycode_alt = 0; 2933e230dd2SCorentin Chary 294633786feSSamuel Thibault /* alt or esc key */ 2953e230dd2SCorentin Chary if (keycode == 1) { 296459a707eSSamuel Thibault enum maybe_keycode next_maybe_keycode; 297459a707eSSamuel Thibault int nextchr = console_getch(&next_maybe_keycode); 2983e230dd2SCorentin Chary 299459a707eSSamuel Thibault if (nextchr != -1) { 3003e230dd2SCorentin Chary chr = nextchr; 301459a707eSSamuel Thibault maybe_keycode = next_maybe_keycode; 3023e230dd2SCorentin Chary keycode_alt = ALT; 303459a707eSSamuel Thibault keycode = curses2keycode(chr, maybe_keycode); 3043e230dd2SCorentin Chary 3053e230dd2SCorentin Chary if (keycode != -1) { 3063e230dd2SCorentin Chary keycode |= ALT; 3073e230dd2SCorentin Chary 3083e230dd2SCorentin Chary /* process keys reserved for qemu */ 3093e230dd2SCorentin Chary if (keycode >= QEMU_KEY_CONSOLE0 && 3103e230dd2SCorentin Chary keycode < QEMU_KEY_CONSOLE0 + 9) { 3113e230dd2SCorentin Chary erase(); 3123e230dd2SCorentin Chary wnoutrefresh(stdscr); 3133e230dd2SCorentin Chary console_select(keycode - QEMU_KEY_CONSOLE0); 3143e230dd2SCorentin Chary 3153e230dd2SCorentin Chary invalidate = 1; 3163e230dd2SCorentin Chary continue; 3173e230dd2SCorentin Chary } 3183e230dd2SCorentin Chary } 3193e230dd2SCorentin Chary } 3203e230dd2SCorentin Chary } 3213e230dd2SCorentin Chary 3223e230dd2SCorentin Chary if (kbd_layout) { 323459a707eSSamuel Thibault keysym = curses2keysym(chr, maybe_keycode); 3243e230dd2SCorentin Chary 3253e230dd2SCorentin Chary if (keysym == -1) { 326d03703c8SSamuel Thibault if (chr < ' ') { 327d03703c8SSamuel Thibault keysym = chr + '@'; 328d03703c8SSamuel Thibault if (keysym >= 'A' && keysym <= 'Z') 329d03703c8SSamuel Thibault keysym += 'a' - 'A'; 330d03703c8SSamuel Thibault keysym |= KEYSYM_CNTRL; 331d03703c8SSamuel Thibault } else 3323e230dd2SCorentin Chary keysym = chr; 3333e230dd2SCorentin Chary } 3343e230dd2SCorentin Chary 335abb4f2c9SGerd Hoffmann keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK, 33619c1b9fdSGerd Hoffmann NULL, false); 3373e230dd2SCorentin Chary if (keycode == 0) 3383e230dd2SCorentin Chary continue; 3393e230dd2SCorentin Chary 3403e230dd2SCorentin Chary keycode |= (keysym & ~KEYSYM_MASK) >> 16; 3413e230dd2SCorentin Chary keycode |= keycode_alt; 3423e230dd2SCorentin Chary } 3433e230dd2SCorentin Chary 3443e230dd2SCorentin Chary if (keycode == -1) 3453e230dd2SCorentin Chary continue; 3463e230dd2SCorentin Chary 34781c0d5a6SGerd Hoffmann if (qemu_console_is_graphic(NULL)) { 3483e230dd2SCorentin Chary /* since terminals don't know about key press and release 3493e230dd2SCorentin Chary * events, we need to emit both for each key received */ 350cd100328SGerd Hoffmann if (keycode & SHIFT) { 351cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, SHIFT_CODE, true); 3525a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 3533e230dd2SCorentin Chary } 354cd100328SGerd Hoffmann if (keycode & CNTRL) { 355cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, CNTRL_CODE, true); 3565a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 3573e230dd2SCorentin Chary } 358cd100328SGerd Hoffmann if (keycode & ALT) { 359cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, ALT_CODE, true); 3605a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 361cd100328SGerd Hoffmann } 362cd100328SGerd Hoffmann if (keycode & ALTGR) { 363cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); 3645a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 365cd100328SGerd Hoffmann } 366cd100328SGerd Hoffmann 367f5c0ab13SAndrew Oates qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true); 3685a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 369f5c0ab13SAndrew Oates qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false); 3705a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 371cd100328SGerd Hoffmann 372cd100328SGerd Hoffmann if (keycode & ALTGR) { 373cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); 3745a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 375cd100328SGerd Hoffmann } 376cd100328SGerd Hoffmann if (keycode & ALT) { 377cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, ALT_CODE, false); 3785a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 379cd100328SGerd Hoffmann } 380cd100328SGerd Hoffmann if (keycode & CNTRL) { 381cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, CNTRL_CODE, false); 3825a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 383cd100328SGerd Hoffmann } 384cd100328SGerd Hoffmann if (keycode & SHIFT) { 385cd100328SGerd Hoffmann qemu_input_event_send_key_number(NULL, SHIFT_CODE, false); 3865a165668SGerd Hoffmann qemu_input_event_send_key_delay(0); 387cd100328SGerd Hoffmann } 3883e230dd2SCorentin Chary } else { 389459a707eSSamuel Thibault keysym = curses2qemu(chr, maybe_keycode); 3903e230dd2SCorentin Chary if (keysym == -1) 3913e230dd2SCorentin Chary keysym = chr; 3923e230dd2SCorentin Chary 3933e230dd2SCorentin Chary kbd_put_keysym(keysym); 3943e230dd2SCorentin Chary } 3953e230dd2SCorentin Chary } 3963e230dd2SCorentin Chary } 3973e230dd2SCorentin Chary 3983e230dd2SCorentin Chary static void curses_atexit(void) 3993e230dd2SCorentin Chary { 4003e230dd2SCorentin Chary endwin(); 4013e230dd2SCorentin Chary } 4023e230dd2SCorentin Chary 403*b7b664a4SSamuel Thibault /* 404*b7b664a4SSamuel Thibault * In the following: 405*b7b664a4SSamuel Thibault * - fch is the font glyph number 406*b7b664a4SSamuel Thibault * - uch is the unicode value 407*b7b664a4SSamuel Thibault * - wch is the wchar_t value (may not be unicode, e.g. on BSD/solaris) 408*b7b664a4SSamuel Thibault * - mbch is the native local-dependent multibyte representation 409*b7b664a4SSamuel Thibault */ 410*b7b664a4SSamuel Thibault 4112f8b7cd5SSamuel Thibault /* Setup wchar glyph for one UCS-2 char */ 412*b7b664a4SSamuel Thibault static void convert_ucs(unsigned char fch, uint16_t uch, iconv_t conv) 4132f8b7cd5SSamuel Thibault { 414*b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 4152f8b7cd5SSamuel Thibault wchar_t wch; 416*b7b664a4SSamuel Thibault char *puch, *pmbch; 417*b7b664a4SSamuel Thibault size_t such, smbch; 418*b7b664a4SSamuel Thibault mbstate_t ps; 4192f8b7cd5SSamuel Thibault 420*b7b664a4SSamuel Thibault puch = (char *) &uch; 421*b7b664a4SSamuel Thibault pmbch = (char *) mbch; 422*b7b664a4SSamuel Thibault such = sizeof(uch); 423*b7b664a4SSamuel Thibault smbch = sizeof(mbch); 4242f8b7cd5SSamuel Thibault 425*b7b664a4SSamuel Thibault if (iconv(conv, &puch, &such, &pmbch, &smbch) == (size_t) -1) { 426*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 427*b7b664a4SSamuel Thibault "from UCS-2 to a multibyte character: %s\n", 428*b7b664a4SSamuel Thibault uch, strerror(errno)); 429*b7b664a4SSamuel Thibault return; 4302f8b7cd5SSamuel Thibault } 431*b7b664a4SSamuel Thibault 432*b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 433*b7b664a4SSamuel Thibault if (mbrtowc(&wch, mbch, sizeof(mbch) - smbch, &ps) == -1) { 434*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 435*b7b664a4SSamuel Thibault "from a multibyte character to wchar_t: %s\n", 436*b7b664a4SSamuel Thibault uch, strerror(errno)); 437*b7b664a4SSamuel Thibault return; 438*b7b664a4SSamuel Thibault } 439*b7b664a4SSamuel Thibault vga_to_curses[fch].chars[0] = wch; 4402f8b7cd5SSamuel Thibault } 4412f8b7cd5SSamuel Thibault 4422f8b7cd5SSamuel Thibault /* Setup wchar glyph for one font character */ 443*b7b664a4SSamuel Thibault static void convert_font(unsigned char fch, iconv_t conv) 4442f8b7cd5SSamuel Thibault { 445*b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 4462f8b7cd5SSamuel Thibault wchar_t wch; 447*b7b664a4SSamuel Thibault char *pfch, *pmbch; 448*b7b664a4SSamuel Thibault size_t sfch, smbch; 449*b7b664a4SSamuel Thibault mbstate_t ps; 4502f8b7cd5SSamuel Thibault 451*b7b664a4SSamuel Thibault pfch = (char *) &fch; 452*b7b664a4SSamuel Thibault pmbch = (char *) &mbch; 453*b7b664a4SSamuel Thibault sfch = sizeof(fch); 454*b7b664a4SSamuel Thibault smbch = sizeof(mbch); 4552f8b7cd5SSamuel Thibault 456*b7b664a4SSamuel Thibault if (iconv(conv, &pfch, &sfch, &pmbch, &smbch) == (size_t) -1) { 457*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert font glyph 0x%02x " 458*b7b664a4SSamuel Thibault "from %s to a multibyte character: %s\n", 459*b7b664a4SSamuel Thibault fch, font_charset, strerror(errno)); 460*b7b664a4SSamuel Thibault return; 4612f8b7cd5SSamuel Thibault } 462*b7b664a4SSamuel Thibault 463*b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 464*b7b664a4SSamuel Thibault if (mbrtowc(&wch, mbch, sizeof(mbch) - smbch, &ps) == -1) { 465*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert font glyph 0x%02x " 466*b7b664a4SSamuel Thibault "from a multibyte character to wchar_t: %s\n", 467*b7b664a4SSamuel Thibault fch, strerror(errno)); 468*b7b664a4SSamuel Thibault return; 469*b7b664a4SSamuel Thibault } 470*b7b664a4SSamuel Thibault vga_to_curses[fch].chars[0] = wch; 4712f8b7cd5SSamuel Thibault } 4722f8b7cd5SSamuel Thibault 4732f8b7cd5SSamuel Thibault /* Convert one wchar to UCS-2 */ 4742f8b7cd5SSamuel Thibault static uint16_t get_ucs(wchar_t wch, iconv_t conv) 4752f8b7cd5SSamuel Thibault { 476*b7b664a4SSamuel Thibault char mbch[MB_LEN_MAX]; 477*b7b664a4SSamuel Thibault uint16_t uch; 478*b7b664a4SSamuel Thibault char *pmbch, *puch; 479*b7b664a4SSamuel Thibault size_t smbch, such; 480*b7b664a4SSamuel Thibault mbstate_t ps; 481*b7b664a4SSamuel Thibault int ret; 4822f8b7cd5SSamuel Thibault 483*b7b664a4SSamuel Thibault memset(&ps, 0, sizeof(ps)); 484*b7b664a4SSamuel Thibault ret = wcrtomb(mbch, wch, &ps); 485*b7b664a4SSamuel Thibault if (ret == -1) { 486*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 487*b7b664a4SSamuel Thibault "from wchar_t to a multibyte character: %s\n", 488*b7b664a4SSamuel Thibault wch, strerror(errno)); 4892f8b7cd5SSamuel Thibault return 0xFFFD; 4902f8b7cd5SSamuel Thibault } 4912f8b7cd5SSamuel Thibault 492*b7b664a4SSamuel Thibault pmbch = (char *) mbch; 493*b7b664a4SSamuel Thibault puch = (char *) &uch; 494*b7b664a4SSamuel Thibault smbch = ret; 495*b7b664a4SSamuel Thibault such = sizeof(uch); 496*b7b664a4SSamuel Thibault 497*b7b664a4SSamuel Thibault if (iconv(conv, &pmbch, &smbch, &puch, &such) == (size_t) -1) { 498*b7b664a4SSamuel Thibault fprintf(stderr, "Could not convert 0x%04x " 499*b7b664a4SSamuel Thibault "from a multibyte character to UCS-2 : %s\n", 500*b7b664a4SSamuel Thibault wch, strerror(errno)); 501*b7b664a4SSamuel Thibault return 0xFFFD; 502*b7b664a4SSamuel Thibault } 503*b7b664a4SSamuel Thibault 504*b7b664a4SSamuel Thibault return uch; 5052f8b7cd5SSamuel Thibault } 5062f8b7cd5SSamuel Thibault 5072f8b7cd5SSamuel Thibault /* 5082f8b7cd5SSamuel Thibault * Setup mapping for vga to curses line graphics. 5092f8b7cd5SSamuel Thibault */ 5102f8b7cd5SSamuel Thibault static void font_setup(void) 5112f8b7cd5SSamuel Thibault { 512*b7b664a4SSamuel Thibault iconv_t ucs2_to_nativecharset; 513*b7b664a4SSamuel Thibault iconv_t nativecharset_to_ucs2; 514*b7b664a4SSamuel Thibault iconv_t font_conv; 515*b7b664a4SSamuel Thibault int i; 516*b7b664a4SSamuel Thibault 5172f8b7cd5SSamuel Thibault /* 5182f8b7cd5SSamuel Thibault * Control characters are normally non-printable, but VGA does have 5192f8b7cd5SSamuel Thibault * well-known glyphs for them. 5202f8b7cd5SSamuel Thibault */ 5212f8b7cd5SSamuel Thibault static uint16_t control_characters[0x20] = { 5222f8b7cd5SSamuel Thibault 0x0020, 5232f8b7cd5SSamuel Thibault 0x263a, 5242f8b7cd5SSamuel Thibault 0x263b, 5252f8b7cd5SSamuel Thibault 0x2665, 5262f8b7cd5SSamuel Thibault 0x2666, 5272f8b7cd5SSamuel Thibault 0x2663, 5282f8b7cd5SSamuel Thibault 0x2660, 5292f8b7cd5SSamuel Thibault 0x2022, 5302f8b7cd5SSamuel Thibault 0x25d8, 5312f8b7cd5SSamuel Thibault 0x25cb, 5322f8b7cd5SSamuel Thibault 0x25d9, 5332f8b7cd5SSamuel Thibault 0x2642, 5342f8b7cd5SSamuel Thibault 0x2640, 5352f8b7cd5SSamuel Thibault 0x266a, 5362f8b7cd5SSamuel Thibault 0x266b, 5372f8b7cd5SSamuel Thibault 0x263c, 5382f8b7cd5SSamuel Thibault 0x25ba, 5392f8b7cd5SSamuel Thibault 0x25c4, 5402f8b7cd5SSamuel Thibault 0x2195, 5412f8b7cd5SSamuel Thibault 0x203c, 5422f8b7cd5SSamuel Thibault 0x00b6, 5432f8b7cd5SSamuel Thibault 0x00a7, 5442f8b7cd5SSamuel Thibault 0x25ac, 5452f8b7cd5SSamuel Thibault 0x21a8, 5462f8b7cd5SSamuel Thibault 0x2191, 5472f8b7cd5SSamuel Thibault 0x2193, 5482f8b7cd5SSamuel Thibault 0x2192, 5492f8b7cd5SSamuel Thibault 0x2190, 5502f8b7cd5SSamuel Thibault 0x221f, 5512f8b7cd5SSamuel Thibault 0x2194, 5522f8b7cd5SSamuel Thibault 0x25b2, 5532f8b7cd5SSamuel Thibault 0x25bc 5542f8b7cd5SSamuel Thibault }; 5552f8b7cd5SSamuel Thibault 556*b7b664a4SSamuel Thibault ucs2_to_nativecharset = iconv_open(nl_langinfo(CODESET), "UCS-2"); 557*b7b664a4SSamuel Thibault if (ucs2_to_nativecharset == (iconv_t) -1) { 5582f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n", 5592f8b7cd5SSamuel Thibault strerror(errno)); 5602f8b7cd5SSamuel Thibault exit(1); 5612f8b7cd5SSamuel Thibault } 5622f8b7cd5SSamuel Thibault 563*b7b664a4SSamuel Thibault nativecharset_to_ucs2 = iconv_open("UCS-2", nl_langinfo(CODESET)); 564*b7b664a4SSamuel Thibault if (nativecharset_to_ucs2 == (iconv_t) -1) { 565*b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 5662f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n", 5672f8b7cd5SSamuel Thibault strerror(errno)); 5682f8b7cd5SSamuel Thibault exit(1); 5692f8b7cd5SSamuel Thibault } 5702f8b7cd5SSamuel Thibault 571*b7b664a4SSamuel Thibault font_conv = iconv_open(nl_langinfo(CODESET), font_charset); 5722f8b7cd5SSamuel Thibault if (font_conv == (iconv_t) -1) { 573*b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 574*b7b664a4SSamuel Thibault iconv_close(nativecharset_to_ucs2); 5752f8b7cd5SSamuel Thibault fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n", 5762f8b7cd5SSamuel Thibault font_charset, strerror(errno)); 5772f8b7cd5SSamuel Thibault exit(1); 5782f8b7cd5SSamuel Thibault } 5792f8b7cd5SSamuel Thibault 5802f8b7cd5SSamuel Thibault /* Control characters */ 5812f8b7cd5SSamuel Thibault for (i = 0; i <= 0x1F; i++) { 582*b7b664a4SSamuel Thibault convert_ucs(i, control_characters[i], ucs2_to_nativecharset); 5832f8b7cd5SSamuel Thibault } 5842f8b7cd5SSamuel Thibault 5852f8b7cd5SSamuel Thibault for (i = 0x20; i <= 0xFF; i++) { 5862f8b7cd5SSamuel Thibault convert_font(i, font_conv); 5872f8b7cd5SSamuel Thibault } 5882f8b7cd5SSamuel Thibault 5892f8b7cd5SSamuel Thibault /* DEL */ 590*b7b664a4SSamuel Thibault convert_ucs(0x7F, 0x2302, ucs2_to_nativecharset); 5912f8b7cd5SSamuel Thibault 5922f8b7cd5SSamuel Thibault if (strcmp(nl_langinfo(CODESET), "UTF-8")) { 5932f8b7cd5SSamuel Thibault /* Non-Unicode capable, use termcap equivalents for those available */ 5942f8b7cd5SSamuel Thibault for (i = 0; i <= 0xFF; i++) { 595*b7b664a4SSamuel Thibault switch (get_ucs(vga_to_curses[i].chars[0], nativecharset_to_ucs2)) { 5962f8b7cd5SSamuel Thibault case 0x00a3: 5972f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_STERLING; 5982f8b7cd5SSamuel Thibault break; 5992f8b7cd5SSamuel Thibault case 0x2591: 6002f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BOARD; 6012f8b7cd5SSamuel Thibault break; 6022f8b7cd5SSamuel Thibault case 0x2592: 6032f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_CKBOARD; 6042f8b7cd5SSamuel Thibault break; 6052f8b7cd5SSamuel Thibault case 0x2502: 6062f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_VLINE; 6072f8b7cd5SSamuel Thibault break; 6082f8b7cd5SSamuel Thibault case 0x2524: 6092f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_RTEE; 6102f8b7cd5SSamuel Thibault break; 6112f8b7cd5SSamuel Thibault case 0x2510: 6122f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_URCORNER; 6132f8b7cd5SSamuel Thibault break; 6142f8b7cd5SSamuel Thibault case 0x2514: 6152f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LLCORNER; 6162f8b7cd5SSamuel Thibault break; 6172f8b7cd5SSamuel Thibault case 0x2534: 6182f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BTEE; 6192f8b7cd5SSamuel Thibault break; 6202f8b7cd5SSamuel Thibault case 0x252c: 6212f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_TTEE; 6222f8b7cd5SSamuel Thibault break; 6232f8b7cd5SSamuel Thibault case 0x251c: 6242f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LTEE; 6252f8b7cd5SSamuel Thibault break; 6262f8b7cd5SSamuel Thibault case 0x2500: 6272f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_HLINE; 6282f8b7cd5SSamuel Thibault break; 6292f8b7cd5SSamuel Thibault case 0x253c: 6302f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PLUS; 6312f8b7cd5SSamuel Thibault break; 6322f8b7cd5SSamuel Thibault case 0x256c: 6332f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LANTERN; 6342f8b7cd5SSamuel Thibault break; 6352f8b7cd5SSamuel Thibault case 0x256a: 6362f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_NEQUAL; 6372f8b7cd5SSamuel Thibault break; 6382f8b7cd5SSamuel Thibault case 0x2518: 6392f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LRCORNER; 6402f8b7cd5SSamuel Thibault break; 6412f8b7cd5SSamuel Thibault case 0x250c: 6422f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_ULCORNER; 6432f8b7cd5SSamuel Thibault break; 6442f8b7cd5SSamuel Thibault case 0x2588: 6452f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BLOCK; 6462f8b7cd5SSamuel Thibault break; 6472f8b7cd5SSamuel Thibault case 0x03c0: 6482f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PI; 6492f8b7cd5SSamuel Thibault break; 6502f8b7cd5SSamuel Thibault case 0x00b1: 6512f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_PLMINUS; 6522f8b7cd5SSamuel Thibault break; 6532f8b7cd5SSamuel Thibault case 0x2265: 6542f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_GEQUAL; 6552f8b7cd5SSamuel Thibault break; 6562f8b7cd5SSamuel Thibault case 0x2264: 6572f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LEQUAL; 6582f8b7cd5SSamuel Thibault break; 6592f8b7cd5SSamuel Thibault case 0x00b0: 6602f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DEGREE; 6612f8b7cd5SSamuel Thibault break; 6622f8b7cd5SSamuel Thibault case 0x25a0: 6632f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_BULLET; 6642f8b7cd5SSamuel Thibault break; 6652f8b7cd5SSamuel Thibault case 0x2666: 6662f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DIAMOND; 6672f8b7cd5SSamuel Thibault break; 6682f8b7cd5SSamuel Thibault case 0x2192: 6692f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_RARROW; 6702f8b7cd5SSamuel Thibault break; 6712f8b7cd5SSamuel Thibault case 0x2190: 6722f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_LARROW; 6732f8b7cd5SSamuel Thibault break; 6742f8b7cd5SSamuel Thibault case 0x2191: 6752f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_UARROW; 6762f8b7cd5SSamuel Thibault break; 6772f8b7cd5SSamuel Thibault case 0x2193: 6782f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_DARROW; 6792f8b7cd5SSamuel Thibault break; 6802f8b7cd5SSamuel Thibault case 0x23ba: 6812f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S1; 6822f8b7cd5SSamuel Thibault break; 6832f8b7cd5SSamuel Thibault case 0x23bb: 6842f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S3; 6852f8b7cd5SSamuel Thibault break; 6862f8b7cd5SSamuel Thibault case 0x23bc: 6872f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S7; 6882f8b7cd5SSamuel Thibault break; 6892f8b7cd5SSamuel Thibault case 0x23bd: 6902f8b7cd5SSamuel Thibault vga_to_curses[i] = *WACS_S9; 6912f8b7cd5SSamuel Thibault break; 6922f8b7cd5SSamuel Thibault } 6932f8b7cd5SSamuel Thibault } 6942f8b7cd5SSamuel Thibault } 695*b7b664a4SSamuel Thibault iconv_close(ucs2_to_nativecharset); 696*b7b664a4SSamuel Thibault iconv_close(nativecharset_to_ucs2); 697a9fda247SSamuel Thibault iconv_close(font_conv); 6982f8b7cd5SSamuel Thibault } 6992f8b7cd5SSamuel Thibault 7003e230dd2SCorentin Chary static void curses_setup(void) 7013e230dd2SCorentin Chary { 7023e230dd2SCorentin Chary int i, colour_default[8] = { 7034083733dSOGAWA Hirofumi [QEMU_COLOR_BLACK] = COLOR_BLACK, 7044083733dSOGAWA Hirofumi [QEMU_COLOR_BLUE] = COLOR_BLUE, 7054083733dSOGAWA Hirofumi [QEMU_COLOR_GREEN] = COLOR_GREEN, 7064083733dSOGAWA Hirofumi [QEMU_COLOR_CYAN] = COLOR_CYAN, 7074083733dSOGAWA Hirofumi [QEMU_COLOR_RED] = COLOR_RED, 7084083733dSOGAWA Hirofumi [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA, 7094083733dSOGAWA Hirofumi [QEMU_COLOR_YELLOW] = COLOR_YELLOW, 7104083733dSOGAWA Hirofumi [QEMU_COLOR_WHITE] = COLOR_WHITE, 7113e230dd2SCorentin Chary }; 7123e230dd2SCorentin Chary 7133e230dd2SCorentin Chary /* input as raw as possible, let everything be interpreted 7143e230dd2SCorentin Chary * by the guest system */ 7153e230dd2SCorentin Chary initscr(); noecho(); intrflush(stdscr, FALSE); 7163e230dd2SCorentin Chary nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); 7173e230dd2SCorentin Chary start_color(); raw(); scrollok(stdscr, FALSE); 718633786feSSamuel Thibault set_escdelay(25); 7193e230dd2SCorentin Chary 7204083733dSOGAWA Hirofumi /* Make color pair to match color format (3bits bg:3bits fg) */ 721615220ddSOGAWA Hirofumi for (i = 0; i < 64; i++) { 7223e230dd2SCorentin Chary init_pair(i, colour_default[i & 7], colour_default[i >> 3]); 7233e230dd2SCorentin Chary } 7244083733dSOGAWA Hirofumi /* Set default color for more than 64 for safety. */ 725615220ddSOGAWA Hirofumi for (i = 64; i < COLOR_PAIRS; i++) { 726615220ddSOGAWA Hirofumi init_pair(i, COLOR_WHITE, COLOR_BLACK); 727615220ddSOGAWA Hirofumi } 728e2368dc9SOGAWA Hirofumi 7292f8b7cd5SSamuel Thibault font_setup(); 730615220ddSOGAWA Hirofumi } 7313e230dd2SCorentin Chary 7323e230dd2SCorentin Chary static void curses_keyboard_setup(void) 7333e230dd2SCorentin Chary { 7343e230dd2SCorentin Chary #if defined(__APPLE__) 7353e230dd2SCorentin Chary /* always use generic keymaps */ 7363e230dd2SCorentin Chary if (!keyboard_layout) 7373e230dd2SCorentin Chary keyboard_layout = "en-us"; 7383e230dd2SCorentin Chary #endif 7393e230dd2SCorentin Chary if(keyboard_layout) { 740ab4f931eSFei Li kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, 741ab4f931eSFei Li &error_fatal); 7423e230dd2SCorentin Chary } 7433e230dd2SCorentin Chary } 7443e230dd2SCorentin Chary 7457c20b4a3SGerd Hoffmann static const DisplayChangeListenerOps dcl_ops = { 7467c20b4a3SGerd Hoffmann .dpy_name = "curses", 7477c20b4a3SGerd Hoffmann .dpy_text_update = curses_update, 7487c20b4a3SGerd Hoffmann .dpy_text_resize = curses_resize, 7497c20b4a3SGerd Hoffmann .dpy_refresh = curses_refresh, 7507c20b4a3SGerd Hoffmann .dpy_text_cursor = curses_cursor_position, 7517c20b4a3SGerd Hoffmann }; 7527c20b4a3SGerd Hoffmann 753b0766612SGerd Hoffmann static void curses_display_init(DisplayState *ds, DisplayOptions *opts) 7543e230dd2SCorentin Chary { 7553e230dd2SCorentin Chary #ifndef _WIN32 7563e230dd2SCorentin Chary if (!isatty(1)) { 7573e230dd2SCorentin Chary fprintf(stderr, "We need a terminal output\n"); 7583e230dd2SCorentin Chary exit(1); 7593e230dd2SCorentin Chary } 7603e230dd2SCorentin Chary #endif 7613e230dd2SCorentin Chary 7622f8b7cd5SSamuel Thibault setlocale(LC_CTYPE, ""); 7632f8b7cd5SSamuel Thibault if (opts->u.curses.charset) { 7642f8b7cd5SSamuel Thibault font_charset = opts->u.curses.charset; 7652f8b7cd5SSamuel Thibault } 7663e230dd2SCorentin Chary curses_setup(); 7673e230dd2SCorentin Chary curses_keyboard_setup(); 7683e230dd2SCorentin Chary atexit(curses_atexit); 7693e230dd2SCorentin Chary 770032ac6f8SGerd Hoffmann curses_winch_init(); 7713e230dd2SCorentin Chary 772fedf0d35SMarkus Armbruster dcl = g_new0(DisplayChangeListener, 1); 7737c20b4a3SGerd Hoffmann dcl->ops = &dcl_ops; 7745209089fSGerd Hoffmann register_displaychangelistener(dcl); 7753e230dd2SCorentin Chary 7763e230dd2SCorentin Chary invalidate = 1; 7773e230dd2SCorentin Chary } 778b0766612SGerd Hoffmann 779b0766612SGerd Hoffmann static QemuDisplay qemu_display_curses = { 780b0766612SGerd Hoffmann .type = DISPLAY_TYPE_CURSES, 781b0766612SGerd Hoffmann .init = curses_display_init, 782b0766612SGerd Hoffmann }; 783b0766612SGerd Hoffmann 784b0766612SGerd Hoffmann static void register_curses(void) 785b0766612SGerd Hoffmann { 786b0766612SGerd Hoffmann qemu_display_register(&qemu_display_curses); 787b0766612SGerd Hoffmann } 788b0766612SGerd Hoffmann 789b0766612SGerd Hoffmann type_init(register_curses); 790