--- sourceforge.net/trunk/rdesktop/xkeymap.c 2003/02/04 15:54:58 310 +++ sourceforge.net/trunk/rdesktop/xkeymap.c 2007/05/03 04:53:39 1405 @@ -1,29 +1,36 @@ -/* +/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping - Copyright (C) Matthew Chapman 1999-2002 - + + 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 GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef RDP2VNC +#include "vnc/x11stubs.h" +#else #include -#define XK_MISCELLANY -#include +#include +#endif + #include #include #include +#include #include "rdesktop.h" #include "scancodes.h" @@ -31,46 +38,248 @@ #define KEYMAP_MASK 0xffff #define KEYMAP_MAX_LINE_LENGTH 80 -extern Display *display; -extern char keymapname[16]; -extern int keylayout; -extern BOOL enable_compose; +extern Display *g_display; +extern Window g_wnd; +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 RD_BOOL g_enable_compose; +extern RD_BOOL g_use_rdp5; +extern RD_BOOL g_numlock_sync; -static BOOL keymap_loaded; -static key_translation keymap[KEYMAP_SIZE]; +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 +free_key_translation(key_translation * ptr) +{ + key_translation *next; + + while (ptr) + { + next = ptr->next; + xfree(ptr); + ptr = next; + } +} static void add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname) { KeySym keysym; + key_translation *tr; keysym = XStringToKeysym(keyname); if (keysym == NoSymbol) { - warning("Bad keysym %s in keymap %s\n", keyname, mapname); + DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname)); return; } DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, " "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers)); - keymap[keysym & KEYMAP_MASK].scancode = scancode; - keymap[keysym & KEYMAP_MASK].modifiers = modifiers; + tr = (key_translation *) xmalloc(sizeof(key_translation)); + memset(tr, 0, sizeof(key_translation)); + tr->scancode = scancode; + tr->modifiers = modifiers; + free_key_translation(keymap[keysym & KEYMAP_MASK]); + keymap[keysym & KEYMAP_MASK] = tr; return; } +static void +add_sequence(char *rest, char *mapname) +{ + KeySym keysym; + key_translation *tr, **prev_next; + size_t chars; + char keyname[KEYMAP_MAX_LINE_LENGTH]; + + /* Skip over whitespace after the sequence keyword */ + chars = strspn(rest, " \t"); + rest += chars; + + /* Fetch the keysym name */ + chars = strcspn(rest, " \t\0"); + STRNCPY(keyname, rest, chars + 1); + rest += chars; + + keysym = XStringToKeysym(keyname); + if (keysym == NoSymbol) + { + DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname)); + return; + } + + + DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname)); + + free_key_translation(keymap[keysym & KEYMAP_MASK]); + prev_next = &keymap[keysym & KEYMAP_MASK]; + + while (*rest) + { + /* Skip whitespace */ + chars = strspn(rest, " \t"); + rest += chars; + + /* Fetch the keysym name */ + chars = strcspn(rest, " \t\0"); + STRNCPY(keyname, rest, chars + 1); + rest += chars; + + keysym = XStringToKeysym(keyname); + if (keysym == NoSymbol) + { + DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, + mapname)); + return; + } + + /* Allocate space for key_translation structure */ + tr = (key_translation *) xmalloc(sizeof(key_translation)); + memset(tr, 0, sizeof(key_translation)); + *prev_next = tr; + prev_next = &tr->next; + tr->seq_keysym = keysym; + + DEBUG_KBD(("0x%x, ", (unsigned int) keysym)); + } + DEBUG_KBD(("\n")); +} + +RD_BOOL +xkeymap_from_locale(const char *locale) +{ + char *str, *ptr; + FILE *fp; + + /* Create a working copy */ + str = xstrdup(locale); -static BOOL + /* 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 * +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 RD_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; @@ -78,23 +287,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 */ @@ -116,26 +313,59 @@ } /* 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 ")) { - keylayout = strtol(line + 4, NULL, 16); - DEBUG_KBD(("Keylayout 0x%x\n", keylayout)); + 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")); - enable_compose = True; + g_enable_compose = True; + continue; + } + + /* sequence */ + 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 ")) + { + g_keyboard_functionkeys = + strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16); + DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys)); continue; } @@ -198,7 +428,7 @@ /* Automatically add uppercase key, with same modifiers plus shift */ for (p = keyname; *p; p++) - *p = toupper((int)*p); + *p = toupper((int) *p); MASK_ADD_BITS(modifiers, MapLeftShiftMask); add_to_keymap(keyname, scancode, modifiers, mapname); } @@ -214,29 +444,68 @@ xkeymap_init(void) { unsigned int max_keycode; - char *mapname_ptr; - /* Make keymapname lowercase */ - mapname_ptr = keymapname; - while (*mapname_ptr) + if (strcmp(g_keymapname, "none")) { - *mapname_ptr = tolower((int)*mapname_ptr); - mapname_ptr++; + if (xkeymap_read(g_keymapname)) + keymap_loaded = True; } - if (strcmp(keymapname, "none")) + XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode); +} + +static void +send_winkey(uint32 ev_time, RD_BOOL pressed, RD_BOOL leftkey) +{ + uint8 winkey; + + if (leftkey) + winkey = SCANCODE_CHAR_LWIN; + else + winkey = SCANCODE_CHAR_RWIN; + + if (pressed) { - if (xkeymap_read(keymapname)) - keymap_loaded = True; + if (g_use_rdp5) + { + rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey); + } + else + { + /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */ + rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL); + rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC); + } + } + else + { + /* key released */ + if (g_use_rdp5) + { + rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey); + } + else + { + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC); + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL); + } } +} - XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode); +static void +reset_winkey(uint32 ev_time) +{ + if (g_use_rdp5) + { + /* For some reason, it seems to suffice to release + *either* the left or right winkey. */ + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN); + } } -/* Handles, for example, multi-scancode keypresses (which is not - possible via keymap-files) */ -BOOL -handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed) +/* Handle special key combinations */ +RD_BOOL +handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed) { switch (keysym) { @@ -263,6 +532,7 @@ } /* No release sequence */ return True; + break; case XK_Pause: /* According to MS Keyboard Scan Code @@ -289,24 +559,44 @@ 0x1d, 0); } return True; + break; case XK_Meta_L: /* Windows keys */ case XK_Super_L: case XK_Hyper_L: + send_winkey(ev_time, pressed, True); + return True; + break; + case XK_Meta_R: case XK_Super_R: case XK_Hyper_R: - if (pressed) - { - rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL); - rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC); - } - else - { - rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC); - rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL); - } + send_winkey(ev_time, pressed, False); + return True; + break; + + case XK_space: + /* Prevent access to the Windows system menu in single app mode */ + if (g_win_button_size + && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))) + return True; + break; + + case XK_Num_Lock: + /* Synchronize on key release */ + if (g_numlock_sync && !pressed) + rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, + ui_get_numlock_state(read_keyboard_state()), 0); + + /* Inhibit */ return True; + break; + case XK_Overlay1_Enable: + /* Toggle SeamlessRDP */ + if (pressed) + ui_seamless_toggle(); + break; + } return False; } @@ -315,58 +605,159 @@ key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state) { - key_translation tr = { 0, 0 }; + key_translation tr = { 0, 0, 0, 0 }; + key_translation *ptr; - tr = keymap[keysym & KEYMAP_MASK]; - - if (tr.modifiers & MapInhibitMask) + ptr = keymap[keysym & KEYMAP_MASK]; + if (ptr) { - DEBUG_KBD(("Inhibiting key\n")); - tr.scancode = 0; - return tr; - } + tr = *ptr; + if (tr.seq_keysym == 0) /* Normal scancode translation */ + { + if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask)) + { + DEBUG_KBD(("Inhibiting key\n")); + tr.scancode = 0; + return tr; + } + + 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 (MASK_HAS_BITS(state, ShiftMask)) + { + tr.modifiers = MapLeftShiftMask; + } + } - if (tr.modifiers & MapLocalStateMask) + /* 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(("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", + tr.scancode, tr.modifiers)); + } + } + else { - /* The modifiers to send for this key should be obtained - from the local state. Currently, only shift is implemented. */ - if (state & ShiftMask) + if (keymap_loaded) + warning("No translation for (keysym 0x%lx, %s)\n", keysym, + get_ksname(keysym)); + + /* not in keymap, try to interpret the raw scancode */ + if (((int) keycode >= min_keycode) && (keycode <= 0x60)) + { + tr.scancode = keycode - min_keycode; + + /* The modifiers to send for this key should be + obtained from the local state. Currently, only + shift is implemented. */ + if (MASK_HAS_BITS(state, ShiftMask)) + { + tr.modifiers = MapLeftShiftMask; + } + + DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); + } + else { - tr.modifiers = MapLeftShiftMask; + DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); } } - if (tr.scancode != 0) + return tr; +} + +static RD_BOOL +is_modifier(uint8 scancode) +{ + switch (scancode) { - DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n", - tr.scancode, tr.modifiers)); - return tr; + case SCANCODE_CHAR_LSHIFT: + case SCANCODE_CHAR_RSHIFT: + case SCANCODE_CHAR_LCTRL: + case SCANCODE_CHAR_RCTRL: + case SCANCODE_CHAR_LALT: + case SCANCODE_CHAR_RALT: + case SCANCODE_CHAR_LWIN: + case SCANCODE_CHAR_RWIN: + case SCANCODE_CHAR_NUMLOCK: + return True; + default: + break; } + return False; +} - if (keymap_loaded) - warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); +static void +save_remote_modifiers_if_modifier(uint8 scancode) +{ + if (!is_modifier(scancode)) + return; - /* not in keymap, try to interpret the raw scancode */ - if ((keycode >= min_keycode) && (keycode <= 0x60)) + saved_remote_modifier_state = remote_modifier_state; +} + +void +xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, + RD_BOOL pressed, uint8 nesting) +{ + key_translation tr, *ptr; + tr = xkeymap_translate_key(keysym, keycode, state); + + if (tr.seq_keysym == 0) { - tr.scancode = keycode - min_keycode; + /* Scancode translation */ + if (tr.scancode == 0) + return; - /* The modifiers to send for this key should be - obtained from the local state. Currently, only - shift is implemented. */ - if (state & ShiftMask) + if (pressed) { - tr.modifiers = MapLeftShiftMask; + save_remote_modifiers(tr.scancode); + ensure_remote_modifiers(ev_time, tr); + rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode); } - - DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); + else + { + rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode); + restore_remote_modifiers(ev_time, tr.scancode); + save_remote_modifiers_if_modifier(tr.scancode); + } + return; } - else + + /* Sequence, only on key down */ + if (pressed) { - DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); - } + ptr = &tr; + do + { + DEBUG_KBD(("Handling sequence element, keysym=0x%x\n", + (unsigned int) ptr->seq_keysym)); - return tr; + 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); + } } uint16 @@ -402,50 +793,62 @@ return ksname; } +void +save_remote_modifiers(uint8 scancode) +{ + if (is_modifier(scancode)) + return; + + saved_remote_modifier_state = remote_modifier_state; +} + +void +restore_remote_modifiers(uint32 ev_time, uint8 scancode) +{ + key_translation dummy; + + if (is_modifier(scancode)) + return; + + dummy.scancode = 0; + dummy.modifiers = saved_remote_modifier_state; + ensure_remote_modifiers(ev_time, dummy); +} void ensure_remote_modifiers(uint32 ev_time, key_translation tr) { /* If this key is a modifier, do nothing */ - switch (tr.scancode) - { - case SCANCODE_CHAR_LSHIFT: - case SCANCODE_CHAR_RSHIFT: - case SCANCODE_CHAR_LCTRL: - case SCANCODE_CHAR_RCTRL: - case SCANCODE_CHAR_LALT: - case SCANCODE_CHAR_RALT: - case SCANCODE_CHAR_LWIN: - case SCANCODE_CHAR_RWIN: - case SCANCODE_CHAR_NUMLOCK: - return; - default: - break; - } + if (is_modifier(tr.scancode)) + return; - /* NumLock */ - if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask) - != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask)) + if (!g_numlock_sync) { - /* The remote modifier state is not correct */ - uint16 new_remote_state; - - if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)) - { - DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n")); - new_remote_state = KBD_FLAG_NUMLOCK; - remote_modifier_state = MapNumLockMask; - } - else + /* NumLock */ + if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask) + != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask)) { - DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n")); - new_remote_state = 0; - remote_modifier_state = 0; - } + /* The remote modifier state is not correct */ + uint16 new_remote_state; + + if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)) + { + DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n")); + new_remote_state = KBD_FLAG_NUMLOCK; + remote_modifier_state = MapNumLockMask; + } + else + { + DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n")); + new_remote_state = 0; + remote_modifier_state = 0; + } - rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0); + rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0); + } } + /* Shift. Left shift and right shift are treated as equal; either is fine. */ if (MASK_HAS_BITS(tr.modifiers, MapShiftMask) != MASK_HAS_BITS(remote_modifier_state, MapShiftMask)) @@ -494,9 +897,39 @@ } +unsigned int +read_keyboard_state() +{ +#ifdef RDP2VNC + return 0; +#else + unsigned int state; + Window wdummy; + int dummy; + + XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); + return state; +#endif +} + + +uint16 +ui_get_numlock_state(unsigned int state) +{ + uint16 numlock_state = 0; + + if (get_key_state(state, XK_Num_Lock)) + numlock_state = KBD_FLAG_NUMLOCK; + + return numlock_state; +} + + void -reset_modifier_keys(unsigned int state) +reset_modifier_keys() { + unsigned int state = read_keyboard_state(); + /* reset keys */ uint32 ev_time; ev_time = time(NULL); @@ -521,13 +954,19 @@ rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT); if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) && - !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)) + !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch) + && !get_key_state(state, XK_ISO_Level3_Shift)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT); + + reset_winkey(ev_time); + + if (g_numlock_sync) + rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0); } 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; @@ -564,16 +1003,15 @@ case SCANCODE_CHAR_NUMLOCK: /* KeyReleases for NumLocks are sent immediately. Toggle the modifier state only on Keypress */ - if (pressed) + if (pressed && !g_numlock_sync) { - BOOL newNumLockState; + RD_BOOL newNumLockState; newNumLockState = (MASK_HAS_BITS (remote_modifier_state, MapNumLockMask) == False); MASK_CHANGE_BIT(remote_modifier_state, MapNumLockMask, newNumLockState); } - break; } #ifdef WITH_DEBUG_KBD