From: Samuel Thibault <samuel.thibault@gnu.org>
To: Gerd Hoffmann <kraxel@redhat.com>
Cc: qemu-devel@nongnu.org, pbonzini@redhat.com, berrange@redhat.com,
peter.maydell@linaro.org, mjt@tls.msk.ru
Subject: Re: [Qemu-devel] [PATCH 0/5] curses: wide character support
Date: Wed, 26 Oct 2016 17:19:07 +0200 [thread overview]
Message-ID: <20161026151907.GR2811@var.bordeaux.inria.fr> (raw)
In-Reply-To: <1477485626.18984.52.camel@redhat.com>
[-- 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,
next prev parent reply other threads:[~2016-10-26 15:19 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
-- strict thread matches above, loose matches on Subject: below --
2016-06-22 22:23 Samuel Thibault
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161026151907.GR2811@var.bordeaux.inria.fr \
--to=samuel.thibault@gnu.org \
--cc=berrange@redhat.com \
--cc=kraxel@redhat.com \
--cc=mjt@tls.msk.ru \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).