cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

keymaps.c (8250B)


      1/*
      2 * QEMU keysym to keycode conversion using rdesktop keymaps
      3 *
      4 * Copyright (c) 2004 Johannes Schindelin
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qemu-common.h"
     27#include "qemu/datadir.h"
     28#include "keymaps.h"
     29#include "trace.h"
     30#include "qemu/ctype.h"
     31#include "qemu/error-report.h"
     32#include "qapi/error.h"
     33#include "ui/input.h"
     34
     35struct keysym2code {
     36    uint32_t count;
     37    uint16_t keycodes[4];
     38};
     39
     40struct kbd_layout_t {
     41    GHashTable *hash;
     42};
     43
     44static int get_keysym(const name2keysym_t *table,
     45                      const char *name)
     46{
     47    const name2keysym_t *p;
     48    for(p = table; p->name != NULL; p++) {
     49        if (!strcmp(p->name, name)) {
     50            return p->keysym;
     51        }
     52    }
     53    if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */
     54        char *end;
     55        int ret = (int)strtoul(name + 1, &end, 16);
     56        if (*end == '\0' && ret > 0) {
     57            return ret;
     58        }
     59    }
     60    return 0;
     61}
     62
     63
     64static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k)
     65{
     66    struct keysym2code *keysym2code;
     67
     68    keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym));
     69    if (keysym2code) {
     70        if (keysym2code->count < ARRAY_SIZE(keysym2code->keycodes)) {
     71            keysym2code->keycodes[keysym2code->count++] = keycode;
     72        } else {
     73            warn_report("more than %zd keycodes for keysym %d",
     74                        ARRAY_SIZE(keysym2code->keycodes), keysym);
     75        }
     76        return;
     77    }
     78
     79    keysym2code = g_new0(struct keysym2code, 1);
     80    keysym2code->keycodes[0] = keycode;
     81    keysym2code->count = 1;
     82    g_hash_table_replace(k->hash, GINT_TO_POINTER(keysym), keysym2code);
     83    trace_keymap_add(keysym, keycode, line);
     84}
     85
     86static int parse_keyboard_layout(kbd_layout_t *k,
     87                                 const name2keysym_t *table,
     88                                 const char *language, Error **errp)
     89{
     90    int ret;
     91    FILE *f;
     92    char * filename;
     93    char line[1024];
     94    char keyname[64];
     95    int len;
     96
     97    filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
     98    trace_keymap_parse(filename);
     99    f = filename ? fopen(filename, "r") : NULL;
    100    g_free(filename);
    101    if (!f) {
    102        error_setg(errp, "could not read keymap file: '%s'", language);
    103        return -1;
    104    }
    105
    106    for(;;) {
    107        if (fgets(line, 1024, f) == NULL) {
    108            break;
    109        }
    110        len = strlen(line);
    111        if (len > 0 && line[len - 1] == '\n') {
    112            line[len - 1] = '\0';
    113        }
    114        if (line[0] == '#') {
    115            continue;
    116        }
    117        if (!strncmp(line, "map ", 4)) {
    118            continue;
    119        }
    120        if (!strncmp(line, "include ", 8)) {
    121            error_setg(errp, "keymap include files are not supported any more");
    122            ret = -1;
    123            goto out;
    124        } else {
    125            int offset = 0;
    126            while (line[offset] != 0 &&
    127                   line[offset] != ' ' &&
    128                   offset < sizeof(keyname) - 1) {
    129                keyname[offset] = line[offset];
    130                offset++;
    131            }
    132            keyname[offset] = 0;
    133            if (strlen(keyname)) {
    134                int keysym;
    135                keysym = get_keysym(table, keyname);
    136                if (keysym == 0) {
    137                    /* warn_report("unknown keysym %s", line);*/
    138                } else {
    139                    const char *rest = line + offset + 1;
    140                    int keycode = strtol(rest, NULL, 0);
    141
    142                    if (strstr(rest, "shift")) {
    143                        keycode |= SCANCODE_SHIFT;
    144                    }
    145                    if (strstr(rest, "altgr")) {
    146                        keycode |= SCANCODE_ALTGR;
    147                    }
    148                    if (strstr(rest, "ctrl")) {
    149                        keycode |= SCANCODE_CTRL;
    150                    }
    151
    152                    add_keysym(line, keysym, keycode, k);
    153
    154                    if (strstr(rest, "addupper")) {
    155                        char *c;
    156                        for (c = keyname; *c; c++) {
    157                            *c = qemu_toupper(*c);
    158                        }
    159                        keysym = get_keysym(table, keyname);
    160                        if (keysym) {
    161                            add_keysym(line, keysym,
    162                                       keycode | SCANCODE_SHIFT, k);
    163                        }
    164                    }
    165                }
    166            }
    167        }
    168    }
    169
    170    ret = 0;
    171out:
    172    fclose(f);
    173    return ret;
    174}
    175
    176
    177kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
    178                                   const char *language, Error **errp)
    179{
    180    kbd_layout_t *k;
    181
    182    k = g_new0(kbd_layout_t, 1);
    183    k->hash = g_hash_table_new(NULL, NULL);
    184    if (parse_keyboard_layout(k, table, language, errp) < 0) {
    185        g_hash_table_unref(k->hash);
    186        g_free(k);
    187        return NULL;
    188    }
    189    return k;
    190}
    191
    192
    193int keysym2scancode(kbd_layout_t *k, int keysym,
    194                    QKbdState *kbd, bool down)
    195{
    196    static const uint32_t mask =
    197        SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL;
    198    uint32_t mods, i;
    199    struct keysym2code *keysym2code;
    200
    201#ifdef XK_ISO_Left_Tab
    202    if (keysym == XK_ISO_Left_Tab) {
    203        keysym = XK_Tab;
    204    }
    205#endif
    206
    207    keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym));
    208    if (!keysym2code) {
    209        trace_keymap_unmapped(keysym);
    210        warn_report("no scancode found for keysym %d", keysym);
    211        return 0;
    212    }
    213
    214    if (keysym2code->count == 1) {
    215        return keysym2code->keycodes[0];
    216    }
    217
    218    /* We have multiple keysym -> keycode mappings. */
    219    if (down) {
    220        /*
    221         * On keydown: Check whenever we find one mapping where the
    222         * modifier state of the mapping matches the current user
    223         * interface modifier state.  If so, prefer that one.
    224         */
    225        mods = 0;
    226        if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_SHIFT)) {
    227            mods |= SCANCODE_SHIFT;
    228        }
    229        if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_ALTGR)) {
    230            mods |= SCANCODE_ALTGR;
    231        }
    232        if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_CTRL)) {
    233            mods |= SCANCODE_CTRL;
    234        }
    235
    236        for (i = 0; i < keysym2code->count; i++) {
    237            if ((keysym2code->keycodes[i] & mask) == mods) {
    238                return keysym2code->keycodes[i];
    239            }
    240        }
    241    } else {
    242        /*
    243         * On keyup: Try find a key which is actually down.
    244         */
    245        for (i = 0; i < keysym2code->count; i++) {
    246            QKeyCode qcode = qemu_input_key_number_to_qcode
    247                (keysym2code->keycodes[i]);
    248            if (kbd && qkbd_state_key_get(kbd, qcode)) {
    249                return keysym2code->keycodes[i];
    250            }
    251        }
    252    }
    253    return keysym2code->keycodes[0];
    254}
    255
    256int keycode_is_keypad(kbd_layout_t *k, int keycode)
    257{
    258    if (keycode >= 0x47 && keycode <= 0x53) {
    259        return true;
    260    }
    261    return false;
    262}
    263
    264int keysym_is_numlock(kbd_layout_t *k, int keysym)
    265{
    266    switch (keysym) {
    267    case 0xffb0 ... 0xffb9:  /* KP_0 .. KP_9 */
    268    case 0xffac:             /* KP_Separator */
    269    case 0xffae:             /* KP_Decimal   */
    270        return true;
    271    }
    272    return false;
    273}