Blame libfreerdp/locale/keyboard_x11.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X11 Keyboard Mapping
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/input.h>
Packit 1fb8d4
Packit 1fb8d4
#include "liblocale.h"
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/locale/locale.h>
Packit 1fb8d4
#include <freerdp/locale/keyboard.h>
Packit 1fb8d4
Packit 1fb8d4
#include "keyboard_x11.h"
Packit 1fb8d4
#include "xkb_layout_ids.h"
Packit 1fb8d4
Packit 1fb8d4
int freerdp_detect_keyboard_layout_from_xkb(DWORD* keyboardLayoutId)
Packit 1fb8d4
{
Packit 1fb8d4
	char* pch;
Packit 1fb8d4
	char* beg;
Packit 1fb8d4
	char* end;
Packit 1fb8d4
	FILE* xprop;
Packit 1fb8d4
	char buffer[1024];
Packit 1fb8d4
	char* layout = NULL;
Packit 1fb8d4
	char* variant = NULL;
Packit 1fb8d4
Packit 1fb8d4
	/* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
Packit 1fb8d4
Packit 1fb8d4
    if (!(xprop = popen("xprop -root _XKB_RULES_NAMES_BACKUP", "r")))
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	/* Sample output for "Canadian Multilingual Standard"
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multix", ""
Packit 1fb8d4
	 * Where "xorg" is the set of rules
Packit 1fb8d4
	 * "pc105" the keyboard type
Packit 1fb8d4
	 * "ca" the keyboard layout
Packit 1fb8d4
	 * "multi" the keyboard layout variant
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	while (fgets(buffer, sizeof(buffer), xprop) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((pch = strstr(buffer, "_XKB_RULES_NAMES_BACKUP(STRING) = ")) != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* "rules" */
Packit 1fb8d4
			pch = strchr(&buffer[34], ','); /* We assume it is xorg */
Packit 1fb8d4
			pch += 1;
Packit 1fb8d4
Packit 1fb8d4
			/* "type" */
Packit 1fb8d4
			pch = strchr(pch, ',');
Packit 1fb8d4
Packit 1fb8d4
			/* "layout" */
Packit 1fb8d4
			beg = strchr(pch + 1, '"');
Packit 1fb8d4
			beg += 1;
Packit 1fb8d4
Packit 1fb8d4
			end = strchr(beg, '"');
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
Packit 1fb8d4
			layout = beg;
Packit 1fb8d4
Packit 1fb8d4
			/* "variant" */
Packit 1fb8d4
			beg = strchr(end + 1, '"');
Packit 1fb8d4
			beg += 1;
Packit 1fb8d4
Packit 1fb8d4
			end = strchr(beg, '"');
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
Packit 1fb8d4
			variant = beg;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pclose(xprop);
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_KBD("_XKB_RULES_NAMES_BACKUP layout: %s, variant: %s", layout, variant);
Packit 1fb8d4
	*keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
Packit 1fb8d4
Packit 1fb8d4
	if (*keyboardLayoutId > 0)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	/* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */
Packit 1fb8d4
Packit 1fb8d4
	if (!(xprop = popen("xprop -root _XKB_RULES_NAMES", "r")))
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	while (fgets(buffer, sizeof(buffer), xprop) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((pch = strstr(buffer, "_XKB_RULES_NAMES(STRING) = ")) != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* "rules" */
Packit 1fb8d4
			pch = strchr(&buffer[27], ','); // We assume it is xorg
Packit 1fb8d4
			pch += 1;
Packit 1fb8d4
Packit 1fb8d4
			/* "type" */
Packit 1fb8d4
			pch = strchr(pch, ',');
Packit 1fb8d4
Packit 1fb8d4
			/* "layout" */
Packit 1fb8d4
			beg = strchr(pch + 1, '"');
Packit 1fb8d4
			beg += 1;
Packit 1fb8d4
Packit 1fb8d4
			end = strchr(beg, '"');
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
Packit 1fb8d4
			layout = beg;
Packit 1fb8d4
Packit 1fb8d4
			/* "variant" */
Packit 1fb8d4
			beg = strchr(end + 1, '"');
Packit 1fb8d4
			beg += 1;
Packit 1fb8d4
Packit 1fb8d4
			end = strchr(beg, '"');
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
Packit 1fb8d4
			variant = beg;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pclose(xprop);
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_KBD("_XKB_RULES_NAMES layout: %s, variant: %s", layout, variant);
Packit 1fb8d4
	*keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
Packit 1fb8d4
Packit 1fb8d4
	if (*keyboardLayoutId > 0)
Packit 1fb8d4
		return *keyboardLayoutId;
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char* freerdp_detect_keymap_from_xkb()
Packit 1fb8d4
{
Packit 1fb8d4
	char* pch;
Packit 1fb8d4
	char* beg;
Packit 1fb8d4
	char* end;
Packit 1fb8d4
	int length;
Packit 1fb8d4
	FILE* setxkbmap;
Packit 1fb8d4
	char buffer[1024];
Packit 1fb8d4
	char* keymap = NULL;
Packit 1fb8d4
Packit 1fb8d4
	/* this tells us about the current XKB configuration, if XKB is available */
Packit 1fb8d4
	setxkbmap = popen("setxkbmap -print", "r");
Packit 1fb8d4
Packit 1fb8d4
	if (!setxkbmap)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	while (fgets(buffer, sizeof(buffer), setxkbmap) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* the line with xkb_keycodes is what interests us */
Packit 1fb8d4
		pch = strstr(buffer, "xkb_keycodes");
Packit 1fb8d4
Packit 1fb8d4
		if (pch != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			pch = strstr(pch, "include");
Packit 1fb8d4
Packit 1fb8d4
			if (pch != NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* check for " " delimiter presence */
Packit 1fb8d4
				if ((beg = strchr(pch, '"')) == NULL)
Packit 1fb8d4
					break;
Packit 1fb8d4
				else
Packit 1fb8d4
					beg++;
Packit 1fb8d4
Packit 1fb8d4
				if ((pch = strchr(beg + 1, '"')) == NULL)
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				end = strcspn(beg + 1, "\"") + beg + 1;
Packit 1fb8d4
				*end = '\0';
Packit 1fb8d4
Packit 1fb8d4
				length = (end - beg);
Packit 1fb8d4
				keymap = (char*) malloc(length + 1);
Packit 1fb8d4
				if (keymap) {
Packit 1fb8d4
					strncpy(keymap, beg, length);
Packit 1fb8d4
					keymap[length] = '\0';
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pclose(setxkbmap);
Packit 1fb8d4
Packit 1fb8d4
	return keymap;
Packit 1fb8d4
}