--- sourceforge.net/trunk/rdesktop/xkeymap.c 2003/02/18 13:02:58 327 +++ sourceforge.net/trunk/rdesktop/xkeymap.c 2004/06/01 08:00:58 705 @@ -1,7 +1,9 @@ /* rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping + Copyright (C) Matthew Chapman 1999-2002 + Copyright (C) Peter Astrand 2003 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 @@ -12,15 +14,19 @@ 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 @@ -31,15 +37,20 @@ #define KEYMAP_MASK 0xffff #define KEYMAP_MAX_LINE_LENGTH 80 -extern Display *display; +extern Display *g_display; +extern Window g_wnd; extern char keymapname[16]; extern int keylayout; -extern BOOL enable_compose; +extern int g_win_button_size; +extern BOOL g_enable_compose; +extern BOOL g_use_rdp5; +extern BOOL g_numlock_sync; static 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); @@ -135,7 +146,7 @@ if (strncmp(line, "enable_compose", 15) == 0) { DEBUG_KBD(("Enabling compose handling\n")); - enable_compose = True; + g_enable_compose = True; continue; } @@ -230,7 +241,56 @@ keymap_loaded = True; } - XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode); + XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode); +} + +static void +send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey) +{ + uint8 winkey; + + if (leftkey) + winkey = SCANCODE_CHAR_LWIN; + else + winkey = SCANCODE_CHAR_RWIN; + + if (pressed) + { + 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); + } + } +} + +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 @@ -263,6 +323,7 @@ } /* No release sequence */ return True; + break; case XK_Pause: /* According to MS Keyboard Scan Code @@ -289,24 +350,35 @@ 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: + /* FIXME: We might want to do RDP_INPUT_SYNCHRONIZE here, if g_numlock_sync */ + if (!g_numlock_sync) + /* Inhibit */ + return True; + break; + } return False; } @@ -347,7 +419,7 @@ warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); /* not in keymap, try to interpret the raw scancode */ - if ((keycode >= min_keycode) && (keycode <= 0x60)) + if (((int) keycode >= min_keycode) && (keycode <= 0x60)) { tr.scancode = keycode - min_keycode; @@ -402,12 +474,10 @@ return ksname; } - -void -ensure_remote_modifiers(uint32 ev_time, key_translation tr) +static BOOL +is_modifier(uint8 scancode) { - /* If this key is a modifier, do nothing */ - switch (tr.scancode) + switch (scancode) { case SCANCODE_CHAR_LSHIFT: case SCANCODE_CHAR_RSHIFT: @@ -418,34 +488,69 @@ case SCANCODE_CHAR_LWIN: case SCANCODE_CHAR_RWIN: case SCANCODE_CHAR_NUMLOCK: - return; + return True; default: break; } + return False; +} - /* NumLock */ - if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask) - != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask)) - { - /* The remote modifier state is not correct */ - uint16 new_remote_state; +void +save_remote_modifiers(uint8 scancode) +{ + if (is_modifier(scancode)) + return; - 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 + 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 */ + if (is_modifier(tr.scancode)) + return; + + if (!g_numlock_sync) + { + /* 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 +599,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,8 +656,13 @@ 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); } @@ -564,7 +704,7 @@ 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; newNumLockState = @@ -573,7 +713,6 @@ MASK_CHANGE_BIT(remote_modifier_state, MapNumLockMask, newNumLockState); } - break; } #ifdef WITH_DEBUG_KBD