]> git.proxmox.com Git - mirror_qemu.git/blobdiff - ui/keymaps.c
console: fix cell overflow
[mirror_qemu.git] / ui / keymaps.c
index 1eba6d70577607203f0f2d3fec5090f1d6f82446..6e8a321971a2cc49d482a3c9dad6d2465efe746c 100644 (file)
  */
 
 #include "qemu/osdep.h"
+#include "qemu-common.h"
 #include "keymaps.h"
 #include "sysemu/sysemu.h"
 #include "trace.h"
+#include "qemu/ctype.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "ui/input.h"
 
 struct keysym2code {
     uint32_t count;
@@ -79,10 +83,11 @@ static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k)
     trace_keymap_add(keysym, keycode, line);
 }
 
-static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
-                                           const char *language,
-                                           kbd_layout_t *k)
+static int parse_keyboard_layout(kbd_layout_t *k,
+                                 const name2keysym_t *table,
+                                 const char *language, Error **errp)
 {
+    int ret;
     FILE *f;
     char * filename;
     char line[1024];
@@ -94,13 +99,8 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
     f = filename ? fopen(filename, "r") : NULL;
     g_free(filename);
     if (!f) {
-        fprintf(stderr, "Could not read keymap file: '%s'\n", language);
-        return NULL;
-    }
-
-    if (!k) {
-        k = g_new0(kbd_layout_t, 1);
-        k->hash = g_hash_table_new(NULL, NULL);
+        error_setg(errp, "could not read keymap file: '%s'", language);
+        return -1;
     }
 
     for(;;) {
@@ -118,7 +118,9 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
             continue;
         }
         if (!strncmp(line, "include ", 8)) {
-            parse_keyboard_layout(table, line + 8, k);
+            error_setg(errp, "keymap include files are not supported any more");
+            ret = -1;
+            goto out;
         } else {
             int offset = 0;
             while (line[offset] != 0 &&
@@ -164,20 +166,36 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
             }
         }
     }
+
+    ret = 0;
+out:
     fclose(f);
-    return k;
+    return ret;
 }
 
 
 kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
-                                   const char *language)
+                                   const char *language, Error **errp)
 {
-    return parse_keyboard_layout(table, language, NULL);
+    kbd_layout_t *k;
+
+    k = g_new0(kbd_layout_t, 1);
+    k->hash = g_hash_table_new(NULL, NULL);
+    if (parse_keyboard_layout(k, table, language, errp) < 0) {
+        g_hash_table_unref(k->hash);
+        g_free(k);
+        return NULL;
+    }
+    return k;
 }
 
 
-int keysym2scancode(kbd_layout_t *k, int keysym)
+int keysym2scancode(kbd_layout_t *k, int keysym,
+                    QKbdState *kbd, bool down)
 {
+    static const uint32_t mask =
+        SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL;
+    uint32_t mods, i;
     struct keysym2code *keysym2code;
 
 #ifdef XK_ISO_Left_Tab
@@ -193,6 +211,45 @@ int keysym2scancode(kbd_layout_t *k, int keysym)
         return 0;
     }
 
+    if (keysym2code->count == 1) {
+        return keysym2code->keycodes[0];
+    }
+
+    /* 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];
+            }
+        }
+    } 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];
 }