qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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
(curses with wide support), or possibly both (curses without 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>
Message-id: 20190304210532.7840-1-samuel.thibault@ens-lyon.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

authored by

Samuel Thibault and committed by
Gerd Hoffmann
459a707e 633786fe

+127 -62
+62 -14
ui/curses.c
··· 42 42 #define FONT_HEIGHT 16 43 43 #define FONT_WIDTH 8 44 44 45 + enum maybe_keycode { 46 + CURSES_KEYCODE, 47 + CURSES_CHAR, 48 + CURSES_CHAR_OR_KEYCODE, 49 + }; 50 + 45 51 static DisplayChangeListener *dcl; 46 52 static console_ch_t screen[160 * 100]; 47 53 static WINDOW *screenpad = NULL; ··· 194 200 195 201 static kbd_layout_t *kbd_layout = NULL; 196 202 203 + static wint_t console_getch(enum maybe_keycode *maybe_keycode) 204 + { 205 + wint_t ret; 206 + switch (get_wch(&ret)) { 207 + case KEY_CODE_YES: 208 + *maybe_keycode = CURSES_KEYCODE; 209 + break; 210 + case OK: 211 + *maybe_keycode = CURSES_CHAR; 212 + break; 213 + case ERR: 214 + ret = -1; 215 + break; 216 + } 217 + return ret; 218 + } 219 + 220 + static int curses2foo(const int _curses2foo[], const int _curseskey2foo[], 221 + int chr, enum maybe_keycode maybe_keycode) 222 + { 223 + int ret = -1; 224 + if (maybe_keycode == CURSES_CHAR) { 225 + if (chr < CURSES_CHARS) { 226 + ret = _curses2foo[chr]; 227 + } 228 + } else { 229 + if (chr < CURSES_KEYS) { 230 + ret = _curseskey2foo[chr]; 231 + } 232 + if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE && 233 + chr < CURSES_CHARS) { 234 + ret = _curses2foo[chr]; 235 + } 236 + } 237 + return ret; 238 + } 239 + 240 + #define curses2keycode(chr, maybe_keycode) \ 241 + curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode) 242 + #define curses2keysym(chr, maybe_keycode) \ 243 + curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode) 244 + #define curses2qemu(chr, maybe_keycode) \ 245 + curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode) 246 + 197 247 static void curses_refresh(DisplayChangeListener *dcl) 198 248 { 199 249 int chr, keysym, keycode, keycode_alt; 250 + enum maybe_keycode maybe_keycode; 200 251 201 252 curses_winch_check(); 202 253 ··· 212 263 213 264 while (1) { 214 265 /* while there are any pending key strokes to process */ 215 - chr = getch(); 266 + chr = console_getch(&maybe_keycode); 216 267 217 - if (chr == ERR) 268 + if (chr == -1) 218 269 break; 219 270 220 271 #ifdef KEY_RESIZE 221 272 /* this shouldn't occur when we use a custom SIGWINCH handler */ 222 - if (chr == KEY_RESIZE) { 273 + if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) { 223 274 clear(); 224 275 refresh(); 225 276 curses_calc_pad(); ··· 228 279 } 229 280 #endif 230 281 231 - keycode = curses2keycode[chr]; 282 + keycode = curses2keycode(chr, maybe_keycode); 232 283 keycode_alt = 0; 233 284 234 285 /* alt or esc key */ 235 286 if (keycode == 1) { 236 - int nextchr = getch(); 287 + enum maybe_keycode next_maybe_keycode; 288 + int nextchr = console_getch(&next_maybe_keycode); 237 289 238 - if (nextchr != ERR) { 290 + if (nextchr != -1) { 239 291 chr = nextchr; 292 + maybe_keycode = next_maybe_keycode; 240 293 keycode_alt = ALT; 241 - keycode = curses2keycode[chr]; 294 + keycode = curses2keycode(chr, maybe_keycode); 242 295 243 296 if (keycode != -1) { 244 297 keycode |= ALT; ··· 258 311 } 259 312 260 313 if (kbd_layout) { 261 - keysym = -1; 262 - if (chr < CURSES_KEYS) 263 - keysym = curses2keysym[chr]; 314 + keysym = curses2keysym(chr, maybe_keycode); 264 315 265 316 if (keysym == -1) { 266 317 if (chr < ' ') { ··· 326 377 qemu_input_event_send_key_delay(0); 327 378 } 328 379 } else { 329 - keysym = -1; 330 - if (chr < CURSES_KEYS) { 331 - keysym = curses2qemu[chr]; 332 - } 380 + keysym = curses2qemu(chr, maybe_keycode); 333 381 if (keysym == -1) 334 382 keysym = chr; 335 383
+65 -48
ui/curses_keys.h
··· 49 49 /* curses won't detect a Control + Alt + 1, so use Alt + 1 */ 50 50 #define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ 51 51 52 + #define CURSES_CHARS 0x100 /* Support latin1 only */ 52 53 #define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */ 53 54 54 - static const int curses2keysym[CURSES_KEYS] = { 55 - [0 ... (CURSES_KEYS - 1)] = -1, 55 + static const int _curses2keysym[CURSES_CHARS] = { 56 + [0 ... (CURSES_CHARS - 1)] = -1, 56 57 57 58 [0x7f] = KEY_BACKSPACE, 58 59 ['\r'] = KEY_ENTER, 59 60 ['\n'] = KEY_ENTER, 60 61 [27] = 27, 62 + }; 63 + 64 + static const int _curseskey2keysym[CURSES_KEYS] = { 65 + [0 ... (CURSES_KEYS - 1)] = -1, 66 + 61 67 [KEY_BTAB] = '\t' | KEYSYM_SHIFT, 62 68 [KEY_SPREVIOUS] = KEY_PPAGE | KEYSYM_SHIFT, 63 69 [KEY_SNEXT] = KEY_NPAGE | KEYSYM_SHIFT, 64 70 }; 65 71 66 - static const int curses2keycode[CURSES_KEYS] = { 67 - [0 ... (CURSES_KEYS - 1)] = -1, 72 + static const int _curses2keycode[CURSES_CHARS] = { 73 + [0 ... (CURSES_CHARS - 1)] = -1, 68 74 69 75 [0x01b] = 1, /* Escape */ 70 76 ['1'] = 2, ··· 80 86 ['-'] = 12, 81 87 ['='] = 13, 82 88 [0x07f] = 14, /* Backspace */ 83 - [KEY_BACKSPACE] = 14, /* Backspace */ 84 89 85 90 ['\t'] = 15, /* Tab */ 86 91 ['q'] = 16, ··· 97 102 [']'] = 27, 98 103 ['\n'] = 28, /* Return */ 99 104 ['\r'] = 28, /* Return */ 100 - [KEY_ENTER] = 28, /* Return */ 101 105 102 106 ['a'] = 30, 103 107 ['s'] = 31, ··· 126 130 127 131 [' '] = 57, 128 132 129 - [KEY_F(1)] = 59, /* Function Key 1 */ 130 - [KEY_F(2)] = 60, /* Function Key 2 */ 131 - [KEY_F(3)] = 61, /* Function Key 3 */ 132 - [KEY_F(4)] = 62, /* Function Key 4 */ 133 - [KEY_F(5)] = 63, /* Function Key 5 */ 134 - [KEY_F(6)] = 64, /* Function Key 6 */ 135 - [KEY_F(7)] = 65, /* Function Key 7 */ 136 - [KEY_F(8)] = 66, /* Function Key 8 */ 137 - [KEY_F(9)] = 67, /* Function Key 9 */ 138 - [KEY_F(10)] = 68, /* Function Key 10 */ 139 - [KEY_F(11)] = 87, /* Function Key 11 */ 140 - [KEY_F(12)] = 88, /* Function Key 12 */ 141 - 142 - [KEY_HOME] = 71 | GREY, /* Home */ 143 - [KEY_UP] = 72 | GREY, /* Up Arrow */ 144 - [KEY_PPAGE] = 73 | GREY, /* Page Up */ 145 - [KEY_LEFT] = 75 | GREY, /* Left Arrow */ 146 - [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ 147 - [KEY_END] = 79 | GREY, /* End */ 148 - [KEY_DOWN] = 80 | GREY, /* Down Arrow */ 149 - [KEY_NPAGE] = 81 | GREY, /* Page Down */ 150 - [KEY_IC] = 82 | GREY, /* Insert */ 151 - [KEY_DC] = 83 | GREY, /* Delete */ 152 - 153 - [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ 154 - [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ 155 - 156 133 ['!'] = 2 | SHIFT, 157 134 ['@'] = 3 | SHIFT, 158 135 ['#'] = 4 | SHIFT, ··· 166 143 ['_'] = 12 | SHIFT, 167 144 ['+'] = 13 | SHIFT, 168 145 169 - [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ 170 146 ['Q'] = 16 | SHIFT, 171 147 ['W'] = 17 | SHIFT, 172 148 ['E'] = 18 | SHIFT, ··· 204 180 ['<'] = 51 | SHIFT, 205 181 ['>'] = 52 | SHIFT, 206 182 ['?'] = 53 | SHIFT, 207 - 208 - [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ 209 - [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ 210 - [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ 211 - [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ 212 - [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ 213 - [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ 214 - [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ 215 - [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ 216 - [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ 217 - [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ 218 - [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ 219 - [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ 220 183 221 184 ['Q' - '@'] = 16 | CNTRL, /* Control + q */ 222 185 ['W' - '@'] = 17 | CNTRL, /* Control + w */ ··· 249 212 250 213 }; 251 214 252 - static const int curses2qemu[CURSES_KEYS] = { 215 + static const int _curseskey2keycode[CURSES_KEYS] = { 253 216 [0 ... (CURSES_KEYS - 1)] = -1, 254 217 218 + [KEY_BACKSPACE] = 14, /* Backspace */ 219 + 220 + [KEY_ENTER] = 28, /* Return */ 221 + 222 + [KEY_F(1)] = 59, /* Function Key 1 */ 223 + [KEY_F(2)] = 60, /* Function Key 2 */ 224 + [KEY_F(3)] = 61, /* Function Key 3 */ 225 + [KEY_F(4)] = 62, /* Function Key 4 */ 226 + [KEY_F(5)] = 63, /* Function Key 5 */ 227 + [KEY_F(6)] = 64, /* Function Key 6 */ 228 + [KEY_F(7)] = 65, /* Function Key 7 */ 229 + [KEY_F(8)] = 66, /* Function Key 8 */ 230 + [KEY_F(9)] = 67, /* Function Key 9 */ 231 + [KEY_F(10)] = 68, /* Function Key 10 */ 232 + [KEY_F(11)] = 87, /* Function Key 11 */ 233 + [KEY_F(12)] = 88, /* Function Key 12 */ 234 + 235 + [KEY_HOME] = 71 | GREY, /* Home */ 236 + [KEY_UP] = 72 | GREY, /* Up Arrow */ 237 + [KEY_PPAGE] = 73 | GREY, /* Page Up */ 238 + [KEY_LEFT] = 75 | GREY, /* Left Arrow */ 239 + [KEY_RIGHT] = 77 | GREY, /* Right Arrow */ 240 + [KEY_END] = 79 | GREY, /* End */ 241 + [KEY_DOWN] = 80 | GREY, /* Down Arrow */ 242 + [KEY_NPAGE] = 81 | GREY, /* Page Down */ 243 + [KEY_IC] = 82 | GREY, /* Insert */ 244 + [KEY_DC] = 83 | GREY, /* Delete */ 245 + 246 + [KEY_SPREVIOUS] = 73 | GREY | SHIFT, /* Shift + Page Up */ 247 + [KEY_SNEXT] = 81 | GREY | SHIFT, /* Shift + Page Down */ 248 + 249 + [KEY_BTAB] = 15 | SHIFT, /* Shift + Tab */ 250 + 251 + [KEY_F(13)] = 59 | SHIFT, /* Shift + Function Key 1 */ 252 + [KEY_F(14)] = 60 | SHIFT, /* Shift + Function Key 2 */ 253 + [KEY_F(15)] = 61 | SHIFT, /* Shift + Function Key 3 */ 254 + [KEY_F(16)] = 62 | SHIFT, /* Shift + Function Key 4 */ 255 + [KEY_F(17)] = 63 | SHIFT, /* Shift + Function Key 5 */ 256 + [KEY_F(18)] = 64 | SHIFT, /* Shift + Function Key 6 */ 257 + [KEY_F(19)] = 65 | SHIFT, /* Shift + Function Key 7 */ 258 + [KEY_F(20)] = 66 | SHIFT, /* Shift + Function Key 8 */ 259 + [KEY_F(21)] = 67 | SHIFT, /* Shift + Function Key 9 */ 260 + [KEY_F(22)] = 68 | SHIFT, /* Shift + Function Key 10 */ 261 + [KEY_F(23)] = 69 | SHIFT, /* Shift + Function Key 11 */ 262 + [KEY_F(24)] = 70 | SHIFT, /* Shift + Function Key 12 */ 263 + }; 264 + 265 + static const int _curses2qemu[CURSES_CHARS] = { 266 + [0 ... (CURSES_CHARS - 1)] = -1, 267 + 255 268 ['\n'] = '\n', 256 269 ['\r'] = '\n', 257 270 258 271 [0x07f] = QEMU_KEY_BACKSPACE, 272 + }; 273 + 274 + static const int _curseskey2qemu[CURSES_KEYS] = { 275 + [0 ... (CURSES_KEYS - 1)] = -1, 259 276 260 277 [KEY_DOWN] = QEMU_KEY_DOWN, 261 278 [KEY_UP] = QEMU_KEY_UP,