2 * FreeRDP: A Remote Desktop Protocol Implementation
5 * Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
28 #include <winpr/crt.h>
30 #include "liblocale.h"
32 #include <freerdp/locale/locale.h>
33 #include <freerdp/locale/keyboard.h>
35 #include "keyboard_x11.h"
36 #include "keyboard_keymap.h"
37 #include "xkb_layout_ids.h"
40 #include "keyboard_sun.h"
44 extern const RDP_SCANCODE VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[256];
47 UINT32 freerdp_detect_keyboard_layout_from_xkb(char** xkb_layout, char** xkb_variant)
56 UINT32 keyboardLayoutId = 0;
58 /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
60 xprop = popen("xprop -root _XKB_RULES_NAMES_BACKUP", "r");
62 /* Sample output for "Canadian Multilingual Standard"
64 * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multix", ""
65 * Where "xorg" is the set of rules
66 * "pc105" the keyboard type
67 * "ca" the keyboard layout
68 * "multi" the keyboard layout variant
71 while(fgets(buffer, sizeof(buffer), xprop) != NULL)
73 if((pch = strstr(buffer, "_XKB_RULES_NAMES_BACKUP(STRING) = ")) != NULL)
76 pch = strchr(&buffer[34], ','); // We assume it is xorg
80 pch = strchr(pch, ',');
83 beg = strchr(pch + 1, '"');
86 end = strchr(beg, '"');
92 beg = strchr(end + 1, '"');
95 end = strchr(beg, '"');
103 DEBUG_KBD("_XKB_RULES_NAMES_BACKUP layout: %s, variant: %s", layout, variant);
104 keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
106 if (keyboardLayoutId > 0)
108 *xkb_layout = _strdup(layout);
109 *xkb_variant = _strdup(variant);
110 return keyboardLayoutId;
113 /* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */
115 xprop = popen("xprop -root _XKB_RULES_NAMES", "r");
117 while(fgets(buffer, sizeof(buffer), xprop) != NULL)
119 if((pch = strstr(buffer, "_XKB_RULES_NAMES(STRING) = ")) != NULL)
122 pch = strchr(&buffer[27], ','); // We assume it is xorg
126 pch = strchr(pch, ',');
129 beg = strchr(pch + 1, '"');
132 end = strchr(beg, '"');
138 beg = strchr(end + 1, '"');
141 end = strchr(beg, '"');
149 DEBUG_KBD("_XKB_RULES_NAMES layout: %s, variant: %s", layout, variant);
150 keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
152 if (keyboardLayoutId > 0)
154 *xkb_layout = _strdup(layout);
155 *xkb_variant = _strdup(variant);
156 return keyboardLayoutId;
162 char* freerdp_detect_keymap_from_xkb()
172 /* this tells us about the current XKB configuration, if XKB is available */
173 setxkbmap = popen("setxkbmap -print", "r");
175 while (fgets(buffer, sizeof(buffer), setxkbmap) != NULL)
177 /* the line with xkb_keycodes is what interests us */
178 pch = strstr(buffer, "xkb_keycodes");
182 pch = strstr(pch, "include");
186 /* check for " " delimiter presence */
187 if ((beg = strchr(pch, '"')) == NULL)
192 if ((pch = strchr(beg + 1, '"')) == NULL)
195 end = strcspn(beg + 1, "\"") + beg + 1;
198 length = (end - beg);
199 keymap = (char*) malloc(length + 1);
200 strncpy(keymap, beg, length);
201 keymap[length] = '\0';
215 const UINT32 KEYCODE_TO_VKCODE_MACOSX[256] =
249 VK_OEM_PLUS, /* 32 */
252 VK_OEM_MINUS, /* 35 */
268 VK_OEM_COMMA, /* 51 */
272 VK_OEM_PERIOD, /* 55 */
284 VK_LCONTROL, /* 67 */
292 VK_MULTIPLY, /* 75 */
303 VK_SUBTRACT, /* 86 */
317 VK_NUMPAD9, /* 100 */
330 VK_SNAPSHOT, /* 113 */
477 UINT32 freerdp_keyboard_init_x11(UINT32 keyboardLayoutId, RDP_SCANCODE x11_keycode_to_rdp_scancode[256])
481 UINT32 keycode_to_vkcode[256];
483 ZeroMemory(keycode_to_vkcode, sizeof(keycode_to_vkcode));
484 ZeroMemory(x11_keycode_to_rdp_scancode, sizeof(RDP_SCANCODE) * 256);
487 /* Apple X11 breaks XKB detection */
489 CopyMemory(keycode_to_vkcode, KEYCODE_TO_VKCODE_MACOSX, sizeof(keycode_to_vkcode));
491 freerdp_keyboard_load_map(keycode_to_vkcode, "macosx(macosx)");
493 #elif defined(WITH_SUN)
497 freerdp_detect_keyboard_type_and_layout_solaris(sunkeymap, sizeof(sunkeymap));
498 freerdp_keyboard_load_map(keycode_to_vkcode, sunkeymap);
503 char* xkb_layout = 0;
504 char* xkb_variant = 0;
506 if (keyboardLayoutId == 0)
508 keyboardLayoutId = freerdp_detect_keyboard_layout_from_xkb(&xkb_layout, &xkb_variant);
516 keymap = freerdp_detect_keymap_from_xkb();
520 freerdp_keyboard_load_maps(keycode_to_vkcode, keymap);
526 for (keycode = 0; keycode < 256; keycode++)
528 vkcode = keycode_to_vkcode[keycode];
530 if (!(vkcode > 0 && vkcode < 256))
533 x11_keycode_to_rdp_scancode[keycode] = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode];
536 return keyboardLayoutId;