xref: /openbmc/qemu/ui/curses.c (revision e2f82e924d057935dd4c61c0c53e11b15762eda2)
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
303e230dd2SCorentin Chary 
313e230dd2SCorentin Chary #include "qemu-common.h"
3228ecbaeeSPaolo Bonzini #include "ui/console.h"
33cd100328SGerd Hoffmann #include "ui/input.h"
349c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
353e230dd2SCorentin Chary 
36*e2f82e92SGerd Hoffmann /* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */
37*e2f82e92SGerd Hoffmann #undef KEY_EVENT
38*e2f82e92SGerd Hoffmann #include <curses.h>
39*e2f82e92SGerd Hoffmann #undef KEY_EVENT
40*e2f82e92SGerd Hoffmann 
413e230dd2SCorentin Chary #define FONT_HEIGHT 16
423e230dd2SCorentin Chary #define FONT_WIDTH 8
433e230dd2SCorentin Chary 
447c20b4a3SGerd Hoffmann static DisplayChangeListener *dcl;
453e230dd2SCorentin Chary static console_ch_t screen[160 * 100];
463e230dd2SCorentin Chary static WINDOW *screenpad = NULL;
473e230dd2SCorentin Chary static int width, height, gwidth, gheight, invalidate;
483e230dd2SCorentin Chary static int px, py, sminx, sminy, smaxx, smaxy;
493e230dd2SCorentin Chary 
50*e2f82e92SGerd Hoffmann static chtype vga_to_curses[256];
51e2368dc9SOGAWA Hirofumi 
527c20b4a3SGerd Hoffmann static void curses_update(DisplayChangeListener *dcl,
537c20b4a3SGerd Hoffmann                           int x, int y, int w, int h)
543e230dd2SCorentin Chary {
55*e2f82e92SGerd Hoffmann     console_ch_t *line;
56*e2f82e92SGerd Hoffmann     chtype curses_line[width];
573e230dd2SCorentin Chary 
58*e2f82e92SGerd Hoffmann     line = screen + y * width;
59*e2f82e92SGerd Hoffmann     for (h += y; y < h; y ++, line += width) {
60*e2f82e92SGerd Hoffmann         for (x = 0; x < width; x++) {
61*e2f82e92SGerd Hoffmann             chtype ch = line[x] & 0xff;
62*e2f82e92SGerd Hoffmann             chtype at = line[x] & ~0xff;
63*e2f82e92SGerd Hoffmann             if (vga_to_curses[ch]) {
64*e2f82e92SGerd Hoffmann                 ch = vga_to_curses[ch];
65*e2f82e92SGerd Hoffmann             }
66*e2f82e92SGerd Hoffmann             curses_line[x] = ch | at;
67*e2f82e92SGerd Hoffmann         }
68*e2f82e92SGerd Hoffmann         mvwaddchnstr(screenpad, y, 0, curses_line, width);
69*e2f82e92SGerd Hoffmann     }
703e230dd2SCorentin Chary 
713e230dd2SCorentin Chary     pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
723e230dd2SCorentin Chary     refresh();
733e230dd2SCorentin Chary }
743e230dd2SCorentin Chary 
753e230dd2SCorentin Chary static void curses_calc_pad(void)
763e230dd2SCorentin Chary {
7781c0d5a6SGerd Hoffmann     if (qemu_console_is_fixedsize(NULL)) {
783e230dd2SCorentin Chary         width = gwidth;
793e230dd2SCorentin Chary         height = gheight;
803e230dd2SCorentin Chary     } else {
813e230dd2SCorentin Chary         width = COLS;
823e230dd2SCorentin Chary         height = LINES;
833e230dd2SCorentin Chary     }
843e230dd2SCorentin Chary 
853e230dd2SCorentin Chary     if (screenpad)
863e230dd2SCorentin Chary         delwin(screenpad);
873e230dd2SCorentin Chary 
883e230dd2SCorentin Chary     clear();
893e230dd2SCorentin Chary     refresh();
903e230dd2SCorentin Chary 
913e230dd2SCorentin Chary     screenpad = newpad(height, width);
923e230dd2SCorentin Chary 
933e230dd2SCorentin Chary     if (width > COLS) {
943e230dd2SCorentin Chary         px = (width - COLS) / 2;
953e230dd2SCorentin Chary         sminx = 0;
963e230dd2SCorentin Chary         smaxx = COLS;
973e230dd2SCorentin Chary     } else {
983e230dd2SCorentin Chary         px = 0;
993e230dd2SCorentin Chary         sminx = (COLS - width) / 2;
1003e230dd2SCorentin Chary         smaxx = sminx + width;
1013e230dd2SCorentin Chary     }
1023e230dd2SCorentin Chary 
1033e230dd2SCorentin Chary     if (height > LINES) {
1043e230dd2SCorentin Chary         py = (height - LINES) / 2;
1053e230dd2SCorentin Chary         sminy = 0;
1063e230dd2SCorentin Chary         smaxy = LINES;
1073e230dd2SCorentin Chary     } else {
1083e230dd2SCorentin Chary         py = 0;
1093e230dd2SCorentin Chary         sminy = (LINES - height) / 2;
1103e230dd2SCorentin Chary         smaxy = sminy + height;
1113e230dd2SCorentin Chary     }
1123e230dd2SCorentin Chary }
1133e230dd2SCorentin Chary 
1147c20b4a3SGerd Hoffmann static void curses_resize(DisplayChangeListener *dcl,
1157c20b4a3SGerd Hoffmann                           int width, int height)
1163e230dd2SCorentin Chary {
117a93a4a22SGerd Hoffmann     if (width == gwidth && height == gheight) {
1183e230dd2SCorentin Chary         return;
119a93a4a22SGerd Hoffmann     }
1203e230dd2SCorentin Chary 
121a93a4a22SGerd Hoffmann     gwidth = width;
122a93a4a22SGerd Hoffmann     gheight = height;
1233e230dd2SCorentin Chary 
1243e230dd2SCorentin Chary     curses_calc_pad();
1253e230dd2SCorentin Chary }
1263e230dd2SCorentin Chary 
127032ac6f8SGerd Hoffmann #if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE)
128032ac6f8SGerd Hoffmann static volatile sig_atomic_t got_sigwinch;
129032ac6f8SGerd Hoffmann static void curses_winch_check(void)
1303e230dd2SCorentin Chary {
1313e230dd2SCorentin Chary     struct winsize {
1323e230dd2SCorentin Chary         unsigned short ws_row;
1333e230dd2SCorentin Chary         unsigned short ws_col;
1343e230dd2SCorentin Chary         unsigned short ws_xpixel;   /* unused */
1353e230dd2SCorentin Chary         unsigned short ws_ypixel;   /* unused */
1363e230dd2SCorentin Chary     } ws;
1373e230dd2SCorentin Chary 
138032ac6f8SGerd Hoffmann     if (!got_sigwinch) {
1393e230dd2SCorentin Chary         return;
140032ac6f8SGerd Hoffmann     }
141032ac6f8SGerd Hoffmann     got_sigwinch = false;
142032ac6f8SGerd Hoffmann 
143032ac6f8SGerd Hoffmann     if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
144032ac6f8SGerd Hoffmann         return;
145032ac6f8SGerd Hoffmann     }
1463e230dd2SCorentin Chary 
1473e230dd2SCorentin Chary     resize_term(ws.ws_row, ws.ws_col);
1483e230dd2SCorentin Chary     invalidate = 1;
1493e230dd2SCorentin Chary }
150032ac6f8SGerd Hoffmann 
151032ac6f8SGerd Hoffmann static void curses_winch_handler(int signum)
152032ac6f8SGerd Hoffmann {
153032ac6f8SGerd Hoffmann     got_sigwinch = true;
154032ac6f8SGerd Hoffmann }
155032ac6f8SGerd Hoffmann 
156032ac6f8SGerd Hoffmann static void curses_winch_init(void)
157032ac6f8SGerd Hoffmann {
158032ac6f8SGerd Hoffmann     struct sigaction old, winch = {
159032ac6f8SGerd Hoffmann         .sa_handler  = curses_winch_handler,
160032ac6f8SGerd Hoffmann     };
161032ac6f8SGerd Hoffmann     sigaction(SIGWINCH, &winch, &old);
162032ac6f8SGerd Hoffmann }
163032ac6f8SGerd Hoffmann #else
164032ac6f8SGerd Hoffmann static void curses_winch_check(void) {}
165032ac6f8SGerd Hoffmann static void curses_winch_init(void) {}
1663e230dd2SCorentin Chary #endif
1673e230dd2SCorentin Chary 
1687c20b4a3SGerd Hoffmann static void curses_cursor_position(DisplayChangeListener *dcl,
1697c20b4a3SGerd Hoffmann                                    int x, int y)
1703e230dd2SCorentin Chary {
1713e230dd2SCorentin Chary     if (x >= 0) {
1723e230dd2SCorentin Chary         x = sminx + x - px;
1733e230dd2SCorentin Chary         y = sminy + y - py;
1743e230dd2SCorentin Chary 
1753e230dd2SCorentin Chary         if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
1763e230dd2SCorentin Chary             move(y, x);
1773e230dd2SCorentin Chary             curs_set(1);
1783e230dd2SCorentin Chary             /* it seems that curs_set(1) must always be called before
1793e230dd2SCorentin Chary              * curs_set(2) for the latter to have effect */
18081c0d5a6SGerd Hoffmann             if (!qemu_console_is_graphic(NULL)) {
1813e230dd2SCorentin Chary                 curs_set(2);
18281c0d5a6SGerd Hoffmann             }
1833e230dd2SCorentin Chary             return;
1843e230dd2SCorentin Chary         }
1853e230dd2SCorentin Chary     }
1863e230dd2SCorentin Chary 
1873e230dd2SCorentin Chary     curs_set(0);
1883e230dd2SCorentin Chary }
1893e230dd2SCorentin Chary 
1903e230dd2SCorentin Chary /* generic keyboard conversion */
1913e230dd2SCorentin Chary 
1923e230dd2SCorentin Chary #include "curses_keys.h"
1933e230dd2SCorentin Chary 
1943e230dd2SCorentin Chary static kbd_layout_t *kbd_layout = NULL;
1953e230dd2SCorentin Chary 
196bc2ed970SGerd Hoffmann static void curses_refresh(DisplayChangeListener *dcl)
1973e230dd2SCorentin Chary {
19899a9ef44SPeter Maydell     int chr, keysym, keycode, keycode_alt;
1993e230dd2SCorentin Chary 
200032ac6f8SGerd Hoffmann     curses_winch_check();
201032ac6f8SGerd Hoffmann 
2023e230dd2SCorentin Chary     if (invalidate) {
2033e230dd2SCorentin Chary         clear();
2043e230dd2SCorentin Chary         refresh();
2053e230dd2SCorentin Chary         curses_calc_pad();
2061dbfa005SGerd Hoffmann         graphic_hw_invalidate(NULL);
2073e230dd2SCorentin Chary         invalidate = 0;
2083e230dd2SCorentin Chary     }
2093e230dd2SCorentin Chary 
2101dbfa005SGerd Hoffmann     graphic_hw_text_update(NULL, screen);
2113e230dd2SCorentin Chary 
2123e230dd2SCorentin Chary     while (1) {
2133e230dd2SCorentin Chary         /* while there are any pending key strokes to process */
2143e230dd2SCorentin Chary         chr = getch();
2153e230dd2SCorentin Chary 
2163e230dd2SCorentin Chary         if (chr == ERR)
2173e230dd2SCorentin Chary             break;
2183e230dd2SCorentin Chary 
2193e230dd2SCorentin Chary #ifdef KEY_RESIZE
2203e230dd2SCorentin Chary         /* this shouldn't occur when we use a custom SIGWINCH handler */
2213e230dd2SCorentin Chary         if (chr == KEY_RESIZE) {
2223e230dd2SCorentin Chary             clear();
2233e230dd2SCorentin Chary             refresh();
2243e230dd2SCorentin Chary             curses_calc_pad();
225bc2ed970SGerd Hoffmann             curses_update(dcl, 0, 0, width, height);
2263e230dd2SCorentin Chary             continue;
2273e230dd2SCorentin Chary         }
2283e230dd2SCorentin Chary #endif
2293e230dd2SCorentin Chary 
2303e230dd2SCorentin Chary         keycode = curses2keycode[chr];
2313e230dd2SCorentin Chary         keycode_alt = 0;
2323e230dd2SCorentin Chary 
2333e230dd2SCorentin Chary         /* alt key */
2343e230dd2SCorentin Chary         if (keycode == 1) {
23599a9ef44SPeter Maydell             int nextchr = getch();
2363e230dd2SCorentin Chary 
2373e230dd2SCorentin Chary             if (nextchr != ERR) {
2383e230dd2SCorentin Chary                 chr = nextchr;
2393e230dd2SCorentin Chary                 keycode_alt = ALT;
24099a9ef44SPeter Maydell                 keycode = curses2keycode[chr];
2413e230dd2SCorentin Chary 
2423e230dd2SCorentin Chary                 if (keycode != -1) {
2433e230dd2SCorentin Chary                     keycode |= ALT;
2443e230dd2SCorentin Chary 
2453e230dd2SCorentin Chary                     /* process keys reserved for qemu */
2463e230dd2SCorentin Chary                     if (keycode >= QEMU_KEY_CONSOLE0 &&
2473e230dd2SCorentin Chary                             keycode < QEMU_KEY_CONSOLE0 + 9) {
2483e230dd2SCorentin Chary                         erase();
2493e230dd2SCorentin Chary                         wnoutrefresh(stdscr);
2503e230dd2SCorentin Chary                         console_select(keycode - QEMU_KEY_CONSOLE0);
2513e230dd2SCorentin Chary 
2523e230dd2SCorentin Chary                         invalidate = 1;
2533e230dd2SCorentin Chary                         continue;
2543e230dd2SCorentin Chary                     }
2553e230dd2SCorentin Chary                 }
2563e230dd2SCorentin Chary             }
2573e230dd2SCorentin Chary         }
2583e230dd2SCorentin Chary 
2593e230dd2SCorentin Chary         if (kbd_layout) {
2603e230dd2SCorentin Chary             keysym = -1;
2613e230dd2SCorentin Chary             if (chr < CURSES_KEYS)
2623e230dd2SCorentin Chary                 keysym = curses2keysym[chr];
2633e230dd2SCorentin Chary 
2643e230dd2SCorentin Chary             if (keysym == -1) {
265d03703c8SSamuel Thibault                 if (chr < ' ') {
266d03703c8SSamuel Thibault                     keysym = chr + '@';
267d03703c8SSamuel Thibault                     if (keysym >= 'A' && keysym <= 'Z')
268d03703c8SSamuel Thibault                         keysym += 'a' - 'A';
269d03703c8SSamuel Thibault                     keysym |= KEYSYM_CNTRL;
270d03703c8SSamuel Thibault                 } else
2713e230dd2SCorentin Chary                     keysym = chr;
2723e230dd2SCorentin Chary             }
2733e230dd2SCorentin Chary 
2743e230dd2SCorentin Chary             keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
2753e230dd2SCorentin Chary             if (keycode == 0)
2763e230dd2SCorentin Chary                 continue;
2773e230dd2SCorentin Chary 
2783e230dd2SCorentin Chary             keycode |= (keysym & ~KEYSYM_MASK) >> 16;
2793e230dd2SCorentin Chary             keycode |= keycode_alt;
2803e230dd2SCorentin Chary         }
2813e230dd2SCorentin Chary 
2823e230dd2SCorentin Chary         if (keycode == -1)
2833e230dd2SCorentin Chary             continue;
2843e230dd2SCorentin Chary 
28581c0d5a6SGerd Hoffmann         if (qemu_console_is_graphic(NULL)) {
2863e230dd2SCorentin Chary             /* since terminals don't know about key press and release
2873e230dd2SCorentin Chary              * events, we need to emit both for each key received */
288cd100328SGerd Hoffmann             if (keycode & SHIFT) {
289cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
2905a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
2913e230dd2SCorentin Chary             }
292cd100328SGerd Hoffmann             if (keycode & CNTRL) {
293cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
2945a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
2953e230dd2SCorentin Chary             }
296cd100328SGerd Hoffmann             if (keycode & ALT) {
297cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, ALT_CODE, true);
2985a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
299cd100328SGerd Hoffmann             }
300cd100328SGerd Hoffmann             if (keycode & ALTGR) {
301cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
3025a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
303cd100328SGerd Hoffmann             }
304cd100328SGerd Hoffmann 
305f5c0ab13SAndrew Oates             qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
3065a165668SGerd Hoffmann             qemu_input_event_send_key_delay(0);
307f5c0ab13SAndrew Oates             qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
3085a165668SGerd Hoffmann             qemu_input_event_send_key_delay(0);
309cd100328SGerd Hoffmann 
310cd100328SGerd Hoffmann             if (keycode & ALTGR) {
311cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
3125a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
313cd100328SGerd Hoffmann             }
314cd100328SGerd Hoffmann             if (keycode & ALT) {
315cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, ALT_CODE, false);
3165a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
317cd100328SGerd Hoffmann             }
318cd100328SGerd Hoffmann             if (keycode & CNTRL) {
319cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
3205a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
321cd100328SGerd Hoffmann             }
322cd100328SGerd Hoffmann             if (keycode & SHIFT) {
323cd100328SGerd Hoffmann                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
3245a165668SGerd Hoffmann                 qemu_input_event_send_key_delay(0);
325cd100328SGerd Hoffmann             }
3263e230dd2SCorentin Chary         } else {
327bba4e1b5SPeter Maydell             keysym = -1;
328bba4e1b5SPeter Maydell             if (chr < CURSES_KEYS) {
3293e230dd2SCorentin Chary                 keysym = curses2qemu[chr];
330bba4e1b5SPeter Maydell             }
3313e230dd2SCorentin Chary             if (keysym == -1)
3323e230dd2SCorentin Chary                 keysym = chr;
3333e230dd2SCorentin Chary 
3343e230dd2SCorentin Chary             kbd_put_keysym(keysym);
3353e230dd2SCorentin Chary         }
3363e230dd2SCorentin Chary     }
3373e230dd2SCorentin Chary }
3383e230dd2SCorentin Chary 
3393e230dd2SCorentin Chary static void curses_atexit(void)
3403e230dd2SCorentin Chary {
3413e230dd2SCorentin Chary     endwin();
3423e230dd2SCorentin Chary }
3433e230dd2SCorentin Chary 
3443e230dd2SCorentin Chary static void curses_setup(void)
3453e230dd2SCorentin Chary {
3463e230dd2SCorentin Chary     int i, colour_default[8] = {
3474083733dSOGAWA Hirofumi         [QEMU_COLOR_BLACK]   = COLOR_BLACK,
3484083733dSOGAWA Hirofumi         [QEMU_COLOR_BLUE]    = COLOR_BLUE,
3494083733dSOGAWA Hirofumi         [QEMU_COLOR_GREEN]   = COLOR_GREEN,
3504083733dSOGAWA Hirofumi         [QEMU_COLOR_CYAN]    = COLOR_CYAN,
3514083733dSOGAWA Hirofumi         [QEMU_COLOR_RED]     = COLOR_RED,
3524083733dSOGAWA Hirofumi         [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA,
3534083733dSOGAWA Hirofumi         [QEMU_COLOR_YELLOW]  = COLOR_YELLOW,
3544083733dSOGAWA Hirofumi         [QEMU_COLOR_WHITE]   = COLOR_WHITE,
3553e230dd2SCorentin Chary     };
3563e230dd2SCorentin Chary 
3573e230dd2SCorentin Chary     /* input as raw as possible, let everything be interpreted
3583e230dd2SCorentin Chary      * by the guest system */
3593e230dd2SCorentin Chary     initscr(); noecho(); intrflush(stdscr, FALSE);
3603e230dd2SCorentin Chary     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
3613e230dd2SCorentin Chary     start_color(); raw(); scrollok(stdscr, FALSE);
3623e230dd2SCorentin Chary 
3634083733dSOGAWA Hirofumi     /* Make color pair to match color format (3bits bg:3bits fg) */
364615220ddSOGAWA Hirofumi     for (i = 0; i < 64; i++) {
3653e230dd2SCorentin Chary         init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
3663e230dd2SCorentin Chary     }
3674083733dSOGAWA Hirofumi     /* Set default color for more than 64 for safety. */
368615220ddSOGAWA Hirofumi     for (i = 64; i < COLOR_PAIRS; i++) {
369615220ddSOGAWA Hirofumi         init_pair(i, COLOR_WHITE, COLOR_BLACK);
370615220ddSOGAWA Hirofumi     }
371e2368dc9SOGAWA Hirofumi 
372e2368dc9SOGAWA Hirofumi     /*
373e2368dc9SOGAWA Hirofumi      * Setup mapping for vga to curses line graphics.
374e2368dc9SOGAWA Hirofumi      * FIXME: for better font, have to use ncursesw and setlocale()
375e2368dc9SOGAWA Hirofumi      */
376e2368dc9SOGAWA Hirofumi #if 0
377e2368dc9SOGAWA Hirofumi     /* FIXME: map from where? */
378e2368dc9SOGAWA Hirofumi     ACS_S1;
379e2368dc9SOGAWA Hirofumi     ACS_S3;
380e2368dc9SOGAWA Hirofumi     ACS_S7;
381e2368dc9SOGAWA Hirofumi     ACS_S9;
382e2368dc9SOGAWA Hirofumi #endif
383e2368dc9SOGAWA Hirofumi     /* ACS_* is not constant. So, we can't initialize statically. */
384e2368dc9SOGAWA Hirofumi     vga_to_curses['\0'] = ' ';
385e2368dc9SOGAWA Hirofumi     vga_to_curses[0x04] = ACS_DIAMOND;
386e2368dc9SOGAWA Hirofumi     vga_to_curses[0x18] = ACS_UARROW;
387e2368dc9SOGAWA Hirofumi     vga_to_curses[0x19] = ACS_DARROW;
388697783a7SSamuel Thibault     vga_to_curses[0x1a] = ACS_RARROW;
389697783a7SSamuel Thibault     vga_to_curses[0x1b] = ACS_LARROW;
390e2368dc9SOGAWA Hirofumi     vga_to_curses[0x9c] = ACS_STERLING;
391e2368dc9SOGAWA Hirofumi     vga_to_curses[0xb0] = ACS_BOARD;
392e2368dc9SOGAWA Hirofumi     vga_to_curses[0xb1] = ACS_CKBOARD;
393e2368dc9SOGAWA Hirofumi     vga_to_curses[0xb3] = ACS_VLINE;
394e2368dc9SOGAWA Hirofumi     vga_to_curses[0xb4] = ACS_RTEE;
395e2368dc9SOGAWA Hirofumi     vga_to_curses[0xbf] = ACS_URCORNER;
396e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc0] = ACS_LLCORNER;
397e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc1] = ACS_BTEE;
398e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc2] = ACS_TTEE;
399e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc3] = ACS_LTEE;
400e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc4] = ACS_HLINE;
401e2368dc9SOGAWA Hirofumi     vga_to_curses[0xc5] = ACS_PLUS;
402e2368dc9SOGAWA Hirofumi     vga_to_curses[0xce] = ACS_LANTERN;
403e2368dc9SOGAWA Hirofumi     vga_to_curses[0xd8] = ACS_NEQUAL;
404e2368dc9SOGAWA Hirofumi     vga_to_curses[0xd9] = ACS_LRCORNER;
405e2368dc9SOGAWA Hirofumi     vga_to_curses[0xda] = ACS_ULCORNER;
406e2368dc9SOGAWA Hirofumi     vga_to_curses[0xdb] = ACS_BLOCK;
407e2368dc9SOGAWA Hirofumi     vga_to_curses[0xe3] = ACS_PI;
408e2368dc9SOGAWA Hirofumi     vga_to_curses[0xf1] = ACS_PLMINUS;
409e2368dc9SOGAWA Hirofumi     vga_to_curses[0xf2] = ACS_GEQUAL;
410e2368dc9SOGAWA Hirofumi     vga_to_curses[0xf3] = ACS_LEQUAL;
411e2368dc9SOGAWA Hirofumi     vga_to_curses[0xf8] = ACS_DEGREE;
412e2368dc9SOGAWA Hirofumi     vga_to_curses[0xfe] = ACS_BULLET;
413615220ddSOGAWA Hirofumi }
4143e230dd2SCorentin Chary 
4153e230dd2SCorentin Chary static void curses_keyboard_setup(void)
4163e230dd2SCorentin Chary {
4173e230dd2SCorentin Chary #if defined(__APPLE__)
4183e230dd2SCorentin Chary     /* always use generic keymaps */
4193e230dd2SCorentin Chary     if (!keyboard_layout)
4203e230dd2SCorentin Chary         keyboard_layout = "en-us";
4213e230dd2SCorentin Chary #endif
4223e230dd2SCorentin Chary     if(keyboard_layout) {
4233e230dd2SCorentin Chary         kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
4243e230dd2SCorentin Chary         if (!kbd_layout)
4253e230dd2SCorentin Chary             exit(1);
4263e230dd2SCorentin Chary     }
4273e230dd2SCorentin Chary }
4283e230dd2SCorentin Chary 
4297c20b4a3SGerd Hoffmann static const DisplayChangeListenerOps dcl_ops = {
4307c20b4a3SGerd Hoffmann     .dpy_name        = "curses",
4317c20b4a3SGerd Hoffmann     .dpy_text_update = curses_update,
4327c20b4a3SGerd Hoffmann     .dpy_text_resize = curses_resize,
4337c20b4a3SGerd Hoffmann     .dpy_refresh     = curses_refresh,
4347c20b4a3SGerd Hoffmann     .dpy_text_cursor = curses_cursor_position,
4357c20b4a3SGerd Hoffmann };
4367c20b4a3SGerd Hoffmann 
4373e230dd2SCorentin Chary void curses_display_init(DisplayState *ds, int full_screen)
4383e230dd2SCorentin Chary {
4393e230dd2SCorentin Chary #ifndef _WIN32
4403e230dd2SCorentin Chary     if (!isatty(1)) {
4413e230dd2SCorentin Chary         fprintf(stderr, "We need a terminal output\n");
4423e230dd2SCorentin Chary         exit(1);
4433e230dd2SCorentin Chary     }
4443e230dd2SCorentin Chary #endif
4453e230dd2SCorentin Chary 
4463e230dd2SCorentin Chary     curses_setup();
4473e230dd2SCorentin Chary     curses_keyboard_setup();
4483e230dd2SCorentin Chary     atexit(curses_atexit);
4493e230dd2SCorentin Chary 
450032ac6f8SGerd Hoffmann     curses_winch_init();
4513e230dd2SCorentin Chary 
452fedf0d35SMarkus Armbruster     dcl = g_new0(DisplayChangeListener, 1);
4537c20b4a3SGerd Hoffmann     dcl->ops = &dcl_ops;
4545209089fSGerd Hoffmann     register_displaychangelistener(dcl);
4553e230dd2SCorentin Chary 
4563e230dd2SCorentin Chary     invalidate = 1;
4573e230dd2SCorentin Chary }
458