FreeRDP/libfreerdp-locale/keyboard_xkb.c
2012-02-18 22:04:28 -05:00

167 lines
4.1 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Client
* XKB-based Keyboard Mapping to Microsoft Keyboard System
*
* Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include "liblocale.h"
#include "keyboard_xkb.h"
#include "keyboard_x11.h"
#include <freerdp/locale/vkcodes.h>
extern const virtualKey virtualKeyboard[258];
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBfile.h>
#include <X11/extensions/XKBrules.h>
#include <freerdp/utils/memory.h>
void* freerdp_keyboard_xkb_init()
{
int status;
Display* display = XOpenDisplay(NULL);
if (display == NULL)
return NULL;
status = XkbQueryExtension(display, NULL, NULL, NULL, NULL, NULL);
if (!status)
return NULL;
return (void*) display;
}
/* return substring starting after nth comma, ending at following comma */
static char* comma_substring(char* s, int n)
{
char *p;
if (!s)
return "";
while (n-- > 0)
{
if (!(p = strchr(s, ',')))
break;
s = p + 1;
}
if ((p = strchr(s, ',')))
*p = 0;
return s;
}
uint32 detect_keyboard_layout_from_xkb(void* display)
{
char* layout;
char* variant;
uint32 group = 0;
uint32 keyboard_layout = 0;
XkbRF_VarDefsRec rules_names;
XKeyboardState coreKbdState;
XkbStateRec state;
DEBUG_KBD("display: %p", display);
if (display && XkbRF_GetNamesProp(display, NULL, &rules_names))
{
DEBUG_KBD("layouts: %s", rules_names.layout ? rules_names.layout : "");
DEBUG_KBD("variants: %s", rules_names.variant ? rules_names.variant : "");
XGetKeyboardControl(display, &coreKbdState);
if (XkbGetState(display, XkbUseCoreKbd, &state) == Success)
group = state.group;
DEBUG_KBD("group: %d", state.group);
layout = comma_substring(rules_names.layout, group);
variant = comma_substring(rules_names.variant, group);
DEBUG_KBD("layout: %s", layout ? layout : "");
DEBUG_KBD("variant: %s", variant ? variant : "");
keyboard_layout = find_keyboard_layout_in_xorg_rules(layout, variant);
xfree(rules_names.model);
xfree(rules_names.layout);
xfree(rules_names.variant);
xfree(rules_names.options);
}
return keyboard_layout;
}
int freerdp_keyboard_load_map_from_xkb(void* display, RdpScancodes x_keycode_to_rdp_scancode, uint8 rdp_scancode_to_x_keycode[256][2])
{
int status = 0;
XkbDescPtr xkb;
if (display && (xkb = XkbGetMap(display, 0, XkbUseCoreKbd)))
{
if (XkbGetNames(display, XkbKeyNamesMask, xkb) == Success)
{
int i, j;
char buf[5] = {42, 42, 42, 42, 0}; /* end-of-string at pos 5 */
for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
{
memcpy(buf, xkb->names->keys[i].name, 4);
j = sizeof(virtualKeyboard) / sizeof(virtualKeyboard[0]) - 1;
while (j >= 0)
{
if (virtualKeyboard[j].x_keyname && !strcmp(buf, virtualKeyboard[j].x_keyname))
break;
j--;
}
if (j >= 0)
{
DEBUG_KBD("X keycode %3d has keyname %-4s -> RDP scancode %d/%d",
i, buf, virtualKeyboard[j].extended, virtualKeyboard[j].scancode);
x_keycode_to_rdp_scancode[i].extended = virtualKeyboard[j].extended;
x_keycode_to_rdp_scancode[i].keycode = virtualKeyboard[j].scancode;
x_keycode_to_rdp_scancode[i].keyname = virtualKeyboard[j].x_keyname;
if (x_keycode_to_rdp_scancode[i].extended)
rdp_scancode_to_x_keycode[virtualKeyboard[j].scancode][1] = i;
else
rdp_scancode_to_x_keycode[virtualKeyboard[j].scancode][0] = i;
}
else
{
DEBUG_KBD("X key code %3d has keyname %-4s -> ??? - not found", i, buf);
}
}
status = 1;
}
XkbFreeKeyboard(xkb, 0, 1);
}
return status;
}