--- sourceforge.net/trunk/rdesktop/xkeymap.c 2002/07/31 06:49:34 85 +++ sourceforge.net/trunk/rdesktop/xkeymap.c 2002/09/26 14:26:46 207 @@ -1,7 +1,7 @@ /* rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping - Copyright (C) Matthew Chapman 1999-2001 + Copyright (C) Matthew Chapman 1999-2002 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 @@ -19,12 +19,11 @@ */ #include -#include -#include -#include -#include +#define XK_MISCELLANY +#include #include #include +#include #include "rdesktop.h" #include "scancodes.h" @@ -37,10 +36,13 @@ extern int keylayout; extern BOOL enable_compose; +static BOOL keymap_loaded; static key_translation keymap[KEYMAP_SIZE]; static int min_keycode; static uint16 remote_modifier_state = 0; +static void update_modifier_state(uint8 scancode, BOOL pressed); + static void add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname) { @@ -175,6 +177,11 @@ MASK_ADD_BITS(modifiers, MapLocalStateMask); } + if (strstr(line_rest, "inhibit")) + { + MASK_ADD_BITS(modifiers, MapInhibitMask); + } + add_to_keymap(keyname, scancode, modifiers, mapname); if (strstr(line_rest, "addupper")) @@ -195,40 +202,115 @@ /* Before connecting and creating UI */ void -xkeymap_init1(void) +xkeymap_init(void) { - int i; - - /* Zeroing keymap */ - for (i = 0; i < KEYMAP_SIZE; i++) - { - keymap[i].scancode = 0; - keymap[i].modifiers = 0; - } + unsigned int max_keycode; if (strcmp(keymapname, "none")) { - xkeymap_read(keymapname); + if (xkeymap_read(keymapname)) + keymap_loaded = True; } + XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode); } -/* After connecting and creating UI */ -void -xkeymap_init2(void) +/* 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) { - unsigned int max_keycode; - XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode); + switch (keysym) + { + case XK_Break: + if (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)) + { + /* toggle full screen */ + if (pressed) + xwin_toggle_fullscreen(); + + } + else + { + /* Send Break sequence E0 46 E0 C6 */ + if (pressed) + { + rdp_send_scancode(ev_time, RDP_KEYPRESS, + (SCANCODE_EXTENDED | 0x46)); + rdp_send_scancode(ev_time, RDP_KEYPRESS, + (SCANCODE_EXTENDED | 0xc6)); + } + /* No break sequence */ + } + + return True; + break; + + case XK_Pause: + /* According to MS Keyboard Scan Code + Specification, pressing Pause should result + in E1 1D 45 E1 9D C5. I'm not exactly sure + of how this is supposed to be sent via + RDP. The code below seems to work, but with + the side effect that Left Ctrl stays + down. Therefore, we release it when Pause + is released. */ + if (pressed) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0); + } + else + { + /* Release Left Ctrl */ + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, + 0); + } + + return True; + break; + + case XK_Meta_L: /* Windows keys */ + case XK_Super_L: + case XK_Hyper_L: + 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); + } + return True; + break; + } + return False; } key_translation -xkeymap_translate_key(KeySym keysym, unsigned int keycode, unsigned int state) +xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state) { key_translation tr = { 0, 0 }; tr = keymap[keysym & KEYMAP_MASK]; + if (tr.modifiers & MapInhibitMask) + { + DEBUG_KBD(("Inhibiting key\n")); + tr.scancode = 0; + return tr; + } + if (tr.modifiers & MapLocalStateMask) { /* The modifiers to send for this key should be obtained @@ -241,23 +323,32 @@ if (tr.scancode != 0) { - DEBUG_KBD - (("Found key translation, scancode=0x%x, modifiers=0x%x\n", - tr.scancode, tr.modifiers)); + DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n", + tr.scancode, tr.modifiers)); return tr; } - printf("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); + if (keymap_loaded) + error("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)) { tr.scancode = keycode - min_keycode; - printf("Sending guessed scancode 0x%x\n", tr.scancode); + + /* The modifiers to send for this key should be + obtained from the local state. Currently, only + shift is implemented. */ + if (state & ShiftMask) + { + tr.modifiers = MapLeftShiftMask; + } + + DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); } else { - printf("No good guess for keycode 0x%x found\n", keycode); + DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); } return tr; @@ -284,7 +375,7 @@ } char * -get_ksname(KeySym keysym) +get_ksname(uint32 keysym) { char *ksname = NULL; @@ -296,22 +387,6 @@ return ksname; } -BOOL -inhibit_key(KeySym keysym) -{ - switch (keysym) - { - case XK_Caps_Lock: - return True; - break; - case XK_Multi_key: - return True; - break; - default: - break; - } - return False; -} void ensure_remote_modifiers(uint32 ev_time, key_translation tr) @@ -333,20 +408,30 @@ break; } - /* Shift */ + /* 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)) { /* The remote modifier state is not correct */ - if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)) + if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask)) { - /* Needs this modifier. Send down. */ + /* Needs left shift. Send down. */ rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT); } + else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask)) + { + /* Needs right shift. Send down. */ + rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT); + } else { - /* Should not use this modifier. Send up. */ - rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT); + /* Should not use this modifier. Send up for shift currently pressed. */ + if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)) + /* Left shift is down */ + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT); + else + /* Right shift is down */ + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT); } } @@ -372,31 +457,62 @@ != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask)) { /* The remote modifier state is not correct */ - DEBUG_KBD(("Remote NumLock state is incorrect. Toggling\n")); + uint16 new_remote_state = 0; + if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)) { - /* Needs this modifier. Toggle */ - rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_NUMLOCK); - rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_NUMLOCK); + DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n")); + new_remote_state |= KBD_FLAG_NUMLOCK; } else { - /* Should not use this modifier. Toggle */ - rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_NUMLOCK); - rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_NUMLOCK); + DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n")); } + + rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0); + update_modifier_state(SCANCODE_CHAR_NUMLOCK, True); } +} + +void +reset_modifier_keys(unsigned int state) +{ + /* reset keys */ + uint32 ev_time; + ev_time = time(NULL); + + if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask) && !get_key_state(state, XK_Shift_L)) + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT); + + if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask) && !get_key_state(state, XK_Shift_R)) + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT); + + if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask) && !get_key_state(state, XK_Control_L)) + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL); + + if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask) && !get_key_state(state, XK_Control_R)) + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL); + + if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L)) + 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)) + rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT); } static void -update_modifier_state(uint16 modifiers, BOOL pressed) +update_modifier_state(uint8 scancode, BOOL pressed) { +#ifdef WITH_DEBUG_KBD + uint16 old_modifier_state; + + old_modifier_state = remote_modifier_state; +#endif - DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n", - remote_modifier_state, pressed)); - switch (modifiers) + switch (scancode) { case SCANCODE_CHAR_LSHIFT: MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed); @@ -436,13 +552,21 @@ } break; } - DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state)); + +#ifdef WITH_DEBUG_KBD + if (old_modifier_state != remote_modifier_state) + { + DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n", + old_modifier_state, pressed)); + DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state)); + } +#endif } /* Send keyboard input */ void -rdp_send_scancode(uint32 time, uint16 flags, uint16 scancode) +rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode) { update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));