xfreerdp-server: add server-side keyboard mapping

This commit is contained in:
Marc-André Moreau 2012-01-08 20:32:50 -05:00
parent b20e76f7e4
commit 843ab55223
8 changed files with 131 additions and 105 deletions

View File

@ -36,6 +36,7 @@ typedef struct rdp_keyboard_layout
FREERDP_API rdpKeyboardLayout* freerdp_kbd_get_layouts(int types);
FREERDP_API uint32 freerdp_kbd_init(void *dpy, uint32 keyboard_layout_id);
FREERDP_API uint8 freerdp_kbd_get_scancode_by_keycode(uint8 keycode, boolean* extended);
FREERDP_API uint8 freerdp_kbd_get_keycode_by_scancode(uint8 scancode, boolean extended);
FREERDP_API uint8 freerdp_kbd_get_scancode_by_virtualkey(int vkcode, boolean* extended);
#endif /* __FREERDP_KBD_H */

View File

@ -231,10 +231,8 @@ static const keyboardIME keyboardIMEs[] =
rdpKeyboardLayout* get_keyboard_layouts(int types)
{
int num, len, i;
rdpKeyboardLayout * layouts;
int num;
int len;
int i;
num = 0;
layouts = (rdpKeyboardLayout *) malloc((num + 1) * sizeof(rdpKeyboardLayout));
@ -263,6 +261,7 @@ rdpKeyboardLayout* get_keyboard_layouts(int types)
{
len = sizeof(keyboardIMEs) / sizeof(keyboardIME);
layouts = (rdpKeyboardLayout *) realloc(layouts, (num + len + 1) * sizeof(rdpKeyboardLayout));
for (i = 0; i < len; i++, num++)
{
layouts[num].code = keyboardIMEs[i].code;
@ -278,22 +277,24 @@ rdpKeyboardLayout* get_keyboard_layouts(int types)
const char* get_layout_name(unsigned int keyboardLayoutID)
{
int i;
for(i = 0; i < sizeof(keyboardLayouts) / sizeof(keyboardLayout); i++)
if(keyboardLayouts[i].code == keyboardLayoutID)
{
for (i = 0; i < sizeof(keyboardLayouts) / sizeof(keyboardLayout); i++)
{
if (keyboardLayouts[i].code == keyboardLayoutID)
return keyboardLayouts[i].name;
}
}
for(i = 0; i < sizeof(keyboardLayoutVariants) / sizeof(keyboardLayoutVariant); i++)
if(keyboardLayoutVariants[i].code == keyboardLayoutID)
{
for (i = 0; i < sizeof(keyboardLayoutVariants) / sizeof(keyboardLayoutVariant); i++)
{
if (keyboardLayoutVariants[i].code == keyboardLayoutID)
return keyboardLayoutVariants[i].name;
}
}
for(i = 0; i < sizeof(keyboardIMEs) / sizeof(keyboardIME); i++)
if(keyboardIMEs[i].code == keyboardLayoutID)
{
for (i = 0; i < sizeof(keyboardIMEs) / sizeof(keyboardIME); i++)
{
if (keyboardIMEs[i].code == keyboardLayoutID)
return keyboardIMEs[i].name;
}
}
return "unknown";
}

View File

@ -106,7 +106,7 @@ unsigned int detect_keyboard_layout_from_xkb(void* dpy)
return keyboard_layout;
}
int init_keycodes_from_xkb(void *dpy, RdpKeycodes x_keycode_to_rdp_keycode)
int init_keycodes_from_xkb(void* dpy, RdpScancodes x_keycode_to_rdp_scancode, uint8 rdp_scancode_to_x_keycode[256][2])
{
int ret = 0;
XkbDescPtr xkb;
@ -115,35 +115,41 @@ int init_keycodes_from_xkb(void *dpy, RdpKeycodes x_keycode_to_rdp_keycode)
{
if (XkbGetNames(dpy, XkbKeyNamesMask, xkb) == Success)
{
char buf[5] = {42, 42, 42, 42, 0}; /* end-of-string at pos 5 */
int i, j;
char buf[5] = {42, 42, 42, 42, 0}; /* end-of-string at pos 5 */
memset(x_keycode_to_rdp_keycode, 0, sizeof(x_keycode_to_rdp_keycode));
for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
{
memcpy(buf, xkb->names->keys[i].name, 4);
/* TODO: Use more efficient search ... but it is so fast that it doesn't matter */
j = sizeof(virtualKeyboard) / sizeof(virtualKeyboard[0]) - 1;
while (j >= 0)
{
if (virtualKeyboard[j].x_keyname &&
!strcmp(buf, virtualKeyboard[j].x_keyname))
if (virtualKeyboard[j].x_keyname && !strcmp(buf, virtualKeyboard[j].x_keyname))
break;
j--;
}
if (j >= 0)
{
DEBUG_KBD("X key code %3d has keyname %-4s -> RDP keycode %d/%d",
DEBUG_KBD("X keycode %3d has keyname %-4s -> RDP scancode %d/%d",
i, buf, virtualKeyboard[j].extended, virtualKeyboard[j].scancode);
x_keycode_to_rdp_keycode[i].extended = virtualKeyboard[j].extended;
x_keycode_to_rdp_keycode[i].keycode = virtualKeyboard[j].scancode;
#ifdef WITH_DEBUG_KBD
x_keycode_to_rdp_keycode[i].keyname = virtualKeyboard[j].x_keyname;
#endif
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);
}
}
ret = 1;
}
@ -196,14 +202,13 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
beg = kbd;
/* Extract file name and keymap name */
if ((end = strrchr(kbd, '(')) != NULL)
{
strncpy(xkbfile, &kbd[beg - kbd], end - beg);
beg = end + 1;
if((end = strrchr(kbd, ')')) != NULL)
if ((end = strrchr(kbd, ')')) != NULL)
{
strncpy(xkbmap, &kbd[beg - kbd], end - beg);
xkbmap[end - beg] = '\0';
@ -228,36 +233,36 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
* when it is for reading only.
*/
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* Look first in path given at compile time (install path) */
snprintf(xkbfilepath, sizeof(xkbfilepath), "%s/%s", KEYMAP_PATH, xkbfile);
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* If ran from the source tree, the keymaps will be in the parent directory */
snprintf(xkbfilepath, sizeof(xkbfilepath), "../keymaps/%s", xkbfile);
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* File wasn't found in the source tree, try ~/.freerdp/ folder */
if((home = getenv("HOME")) == NULL)
if ((home = getenv("HOME")) == NULL)
return 0;
/* Get path to file in ~/.freerdp/ folder */
snprintf(xkbfilepath, sizeof(xkbfilepath), "%s/.freerdp/keymaps/%s", home, xkbfile);
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* Try /usr/share/freerdp folder */
snprintf(xkbfilepath, sizeof(xkbfilepath), "/usr/share/freerdp/keymaps/%s", xkbfile);
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* Try /usr/local/share/freerdp folder */
snprintf(xkbfilepath, sizeof(xkbfilepath), "/usr/local/share/freerdp/keymaps/%s", xkbfile);
if((fp = fopen(xkbfilepath, "r")) == NULL)
if ((fp = fopen(xkbfilepath, "r")) == NULL)
{
/* Error: Could not find keymap */
DEBUG_KBD("keymaps for %s not found", xkbfile);
@ -273,12 +278,12 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
while(fgets(buffer, sizeof(buffer), fp) != NULL)
{
if(buffer[0] == '#')
if (buffer[0] == '#')
{
continue; /* Skip comments */
}
if(kbdFound)
if (kbdFound)
{
/* Closing curly bracket and semicolon */
if ((pch = strstr(buffer, "};")) != NULL)
@ -296,12 +301,12 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
vkcodeName[end - beg] = '\0';
/* Now we want to extract the virtual key code itself which is in between '<' and '>' */
if((beg = strchr(pch + 3, '<')) == NULL)
if ((beg = strchr(pch + 3, '<')) == NULL)
break;
else
beg++;
if((end = strchr(beg, '>')) == NULL)
if ((end = strchr(beg, '>')) == NULL)
break;
/* We copy the string representing the number in a string */
@ -312,13 +317,13 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
keycode = atoi(keycodeString);
/* Make sure it is a valid keycode */
if(keycode < 0 || keycode > 255)
if (keycode < 0 || keycode > 255)
break;
/* Load this key mapping in the keyboard mapping */
for(i = 0; i < sizeof(virtualKeyboard) / sizeof(virtualKey); i++)
{
if(strcmp(vkcodeName, virtualKeyboard[i].name) == 0)
if (strcmp(vkcodeName, virtualKeyboard[i].name) == 0)
{
map[keycode] = i;
}
@ -351,14 +356,14 @@ static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
break;
beg++;
if((end = strchr(beg, '"')) == NULL)
if ((end = strchr(beg, '"')) == NULL)
break;
pch = beg;
buffer[end - beg] = '\0';
/* Does it match our keymap name? */
if(strncmp(xkbmap, pch, strlen(xkbmap)) == 0)
if (strncmp(xkbmap, pch, strlen(xkbmap)) == 0)
kbdFound = 1;
}
}

View File

@ -26,26 +26,18 @@ typedef struct
{
unsigned char extended;
unsigned char keycode;
#ifdef WITH_DEBUG_KBD
char *keyname;
#endif
} RdpKeycodeRec, RdpKeycodes[256];
char* keyname;
} RdpKeycodeRec, RdpScancodes[256];
#ifdef WITH_XKBFILE
int
init_xkb(void *dpy);
unsigned int
detect_keyboard_layout_from_xkb(void *dpy);
int
init_keycodes_from_xkb(void *dpy, RdpKeycodes x_keycode_to_rdp_keycode);
int init_xkb(void *dpy);
unsigned int detect_keyboard_layout_from_xkb(void *dpy);
int init_keycodes_from_xkb(void* dpy, RdpScancodes x_keycode_to_rdp_scancode, uint8 rdp_scancode_to_x_keycode[256][2]);
#else
void
load_keyboard_map(KeycodeToVkcode keycodeToVkcode, char *xkbfile);
void load_keyboard_map(KeycodeToVkcode keycodeToVkcode, char *xkbfile);
#endif

View File

@ -36,7 +36,9 @@
* but it only depends on which keycodes the X servers keyboard driver uses and is thus very static.
*/
RdpKeycodes x_keycode_to_rdp_keycode;
RdpScancodes x_keycode_to_rdp_scancode;
uint8 rdp_scancode_to_x_keycode[256][2];
#ifndef WITH_XKBFILE
@ -48,14 +50,14 @@ static unsigned int detect_keyboard(void* dpy, unsigned int keyboardLayoutID, ch
DEBUG_KBD("keyboard layout configuration: %X", keyboardLayoutID);
#if defined(sun)
if(keyboardLayoutID == 0)
if (keyboardLayoutID == 0)
{
keyboardLayoutID = detect_keyboard_type_and_layout_sunos(xkbfile, xkbfilelength);
DEBUG_KBD("detect_keyboard_type_and_layout_sunos: %X %s", keyboardLayoutID, xkbfile);
}
#endif
if(keyboardLayoutID == 0)
if (keyboardLayoutID == 0)
{
keyboardLayoutID = detect_keyboard_layout_from_locale();
DEBUG_KBD("detect_keyboard_layout_from_locale: %X", keyboardLayoutID);
@ -85,6 +87,9 @@ static unsigned int detect_keyboard(void* dpy, unsigned int keyboardLayoutID, ch
unsigned int freerdp_kbd_init(void* dpy, unsigned int keyboard_layout_id)
{
memset(x_keycode_to_rdp_scancode, 0, sizeof(x_keycode_to_rdp_scancode));
memset(rdp_scancode_to_x_keycode, '\0', sizeof(rdp_scancode_to_x_keycode));
#ifdef WITH_XKBFILE
if (!init_xkb(dpy))
{
@ -96,11 +101,12 @@ unsigned int freerdp_kbd_init(void* dpy, unsigned int keyboard_layout_id)
keyboard_layout_id = detect_keyboard_layout_from_xkb(dpy);
DEBUG_KBD("detect_keyboard_layout_from_xkb: %X", keyboard_layout_id);
}
init_keycodes_from_xkb(dpy, x_keycode_to_rdp_keycode);
init_keycodes_from_xkb(dpy, x_keycode_to_rdp_scancode, rdp_scancode_to_x_keycode);
#else
int vkcode;
int keycode;
char xkbfile[256];
KeycodeToVkcode keycodeToVkcode;
int keycode;
if (keyboard_layout_id == 0)
keyboard_layout_id = detect_keyboard(dpy, keyboard_layout_id, xkbfile, sizeof(xkbfile));
@ -110,18 +116,22 @@ unsigned int freerdp_kbd_init(void* dpy, unsigned int keyboard_layout_id)
load_keyboard_map(keycodeToVkcode, xkbfile);
for (keycode=0; keycode<256; keycode++)
for (keycode = 0; keycode < 256; keycode++)
{
int vkcode;
vkcode = keycodeToVkcode[keycode];
DEBUG_KBD("X key code %3d VK %3d %-19s-> RDP keycode %d/%d",
DEBUG_KBD("X keycode %3d VK %3d %-19s-> RDP scancode %d/%d",
keycode, vkcode, virtualKeyboard[vkcode].name,
virtualKeyboard[vkcode].extended, virtualKeyboard[vkcode].scancode);
x_keycode_to_rdp_keycode[keycode].keycode = virtualKeyboard[vkcode].scancode;
x_keycode_to_rdp_keycode[keycode].extended = virtualKeyboard[vkcode].extended;
#ifdef WITH_DEBUG_KBD
x_keycode_to_rdp_keycode[keycode].keyname = virtualKeyboard[vkcode].name;
#endif
x_keycode_to_rdp_scancode[keycode].keycode = virtualKeyboard[vkcode].scancode;
x_keycode_to_rdp_scancode[keycode].extended = virtualKeyboard[vkcode].extended;
x_keycode_to_rdp_scancode[keycode].keyname = virtualKeyboard[vkcode].name;
if (x_keycode_to_rdp_scancode[keycode].extended)
rdp_scancode_to_x_keycode[virtualKeyboard[vkcode].scancode][1] = keycode;
else
rdp_scancode_to_x_keycode[virtualKeyboard[vkcode].scancode][0] = keycode;
}
#endif
@ -135,10 +145,20 @@ rdpKeyboardLayout* freerdp_kbd_get_layouts(int types)
uint8 freerdp_kbd_get_scancode_by_keycode(uint8 keycode, boolean* extended)
{
DEBUG_KBD("%2x %4s -> %d/%d", keycode, x_keycode_to_rdp_keycode[keycode].keyname,
x_keycode_to_rdp_keycode[keycode].extended, x_keycode_to_rdp_keycode[keycode].keycode);
*extended = x_keycode_to_rdp_keycode[keycode].extended;
return x_keycode_to_rdp_keycode[keycode].keycode;
DEBUG_KBD("%2x %4s -> %d/%d", keycode, x_keycode_to_rdp_scancode[keycode].keyname,
x_keycode_to_rdp_scancode[keycode].extended, x_keycode_to_rdp_scancode[keycode].keycode);
*extended = x_keycode_to_rdp_scancode[keycode].extended;
return x_keycode_to_rdp_scancode[keycode].keycode;
}
uint8 freerdp_kbd_get_keycode_by_scancode(uint8 scancode, boolean extended)
{
if (extended)
return rdp_scancode_to_x_keycode[scancode][1];
else
return rdp_scancode_to_x_keycode[scancode][0];
}
uint8 freerdp_kbd_get_scancode_by_virtualkey(int vkcode, boolean* extended)

View File

@ -423,24 +423,21 @@ static const localeAndKeyboardLayout defaultKeyboardLayouts[] =
unsigned int detect_keyboard_layout_from_locale()
{
int i;
int j;
int k;
int dot;
int i, j, k;
int underscore;
char language[4];
char country[10];
/* LANG = <language>_<country>.<encoding> */
char* envLang = getenv("LANG"); /* Get locale from environment variable LANG */
if(envLang == NULL)
if (envLang == NULL)
return 0; /* LANG environment variable was not set */
underscore = strcspn(envLang, "_");
if(underscore > 3)
if (underscore > 3)
return 0; /* The language name should not be more than 3 letters long */
else
{
@ -454,13 +451,13 @@ unsigned int detect_keyboard_layout_from_locale()
* In this case, use a U.S. keyboard and a U.S. keyboard layout
*/
if((strcmp(language, "C") == 0) || (strcmp(language, "POSIX") == 0))
if ((strcmp(language, "C") == 0) || (strcmp(language, "POSIX") == 0))
return ENGLISH_UNITED_STATES; /* U.S. Keyboard Layout */
dot = strcspn(envLang, ".");
/* Get country code */
if(dot > underscore)
if (dot > underscore)
{
strncpy(country, &envLang[underscore + 1], dot - underscore - 1);
country[dot - underscore - 1] = '\0';
@ -468,26 +465,26 @@ unsigned int detect_keyboard_layout_from_locale()
else
return 0; /* Invalid locale */
for(i = 0; i < sizeof(locales) / sizeof(locale); i++)
for (i = 0; i < sizeof(locales) / sizeof(locale); i++)
{
if((strcmp(language, locales[i].language) == 0) && (strcmp(country, locales[i].country) == 0))
if ((strcmp(language, locales[i].language) == 0) && (strcmp(country, locales[i].country) == 0))
break;
}
DEBUG_KBD("Found locale : %s_%s", locales[i].language, locales[i].country);
for(j = 0; j < sizeof(defaultKeyboardLayouts) / sizeof(localeAndKeyboardLayout); j++)
for (j = 0; j < sizeof(defaultKeyboardLayouts) / sizeof(localeAndKeyboardLayout); j++)
{
if(defaultKeyboardLayouts[j].locale == locales[i].code)
if (defaultKeyboardLayouts[j].locale == locales[i].code)
{
/* Locale found in list of default keyboard layouts */
for(k = 0; k < 5; k++)
for (k = 0; k < 5; k++)
{
if(defaultKeyboardLayouts[j].keyboardLayouts[k] == ENGLISH_UNITED_STATES)
if (defaultKeyboardLayouts[j].keyboardLayouts[k] == ENGLISH_UNITED_STATES)
{
continue; /* Skip, try to get a more localized keyboard layout */
}
else if(defaultKeyboardLayouts[j].keyboardLayouts[k] == 0)
else if (defaultKeyboardLayouts[j].keyboardLayouts[k] == 0)
{
break; /* No more keyboard layouts */
}
@ -502,7 +499,7 @@ unsigned int detect_keyboard_layout_from_locale()
* other possible keyboard layout for the locale, we end up here with k > 1
*/
if(k >= 1)
if (k >= 1)
return ENGLISH_UNITED_STATES;
else
return 0;

View File

@ -56,4 +56,5 @@ target_link_libraries(xfreerdp-server freerdp-core)
target_link_libraries(xfreerdp-server freerdp-codec)
target_link_libraries(xfreerdp-server freerdp-utils)
target_link_libraries(xfreerdp-server freerdp-gdi)
target_link_libraries(xfreerdp-server freerdp-kbd)
target_link_libraries(xfreerdp-server ${X11_LIBRARIES})

View File

@ -25,6 +25,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/select.h>
#include <freerdp/kbd/kbd.h>
#include <freerdp/codec/color.h>
#include <freerdp/utils/sleep.h>
#include <freerdp/utils/memory.h>
@ -177,6 +178,8 @@ xfInfo* xf_info_init()
xf_xdamage_init(xfi);
#endif
freerdp_kbd_init(xfi->display, 0);
return xfi;
}
@ -616,26 +619,32 @@ void xf_peer_synchronize_event(rdpInput* input, uint32 flags)
void xf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
{
freerdp_peer* client = (freerdp_peer*) input->context->peer;
rdpUpdate* update = client->update;
unsigned int keycode;
boolean extended = false;
xfPeerContext* xfp = (xfPeerContext*) input->context;
xfInfo* xfi = xfp->info;
printf("Client sent a keyboard event (flags:0x%X code:0x%X)\n", flags, code);
if ((flags & 0x4000) && code == 0x1F) /* 's' key */
if (flags & KBD_FLAGS_EXTENDED)
extended = true;
keycode = freerdp_kbd_get_keycode_by_scancode(code, extended);
printf("keycode: %d\n", keycode);
if (keycode != 0)
{
if (client->settings->width != 800)
{
client->settings->width = 800;
client->settings->height = 600;
}
else
{
client->settings->width = 640;
client->settings->height = 480;
}
update->DesktopResize(update->context);
xfp->activated = false;
#ifdef WITH_XTEST
pthread_mutex_lock(&(xfp->mutex));
if (flags & KBD_FLAGS_DOWN)
XTestFakeKeyEvent(xfi->display, keycode, True, 0);
else if (flags & KBD_FLAGS_RELEASE)
XTestFakeKeyEvent(xfi->display, keycode, False, 0);
pthread_mutex_unlock(&(xfp->mutex));
#endif
}
}