From bc65c2d70f29e8630be738ccf9a4d52946cf2f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 21 Feb 2012 21:28:52 -0500 Subject: [PATCH] libfreerdp-locale: fix non-XKB keymap loading --- libfreerdp-locale/keyboard.c | 35 +--- libfreerdp-locale/keyboard_x11.c | 278 +++++++++++++++++++++++++------ 2 files changed, 236 insertions(+), 77 deletions(-) diff --git a/libfreerdp-locale/keyboard.c b/libfreerdp-locale/keyboard.c index 2f98b125e..7e4231b12 100644 --- a/libfreerdp-locale/keyboard.c +++ b/libfreerdp-locale/keyboard.c @@ -57,6 +57,8 @@ int freerdp_keyboard_load_map(uint32 keycode_to_vkcode[256], char* name) char* beg; char* end; int i = 0; + uint32 vkcode; + uint32 scancode; int kbd_found = 0; char* keymap_path; uint32 keycode = 0; @@ -68,7 +70,6 @@ int freerdp_keyboard_load_map(uint32 keycode_to_vkcode[256], char* name) char vkcode_name[128] = ""; boolean found = false; boolean extended = false; - VIRTUAL_KEY_CODE* vkcode; beg = name; @@ -150,37 +151,19 @@ int freerdp_keyboard_load_map(uint32 keycode_to_vkcode[256], char* name) found = false; extended = false; - do + for (i = 0; i < 256; i++) { - vkcode = (VIRTUAL_KEY_CODE*) &VIRTUAL_KEY_CODE_TABLE[i]; - - if (strcmp(vkcode_name, vkcode->name) == 0) + if (VIRTUAL_KEY_CODE_TABLE[i].name) { - found = true; - extended = false; - keycode_to_vkcode[keycode] = vkcode->code; - } - - i++; - } - while (vkcode->code != 0); - - if (!found) - { - do - { - vkcode = (VIRTUAL_KEY_CODE*) &VIRTUAL_KEY_CODE_TABLE[i]; - - if (strcmp(vkcode_name, vkcode->name) == 0) + if (strcmp(vkcode_name, VIRTUAL_KEY_CODE_TABLE[i].name) == 0) { found = true; - extended = true; - keycode_to_vkcode[keycode] = vkcode->code; + vkcode = VIRTUAL_KEY_CODE_TABLE[i].code; + scancode = VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[vkcode]; + extended = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode].extended; + keycode_to_vkcode[keycode] = vkcode; } - - i++; } - while (vkcode->code != 0); } } else if ((pch = strstr(buffer, ": extends")) != NULL) diff --git a/libfreerdp-locale/keyboard_x11.c b/libfreerdp-locale/keyboard_x11.c index 74094f64b..fd95da600 100644 --- a/libfreerdp-locale/keyboard_x11.c +++ b/libfreerdp-locale/keyboard_x11.c @@ -22,6 +22,7 @@ #include #include "liblocale.h" +#include #include #include @@ -897,57 +898,6 @@ static const XKB_LAYOUT xkbLayouts[] = { "tm", KBD_TURKISH_Q, tm_variants }, /* Turkmenistan */ }; -uint32 freerdp_keyboard_init_x11(uint32 keyboardLayoutId) -{ - uint32 vkcode; - uint32 keycode; - uint32 scancode; - boolean extended; - uint32 keycode_to_vkcode[256]; - - memset(keycode_to_vkcode, 0, sizeof(keycode_to_vkcode)); - memset(X11_KEYCODE_TO_RDP_SCANCODE, 0, sizeof(X11_KEYCODE_TO_RDP_SCANCODE)); - memset(RDP_SCANCODE_TO_X11_KEYCODE, 0, sizeof(RDP_SCANCODE_TO_X11_KEYCODE)); - - if (keyboardLayoutId == 0) - { - keyboardLayoutId = freerdp_detect_keyboard_layout_from_system_locale(); - DEBUG_KBD("using keyboard layout: %X", keyboardLayoutId); - } - - if (keyboardLayoutId == 0) - { - keyboardLayoutId = 0x0409; - DEBUG_KBD("using default keyboard layout: %X", keyboardLayoutId); - } - -#ifdef __APPLE__ - /* Apple X11 breaks XKB detection */ - freerdp_keyboard_load_map(keycode_to_vkcode, "macosx(macosx)"); -#endif - - for (keycode = 0; keycode < 256; keycode++) - { - vkcode = keycode_to_vkcode[keycode]; - - if (!(vkcode > 0 && vkcode < 256)) - continue; - - scancode = VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[vkcode]; - extended = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode].extended; - - X11_KEYCODE_TO_RDP_SCANCODE[keycode].code = scancode; - X11_KEYCODE_TO_RDP_SCANCODE[keycode].extended = extended; - - if (extended) - RDP_SCANCODE_TO_X11_KEYCODE[scancode][1] = keycode; - else - RDP_SCANCODE_TO_X11_KEYCODE[scancode][0] = keycode; - } - - return keyboardLayoutId; -} - uint32 find_keyboard_layout_in_xorg_rules(char* layout, char* variant) { int i, j; @@ -975,3 +925,229 @@ uint32 find_keyboard_layout_in_xorg_rules(char* layout, char* variant) return 0; } + +uint32 freerdp_detect_keyboard_layout_from_xkb(char** xkb_layout, char** xkb_variant) +{ + char* pch; + char* beg; + char* end; + FILE* xprop; + char buffer[1024]; + char* layout = NULL; + char* variant = NULL; + uint32 keyboardLayoutId = 0; + + /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */ + + xprop = popen("xprop -root _XKB_RULES_NAMES_BACKUP", "r"); + + /* Sample output for "Canadian Multilingual Standard" + * + * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multix", "" + * Where "xorg" is the set of rules + * "pc105" the keyboard type + * "ca" the keyboard layout + * "multi" the keyboard layout variant + */ + + while(fgets(buffer, sizeof(buffer), xprop) != NULL) + { + if((pch = strstr(buffer, "_XKB_RULES_NAMES_BACKUP(STRING) = ")) != NULL) + { + /* "rules" */ + pch = strchr(&buffer[34], ','); // We assume it is xorg + pch += 1; + + /* "type" */ + pch = strchr(pch, ','); + + /* "layout" */ + beg = strchr(pch + 1, '"'); + beg += 1; + + end = strchr(beg, '"'); + *end = '\0'; + + layout = beg; + + /* "variant" */ + beg = strchr(end + 1, '"'); + beg += 1; + + end = strchr(beg, '"'); + *end = '\0'; + + variant = beg; + } + } + pclose(xprop); + + keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant); + + if (keyboardLayoutId > 0) + { + *xkb_layout = xstrdup(layout); + *xkb_variant = xstrdup(variant); + return keyboardLayoutId; + } + + /* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */ + + xprop = popen("xprop -root _XKB_RULES_NAMES", "r"); + + while(fgets(buffer, sizeof(buffer), xprop) != NULL) + { + if((pch = strstr(buffer, "_XKB_RULES_NAMES(STRING) = ")) != NULL) + { + /* "rules" */ + pch = strchr(&buffer[27], ','); // We assume it is xorg + pch += 1; + + /* "type" */ + pch = strchr(pch, ','); + + /* "layout" */ + beg = strchr(pch + 1, '"'); + beg += 1; + + end = strchr(beg, '"'); + *end = '\0'; + + layout = beg; + + /* "variant" */ + beg = strchr(end + 1, '"'); + beg += 1; + + end = strchr(beg, '"'); + *end = '\0'; + + variant = beg; + } + } + pclose(xprop); + + keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant); + + if (keyboardLayoutId > 0) + { + *xkb_layout = xstrdup(layout); + *xkb_variant = xstrdup(variant); + return keyboardLayoutId; + } + + return 0; +} + +char* freerdp_detect_keymap_from_xkb() +{ + char* pch; + char* beg; + char* end; + int length; + FILE* setxkbmap; + char buffer[1024]; + char* keymap = NULL; + + /* this tells us about the current XKB configuration, if XKB is available */ + setxkbmap = popen("setxkbmap -print", "r"); + + while (fgets(buffer, sizeof(buffer), setxkbmap) != NULL) + { + /* the line with xkb_keycodes is what interests us */ + pch = strstr(buffer, "xkb_keycodes"); + + if (pch != NULL) + { + pch = strstr(pch, "include"); + + if (pch != NULL) + { + /* check for " " delimiter presence */ + if ((beg = strchr(pch, '"')) == NULL) + break; + else + beg++; + + if ((pch = strchr(beg + 1, '"')) == NULL) + break; + + end = strcspn(beg + 1, "\"") + beg + 1; + *end = '\0'; + + length = (end - beg); + keymap = (char*) xmalloc(length + 1); + strncpy(keymap, beg, length); + keymap[length] = '\0'; + + break; + } + } + } + + pclose(setxkbmap); + + return keymap; +} + +uint32 freerdp_keyboard_init_x11(uint32 keyboardLayoutId) +{ + char* keymap; + uint32 vkcode; + uint32 keycode; + uint32 scancode; + boolean extended; + char* xkb_layout; + char* xkb_variant; + uint32 keycode_to_vkcode[256]; + + memset(keycode_to_vkcode, 0, sizeof(keycode_to_vkcode)); + memset(X11_KEYCODE_TO_RDP_SCANCODE, 0, sizeof(X11_KEYCODE_TO_RDP_SCANCODE)); + memset(RDP_SCANCODE_TO_X11_KEYCODE, 0, sizeof(RDP_SCANCODE_TO_X11_KEYCODE)); + + if (keyboardLayoutId == 0) + { + keyboardLayoutId = freerdp_detect_keyboard_layout_from_system_locale(); + DEBUG_KBD("using keyboard layout: %X", keyboardLayoutId); + } + + if (keyboardLayoutId == 0) + { + keyboardLayoutId = 0x0409; + DEBUG_KBD("using default keyboard layout: %X", keyboardLayoutId); + } + +#ifdef __APPLE__ + /* Apple X11 breaks XKB detection */ + freerdp_keyboard_load_map(keycode_to_vkcode, "macosx(macosx)"); +#else + if (keyboardLayoutId == 0) + keyboardLayoutId = freerdp_detect_keyboard_layout_from_xkb(&xkb_layout, &xkb_variant); + + keymap = freerdp_detect_keymap_from_xkb(); + + if (keymap != NULL) + freerdp_keyboard_load_maps(keycode_to_vkcode, keymap); +#endif + + for (keycode = 0; keycode < 256; keycode++) + { + vkcode = keycode_to_vkcode[keycode]; + + if (!(vkcode > 0 && vkcode < 256)) + continue; + + scancode = VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[vkcode]; + extended = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode].extended; + + X11_KEYCODE_TO_RDP_SCANCODE[keycode].code = scancode; + X11_KEYCODE_TO_RDP_SCANCODE[keycode].extended = extended; + + if (extended) + RDP_SCANCODE_TO_X11_KEYCODE[scancode][1] = keycode; + else + RDP_SCANCODE_TO_X11_KEYCODE[scancode][0] = keycode; + } + + return keyboardLayoutId; +}