--- sourceforge.net/trunk/rdesktop/xkeymap.c 2005/08/02 18:15:07 952 +++ sourceforge.net/trunk/rdesktop/xkeymap.c 2005/12/30 20:32:06 1035 @@ -1,4 +1,4 @@ -/* +/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping @@ -30,6 +30,7 @@ #include #include #include +#include #include "rdesktop.h" #include "scancodes.h" @@ -39,8 +40,11 @@ extern Display *g_display; extern Window g_wnd; -extern char keymapname[16]; -extern int g_keylayout; +extern char g_keymapname[16]; +extern unsigned int g_keylayout; +extern int g_keyboard_type; +extern int g_keyboard_subtype; +extern int g_keyboard_functionkeys; extern int g_win_button_size; extern BOOL g_enable_compose; extern BOOL g_use_rdp5; @@ -54,8 +58,8 @@ static void update_modifier_state(uint8 scancode, BOOL pressed); -/* Free key_translation structure, included linked list */ -void +/* Free key_translation structure, including linked list */ +static void free_key_translation(key_translation * ptr) { key_translation *next; @@ -155,12 +159,125 @@ DEBUG_KBD(("\n")); } +BOOL +xkeymap_from_locale(const char *locale) +{ + char *str, *ptr; + FILE *fp; + + /* Create a working copy */ + str = xstrdup(locale); + + /* Truncate at dot and at */ + ptr = strrchr(str, '.'); + if (ptr) + *ptr = '\0'; + ptr = strrchr(str, '@'); + if (ptr) + *ptr = '\0'; + + /* Replace _ with - */ + ptr = strrchr(str, '_'); + if (ptr) + *ptr = '-'; + + /* Convert to lowercase */ + ptr = str; + while (*ptr) + { + *ptr = tolower((int) *ptr); + ptr++; + } + + /* Try to open this keymap (da-dk) */ + fp = xkeymap_open(str); + if (fp == NULL) + { + /* Truncate at dash */ + ptr = strrchr(str, '-'); + if (ptr) + *ptr = '\0'; + + /* Try the short name (da) */ + fp = xkeymap_open(str); + } + + if (fp) + { + fclose(fp); + STRNCPY(g_keymapname, str, sizeof(g_keymapname)); + return True; + } + + return False; +} + + +/* Joins two path components. The result should be freed with + xfree(). */ +static char * +pathjoin(const char *a, const char *b) +{ + char *result; + result = xmalloc(PATH_MAX * 2 + 1); + + if (b[0] == '/') + { + strncpy(result, b, PATH_MAX); + } + else + { + strncpy(result, a, PATH_MAX); + strcat(result, "/"); + strncat(result, b, PATH_MAX); + } + return result; +} + +/* Try to open a keymap with fopen() */ +FILE * +xkeymap_open(const char *filename) +{ + char *path1, *path2; + char *home; + FILE *fp; + + /* Try ~/.rdesktop/keymaps */ + home = getenv("HOME"); + if (home) + { + path1 = pathjoin(home, ".rdesktop/keymaps"); + path2 = pathjoin(path1, filename); + xfree(path1); + fp = fopen(path2, "r"); + xfree(path2); + if (fp) + return fp; + } + + /* Try KEYMAP_PATH */ + path1 = pathjoin(KEYMAP_PATH, filename); + fp = fopen(path1, "r"); + xfree(path1); + if (fp) + return fp; + + /* Try current directory, in case we are running from the source + tree */ + path1 = pathjoin("keymaps", filename); + fp = fopen(path1, "r"); + xfree(path1); + if (fp) + return fp; + + return NULL; +} + static BOOL xkeymap_read(char *mapname) { FILE *fp; char line[KEYMAP_MAX_LINE_LENGTH]; - char path[PATH_MAX], inplace_path[PATH_MAX]; unsigned int line_num = 0; unsigned int line_length = 0; char *keyname, *p; @@ -168,23 +285,11 @@ uint8 scancode; uint16 modifiers; - - strcpy(path, KEYMAP_PATH); - strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH)); - - fp = fopen(path, "r"); + fp = xkeymap_open(mapname); if (fp == NULL) { - /* in case we are running from the source tree */ - strcpy(inplace_path, "keymaps/"); - strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/")); - - fp = fopen(inplace_path, "r"); - if (fp == NULL) - { - error("Failed to open keymap %s\n", path); - return False; - } + error("Failed to open keymap %s\n", mapname); + return False; } /* FIXME: More tolerant on white space */ @@ -206,23 +311,23 @@ } /* Include */ - if (strncmp(line, "include ", 8) == 0) + if (str_startswith(line, "include ")) { - if (!xkeymap_read(line + 8)) + if (!xkeymap_read(line + sizeof("include ") - 1)) return False; continue; } /* map */ - if (strncmp(line, "map ", 4) == 0) + if (str_startswith(line, "map ")) { - g_keylayout = strtol(line + 4, NULL, 16); + g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16); DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout)); continue; } /* compose */ - if (strncmp(line, "enable_compose", 15) == 0) + if (str_startswith(line, "enable_compose")) { DEBUG_KBD(("Enabling compose handling\n")); g_enable_compose = True; @@ -230,9 +335,35 @@ } /* sequence */ - if (strncmp(line, "sequence", 8) == 0) + if (str_startswith(line, "sequence")) { - add_sequence(line + 8, mapname); + add_sequence(line + sizeof("sequence") - 1, mapname); + continue; + } + + /* keyboard_type */ + if (str_startswith(line, "keyboard_type ")) + { + g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16); + DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type)); + continue; + } + + /* keyboard_subtype */ + if (str_startswith(line, "keyboard_subtype ")) + { + g_keyboard_subtype = + strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16); + DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype)); + continue; + } + + /* keyboard_functionkeys */ + if (str_startswith(line, "keyboard_functionkeys ")) + { + g_keyboard_functionkeys = + strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16); + DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys)); continue; } @@ -311,19 +442,10 @@ xkeymap_init(void) { unsigned int max_keycode; - char *mapname_ptr; - - /* Make keymapname lowercase */ - mapname_ptr = keymapname; - while (*mapname_ptr) - { - *mapname_ptr = tolower((int) *mapname_ptr); - mapname_ptr++; - } - if (strcmp(keymapname, "none")) + if (strcmp(g_keymapname, "none")) { - if (xkeymap_read(keymapname)) + if (xkeymap_read(g_keymapname)) keymap_loaded = True; } @@ -547,7 +669,7 @@ void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, - BOOL pressed) + BOOL pressed, uint8 nesting) { key_translation tr, *ptr; tr = xkeymap_translate_key(keysym, keycode, state); @@ -580,8 +702,15 @@ { DEBUG_KBD(("Handling sequence element, keysym=0x%x\n", (unsigned int) ptr->seq_keysym)); - xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True); - xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False); + + if (nesting++ > 32) + { + error("Sequence nesting too deep\n"); + return; + } + + xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting); + xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting); ptr = ptr->next; } while (ptr);