1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X keyboard mapping
5 Copyright (C) Matthew Chapman 1999-2005
6 Copyright (C) Peter Astrand <peter@cendio.se> 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "vnc/x11stubs.h"
27 #include <X11/keysym.h>
35 #include "scancodes.h"
37 #define KEYMAP_MASK 0xffff
38 #define KEYMAP_MAX_LINE_LENGTH 80
40 static void update_modifier_state(RDPCLIENT
* This
, uint8 scancode
, BOOL pressed
);
42 /* Free key_translation structure, including linked list */
44 free_key_translation(key_translation
* ptr
)
46 key_translation
*next
;
57 add_to_keymap(RDPCLIENT
* This
, char *keyname
, uint8 scancode
, uint16 modifiers
, char *mapname
)
62 keysym
= XStringToKeysym(keyname
);
63 if (keysym
== NoSymbol
)
65 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname
, mapname
));
69 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
70 "modifiers=0x%x\n", (unsigned int) keysym
, scancode
, modifiers
));
72 tr
= (key_translation
*) xmalloc(sizeof(key_translation
));
73 memset(tr
, 0, sizeof(key_translation
));
74 tr
->scancode
= scancode
;
75 tr
->modifiers
= modifiers
;
76 free_key_translation(This
->xkeymap
.keymap
[keysym
& KEYMAP_MASK
]);
77 This
->xkeymap
.keymap
[keysym
& KEYMAP_MASK
] = tr
;
83 add_sequence(RDPCLIENT
* This
, char *rest
, char *mapname
)
86 key_translation
*tr
, **prev_next
;
88 char keyname
[KEYMAP_MAX_LINE_LENGTH
];
90 /* Skip over whitespace after the sequence keyword */
91 chars
= strspn(rest
, " \t");
94 /* Fetch the keysym name */
95 chars
= strcspn(rest
, " \t\0");
96 STRNCPY(keyname
, rest
, chars
+ 1);
99 keysym
= XStringToKeysym(keyname
);
100 if (keysym
== NoSymbol
)
102 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname
, mapname
));
107 DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym
, keyname
));
109 free_key_translation(This
->xkeymap
.keymap
[keysym
& KEYMAP_MASK
]);
110 prev_next
= &This
->xkeymap
.keymap
[keysym
& KEYMAP_MASK
];
114 /* Skip whitespace */
115 chars
= strspn(rest
, " \t");
118 /* Fetch the keysym name */
119 chars
= strcspn(rest
, " \t\0");
120 STRNCPY(keyname
, rest
, chars
+ 1);
123 keysym
= XStringToKeysym(keyname
);
124 if (keysym
== NoSymbol
)
126 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname
,
131 /* Allocate space for key_translation structure */
132 tr
= (key_translation
*) xmalloc(sizeof(key_translation
));
133 memset(tr
, 0, sizeof(key_translation
));
135 prev_next
= &tr
->next
;
136 tr
->seq_keysym
= keysym
;
138 DEBUG_KBD(("0x%x, ", (unsigned int) keysym
));
144 xkeymap_from_locale(RDPCLIENT
* This
, const char *locale
)
149 /* Create a working copy */
150 str
= xstrdup(locale
);
152 /* Truncate at dot and at */
153 ptr
= strrchr(str
, '.');
156 ptr
= strrchr(str
, '@');
160 /* Replace _ with - */
161 ptr
= strrchr(str
, '_');
165 /* Convert to lowercase */
169 *ptr
= tolower((int) *ptr
);
173 /* Try to open this keymap (da-dk) */
174 fp
= xkeymap_open(str
);
177 /* Truncate at dash */
178 ptr
= strrchr(str
, '-');
182 /* Try the short name (da) */
183 fp
= xkeymap_open(str
);
189 STRNCPY(This
->keymapname
, str
, sizeof(This
->keymapname
));
199 /* Joins two path components. The result should be freed with
202 pathjoin(const char *a
, const char *b
)
205 result
= xmalloc(PATH_MAX
* 2 + 1);
209 strncpy(result
, b
, PATH_MAX
);
213 strncpy(result
, a
, PATH_MAX
);
215 strncat(result
, b
, PATH_MAX
);
220 /* Try to open a keymap with fopen() */
222 xkeymap_open(const char *filename
)
228 /* Try ~/.rdesktop/keymaps */
229 home
= getenv("HOME");
232 path1
= pathjoin(home
, ".rdesktop/keymaps");
233 path2
= pathjoin(path1
, filename
);
235 fp
= fopen(path2
, "r");
241 /* Try KEYMAP_PATH */
242 path1
= pathjoin(KEYMAP_PATH
, filename
);
243 fp
= fopen(path1
, "r");
248 /* Try current directory, in case we are running from the source
250 path1
= pathjoin("keymaps", filename
);
251 fp
= fopen(path1
, "r");
260 xkeymap_read(RDPCLIENT
* This
, char *mapname
)
263 char line
[KEYMAP_MAX_LINE_LENGTH
];
264 unsigned int line_num
= 0;
265 unsigned int line_length
= 0;
271 fp
= xkeymap_open(mapname
);
274 error("Failed to open keymap %s\n", mapname
);
278 /* FIXME: More tolerant on white space */
279 while (fgets(line
, sizeof(line
), fp
) != NULL
)
283 /* Replace the \n with \0 */
284 p
= strchr(line
, '\n');
288 line_length
= strlen(line
);
290 /* Completely empty line */
291 if (strspn(line
, " \t\n\r\f\v") == line_length
)
297 if (str_startswith(line
, "include "))
299 if (!xkeymap_read(This
, line
+ sizeof("include ") - 1))
305 if (str_startswith(line
, "map "))
307 This
->keylayout
= strtoul(line
+ sizeof("map ") - 1, NULL
, 16);
308 DEBUG_KBD(("Keylayout 0x%x\n", This
->keylayout
));
313 if (str_startswith(line
, "enable_compose"))
315 DEBUG_KBD(("Enabling compose handling\n"));
316 This
->enable_compose
= True
;
321 if (str_startswith(line
, "sequence"))
323 add_sequence(This
, line
+ sizeof("sequence") - 1, mapname
);
328 if (str_startswith(line
, "keyboard_type "))
330 This
->keyboard_type
= strtol(line
+ sizeof("keyboard_type ") - 1, NULL
, 16);
331 DEBUG_KBD(("keyboard_type 0x%x\n", This
->keyboard_type
));
335 /* keyboard_subtype */
336 if (str_startswith(line
, "keyboard_subtype "))
338 This
->keyboard_subtype
=
339 strtol(line
+ sizeof("keyboard_subtype ") - 1, NULL
, 16);
340 DEBUG_KBD(("keyboard_subtype 0x%x\n", This
->keyboard_subtype
));
344 /* keyboard_functionkeys */
345 if (str_startswith(line
, "keyboard_functionkeys "))
347 This
->keyboard_functionkeys
=
348 strtol(line
+ sizeof("keyboard_functionkeys ") - 1, NULL
, 16);
349 DEBUG_KBD(("keyboard_functionkeys 0x%x\n", This
->keyboard_functionkeys
));
361 p
= strchr(line
, ' ');
364 error("Bad line %d in keymap %s\n", line_num
, mapname
);
374 scancode
= strtol(p
, &line_rest
, 16);
377 /* FIXME: Should allow case-insensitive flag names.
378 Fix by using lex+yacc... */
380 if (strstr(line_rest
, "altgr"))
382 MASK_ADD_BITS(modifiers
, MapAltGrMask
);
385 if (strstr(line_rest
, "shift"))
387 MASK_ADD_BITS(modifiers
, MapLeftShiftMask
);
390 if (strstr(line_rest
, "numlock"))
392 MASK_ADD_BITS(modifiers
, MapNumLockMask
);
395 if (strstr(line_rest
, "localstate"))
397 MASK_ADD_BITS(modifiers
, MapLocalStateMask
);
400 if (strstr(line_rest
, "inhibit"))
402 MASK_ADD_BITS(modifiers
, MapInhibitMask
);
405 add_to_keymap(This
, keyname
, scancode
, modifiers
, mapname
);
407 if (strstr(line_rest
, "addupper"))
409 /* Automatically add uppercase key, with same modifiers
411 for (p
= keyname
; *p
; p
++)
412 *p
= toupper((int) *p
);
413 MASK_ADD_BITS(modifiers
, MapLeftShiftMask
);
414 add_to_keymap(This
, keyname
, scancode
, modifiers
, mapname
);
423 /* Before connecting and creating UI */
425 xkeymap_init(RDPCLIENT
* This
)
427 unsigned int max_keycode
;
429 if (strcmp(This
->keymapname
, "none"))
431 if (xkeymap_read(This
, This
->keymapname
))
432 This
->xkeymap
.keymap_loaded
= True
;
435 XDisplayKeycodes(This
->display
, &This
->xkeymap
.min_keycode
, (int *) &max_keycode
);
439 send_winkey(RDPCLIENT
* This
, uint32 ev_time
, BOOL pressed
, BOOL leftkey
)
444 winkey
= SCANCODE_CHAR_LWIN
;
446 winkey
= SCANCODE_CHAR_RWIN
;
452 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, winkey
);
456 /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
457 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, SCANCODE_CHAR_LCTRL
);
458 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, SCANCODE_CHAR_ESC
);
466 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, winkey
);
470 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_ESC
);
471 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LCTRL
);
477 reset_winkey(RDPCLIENT
* This
, uint32 ev_time
)
481 /* For some reason, it seems to suffice to release
482 *either* the left or right winkey. */
483 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LWIN
);
487 /* Handle special key combinations */
489 handle_special_keys(RDPCLIENT
* This
, uint32 keysym
, unsigned int state
, uint32 ev_time
, BOOL pressed
)
494 if ((get_key_state(This
, state
, XK_Alt_L
) || get_key_state(This
, state
, XK_Alt_R
))
495 && (get_key_state(This
, state
, XK_Control_L
)
496 || get_key_state(This
, state
, XK_Control_R
)))
498 /* Ctrl-Alt-Enter: toggle full screen */
500 xwin_toggle_fullscreen(This
);
506 /* Send Break sequence E0 46 E0 C6 */
509 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
,
510 (SCANCODE_EXTENDED
| 0x46));
511 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
,
512 (SCANCODE_EXTENDED
| 0xc6));
514 /* No release sequence */
519 /* According to MS Keyboard Scan Code
520 Specification, pressing Pause should result
521 in E1 1D 45 E1 9D C5. I'm not exactly sure
522 of how this is supposed to be sent via
523 RDP. The code below seems to work, but with
524 the side effect that Left Ctrl stays
525 down. Therefore, we release it when Pause
529 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0xe1, 0);
530 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0x1d, 0);
531 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0x45, 0);
532 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0xe1, 0);
533 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0x9d, 0);
534 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYPRESS
, 0xc5, 0);
538 /* Release Left Ctrl */
539 rdp_send_input(This
, ev_time
, RDP_INPUT_SCANCODE
, RDP_KEYRELEASE
,
545 case XK_Meta_L
: /* Windows keys */
548 send_winkey(This
, ev_time
, pressed
, True
);
555 send_winkey(This
, ev_time
, pressed
, False
);
560 /* Prevent access to the Windows system menu in single app mode */
561 if (This
->win_button_size
562 && (get_key_state(This
, state
, XK_Alt_L
) || get_key_state(This
, state
, XK_Alt_R
)))
567 /* Synchronize on key release */
568 if (This
->numlock_sync
&& !pressed
)
569 rdp_send_input(This
, 0, RDP_INPUT_SYNCHRONIZE
, 0,
570 ui_get_numlock_state(This
, read_keyboard_state(This
)), 0);
575 case XK_Overlay1_Enable
:
576 /* Toggle SeamlessRDP */
578 ui_seamless_toggle(This
);
587 xkeymap_translate_key(RDPCLIENT
* This
, uint32 keysym
, unsigned int keycode
, unsigned int state
)
589 key_translation tr
= { 0, 0, 0, 0 };
590 key_translation
*ptr
;
592 ptr
= This
->xkeymap
.keymap
[keysym
& KEYMAP_MASK
];
596 if (tr
.seq_keysym
== 0) /* Normal scancode translation */
598 if (MASK_HAS_BITS(tr
.modifiers
, MapInhibitMask
))
600 DEBUG_KBD(("Inhibiting key\n"));
605 if (MASK_HAS_BITS(tr
.modifiers
, MapLocalStateMask
))
607 /* The modifiers to send for this key should be obtained
608 from the local state. Currently, only shift is implemented. */
609 if (MASK_HAS_BITS(state
, ShiftMask
))
611 tr
.modifiers
= MapLeftShiftMask
;
615 /* Windows interprets CapsLock+Ctrl+key
616 differently from Shift+Ctrl+key. Since we
617 are simulating CapsLock with Shifts, things
618 like Ctrl+f with CapsLock on breaks. To
619 solve this, we are releasing Shift if Ctrl
620 is on, but only if Shift isn't physically pressed. */
621 if (MASK_HAS_BITS(tr
.modifiers
, MapShiftMask
)
622 && MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapCtrlMask
)
623 && !MASK_HAS_BITS(state
, ShiftMask
))
625 DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
626 MASK_REMOVE_BITS(tr
.modifiers
, MapShiftMask
);
629 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
630 tr
.scancode
, tr
.modifiers
));
635 if (This
->xkeymap
.keymap_loaded
)
636 warning("No translation for (keysym 0x%lx, %s)\n", keysym
,
639 /* not in keymap, try to interpret the raw scancode */
640 if (((int) keycode
>= This
->xkeymap
.min_keycode
) && (keycode
<= 0x60))
642 tr
.scancode
= keycode
- This
->xkeymap
.min_keycode
;
644 /* The modifiers to send for this key should be
645 obtained from the local state. Currently, only
646 shift is implemented. */
647 if (MASK_HAS_BITS(state
, ShiftMask
))
649 tr
.modifiers
= MapLeftShiftMask
;
652 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr
.scancode
));
656 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode
));
664 xkeymap_send_keys(RDPCLIENT
* This
, uint32 keysym
, unsigned int keycode
, unsigned int state
, uint32 ev_time
,
665 BOOL pressed
, uint8 nesting
)
667 key_translation tr
, *ptr
;
668 tr
= xkeymap_translate_key(This
, keysym
, keycode
, state
);
670 if (tr
.seq_keysym
== 0)
672 /* Scancode translation */
673 if (tr
.scancode
== 0)
678 save_remote_modifiers(This
, tr
.scancode
);
679 ensure_remote_modifiers(This
, ev_time
, tr
);
680 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, tr
.scancode
);
681 restore_remote_modifiers(This
, ev_time
, tr
.scancode
);
685 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, tr
.scancode
);
690 /* Sequence, only on key down */
696 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
697 (unsigned int) ptr
->seq_keysym
));
701 error("Sequence nesting too deep\n");
705 xkeymap_send_keys(This
, ptr
->seq_keysym
, keycode
, state
, ev_time
, True
, nesting
);
706 xkeymap_send_keys(This
, ptr
->seq_keysym
, keycode
, state
, ev_time
, False
, nesting
);
714 xkeymap_translate_button(unsigned int button
)
718 case Button1
: /* left */
719 return MOUSE_FLAG_BUTTON1
;
720 case Button2
: /* middle */
721 return MOUSE_FLAG_BUTTON3
;
722 case Button3
: /* right */
723 return MOUSE_FLAG_BUTTON2
;
724 case Button4
: /* wheel up */
725 return MOUSE_FLAG_BUTTON4
;
726 case Button5
: /* wheel down */
727 return MOUSE_FLAG_BUTTON5
;
734 get_ksname(uint32 keysym
)
738 if (keysym
== NoSymbol
)
740 else if (!(ksname
= XKeysymToString(keysym
)))
741 ksname
= "(no name)";
747 is_modifier(uint8 scancode
)
751 case SCANCODE_CHAR_LSHIFT
:
752 case SCANCODE_CHAR_RSHIFT
:
753 case SCANCODE_CHAR_LCTRL
:
754 case SCANCODE_CHAR_RCTRL
:
755 case SCANCODE_CHAR_LALT
:
756 case SCANCODE_CHAR_RALT
:
757 case SCANCODE_CHAR_LWIN
:
758 case SCANCODE_CHAR_RWIN
:
759 case SCANCODE_CHAR_NUMLOCK
:
768 save_remote_modifiers(RDPCLIENT
* This
, uint8 scancode
)
770 if (is_modifier(scancode
))
773 This
->xkeymap
.saved_remote_modifier_state
= This
->xkeymap
.remote_modifier_state
;
777 restore_remote_modifiers(RDPCLIENT
* This
, uint32 ev_time
, uint8 scancode
)
779 key_translation dummy
;
781 if (is_modifier(scancode
))
785 dummy
.modifiers
= This
->xkeymap
.saved_remote_modifier_state
;
786 ensure_remote_modifiers(This
, ev_time
, dummy
);
790 ensure_remote_modifiers(RDPCLIENT
* This
, uint32 ev_time
, key_translation tr
)
792 /* If this key is a modifier, do nothing */
793 if (is_modifier(tr
.scancode
))
796 if (!This
->numlock_sync
)
799 if (MASK_HAS_BITS(tr
.modifiers
, MapNumLockMask
)
800 != MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapNumLockMask
))
802 /* The remote modifier state is not correct */
803 uint16 new_remote_state
;
805 if (MASK_HAS_BITS(tr
.modifiers
, MapNumLockMask
))
807 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
808 new_remote_state
= KBD_FLAG_NUMLOCK
;
809 This
->xkeymap
.remote_modifier_state
= MapNumLockMask
;
813 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
814 new_remote_state
= 0;
815 This
->xkeymap
.remote_modifier_state
= 0;
818 rdp_send_input(This
, 0, RDP_INPUT_SYNCHRONIZE
, 0, new_remote_state
, 0);
823 /* Shift. Left shift and right shift are treated as equal; either is fine. */
824 if (MASK_HAS_BITS(tr
.modifiers
, MapShiftMask
)
825 != MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapShiftMask
))
827 /* The remote modifier state is not correct */
828 if (MASK_HAS_BITS(tr
.modifiers
, MapLeftShiftMask
))
830 /* Needs left shift. Send down. */
831 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, SCANCODE_CHAR_LSHIFT
);
833 else if (MASK_HAS_BITS(tr
.modifiers
, MapRightShiftMask
))
835 /* Needs right shift. Send down. */
836 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, SCANCODE_CHAR_RSHIFT
);
840 /* Should not use this modifier. Send up for shift currently pressed. */
841 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapLeftShiftMask
))
842 /* Left shift is down */
843 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LSHIFT
);
845 /* Right shift is down */
846 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_RSHIFT
);
851 if (MASK_HAS_BITS(tr
.modifiers
, MapAltGrMask
)
852 != MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapAltGrMask
))
854 /* The remote modifier state is not correct */
855 if (MASK_HAS_BITS(tr
.modifiers
, MapAltGrMask
))
857 /* Needs this modifier. Send down. */
858 rdp_send_scancode(This
, ev_time
, RDP_KEYPRESS
, SCANCODE_CHAR_RALT
);
862 /* Should not use this modifier. Send up. */
863 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_RALT
);
872 read_keyboard_state(RDPCLIENT
* This
)
881 XQueryPointer(This
->display
, This
->wnd
, &wdummy
, &wdummy
, &dummy
, &dummy
, &dummy
, &dummy
, &state
);
888 ui_get_numlock_state(RDPCLIENT
* This
, unsigned int state
)
890 uint16 numlock_state
= 0;
892 if (get_key_state(This
, state
, XK_Num_Lock
))
893 numlock_state
= KBD_FLAG_NUMLOCK
;
895 return numlock_state
;
900 reset_modifier_keys(RDPCLIENT
* This
)
902 unsigned int state
= read_keyboard_state(This
);
906 ev_time
= time(NULL
);
908 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapLeftShiftMask
)
909 && !get_key_state(This
, state
, XK_Shift_L
))
910 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LSHIFT
);
912 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapRightShiftMask
)
913 && !get_key_state(This
, state
, XK_Shift_R
))
914 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_RSHIFT
);
916 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapLeftCtrlMask
)
917 && !get_key_state(This
, state
, XK_Control_L
))
918 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LCTRL
);
920 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapRightCtrlMask
)
921 && !get_key_state(This
, state
, XK_Control_R
))
922 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_RCTRL
);
924 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapLeftAltMask
) && !get_key_state(This
, state
, XK_Alt_L
))
925 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_LALT
);
927 if (MASK_HAS_BITS(This
->xkeymap
.remote_modifier_state
, MapRightAltMask
) &&
928 !get_key_state(This
, state
, XK_Alt_R
) && !get_key_state(This
, state
, XK_Mode_switch
)
929 && !get_key_state(This
, state
, XK_ISO_Level3_Shift
))
930 rdp_send_scancode(This
, ev_time
, RDP_KEYRELEASE
, SCANCODE_CHAR_RALT
);
932 reset_winkey(This
, ev_time
);
934 if (This
->numlock_sync
)
935 rdp_send_input(This
, ev_time
, RDP_INPUT_SYNCHRONIZE
, 0, ui_get_numlock_state(This
, state
), 0);
940 update_modifier_state(RDPCLIENT
* This
, uint8 scancode
, BOOL pressed
)
942 #ifdef WITH_DEBUG_KBD
943 uint16 old_modifier_state
;
945 old_modifier_state
= This
->xkeymap
.remote_modifier_state
;
950 case SCANCODE_CHAR_LSHIFT
:
951 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapLeftShiftMask
, pressed
);
953 case SCANCODE_CHAR_RSHIFT
:
954 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapRightShiftMask
, pressed
);
956 case SCANCODE_CHAR_LCTRL
:
957 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapLeftCtrlMask
, pressed
);
959 case SCANCODE_CHAR_RCTRL
:
960 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapRightCtrlMask
, pressed
);
962 case SCANCODE_CHAR_LALT
:
963 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapLeftAltMask
, pressed
);
965 case SCANCODE_CHAR_RALT
:
966 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapRightAltMask
, pressed
);
968 case SCANCODE_CHAR_LWIN
:
969 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapLeftWinMask
, pressed
);
971 case SCANCODE_CHAR_RWIN
:
972 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
, MapRightWinMask
, pressed
);
974 case SCANCODE_CHAR_NUMLOCK
:
975 /* KeyReleases for NumLocks are sent immediately. Toggle the
976 modifier state only on Keypress */
977 if (pressed
&& !This
->numlock_sync
)
979 BOOL newNumLockState
;
982 (This
->xkeymap
.remote_modifier_state
, MapNumLockMask
) == False
);
983 MASK_CHANGE_BIT(This
->xkeymap
.remote_modifier_state
,
984 MapNumLockMask
, newNumLockState
);
988 #ifdef WITH_DEBUG_KBD
989 if (old_modifier_state
!= This
->xkeymap
.remote_modifier_state
)
991 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
992 old_modifier_state
, pressed
));
993 DEBUG_KBD(("After updating modifier_state:0x%x\n", This
->xkeymap
.remote_modifier_state
));
999 /* Send keyboard input */
1001 rdp_send_scancode(RDPCLIENT
* This
, uint32 time
, uint16 flags
, uint8 scancode
)
1003 update_modifier_state(This
, scancode
, !(flags
& RDP_KEYRELEASE
));
1005 if (scancode
& SCANCODE_EXTENDED
)
1007 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1008 scancode
& ~SCANCODE_EXTENDED
, flags
));
1009 rdp_send_input(This
, time
, RDP_INPUT_SCANCODE
, flags
| KBD_FLAG_EXT
,
1010 scancode
& ~SCANCODE_EXTENDED
, 0);
1014 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode
, flags
));
1015 rdp_send_input(This
, time
, RDP_INPUT_SCANCODE
, flags
, scancode
, 0);