Skip to content

Commit

Permalink
keymap: fix keyup mappings
Browse files Browse the repository at this point in the history
It is possible that the modifier state on keyup is different from the
modifier state on keydown.  In that case the keycode lookup can end up
with different keys in case multiple keysym -> keycode mappings exist,
because it picks the mapping depending on modifier state.

To fix that change the lookup logic for keyup events.  Instead of
looking at the modifier state check the key state and prefer a keycodes
where the key is in "down" state right now.

Fixes: abb4f2c keymap: consider modifier state when picking a mapping
Buglink: https://bugs.launchpad.net/bugs/1738283
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1658676
Signed-off-by: Gerd Hoffmann <[email protected]>
Reviewed-by: Daniel P. Berrangé <[email protected]>
Message-id: [email protected]
  • Loading branch information
kraxel committed Feb 5, 2019
1 parent 4ed26e1 commit 19c1b9f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 24 deletions.
2 changes: 1 addition & 1 deletion ui/curses.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
}

keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK,
NULL);
NULL, false);
if (keycode == 0)
continue;

Expand Down
55 changes: 34 additions & 21 deletions ui/keymaps.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "trace.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "ui/input.h"

struct keysym2code {
uint32_t count;
Expand Down Expand Up @@ -188,7 +189,7 @@ kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,


int keysym2scancode(kbd_layout_t *k, int keysym,
QKbdState *kbd)
QKbdState *kbd, bool down)
{
static const uint32_t mask =
SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL;
Expand All @@ -212,27 +213,39 @@ int keysym2scancode(kbd_layout_t *k, int keysym,
return keysym2code->keycodes[0];
}

/*
* We have multiple keysym -> keycode mappings.
*
* Check whenever we find one mapping where the modifier state of
* the mapping matches the current user interface modifier state.
* If so, prefer that one.
*/
mods = 0;
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_SHIFT)) {
mods |= SCANCODE_SHIFT;
}
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_ALTGR)) {
mods |= SCANCODE_ALTGR;
}
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_CTRL)) {
mods |= SCANCODE_CTRL;
}
/* We have multiple keysym -> keycode mappings. */
if (down) {
/*
* On keydown: Check whenever we find one mapping where the
* modifier state of the mapping matches the current user
* interface modifier state. If so, prefer that one.
*/
mods = 0;
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_SHIFT)) {
mods |= SCANCODE_SHIFT;
}
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_ALTGR)) {
mods |= SCANCODE_ALTGR;
}
if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_CTRL)) {
mods |= SCANCODE_CTRL;
}

for (i = 0; i < keysym2code->count; i++) {
if ((keysym2code->keycodes[i] & mask) == mods) {
return keysym2code->keycodes[i];
for (i = 0; i < keysym2code->count; i++) {
if ((keysym2code->keycodes[i] & mask) == mods) {
return keysym2code->keycodes[i];
}
}
} else {
/*
* On keyup: Try find a key which is actually down.
*/
for (i = 0; i < keysym2code->count; i++) {
QKeyCode qcode = qemu_input_key_number_to_qcode
(keysym2code->keycodes[i]);
if (kbd && qkbd_state_key_get(kbd, qcode)) {
return keysym2code->keycodes[i];
}
}
}
return keysym2code->keycodes[0];
Expand Down
2 changes: 1 addition & 1 deletion ui/keymaps.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ typedef struct kbd_layout_t kbd_layout_t;
kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
const char *language, Error **errp);
int keysym2scancode(kbd_layout_t *k, int keysym,
QKbdState *kbd);
QKbdState *kbd, bool down);
int keycode_is_keypad(kbd_layout_t *k, int keycode);
int keysym_is_numlock(kbd_layout_t *k, int keysym);

Expand Down
2 changes: 1 addition & 1 deletion ui/vnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
}

keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF,
vs->vd->kbd) & SCANCODE_KEYMASK;
vs->vd->kbd, down) & SCANCODE_KEYMASK;
trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
do_key_event(vs, down, keycode, sym);
}
Expand Down

0 comments on commit 19c1b9f

Please sign in to comment.