--- sourceforge.net/trunk/rdesktop/xkeymap.c 2005/08/03 08:41:02 960 +++ sourceforge.net/trunk/rdesktop/xkeymap.c 2007/01/08 04:47:06 1372 @@ -1,15 +1,15 @@ -/* +/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping - Copyright (C) Matthew Chapman 1999-2005 - Copyright (C) Peter Astrand 2003 - + Copyright (C) Matthew Chapman 1999-2007 + Copyright (C) Peter Astrand 2003-2007 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -30,6 +30,7 @@ #include #include #include +#include #include "rdesktop.h" #include "scancodes.h" @@ -39,20 +40,23 @@ 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; -extern BOOL g_numlock_sync; +extern RD_BOOL g_enable_compose; +extern RD_BOOL g_use_rdp5; +extern RD_BOOL g_numlock_sync; -static BOOL keymap_loaded; +static RD_BOOL keymap_loaded; static key_translation *keymap[KEYMAP_SIZE]; static int min_keycode; static uint16 remote_modifier_state = 0; static uint16 saved_remote_modifier_state = 0; -static void update_modifier_state(uint8 scancode, BOOL pressed); +static void update_modifier_state(uint8 scancode, RD_BOOL pressed); /* Free key_translation structure, including linked list */ static void @@ -155,6 +159,62 @@ DEBUG_KBD(("\n")); } +RD_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)); + xfree(str); + return True; + } + + xfree(str); + return False; +} + + /* Joins two path components. The result should be freed with xfree(). */ static char * @@ -215,7 +275,7 @@ return NULL; } -static BOOL +static RD_BOOL xkeymap_read(char *mapname) { FILE *fp; @@ -253,23 +313,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; @@ -277,9 +337,35 @@ } /* sequence */ - if (strncmp(line, "sequence", 8) == 0) + if (str_startswith(line, "sequence")) + { + 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 ")) { - add_sequence(line + 8, mapname); + g_keyboard_functionkeys = + strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16); + DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys)); continue; } @@ -358,19 +444,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; } @@ -378,7 +455,7 @@ } static void -send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey) +send_winkey(uint32 ev_time, RD_BOOL pressed, RD_BOOL leftkey) { uint8 winkey; @@ -427,8 +504,8 @@ } /* Handle special key combinations */ -BOOL -handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed) +RD_BOOL +handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed) { switch (keysym) { @@ -514,6 +591,11 @@ /* Inhibit */ return True; break; + case XK_Overlay1_Enable: + /* Toggle SeamlessRDP */ + if (pressed) + ui_seamless_toggle(); + break; } return False; @@ -532,30 +614,35 @@ tr = *ptr; if (tr.seq_keysym == 0) /* Normal scancode translation */ { - if (tr.modifiers & MapInhibitMask) + if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask)) { DEBUG_KBD(("Inhibiting key\n")); tr.scancode = 0; return tr; } - if (tr.modifiers & MapLocalStateMask) + if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask)) { /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ - if (state & ShiftMask) + if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } } - if ((tr.modifiers & MapLeftShiftMask) - && ((remote_modifier_state & MapLeftCtrlMask) - || (remote_modifier_state & MapRightCtrlMask)) - && get_key_state(state, XK_Caps_Lock)) + /* Windows interprets CapsLock+Ctrl+key + differently from Shift+Ctrl+key. Since we + are simulating CapsLock with Shifts, things + like Ctrl+f with CapsLock on breaks. To + solve this, we are releasing Shift if Ctrl + is on, but only if Shift isn't physically pressed. */ + if (MASK_HAS_BITS(tr.modifiers, MapShiftMask) + && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask) + && !MASK_HAS_BITS(state, ShiftMask)) { - DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n")); - tr.modifiers ^= MapLeftShiftMask; + DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n")); + MASK_REMOVE_BITS(tr.modifiers, MapShiftMask); } DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n", @@ -576,7 +663,7 @@ /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ - if (state & ShiftMask) + if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } @@ -594,7 +681,7 @@ void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, - BOOL pressed) + RD_BOOL pressed, uint8 nesting) { key_translation tr, *ptr; tr = xkeymap_translate_key(keysym, keycode, state); @@ -627,8 +714,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); @@ -668,7 +762,7 @@ return ksname; } -static BOOL +static RD_BOOL is_modifier(uint8 scancode) { switch (scancode) @@ -862,7 +956,7 @@ static void -update_modifier_state(uint8 scancode, BOOL pressed) +update_modifier_state(uint8 scancode, RD_BOOL pressed) { #ifdef WITH_DEBUG_KBD uint16 old_modifier_state; @@ -901,7 +995,7 @@ modifier state only on Keypress */ if (pressed && !g_numlock_sync) { - BOOL newNumLockState; + RD_BOOL newNumLockState; newNumLockState = (MASK_HAS_BITS (remote_modifier_state, MapNumLockMask) == False);