diff options
Diffstat (limited to 'ui/keymaps.c')
| -rw-r--r-- | ui/keymaps.c | 163 |
1 files changed, 83 insertions, 80 deletions
diff --git a/ui/keymaps.c b/ui/keymaps.c index f9762d1497..43fe604724 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -28,6 +28,15 @@ #include "trace.h" #include "qemu/error-report.h" +struct keysym2code { + uint32_t count; + uint16_t keycodes[4]; +}; + +struct kbd_layout_t { + GHashTable *hash; +}; + static int get_keysym(const name2keysym_t *table, const char *name) { @@ -48,46 +57,26 @@ static int get_keysym(const name2keysym_t *table, } -static void add_to_key_range(struct key_range **krp, int code) { - struct key_range *kr; - for (kr = *krp; kr; kr = kr->next) { - if (code >= kr->start && code <= kr->end) { - break; - } - if (code == kr->start - 1) { - kr->start--; - break; - } - if (code == kr->end + 1) { - kr->end++; - break; - } - } - if (kr == NULL) { - kr = g_malloc0(sizeof(*kr)); - kr->start = kr->end = code; - kr->next = *krp; - *krp = kr; - } -} +static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) +{ + struct keysym2code *keysym2code; -static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) { - if (keysym < MAX_NORMAL_KEYCODE) { - trace_keymap_add("normal", keysym, keycode, line); - k->keysym2keycode[keysym] = keycode; - } else { - if (k->extra_count >= MAX_EXTRA_COUNT) { - warn_report("Could not assign keysym %s (0x%x)" - " because of memory constraints.", line, keysym); + keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym)); + if (keysym2code) { + if (keysym2code->count < ARRAY_SIZE(keysym2code->keycodes)) { + keysym2code->keycodes[keysym2code->count++] = keycode; } else { - trace_keymap_add("extra", keysym, keycode, line); - k->keysym2keycode_extra[k->extra_count]. - keysym = keysym; - k->keysym2keycode_extra[k->extra_count]. - keycode = keycode; - k->extra_count++; + warn_report("more than %zd keycodes for keysym %d", + ARRAY_SIZE(keysym2code->keycodes), keysym); } + return; } + + keysym2code = g_new0(struct keysym2code, 1); + keysym2code->keycodes[0] = keycode; + keysym2code->count = 1; + g_hash_table_replace(k->hash, GINT_TO_POINTER(keysym), keysym2code); + trace_keymap_add(keysym, keycode, line); } static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, @@ -111,6 +100,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, if (!k) { k = g_new0(kbd_layout_t, 1); + k->hash = g_hash_table_new(NULL, NULL); } for(;;) { @@ -147,13 +137,6 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, const char *rest = line + offset + 1; int keycode = strtol(rest, NULL, 0); - if (strstr(rest, "numlock")) { - add_to_key_range(&k->keypad_range, keycode); - add_to_key_range(&k->numlock_range, keysym); - /* fprintf(stderr, "keypad keysym %04x keycode %d\n", - keysym, keycode); */ - } - if (strstr(rest, "shift")) { keycode |= SCANCODE_SHIFT; } @@ -186,59 +169,79 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, } -void *init_keyboard_layout(const name2keysym_t *table, const char *language) +kbd_layout_t *init_keyboard_layout(const name2keysym_t *table, + const char *language) { return parse_keyboard_layout(table, language, NULL); } -int keysym2scancode(void *kbd_layout, int keysym) +int keysym2scancode(kbd_layout_t *k, int keysym, + bool shift, bool altgr, bool ctrl) { - kbd_layout_t *k = kbd_layout; - if (keysym < MAX_NORMAL_KEYCODE) { - if (k->keysym2keycode[keysym] == 0) { - trace_keymap_unmapped(keysym); - warn_report("no scancode found for keysym %d", keysym); - } - return k->keysym2keycode[keysym]; - } else { - int i; + static const uint32_t mask = + SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL; + uint32_t mods, i; + struct keysym2code *keysym2code; + #ifdef XK_ISO_Left_Tab - if (keysym == XK_ISO_Left_Tab) { - keysym = XK_Tab; - } + if (keysym == XK_ISO_Left_Tab) { + keysym = XK_Tab; + } #endif - for (i = 0; i < k->extra_count; i++) { - if (k->keysym2keycode_extra[i].keysym == keysym) { - return k->keysym2keycode_extra[i].keycode; - } - } + + keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym)); + if (!keysym2code) { + trace_keymap_unmapped(keysym); + warn_report("no scancode found for keysym %d", keysym); + return 0; } - return 0; -} -int keycode_is_keypad(void *kbd_layout, int keycode) -{ - kbd_layout_t *k = kbd_layout; - struct key_range *kr; + if (keysym2code->count == 1) { + 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 (shift) { + mods |= SCANCODE_SHIFT; + } + if (altgr) { + mods |= SCANCODE_ALTGR; + } + if (ctrl) { + mods |= SCANCODE_CTRL; + } - for (kr = k->keypad_range; kr; kr = kr->next) { - if (keycode >= kr->start && keycode <= kr->end) { - return 1; + for (i = 0; i < keysym2code->count; i++) { + if ((keysym2code->keycodes[i] & mask) == mods) { + return keysym2code->keycodes[i]; } } - return 0; + return keysym2code->keycodes[0]; } -int keysym_is_numlock(void *kbd_layout, int keysym) +int keycode_is_keypad(kbd_layout_t *k, int keycode) { - kbd_layout_t *k = kbd_layout; - struct key_range *kr; + if (keycode >= 0x47 && keycode <= 0x53) { + return true; + } + return false; +} - for (kr = k->numlock_range; kr; kr = kr->next) { - if (keysym >= kr->start && keysym <= kr->end) { - return 1; - } +int keysym_is_numlock(kbd_layout_t *k, int keysym) +{ + switch (keysym) { + case 0xffb0 ... 0xffb9: /* KP_0 .. KP_9 */ + case 0xffac: /* KP_Separator */ + case 0xffae: /* KP_Decimal */ + return true; } - return 0; + return false; } |