* [Qemu-devel] [PATCH 0/5] curses: wide character support
@ 2016-06-22 22:23 Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault
` (4 more replies)
0 siblings, 5 replies; 8+ 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] 8+ messages in thread
* [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
@ 2016-06-22 22:23 ` Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available Samuel Thibault
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ 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
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 49d3ce6..438b8be 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -374,10 +374,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.8.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault
@ 2016-06-22 22:23 ` Samuel Thibault
2016-06-23 7:29 ` Gerd Hoffmann
2016-06-22 22:23 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ 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
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
configure | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/configure b/configure
index 10cb212..ff10012 100755
--- a/configure
+++ b/configure
@@ -203,6 +203,7 @@ bluez=""
brlapi=""
curl=""
curses=""
+cursesw=""
docs=""
fdt=""
netmap="no"
@@ -978,6 +979,10 @@ for opt do
;;
--enable-curses) curses="yes"
;;
+ --disable-cursesw) cursesw="no"
+ ;;
+ --enable-cursesw) cursesw="yes"
+ ;;
--disable-curl) curl="no"
;;
--enable-curl) curl="yes"
@@ -1327,6 +1332,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
+ cursesw cursesw UI
vnc VNC UI support
vnc-sasl SASL encryption for VNC server
vnc-jpeg JPEG lossy compression for VNC server
@@ -2873,8 +2879,60 @@ EOF
fi
##########################################
+# cursesw probe
+if test "$cursesw" != "no" ; then
+ if test "$mingw32" = "yes" ; then
+ cursesw_inc_list="$($pkg_config --cflags ncursesw 2>/dev/null):"
+ cursesw_lib_list="$($pkg_config --libs ncursesw 2>/dev/null):-lpdcurses"
+ else
+ cursesw_inc_list="$($pkg_config --cflags ncursesw 2>/dev/null):"
+ cursesw_lib_list="$($pkg_config --libs ncursesw 2>/dev/null):-lncursesw:-lcursesw:-lncurses:-lcurses"
+ fi
+ cursesw_found=no
+ cat > $TMPC << EOF
+#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);
+ codeset = nl_langinfo(CODESET);
+ return s != 0 && codeset != 0;
+}
+EOF
+ IFS=:
+ for cursesw_inc in $cursesw_inc_list; do
+ for cursesw_lib in $cursesw_lib_list; do
+ unset IFS
+ if compile_prog "$cursesw_inc" "$cursesw_lib" ; then
+ cursesw_found=yes
+ QEMU_CFLAGS="$cursesw_inc $QEMU_CFLAGS"
+ libs_softmmu="$cursesw_lib $libs_softmmu"
+ break
+ fi
+ done
+ done
+ unset IFS
+ if test "$cursesw_found" = "yes" ; then
+ cursesw=yes
+ curses=yes
+ else
+ if test "$cursesw" = "yes" ; then
+ feature_not_found "cursesw" "Install ncursesw devel"
+ fi
+ cursesw=no
+ fi
+fi
+
+##########################################
# curses probe
-if test "$curses" != "no" ; then
+if test "$curses" != "no" -a "$cursesw" != "yes"; then
if test "$mingw32" = "yes" ; then
curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lpdcurses"
else
@@ -4800,6 +4858,7 @@ echo "nettle $nettle $(echo_version $nettle $nettle_version)"
echo "nettle kdf $nettle_kdf"
echo "libtasn1 $tasn1"
echo "curses support $curses"
+echo "cursesw support $cursesw"
echo "virgl support $virglrenderer"
echo "curl support $curl"
echo "mingw32 support $mingw32"
@@ -5058,6 +5117,9 @@ fi
if test "$curses" = "yes" ; then
echo "CONFIG_CURSES=y" >> $config_host_mak
fi
+if test "$cursesw" = "yes" ; then
+ echo "CONFIG_CURSESW=y" >> $config_host_mak
+fi
if test "$utimens" = "yes" ; then
echo "CONFIG_UTIMENSAT=y" >> $config_host_mak
fi
--
2.8.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 3/5] curses: use wide output functions
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available Samuel Thibault
@ 2016-06-22 22:23 ` Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 5/5] curses: support wide input Samuel Thibault
4 siblings, 0 replies; 8+ 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
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>
---
hw/display/vga.c | 4 +-
include/ui/console.h | 19 +++-
ui/curses.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 278 insertions(+), 15 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 9ebc54f..53d3c9a 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1968,7 +1968,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;
@@ -1977,7 +1977,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 52a5f65..2939176 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -336,8 +336,12 @@ static inline pixman_format_code_t surface_format(DisplaySurface *s)
#ifdef CONFIG_CURSES
#include <curses.h>
+#ifdef CONFIG_CURSESW
+typedef cchar_t console_ch_t;
+#else
typedef chtype console_ch_t;
-extern chtype vga_to_curses[];
+#endif
+extern console_ch_t vga_to_curses[];
#else
typedef unsigned long console_ch_t;
#endif
@@ -345,16 +349,27 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
{
uint8_t c = ch;
#ifdef CONFIG_CURSES
+#ifdef CONFIG_CURSESW
+ if (vga_to_curses[c].chars[0]) {
+ *dest = vga_to_curses[c];
+ } else {
+ dest->chars[0] = c;
+ dest->attr = 0;
+ }
+ dest->attr |= ch & ~0xff;
+#else
if (vga_to_curses[c]) {
ch &= ~(console_ch_t)0xff;
ch |= vga_to_curses[c];
}
+ *dest = ch;
+#endif
#else
if (c == '\0') {
ch |= ' ';
}
-#endif
*dest = ch;
+#endif
}
typedef struct GraphicHwOps {
diff --git a/ui/curses.c b/ui/curses.c
index 438b8be..9ef54b5 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -28,6 +28,11 @@
#include <sys/ioctl.h>
#include <termios.h>
#endif
+#ifdef CONFIG_CURSESW
+#include <locale.h>
+#include <wchar.h>
+#include <langinfo.h>
+#endif
#include "qemu-common.h"
#include "ui/console.h"
@@ -43,16 +48,25 @@ static WINDOW *screenpad = NULL;
static int width, height, gwidth, gheight, invalidate;
static int px, py, sminx, sminy, smaxx, smaxy;
+#ifdef CONFIG_CURSESW
+console_ch_t vga_to_curses[256];
+#else
chtype vga_to_curses[256];
+#endif
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)
+ line = ((console_ch_t *) screen) + y * width;
+ for (h += y; y < h; y ++, line += width) {
+#ifdef CONFIG_CURSESW
+ mvwadd_wchnstr(screenpad, y, 0, line, width);
+#else
mvwaddchnstr(screenpad, y, 0, line, width);
+#endif
+ }
pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
refresh();
@@ -362,15 +376,245 @@ 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
+
+#ifdef CONFIG_CURSESW
+ 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++)
+ {
+ if (vga_to_curses[i].chars[0] == L'\u00a3')
+ vga_to_curses[i] = *WACS_STERLING;
+ if (vga_to_curses[i].chars[0] == L'\u2591')
+ vga_to_curses[i] = *WACS_BOARD;
+ if (vga_to_curses[i].chars[0] == L'\u2592')
+ vga_to_curses[i] = *WACS_CKBOARD;
+ if (vga_to_curses[i].chars[0] == L'\u2502')
+ vga_to_curses[i] = *WACS_VLINE;
+ if (vga_to_curses[i].chars[0] == L'\u2524')
+ vga_to_curses[i] = *WACS_RTEE;
+ if (vga_to_curses[i].chars[0] == L'\u2510')
+ vga_to_curses[i] = *WACS_URCORNER;
+ if (vga_to_curses[i].chars[0] == L'\u2514')
+ vga_to_curses[i] = *WACS_LLCORNER;
+ if (vga_to_curses[i].chars[0] == L'\u2534')
+ vga_to_curses[i] = *WACS_BTEE;
+ if (vga_to_curses[i].chars[0] == L'\u252c')
+ vga_to_curses[i] = *WACS_TTEE;
+ if (vga_to_curses[i].chars[0] == L'\u251c')
+ vga_to_curses[i] = *WACS_LTEE;
+ if (vga_to_curses[i].chars[0] == L'\u2500')
+ vga_to_curses[i] = *WACS_HLINE;
+ if (vga_to_curses[i].chars[0] == L'\u253c')
+ vga_to_curses[i] = *WACS_PLUS;
+ if (vga_to_curses[i].chars[0] == L'\u256c')
+ vga_to_curses[i] = *WACS_LANTERN;
+ if (vga_to_curses[i].chars[0] == L'\u256a')
+ vga_to_curses[i] = *WACS_NEQUAL;
+ if (vga_to_curses[i].chars[0] == L'\u2518')
+ vga_to_curses[i] = *WACS_LRCORNER;
+ if (vga_to_curses[i].chars[0] == L'\u250c')
+ vga_to_curses[i] = *WACS_ULCORNER;
+ if (vga_to_curses[i].chars[0] == L'\u2588')
+ vga_to_curses[i] = *WACS_BLOCK;
+ if (vga_to_curses[i].chars[0] == L'\u03c0')
+ vga_to_curses[i] = *WACS_PI;
+ if (vga_to_curses[i].chars[0] == L'\u00b1')
+ vga_to_curses[i] = *WACS_PLMINUS;
+ if (vga_to_curses[i].chars[0] == L'\u2265')
+ vga_to_curses[i] = *WACS_GEQUAL;
+ if (vga_to_curses[i].chars[0] == L'\u2264')
+ vga_to_curses[i] = *WACS_LEQUAL;
+ if (vga_to_curses[i].chars[0] == L'\u00b0')
+ vga_to_curses[i] = *WACS_DEGREE;
+ if (vga_to_curses[i].chars[0] == L'\u25a0')
+ vga_to_curses[i] = *WACS_BULLET;
+ if (vga_to_curses[i].chars[0] == L'\u2666')
+ vga_to_curses[i] = *WACS_DIAMOND;
+ if (vga_to_curses[i].chars[0] == L'\u2192')
+ vga_to_curses[i] = *WACS_RARROW;
+ if (vga_to_curses[i].chars[0] == L'\u2190')
+ vga_to_curses[i] = *WACS_LARROW;
+ if (vga_to_curses[i].chars[0] == L'\u2191')
+ vga_to_curses[i] = *WACS_UARROW;
+ if (vga_to_curses[i].chars[0] == L'\u2193')
+ vga_to_curses[i] = *WACS_DARROW;
+ if (vga_to_curses[i].chars[0] == L'\u23ba')
+ vga_to_curses[i] = *WACS_S1;
+ if (vga_to_curses[i].chars[0] == L'\u23bb')
+ vga_to_curses[i] = *WACS_S3;
+ if (vga_to_curses[i].chars[0] == L'\u23bc')
+ vga_to_curses[i] = *WACS_S7;
+ if (vga_to_curses[i].chars[0] == L'\u23bd')
+ vga_to_curses[i] = *WACS_S9;
+ }
+ }
+#else
+ /* No wide char support, hardcode ASCII + termcap-portable CP437 */
/* ACS_* is not constant. So, we can't initialize statically. */
vga_to_curses['\0'] = ' ';
vga_to_curses[0x04] = ACS_DIAMOND;
@@ -401,6 +645,7 @@ static void curses_setup(void)
vga_to_curses[0xf3] = ACS_LEQUAL;
vga_to_curses[0xf8] = ACS_DEGREE;
vga_to_curses[0xfe] = ACS_BULLET;
+#endif
}
static void curses_keyboard_setup(void)
@@ -434,6 +679,9 @@ void curses_display_init(DisplayState *ds, int full_screen)
}
#endif
+#ifdef CONFIG_CURSESW
+ setlocale(LC_CTYPE, "");
+#endif
curses_setup();
curses_keyboard_setup();
atexit(curses_atexit);
--
2.8.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
` (2 preceding siblings ...)
2016-06-22 22:23 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault
@ 2016-06-22 22:23 ` Samuel Thibault
2016-06-23 7:34 ` Markus Armbruster
2016-06-22 22:23 ` [Qemu-devel] [PATCH 5/5] curses: support wide input Samuel Thibault
4 siblings, 1 reply; 8+ 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
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 | 20 ++++++++++++++++++++
ui/curses.c | 40 ++++++++++++++++++++++++++++++++++++++++
vl.c | 4 ++++
5 files changed, 102 insertions(+)
diff --git a/configure b/configure
index ff10012..14e98f5 100755
--- a/configure
+++ b/configure
@@ -204,6 +204,7 @@ brlapi=""
curl=""
curses=""
cursesw=""
+iconv=""
docs=""
fdt=""
netmap="no"
@@ -983,6 +984,10 @@ for opt do
;;
--enable-cursesw) cursesw="yes"
;;
+ --disable-iconv) iconv="no"
+ ;;
+ --enable-iconv) iconv="yes"
+ ;;
--disable-curl) curl="no"
;;
--enable-curl) curl="yes"
@@ -1333,6 +1338,7 @@ disabled with --disable-FEATURE, default is enabled if available:
vte vte support for the gtk UI
curses curses UI
cursesw cursesw 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
@@ -2968,6 +2974,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
@@ -4859,6 +4892,7 @@ echo "nettle kdf $nettle_kdf"
echo "libtasn1 $tasn1"
echo "curses support $curses"
echo "cursesw support $cursesw"
+echo "iconv support $iconv"
echo "virgl support $virglrenderer"
echo "curl support $curl"
echo "mingw32 support $mingw32"
@@ -5120,6 +5154,9 @@ fi
if test "$cursesw" = "yes" ; then
echo "CONFIG_CURSESW=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 7313673..a690c18 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -147,6 +147,7 @@ extern int graphic_height;
extern int graphic_depth;
extern int display_opengl;
extern const char *keyboard_layout;
+extern const char *font_encoding;
extern int win2k_install_hack;
extern int alt_grab;
extern int ctrl_grab;
diff --git a/qemu-options.hx b/qemu-options.hx
index ce535a9..2187886 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -321,6 +321,26 @@ The default is @code{en-us}.
ETEXI
+DEF("f", HAS_ARG, QEMU_OPTION_f,
+ "-f encoding use font encoding (for example 'CP850' for IBM CP850 encoding)\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -h @var{encoding}
+@findex -h
+Use font encoding @var{encoding} (for example @code{CP850} for
+IBM CP/850 encoding). This option is only needed where output is text-only, i.e.
+with the curses display, to convert from text-mode output from the guest to
+proper text glyphs.
+
+The available encoding are provided by the libc, the full list can be obtained by
+@example
+iconv -l
+@end example
+
+The default is @code{CP437}.
+ETEXI
+
+
DEF("audio-help", 0, QEMU_OPTION_audio_help,
"-audio-help print list of audio drivers and their options\n",
QEMU_ARCH_ALL)
diff --git a/ui/curses.c b/ui/curses.c
index 9ef54b5..a8dada9 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -33,6 +33,9 @@
#include <wchar.h>
#include <langinfo.h>
#endif
+#ifdef CONFIG_ICONV
+#include <iconv.h>
+#endif
#include "qemu-common.h"
#include "ui/console.h"
@@ -412,6 +415,43 @@ 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_encoding) {
+ unsigned char ch;
+ wchar_t wch;
+ char *pch, *pwch;
+ size_t sch, swch;
+ iconv_t conv;
+
+ conv = iconv_open("WCHAR_T", font_encoding);
+ if (conv == (iconv_t) -1) {
+ fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n", font_encoding, 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_encoding, strerror(errno));
+ } else {
+ vga_to_curses[ch].chars[0] = wch;
+ }
+ }
+ } else
+#else
+ if (font_encoding) {
+ if (strcmp(font_encoding, "CP437"))
+ {
+ fprintf(stderr,"iconv support not enabled for converting from %s, only CP437 supported\n", font_encoding);
+ exit(1);
+ }
+ }
+#endif
{
/* Hardcode CP437 to unicode */
vga_to_curses[0x80].chars[0] = L'\u00C7';
diff --git a/vl.c b/vl.c
index 2f63eb4..508a59f 100644
--- a/vl.c
+++ b/vl.c
@@ -132,6 +132,7 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
int request_opengl = -1;
int display_opengl;
const char* keyboard_layout = NULL;
+const char* font_encoding = NULL;
ram_addr_t ram_size;
const char *mem_path = NULL;
int mem_prealloc = 0; /* force preallocation of physical target memory */
@@ -3370,6 +3371,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_k:
keyboard_layout = optarg;
break;
+ case QEMU_OPTION_f:
+ font_encoding = optarg;
+ break;
case QEMU_OPTION_localtime:
rtc_utc = 0;
break;
--
2.8.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 5/5] curses: support wide input
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
` (3 preceding siblings ...)
2016-06-22 22:23 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault
@ 2016-06-22 22:23 ` Samuel Thibault
4 siblings, 0 replies; 8+ 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
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 | 96 ++++++++++++++++++++++++++++++++++++++--------
ui/curses_keys.h | 113 ++++++++++++++++++++++++++++++++-----------------------
2 files changed, 145 insertions(+), 64 deletions(-)
diff --git a/ui/curses.c b/ui/curses.c
index a8dada9..c282677 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -45,6 +45,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;
@@ -57,6 +63,36 @@ console_ch_t vga_to_curses[256];
chtype vga_to_curses[256];
#endif
+#ifdef CONFIG_CURSESW
+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;
+}
+#else
+static int console_getch(int *maybe_keycode)
+{
+ int ret;
+ *maybe_keycode = CURSES_CHAR_OR_KEYCODE;
+ ret = getch();
+ if (ret == ERR)
+ return -1;
+ else
+ return ret;
+}
+#endif
+
static void curses_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
@@ -196,9 +232,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, nextchr, keysym, keycode, keycode_alt;
+ int maybe_keycode, next_maybe_keycode;
curses_winch_check();
@@ -212,22 +276,23 @@ static void curses_refresh(DisplayChangeListener *dcl)
graphic_hw_text_update(NULL, screen);
- nextchr = ERR;
+ nextchr = -1;
while (1) {
/* while there are any pending key strokes to process */
- if (nextchr == ERR)
- chr = getch();
- else {
+ if (nextchr == -1) {
+ chr = console_getch(&maybe_keycode);
+ } else {
chr = nextchr;
- nextchr = ERR;
+ maybe_keycode = next_maybe_keycode;
+ nextchr = -1;
}
- 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();
@@ -236,18 +301,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) {
- nextchr = getch();
+ nextchr = console_getch(&next_maybe_keycode);
- if (nextchr != ERR) {
+ if (nextchr != -1) {
chr = nextchr;
+ maybe_keycode = next_maybe_keycode;
keycode_alt = ALT;
- keycode = curses2keycode[nextchr];
- nextchr = ERR;
+ keycode = curses2keycode(chr, maybe_keycode);
+ nextchr = -1;
if (keycode != -1) {
keycode |= ALT;
@@ -267,9 +333,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 < ' ') {
@@ -334,7 +398,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
qemu_input_event_send_key_delay(0);
}
} else {
- 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 f746744..c9f025c 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.8.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available
2016-06-22 22:23 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available Samuel Thibault
@ 2016-06-23 7:29 ` Gerd Hoffmann
0 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2016-06-23 7:29 UTC (permalink / raw)
To: Samuel Thibault; +Cc: qemu-devel, pbonzini, berrange, peter.maydell, mjt
Hi,
> ##########################################
> +# cursesw probe
> +if test "$cursesw" != "no" ; then
> + if test "$mingw32" = "yes" ; then
> + cursesw_inc_list="$($pkg_config --cflags ncursesw 2>/dev/null):"
> + cursesw_lib_list="$($pkg_config --libs ncursesw 2>/dev/null):-lpdcurses"
> + else
> + cursesw_inc_list="$($pkg_config --cflags ncursesw 2>/dev/null):"
> + cursesw_lib_list="$($pkg_config --libs ncursesw 2>/dev/null):-lncursesw:-lcursesw:-lncurses:-lcurses"
> + fi
> [ ... ]
Do we *really* want this mess?
Is there any curses implementation without wide char support which is
still relevant today?
Is there any curses implementation beside ncurses still relevant today?
/me boots the freebsd guest.
/me finds libcurses being symlinks to libncurses.
I'm tempted to say just require ncursesw and be done with it.
That will also avoid the #ifdef mess in the following patches.
cheers,
Gerd
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding
2016-06-22 22:23 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault
@ 2016-06-23 7:34 ` Markus Armbruster
0 siblings, 0 replies; 8+ messages in thread
From: Markus Armbruster @ 2016-06-23 7:34 UTC (permalink / raw)
To: Samuel Thibault
Cc: qemu-devel, kraxel, pbonzini, berrange, peter.maydell, mjt
Samuel Thibault <samuel.thibault@ens-lyon.org> writes:
> 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>
[...]
> diff --git a/qemu-options.hx b/qemu-options.hx
> index ce535a9..2187886 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -321,6 +321,26 @@ The default is @code{en-us}.
> ETEXI
>
>
> +DEF("f", HAS_ARG, QEMU_OPTION_f,
> + "-f encoding use font encoding (for example 'CP850' for IBM CP850 encoding)\n",
> + QEMU_ARCH_ALL)
> +STEXI
> +@item -h @var{encoding}
> +@findex -h
> +Use font encoding @var{encoding} (for example @code{CP850} for
> +IBM CP/850 encoding). This option is only needed where output is text-only, i.e.
> +with the curses display, to convert from text-mode output from the guest to
> +proper text glyphs.
> +
> +The available encoding are provided by the libc, the full list can be obtained by
> +@example
> +iconv -l
> +@end example
> +
> +The default is @code{CP437}.
> +ETEXI
> +
> +
Since this option applies only to the curses display, it should be a
-display curses parameter, like this: -display curses,charset=CP850.
> DEF("audio-help", 0, QEMU_OPTION_audio_help,
> "-audio-help print list of audio drivers and their options\n",
> QEMU_ARCH_ALL)
[...]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-06-23 7:34 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-06-22 22:23 [Qemu-devel] [PATCH 0/5] curses: wide character support Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 1/5] curses: fix left/right arrow translation Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 2/5] curses: Use cursesw when available Samuel Thibault
2016-06-23 7:29 ` Gerd Hoffmann
2016-06-22 22:23 ` [Qemu-devel] [PATCH 3/5] curses: use wide output functions Samuel Thibault
2016-06-22 22:23 ` [Qemu-devel] [PATCH 4/5] curses: add option to specify VGA font encoding Samuel Thibault
2016-06-23 7:34 ` Markus Armbruster
2016-06-22 22:23 ` [Qemu-devel] [PATCH 5/5] curses: support wide input 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).