qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

keymaps.c (8225B)


      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/datadir.h"
     27 #include "keymaps.h"
     28 #include "trace.h"
     29 #include "qemu/ctype.h"
     30 #include "qemu/error-report.h"
     31 #include "qapi/error.h"
     32 #include "ui/input.h"
     33 
     34 struct keysym2code {
     35     uint32_t count;
     36     uint16_t keycodes[4];
     37 };
     38 
     39 struct kbd_layout_t {
     40     GHashTable *hash;
     41 };
     42 
     43 static int get_keysym(const name2keysym_t *table,
     44                       const char *name)
     45 {
     46     const name2keysym_t *p;
     47     for(p = table; p->name != NULL; p++) {
     48         if (!strcmp(p->name, name)) {
     49             return p->keysym;
     50         }
     51     }
     52     if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */
     53         char *end;
     54         int ret = (int)strtoul(name + 1, &end, 16);
     55         if (*end == '\0' && ret > 0) {
     56             return ret;
     57         }
     58     }
     59     return 0;
     60 }
     61 
     62 
     63 static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k)
     64 {
     65     struct keysym2code *keysym2code;
     66 
     67     keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym));
     68     if (keysym2code) {
     69         if (keysym2code->count < ARRAY_SIZE(keysym2code->keycodes)) {
     70             keysym2code->keycodes[keysym2code->count++] = keycode;
     71         } else {
     72             warn_report("more than %zd keycodes for keysym %d",
     73                         ARRAY_SIZE(keysym2code->keycodes), keysym);
     74         }
     75         return;
     76     }
     77 
     78     keysym2code = g_new0(struct keysym2code, 1);
     79     keysym2code->keycodes[0] = keycode;
     80     keysym2code->count = 1;
     81     g_hash_table_replace(k->hash, GINT_TO_POINTER(keysym), keysym2code);
     82     trace_keymap_add(keysym, keycode, line);
     83 }
     84 
     85 static int parse_keyboard_layout(kbd_layout_t *k,
     86                                  const name2keysym_t *table,
     87                                  const char *language, Error **errp)
     88 {
     89     int ret;
     90     FILE *f;
     91     char * filename;
     92     char line[1024];
     93     char keyname[64];
     94     int len;
     95 
     96     filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
     97     trace_keymap_parse(filename);
     98     f = filename ? fopen(filename, "r") : NULL;
     99     g_free(filename);
    100     if (!f) {
    101         error_setg(errp, "could not read keymap file: '%s'", language);
    102         return -1;
    103     }
    104 
    105     for(;;) {
    106         if (fgets(line, 1024, f) == NULL) {
    107             break;
    108         }
    109         len = strlen(line);
    110         if (len > 0 && line[len - 1] == '\n') {
    111             line[len - 1] = '\0';
    112         }
    113         if (line[0] == '#') {
    114             continue;
    115         }
    116         if (!strncmp(line, "map ", 4)) {
    117             continue;
    118         }
    119         if (!strncmp(line, "include ", 8)) {
    120             error_setg(errp, "keymap include files are not supported any more");
    121             ret = -1;
    122             goto out;
    123         } else {
    124             int offset = 0;
    125             while (line[offset] != 0 &&
    126                    line[offset] != ' ' &&
    127                    offset < sizeof(keyname) - 1) {
    128                 keyname[offset] = line[offset];
    129                 offset++;
    130             }
    131             keyname[offset] = 0;
    132             if (strlen(keyname)) {
    133                 int keysym;
    134                 keysym = get_keysym(table, keyname);
    135                 if (keysym == 0) {
    136                     /* warn_report("unknown keysym %s", line);*/
    137                 } else {
    138                     const char *rest = line + offset + 1;
    139                     int keycode = strtol(rest, NULL, 0);
    140 
    141                     if (strstr(rest, "shift")) {
    142                         keycode |= SCANCODE_SHIFT;
    143                     }
    144                     if (strstr(rest, "altgr")) {
    145                         keycode |= SCANCODE_ALTGR;
    146                     }
    147                     if (strstr(rest, "ctrl")) {
    148                         keycode |= SCANCODE_CTRL;
    149                     }
    150 
    151                     add_keysym(line, keysym, keycode, k);
    152 
    153                     if (strstr(rest, "addupper")) {
    154                         char *c;
    155                         for (c = keyname; *c; c++) {
    156                             *c = qemu_toupper(*c);
    157                         }
    158                         keysym = get_keysym(table, keyname);
    159                         if (keysym) {
    160                             add_keysym(line, keysym,
    161                                        keycode | SCANCODE_SHIFT, k);
    162                         }
    163                     }
    164                 }
    165             }
    166         }
    167     }
    168 
    169     ret = 0;
    170 out:
    171     fclose(f);
    172     return ret;
    173 }
    174 
    175 
    176 kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
    177                                    const char *language, Error **errp)
    178 {
    179     kbd_layout_t *k;
    180 
    181     k = g_new0(kbd_layout_t, 1);
    182     k->hash = g_hash_table_new(NULL, NULL);
    183     if (parse_keyboard_layout(k, table, language, errp) < 0) {
    184         g_hash_table_unref(k->hash);
    185         g_free(k);
    186         return NULL;
    187     }
    188     return k;
    189 }
    190 
    191 
    192 int keysym2scancode(kbd_layout_t *k, int keysym,
    193                     QKbdState *kbd, bool down)
    194 {
    195     static const uint32_t mask =
    196         SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL;
    197     uint32_t mods, i;
    198     struct keysym2code *keysym2code;
    199 
    200 #ifdef XK_ISO_Left_Tab
    201     if (keysym == XK_ISO_Left_Tab) {
    202         keysym = XK_Tab;
    203     }
    204 #endif
    205 
    206     keysym2code = g_hash_table_lookup(k->hash, GINT_TO_POINTER(keysym));
    207     if (!keysym2code) {
    208         trace_keymap_unmapped(keysym);
    209         warn_report("no scancode found for keysym %d", keysym);
    210         return 0;
    211     }
    212 
    213     if (keysym2code->count == 1) {
    214         return keysym2code->keycodes[0];
    215     }
    216 
    217     /* We have multiple keysym -> keycode mappings. */
    218     if (down) {
    219         /*
    220          * On keydown: Check whenever we find one mapping where the
    221          * modifier state of the mapping matches the current user
    222          * interface modifier state.  If so, prefer that one.
    223          */
    224         mods = 0;
    225         if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_SHIFT)) {
    226             mods |= SCANCODE_SHIFT;
    227         }
    228         if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_ALTGR)) {
    229             mods |= SCANCODE_ALTGR;
    230         }
    231         if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_CTRL)) {
    232             mods |= SCANCODE_CTRL;
    233         }
    234 
    235         for (i = 0; i < keysym2code->count; i++) {
    236             if ((keysym2code->keycodes[i] & mask) == mods) {
    237                 return keysym2code->keycodes[i];
    238             }
    239         }
    240     } else {
    241         /*
    242          * On keyup: Try find a key which is actually down.
    243          */
    244         for (i = 0; i < keysym2code->count; i++) {
    245             QKeyCode qcode = qemu_input_key_number_to_qcode
    246                 (keysym2code->keycodes[i]);
    247             if (kbd && qkbd_state_key_get(kbd, qcode)) {
    248                 return keysym2code->keycodes[i];
    249             }
    250         }
    251     }
    252     return keysym2code->keycodes[0];
    253 }
    254 
    255 int keycode_is_keypad(kbd_layout_t *k, int keycode)
    256 {
    257     if (keycode >= 0x47 && keycode <= 0x53) {
    258         return true;
    259     }
    260     return false;
    261 }
    262 
    263 int keysym_is_numlock(kbd_layout_t *k, int keysym)
    264 {
    265     switch (keysym) {
    266     case 0xffb0 ... 0xffb9:  /* KP_0 .. KP_9 */
    267     case 0xffac:             /* KP_Separator */
    268     case 0xffae:             /* KP_Decimal   */
    269         return true;
    270     }
    271     return false;
    272 }