From 80c9aab9b46cfa70972e031bd5566e48f7b7ce8e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 17 Feb 2012 11:21:13 +0100 Subject: [PATCH 3/4] Fix curses interaction with keymaps RH-Author: Gerd Hoffmann Message-id: <1329477674-2422-2-git-send-email-kraxel@redhat.com> Patchwork-id: 37411 O-Subject: [RHEL-6.3 qemu-kvm PATCH 1/2] Fix curses interaction with keymaps Bugzilla: 785963 RH-Acked-by: Alex Williamson RH-Acked-by: Paolo Bonzini RH-Acked-by: Laszlo Ersek RH-Acked-by: Amos Kong The combination of keymap support (-k option) and curses is currently very broken. The patch below fixes it by first extending keymap support to interpret the shift, ctrl, altgr and addupper keywords in keymaps, and to fix curses into properly using keymaps. Signed-off-by: Aurelien Jarno Signed-off-by: Samuel Thibault (cherry picked from commit 44bb61c8d9ad5fa0045465933b1ac8f2b1b98762) Conflicts: curses_keys.h --- curses.c | 89 ++++++++++++++++++++++++++-------------------------- curses_keys.h | 96 ++++++++++++++++++++++++++++++++++---------------------- keymaps.c | 60 +++++++++++++++++++++++------------ keymaps.h | 17 ++++++++++ sdl.c | 20 ++++++------ vnc.c | 25 +++++++++------ 6 files changed, 183 insertions(+), 124 deletions(-) Signed-off-by: Michal Novotny --- curses.c | 89 ++++++++++++++++++++++++++-------------------------- curses_keys.h | 96 ++++++++++++++++++++++++++++++++++---------------------- keymaps.c | 60 +++++++++++++++++++++++------------ keymaps.h | 17 ++++++++++ sdl.c | 20 ++++++------ vnc.c | 25 +++++++++------ 6 files changed, 183 insertions(+), 124 deletions(-) diff --git a/curses.c b/curses.c index 3ce12b9..4b5beac 100644 --- a/curses.c +++ b/curses.c @@ -159,11 +159,10 @@ static void curses_cursor_position(DisplayState *ds, int x, int y) #include "curses_keys.h" static kbd_layout_t *kbd_layout = NULL; -static int keycode2keysym[CURSES_KEYS]; static void curses_refresh(DisplayState *ds) { - int chr, nextchr, keysym, keycode; + int chr, nextchr, keysym, keycode, keycode_alt; if (invalidate) { clear(); @@ -204,43 +203,58 @@ static void curses_refresh(DisplayState *ds) #endif keycode = curses2keycode[chr]; - if (keycode == -1) - continue; + keycode_alt = 0; /* alt key */ if (keycode == 1) { nextchr = getch(); if (nextchr != ERR) { + chr = nextchr; + keycode_alt = ALT; keycode = curses2keycode[nextchr]; nextchr = ERR; - if (keycode == -1) - continue; - keycode |= ALT; + if (keycode != -1) { + keycode |= ALT; - /* process keys reserved for qemu */ - if (keycode >= QEMU_KEY_CONSOLE0 && - keycode < QEMU_KEY_CONSOLE0 + 9) { - erase(); - wnoutrefresh(stdscr); - console_select(keycode - QEMU_KEY_CONSOLE0); + /* process keys reserved for qemu */ + if (keycode >= QEMU_KEY_CONSOLE0 && + keycode < QEMU_KEY_CONSOLE0 + 9) { + erase(); + wnoutrefresh(stdscr); + console_select(keycode - QEMU_KEY_CONSOLE0); - invalidate = 1; - continue; + invalidate = 1; + continue; + } } } } - if (kbd_layout && !(keycode & GREY)) { - keysym = keycode2keysym[keycode & KEY_MASK]; - if (keysym == -1) - keysym = chr; + if (kbd_layout) { + keysym = -1; + if (chr < CURSES_KEYS) + keysym = curses2keysym[chr]; + + if (keysym == -1) { + if (chr < ' ') + keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL; + else + keysym = chr; + } - keycode &= ~KEY_MASK; - keycode |= keysym2scancode(kbd_layout, keysym); + keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK); + if (keycode == 0) + continue; + + keycode |= (keysym & ~KEYSYM_MASK) >> 16; + keycode |= keycode_alt; } + if (keycode == -1) + continue; + if (is_graphic_console()) { /* since terminals don't know about key press and release * events, we need to emit both for each key received */ @@ -250,12 +264,20 @@ static void curses_refresh(DisplayState *ds) kbd_put_keycode(CNTRL_CODE); if (keycode & ALT) kbd_put_keycode(ALT_CODE); + if (keycode & ALTGR) { + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(ALT_CODE); + } if (keycode & GREY) kbd_put_keycode(GREY_CODE); kbd_put_keycode(keycode & KEY_MASK); if (keycode & GREY) kbd_put_keycode(GREY_CODE); kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); + if (keycode & ALTGR) { + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(ALT_CODE | KEY_RELEASE); + } if (keycode & ALT) kbd_put_keycode(ALT_CODE | KEY_RELEASE); if (keycode & CNTRL) @@ -263,7 +285,7 @@ static void curses_refresh(DisplayState *ds) if (keycode & SHIFT) kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); } else { - keysym = curses2keysym[chr]; + keysym = curses2qemu[chr]; if (keysym == -1) keysym = chr; @@ -301,8 +323,6 @@ static void curses_setup(void) static void curses_keyboard_setup(void) { - int i, keycode, keysym; - #if defined(__APPLE__) /* always use generic keymaps */ if (!keyboard_layout) @@ -313,27 +333,6 @@ static void curses_keyboard_setup(void) if (!kbd_layout) exit(1); } - - for (i = 0; i < CURSES_KEYS; i ++) - keycode2keysym[i] = -1; - - for (i = 0; i < CURSES_KEYS; i ++) { - if (curses2keycode[i] == -1) - continue; - - keycode = curses2keycode[i] & KEY_MASK; - if (keycode2keysym[keycode] >= 0) - continue; - - for (keysym = 0; keysym < CURSES_KEYS; keysym ++) - if (curses2keycode[keysym] == keycode) { - keycode2keysym[keycode] = keysym; - break; - } - - if (keysym >= CURSES_KEYS) - keycode2keysym[keycode] = i; - } } void curses_display_init(DisplayState *ds, int full_screen) diff --git a/curses_keys.h b/curses_keys.h index a6e41cf..819e5d8 100644 --- a/curses_keys.h +++ b/curses_keys.h @@ -27,20 +27,36 @@ #define KEY_RELEASE 0x80 #define KEY_MASK 0x7f -#define SHIFT_CODE 0x2a -#define SHIFT 0x0080 #define GREY_CODE 0xe0 -#define GREY 0x0100 +#define GREY SCANCODE_GREY +#define SHIFT_CODE 0x2a +#define SHIFT SCANCODE_SHIFT #define CNTRL_CODE 0x1d -#define CNTRL 0x0200 +#define CNTRL SCANCODE_CTRL #define ALT_CODE 0x38 -#define ALT 0x0400 +#define ALT SCANCODE_ALT +#define ALTGR SCANCODE_ALTGR + +#define KEYSYM_MASK 0x0ffffff +#define KEYSYM_SHIFT (SCANCODE_SHIFT << 16) +#define KEYSYM_CNTRL (SCANCODE_CTRL << 16) +#define KEYSYM_ALT (SCANCODE_ALT << 16) +#define KEYSYM_ALTGR (SCANCODE_ALTGR << 16) /* curses won't detect a Control + Alt + 1, so use Alt + 1 */ #define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ #define CURSES_KEYS KEY_MAX /* KEY_MAX defined in */ +static const int curses2keysym[CURSES_KEYS] = { + [0 ... (CURSES_KEYS - 1)] = -1, + + [0x7f] = KEY_BACKSPACE, + ['\r'] = KEY_ENTER, + ['\n'] = KEY_ENTER, + [KEY_BTAB] = '\t' | KEYSYM_SHIFT, +}; + static const int curses2keycode[CURSES_KEYS] = { [0 ... (CURSES_KEYS - 1)] = -1, @@ -220,7 +236,7 @@ static const int curses2keycode[CURSES_KEYS] = { }; -static const int curses2keysym[CURSES_KEYS] = { +static const int curses2qemu[CURSES_KEYS] = { [0 ... (CURSES_KEYS - 1)] = -1, ['\n'] = '\n', @@ -444,39 +460,43 @@ static const name2keysym_t name2keysym[] = { { "ydiaeresis", 0x0ff }, /* Special keys */ - { "BackSpace", 0x07f }, + { "BackSpace", KEY_BACKSPACE }, { "Tab", '\t' }, - { "Return", '\r' }, - { "Right", 0x105 }, - { "Left", 0x104 }, - { "Up", 0x103 }, - { "Down", 0x102 }, - { "Page_Down", 0x152 }, - { "Page_Up", 0x153 }, - { "Insert", 0x14b }, - { "Delete", 0x14a }, - { "Home", 0x106 }, - { "End", 0x168 }, - { "F1", 0x109 }, - { "F2", 0x10a }, - { "F3", 0x10b }, - { "F4", 0x10c }, - { "F5", 0x10d }, - { "F6", 0x10e }, - { "F7", 0x10f }, - { "F8", 0x110 }, - { "F9", 0x111 }, - { "F10", 0x112 }, - { "F11", 0x113 }, - { "F12", 0x114 }, - { "F13", 0x115 }, - { "F14", 0x116 }, - { "F15", 0x117 }, - { "F16", 0x118 }, - { "F17", 0x119 }, - { "F18", 0x11a }, - { "F19", 0x11b }, - { "F20", 0x11c }, + { "Return", KEY_ENTER }, + { "Right", KEY_RIGHT }, + { "Left", KEY_LEFT }, + { "Up", KEY_UP }, + { "Down", KEY_DOWN }, + { "Page_Down", KEY_NPAGE }, + { "Page_Up", KEY_PPAGE }, + { "Insert", KEY_IC }, + { "Delete", KEY_DC }, + { "Home", KEY_HOME }, + { "End", KEY_END }, + { "F1", KEY_F(1) }, + { "F2", KEY_F(2) }, + { "F3", KEY_F(3) }, + { "F4", KEY_F(4) }, + { "F5", KEY_F(5) }, + { "F6", KEY_F(6) }, + { "F7", KEY_F(7) }, + { "F8", KEY_F(8) }, + { "F9", KEY_F(9) }, + { "F10", KEY_F(10) }, + { "F11", KEY_F(11) }, + { "F12", KEY_F(12) }, + { "F13", KEY_F(13) }, + { "F14", KEY_F(14) }, + { "F15", KEY_F(15) }, + { "F16", KEY_F(16) }, + { "F17", KEY_F(17) }, + { "F18", KEY_F(18) }, + { "F19", KEY_F(19) }, + { "F20", KEY_F(20) }, + { "F21", KEY_F(21) }, + { "F22", KEY_F(22) }, + { "F23", KEY_F(23) }, + { "F24", KEY_F(24) }, { "Escape", 27 }, { NULL, 0 }, diff --git a/keymaps.c b/keymaps.c index da4ed2b..31bbf8d 100644 --- a/keymaps.c +++ b/keymaps.c @@ -59,6 +59,29 @@ static void add_to_key_range(struct key_range **krp, int code) { } } +static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) { + if (keysym < MAX_NORMAL_KEYCODE) { + //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); + k->keysym2keycode[keysym] = keycode; + } else { + if (k->extra_count >= MAX_EXTRA_COUNT) { + fprintf(stderr, + "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n", + line, keysym); + } else { +#if 0 + fprintf(stderr, "Setting %d: %d,%d\n", + k->extra_count, keysym, keycode); +#endif + k->keysym2keycode_extra[k->extra_count]. + keysym = keysym; + k->keysym2keycode_extra[k->extra_count]. + keycode = keycode; + k->extra_count++; + } + } +} + static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, const char *language, kbd_layout_t * k) @@ -113,27 +136,22 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode); } - /* if(keycode&0x80) - keycode=(keycode<<8)^0x80e0; */ - if (keysym < MAX_NORMAL_KEYCODE) { - //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); - k->keysym2keycode[keysym] = keycode; - } else { - if (k->extra_count >= MAX_EXTRA_COUNT) { - fprintf(stderr, - "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n", - line, keysym); - } else { -#if 0 - fprintf(stderr, "Setting %d: %d,%d\n", - k->extra_count, keysym, keycode); -#endif - k->keysym2keycode_extra[k->extra_count]. - keysym = keysym; - k->keysym2keycode_extra[k->extra_count]. - keycode = keycode; - k->extra_count++; - } + if (rest && strstr(rest, "shift")) + keycode |= SCANCODE_SHIFT; + if (rest && strstr(rest, "altgr")) + keycode |= SCANCODE_ALTGR; + if (rest && strstr(rest, "ctrl")) + keycode |= SCANCODE_CTRL; + + add_keysym(line, keysym, keycode, k); + + if (rest && strstr(rest, "addupper")) { + char *c; + for (c = line; *c; c++) + *c = toupper(*c); + keysym = get_keysym(table, line); + if (keysym) + add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k); } } } diff --git a/keymaps.h b/keymaps.h index 17f6efd..a7600d5 100644 --- a/keymaps.h +++ b/keymaps.h @@ -51,6 +51,23 @@ typedef struct { struct key_range *numlock_range; } kbd_layout_t; +/* scancode without modifiers */ +#define SCANCODE_KEYMASK 0xff +/* scancode without grey or up bit */ +#define SCANCODE_KEYCODEMASK 0x7f + +/* "grey" keys will usually need a 0xe0 prefix */ +#define SCANCODE_GREY 0x80 +#define SCANCODE_EMUL0 0xE0 +/* "up" flag */ +#define SCANCODE_UP 0x80 + +/* Additional modifiers to use if not catched another way. */ +#define SCANCODE_SHIFT 0x100 +#define SCANCODE_CTRL 0x200 +#define SCANCODE_ALT 0x400 +#define SCANCODE_ALTGR 0x800 + void *init_keyboard_layout(const name2keysym_t *table, const char *language); int keysym2scancode(void *kbd_layout, int keysym); diff --git a/sdl.c b/sdl.c index ff4655c..5a37653 100644 --- a/sdl.c +++ b/sdl.c @@ -249,7 +249,7 @@ static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev) if (keysym == 92 && ev->keysym.scancode == 133) { keysym = 0xa5; } - return keysym2scancode(kbd_layout, keysym); + return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK; } /* specific keyboard conversions from scan codes */ @@ -344,9 +344,9 @@ static void reset_keys(void) int i; for(i = 0; i < 256; i++) { if (modifiers_state[i]) { - if (i & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(i | 0x80); + if (i & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(i | SCANCODE_UP); modifiers_state[i] = 0; } } @@ -360,7 +360,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) /* specific case */ v = 0; if (ev->type == SDL_KEYUP) - v |= 0x80; + v |= SCANCODE_UP; kbd_put_keycode(0xe1); kbd_put_keycode(0x1d | v); kbd_put_keycode(0x45 | v); @@ -393,17 +393,17 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) case 0x3a: /* caps lock */ /* SDL does not send the key up event, so we generate it */ kbd_put_keycode(keycode); - kbd_put_keycode(keycode | 0x80); + kbd_put_keycode(keycode | SCANCODE_UP); return; } /* now send the key code */ - if (keycode & 0x80) - kbd_put_keycode(0xe0); + if (keycode & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); if (ev->type == SDL_KEYUP) - kbd_put_keycode(keycode | 0x80); + kbd_put_keycode(keycode | SCANCODE_UP); else - kbd_put_keycode(keycode & 0x7f); + kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); } static void sdl_update_caption(void) diff --git a/vnc.c b/vnc.c index 0d0b4a1..5df8467 100644 --- a/vnc.c +++ b/vnc.c @@ -1494,9 +1494,9 @@ static void reset_keys(VncState *vs) int i; for(i = 0; i < 256; i++) { if (vs->modifiers_state[i]) { - if (i & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(i | 0x80); + if (i & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(i | SCANCODE_UP); vs->modifiers_state[i] = 0; } } @@ -1504,8 +1504,13 @@ static void reset_keys(VncState *vs) static void press_key(VncState *vs, int keysym) { - kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f); - kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80); + int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; + if (keycode & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); + if (keycode & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); + kbd_put_keycode(keycode | SCANCODE_UP); } static void kbd_leds(void *opaque, int ledstate) @@ -1594,12 +1599,12 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) } if (is_graphic_console()) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); + if (keycode & SCANCODE_GREY) + kbd_put_keycode(SCANCODE_EMUL0); if (down) - kbd_put_keycode(keycode & 0x7f); + kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); else - kbd_put_keycode(keycode | 0x80); + kbd_put_keycode(keycode | SCANCODE_UP); } else { /* QEMU console emulation */ if (down) { @@ -1707,7 +1712,7 @@ static void key_event(VncState *vs, int down, uint32_t sym) lsym = lsym - 'A' + 'a'; } - keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF); + keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK; do_key_event(vs, down, keycode, sym); } -- 1.7.7.6