2011-06-30 23:55:03 +04:00
|
|
|
/**
|
2012-02-20 05:24:06 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* X11 Keyboard Mapping
|
2011-06-30 23:55:03 +04:00
|
|
|
*
|
2012-02-20 05:24:06 +04:00
|
|
|
* Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2011-06-30 23:55:03 +04:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2012-08-15 01:09:01 +04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2011-06-30 23:55:03 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2012-10-09 07:42:01 +04:00
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
2012-02-19 07:04:28 +04:00
|
|
|
#include "liblocale.h"
|
2012-10-09 07:42:01 +04:00
|
|
|
|
2012-02-22 06:28:52 +04:00
|
|
|
#include <freerdp/utils/memory.h>
|
2012-02-20 05:24:06 +04:00
|
|
|
#include <freerdp/locale/locale.h>
|
2012-02-19 08:08:17 +04:00
|
|
|
#include <freerdp/locale/keyboard.h>
|
2011-06-30 23:55:03 +04:00
|
|
|
|
2012-02-19 07:04:28 +04:00
|
|
|
#include "keyboard_x11.h"
|
2012-03-24 04:57:09 +04:00
|
|
|
#include "keyboard_keymap.h"
|
2012-03-24 04:57:10 +04:00
|
|
|
#include "xkb_layout_ids.h"
|
2011-06-30 23:55:03 +04:00
|
|
|
|
2012-03-24 04:57:10 +04:00
|
|
|
#ifdef WITH_SUN
|
|
|
|
#include "keyboard_sun.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2012-02-22 05:56:34 +04:00
|
|
|
extern const RDP_SCANCODE VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[256];
|
2012-02-20 05:24:06 +04:00
|
|
|
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 freerdp_detect_keyboard_layout_from_xkb(char** xkb_layout, char** xkb_variant)
|
2012-02-22 06:28:52 +04:00
|
|
|
{
|
|
|
|
char* pch;
|
|
|
|
char* beg;
|
|
|
|
char* end;
|
|
|
|
FILE* xprop;
|
|
|
|
char buffer[1024];
|
|
|
|
char* layout = NULL;
|
|
|
|
char* variant = NULL;
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 keyboardLayoutId = 0;
|
2012-02-22 06:28:52 +04:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
2012-03-24 05:01:12 +04:00
|
|
|
while(fgets(buffer, sizeof(buffer), xprop) != NULL)
|
|
|
|
{
|
2012-02-22 06:28:52 +04:00
|
|
|
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;
|
|
|
|
}
|
2012-03-24 05:01:12 +04:00
|
|
|
}
|
|
|
|
pclose(xprop);
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-03-24 05:01:12 +04:00
|
|
|
DEBUG_KBD("_XKB_RULES_NAMES_BACKUP layout: %s, variant: %s", layout, variant);
|
2012-02-22 06:28:52 +04:00
|
|
|
keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
|
|
|
|
|
|
|
|
if (keyboardLayoutId > 0)
|
|
|
|
{
|
2012-10-09 07:42:01 +04:00
|
|
|
*xkb_layout = _strdup(layout);
|
|
|
|
*xkb_variant = _strdup(variant);
|
2012-02-22 06:28:52 +04:00
|
|
|
return keyboardLayoutId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */
|
|
|
|
|
2012-03-24 05:01:12 +04:00
|
|
|
xprop = popen("xprop -root _XKB_RULES_NAMES", "r");
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-03-24 05:01:12 +04:00
|
|
|
while(fgets(buffer, sizeof(buffer), xprop) != NULL)
|
|
|
|
{
|
2012-02-22 06:28:52 +04:00
|
|
|
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;
|
|
|
|
}
|
2012-03-24 05:01:12 +04:00
|
|
|
}
|
|
|
|
pclose(xprop);
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-03-24 05:01:12 +04:00
|
|
|
DEBUG_KBD("_XKB_RULES_NAMES layout: %s, variant: %s", layout, variant);
|
2012-02-22 06:28:52 +04:00
|
|
|
keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
|
|
|
|
|
|
|
|
if (keyboardLayoutId > 0)
|
|
|
|
{
|
2012-10-09 07:42:01 +04:00
|
|
|
*xkb_layout = _strdup(layout);
|
|
|
|
*xkb_variant = _strdup(variant);
|
2012-02-22 06:28:52 +04:00
|
|
|
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);
|
2012-10-09 07:21:26 +04:00
|
|
|
keymap = (char*) malloc(length + 1);
|
2012-02-22 06:28:52 +04:00
|
|
|
strncpy(keymap, beg, length);
|
|
|
|
keymap[length] = '\0';
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pclose(setxkbmap);
|
|
|
|
|
|
|
|
return keymap;
|
|
|
|
}
|
|
|
|
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 freerdp_keyboard_init_x11(UINT32 keyboardLayoutId, RDP_SCANCODE x11_keycode_to_rdp_scancode[256])
|
2012-02-20 05:24:06 +04:00
|
|
|
{
|
2012-10-09 11:26:39 +04:00
|
|
|
UINT32 vkcode;
|
|
|
|
UINT32 keycode;
|
|
|
|
UINT32 keycode_to_vkcode[256];
|
2012-02-20 05:24:06 +04:00
|
|
|
|
2012-02-20 21:25:45 +04:00
|
|
|
memset(keycode_to_vkcode, 0, sizeof(keycode_to_vkcode));
|
2012-03-24 04:57:10 +04:00
|
|
|
memset(x11_keycode_to_rdp_scancode, 0, sizeof(x11_keycode_to_rdp_scancode));
|
2012-02-20 05:24:06 +04:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
/* Apple X11 breaks XKB detection */
|
|
|
|
freerdp_keyboard_load_map(keycode_to_vkcode, "macosx(macosx)");
|
2012-03-24 04:57:10 +04:00
|
|
|
#elif defined(WITH_SUN)
|
2012-03-24 04:57:10 +04:00
|
|
|
{
|
2012-03-24 04:57:10 +04:00
|
|
|
char sunkeymap[32];
|
|
|
|
|
|
|
|
freerdp_detect_keyboard_type_and_layout_solaris(sunkeymap, sizeof(sunkeymap));
|
|
|
|
freerdp_keyboard_load_map(keycode_to_vkcode, sunkeymap);
|
2012-03-24 04:57:10 +04:00
|
|
|
}
|
2012-03-24 04:57:10 +04:00
|
|
|
#else
|
|
|
|
{
|
|
|
|
char* keymap;
|
|
|
|
char* xkb_layout;
|
|
|
|
char* xkb_variant;
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-03-24 04:57:10 +04:00
|
|
|
if (keyboardLayoutId == 0)
|
|
|
|
{
|
|
|
|
keyboardLayoutId = freerdp_detect_keyboard_layout_from_xkb(&xkb_layout, &xkb_variant);
|
2012-10-09 07:21:26 +04:00
|
|
|
free(xkb_layout);
|
|
|
|
free(xkb_variant);
|
2012-03-24 04:57:10 +04:00
|
|
|
}
|
2012-02-22 06:28:52 +04:00
|
|
|
|
2012-03-24 04:57:10 +04:00
|
|
|
keymap = freerdp_detect_keymap_from_xkb();
|
|
|
|
|
|
|
|
if (keymap != NULL)
|
|
|
|
{
|
|
|
|
freerdp_keyboard_load_maps(keycode_to_vkcode, keymap);
|
2012-10-09 07:21:26 +04:00
|
|
|
free(keymap);
|
2012-03-24 04:57:10 +04:00
|
|
|
}
|
2012-03-24 04:57:10 +04:00
|
|
|
}
|
2012-02-20 05:24:06 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (keycode = 0; keycode < 256; keycode++)
|
|
|
|
{
|
|
|
|
vkcode = keycode_to_vkcode[keycode];
|
|
|
|
|
2012-02-20 21:25:45 +04:00
|
|
|
if (!(vkcode > 0 && vkcode < 256))
|
|
|
|
continue;
|
|
|
|
|
2012-03-29 03:12:35 +04:00
|
|
|
x11_keycode_to_rdp_scancode[keycode] = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode];
|
2012-02-20 05:24:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return keyboardLayoutId;
|
|
|
|
}
|