* [Qemu-devel] [PATCH 0/5] curses: wide character support @ 2016-10-15 19:53 Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault ` (5 more replies) 0 siblings, 6 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault Hello, This patch series adds wide character support to the curses frontend of qemu, thus allowing to fix a lot of input and output issues with e.g. accented letters and semi-graphic glyphs. Since qemu can't know the encoding of the VGA font, the user has to specify it (just like he has to specify the keyboard layout with -k). I used option -f to make it simple for now, but I welcome any other idea :) Samuel Samuel Thibault (5): curses: fix left/right arrow translation curses: Use cursesw instead of curses curses: use wide output functions curses: add option to specify VGA font encoding curses: support wide input configure | 71 ++++++-- hw/display/vga.c | 4 +- include/sysemu/sysemu.h | 1 + include/ui/console.h | 16 +- qemu-options.hx | 5 +- ui/curses.c | 436 +++++++++++++++++++++++++++++++++++++++++------- ui/curses_keys.h | 113 +++++++------ vl.c | 21 ++- 8 files changed, 543 insertions(+), 124 deletions(-) -- 2.9.3 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault @ 2016-10-15 19:53 ` Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw instead of curses Samuel Thibault ` (4 subsequent siblings) 5 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault In default VGA font, left/right arrow are glyphs 0x1a and 0x1b, not 0x0a and 0x0b. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- ui/curses.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/curses.c b/ui/curses.c index c8be4b7..3599295 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -370,10 +370,10 @@ static void curses_setup(void) /* ACS_* is not constant. So, we can't initialize statically. */ vga_to_curses['\0'] = ' '; vga_to_curses[0x04] = ACS_DIAMOND; - vga_to_curses[0x0a] = ACS_RARROW; - vga_to_curses[0x0b] = ACS_LARROW; vga_to_curses[0x18] = ACS_UARROW; vga_to_curses[0x19] = ACS_DARROW; + vga_to_curses[0x1a] = ACS_RARROW; + vga_to_curses[0x1b] = ACS_LARROW; vga_to_curses[0x9c] = ACS_STERLING; vga_to_curses[0xb0] = ACS_BOARD; vga_to_curses[0xb1] = ACS_CKBOARD; -- 2.9.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 2/5] curses: Use cursesw instead of curses 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault @ 2016-10-15 19:53 ` Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault ` (3 subsequent siblings) 5 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault Use ncursesw package instead of curses on non-mingw, and check a few functions. Also take cflags from pkg-config, since cursesw headers may be in a separate, non-default directory. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- configure | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 7d083bd..29649d9 100755 --- a/configure +++ b/configure @@ -2890,27 +2890,38 @@ fi # curses probe if test "$curses" != "no" ; then if test "$mingw32" = "yes" ; then - curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lpdcurses" + curses_inc_list="$($pkg_config --cflags ncurses 2>/dev/null):" + curses_lib_list="$($pkg_config --libs ncurses 2>/dev/null):-lpdcurses" else - curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lncurses:-lcurses" + curses_inc_list="$($pkg_config --cflags ncursesw 2>/dev/null):" + curses_lib_list="$($pkg_config --libs ncursesw 2>/dev/null):-lncursesw:-lcursesw" fi curses_found=no cat > $TMPC << EOF +#include <locale.h> #include <curses.h> +#include <wchar.h> int main(void) { const char *s = curses_version(); + wchar_t wch = L'w'; + setlocale(LC_ALL, ""); resize_term(0, 0); + addwstr(L"wide chars\n"); + addnwstr(&wch, 1); return s != 0; } EOF IFS=: - for curses_lib in $curses_list; do - unset IFS - if compile_prog "" "$curses_lib" ; then - curses_found=yes - libs_softmmu="$curses_lib $libs_softmmu" - break - fi + for curses_inc in $curses_inc_list; do + for curses_lib in $curses_lib_list; do + unset IFS + if compile_prog "$curses_inc" "$curses_lib" ; then + curses_found=yes + QEMU_CFLAGS="$curses_inc $QEMU_CFLAGS" + libs_softmmu="$curses_lib $libs_softmmu" + break + fi + done done unset IFS if test "$curses_found" = "yes" ; then -- 2.9.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 3/5] curses: use wide output functions 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw instead of curses Samuel Thibault @ 2016-10-15 19:53 ` Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault ` (2 subsequent siblings) 5 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault This makes use of cchar_t instead of chtype when using ncursesw, which allows to store a wide char as well as the WACS values. This also allows to complete the printable glyphs list beyond ascii and the ACS values. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- configure | 5 +- hw/display/vga.c | 4 +- include/ui/console.h | 16 ++- ui/curses.c | 321 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 294 insertions(+), 52 deletions(-) diff --git a/configure b/configure index 29649d9..ebe0599 100755 --- a/configure +++ b/configure @@ -2901,14 +2901,17 @@ if test "$curses" != "no" ; then #include <locale.h> #include <curses.h> #include <wchar.h> +#include <langinfo.h> int main(void) { const char *s = curses_version(); + const char *codeset; wchar_t wch = L'w'; setlocale(LC_ALL, ""); resize_term(0, 0); addwstr(L"wide chars\n"); addnwstr(&wch, 1); - return s != 0; + codeset = nl_langinfo(CODESET); + return s != 0 && codeset != 0; } EOF IFS=: diff --git a/hw/display/vga.c b/hw/display/vga.c index 2a88b3c..ce225c9 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1966,7 +1966,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; src ++, dst ++, i ++) { console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); - if (*dst != val) { + if (memcmp(dst, &val, sizeof(val))) { *dst = val; c_max = i; break; @@ -1975,7 +1975,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) c_min = i; for (; i < size; src ++, dst ++, i ++) { console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); - if (*dst != val) { + if (memcmp(dst, &val, sizeof(val))) { *dst = val; c_max = i; } diff --git a/include/ui/console.h b/include/ui/console.h index d9c13d2..94e3133 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -338,8 +338,8 @@ static inline pixman_format_code_t surface_format(DisplaySurface *s) #ifdef CONFIG_CURSES #include <curses.h> -typedef chtype console_ch_t; -extern chtype vga_to_curses[]; +typedef cchar_t console_ch_t; +extern console_ch_t vga_to_curses[]; #else typedef unsigned long console_ch_t; #endif @@ -347,16 +347,20 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { uint8_t c = ch; #ifdef CONFIG_CURSES - if (vga_to_curses[c]) { - ch &= ~(console_ch_t)0xff; - ch |= vga_to_curses[c]; + if (vga_to_curses[c].chars[0]) { + *dest = vga_to_curses[c]; + } else { + dest->chars[0] = c; + dest->chars[1] = 0; + dest->attr = 0; } + dest->attr |= ch & ~0xff; #else if (c == '\0') { ch |= ' '; } -#endif *dest = ch; +#endif } typedef struct GraphicHwOps { diff --git a/ui/curses.c b/ui/curses.c index 3599295..cd8ed5f 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -28,6 +28,9 @@ #include <sys/ioctl.h> #include <termios.h> #endif +#include <locale.h> +#include <wchar.h> +#include <langinfo.h> #include "qemu-common.h" #include "ui/console.h" @@ -43,16 +46,17 @@ static WINDOW *screenpad = NULL; static int width, height, gwidth, gheight, invalidate; static int px, py, sminx, sminy, smaxx, smaxy; -chtype vga_to_curses[256]; +console_ch_t vga_to_curses[256]; static void curses_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { - chtype *line; + console_ch_t *line; - line = ((chtype *) screen) + y * width; - for (h += y; y < h; y ++, line += width) - mvwaddchnstr(screenpad, y, 0, line, width); + line = ((console_ch_t *) screen) + y * width; + for (h += y; y < h; y ++, line += width) { + mvwadd_wchnstr(screenpad, y, 0, line, width); + } pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); refresh(); @@ -358,45 +362,275 @@ static void curses_setup(void) /* * Setup mapping for vga to curses line graphics. - * FIXME: for better font, have to use ncursesw and setlocale() */ -#if 0 - /* FIXME: map from where? */ - ACS_S1; - ACS_S3; - ACS_S7; - ACS_S9; -#endif - /* ACS_* is not constant. So, we can't initialize statically. */ - vga_to_curses['\0'] = ' '; - vga_to_curses[0x04] = ACS_DIAMOND; - vga_to_curses[0x18] = ACS_UARROW; - vga_to_curses[0x19] = ACS_DARROW; - vga_to_curses[0x1a] = ACS_RARROW; - vga_to_curses[0x1b] = ACS_LARROW; - vga_to_curses[0x9c] = ACS_STERLING; - vga_to_curses[0xb0] = ACS_BOARD; - vga_to_curses[0xb1] = ACS_CKBOARD; - vga_to_curses[0xb3] = ACS_VLINE; - vga_to_curses[0xb4] = ACS_RTEE; - vga_to_curses[0xbf] = ACS_URCORNER; - vga_to_curses[0xc0] = ACS_LLCORNER; - vga_to_curses[0xc1] = ACS_BTEE; - vga_to_curses[0xc2] = ACS_TTEE; - vga_to_curses[0xc3] = ACS_LTEE; - vga_to_curses[0xc4] = ACS_HLINE; - vga_to_curses[0xc5] = ACS_PLUS; - vga_to_curses[0xce] = ACS_LANTERN; - vga_to_curses[0xd8] = ACS_NEQUAL; - vga_to_curses[0xd9] = ACS_LRCORNER; - vga_to_curses[0xda] = ACS_ULCORNER; - vga_to_curses[0xdb] = ACS_BLOCK; - vga_to_curses[0xe3] = ACS_PI; - vga_to_curses[0xf1] = ACS_PLMINUS; - vga_to_curses[0xf2] = ACS_GEQUAL; - vga_to_curses[0xf3] = ACS_LEQUAL; - vga_to_curses[0xf8] = ACS_DEGREE; - vga_to_curses[0xfe] = ACS_BULLET; + + vga_to_curses['\0'].chars[0] = L' '; + vga_to_curses[0x01].chars[0] = L'\u263a'; + vga_to_curses[0x02].chars[0] = L'\u263b'; + vga_to_curses[0x03].chars[0] = L'\u2665'; + vga_to_curses[0x04].chars[0] = L'\u2666'; + vga_to_curses[0x05].chars[0] = L'\u2663'; + vga_to_curses[0x06].chars[0] = L'\u2660'; + vga_to_curses[0x07].chars[0] = L'\u2022'; + vga_to_curses[0x08].chars[0] = L'\u25d8'; + vga_to_curses[0x09].chars[0] = L'\u25cb'; + vga_to_curses[0x0a].chars[0] = L'\u25d9'; + vga_to_curses[0x0b].chars[0] = L'\u2642'; + vga_to_curses[0x0c].chars[0] = L'\u2640'; + vga_to_curses[0x0d].chars[0] = L'\u266a'; + vga_to_curses[0x0e].chars[0] = L'\u266b'; + vga_to_curses[0x0f].chars[0] = L'\u263c'; + vga_to_curses[0x10].chars[0] = L'\u25ba'; + vga_to_curses[0x11].chars[0] = L'\u25c4'; + vga_to_curses[0x12].chars[0] = L'\u2195'; + vga_to_curses[0x13].chars[0] = L'\u203c'; + vga_to_curses[0x14].chars[0] = L'\u00b6'; + vga_to_curses[0x15].chars[0] = L'\u00a7'; + vga_to_curses[0x16].chars[0] = L'\u25ac'; + vga_to_curses[0x17].chars[0] = L'\u21a8'; + vga_to_curses[0x18].chars[0] = L'\u2191'; + vga_to_curses[0x19].chars[0] = L'\u2193'; + vga_to_curses[0x1a].chars[0] = L'\u2192'; + vga_to_curses[0x1b].chars[0] = L'\u2190'; + vga_to_curses[0x1c].chars[0] = L'\u221f'; + vga_to_curses[0x1d].chars[0] = L'\u2194'; + vga_to_curses[0x1e].chars[0] = L'\u25b2'; + vga_to_curses[0x1f].chars[0] = L'\u25bc'; + + { + /* Hardcode CP437 to unicode */ + vga_to_curses[0x80].chars[0] = L'\u00C7'; + vga_to_curses[0x81].chars[0] = L'\u00FC'; + vga_to_curses[0x82].chars[0] = L'\u00E9'; + vga_to_curses[0x83].chars[0] = L'\u00E2'; + vga_to_curses[0x84].chars[0] = L'\u00E4'; + vga_to_curses[0x85].chars[0] = L'\u00E0'; + vga_to_curses[0x86].chars[0] = L'\u00E5'; + vga_to_curses[0x87].chars[0] = L'\u00E7'; + vga_to_curses[0x88].chars[0] = L'\u00EA'; + vga_to_curses[0x89].chars[0] = L'\u00EB'; + vga_to_curses[0x8a].chars[0] = L'\u00E8'; + vga_to_curses[0x8b].chars[0] = L'\u00EF'; + vga_to_curses[0x8c].chars[0] = L'\u00EE'; + vga_to_curses[0x8d].chars[0] = L'\u00EC'; + vga_to_curses[0x8e].chars[0] = L'\u00C4'; + vga_to_curses[0x8f].chars[0] = L'\u00C5'; + vga_to_curses[0x90].chars[0] = L'\u00C9'; + vga_to_curses[0x91].chars[0] = L'\u00E6'; + vga_to_curses[0x92].chars[0] = L'\u00C6'; + vga_to_curses[0x93].chars[0] = L'\u00F4'; + vga_to_curses[0x94].chars[0] = L'\u00F6'; + vga_to_curses[0x95].chars[0] = L'\u00F2'; + vga_to_curses[0x96].chars[0] = L'\u00FB'; + vga_to_curses[0x97].chars[0] = L'\u00F9'; + vga_to_curses[0x98].chars[0] = L'\u00FF'; + vga_to_curses[0x99].chars[0] = L'\u00D6'; + vga_to_curses[0x9a].chars[0] = L'\u00DC'; + vga_to_curses[0x9b].chars[0] = L'\u00A2'; + vga_to_curses[0x9c].chars[0] = L'\u00A3'; + vga_to_curses[0x9d].chars[0] = L'\u00A5'; + vga_to_curses[0x9e].chars[0] = L'\u20A7'; + vga_to_curses[0x9f].chars[0] = L'\u0192'; + vga_to_curses[0xa0].chars[0] = L'\u00E1'; + vga_to_curses[0xa1].chars[0] = L'\u00ED'; + vga_to_curses[0xa2].chars[0] = L'\u00F3'; + vga_to_curses[0xa3].chars[0] = L'\u00FA'; + vga_to_curses[0xa4].chars[0] = L'\u00F1'; + vga_to_curses[0xa5].chars[0] = L'\u00D1'; + vga_to_curses[0xa6].chars[0] = L'\u00AA'; + vga_to_curses[0xa7].chars[0] = L'\u00BA'; + vga_to_curses[0xa8].chars[0] = L'\u00BF'; + vga_to_curses[0xa9].chars[0] = L'\u2310'; + vga_to_curses[0xaa].chars[0] = L'\u00AC'; + vga_to_curses[0xab].chars[0] = L'\u00BD'; + vga_to_curses[0xac].chars[0] = L'\u00BC'; + vga_to_curses[0xad].chars[0] = L'\u00A1'; + vga_to_curses[0xae].chars[0] = L'\u00AB'; + vga_to_curses[0xaf].chars[0] = L'\u00BB'; + vga_to_curses[0xb0].chars[0] = L'\u2591'; + vga_to_curses[0xb1].chars[0] = L'\u2592'; + vga_to_curses[0xb2].chars[0] = L'\u2593'; + vga_to_curses[0xb3].chars[0] = L'\u2502'; + vga_to_curses[0xb4].chars[0] = L'\u2524'; + vga_to_curses[0xb5].chars[0] = L'\u2561'; + vga_to_curses[0xb6].chars[0] = L'\u2562'; + vga_to_curses[0xb7].chars[0] = L'\u2556'; + vga_to_curses[0xb8].chars[0] = L'\u2555'; + vga_to_curses[0xb9].chars[0] = L'\u2563'; + vga_to_curses[0xba].chars[0] = L'\u2551'; + vga_to_curses[0xbb].chars[0] = L'\u2557'; + vga_to_curses[0xbc].chars[0] = L'\u255D'; + vga_to_curses[0xbd].chars[0] = L'\u255C'; + vga_to_curses[0xbe].chars[0] = L'\u255B'; + vga_to_curses[0xbf].chars[0] = L'\u2510'; + vga_to_curses[0xc0].chars[0] = L'\u2514'; + vga_to_curses[0xc1].chars[0] = L'\u2534'; + vga_to_curses[0xc2].chars[0] = L'\u252C'; + vga_to_curses[0xc3].chars[0] = L'\u251C'; + vga_to_curses[0xc4].chars[0] = L'\u2500'; + vga_to_curses[0xc5].chars[0] = L'\u253C'; + vga_to_curses[0xc6].chars[0] = L'\u255E'; + vga_to_curses[0xc7].chars[0] = L'\u255F'; + vga_to_curses[0xc8].chars[0] = L'\u255A'; + vga_to_curses[0xc9].chars[0] = L'\u2554'; + vga_to_curses[0xca].chars[0] = L'\u2569'; + vga_to_curses[0xcb].chars[0] = L'\u2566'; + vga_to_curses[0xcc].chars[0] = L'\u2560'; + vga_to_curses[0xcd].chars[0] = L'\u2550'; + vga_to_curses[0xce].chars[0] = L'\u256C'; + vga_to_curses[0xcf].chars[0] = L'\u2567'; + vga_to_curses[0xd0].chars[0] = L'\u2568'; + vga_to_curses[0xd1].chars[0] = L'\u2564'; + vga_to_curses[0xd2].chars[0] = L'\u2565'; + vga_to_curses[0xd3].chars[0] = L'\u2559'; + vga_to_curses[0xd4].chars[0] = L'\u2558'; + vga_to_curses[0xd5].chars[0] = L'\u2552'; + vga_to_curses[0xd6].chars[0] = L'\u2553'; + vga_to_curses[0xd7].chars[0] = L'\u256B'; + vga_to_curses[0xd8].chars[0] = L'\u256A'; + vga_to_curses[0xd9].chars[0] = L'\u2518'; + vga_to_curses[0xda].chars[0] = L'\u250C'; + vga_to_curses[0xdb].chars[0] = L'\u2588'; + vga_to_curses[0xdc].chars[0] = L'\u2584'; + vga_to_curses[0xdd].chars[0] = L'\u258C'; + vga_to_curses[0xde].chars[0] = L'\u2590'; + vga_to_curses[0xdf].chars[0] = L'\u2580'; + vga_to_curses[0xe0].chars[0] = L'\u03B1'; + vga_to_curses[0xe1].chars[0] = L'\u00DF'; + vga_to_curses[0xe2].chars[0] = L'\u0393'; + vga_to_curses[0xe3].chars[0] = L'\u03C0'; + vga_to_curses[0xe4].chars[0] = L'\u03A3'; + vga_to_curses[0xe5].chars[0] = L'\u03C3'; + vga_to_curses[0xe6].chars[0] = L'\u00B5'; + vga_to_curses[0xe7].chars[0] = L'\u03C4'; + vga_to_curses[0xe8].chars[0] = L'\u03A6'; + vga_to_curses[0xe9].chars[0] = L'\u0398'; + vga_to_curses[0xea].chars[0] = L'\u03A9'; + vga_to_curses[0xeb].chars[0] = L'\u03B4'; + vga_to_curses[0xec].chars[0] = L'\u221E'; + vga_to_curses[0xed].chars[0] = L'\u03C6'; + vga_to_curses[0xee].chars[0] = L'\u03B5'; + vga_to_curses[0xef].chars[0] = L'\u2229'; + vga_to_curses[0xf0].chars[0] = L'\u2261'; + vga_to_curses[0xf1].chars[0] = L'\u00B1'; + vga_to_curses[0xf2].chars[0] = L'\u2265'; + vga_to_curses[0xf3].chars[0] = L'\u2264'; + vga_to_curses[0xf4].chars[0] = L'\u2320'; + vga_to_curses[0xf5].chars[0] = L'\u2321'; + vga_to_curses[0xf6].chars[0] = L'\u00F7'; + vga_to_curses[0xf7].chars[0] = L'\u2248'; + vga_to_curses[0xf8].chars[0] = L'\u00B0'; + vga_to_curses[0xf9].chars[0] = L'\u2219'; + vga_to_curses[0xfa].chars[0] = L'\u00B7'; + vga_to_curses[0xfb].chars[0] = L'\u221A'; + vga_to_curses[0xfc].chars[0] = L'\u207F'; + vga_to_curses[0xfd].chars[0] = L'\u00B2'; + vga_to_curses[0xfe].chars[0] = L'\u25A0'; + vga_to_curses[0xff].chars[0] = L'\u00A0'; + } + if (strcmp(nl_langinfo(CODESET), "UTF-8")) { + /* Non-Unicode capable, use termcap equivalents for those available */ + for (i = 0; i <= 0xff; i++) { + switch (vga_to_curses[i].chars[0]) { + case L'\u00a3': + vga_to_curses[i] = *WACS_STERLING; + break; + case L'\u2591': + vga_to_curses[i] = *WACS_BOARD; + break; + case L'\u2592': + vga_to_curses[i] = *WACS_CKBOARD; + break; + case L'\u2502': + vga_to_curses[i] = *WACS_VLINE; + break; + case L'\u2524': + vga_to_curses[i] = *WACS_RTEE; + break; + case L'\u2510': + vga_to_curses[i] = *WACS_URCORNER; + break; + case L'\u2514': + vga_to_curses[i] = *WACS_LLCORNER; + break; + case L'\u2534': + vga_to_curses[i] = *WACS_BTEE; + break; + case L'\u252c': + vga_to_curses[i] = *WACS_TTEE; + break; + case L'\u251c': + vga_to_curses[i] = *WACS_LTEE; + break; + case L'\u2500': + vga_to_curses[i] = *WACS_HLINE; + break; + case L'\u253c': + vga_to_curses[i] = *WACS_PLUS; + break; + case L'\u256c': + vga_to_curses[i] = *WACS_LANTERN; + break; + case L'\u256a': + vga_to_curses[i] = *WACS_NEQUAL; + break; + case L'\u2518': + vga_to_curses[i] = *WACS_LRCORNER; + break; + case L'\u250c': + vga_to_curses[i] = *WACS_ULCORNER; + break; + case L'\u2588': + vga_to_curses[i] = *WACS_BLOCK; + break; + case L'\u03c0': + vga_to_curses[i] = *WACS_PI; + break; + case L'\u00b1': + vga_to_curses[i] = *WACS_PLMINUS; + break; + case L'\u2265': + vga_to_curses[i] = *WACS_GEQUAL; + break; + case L'\u2264': + vga_to_curses[i] = *WACS_LEQUAL; + break; + case L'\u00b0': + vga_to_curses[i] = *WACS_DEGREE; + break; + case L'\u25a0': + vga_to_curses[i] = *WACS_BULLET; + break; + case L'\u2666': + vga_to_curses[i] = *WACS_DIAMOND; + break; + case L'\u2192': + vga_to_curses[i] = *WACS_RARROW; + break; + case L'\u2190': + vga_to_curses[i] = *WACS_LARROW; + break; + case L'\u2191': + vga_to_curses[i] = *WACS_UARROW; + break; + case L'\u2193': + vga_to_curses[i] = *WACS_DARROW; + break; + case L'\u23ba': + vga_to_curses[i] = *WACS_S1; + break; + case L'\u23bb': + vga_to_curses[i] = *WACS_S3; + break; + case L'\u23bc': + vga_to_curses[i] = *WACS_S7; + break; + case L'\u23bd': + vga_to_curses[i] = *WACS_S9; + break; + } + } + } } static void curses_keyboard_setup(void) @@ -430,6 +664,7 @@ void curses_display_init(DisplayState *ds, int full_screen) } #endif + setlocale(LC_CTYPE, ""); curses_setup(); curses_keyboard_setup(); atexit(curses_atexit); -- 2.9.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault ` (2 preceding siblings ...) 2016-10-15 19:53 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault @ 2016-10-15 19:53 ` Samuel Thibault 2016-10-15 21:07 ` Paolo Bonzini 2016-10-25 23:16 ` Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 5/5] curses: support wide input Samuel Thibault 2016-10-25 22:26 ` [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 5 siblings, 2 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault This detects and uses iconv to convert glyphs from the specified VGA font encoding to unicode. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- configure | 37 +++++++++++++++++++++++++++++++++++++ include/sysemu/sysemu.h | 1 + qemu-options.hx | 5 ++++- ui/curses.c | 41 +++++++++++++++++++++++++++++++++++++++++ vl.c | 21 ++++++++++++++++++++- 5 files changed, 103 insertions(+), 2 deletions(-) diff --git a/configure b/configure index ebe0599..2ecd03a 100755 --- a/configure +++ b/configure @@ -203,6 +203,7 @@ bluez="" brlapi="" curl="" curses="" +cursesw="" docs="" fdt="" netmap="no" @@ -984,6 +985,10 @@ for opt do ;; --enable-curses) curses="yes" ;; + --disable-iconv) iconv="no" + ;; + --enable-iconv) iconv="yes" + ;; --disable-curl) curl="no" ;; --enable-curl) curl="yes" @@ -1351,6 +1356,7 @@ disabled with --disable-FEATURE, default is enabled if available: --with-gtkabi select preferred GTK ABI 2.0 or 3.0 vte vte support for the gtk UI curses curses UI + iconv font glyph conversion support vnc VNC UI support vnc-sasl SASL encryption for VNC server vnc-jpeg JPEG lossy compression for VNC server @@ -2938,6 +2944,33 @@ EOF fi ########################################## +# iconv probe +if test "$iconv" != "no" ; then + cat > $TMPC << EOF +#include <iconv.h> +int main(void) { + iconv_t conv = iconv_open("ISO-8859-1", "ISO-8859-1"); + return conv != (iconv_t) -1; +} +EOF + for iconv_lib in '' -liconv; do + if compile_prog "" "$iconv_lib" ; then + iconv_found=yes + libs_softmmu="$iconv_lib $libs_softmmu" + break + fi + done + if test "$iconv_found" = "yes" ; then + iconv=yes + else + if test "$iconv" = "yes" ; then + feature_not_found "iconv" "Install iconv devel" + fi + iconv=no + fi +fi + +########################################## # curl probe if test "$curl" != "no" ; then if $pkg_config libcurl --exists; then @@ -4860,6 +4893,7 @@ echo "nettle $nettle $(echo_version $nettle $nettle_version)" echo "nettle kdf $nettle_kdf" echo "libtasn1 $tasn1" echo "curses support $curses" +echo "iconv support $iconv" echo "virgl support $virglrenderer" echo "curl support $curl" echo "mingw32 support $mingw32" @@ -5120,6 +5154,9 @@ fi if test "$curses" = "yes" ; then echo "CONFIG_CURSES=y" >> $config_host_mak fi +if test "$iconv" = "yes" ; then + echo "CONFIG_ICONV=y" >> $config_host_mak +fi if test "$utimens" = "yes" ; then echo "CONFIG_UTIMENSAT=y" >> $config_host_mak fi diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ee7c760..b90b9b1 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -148,6 +148,7 @@ extern int graphic_height; extern int graphic_depth; extern int display_opengl; extern const char *keyboard_layout; +extern const char *font_charset; extern int win2k_install_hack; extern int alt_grab; extern int ctrl_grab; diff --git a/qemu-options.hx b/qemu-options.hx index 0b621bb..c82a26e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -930,7 +930,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, " [,window_close=on|off][,gl=on|off]|curses|none|\n" "-display gtk[,grab_on_hover=on|off][,gl=on|off]|\n" "-display vnc=<display>[,<optargs>]\n" - "-display curses\n" + "-display curses[,charset=<encoding>]\n" "-display none" " select display type\n" "The default display is equivalent to\n" @@ -961,6 +961,9 @@ support a text mode, QEMU can display this output using a curses/ncurses interface. Nothing is displayed when the graphics device is in graphical mode or if the graphics device does not support a text mode. Generally only the VGA device models support text mode. +The font charset used by the guest can be specified with the +@code{charset} option, for example @code{charset=CP850} for IBM CP850 +encoding. The default is @code{CP437}. @item none Do not display video output. The guest will still see an emulated graphics card, but its output will not be displayed to the QEMU diff --git a/ui/curses.c b/ui/curses.c index cd8ed5f..f839a9d 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -31,6 +31,9 @@ #include <locale.h> #include <wchar.h> #include <langinfo.h> +#ifdef CONFIG_ICONV +#include <iconv.h> +#endif #include "qemu-common.h" #include "ui/console.h" @@ -397,6 +400,44 @@ static void curses_setup(void) vga_to_curses[0x1e].chars[0] = L'\u25b2'; vga_to_curses[0x1f].chars[0] = L'\u25bc'; +#ifdef CONFIG_ICONV + if (font_charset) { + unsigned char ch; + wchar_t wch; + char *pch, *pwch; + size_t sch, swch; + iconv_t conv; + + conv = iconv_open("WCHAR_T", font_charset); + if (conv == (iconv_t) -1) { + fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n", + font_charset, strerror(errno)); + exit(1); + } + + for (i = 0x20; i <= 0xff; i++) { + ch = i; + pch = (char *) &ch; + pwch = (char *) &wch; + sch = sizeof(ch); + swch = sizeof(wch); + if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) { + fprintf(stderr, "Could not convert 0x%2x from %s: '%s'\n", + ch, font_charset, strerror(errno)); + } else { + vga_to_curses[ch].chars[0] = wch; + } + } + } else +#else + if (font_charset) { + if (strcmp(font_charset, "CP437")) { + fprintf(stderr, "iconv support not enabled for converting from %s, " + "only CP437 supported\n", font_charset); + exit(1); + } + } +#endif { /* Hardcode CP437 to unicode */ vga_to_curses[0x80].chars[0] = L'\u00C7'; diff --git a/vl.c b/vl.c index ad2664b..3043132 100644 --- a/vl.c +++ b/vl.c @@ -132,7 +132,8 @@ const char *bios_name = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; int request_opengl = -1; int display_opengl; -const char* keyboard_layout = NULL; +const char *keyboard_layout; +const char *font_charset; ram_addr_t ram_size; const char *mem_path = NULL; int mem_prealloc = 0; /* force preallocation of physical target memory */ @@ -2140,6 +2141,24 @@ static DisplayType select_display(const char *p) } else if (strstart(p, "curses", &opts)) { #ifdef CONFIG_CURSES display = DT_CURSES; + while (*opts) { + const char *nextopt, *name; + + if (strstart(opts, ",charset=", &name)) { + nextopt = strchr(name, ','); + if (nextopt) { + font_charset = g_strndup(name, nextopt - name); + nextopt++; + } else { + font_charset = g_strdup(name); + nextopt = name + strlen(name); + } + } else { + error_report("invalid curses option string"); + exit(1); + } + opts = nextopt; + } #else error_report("curses support is disabled"); exit(1); -- 2.9.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding 2016-10-15 19:53 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault @ 2016-10-15 21:07 ` Paolo Bonzini 2016-10-25 23:16 ` Samuel Thibault 1 sibling, 0 replies; 15+ messages in thread From: Paolo Bonzini @ 2016-10-15 21:07 UTC (permalink / raw) To: Samuel Thibault; +Cc: qemu-devel, kraxel, berrange, peter maydell, mjt > +#ifdef CONFIG_ICONV > + if (font_charset) { > + unsigned char ch; > + wchar_t wch; > + char *pch, *pwch; > + size_t sch, swch; > + iconv_t conv; > + > + conv = iconv_open("WCHAR_T", font_charset); Is this portable? It seems safer to convert to UTF-8 and parse the resulting character (assuming that wchar_t is Unicode). There is already mod_utf8_codepoint for this task. Paolo ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding 2016-10-15 19:53 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault 2016-10-15 21:07 ` Paolo Bonzini @ 2016-10-25 23:16 ` Samuel Thibault 1 sibling, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-25 23:16 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Hello, It seems that in the flurry of qemu-devel mails, I missed this answer. Paolo Bonzini wrote: > > +#ifdef CONFIG_ICONV > > + if (font_charset) { > > + unsigned char ch; > > + wchar_t wch; > > + char *pch, *pwch; > > + size_t sch, swch; > > + iconv_t conv; > > + > > + conv = iconv_open("WCHAR_T", font_charset); > > Is this portable? I confirm it works on at least glibc (thus Linux and other GNUs), MacOS, OpenBSD, FreeBSD, Windows mingw. Samuel ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 5/5] curses: support wide input 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault ` (3 preceding siblings ...) 2016-10-15 19:53 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault @ 2016-10-15 19:53 ` Samuel Thibault 2016-10-25 22:26 ` [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 5 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-15 19:53 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault This makes use of wide curses functions instead of 8bit functions. This allows to type e.g. accented letters. Unfortunately, key codes are then returned with values that could be confused with wide characters by ncurses, so we need to add a maybe_keycode variable to know whether the returned value is a key code or a character (wide support), or possibly both (non-wide support). The translation tables thus also need to be separated into key code translation and character translation. The curses2foo helper makes it easier to use them. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- ui/curses.c | 76 ++++++++++++++++++++++++++++++------- ui/curses_keys.h | 113 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 127 insertions(+), 62 deletions(-) diff --git a/ui/curses.c b/ui/curses.c index f839a9d..441cc93 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -43,6 +43,12 @@ #define FONT_HEIGHT 16 #define FONT_WIDTH 8 +enum maybe_keycode { + CURSES_KEYCODE, + CURSES_CHAR, + CURSES_CHAR_OR_KEYCODE, +}; + static DisplayChangeListener *dcl; static console_ch_t screen[160 * 100]; static WINDOW *screenpad = NULL; @@ -51,6 +57,23 @@ static int px, py, sminx, sminy, smaxx, smaxy; console_ch_t vga_to_curses[256]; +static wint_t console_getch(int *maybe_keycode) +{ + wint_t ret; + switch (get_wch(&ret)) { + case KEY_CODE_YES: + *maybe_keycode = CURSES_KEYCODE; + break; + case OK: + *maybe_keycode = CURSES_CHAR; + break; + case ERR: + ret = -1; + break; + } + return ret; +} + static void curses_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { @@ -186,9 +209,37 @@ static void curses_cursor_position(DisplayChangeListener *dcl, static kbd_layout_t *kbd_layout = NULL; +static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], + int chr, int maybe_keycode) +{ + int ret = -1; + if (maybe_keycode == CURSES_CHAR) { + if (chr < CURSES_CHARS) { + ret = _curses2foo[chr]; + } + } else { + if (chr < CURSES_KEYS) { + ret = _curseskey2foo[chr]; + } + if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE && + chr < CURSES_CHARS) { + ret = _curses2foo[chr]; + } + } + return ret; +} + +#define curses2keycode(chr, maybe_keycode) \ + curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) +#define curses2keysym(chr, maybe_keycode) \ + curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode) +#define curses2qemu(chr, maybe_keycode) \ + curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode) + static void curses_refresh(DisplayChangeListener *dcl) { int chr, keysym, keycode, keycode_alt; + int maybe_keycode; curses_winch_check(); @@ -204,14 +255,14 @@ static void curses_refresh(DisplayChangeListener *dcl) while (1) { /* while there are any pending key strokes to process */ - chr = getch(); + chr = console_getch(&maybe_keycode); - if (chr == ERR) + if (chr == -1) break; #ifdef KEY_RESIZE /* this shouldn't occur when we use a custom SIGWINCH handler */ - if (chr == KEY_RESIZE) { + if (maybe_keycode != 0 && chr == KEY_RESIZE) { clear(); refresh(); curses_calc_pad(); @@ -220,17 +271,19 @@ static void curses_refresh(DisplayChangeListener *dcl) } #endif - keycode = curses2keycode[chr]; + keycode = curses2keycode(chr, maybe_keycode); keycode_alt = 0; /* alt or esc key */ if (keycode == 1) { - int nextchr = getch(); + int next_maybe_keycode; + int nextchr = console_getch(&next_maybe_keycode); - if (nextchr != ERR) { + if (nextchr != -1) { chr = nextchr; + maybe_keycode = next_maybe_keycode; keycode_alt = ALT; - keycode = curses2keycode[chr]; + keycode = curses2keycode(chr, maybe_keycode); if (keycode != -1) { keycode |= ALT; @@ -250,9 +303,7 @@ static void curses_refresh(DisplayChangeListener *dcl) } if (kbd_layout) { - keysym = -1; - if (chr < CURSES_KEYS) - keysym = curses2keysym[chr]; + keysym = curses2keysym(chr, maybe_keycode); if (keysym == -1) { if (chr < ' ') { @@ -317,10 +368,7 @@ static void curses_refresh(DisplayChangeListener *dcl) qemu_input_event_send_key_delay(0); } } else { - keysym = -1; - if (chr < CURSES_KEYS) { - keysym = curses2qemu[chr]; - } + keysym = curses2qemu(chr, maybe_keycode); if (keysym == -1) keysym = chr; diff --git a/ui/curses_keys.h b/ui/curses_keys.h index e39ef9e..ba561f1 100644 --- a/ui/curses_keys.h +++ b/ui/curses_keys.h @@ -49,22 +49,28 @@ /* curses won't detect a Control + Alt + 1, so use Alt + 1 */ #define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ +#define CURSES_CHARS 0x100 /* Support latin1 only */ #define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */ -static const int curses2keysym[CURSES_KEYS] = { - [0 ... (CURSES_KEYS - 1)] = -1, +static const int _curses2keysym[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, [0x7f] = KEY_BACKSPACE, ['\r'] = KEY_ENTER, ['\n'] = KEY_ENTER, [27] = 27, +}; + +static const int _curseskey2keysym[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, + [KEY_BTAB] = '\t' | KEYSYM_SHIFT, [KEY_SPREVIOUS] = KEY_PPAGE | KEYSYM_SHIFT, [KEY_SNEXT] = KEY_NPAGE | KEYSYM_SHIFT, }; -static const int curses2keycode[CURSES_KEYS] = { - [0 ... (CURSES_KEYS - 1)] = -1, +static const int _curses2keycode[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, [0x01b] = 1, /* Escape */ ['1'] = 2, @@ -80,7 +86,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['-'] = 12, ['='] = 13, [0x07f] = 14, /* Backspace */ - [KEY_BACKSPACE] = 14, /* Backspace */ ['\t'] = 15, /* Tab */ ['q'] = 16, @@ -97,7 +102,6 @@ static const int curses2keycode[CURSES_KEYS] = { [']'] = 27, ['\n'] = 28, /* Return */ ['\r'] = 28, /* Return */ - [KEY_ENTER] = 28, /* Return */ ['a'] = 30, ['s'] = 31, @@ -126,33 +130,6 @@ static const int curses2keycode[CURSES_KEYS] = { [' '] = 57, - [KEY_F(1)] = 59, /* Function Key 1 */ - [KEY_F(2)] = 60, /* Function Key 2 */ - [KEY_F(3)] = 61, /* Function Key 3 */ - [KEY_F(4)] = 62, /* Function Key 4 */ - [KEY_F(5)] = 63, /* Function Key 5 */ - [KEY_F(6)] = 64, /* Function Key 6 */ - [KEY_F(7)] = 65, /* Function Key 7 */ - [KEY_F(8)] = 66, /* Function Key 8 */ - [KEY_F(9)] = 67, /* Function Key 9 */ - [KEY_F(10)] = 68, /* Function Key 10 */ - [KEY_F(11)] = 87, /* Function Key 11 */ - [KEY_F(12)] = 88, /* Function Key 12 */ - - [KEY_HOME] = 71 | GREY, /* Home */ - [KEY_UP] = 72 | GREY, /* Up Arrow */ - [KEY_PPAGE] = 73 | GREY, /* Page Up */ - [KEY_LEFT] = 75 | GREY, /* Left Arrow */ - [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ - [KEY_END] = 79 | GREY, /* End */ - [KEY_DOWN] = 80 | GREY, /* Down Arrow */ - [KEY_NPAGE] = 81 | GREY, /* Page Down */ - [KEY_IC] = 82 | GREY, /* Insert */ - [KEY_DC] = 83 | GREY, /* Delete */ - - [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ - [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ - ['!'] = 2 | SHIFT, ['@'] = 3 | SHIFT, ['#'] = 4 | SHIFT, @@ -166,7 +143,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['_'] = 12 | SHIFT, ['+'] = 13 | SHIFT, - [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ ['Q'] = 16 | SHIFT, ['W'] = 17 | SHIFT, ['E'] = 18 | SHIFT, @@ -205,19 +181,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['>'] = 52 | SHIFT, ['?'] = 53 | SHIFT, - [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ - [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ - [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ - [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ - [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ - [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ - [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ - [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ - [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ - [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ - [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ - [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ - ['Q' - '@'] = 16 | CNTRL, /* Control + q */ ['W' - '@'] = 17 | CNTRL, /* Control + w */ ['E' - '@'] = 18 | CNTRL, /* Control + e */ @@ -249,13 +212,67 @@ static const int curses2keycode[CURSES_KEYS] = { }; -static const int curses2qemu[CURSES_KEYS] = { +static const int _curseskey2keycode[CURSES_KEYS] = { [0 ... (CURSES_KEYS - 1)] = -1, + [KEY_BACKSPACE] = 14, /* Backspace */ + + [KEY_ENTER] = 28, /* Return */ + + [KEY_F(1)] = 59, /* Function Key 1 */ + [KEY_F(2)] = 60, /* Function Key 2 */ + [KEY_F(3)] = 61, /* Function Key 3 */ + [KEY_F(4)] = 62, /* Function Key 4 */ + [KEY_F(5)] = 63, /* Function Key 5 */ + [KEY_F(6)] = 64, /* Function Key 6 */ + [KEY_F(7)] = 65, /* Function Key 7 */ + [KEY_F(8)] = 66, /* Function Key 8 */ + [KEY_F(9)] = 67, /* Function Key 9 */ + [KEY_F(10)] = 68, /* Function Key 10 */ + [KEY_F(11)] = 87, /* Function Key 11 */ + [KEY_F(12)] = 88, /* Function Key 12 */ + + [KEY_HOME] = 71 | GREY, /* Home */ + [KEY_UP] = 72 | GREY, /* Up Arrow */ + [KEY_PPAGE] = 73 | GREY, /* Page Up */ + [KEY_LEFT] = 75 | GREY, /* Left Arrow */ + [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ + [KEY_END] = 79 | GREY, /* End */ + [KEY_DOWN] = 80 | GREY, /* Down Arrow */ + [KEY_NPAGE] = 81 | GREY, /* Page Down */ + [KEY_IC] = 82 | GREY, /* Insert */ + [KEY_DC] = 83 | GREY, /* Delete */ + + [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ + [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ + + [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ + + [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ + [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ + [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ + [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ + [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ + [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ + [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ + [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ + [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ + [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ + [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ + [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ +}; + +static const int _curses2qemu[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, + ['\n'] = '\n', ['\r'] = '\n', [0x07f] = QEMU_KEY_BACKSPACE, +}; + +static const int _curseskey2qemu[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, [KEY_DOWN] = QEMU_KEY_DOWN, [KEY_UP] = QEMU_KEY_UP, -- 2.9.3 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault ` (4 preceding siblings ...) 2016-10-15 19:53 ` [Qemu-devel] [PATCH 5/5] curses: support wide input Samuel Thibault @ 2016-10-25 22:26 ` Samuel Thibault 2016-10-26 10:05 ` Gerd Hoffmann 5 siblings, 1 reply; 15+ messages in thread From: Samuel Thibault @ 2016-10-25 22:26 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Hello, Ping? Samuel Thibault, on Sat 15 Oct 2016 21:53:03 +0200, wrote: > This patch series adds wide character support to the curses frontend of qemu, > thus allowing to fix a lot of input and output issues with e.g. accented letters > and semi-graphic glyphs. Since qemu can't know the encoding of the VGA font, the > user has to specify it (just like he has to specify the keyboard layout with > -k). I used option -f to make it simple for now, but I welcome any other idea :) I forgot to mention that I updated the patches according to the reviews on the list (assume cursesw support, and use -display option). Samuel > Samuel Thibault (5): > curses: fix left/right arrow translation > curses: Use cursesw instead of curses > curses: use wide output functions > curses: add option to specify VGA font encoding > curses: support wide input > > configure | 71 ++++++-- > hw/display/vga.c | 4 +- > include/sysemu/sysemu.h | 1 + > include/ui/console.h | 16 +- > qemu-options.hx | 5 +- > ui/curses.c | 436 +++++++++++++++++++++++++++++++++++++++++------- > ui/curses_keys.h | 113 +++++++------ > vl.c | 21 ++- > 8 files changed, 543 insertions(+), 124 deletions(-) > > -- > 2.9.3 > -- Samuel Tu as lu les docs. Tu es devenu un informaticien. Que tu le veuilles ou non. Lire la doc, c'est le Premier et Unique Commandement de l'informaticien. -+- TP in: Guide du Linuxien pervers - "L'évangile selon St Thomas" ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-25 22:26 ` [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault @ 2016-10-26 10:05 ` Gerd Hoffmann 2016-10-26 11:43 ` Samuel Thibault 0 siblings, 1 reply; 15+ messages in thread From: Gerd Hoffmann @ 2016-10-26 10:05 UTC (permalink / raw) To: Samuel Thibault; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt On Mi, 2016-10-26 at 00:26 +0200, Samuel Thibault wrote: > Hello, > > Ping? Back online now after being sick for a while. Sorry for the delay. > Samuel Thibault, on Sat 15 Oct 2016 21:53:03 +0200, wrote: > > This patch series adds wide character support to the curses frontend of qemu, > > thus allowing to fix a lot of input and output issues with e.g. accented letters > > and semi-graphic glyphs. Since qemu can't know the encoding of the VGA font, the > > user has to specify it (just like he has to specify the keyboard layout with > > -k). I used option -f to make it simple for now, but I welcome any other idea :) > > I forgot to mention that I updated the patches according to the reviews > on the list (assume cursesw support, and use -display option). Good, looks much better now without all the #ifdefs. /me wonders whenever we should do the same with iconv. It's part of the POSIX.1-2001 specs, and we have 2016 now. Do we *really* need configure checks and #ifdefs for it? Also we could use iconv for the cp437-to-unicode mapping instead of having a hard-coded table for it. Given how close the freeze deadline is now I'm tempted to cherry-pick patches 0-3 and prepare a pull request ASAP. cheers, Gerd ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-26 10:05 ` Gerd Hoffmann @ 2016-10-26 11:43 ` Samuel Thibault 2016-10-26 12:18 ` Gerd Hoffmann 2016-10-26 12:40 ` Gerd Hoffmann 0 siblings, 2 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-26 11:43 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt Hello, Gerd Hoffmann, on Wed 26 Oct 2016 12:05:55 +0200, wrote: > Back online now after being sick for a while. Oh, sorry about that, hoping you're fine. > > Samuel Thibault, on Sat 15 Oct 2016 21:53:03 +0200, wrote: > > > This patch series adds wide character support to the curses frontend of qemu, > > > thus allowing to fix a lot of input and output issues with e.g. accented letters > > > and semi-graphic glyphs. Since qemu can't know the encoding of the VGA font, the > > > user has to specify it (just like he has to specify the keyboard layout with > > > -k). I used option -f to make it simple for now, but I welcome any other idea :) > > > > I forgot to mention that I updated the patches according to the reviews > > on the list (assume cursesw support, and use -display option). > > Good, looks much better now without all the #ifdefs. > > /me wonders whenever we should do the same with iconv. It's part of the > POSIX.1-2001 specs, and we have 2016 now. Do we *really* need configure > checks and #ifdefs for it? I would only say that libiconv is not always installed by default on BSD systems for instance. > Also we could use iconv for the cp437-to-unicode mapping instead of > having a hard-coded table for it. Ah, indeed. > Given how close the freeze deadline is now I'm tempted to cherry-pick > patches 0-3 and prepare a pull request ASAP. You mean patches 1-3? Patch 5 would be very useful too to fix typing accented letters, and it doesn't depend on patch 4. Thanks, Samuel ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-26 11:43 ` Samuel Thibault @ 2016-10-26 12:18 ` Gerd Hoffmann 2016-10-26 12:40 ` Gerd Hoffmann 1 sibling, 0 replies; 15+ messages in thread From: Gerd Hoffmann @ 2016-10-26 12:18 UTC (permalink / raw) To: Samuel Thibault; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt Hi, > > /me wonders whenever we should do the same with iconv. It's part of the > > POSIX.1-2001 specs, and we have 2016 now. Do we *really* need configure > > checks and #ifdefs for it? > > I would only say that libiconv is not always installed by default on BSD > systems for instance. Hmm, maybe keep the check but disable curses altogether in case iconv isn't there, so we can at least avoid the #ifdefs? > You mean patches 1-3? Patch 5 would be very useful too to fix typing accented > letters, and it doesn't depend on patch 4. Ok, then I'll go pick #5 too. cheers, Gerd ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-26 11:43 ` Samuel Thibault 2016-10-26 12:18 ` Gerd Hoffmann @ 2016-10-26 12:40 ` Gerd Hoffmann 2016-10-26 15:19 ` Samuel Thibault 1 sibling, 1 reply; 15+ messages in thread From: Gerd Hoffmann @ 2016-10-26 12:40 UTC (permalink / raw) To: Samuel Thibault; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt Hi, > > Given how close the freeze deadline is now I'm tempted to cherry-pick > > patches 0-3 and prepare a pull request ASAP. > > You mean patches 1-3? Patch 5 would be very useful too to fix typing accented > letters, and it doesn't depend on patch 4. Hmm, seems #5 needs a rebase, doesn't apply cleanly. Picked 1-3 now. Current queue is at http://localhost/cgit/projects/qemu/.git/log/?h=queue/ui cheers, Gerd ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] curses: wide character support 2016-10-26 12:40 ` Gerd Hoffmann @ 2016-10-26 15:19 ` Samuel Thibault 0 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-10-26 15:19 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt [-- Attachment #1: Type: text/plain, Size: 428 bytes --] Gerd Hoffmann, on Wed 26 Oct 2016 14:40:26 +0200, wrote: > > > Given how close the freeze deadline is now I'm tempted to cherry-pick > > > patches 0-3 and prepare a pull request ASAP. > > > > You mean patches 1-3? Patch 5 would be very useful too to fix typing accented > > letters, and it doesn't depend on patch 4. > > Hmm, seems #5 needs a rebase, doesn't apply cleanly. Here is a patch rebased on current master. Samuel [-- Attachment #2: patch --] [-- Type: text/plain, Size: 11648 bytes --] commit c230fb0bee630a1a138acce542ba6ed4aabdc232 Author: Samuel Thibault <samuel.thibault@ens-lyon.org> Date: Wed Jun 22 23:41:50 2016 +0200 curses: support wide input This makes use of wide curses functions instead of 8bit functions. This allows to type e.g. accented letters. Unfortunately, key codes are then returned with values that could be confused with wide characters by ncurses, so we need to add a maybe_keycode variable to know whether the returned value is a key code or a character (wide support), or possibly both (non-wide support). The translation tables thus also need to be separated into key code translation and character translation. The curses2foo helper makes it easier to use them. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/ui/curses.c b/ui/curses.c index f839a9d..441cc93 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -43,6 +43,12 @@ #define FONT_HEIGHT 16 #define FONT_WIDTH 8 +enum maybe_keycode { + CURSES_KEYCODE, + CURSES_CHAR, + CURSES_CHAR_OR_KEYCODE, +}; + static DisplayChangeListener *dcl; static console_ch_t screen[160 * 100]; static WINDOW *screenpad = NULL; @@ -51,6 +57,23 @@ static int px, py, sminx, sminy, smaxx, smaxy; console_ch_t vga_to_curses[256]; +static wint_t console_getch(int *maybe_keycode) +{ + wint_t ret; + switch (get_wch(&ret)) { + case KEY_CODE_YES: + *maybe_keycode = CURSES_KEYCODE; + break; + case OK: + *maybe_keycode = CURSES_CHAR; + break; + case ERR: + ret = -1; + break; + } + return ret; +} + static void curses_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { @@ -186,9 +209,37 @@ static void curses_cursor_position(DisplayChangeListener *dcl, static kbd_layout_t *kbd_layout = NULL; +static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], + int chr, int maybe_keycode) +{ + int ret = -1; + if (maybe_keycode == CURSES_CHAR) { + if (chr < CURSES_CHARS) { + ret = _curses2foo[chr]; + } + } else { + if (chr < CURSES_KEYS) { + ret = _curseskey2foo[chr]; + } + if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE && + chr < CURSES_CHARS) { + ret = _curses2foo[chr]; + } + } + return ret; +} + +#define curses2keycode(chr, maybe_keycode) \ + curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) +#define curses2keysym(chr, maybe_keycode) \ + curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode) +#define curses2qemu(chr, maybe_keycode) \ + curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode) + static void curses_refresh(DisplayChangeListener *dcl) { int chr, keysym, keycode, keycode_alt; + int maybe_keycode; curses_winch_check(); @@ -204,14 +255,14 @@ static void curses_refresh(DisplayChangeListener *dcl) while (1) { /* while there are any pending key strokes to process */ - chr = getch(); + chr = console_getch(&maybe_keycode); - if (chr == ERR) + if (chr == -1) break; #ifdef KEY_RESIZE /* this shouldn't occur when we use a custom SIGWINCH handler */ - if (chr == KEY_RESIZE) { + if (maybe_keycode != 0 && chr == KEY_RESIZE) { clear(); refresh(); curses_calc_pad(); @@ -220,17 +271,19 @@ static void curses_refresh(DisplayChangeListener *dcl) } #endif - keycode = curses2keycode[chr]; + keycode = curses2keycode(chr, maybe_keycode); keycode_alt = 0; /* alt or esc key */ if (keycode == 1) { - int nextchr = getch(); + int next_maybe_keycode; + int nextchr = console_getch(&next_maybe_keycode); - if (nextchr != ERR) { + if (nextchr != -1) { chr = nextchr; + maybe_keycode = next_maybe_keycode; keycode_alt = ALT; - keycode = curses2keycode[chr]; + keycode = curses2keycode(chr, maybe_keycode); if (keycode != -1) { keycode |= ALT; @@ -250,9 +303,7 @@ static void curses_refresh(DisplayChangeListener *dcl) } if (kbd_layout) { - keysym = -1; - if (chr < CURSES_KEYS) - keysym = curses2keysym[chr]; + keysym = curses2keysym(chr, maybe_keycode); if (keysym == -1) { if (chr < ' ') { @@ -317,10 +368,7 @@ static void curses_refresh(DisplayChangeListener *dcl) qemu_input_event_send_key_delay(0); } } else { - keysym = -1; - if (chr < CURSES_KEYS) { - keysym = curses2qemu[chr]; - } + keysym = curses2qemu(chr, maybe_keycode); if (keysym == -1) keysym = chr; diff --git a/ui/curses_keys.h b/ui/curses_keys.h index e39ef9e..ba561f1 100644 --- a/ui/curses_keys.h +++ b/ui/curses_keys.h @@ -49,22 +49,28 @@ /* curses won't detect a Control + Alt + 1, so use Alt + 1 */ #define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ +#define CURSES_CHARS 0x100 /* Support latin1 only */ #define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */ -static const int curses2keysym[CURSES_KEYS] = { - [0 ... (CURSES_KEYS - 1)] = -1, +static const int _curses2keysym[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, [0x7f] = KEY_BACKSPACE, ['\r'] = KEY_ENTER, ['\n'] = KEY_ENTER, [27] = 27, +}; + +static const int _curseskey2keysym[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, + [KEY_BTAB] = '\t' | KEYSYM_SHIFT, [KEY_SPREVIOUS] = KEY_PPAGE | KEYSYM_SHIFT, [KEY_SNEXT] = KEY_NPAGE | KEYSYM_SHIFT, }; -static const int curses2keycode[CURSES_KEYS] = { - [0 ... (CURSES_KEYS - 1)] = -1, +static const int _curses2keycode[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, [0x01b] = 1, /* Escape */ ['1'] = 2, @@ -80,7 +86,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['-'] = 12, ['='] = 13, [0x07f] = 14, /* Backspace */ - [KEY_BACKSPACE] = 14, /* Backspace */ ['\t'] = 15, /* Tab */ ['q'] = 16, @@ -97,7 +102,6 @@ static const int curses2keycode[CURSES_KEYS] = { [']'] = 27, ['\n'] = 28, /* Return */ ['\r'] = 28, /* Return */ - [KEY_ENTER] = 28, /* Return */ ['a'] = 30, ['s'] = 31, @@ -126,33 +130,6 @@ static const int curses2keycode[CURSES_KEYS] = { [' '] = 57, - [KEY_F(1)] = 59, /* Function Key 1 */ - [KEY_F(2)] = 60, /* Function Key 2 */ - [KEY_F(3)] = 61, /* Function Key 3 */ - [KEY_F(4)] = 62, /* Function Key 4 */ - [KEY_F(5)] = 63, /* Function Key 5 */ - [KEY_F(6)] = 64, /* Function Key 6 */ - [KEY_F(7)] = 65, /* Function Key 7 */ - [KEY_F(8)] = 66, /* Function Key 8 */ - [KEY_F(9)] = 67, /* Function Key 9 */ - [KEY_F(10)] = 68, /* Function Key 10 */ - [KEY_F(11)] = 87, /* Function Key 11 */ - [KEY_F(12)] = 88, /* Function Key 12 */ - - [KEY_HOME] = 71 | GREY, /* Home */ - [KEY_UP] = 72 | GREY, /* Up Arrow */ - [KEY_PPAGE] = 73 | GREY, /* Page Up */ - [KEY_LEFT] = 75 | GREY, /* Left Arrow */ - [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ - [KEY_END] = 79 | GREY, /* End */ - [KEY_DOWN] = 80 | GREY, /* Down Arrow */ - [KEY_NPAGE] = 81 | GREY, /* Page Down */ - [KEY_IC] = 82 | GREY, /* Insert */ - [KEY_DC] = 83 | GREY, /* Delete */ - - [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ - [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ - ['!'] = 2 | SHIFT, ['@'] = 3 | SHIFT, ['#'] = 4 | SHIFT, @@ -166,7 +143,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['_'] = 12 | SHIFT, ['+'] = 13 | SHIFT, - [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ ['Q'] = 16 | SHIFT, ['W'] = 17 | SHIFT, ['E'] = 18 | SHIFT, @@ -205,19 +181,6 @@ static const int curses2keycode[CURSES_KEYS] = { ['>'] = 52 | SHIFT, ['?'] = 53 | SHIFT, - [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ - [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ - [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ - [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ - [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ - [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ - [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ - [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ - [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ - [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ - [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ - [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ - ['Q' - '@'] = 16 | CNTRL, /* Control + q */ ['W' - '@'] = 17 | CNTRL, /* Control + w */ ['E' - '@'] = 18 | CNTRL, /* Control + e */ @@ -249,13 +212,67 @@ static const int curses2keycode[CURSES_KEYS] = { }; -static const int curses2qemu[CURSES_KEYS] = { +static const int _curseskey2keycode[CURSES_KEYS] = { [0 ... (CURSES_KEYS - 1)] = -1, + [KEY_BACKSPACE] = 14, /* Backspace */ + + [KEY_ENTER] = 28, /* Return */ + + [KEY_F(1)] = 59, /* Function Key 1 */ + [KEY_F(2)] = 60, /* Function Key 2 */ + [KEY_F(3)] = 61, /* Function Key 3 */ + [KEY_F(4)] = 62, /* Function Key 4 */ + [KEY_F(5)] = 63, /* Function Key 5 */ + [KEY_F(6)] = 64, /* Function Key 6 */ + [KEY_F(7)] = 65, /* Function Key 7 */ + [KEY_F(8)] = 66, /* Function Key 8 */ + [KEY_F(9)] = 67, /* Function Key 9 */ + [KEY_F(10)] = 68, /* Function Key 10 */ + [KEY_F(11)] = 87, /* Function Key 11 */ + [KEY_F(12)] = 88, /* Function Key 12 */ + + [KEY_HOME] = 71 | GREY, /* Home */ + [KEY_UP] = 72 | GREY, /* Up Arrow */ + [KEY_PPAGE] = 73 | GREY, /* Page Up */ + [KEY_LEFT] = 75 | GREY, /* Left Arrow */ + [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ + [KEY_END] = 79 | GREY, /* End */ + [KEY_DOWN] = 80 | GREY, /* Down Arrow */ + [KEY_NPAGE] = 81 | GREY, /* Page Down */ + [KEY_IC] = 82 | GREY, /* Insert */ + [KEY_DC] = 83 | GREY, /* Delete */ + + [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ + [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ + + [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ + + [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ + [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ + [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ + [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ + [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ + [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ + [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ + [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ + [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ + [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ + [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ + [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ +}; + +static const int _curses2qemu[CURSES_CHARS] = { + [0 ... (CURSES_CHARS - 1)] = -1, + ['\n'] = '\n', ['\r'] = '\n', [0x07f] = QEMU_KEY_BACKSPACE, +}; + +static const int _curseskey2qemu[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, [KEY_DOWN] = QEMU_KEY_DOWN, [KEY_UP] = QEMU_KEY_UP, ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 0/5] curses: wide character support @ 2016-06-22 22:23 Samuel Thibault 0 siblings, 0 replies; 15+ messages in thread From: Samuel Thibault @ 2016-06-22 22:23 UTC (permalink / raw) To: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt Cc: Samuel Thibault Hello, This patch series adds wide character support to the curses frontend of qemu, thus allowing to fix a lot of input and output issues with e.g. accented letters and semi-graphic glyphs. Since qemu can't know the encoding of the VGA font, the user has to specify it (just like he has to specify the keyboard layout with -k). I used option -f to make it simple for now, but I welcome any other idea :) Samuel Samuel Thibault (5): curses: fix left/right arrow translation curses: Use cursesw when available curses: use wide output functions curses: add option to specify VGA font encoding curses: support wide input configure | 101 +++++++++++- hw/display/vga.c | 4 +- include/sysemu/sysemu.h | 1 + include/ui/console.h | 19 ++- qemu-options.hx | 20 +++ ui/curses.c | 408 ++++++++++++++++++++++++++++++++++++++++++++---- ui/curses_keys.h | 113 ++++++++------ vl.c | 4 + 8 files changed, 589 insertions(+), 81 deletions(-) -- 2.8.1 ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2016-10-26 15:19 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-10-15 19:53 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw instead of curses Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault 2016-10-15 21:07 ` Paolo Bonzini 2016-10-25 23:16 ` Samuel Thibault 2016-10-15 19:53 ` [Qemu-devel] [PATCH 5/5] curses: support wide input Samuel Thibault 2016-10-25 22:26 ` [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault 2016-10-26 10:05 ` Gerd Hoffmann 2016-10-26 11:43 ` Samuel Thibault 2016-10-26 12:18 ` Gerd Hoffmann 2016-10-26 12:40 ` Gerd Hoffmann 2016-10-26 15:19 ` Samuel Thibault -- strict thread matches above, loose matches on Subject: below -- 2016-06-22 22:23 Samuel Thibault
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).