Commit 4d3b6f6e126553107a78999bd1070b086ae3c023
1 parent
c0be16d3
Add an ncurses UI.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3976 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
21 changed files
with
1238 additions
and
34 deletions
Makefile
| @@ -99,6 +99,9 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) | @@ -99,6 +99,9 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) | ||
| 99 | ifdef CONFIG_SDL | 99 | ifdef CONFIG_SDL |
| 100 | OBJS+=sdl.o x_keymap.o | 100 | OBJS+=sdl.o x_keymap.o |
| 101 | endif | 101 | endif |
| 102 | +ifdef CONFIG_CURSES | ||
| 103 | +OBJS+=curses.o | ||
| 104 | +endif | ||
| 102 | OBJS+=vnc.o d3des.o | 105 | OBJS+=vnc.o d3des.o |
| 103 | 106 | ||
| 104 | ifdef CONFIG_COCOA | 107 | ifdef CONFIG_COCOA |
| @@ -122,6 +125,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h | @@ -122,6 +125,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h | ||
| 122 | vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h | 125 | vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h |
| 123 | $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< | 126 | $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< |
| 124 | 127 | ||
| 128 | +curses.o: curses.c keymaps.c curses_keys.h | ||
| 129 | + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< | ||
| 130 | + | ||
| 125 | audio/sdlaudio.o: audio/sdlaudio.c | 131 | audio/sdlaudio.o: audio/sdlaudio.c |
| 126 | $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< | 132 | $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< |
| 127 | 133 |
Makefile.target
| @@ -647,7 +647,7 @@ main.o: CFLAGS+=-p | @@ -647,7 +647,7 @@ main.o: CFLAGS+=-p | ||
| 647 | endif | 647 | endif |
| 648 | 648 | ||
| 649 | $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a | 649 | $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a |
| 650 | - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) | 650 | + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) |
| 651 | 651 | ||
| 652 | endif # !CONFIG_USER_ONLY | 652 | endif # !CONFIG_USER_ONLY |
| 653 | 653 |
configure
| @@ -108,6 +108,7 @@ linux_user="no" | @@ -108,6 +108,7 @@ linux_user="no" | ||
| 108 | darwin_user="no" | 108 | darwin_user="no" |
| 109 | build_docs="no" | 109 | build_docs="no" |
| 110 | uname_release="" | 110 | uname_release="" |
| 111 | +curses="yes" | ||
| 111 | 112 | ||
| 112 | # OS specific | 113 | # OS specific |
| 113 | targetos=`uname -s` | 114 | targetos=`uname -s` |
| @@ -323,6 +324,8 @@ for opt do | @@ -323,6 +324,8 @@ for opt do | ||
| 323 | ;; | 324 | ;; |
| 324 | --disable-werror) werror="no" | 325 | --disable-werror) werror="no" |
| 325 | ;; | 326 | ;; |
| 327 | + --disable-curses) curses="no" | ||
| 328 | + ;; | ||
| 326 | *) echo "ERROR: unknown option $opt"; show_help="yes" | 329 | *) echo "ERROR: unknown option $opt"; show_help="yes" |
| 327 | ;; | 330 | ;; |
| 328 | esac | 331 | esac |
| @@ -669,6 +672,20 @@ EOF | @@ -669,6 +672,20 @@ EOF | ||
| 669 | fi | 672 | fi |
| 670 | fi | 673 | fi |
| 671 | 674 | ||
| 675 | +########################################## | ||
| 676 | +# curses probe | ||
| 677 | + | ||
| 678 | +if test "$curses" = "yes" ; then | ||
| 679 | + curses=no | ||
| 680 | + cat > $TMPC << EOF | ||
| 681 | +#include <curses.h> | ||
| 682 | +int main(void) { return curses_version(); } | ||
| 683 | +EOF | ||
| 684 | + if $cc -o $TMPE $TMPC -lcurses 2> /dev/null ; then | ||
| 685 | + curses=yes | ||
| 686 | + fi | ||
| 687 | +fi # test "$curses" | ||
| 688 | + | ||
| 672 | # Check if tools are available to build documentation. | 689 | # Check if tools are available to build documentation. |
| 673 | if [ -x "`which texi2html 2>/dev/null`" ] && \ | 690 | if [ -x "`which texi2html 2>/dev/null`" ] && \ |
| 674 | [ -x "`which pod2man 2>/dev/null`" ]; then | 691 | [ -x "`which pod2man 2>/dev/null`" ]; then |
| @@ -720,6 +737,7 @@ echo "SDL support $sdl" | @@ -720,6 +737,7 @@ echo "SDL support $sdl" | ||
| 720 | if test "$sdl" != "no" ; then | 737 | if test "$sdl" != "no" ; then |
| 721 | echo "SDL static link $sdl_static" | 738 | echo "SDL static link $sdl_static" |
| 722 | fi | 739 | fi |
| 740 | +echo "curses support $curses" | ||
| 723 | echo "mingw32 support $mingw32" | 741 | echo "mingw32 support $mingw32" |
| 724 | echo "Adlib support $adlib" | 742 | echo "Adlib support $adlib" |
| 725 | echo "AC97 support $ac97" | 743 | echo "AC97 support $ac97" |
| @@ -974,8 +992,13 @@ if test "$sdl1" = "yes" ; then | @@ -974,8 +992,13 @@ if test "$sdl1" = "yes" ; then | ||
| 974 | fi | 992 | fi |
| 975 | fi | 993 | fi |
| 976 | if test "$cocoa" = "yes" ; then | 994 | if test "$cocoa" = "yes" ; then |
| 977 | - echo "#define CONFIG_COCOA 1" >> $config_h | ||
| 978 | - echo "CONFIG_COCOA=yes" >> $config_mak | 995 | + echo "#define CONFIG_COCOA 1" >> $config_h |
| 996 | + echo "CONFIG_COCOA=yes" >> $config_mak | ||
| 997 | +fi | ||
| 998 | +if test "$curses" = "yes" ; then | ||
| 999 | + echo "#define CONFIG_CURSES 1" >> $config_h | ||
| 1000 | + echo "CONFIG_CURSES=yes" >> $config_mak | ||
| 1001 | + echo "CURSES_LIBS=-lcurses" >> $config_mak | ||
| 979 | fi | 1002 | fi |
| 980 | 1003 | ||
| 981 | # XXX: suppress that | 1004 | # XXX: suppress that |
| @@ -1040,7 +1063,8 @@ if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ | @@ -1040,7 +1063,8 @@ if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ | ||
| 1040 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then | 1063 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then |
| 1041 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" | 1064 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" |
| 1042 | echo "To build QEMU without graphical output configure with --disable-gfx-check" | 1065 | echo "To build QEMU without graphical output configure with --disable-gfx-check" |
| 1043 | - echo "Note that this will disable all output from the virtual graphics card." | 1066 | + echo "Note that this will disable all output from the virtual graphics card" |
| 1067 | + echo "except through VNC or curses." | ||
| 1044 | exit 1; | 1068 | exit 1; |
| 1045 | fi | 1069 | fi |
| 1046 | 1070 |
console.c
| @@ -121,6 +121,7 @@ struct TextConsole { | @@ -121,6 +121,7 @@ struct TextConsole { | ||
| 121 | vga_hw_update_ptr hw_update; | 121 | vga_hw_update_ptr hw_update; |
| 122 | vga_hw_invalidate_ptr hw_invalidate; | 122 | vga_hw_invalidate_ptr hw_invalidate; |
| 123 | vga_hw_screen_dump_ptr hw_screen_dump; | 123 | vga_hw_screen_dump_ptr hw_screen_dump; |
| 124 | + vga_hw_text_update_ptr hw_text_update; | ||
| 124 | void *hw; | 125 | void *hw; |
| 125 | 126 | ||
| 126 | int g_width, g_height; | 127 | int g_width, g_height; |
| @@ -135,6 +136,7 @@ struct TextConsole { | @@ -135,6 +136,7 @@ struct TextConsole { | ||
| 135 | TextAttributes t_attrib_default; /* default text attributes */ | 136 | TextAttributes t_attrib_default; /* default text attributes */ |
| 136 | TextAttributes t_attrib; /* currently active text attributes */ | 137 | TextAttributes t_attrib; /* currently active text attributes */ |
| 137 | TextCell *cells; | 138 | TextCell *cells; |
| 139 | + int text_x[2], text_y[2], cursor_invalidate; | ||
| 138 | 140 | ||
| 139 | enum TTYState state; | 141 | enum TTYState state; |
| 140 | int esc_params[MAX_ESC_PARAMS]; | 142 | int esc_params[MAX_ESC_PARAMS]; |
| @@ -171,6 +173,12 @@ void vga_hw_screen_dump(const char *filename) | @@ -171,6 +173,12 @@ void vga_hw_screen_dump(const char *filename) | ||
| 171 | consoles[0]->hw_screen_dump(consoles[0]->hw, filename); | 173 | consoles[0]->hw_screen_dump(consoles[0]->hw, filename); |
| 172 | } | 174 | } |
| 173 | 175 | ||
| 176 | +void vga_hw_text_update(console_ch_t *chardata) | ||
| 177 | +{ | ||
| 178 | + if (active_console && active_console->hw_text_update) | ||
| 179 | + active_console->hw_text_update(active_console->hw, chardata); | ||
| 180 | +} | ||
| 181 | + | ||
| 174 | /* convert a RGBA color to a color index usable in graphic primitives */ | 182 | /* convert a RGBA color to a color index usable in graphic primitives */ |
| 175 | static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) | 183 | static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) |
| 176 | { | 184 | { |
| @@ -515,12 +523,25 @@ static void text_console_resize(TextConsole *s) | @@ -515,12 +523,25 @@ static void text_console_resize(TextConsole *s) | ||
| 515 | s->cells = cells; | 523 | s->cells = cells; |
| 516 | } | 524 | } |
| 517 | 525 | ||
| 526 | +static inline void text_update_xy(TextConsole *s, int x, int y) | ||
| 527 | +{ | ||
| 528 | + s->text_x[0] = MIN(s->text_x[0], x); | ||
| 529 | + s->text_x[1] = MAX(s->text_x[1], x); | ||
| 530 | + s->text_y[0] = MIN(s->text_y[0], y); | ||
| 531 | + s->text_y[1] = MAX(s->text_y[1], y); | ||
| 532 | +} | ||
| 533 | + | ||
| 518 | static void update_xy(TextConsole *s, int x, int y) | 534 | static void update_xy(TextConsole *s, int x, int y) |
| 519 | { | 535 | { |
| 520 | TextCell *c; | 536 | TextCell *c; |
| 521 | int y1, y2; | 537 | int y1, y2; |
| 522 | 538 | ||
| 523 | if (s == active_console) { | 539 | if (s == active_console) { |
| 540 | + if (!s->ds->depth) { | ||
| 541 | + text_update_xy(s, x, y); | ||
| 542 | + return; | ||
| 543 | + } | ||
| 544 | + | ||
| 524 | y1 = (s->y_base + y) % s->total_height; | 545 | y1 = (s->y_base + y) % s->total_height; |
| 525 | y2 = y1 - s->y_displayed; | 546 | y2 = y1 - s->y_displayed; |
| 526 | if (y2 < 0) | 547 | if (y2 < 0) |
| @@ -542,6 +563,12 @@ static void console_show_cursor(TextConsole *s, int show) | @@ -542,6 +563,12 @@ static void console_show_cursor(TextConsole *s, int show) | ||
| 542 | 563 | ||
| 543 | if (s == active_console) { | 564 | if (s == active_console) { |
| 544 | int x = s->x; | 565 | int x = s->x; |
| 566 | + | ||
| 567 | + if (!s->ds->depth) { | ||
| 568 | + s->cursor_invalidate = 1; | ||
| 569 | + return; | ||
| 570 | + } | ||
| 571 | + | ||
| 545 | if (x >= s->width) { | 572 | if (x >= s->width) { |
| 546 | x = s->width - 1; | 573 | x = s->width - 1; |
| 547 | } | 574 | } |
| @@ -571,6 +598,14 @@ static void console_refresh(TextConsole *s) | @@ -571,6 +598,14 @@ static void console_refresh(TextConsole *s) | ||
| 571 | 598 | ||
| 572 | if (s != active_console) | 599 | if (s != active_console) |
| 573 | return; | 600 | return; |
| 601 | + if (!s->ds->depth) { | ||
| 602 | + s->text_x[0] = 0; | ||
| 603 | + s->text_y[0] = 0; | ||
| 604 | + s->text_x[1] = s->width - 1; | ||
| 605 | + s->text_y[1] = s->height - 1; | ||
| 606 | + s->cursor_invalidate = 1; | ||
| 607 | + return; | ||
| 608 | + } | ||
| 574 | 609 | ||
| 575 | vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, | 610 | vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, |
| 576 | color_table[0][COLOR_BLACK]); | 611 | color_table[0][COLOR_BLACK]); |
| @@ -648,6 +683,14 @@ static void console_put_lf(TextConsole *s) | @@ -648,6 +683,14 @@ static void console_put_lf(TextConsole *s) | ||
| 648 | c++; | 683 | c++; |
| 649 | } | 684 | } |
| 650 | if (s == active_console && s->y_displayed == s->y_base) { | 685 | if (s == active_console && s->y_displayed == s->y_base) { |
| 686 | + if (!s->ds->depth) { | ||
| 687 | + s->text_x[0] = 0; | ||
| 688 | + s->text_y[0] = 0; | ||
| 689 | + s->text_x[1] = s->width - 1; | ||
| 690 | + s->text_y[1] = s->height - 1; | ||
| 691 | + return; | ||
| 692 | + } | ||
| 693 | + | ||
| 651 | vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, | 694 | vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, |
| 652 | s->width * FONT_WIDTH, | 695 | s->width * FONT_WIDTH, |
| 653 | (s->height - 1) * FONT_HEIGHT); | 696 | (s->height - 1) * FONT_HEIGHT); |
| @@ -998,21 +1041,7 @@ void console_select(unsigned int index) | @@ -998,21 +1041,7 @@ void console_select(unsigned int index) | ||
| 998 | s = consoles[index]; | 1041 | s = consoles[index]; |
| 999 | if (s) { | 1042 | if (s) { |
| 1000 | active_console = s; | 1043 | active_console = s; |
| 1001 | - if (s->console_type != GRAPHIC_CONSOLE) { | ||
| 1002 | - if (s->g_width != s->ds->width || | ||
| 1003 | - s->g_height != s->ds->height) { | ||
| 1004 | - if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) { | ||
| 1005 | - dpy_resize(s->ds, s->g_width, s->g_height); | ||
| 1006 | - } else { | ||
| 1007 | - s->g_width = s->ds->width; | ||
| 1008 | - s->g_height = s->ds->height; | ||
| 1009 | - text_console_resize(s); | ||
| 1010 | - } | ||
| 1011 | - } | ||
| 1012 | - console_refresh(s); | ||
| 1013 | - } else { | ||
| 1014 | - vga_hw_invalidate(); | ||
| 1015 | - } | 1044 | + vga_hw_invalidate(); |
| 1016 | } | 1045 | } |
| 1017 | } | 1046 | } |
| 1018 | 1047 | ||
| @@ -1116,6 +1145,52 @@ void kbd_put_keysym(int keysym) | @@ -1116,6 +1145,52 @@ void kbd_put_keysym(int keysym) | ||
| 1116 | } | 1145 | } |
| 1117 | } | 1146 | } |
| 1118 | 1147 | ||
| 1148 | +static void text_console_invalidate(void *opaque) | ||
| 1149 | +{ | ||
| 1150 | + TextConsole *s = (TextConsole *) opaque; | ||
| 1151 | + | ||
| 1152 | + if (s->console_type != GRAPHIC_CONSOLE) { | ||
| 1153 | + if (s->g_width != s->ds->width || | ||
| 1154 | + s->g_height != s->ds->height) { | ||
| 1155 | + if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) | ||
| 1156 | + dpy_resize(s->ds, s->g_width, s->g_height); | ||
| 1157 | + else { | ||
| 1158 | + s->g_width = s->ds->width; | ||
| 1159 | + s->g_height = s->ds->height; | ||
| 1160 | + text_console_resize(s); | ||
| 1161 | + } | ||
| 1162 | + } | ||
| 1163 | + } | ||
| 1164 | + console_refresh(s); | ||
| 1165 | +} | ||
| 1166 | + | ||
| 1167 | +static void text_console_update(void *opaque, console_ch_t *chardata) | ||
| 1168 | +{ | ||
| 1169 | + TextConsole *s = (TextConsole *) opaque; | ||
| 1170 | + int i, j, src; | ||
| 1171 | + | ||
| 1172 | + if (s->text_x[0] <= s->text_x[1]) { | ||
| 1173 | + src = (s->y_base + s->text_y[0]) * s->width; | ||
| 1174 | + chardata += s->text_y[0] * s->width; | ||
| 1175 | + for (i = s->text_y[0]; i <= s->text_y[1]; i ++) | ||
| 1176 | + for (j = 0; j < s->width; j ++, src ++) | ||
| 1177 | + console_write_ch(chardata ++, s->cells[src].ch | | ||
| 1178 | + (s->cells[src].t_attrib.fgcol << 12) | | ||
| 1179 | + (s->cells[src].t_attrib.bgcol << 8) | | ||
| 1180 | + (s->cells[src].t_attrib.bold << 21)); | ||
| 1181 | + dpy_update(s->ds, s->text_x[0], s->text_y[0], | ||
| 1182 | + s->text_x[1] - s->text_x[0], i - s->text_y[0]); | ||
| 1183 | + s->text_x[0] = s->width; | ||
| 1184 | + s->text_y[0] = s->height; | ||
| 1185 | + s->text_x[1] = 0; | ||
| 1186 | + s->text_y[1] = 0; | ||
| 1187 | + } | ||
| 1188 | + if (s->cursor_invalidate) { | ||
| 1189 | + dpy_cursor(s->ds, s->x, s->y); | ||
| 1190 | + s->cursor_invalidate = 0; | ||
| 1191 | + } | ||
| 1192 | +} | ||
| 1193 | + | ||
| 1119 | static TextConsole *new_console(DisplayState *ds, console_type_t console_type) | 1194 | static TextConsole *new_console(DisplayState *ds, console_type_t console_type) |
| 1120 | { | 1195 | { |
| 1121 | TextConsole *s; | 1196 | TextConsole *s; |
| @@ -1150,6 +1225,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) | @@ -1150,6 +1225,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) | ||
| 1150 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, | 1225 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, |
| 1151 | vga_hw_invalidate_ptr invalidate, | 1226 | vga_hw_invalidate_ptr invalidate, |
| 1152 | vga_hw_screen_dump_ptr screen_dump, | 1227 | vga_hw_screen_dump_ptr screen_dump, |
| 1228 | + vga_hw_text_update_ptr text_update, | ||
| 1153 | void *opaque) | 1229 | void *opaque) |
| 1154 | { | 1230 | { |
| 1155 | TextConsole *s; | 1231 | TextConsole *s; |
| @@ -1160,13 +1236,14 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, | @@ -1160,13 +1236,14 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, | ||
| 1160 | s->hw_update = update; | 1236 | s->hw_update = update; |
| 1161 | s->hw_invalidate = invalidate; | 1237 | s->hw_invalidate = invalidate; |
| 1162 | s->hw_screen_dump = screen_dump; | 1238 | s->hw_screen_dump = screen_dump; |
| 1239 | + s->hw_text_update = text_update; | ||
| 1163 | s->hw = opaque; | 1240 | s->hw = opaque; |
| 1164 | return s; | 1241 | return s; |
| 1165 | } | 1242 | } |
| 1166 | 1243 | ||
| 1167 | int is_graphic_console(void) | 1244 | int is_graphic_console(void) |
| 1168 | { | 1245 | { |
| 1169 | - return active_console->console_type == GRAPHIC_CONSOLE; | 1246 | + return active_console && active_console->console_type == GRAPHIC_CONSOLE; |
| 1170 | } | 1247 | } |
| 1171 | 1248 | ||
| 1172 | void console_color_init(DisplayState *ds) | 1249 | void console_color_init(DisplayState *ds) |
| @@ -1234,6 +1311,10 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) | @@ -1234,6 +1311,10 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) | ||
| 1234 | s->g_width = width; | 1311 | s->g_width = width; |
| 1235 | s->g_height = height; | 1312 | s->g_height = height; |
| 1236 | 1313 | ||
| 1314 | + s->hw_invalidate = text_console_invalidate; | ||
| 1315 | + s->hw_text_update = text_console_update; | ||
| 1316 | + s->hw = s; | ||
| 1317 | + | ||
| 1237 | /* Set text attribute defaults */ | 1318 | /* Set text attribute defaults */ |
| 1238 | s->t_attrib_default.bold = 0; | 1319 | s->t_attrib_default.bold = 0; |
| 1239 | s->t_attrib_default.uline = 0; | 1320 | s->t_attrib_default.uline = 0; |
console.h
| @@ -79,6 +79,7 @@ struct DisplayState { | @@ -79,6 +79,7 @@ struct DisplayState { | ||
| 79 | int dst_x, int dst_y, int w, int h); | 79 | int dst_x, int dst_y, int w, int h); |
| 80 | void (*dpy_fill)(struct DisplayState *s, int x, int y, | 80 | void (*dpy_fill)(struct DisplayState *s, int x, int y, |
| 81 | int w, int h, uint32_t c); | 81 | int w, int h, uint32_t c); |
| 82 | + void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); | ||
| 82 | void (*mouse_set)(int x, int y, int on); | 83 | void (*mouse_set)(int x, int y, int on); |
| 83 | void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, | 84 | void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, |
| 84 | uint8_t *image, uint8_t *mask); | 85 | uint8_t *image, uint8_t *mask); |
| @@ -94,17 +95,32 @@ static inline void dpy_resize(DisplayState *s, int w, int h) | @@ -94,17 +95,32 @@ static inline void dpy_resize(DisplayState *s, int w, int h) | ||
| 94 | s->dpy_resize(s, w, h); | 95 | s->dpy_resize(s, w, h); |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 98 | +static inline void dpy_cursor(DisplayState *s, int x, int y) | ||
| 99 | +{ | ||
| 100 | + if (s->dpy_text_cursor) | ||
| 101 | + s->dpy_text_cursor(s, x, y); | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +typedef unsigned long console_ch_t; | ||
| 105 | +static inline void console_write_ch(console_ch_t *dest, uint32_t ch) | ||
| 106 | +{ | ||
| 107 | + cpu_to_le32wu((uint32_t *) dest, ch); | ||
| 108 | +} | ||
| 109 | + | ||
| 97 | typedef void (*vga_hw_update_ptr)(void *); | 110 | typedef void (*vga_hw_update_ptr)(void *); |
| 98 | typedef void (*vga_hw_invalidate_ptr)(void *); | 111 | typedef void (*vga_hw_invalidate_ptr)(void *); |
| 99 | typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); | 112 | typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); |
| 113 | +typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); | ||
| 100 | 114 | ||
| 101 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, | 115 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, |
| 102 | vga_hw_invalidate_ptr invalidate, | 116 | vga_hw_invalidate_ptr invalidate, |
| 103 | vga_hw_screen_dump_ptr screen_dump, | 117 | vga_hw_screen_dump_ptr screen_dump, |
| 118 | + vga_hw_text_update_ptr text_update, | ||
| 104 | void *opaque); | 119 | void *opaque); |
| 105 | void vga_hw_update(void); | 120 | void vga_hw_update(void); |
| 106 | void vga_hw_invalidate(void); | 121 | void vga_hw_invalidate(void); |
| 107 | void vga_hw_screen_dump(const char *filename); | 122 | void vga_hw_screen_dump(const char *filename); |
| 123 | +void vga_hw_text_update(console_ch_t *chardata); | ||
| 108 | 124 | ||
| 109 | int is_graphic_console(void); | 125 | int is_graphic_console(void); |
| 110 | CharDriverState *text_console_init(DisplayState *ds, const char *p); | 126 | CharDriverState *text_console_init(DisplayState *ds, const char *p); |
| @@ -124,6 +140,9 @@ int vnc_display_open(DisplayState *ds, const char *display); | @@ -124,6 +140,9 @@ int vnc_display_open(DisplayState *ds, const char *display); | ||
| 124 | int vnc_display_password(DisplayState *ds, const char *password); | 140 | int vnc_display_password(DisplayState *ds, const char *password); |
| 125 | void do_info_vnc(void); | 141 | void do_info_vnc(void); |
| 126 | 142 | ||
| 143 | +/* curses.c */ | ||
| 144 | +void curses_display_init(DisplayState *ds, int full_screen); | ||
| 145 | + | ||
| 127 | /* x_keymap.c */ | 146 | /* x_keymap.c */ |
| 128 | extern uint8_t _translate_keycode(const int key); | 147 | extern uint8_t _translate_keycode(const int key); |
| 129 | 148 |
curses.c
0 โ 100644
| 1 | +/* | ||
| 2 | + * QEMU curses/ncurses display driver | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org> | ||
| 5 | + * | ||
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | + * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | + * in the Software without restriction, including without limitation the rights | ||
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | + * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | + * furnished to do so, subject to the following conditions: | ||
| 12 | + * | ||
| 13 | + * The above copyright notice and this permission notice shall be included in | ||
| 14 | + * all copies or substantial portions of the Software. | ||
| 15 | + * | ||
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | + * THE SOFTWARE. | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +#include "qemu-common.h" | ||
| 26 | +#include "console.h" | ||
| 27 | +#include "sysemu.h" | ||
| 28 | + | ||
| 29 | +#include <curses.h> | ||
| 30 | + | ||
| 31 | +#ifndef _WIN32 | ||
| 32 | +#include <signal.h> | ||
| 33 | +#include <sys/ioctl.h> | ||
| 34 | +#include <termios.h> | ||
| 35 | +#endif | ||
| 36 | + | ||
| 37 | +#define FONT_HEIGHT 16 | ||
| 38 | +#define FONT_WIDTH 8 | ||
| 39 | + | ||
| 40 | +static console_ch_t screen[160 * 100]; | ||
| 41 | +static WINDOW *screenpad = NULL; | ||
| 42 | +static int width, height, gwidth, gheight, invalidate; | ||
| 43 | +static int px, py, sminx, sminy, smaxx, smaxy; | ||
| 44 | + | ||
| 45 | +static void curses_update(DisplayState *ds, int x, int y, int w, int h) | ||
| 46 | +{ | ||
| 47 | + chtype *line; | ||
| 48 | + | ||
| 49 | + line = ((chtype *) screen) + y * width; | ||
| 50 | + for (h += y; y < h; y ++, line += width) | ||
| 51 | + mvwaddchnstr(screenpad, y, 0, line, width); | ||
| 52 | + | ||
| 53 | + pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); | ||
| 54 | + refresh(); | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +static void curses_calc_pad(void) | ||
| 58 | +{ | ||
| 59 | + if (is_graphic_console()) { | ||
| 60 | + width = gwidth; | ||
| 61 | + height = gheight; | ||
| 62 | + } else { | ||
| 63 | + width = COLS; | ||
| 64 | + height = LINES; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + if (screenpad) | ||
| 68 | + delwin(screenpad); | ||
| 69 | + | ||
| 70 | + clear(); | ||
| 71 | + refresh(); | ||
| 72 | + | ||
| 73 | + screenpad = newpad(height, width); | ||
| 74 | + | ||
| 75 | + if (width > COLS) { | ||
| 76 | + px = (width - COLS) / 2; | ||
| 77 | + sminx = 0; | ||
| 78 | + smaxx = COLS; | ||
| 79 | + } else { | ||
| 80 | + px = 0; | ||
| 81 | + sminx = (COLS - width) / 2; | ||
| 82 | + smaxx = sminx + width; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + if (height > LINES) { | ||
| 86 | + py = (height - LINES) / 2; | ||
| 87 | + sminy = 0; | ||
| 88 | + smaxy = LINES; | ||
| 89 | + } else { | ||
| 90 | + py = 0; | ||
| 91 | + sminy = (LINES - height) / 2; | ||
| 92 | + smaxy = sminy + height; | ||
| 93 | + } | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +static void curses_resize(DisplayState *ds, int w, int h) | ||
| 97 | +{ | ||
| 98 | + if (w == gwidth && h == gheight) | ||
| 99 | + return; | ||
| 100 | + | ||
| 101 | + gwidth = w; | ||
| 102 | + gheight = h; | ||
| 103 | + | ||
| 104 | + curses_calc_pad(); | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +#ifndef _WIN32 | ||
| 108 | +#ifdef SIGWINCH | ||
| 109 | +static void curses_winch_handler(int signum) | ||
| 110 | +{ | ||
| 111 | + struct winsize { | ||
| 112 | + unsigned short ws_row; | ||
| 113 | + unsigned short ws_col; | ||
| 114 | + unsigned short ws_xpixel; /* unused */ | ||
| 115 | + unsigned short ws_ypixel; /* unused */ | ||
| 116 | + } ws; | ||
| 117 | + | ||
| 118 | + /* terminal size changed */ | ||
| 119 | + if (ioctl(1, TIOCGWINSZ, &ws) == -1) | ||
| 120 | + return; | ||
| 121 | + | ||
| 122 | + resize_term(ws.ws_row, ws.ws_col); | ||
| 123 | + curses_calc_pad(); | ||
| 124 | + invalidate = 1; | ||
| 125 | + | ||
| 126 | + /* some systems require this */ | ||
| 127 | + signal(SIGWINCH, curses_winch_handler); | ||
| 128 | +} | ||
| 129 | +#endif | ||
| 130 | +#endif | ||
| 131 | + | ||
| 132 | +static void curses_cursor_position(DisplayState *ds, int x, int y) | ||
| 133 | +{ | ||
| 134 | + if (x >= 0) { | ||
| 135 | + x = sminx + x - px; | ||
| 136 | + y = sminy + y - py; | ||
| 137 | + | ||
| 138 | + if (x >= 0 && y >= 0 && x < COLS && y < LINES) { | ||
| 139 | + move(y, x); | ||
| 140 | + curs_set(1); | ||
| 141 | + /* it seems that curs_set(1) must always be called before | ||
| 142 | + * curs_set(2) for the latter to have effect */ | ||
| 143 | + if (!is_graphic_console()) | ||
| 144 | + curs_set(2); | ||
| 145 | + return; | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + curs_set(0); | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +/* generic keyboard conversion */ | ||
| 153 | + | ||
| 154 | +#include "curses_keys.h" | ||
| 155 | +#include "keymaps.c" | ||
| 156 | + | ||
| 157 | +static kbd_layout_t *kbd_layout = 0; | ||
| 158 | +static int keycode2keysym[CURSES_KEYS]; | ||
| 159 | + | ||
| 160 | +static void curses_refresh(DisplayState *ds) | ||
| 161 | +{ | ||
| 162 | + int chr, nextchr, keysym, keycode; | ||
| 163 | + | ||
| 164 | + if (invalidate) { | ||
| 165 | + clear(); | ||
| 166 | + refresh(); | ||
| 167 | + curses_calc_pad(); | ||
| 168 | + ds->width = FONT_WIDTH * width; | ||
| 169 | + ds->height = FONT_HEIGHT * height; | ||
| 170 | + vga_hw_invalidate(); | ||
| 171 | + invalidate = 0; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + vga_hw_text_update(screen); | ||
| 175 | + | ||
| 176 | + nextchr = ERR; | ||
| 177 | + while (1) { | ||
| 178 | + /* while there are any pending key strokes to process */ | ||
| 179 | + if (nextchr == ERR) | ||
| 180 | + chr = getch(); | ||
| 181 | + else { | ||
| 182 | + chr = nextchr; | ||
| 183 | + nextchr = ERR; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + if (chr == ERR) | ||
| 187 | + break; | ||
| 188 | + | ||
| 189 | + /* this shouldn't occur when we use a custom SIGWINCH handler */ | ||
| 190 | + if (chr == KEY_RESIZE) { | ||
| 191 | + clear(); | ||
| 192 | + refresh(); | ||
| 193 | + curses_calc_pad(); | ||
| 194 | + curses_update(ds, 0, 0, width, height); | ||
| 195 | + ds->width = FONT_WIDTH * width; | ||
| 196 | + ds->height = FONT_HEIGHT * height; | ||
| 197 | + continue; | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + keycode = curses2keycode[chr]; | ||
| 201 | + if (keycode == -1) | ||
| 202 | + continue; | ||
| 203 | + | ||
| 204 | + /* alt key */ | ||
| 205 | + if (keycode == 1) { | ||
| 206 | + nextchr = getch(); | ||
| 207 | + | ||
| 208 | + if (nextchr != ERR) { | ||
| 209 | + keycode = curses2keycode[nextchr]; | ||
| 210 | + nextchr = ERR; | ||
| 211 | + if (keycode == -1) | ||
| 212 | + continue; | ||
| 213 | + | ||
| 214 | + keycode |= ALT; | ||
| 215 | + | ||
| 216 | + /* process keys reserved for qemu */ | ||
| 217 | + if (keycode >= QEMU_KEY_CONSOLE0 && | ||
| 218 | + keycode < QEMU_KEY_CONSOLE0 + 9) { | ||
| 219 | + erase(); | ||
| 220 | + wnoutrefresh(stdscr); | ||
| 221 | + console_select(keycode - QEMU_KEY_CONSOLE0); | ||
| 222 | + | ||
| 223 | + invalidate = 1; | ||
| 224 | + continue; | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + if (kbd_layout && !(keycode & GREY)) { | ||
| 230 | + keysym = keycode2keysym[keycode & KEY_MASK]; | ||
| 231 | + if (keysym == -1) | ||
| 232 | + keysym = chr; | ||
| 233 | + | ||
| 234 | + keycode &= ~KEY_MASK; | ||
| 235 | + keycode |= keysym2scancode(kbd_layout, keysym); | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + if (is_graphic_console()) { | ||
| 239 | + /* since terminals don't know about key press and release | ||
| 240 | + * events, we need to emit both for each key received */ | ||
| 241 | + if (keycode & SHIFT) | ||
| 242 | + kbd_put_keycode(SHIFT_CODE); | ||
| 243 | + if (keycode & CNTRL) | ||
| 244 | + kbd_put_keycode(CNTRL_CODE); | ||
| 245 | + if (keycode & ALT) | ||
| 246 | + kbd_put_keycode(ALT_CODE); | ||
| 247 | + if (keycode & GREY) | ||
| 248 | + kbd_put_keycode(GREY_CODE); | ||
| 249 | + kbd_put_keycode(keycode & KEY_MASK); | ||
| 250 | + if (keycode & GREY) | ||
| 251 | + kbd_put_keycode(GREY_CODE); | ||
| 252 | + kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); | ||
| 253 | + if (keycode & ALT) | ||
| 254 | + kbd_put_keycode(ALT_CODE | KEY_RELEASE); | ||
| 255 | + if (keycode & CNTRL) | ||
| 256 | + kbd_put_keycode(CNTRL_CODE | KEY_RELEASE); | ||
| 257 | + if (keycode & SHIFT) | ||
| 258 | + kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); | ||
| 259 | + } else { | ||
| 260 | + keysym = curses2keysym[chr]; | ||
| 261 | + if (keysym == -1) | ||
| 262 | + keysym = chr; | ||
| 263 | + | ||
| 264 | + kbd_put_keysym(keysym); | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +static void curses_cleanup(void *opaque) | ||
| 270 | +{ | ||
| 271 | + endwin(); | ||
| 272 | +} | ||
| 273 | + | ||
| 274 | +static void curses_atexit(void) | ||
| 275 | +{ | ||
| 276 | + curses_cleanup(NULL); | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +static void curses_setup(void) | ||
| 280 | +{ | ||
| 281 | + int i, colour_default[8] = { | ||
| 282 | + COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, | ||
| 283 | + COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, | ||
| 284 | + }; | ||
| 285 | + | ||
| 286 | + /* input as raw as possible, let everything be interpreted | ||
| 287 | + * by the guest system */ | ||
| 288 | + initscr(); noecho(); intrflush(stdscr, FALSE); | ||
| 289 | + nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); | ||
| 290 | + start_color(); raw(); scrollok(stdscr, FALSE); | ||
| 291 | + | ||
| 292 | + for (i = 0; i < 64; i ++) | ||
| 293 | + init_pair(i, colour_default[i & 7], colour_default[i >> 3]); | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +static void curses_keyboard_setup(void) | ||
| 297 | +{ | ||
| 298 | + int i, keycode, keysym; | ||
| 299 | + | ||
| 300 | +#if defined(__APPLE__) | ||
| 301 | + /* always use generic keymaps */ | ||
| 302 | + if (!keyboard_layout) | ||
| 303 | + keyboard_layout = "en-us"; | ||
| 304 | +#endif | ||
| 305 | + if(keyboard_layout) { | ||
| 306 | + kbd_layout = init_keyboard_layout(keyboard_layout); | ||
| 307 | + if (!kbd_layout) | ||
| 308 | + exit(1); | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + for (i = 0; i < CURSES_KEYS; i ++) | ||
| 312 | + keycode2keysym[i] = -1; | ||
| 313 | + | ||
| 314 | + for (i = 0; i < CURSES_KEYS; i ++) { | ||
| 315 | + if (curses2keycode[i] == -1) | ||
| 316 | + continue; | ||
| 317 | + | ||
| 318 | + keycode = curses2keycode[i] & KEY_MASK; | ||
| 319 | + if (keycode2keysym[keycode] >= 0) | ||
| 320 | + continue; | ||
| 321 | + | ||
| 322 | + for (keysym = 0; keysym < CURSES_KEYS; keysym ++) | ||
| 323 | + if (curses2keycode[keysym] == keycode) { | ||
| 324 | + keycode2keysym[keycode] = keysym; | ||
| 325 | + break; | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + if (keysym >= CURSES_KEYS) | ||
| 329 | + keycode2keysym[keycode] = i; | ||
| 330 | + } | ||
| 331 | +} | ||
| 332 | + | ||
| 333 | +void curses_display_init(DisplayState *ds, int full_screen) | ||
| 334 | +{ | ||
| 335 | +#ifndef _WIN32 | ||
| 336 | + if (!isatty(1)) { | ||
| 337 | + fprintf(stderr, "We need a terminal output\n"); | ||
| 338 | + exit(1); | ||
| 339 | + } | ||
| 340 | +#endif | ||
| 341 | + | ||
| 342 | + curses_setup(); | ||
| 343 | + curses_keyboard_setup(); | ||
| 344 | + atexit(curses_atexit); | ||
| 345 | + | ||
| 346 | +#ifndef _WIN32 | ||
| 347 | + signal(SIGINT, SIG_DFL); | ||
| 348 | + signal(SIGQUIT, SIG_DFL); | ||
| 349 | +#ifdef SIGWINCH | ||
| 350 | + /* some curses implementations provide a handler, but we | ||
| 351 | + * want to be sure this is handled regardless of the library */ | ||
| 352 | + signal(SIGWINCH, curses_winch_handler); | ||
| 353 | +#endif | ||
| 354 | +#endif | ||
| 355 | + | ||
| 356 | + ds->data = (void *) screen; | ||
| 357 | + ds->linesize = 0; | ||
| 358 | + ds->depth = 0; | ||
| 359 | + ds->width = 640; | ||
| 360 | + ds->height = 400; | ||
| 361 | + ds->dpy_update = curses_update; | ||
| 362 | + ds->dpy_resize = curses_resize; | ||
| 363 | + ds->dpy_refresh = curses_refresh; | ||
| 364 | + ds->dpy_text_cursor = curses_cursor_position; | ||
| 365 | + | ||
| 366 | + invalidate = 1; | ||
| 367 | + | ||
| 368 | + /* Standard VGA initial text mode dimensions */ | ||
| 369 | + curses_resize(ds, 80, 25); | ||
| 370 | +} |
curses_keys.h
0 โ 100644
| 1 | +/* | ||
| 2 | + * Keycode and keysyms conversion tables for curses | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org> | ||
| 5 | + * | ||
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | + * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | + * in the Software without restriction, including without limitation the rights | ||
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | + * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | + * furnished to do so, subject to the following conditions: | ||
| 12 | + * | ||
| 13 | + * The above copyright notice and this permission notice shall be included in | ||
| 14 | + * all copies or substantial portions of the Software. | ||
| 15 | + * | ||
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | + * THE SOFTWARE. | ||
| 23 | + */ | ||
| 24 | +#define KEY_RELEASE 0x80 | ||
| 25 | +#define KEY_MASK 0x7f | ||
| 26 | +#define SHIFT_CODE 0x2a | ||
| 27 | +#define SHIFT 0x0080 | ||
| 28 | +#define GREY_CODE 0xe0 | ||
| 29 | +#define GREY 0x0100 | ||
| 30 | +#define CNTRL_CODE 0x1d | ||
| 31 | +#define CNTRL 0x0200 | ||
| 32 | +#define ALT_CODE 0x38 | ||
| 33 | +#define ALT 0x0400 | ||
| 34 | + | ||
| 35 | +/* curses won't detect a Control + Alt + 1, so use Alt + 1 */ | ||
| 36 | +#define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ | ||
| 37 | + | ||
| 38 | +#define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */ | ||
| 39 | + | ||
| 40 | +int curses2keycode[CURSES_KEYS] = { | ||
| 41 | + [0 ... (CURSES_KEYS - 1)] = -1, | ||
| 42 | + | ||
| 43 | + [0x01b] = 1, /* Escape */ | ||
| 44 | + ['1'] = 2, | ||
| 45 | + ['2'] = 3, | ||
| 46 | + ['3'] = 4, | ||
| 47 | + ['4'] = 5, | ||
| 48 | + ['5'] = 6, | ||
| 49 | + ['6'] = 7, | ||
| 50 | + ['7'] = 8, | ||
| 51 | + ['8'] = 9, | ||
| 52 | + ['9'] = 10, | ||
| 53 | + ['0'] = 11, | ||
| 54 | + ['-'] = 12, | ||
| 55 | + ['='] = 13, | ||
| 56 | + [0x07f] = 14, /* Backspace */ | ||
| 57 | + [0x107] = 14, /* Backspace */ | ||
| 58 | + | ||
| 59 | + ['\t'] = 15, /* Tab */ | ||
| 60 | + ['q'] = 16, | ||
| 61 | + ['w'] = 17, | ||
| 62 | + ['e'] = 18, | ||
| 63 | + ['r'] = 19, | ||
| 64 | + ['t'] = 20, | ||
| 65 | + ['y'] = 21, | ||
| 66 | + ['u'] = 22, | ||
| 67 | + ['i'] = 23, | ||
| 68 | + ['o'] = 24, | ||
| 69 | + ['p'] = 25, | ||
| 70 | + ['['] = 26, | ||
| 71 | + [']'] = 27, | ||
| 72 | + ['\n'] = 28, /* Return */ | ||
| 73 | + ['\r'] = 28, /* Return */ | ||
| 74 | + [0x157] = 28, /* Return */ | ||
| 75 | + | ||
| 76 | + ['a'] = 30, | ||
| 77 | + ['s'] = 31, | ||
| 78 | + ['d'] = 32, | ||
| 79 | + ['f'] = 33, | ||
| 80 | + ['g'] = 34, | ||
| 81 | + ['h'] = 35, | ||
| 82 | + ['j'] = 36, | ||
| 83 | + ['k'] = 37, | ||
| 84 | + ['l'] = 38, | ||
| 85 | + [';'] = 39, | ||
| 86 | + ['\''] = 40, /* Single quote */ | ||
| 87 | + ['`'] = 41, | ||
| 88 | + ['\\'] = 43, /* Backslash */ | ||
| 89 | + | ||
| 90 | + ['z'] = 44, | ||
| 91 | + ['x'] = 45, | ||
| 92 | + ['c'] = 46, | ||
| 93 | + ['v'] = 47, | ||
| 94 | + ['b'] = 48, | ||
| 95 | + ['n'] = 49, | ||
| 96 | + ['m'] = 50, | ||
| 97 | + [','] = 51, | ||
| 98 | + ['.'] = 52, | ||
| 99 | + ['/'] = 53, | ||
| 100 | + | ||
| 101 | + [' '] = 57, | ||
| 102 | + | ||
| 103 | + [0x109] = 59, /* Function Key 1 */ | ||
| 104 | + [0x10a] = 60, /* Function Key 2 */ | ||
| 105 | + [0x10b] = 61, /* Function Key 3 */ | ||
| 106 | + [0x10c] = 62, /* Function Key 4 */ | ||
| 107 | + [0x10d] = 63, /* Function Key 5 */ | ||
| 108 | + [0x10e] = 64, /* Function Key 6 */ | ||
| 109 | + [0x10f] = 65, /* Function Key 7 */ | ||
| 110 | + [0x110] = 66, /* Function Key 8 */ | ||
| 111 | + [0x111] = 67, /* Function Key 9 */ | ||
| 112 | + [0x112] = 68, /* Function Key 10 */ | ||
| 113 | + [0x113] = 87, /* Function Key 11 */ | ||
| 114 | + [0x114] = 88, /* Function Key 12 */ | ||
| 115 | + | ||
| 116 | + [0x106] = 71 | GREY, /* Home */ | ||
| 117 | + [0x103] = 72 | GREY, /* Up Arrow */ | ||
| 118 | + [0x153] = 73 | GREY, /* Page Up */ | ||
| 119 | + [0x104] = 75 | GREY, /* Left Arrow */ | ||
| 120 | + [0x105] = 77 | GREY, /* Right Arrow */ | ||
| 121 | + [0x168] = 79 | GREY, /* End */ | ||
| 122 | + [0x102] = 80 | GREY, /* Down Arrow */ | ||
| 123 | + [0x152] = 81 | GREY, /* Page Down */ | ||
| 124 | + [0x14b] = 82 | GREY, /* Insert */ | ||
| 125 | + [0x14a] = 83 | GREY, /* Delete */ | ||
| 126 | + | ||
| 127 | + ['!'] = 2 | SHIFT, | ||
| 128 | + ['@'] = 3 | SHIFT, | ||
| 129 | + ['#'] = 4 | SHIFT, | ||
| 130 | + ['$'] = 5 | SHIFT, | ||
| 131 | + ['%'] = 6 | SHIFT, | ||
| 132 | + ['^'] = 7 | SHIFT, | ||
| 133 | + ['&'] = 8 | SHIFT, | ||
| 134 | + ['*'] = 9 | SHIFT, | ||
| 135 | + ['('] = 10 | SHIFT, | ||
| 136 | + [')'] = 11 | SHIFT, | ||
| 137 | + ['_'] = 12 | SHIFT, | ||
| 138 | + ['+'] = 13 | SHIFT, | ||
| 139 | + | ||
| 140 | + [0x161] = 15 | SHIFT, /* Shift + Tab */ | ||
| 141 | + ['Q'] = 16 | SHIFT, | ||
| 142 | + ['W'] = 17 | SHIFT, | ||
| 143 | + ['E'] = 18 | SHIFT, | ||
| 144 | + ['R'] = 19 | SHIFT, | ||
| 145 | + ['T'] = 20 | SHIFT, | ||
| 146 | + ['Y'] = 21 | SHIFT, | ||
| 147 | + ['U'] = 22 | SHIFT, | ||
| 148 | + ['I'] = 23 | SHIFT, | ||
| 149 | + ['O'] = 24 | SHIFT, | ||
| 150 | + ['P'] = 25 | SHIFT, | ||
| 151 | + ['{'] = 26 | SHIFT, | ||
| 152 | + ['}'] = 27 | SHIFT, | ||
| 153 | + | ||
| 154 | + ['A'] = 30 | SHIFT, | ||
| 155 | + ['S'] = 31 | SHIFT, | ||
| 156 | + ['D'] = 32 | SHIFT, | ||
| 157 | + ['F'] = 33 | SHIFT, | ||
| 158 | + ['G'] = 34 | SHIFT, | ||
| 159 | + ['H'] = 35 | SHIFT, | ||
| 160 | + ['J'] = 36 | SHIFT, | ||
| 161 | + ['K'] = 37 | SHIFT, | ||
| 162 | + ['L'] = 38 | SHIFT, | ||
| 163 | + [':'] = 39 | SHIFT, | ||
| 164 | + ['"'] = 40 | SHIFT, | ||
| 165 | + ['~'] = 41 | SHIFT, | ||
| 166 | + ['|'] = 43 | SHIFT, | ||
| 167 | + | ||
| 168 | + ['Z'] = 44 | SHIFT, | ||
| 169 | + ['X'] = 45 | SHIFT, | ||
| 170 | + ['C'] = 46 | SHIFT, | ||
| 171 | + ['V'] = 47 | SHIFT, | ||
| 172 | + ['B'] = 48 | SHIFT, | ||
| 173 | + ['N'] = 49 | SHIFT, | ||
| 174 | + ['M'] = 50 | SHIFT, | ||
| 175 | + ['<'] = 51 | SHIFT, | ||
| 176 | + ['>'] = 52 | SHIFT, | ||
| 177 | + ['?'] = 53 | SHIFT, | ||
| 178 | + | ||
| 179 | + [0x115] = 59 | SHIFT, /* Shift + Function Key 1 */ | ||
| 180 | + [0x116] = 60 | SHIFT, /* Shift + Function Key 2 */ | ||
| 181 | + [0x117] = 61 | SHIFT, /* Shift + Function Key 3 */ | ||
| 182 | + [0x118] = 62 | SHIFT, /* Shift + Function Key 4 */ | ||
| 183 | + [0x119] = 63 | SHIFT, /* Shift + Function Key 5 */ | ||
| 184 | + [0x11a] = 64 | SHIFT, /* Shift + Function Key 6 */ | ||
| 185 | + [0x11b] = 65 | SHIFT, /* Shift + Function Key 7 */ | ||
| 186 | + [0x11c] = 66 | SHIFT, /* Shift + Function Key 8 */ | ||
| 187 | + | ||
| 188 | + [0x011] = 16 | CNTRL, /* Control + q */ | ||
| 189 | + [0x017] = 17 | CNTRL, /* Control + w */ | ||
| 190 | + [0x005] = 18 | CNTRL, /* Control + e */ | ||
| 191 | + [0x012] = 19 | CNTRL, /* Control + r */ | ||
| 192 | + [0x014] = 20 | CNTRL, /* Control + t */ | ||
| 193 | + [0x019] = 21 | CNTRL, /* Control + y */ | ||
| 194 | + [0x015] = 22 | CNTRL, /* Control + u */ | ||
| 195 | + [0x009] = 23 | CNTRL, /* Control + i */ | ||
| 196 | + [0x00f] = 24 | CNTRL, /* Control + o */ | ||
| 197 | + [0x010] = 25 | CNTRL, /* Control + p */ | ||
| 198 | + | ||
| 199 | + [0x001] = 30 | CNTRL, /* Control + a */ | ||
| 200 | + [0x013] = 31 | CNTRL, /* Control + s */ | ||
| 201 | + [0x014] = 32 | CNTRL, /* Control + d */ | ||
| 202 | + [0x006] = 33 | CNTRL, /* Control + f */ | ||
| 203 | + [0x007] = 34 | CNTRL, /* Control + g */ | ||
| 204 | + [0x008] = 35 | CNTRL, /* Control + h */ | ||
| 205 | + [0x00a] = 36 | CNTRL, /* Control + j */ | ||
| 206 | + [0x00b] = 37 | CNTRL, /* Control + k */ | ||
| 207 | + [0x00c] = 38 | CNTRL, /* Control + l */ | ||
| 208 | + | ||
| 209 | + [0x01a] = 44 | CNTRL, /* Control + z */ | ||
| 210 | + [0x018] = 45 | CNTRL, /* Control + x */ | ||
| 211 | + [0x003] = 46 | CNTRL, /* Control + c */ | ||
| 212 | + [0x016] = 47 | CNTRL, /* Control + v */ | ||
| 213 | + [0x002] = 48 | CNTRL, /* Control + b */ | ||
| 214 | + [0x00e] = 49 | CNTRL, /* Control + n */ | ||
| 215 | + /* Control + m collides with the keycode for Enter */ | ||
| 216 | + | ||
| 217 | +}; | ||
| 218 | + | ||
| 219 | +int curses2keysym[CURSES_KEYS] = { | ||
| 220 | + [0 ... (CURSES_KEYS - 1)] = -1, | ||
| 221 | + | ||
| 222 | + ['\n'] = '\n', | ||
| 223 | + ['\r'] = '\n', | ||
| 224 | + | ||
| 225 | + [0x07f] = QEMU_KEY_BACKSPACE, | ||
| 226 | + | ||
| 227 | + [0x102] = QEMU_KEY_DOWN, | ||
| 228 | + [0x103] = QEMU_KEY_UP, | ||
| 229 | + [0x104] = QEMU_KEY_LEFT, | ||
| 230 | + [0x105] = QEMU_KEY_RIGHT, | ||
| 231 | + [0x106] = QEMU_KEY_HOME, | ||
| 232 | + [0x107] = QEMU_KEY_BACKSPACE, | ||
| 233 | + | ||
| 234 | + [0x14a] = QEMU_KEY_DELETE, | ||
| 235 | + [0x152] = QEMU_KEY_PAGEDOWN, | ||
| 236 | + [0x153] = QEMU_KEY_PAGEUP, | ||
| 237 | + [0x157] = '\n', | ||
| 238 | + [0x168] = QEMU_KEY_END, | ||
| 239 | + | ||
| 240 | +}; | ||
| 241 | + | ||
| 242 | +typedef struct { | ||
| 243 | + const char* name; | ||
| 244 | + int keysym; | ||
| 245 | +} name2keysym_t; | ||
| 246 | + | ||
| 247 | +static name2keysym_t name2keysym[] = { | ||
| 248 | + /* Plain ASCII */ | ||
| 249 | + { "space", 0x020 }, | ||
| 250 | + { "exclam", 0x021 }, | ||
| 251 | + { "quotedbl", 0x022 }, | ||
| 252 | + { "numbersign", 0x023 }, | ||
| 253 | + { "dollar", 0x024 }, | ||
| 254 | + { "percent", 0x025 }, | ||
| 255 | + { "ampersand", 0x026 }, | ||
| 256 | + { "apostrophe", 0x027 }, | ||
| 257 | + { "parenleft", 0x028 }, | ||
| 258 | + { "parenright", 0x029 }, | ||
| 259 | + { "asterisk", 0x02a }, | ||
| 260 | + { "plus", 0x02b }, | ||
| 261 | + { "comma", 0x02c }, | ||
| 262 | + { "minus", 0x02d }, | ||
| 263 | + { "period", 0x02e }, | ||
| 264 | + { "slash", 0x02f }, | ||
| 265 | + { "0", 0x030 }, | ||
| 266 | + { "1", 0x031 }, | ||
| 267 | + { "2", 0x032 }, | ||
| 268 | + { "3", 0x033 }, | ||
| 269 | + { "4", 0x034 }, | ||
| 270 | + { "5", 0x035 }, | ||
| 271 | + { "6", 0x036 }, | ||
| 272 | + { "7", 0x037 }, | ||
| 273 | + { "8", 0x038 }, | ||
| 274 | + { "9", 0x039 }, | ||
| 275 | + { "colon", 0x03a }, | ||
| 276 | + { "semicolon", 0x03b }, | ||
| 277 | + { "less", 0x03c }, | ||
| 278 | + { "equal", 0x03d }, | ||
| 279 | + { "greater", 0x03e }, | ||
| 280 | + { "question", 0x03f }, | ||
| 281 | + { "at", 0x040 }, | ||
| 282 | + { "A", 0x041 }, | ||
| 283 | + { "B", 0x042 }, | ||
| 284 | + { "C", 0x043 }, | ||
| 285 | + { "D", 0x044 }, | ||
| 286 | + { "E", 0x045 }, | ||
| 287 | + { "F", 0x046 }, | ||
| 288 | + { "G", 0x047 }, | ||
| 289 | + { "H", 0x048 }, | ||
| 290 | + { "I", 0x049 }, | ||
| 291 | + { "J", 0x04a }, | ||
| 292 | + { "K", 0x04b }, | ||
| 293 | + { "L", 0x04c }, | ||
| 294 | + { "M", 0x04d }, | ||
| 295 | + { "N", 0x04e }, | ||
| 296 | + { "O", 0x04f }, | ||
| 297 | + { "P", 0x050 }, | ||
| 298 | + { "Q", 0x051 }, | ||
| 299 | + { "R", 0x052 }, | ||
| 300 | + { "S", 0x053 }, | ||
| 301 | + { "T", 0x054 }, | ||
| 302 | + { "U", 0x055 }, | ||
| 303 | + { "V", 0x056 }, | ||
| 304 | + { "W", 0x057 }, | ||
| 305 | + { "X", 0x058 }, | ||
| 306 | + { "Y", 0x059 }, | ||
| 307 | + { "Z", 0x05a }, | ||
| 308 | + { "bracketleft", 0x05b }, | ||
| 309 | + { "backslash", 0x05c }, | ||
| 310 | + { "bracketright", 0x05d }, | ||
| 311 | + { "asciicircum", 0x05e }, | ||
| 312 | + { "underscore", 0x05f }, | ||
| 313 | + { "grave", 0x060 }, | ||
| 314 | + { "a", 0x061 }, | ||
| 315 | + { "b", 0x062 }, | ||
| 316 | + { "c", 0x063 }, | ||
| 317 | + { "d", 0x064 }, | ||
| 318 | + { "e", 0x065 }, | ||
| 319 | + { "f", 0x066 }, | ||
| 320 | + { "g", 0x067 }, | ||
| 321 | + { "h", 0x068 }, | ||
| 322 | + { "i", 0x069 }, | ||
| 323 | + { "j", 0x06a }, | ||
| 324 | + { "k", 0x06b }, | ||
| 325 | + { "l", 0x06c }, | ||
| 326 | + { "m", 0x06d }, | ||
| 327 | + { "n", 0x06e }, | ||
| 328 | + { "o", 0x06f }, | ||
| 329 | + { "p", 0x070 }, | ||
| 330 | + { "q", 0x071 }, | ||
| 331 | + { "r", 0x072 }, | ||
| 332 | + { "s", 0x073 }, | ||
| 333 | + { "t", 0x074 }, | ||
| 334 | + { "u", 0x075 }, | ||
| 335 | + { "v", 0x076 }, | ||
| 336 | + { "w", 0x077 }, | ||
| 337 | + { "x", 0x078 }, | ||
| 338 | + { "y", 0x079 }, | ||
| 339 | + { "z", 0x07a }, | ||
| 340 | + { "braceleft", 0x07b }, | ||
| 341 | + { "bar", 0x07c }, | ||
| 342 | + { "braceright", 0x07d }, | ||
| 343 | + { "asciitilde", 0x07e }, | ||
| 344 | + | ||
| 345 | + /* Latin-1 extensions */ | ||
| 346 | + { "nobreakspace", 0x0a0 }, | ||
| 347 | + { "exclamdown", 0x0a1 }, | ||
| 348 | + { "cent", 0x0a2 }, | ||
| 349 | + { "sterling", 0x0a3 }, | ||
| 350 | + { "currency", 0x0a4 }, | ||
| 351 | + { "yen", 0x0a5 }, | ||
| 352 | + { "brokenbar", 0x0a6 }, | ||
| 353 | + { "section", 0x0a7 }, | ||
| 354 | + { "diaeresis", 0x0a8 }, | ||
| 355 | + { "copyright", 0x0a9 }, | ||
| 356 | + { "ordfeminine", 0x0aa }, | ||
| 357 | + { "guillemotleft", 0x0ab }, | ||
| 358 | + { "notsign", 0x0ac }, | ||
| 359 | + { "hyphen", 0x0ad }, | ||
| 360 | + { "registered", 0x0ae }, | ||
| 361 | + { "macron", 0x0af }, | ||
| 362 | + { "degree", 0x0b0 }, | ||
| 363 | + { "plusminus", 0x0b1 }, | ||
| 364 | + { "twosuperior", 0x0b2 }, | ||
| 365 | + { "threesuperior", 0x0b3 }, | ||
| 366 | + { "acute", 0x0b4 }, | ||
| 367 | + { "mu", 0x0b5 }, | ||
| 368 | + { "paragraph", 0x0b6 }, | ||
| 369 | + { "periodcentered", 0x0b7 }, | ||
| 370 | + { "cedilla", 0x0b8 }, | ||
| 371 | + { "onesuperior", 0x0b9 }, | ||
| 372 | + { "masculine", 0x0ba }, | ||
| 373 | + { "guillemotright", 0x0bb }, | ||
| 374 | + { "onequarter", 0x0bc }, | ||
| 375 | + { "onehalf", 0x0bd }, | ||
| 376 | + { "threequarters", 0x0be }, | ||
| 377 | + { "questiondown", 0x0bf }, | ||
| 378 | + { "Agrave", 0x0c0 }, | ||
| 379 | + { "Aacute", 0x0c1 }, | ||
| 380 | + { "Acircumflex", 0x0c2 }, | ||
| 381 | + { "Atilde", 0x0c3 }, | ||
| 382 | + { "Adiaeresis", 0x0c4 }, | ||
| 383 | + { "Aring", 0x0c5 }, | ||
| 384 | + { "AE", 0x0c6 }, | ||
| 385 | + { "Ccedilla", 0x0c7 }, | ||
| 386 | + { "Egrave", 0x0c8 }, | ||
| 387 | + { "Eacute", 0x0c9 }, | ||
| 388 | + { "Ecircumflex", 0x0ca }, | ||
| 389 | + { "Ediaeresis", 0x0cb }, | ||
| 390 | + { "Igrave", 0x0cc }, | ||
| 391 | + { "Iacute", 0x0cd }, | ||
| 392 | + { "Icircumflex", 0x0ce }, | ||
| 393 | + { "Idiaeresis", 0x0cf }, | ||
| 394 | + { "ETH", 0x0d0 }, | ||
| 395 | + { "Eth", 0x0d0 }, | ||
| 396 | + { "Ntilde", 0x0d1 }, | ||
| 397 | + { "Ograve", 0x0d2 }, | ||
| 398 | + { "Oacute", 0x0d3 }, | ||
| 399 | + { "Ocircumflex", 0x0d4 }, | ||
| 400 | + { "Otilde", 0x0d5 }, | ||
| 401 | + { "Odiaeresis", 0x0d6 }, | ||
| 402 | + { "multiply", 0x0d7 }, | ||
| 403 | + { "Ooblique", 0x0d8 }, | ||
| 404 | + { "Oslash", 0x0d8 }, | ||
| 405 | + { "Ugrave", 0x0d9 }, | ||
| 406 | + { "Uacute", 0x0da }, | ||
| 407 | + { "Ucircumflex", 0x0db }, | ||
| 408 | + { "Udiaeresis", 0x0dc }, | ||
| 409 | + { "Yacute", 0x0dd }, | ||
| 410 | + { "THORN", 0x0de }, | ||
| 411 | + { "Thorn", 0x0de }, | ||
| 412 | + { "ssharp", 0x0df }, | ||
| 413 | + { "agrave", 0x0e0 }, | ||
| 414 | + { "aacute", 0x0e1 }, | ||
| 415 | + { "acircumflex", 0x0e2 }, | ||
| 416 | + { "atilde", 0x0e3 }, | ||
| 417 | + { "adiaeresis", 0x0e4 }, | ||
| 418 | + { "aring", 0x0e5 }, | ||
| 419 | + { "ae", 0x0e6 }, | ||
| 420 | + { "ccedilla", 0x0e7 }, | ||
| 421 | + { "egrave", 0x0e8 }, | ||
| 422 | + { "eacute", 0x0e9 }, | ||
| 423 | + { "ecircumflex", 0x0ea }, | ||
| 424 | + { "ediaeresis", 0x0eb }, | ||
| 425 | + { "igrave", 0x0ec }, | ||
| 426 | + { "iacute", 0x0ed }, | ||
| 427 | + { "icircumflex", 0x0ee }, | ||
| 428 | + { "idiaeresis", 0x0ef }, | ||
| 429 | + { "eth", 0x0f0 }, | ||
| 430 | + { "ntilde", 0x0f1 }, | ||
| 431 | + { "ograve", 0x0f2 }, | ||
| 432 | + { "oacute", 0x0f3 }, | ||
| 433 | + { "ocircumflex", 0x0f4 }, | ||
| 434 | + { "otilde", 0x0f5 }, | ||
| 435 | + { "odiaeresis", 0x0f6 }, | ||
| 436 | + { "division", 0x0f7 }, | ||
| 437 | + { "oslash", 0x0f8 }, | ||
| 438 | + { "ooblique", 0x0f8 }, | ||
| 439 | + { "ugrave", 0x0f9 }, | ||
| 440 | + { "uacute", 0x0fa }, | ||
| 441 | + { "ucircumflex", 0x0fb }, | ||
| 442 | + { "udiaeresis", 0x0fc }, | ||
| 443 | + { "yacute", 0x0fd }, | ||
| 444 | + { "thorn", 0x0fe }, | ||
| 445 | + { "ydiaeresis", 0x0ff }, | ||
| 446 | + | ||
| 447 | + /* Special keys */ | ||
| 448 | + { "BackSpace", 0x07f }, | ||
| 449 | + { "Tab", '\t' }, | ||
| 450 | + { "Return", '\r' }, | ||
| 451 | + { "Right", 0x105 }, | ||
| 452 | + { "Left", 0x104 }, | ||
| 453 | + { "Up", 0x103 }, | ||
| 454 | + { "Down", 0x102 }, | ||
| 455 | + { "Page_Down", 0x152 }, | ||
| 456 | + { "Page_Up", 0x153 }, | ||
| 457 | + { "Insert", 0x14b }, | ||
| 458 | + { "Delete", 0x14a }, | ||
| 459 | + { "Home", 0x106 }, | ||
| 460 | + { "End", 0x168 }, | ||
| 461 | + { "F1", 0x109 }, | ||
| 462 | + { "F2", 0x10a }, | ||
| 463 | + { "F3", 0x10b }, | ||
| 464 | + { "F4", 0x10c }, | ||
| 465 | + { "F5", 0x10d }, | ||
| 466 | + { "F6", 0x10e }, | ||
| 467 | + { "F7", 0x10f }, | ||
| 468 | + { "F8", 0x110 }, | ||
| 469 | + { "F9", 0x111 }, | ||
| 470 | + { "F10", 0x112 }, | ||
| 471 | + { "F11", 0x113 }, | ||
| 472 | + { "F12", 0x114 }, | ||
| 473 | + { "F13", 0x115 }, | ||
| 474 | + { "F14", 0x116 }, | ||
| 475 | + { "F15", 0x117 }, | ||
| 476 | + { "F16", 0x118 }, | ||
| 477 | + { "F17", 0x119 }, | ||
| 478 | + { "F18", 0x11a }, | ||
| 479 | + { "F19", 0x11b }, | ||
| 480 | + { "F20", 0x11c }, | ||
| 481 | + { "Escape", 27 }, | ||
| 482 | + | ||
| 483 | + { 0, 0 }, | ||
| 484 | +}; |
hw/cirrus_vga.c
| @@ -3257,7 +3257,8 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, | @@ -3257,7 +3257,8 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, | ||
| 3257 | ds, vga_ram_base, vga_ram_offset, vga_ram_size); | 3257 | ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
| 3258 | cirrus_init_common(s, device_id, 1); | 3258 | cirrus_init_common(s, device_id, 1); |
| 3259 | 3259 | ||
| 3260 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | 3260 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, |
| 3261 | + s->text_update, s); | ||
| 3261 | 3262 | ||
| 3262 | s->pci_dev = (PCIDevice *)d; | 3263 | s->pci_dev = (PCIDevice *)d; |
| 3263 | 3264 |
hw/jazz_led.c
| @@ -285,6 +285,22 @@ static void jazz_led_screen_dump(void *opaque, const char *filename) | @@ -285,6 +285,22 @@ static void jazz_led_screen_dump(void *opaque, const char *filename) | ||
| 285 | printf("jazz_led_screen_dump() not implemented\n"); | 285 | printf("jazz_led_screen_dump() not implemented\n"); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | +static void jazz_led_text_update(void *opaque, console_ch_t *chardata) | ||
| 289 | +{ | ||
| 290 | + LedState *s = opaque; | ||
| 291 | + char buf[2]; | ||
| 292 | + | ||
| 293 | + dpy_cursor(s->ds, -1, -1); | ||
| 294 | + dpy_resize(s->ds, 2, 1); | ||
| 295 | + | ||
| 296 | + /* TODO: draw the segments */ | ||
| 297 | + snprintf(buf, 2, "%02hhx\n", s->segments); | ||
| 298 | + console_write_ch(chardata++, 0x00200100 | buf[0]); | ||
| 299 | + console_write_ch(chardata++, 0x00200100 | buf[1]); | ||
| 300 | + | ||
| 301 | + dpy_update(s->ds, 0, 0, 2, 1); | ||
| 302 | +} | ||
| 303 | + | ||
| 288 | void jazz_led_init(DisplayState *ds, target_phys_addr_t base) | 304 | void jazz_led_init(DisplayState *ds, target_phys_addr_t base) |
| 289 | { | 305 | { |
| 290 | LedState *s; | 306 | LedState *s; |
| @@ -301,5 +317,7 @@ void jazz_led_init(DisplayState *ds, target_phys_addr_t base) | @@ -301,5 +317,7 @@ void jazz_led_init(DisplayState *ds, target_phys_addr_t base) | ||
| 301 | io = cpu_register_io_memory(0, led_read, led_write, s); | 317 | io = cpu_register_io_memory(0, led_read, led_write, s); |
| 302 | cpu_register_physical_memory(s->base, 1, io); | 318 | cpu_register_physical_memory(s->base, 1, io); |
| 303 | 319 | ||
| 304 | - graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s); | 320 | + graphic_console_init(ds, jazz_led_update_display, |
| 321 | + jazz_led_invalidate_display, jazz_led_screen_dump, | ||
| 322 | + jazz_led_text_update, s); | ||
| 305 | } | 323 | } |
hw/omap_lcdc.c
| @@ -495,7 +495,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, | @@ -495,7 +495,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, | ||
| 495 | cpu_register_physical_memory(s->base, 0x100, iomemtype); | 495 | cpu_register_physical_memory(s->base, 0x100, iomemtype); |
| 496 | 496 | ||
| 497 | graphic_console_init(ds, omap_update_display, | 497 | graphic_console_init(ds, omap_update_display, |
| 498 | - omap_invalidate_display, omap_screen_dump, s); | 498 | + omap_invalidate_display, omap_screen_dump, NULL, s); |
| 499 | 499 | ||
| 500 | return s; | 500 | return s; |
| 501 | } | 501 | } |
hw/pl110.c
| @@ -426,7 +426,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, | @@ -426,7 +426,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, | ||
| 426 | s->versatile = versatile; | 426 | s->versatile = versatile; |
| 427 | s->irq = irq; | 427 | s->irq = irq; |
| 428 | graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, | 428 | graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, |
| 429 | - NULL, s); | 429 | + NULL, NULL, s); |
| 430 | /* ??? Save/restore. */ | 430 | /* ??? Save/restore. */ |
| 431 | return s; | 431 | return s; |
| 432 | } | 432 | } |
hw/pxa2xx_lcd.c
| @@ -1002,7 +1002,7 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, | @@ -1002,7 +1002,7 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, | ||
| 1002 | cpu_register_physical_memory(base, 0x00100000, iomemtype); | 1002 | cpu_register_physical_memory(base, 0x00100000, iomemtype); |
| 1003 | 1003 | ||
| 1004 | graphic_console_init(ds, pxa2xx_update_display, | 1004 | graphic_console_init(ds, pxa2xx_update_display, |
| 1005 | - pxa2xx_invalidate_display, pxa2xx_screen_dump, s); | 1005 | + pxa2xx_invalidate_display, pxa2xx_screen_dump, NULL, s); |
| 1006 | 1006 | ||
| 1007 | switch (s->ds->depth) { | 1007 | switch (s->ds->depth) { |
| 1008 | case 0: | 1008 | case 0: |
hw/ssd0303.c
| @@ -270,6 +270,6 @@ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) | @@ -270,6 +270,6 @@ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) | ||
| 270 | s->i2c.recv = ssd0303_recv; | 270 | s->i2c.recv = ssd0303_recv; |
| 271 | s->i2c.send = ssd0303_send; | 271 | s->i2c.send = ssd0303_send; |
| 272 | graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, | 272 | graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, |
| 273 | - NULL, s); | 273 | + NULL, NULL, s); |
| 274 | dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); | 274 | dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); |
| 275 | } | 275 | } |
hw/ssd0323.c
| @@ -280,7 +280,7 @@ void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) | @@ -280,7 +280,7 @@ void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) | ||
| 280 | s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); | 280 | s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); |
| 281 | s->ds = ds; | 281 | s->ds = ds; |
| 282 | graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, | 282 | graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, |
| 283 | - NULL, s); | 283 | + NULL, NULL, s); |
| 284 | dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); | 284 | dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); |
| 285 | s->col_end = 63; | 285 | s->col_end = 63; |
| 286 | s->row_end = 79; | 286 | s->row_end = 79; |
hw/tcx.c
| @@ -537,12 +537,13 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, | @@ -537,12 +537,13 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, | ||
| 537 | s->cplane_offset = vram_offset; | 537 | s->cplane_offset = vram_offset; |
| 538 | cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); | 538 | cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); |
| 539 | graphic_console_init(s->ds, tcx24_update_display, | 539 | graphic_console_init(s->ds, tcx24_update_display, |
| 540 | - tcx24_invalidate_display, tcx24_screen_dump, s); | 540 | + tcx24_invalidate_display, |
| 541 | + tcx24_screen_dump, NULL, s); | ||
| 541 | } else { | 542 | } else { |
| 542 | cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, | 543 | cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, |
| 543 | dummy_memory); | 544 | dummy_memory); |
| 544 | graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, | 545 | graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, |
| 545 | - tcx_screen_dump, s); | 546 | + tcx_screen_dump, NULL, s); |
| 546 | } | 547 | } |
| 547 | // NetBSD writes here even with 8-bit display | 548 | // NetBSD writes here even with 8-bit display |
| 548 | cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, | 549 | cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, |
hw/vga.c
| @@ -1660,6 +1660,165 @@ static void vga_reset(VGAState *s) | @@ -1660,6 +1660,165 @@ static void vga_reset(VGAState *s) | ||
| 1660 | s->graphic_mode = -1; /* force full update */ | 1660 | s->graphic_mode = -1; /* force full update */ |
| 1661 | } | 1661 | } |
| 1662 | 1662 | ||
| 1663 | +#define TEXTMODE_X(x) ((x) % width) | ||
| 1664 | +#define TEXTMODE_Y(x) ((x) / width) | ||
| 1665 | +#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ | ||
| 1666 | + ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) | ||
| 1667 | +/* relay text rendering to the display driver | ||
| 1668 | + * instead of doing a full vga_update_display() */ | ||
| 1669 | +static void vga_update_text(void *opaque, console_ch_t *chardata) | ||
| 1670 | +{ | ||
| 1671 | + VGAState *s = (VGAState *) opaque; | ||
| 1672 | + int graphic_mode, i, cursor_offset, cursor_visible; | ||
| 1673 | + int cw, cheight, width, height, size, c_min, c_max; | ||
| 1674 | + uint32_t *src; | ||
| 1675 | + console_ch_t *dst, val; | ||
| 1676 | + char msg_buffer[80]; | ||
| 1677 | + int full_update; | ||
| 1678 | + full_update = 0; | ||
| 1679 | + | ||
| 1680 | + if (!(s->ar_index & 0x20)) { | ||
| 1681 | + graphic_mode = GMODE_BLANK; | ||
| 1682 | + } else { | ||
| 1683 | + graphic_mode = s->gr[6] & 1; | ||
| 1684 | + } | ||
| 1685 | + if (graphic_mode != s->graphic_mode) { | ||
| 1686 | + s->graphic_mode = graphic_mode; | ||
| 1687 | + full_update = 1; | ||
| 1688 | + } | ||
| 1689 | + if (s->last_width == -1) { | ||
| 1690 | + s->last_width = 0; | ||
| 1691 | + full_update = 1; | ||
| 1692 | + } | ||
| 1693 | + | ||
| 1694 | + switch (graphic_mode) { | ||
| 1695 | + case GMODE_TEXT: | ||
| 1696 | + /* TODO: update palette */ | ||
| 1697 | + full_update |= update_basic_params(s); | ||
| 1698 | + | ||
| 1699 | + /* total width & height */ | ||
| 1700 | + cheight = (s->cr[9] & 0x1f) + 1; | ||
| 1701 | + cw = 8; | ||
| 1702 | + if (!(s->sr[1] & 0x01)) | ||
| 1703 | + cw = 9; | ||
| 1704 | + if (s->sr[1] & 0x08) | ||
| 1705 | + cw = 16; /* NOTE: no 18 pixel wide */ | ||
| 1706 | + width = (s->cr[0x01] + 1); | ||
| 1707 | + if (s->cr[0x06] == 100) { | ||
| 1708 | + /* ugly hack for CGA 160x100x16 - explain me the logic */ | ||
| 1709 | + height = 100; | ||
| 1710 | + } else { | ||
| 1711 | + height = s->cr[0x12] | | ||
| 1712 | + ((s->cr[0x07] & 0x02) << 7) | | ||
| 1713 | + ((s->cr[0x07] & 0x40) << 3); | ||
| 1714 | + height = (height + 1) / cheight; | ||
| 1715 | + } | ||
| 1716 | + | ||
| 1717 | + size = (height * width); | ||
| 1718 | + if (size > CH_ATTR_SIZE) { | ||
| 1719 | + if (!full_update) | ||
| 1720 | + return; | ||
| 1721 | + | ||
| 1722 | + sprintf(msg_buffer, "%i x %i Text mode", width, height); | ||
| 1723 | + break; | ||
| 1724 | + } | ||
| 1725 | + | ||
| 1726 | + if (width != s->last_width || height != s->last_height || | ||
| 1727 | + cw != s->last_cw || cheight != s->last_ch) { | ||
| 1728 | + s->last_scr_width = width * cw; | ||
| 1729 | + s->last_scr_height = height * cheight; | ||
| 1730 | + dpy_resize(s->ds, width, height); | ||
| 1731 | + s->last_width = width; | ||
| 1732 | + s->last_height = height; | ||
| 1733 | + s->last_ch = cheight; | ||
| 1734 | + s->last_cw = cw; | ||
| 1735 | + full_update = 1; | ||
| 1736 | + } | ||
| 1737 | + | ||
| 1738 | + /* Update "hardware" cursor */ | ||
| 1739 | + cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; | ||
| 1740 | + if (cursor_offset != s->cursor_offset || | ||
| 1741 | + s->cr[0xa] != s->cursor_start || | ||
| 1742 | + s->cr[0xb] != s->cursor_end || full_update) { | ||
| 1743 | + cursor_visible = !(s->cr[0xa] & 0x20); | ||
| 1744 | + if (cursor_visible && cursor_offset < size && cursor_offset >= 0) | ||
| 1745 | + dpy_cursor(s->ds, | ||
| 1746 | + TEXTMODE_X(cursor_offset), | ||
| 1747 | + TEXTMODE_Y(cursor_offset)); | ||
| 1748 | + else | ||
| 1749 | + dpy_cursor(s->ds, -1, -1); | ||
| 1750 | + s->cursor_offset = cursor_offset; | ||
| 1751 | + s->cursor_start = s->cr[0xa]; | ||
| 1752 | + s->cursor_end = s->cr[0xb]; | ||
| 1753 | + } | ||
| 1754 | + | ||
| 1755 | + src = (uint32_t *) s->vram_ptr + s->start_addr; | ||
| 1756 | + dst = chardata; | ||
| 1757 | + | ||
| 1758 | + if (full_update) { | ||
| 1759 | + for (i = 0; i < size; src ++, dst ++, i ++) | ||
| 1760 | + console_write_ch(dst, VMEM2CHTYPE(*src)); | ||
| 1761 | + | ||
| 1762 | + dpy_update(s->ds, 0, 0, width, height); | ||
| 1763 | + } else { | ||
| 1764 | + c_max = 0; | ||
| 1765 | + | ||
| 1766 | + for (i = 0; i < size; src ++, dst ++, i ++) { | ||
| 1767 | + console_write_ch(&val, VMEM2CHTYPE(*src)); | ||
| 1768 | + if (*dst != val) { | ||
| 1769 | + *dst = val; | ||
| 1770 | + c_max = i; | ||
| 1771 | + break; | ||
| 1772 | + } | ||
| 1773 | + } | ||
| 1774 | + c_min = i; | ||
| 1775 | + for (; i < size; src ++, dst ++, i ++) { | ||
| 1776 | + console_write_ch(&val, VMEM2CHTYPE(*src)); | ||
| 1777 | + if (*dst != val) { | ||
| 1778 | + *dst = val; | ||
| 1779 | + c_max = i; | ||
| 1780 | + } | ||
| 1781 | + } | ||
| 1782 | + | ||
| 1783 | + if (c_min <= c_max) { | ||
| 1784 | + i = TEXTMODE_Y(c_min); | ||
| 1785 | + dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); | ||
| 1786 | + } | ||
| 1787 | + } | ||
| 1788 | + | ||
| 1789 | + return; | ||
| 1790 | + case GMODE_GRAPH: | ||
| 1791 | + if (!full_update) | ||
| 1792 | + return; | ||
| 1793 | + | ||
| 1794 | + s->get_resolution(s, &width, &height); | ||
| 1795 | + sprintf(msg_buffer, "%i x %i Graphic mode", width, height); | ||
| 1796 | + break; | ||
| 1797 | + case GMODE_BLANK: | ||
| 1798 | + default: | ||
| 1799 | + if (!full_update) | ||
| 1800 | + return; | ||
| 1801 | + | ||
| 1802 | + sprintf(msg_buffer, "VGA Blank mode"); | ||
| 1803 | + break; | ||
| 1804 | + } | ||
| 1805 | + | ||
| 1806 | + /* Display a message */ | ||
| 1807 | + dpy_cursor(s->ds, -1, -1); | ||
| 1808 | + dpy_resize(s->ds, 60, 3); | ||
| 1809 | + | ||
| 1810 | + for (dst = chardata, i = 0; i < 60 * 3; i ++) | ||
| 1811 | + console_write_ch(dst ++, ' '); | ||
| 1812 | + | ||
| 1813 | + size = strlen(msg_buffer); | ||
| 1814 | + width = (60 - size) / 2; | ||
| 1815 | + dst = chardata + 60 + width; | ||
| 1816 | + for (i = 0; i < size; i ++) | ||
| 1817 | + console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); | ||
| 1818 | + | ||
| 1819 | + dpy_update(s->ds, 0, 0, 60, 3); | ||
| 1820 | +} | ||
| 1821 | + | ||
| 1663 | static CPUReadMemoryFunc *vga_mem_read[3] = { | 1822 | static CPUReadMemoryFunc *vga_mem_read[3] = { |
| 1664 | vga_mem_readb, | 1823 | vga_mem_readb, |
| 1665 | vga_mem_readw, | 1824 | vga_mem_readw, |
| @@ -1830,6 +1989,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, | @@ -1830,6 +1989,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, | ||
| 1830 | s->update = vga_update_display; | 1989 | s->update = vga_update_display; |
| 1831 | s->invalidate = vga_invalidate_display; | 1990 | s->invalidate = vga_invalidate_display; |
| 1832 | s->screen_dump = vga_screen_dump; | 1991 | s->screen_dump = vga_screen_dump; |
| 1992 | + s->text_update = vga_update_text; | ||
| 1833 | } | 1993 | } |
| 1834 | 1994 | ||
| 1835 | /* used by both ISA and PCI */ | 1995 | /* used by both ISA and PCI */ |
| @@ -1971,7 +2131,8 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, | @@ -1971,7 +2131,8 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, | ||
| 1971 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); | 2131 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
| 1972 | vga_init(s); | 2132 | vga_init(s); |
| 1973 | 2133 | ||
| 1974 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | 2134 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, |
| 2135 | + s->text_update, s); | ||
| 1975 | 2136 | ||
| 1976 | #ifdef CONFIG_BOCHS_VBE | 2137 | #ifdef CONFIG_BOCHS_VBE |
| 1977 | /* XXX: use optimized standard vga accesses */ | 2138 | /* XXX: use optimized standard vga accesses */ |
| @@ -1995,7 +2156,8 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, | @@ -1995,7 +2156,8 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, | ||
| 1995 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); | 2156 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
| 1996 | vga_mm_init(s, vram_base, ctrl_base, it_shift); | 2157 | vga_mm_init(s, vram_base, ctrl_base, it_shift); |
| 1997 | 2158 | ||
| 1998 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | 2159 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, |
| 2160 | + s->text_update, s); | ||
| 1999 | 2161 | ||
| 2000 | #ifdef CONFIG_BOCHS_VBE | 2162 | #ifdef CONFIG_BOCHS_VBE |
| 2001 | /* XXX: use optimized standard vga accesses */ | 2163 | /* XXX: use optimized standard vga accesses */ |
| @@ -2023,7 +2185,8 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, | @@ -2023,7 +2185,8 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, | ||
| 2023 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); | 2185 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
| 2024 | vga_init(s); | 2186 | vga_init(s); |
| 2025 | 2187 | ||
| 2026 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | 2188 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, |
| 2189 | + s->text_update, s); | ||
| 2027 | 2190 | ||
| 2028 | s->pci_dev = &d->dev; | 2191 | s->pci_dev = &d->dev; |
| 2029 | 2192 |
hw/vga_int.h
| @@ -139,6 +139,7 @@ | @@ -139,6 +139,7 @@ | ||
| 139 | vga_hw_update_ptr update; \ | 139 | vga_hw_update_ptr update; \ |
| 140 | vga_hw_invalidate_ptr invalidate; \ | 140 | vga_hw_invalidate_ptr invalidate; \ |
| 141 | vga_hw_screen_dump_ptr screen_dump; \ | 141 | vga_hw_screen_dump_ptr screen_dump; \ |
| 142 | + vga_hw_text_update_ptr text_update; \ | ||
| 142 | /* hardware mouse cursor support */ \ | 143 | /* hardware mouse cursor support */ \ |
| 143 | uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ | 144 | uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ |
| 144 | void (*cursor_invalidate)(struct VGAState *s); \ | 145 | void (*cursor_invalidate)(struct VGAState *s); \ |
hw/vmware_vga.c
| @@ -949,6 +949,14 @@ static void vmsvga_screen_dump(void *opaque, const char *filename) | @@ -949,6 +949,14 @@ static void vmsvga_screen_dump(void *opaque, const char *filename) | ||
| 949 | } | 949 | } |
| 950 | } | 950 | } |
| 951 | 951 | ||
| 952 | +static void vmsvga_text_update(void *opaque, console_ch_t *chardata) | ||
| 953 | +{ | ||
| 954 | + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; | ||
| 955 | + | ||
| 956 | + if (s->text_update) | ||
| 957 | + s->text_update(opaque, chardata); | ||
| 958 | +} | ||
| 959 | + | ||
| 952 | #ifdef DIRECT_VRAM | 960 | #ifdef DIRECT_VRAM |
| 953 | static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) | 961 | static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) |
| 954 | { | 962 | { |
| @@ -1101,7 +1109,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds, | @@ -1101,7 +1109,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds, | ||
| 1101 | iomemtype); | 1109 | iomemtype); |
| 1102 | 1110 | ||
| 1103 | graphic_console_init(ds, vmsvga_update_display, | 1111 | graphic_console_init(ds, vmsvga_update_display, |
| 1104 | - vmsvga_invalidate_display, vmsvga_screen_dump, s); | 1112 | + vmsvga_invalidate_display, vmsvga_screen_dump, |
| 1113 | + vmsvga_text_update, s); | ||
| 1105 | 1114 | ||
| 1106 | #ifdef EMBED_STDVGA | 1115 | #ifdef EMBED_STDVGA |
| 1107 | vga_common_init((VGAState *) s, ds, | 1116 | vga_common_init((VGAState *) s, ds, |
monitor.c
| @@ -824,6 +824,8 @@ static const KeyDef key_defs[] = { | @@ -824,6 +824,8 @@ static const KeyDef key_defs[] = { | ||
| 824 | { 0x31, "n" }, | 824 | { 0x31, "n" }, |
| 825 | { 0x32, "m" }, | 825 | { 0x32, "m" }, |
| 826 | 826 | ||
| 827 | + { 0x37, "asterisk" }, | ||
| 828 | + | ||
| 827 | { 0x39, "spc" }, | 829 | { 0x39, "spc" }, |
| 828 | { 0x3a, "caps_lock" }, | 830 | { 0x3a, "caps_lock" }, |
| 829 | { 0x3b, "f1" }, | 831 | { 0x3b, "f1" }, |
vl.c
| @@ -172,6 +172,7 @@ BlockDriverState *bs_snapshots; | @@ -172,6 +172,7 @@ BlockDriverState *bs_snapshots; | ||
| 172 | int vga_ram_size; | 172 | int vga_ram_size; |
| 173 | static DisplayState display_state; | 173 | static DisplayState display_state; |
| 174 | int nographic; | 174 | int nographic; |
| 175 | +int curses; | ||
| 175 | const char* keyboard_layout = NULL; | 176 | const char* keyboard_layout = NULL; |
| 176 | int64_t ticks_per_sec; | 177 | int64_t ticks_per_sec; |
| 177 | int ram_size; | 178 | int ram_size; |
| @@ -7652,6 +7653,9 @@ static void help(int exitcode) | @@ -7652,6 +7653,9 @@ static void help(int exitcode) | ||
| 7652 | " (default is CL-GD5446 PCI VGA)\n" | 7653 | " (default is CL-GD5446 PCI VGA)\n" |
| 7653 | "-no-acpi disable ACPI\n" | 7654 | "-no-acpi disable ACPI\n" |
| 7654 | #endif | 7655 | #endif |
| 7656 | +#ifdef CONFIG_CURSES | ||
| 7657 | + "-curses use a curses/ncurses interface instead of SDL\n" | ||
| 7658 | +#endif | ||
| 7655 | "-no-reboot exit instead of rebooting\n" | 7659 | "-no-reboot exit instead of rebooting\n" |
| 7656 | "-loadvm file start right away with a saved state (loadvm in monitor)\n" | 7660 | "-loadvm file start right away with a saved state (loadvm in monitor)\n" |
| 7657 | "-vnc display start a VNC server on display\n" | 7661 | "-vnc display start a VNC server on display\n" |
| @@ -7757,6 +7761,7 @@ enum { | @@ -7757,6 +7761,7 @@ enum { | ||
| 7757 | QEMU_OPTION_smp, | 7761 | QEMU_OPTION_smp, |
| 7758 | QEMU_OPTION_vnc, | 7762 | QEMU_OPTION_vnc, |
| 7759 | QEMU_OPTION_no_acpi, | 7763 | QEMU_OPTION_no_acpi, |
| 7764 | + QEMU_OPTION_curses, | ||
| 7760 | QEMU_OPTION_no_reboot, | 7765 | QEMU_OPTION_no_reboot, |
| 7761 | QEMU_OPTION_show_cursor, | 7766 | QEMU_OPTION_show_cursor, |
| 7762 | QEMU_OPTION_daemonize, | 7767 | QEMU_OPTION_daemonize, |
| @@ -7853,6 +7858,9 @@ const QEMUOption qemu_options[] = { | @@ -7853,6 +7858,9 @@ const QEMUOption qemu_options[] = { | ||
| 7853 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, | 7858 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, |
| 7854 | { "smp", HAS_ARG, QEMU_OPTION_smp }, | 7859 | { "smp", HAS_ARG, QEMU_OPTION_smp }, |
| 7855 | { "vnc", HAS_ARG, QEMU_OPTION_vnc }, | 7860 | { "vnc", HAS_ARG, QEMU_OPTION_vnc }, |
| 7861 | +#ifdef CONFIG_CURSES | ||
| 7862 | + { "curses", 0, QEMU_OPTION_curses }, | ||
| 7863 | +#endif | ||
| 7856 | 7864 | ||
| 7857 | /* temporary options */ | 7865 | /* temporary options */ |
| 7858 | { "usb", 0, QEMU_OPTION_usb }, | 7866 | { "usb", 0, QEMU_OPTION_usb }, |
| @@ -8189,6 +8197,7 @@ int main(int argc, char **argv) | @@ -8189,6 +8197,7 @@ int main(int argc, char **argv) | ||
| 8189 | #endif | 8197 | #endif |
| 8190 | snapshot = 0; | 8198 | snapshot = 0; |
| 8191 | nographic = 0; | 8199 | nographic = 0; |
| 8200 | + curses = 0; | ||
| 8192 | kernel_filename = NULL; | 8201 | kernel_filename = NULL; |
| 8193 | kernel_cmdline = ""; | 8202 | kernel_cmdline = ""; |
| 8194 | cyls = heads = secs = 0; | 8203 | cyls = heads = secs = 0; |
| @@ -8363,6 +8372,11 @@ int main(int argc, char **argv) | @@ -8363,6 +8372,11 @@ int main(int argc, char **argv) | ||
| 8363 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | 8372 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
| 8364 | nographic = 1; | 8373 | nographic = 1; |
| 8365 | break; | 8374 | break; |
| 8375 | +#ifdef CONFIG_CURSES | ||
| 8376 | + case QEMU_OPTION_curses: | ||
| 8377 | + curses = 1; | ||
| 8378 | + break; | ||
| 8379 | +#endif | ||
| 8366 | case QEMU_OPTION_portrait: | 8380 | case QEMU_OPTION_portrait: |
| 8367 | graphic_rotate = 1; | 8381 | graphic_rotate = 1; |
| 8368 | break; | 8382 | break; |
| @@ -8903,13 +8917,23 @@ int main(int argc, char **argv) | @@ -8903,13 +8917,23 @@ int main(int argc, char **argv) | ||
| 8903 | /* terminal init */ | 8917 | /* terminal init */ |
| 8904 | memset(&display_state, 0, sizeof(display_state)); | 8918 | memset(&display_state, 0, sizeof(display_state)); |
| 8905 | if (nographic) { | 8919 | if (nographic) { |
| 8920 | + if (curses) { | ||
| 8921 | + fprintf(stderr, "fatal: -nographic can't be used with -curses\n"); | ||
| 8922 | + exit(1); | ||
| 8923 | + } | ||
| 8906 | /* nearly nothing to do */ | 8924 | /* nearly nothing to do */ |
| 8907 | dumb_display_init(ds); | 8925 | dumb_display_init(ds); |
| 8908 | } else if (vnc_display != NULL) { | 8926 | } else if (vnc_display != NULL) { |
| 8909 | vnc_display_init(ds); | 8927 | vnc_display_init(ds); |
| 8910 | if (vnc_display_open(ds, vnc_display) < 0) | 8928 | if (vnc_display_open(ds, vnc_display) < 0) |
| 8911 | exit(1); | 8929 | exit(1); |
| 8912 | - } else { | 8930 | + } else |
| 8931 | +#if defined(CONFIG_CURSES) | ||
| 8932 | + if (curses) { | ||
| 8933 | + curses_display_init(ds, full_screen); | ||
| 8934 | + } else | ||
| 8935 | +#endif | ||
| 8936 | + { | ||
| 8913 | #if defined(CONFIG_SDL) | 8937 | #if defined(CONFIG_SDL) |
| 8914 | sdl_display_init(ds, full_screen, no_frame); | 8938 | sdl_display_init(ds, full_screen, no_frame); |
| 8915 | #elif defined(CONFIG_COCOA) | 8939 | #elif defined(CONFIG_COCOA) |
vnc.c
| @@ -945,6 +945,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) | @@ -945,6 +945,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) | ||
| 945 | return; | 945 | return; |
| 946 | } | 946 | } |
| 947 | break; | 947 | break; |
| 948 | + case 0x3a: /* CapsLock */ | ||
| 948 | case 0x45: /* NumLock */ | 949 | case 0x45: /* NumLock */ |
| 949 | if (!down) | 950 | if (!down) |
| 950 | vs->modifiers_state[keycode] ^= 1; | 951 | vs->modifiers_state[keycode] ^= 1; |