123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- /*
- * QEMU keysym to keycode conversion using rdesktop keymaps
- *
- * Copyright (c) 2004 Johannes Schindelin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include "qemu/osdep.h"
- #include "qemu/datadir.h"
- #include "keymaps.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;
- uint16_t keycodes[4];
- };
- struct kbd_layout_t {
- GHashTable *hash;
- };
- static int get_keysym(const name2keysym_t *table,
- const char *name)
- {
- const name2keysym_t *p;
- for(p = table; p->name != NULL; p++) {
- if (!strcmp(p->name, name)) {
- return p->keysym;
- }
- }
- if (name[0] == 'U' && strlen(name) == 5) { /* try unicode Uxxxx */
- char *end;
- int ret = (int)strtoul(name + 1, &end, 16);
- if (*end == '\0' && ret > 0) {
- return ret;
- }
- }
- return 0;
- }
- static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k)
- {
- struct keysym2code *keysym2code;
- 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 {
- 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 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];
- char keyname[64];
- int len;
- filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
- trace_keymap_parse(filename);
- f = filename ? fopen(filename, "r") : NULL;
- g_free(filename);
- if (!f) {
- error_setg(errp, "could not read keymap file: '%s'", language);
- return -1;
- }
- for(;;) {
- if (fgets(line, 1024, f) == NULL) {
- break;
- }
- len = strlen(line);
- if (len > 0 && line[len - 1] == '\n') {
- line[len - 1] = '\0';
- }
- if (line[0] == '#') {
- continue;
- }
- if (!strncmp(line, "map ", 4)) {
- continue;
- }
- if (!strncmp(line, "include ", 8)) {
- error_setg(errp, "keymap include files are not supported any more");
- ret = -1;
- goto out;
- } else {
- int offset = 0;
- while (line[offset] != 0 &&
- line[offset] != ' ' &&
- offset < sizeof(keyname) - 1) {
- keyname[offset] = line[offset];
- offset++;
- }
- keyname[offset] = 0;
- if (strlen(keyname)) {
- int keysym;
- keysym = get_keysym(table, keyname);
- if (keysym == 0) {
- /* warn_report("unknown keysym %s", line);*/
- } else {
- const char *rest = line + offset + 1;
- int keycode = strtol(rest, NULL, 0);
- if (strstr(rest, "shift")) {
- keycode |= SCANCODE_SHIFT;
- }
- if (strstr(rest, "altgr")) {
- keycode |= SCANCODE_ALTGR;
- }
- if (strstr(rest, "ctrl")) {
- keycode |= SCANCODE_CTRL;
- }
- add_keysym(line, keysym, keycode, k);
- if (strstr(rest, "addupper")) {
- char *c;
- for (c = keyname; *c; c++) {
- *c = qemu_toupper(*c);
- }
- keysym = get_keysym(table, keyname);
- if (keysym) {
- add_keysym(line, keysym,
- keycode | SCANCODE_SHIFT, k);
- }
- }
- }
- }
- }
- }
- ret = 0;
- out:
- fclose(f);
- return ret;
- }
- kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
- const char *language, Error **errp)
- {
- 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,
- 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
- if (keysym == XK_ISO_Left_Tab) {
- keysym = XK_Tab;
- }
- #endif
- 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;
- }
- 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];
- }
- int keycode_is_keypad(kbd_layout_t *k, int keycode)
- {
- if (keycode >= 0x47 && keycode <= 0x53) {
- return true;
- }
- return false;
- }
- 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 false;
- }
|