/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 949 - (show annotations)
Tue Aug 2 15:07:35 2005 UTC (18 years, 10 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 20836 byte(s)
Implemented support for keyboard "sequences", which makes it possible to send multiple scancodes to the RDP server in response to one X11 keyboard event.

1 /*
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X keyboard mapping
4
5 Copyright (C) Matthew Chapman 1999-2005
6 Copyright (C) Peter Astrand <peter@cendio.se> 2003
7
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.
12
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.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef RDP2VNC
24 #include "vnc/x11stubs.h"
25 #else
26 #include <X11/Xlib.h>
27 #include <X11/keysym.h>
28 #endif
29
30 #include <ctype.h>
31 #include <limits.h>
32 #include <time.h>
33 #include "rdesktop.h"
34 #include "scancodes.h"
35
36 #define KEYMAP_SIZE 0xffff+1
37 #define KEYMAP_MASK 0xffff
38 #define KEYMAP_MAX_LINE_LENGTH 80
39
40 extern Display *g_display;
41 extern Window g_wnd;
42 extern char keymapname[16];
43 extern int g_keylayout;
44 extern int g_win_button_size;
45 extern BOOL g_enable_compose;
46 extern BOOL g_use_rdp5;
47 extern BOOL g_numlock_sync;
48
49 static BOOL keymap_loaded;
50 static key_translation *keymap[KEYMAP_SIZE];
51 static int min_keycode;
52 static uint16 remote_modifier_state = 0;
53 static uint16 saved_remote_modifier_state = 0;
54
55 static void update_modifier_state(uint8 scancode, BOOL pressed);
56
57 static void
58 add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
59 {
60 KeySym keysym;
61 key_translation *tr;
62
63 keysym = XStringToKeysym(keyname);
64 if (keysym == NoSymbol)
65 {
66 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
67 return;
68 }
69
70 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
71 "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
72
73 tr = (key_translation *) xmalloc(sizeof(key_translation));
74 memset(tr, 0, sizeof(key_translation));
75 tr->scancode = scancode;
76 tr->modifiers = modifiers;
77 keymap[keysym & KEYMAP_MASK] = tr;
78
79 return;
80 }
81
82 static void
83 add_sequence(char *rest, char *mapname)
84 {
85 KeySym keysym;
86 key_translation *tr, **prev_next;
87 size_t chars;
88 char keyname[KEYMAP_MAX_LINE_LENGTH];
89
90 /* Skip over whitespace after the sequence keyword */
91 chars = strspn(rest, " \t");
92 rest += chars;
93
94 /* Fetch the keysym name */
95 chars = strcspn(rest, " \t\0");
96 STRNCPY(keyname, rest, chars + 1);
97 rest += chars;
98
99 keysym = XStringToKeysym(keyname);
100 if (keysym == NoSymbol)
101 {
102 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
103 return;
104 }
105
106
107 DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
108
109 prev_next = &keymap[keysym & KEYMAP_MASK];
110
111 while (*rest)
112 {
113 /* Skip whitespace */
114 chars = strspn(rest, " \t");
115 rest += chars;
116
117 /* Fetch the keysym name */
118 chars = strcspn(rest, " \t\0");
119 STRNCPY(keyname, rest, chars + 1);
120 rest += chars;
121
122 keysym = XStringToKeysym(keyname);
123 if (keysym == NoSymbol)
124 {
125 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
126 mapname));
127 return;
128 }
129
130 /* Allocate space for key_translation structure */
131 tr = (key_translation *) xmalloc(sizeof(key_translation));
132 memset(tr, 0, sizeof(key_translation));
133 *prev_next = tr;
134 prev_next = &tr->next;
135 tr->seq_keysym = keysym;
136
137 DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
138 }
139 DEBUG_KBD(("\n"));
140 }
141
142
143 static BOOL
144 xkeymap_read(char *mapname)
145 {
146 FILE *fp;
147 char line[KEYMAP_MAX_LINE_LENGTH];
148 char path[PATH_MAX], inplace_path[PATH_MAX];
149 unsigned int line_num = 0;
150 unsigned int line_length = 0;
151 char *keyname, *p;
152 char *line_rest;
153 uint8 scancode;
154 uint16 modifiers;
155
156
157 strcpy(path, KEYMAP_PATH);
158 strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
159
160 fp = fopen(path, "r");
161 if (fp == NULL)
162 {
163 /* in case we are running from the source tree */
164 strcpy(inplace_path, "keymaps/");
165 strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));
166
167 fp = fopen(inplace_path, "r");
168 if (fp == NULL)
169 {
170 error("Failed to open keymap %s\n", path);
171 return False;
172 }
173 }
174
175 /* FIXME: More tolerant on white space */
176 while (fgets(line, sizeof(line), fp) != NULL)
177 {
178 line_num++;
179
180 /* Replace the \n with \0 */
181 p = strchr(line, '\n');
182 if (p != NULL)
183 *p = 0;
184
185 line_length = strlen(line);
186
187 /* Completely empty line */
188 if (strspn(line, " \t\n\r\f\v") == line_length)
189 {
190 continue;
191 }
192
193 /* Include */
194 if (strncmp(line, "include ", 8) == 0)
195 {
196 if (!xkeymap_read(line + 8))
197 return False;
198 continue;
199 }
200
201 /* map */
202 if (strncmp(line, "map ", 4) == 0)
203 {
204 g_keylayout = strtol(line + 4, NULL, 16);
205 DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
206 continue;
207 }
208
209 /* compose */
210 if (strncmp(line, "enable_compose", 15) == 0)
211 {
212 DEBUG_KBD(("Enabling compose handling\n"));
213 g_enable_compose = True;
214 continue;
215 }
216
217 /* sequence */
218 if (strncmp(line, "sequence", 8) == 0)
219 {
220 add_sequence(line + 8, mapname);
221 continue;
222 }
223
224 /* Comment */
225 if (line[0] == '#')
226 {
227 continue;
228 }
229
230 /* Normal line */
231 keyname = line;
232 p = strchr(line, ' ');
233 if (p == NULL)
234 {
235 error("Bad line %d in keymap %s\n", line_num, mapname);
236 continue;
237 }
238 else
239 {
240 *p = 0;
241 }
242
243 /* scancode */
244 p++;
245 scancode = strtol(p, &line_rest, 16);
246
247 /* flags */
248 /* FIXME: Should allow case-insensitive flag names.
249 Fix by using lex+yacc... */
250 modifiers = 0;
251 if (strstr(line_rest, "altgr"))
252 {
253 MASK_ADD_BITS(modifiers, MapAltGrMask);
254 }
255
256 if (strstr(line_rest, "shift"))
257 {
258 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
259 }
260
261 if (strstr(line_rest, "numlock"))
262 {
263 MASK_ADD_BITS(modifiers, MapNumLockMask);
264 }
265
266 if (strstr(line_rest, "localstate"))
267 {
268 MASK_ADD_BITS(modifiers, MapLocalStateMask);
269 }
270
271 if (strstr(line_rest, "inhibit"))
272 {
273 MASK_ADD_BITS(modifiers, MapInhibitMask);
274 }
275
276 add_to_keymap(keyname, scancode, modifiers, mapname);
277
278 if (strstr(line_rest, "addupper"))
279 {
280 /* Automatically add uppercase key, with same modifiers
281 plus shift */
282 for (p = keyname; *p; p++)
283 *p = toupper((int) *p);
284 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
285 add_to_keymap(keyname, scancode, modifiers, mapname);
286 }
287 }
288
289 fclose(fp);
290 return True;
291 }
292
293
294 /* Before connecting and creating UI */
295 void
296 xkeymap_init(void)
297 {
298 unsigned int max_keycode;
299 char *mapname_ptr;
300
301 /* Make keymapname lowercase */
302 mapname_ptr = keymapname;
303 while (*mapname_ptr)
304 {
305 *mapname_ptr = tolower((int) *mapname_ptr);
306 mapname_ptr++;
307 }
308
309 if (strcmp(keymapname, "none"))
310 {
311 if (xkeymap_read(keymapname))
312 keymap_loaded = True;
313 }
314
315 XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
316 }
317
318 static void
319 send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
320 {
321 uint8 winkey;
322
323 if (leftkey)
324 winkey = SCANCODE_CHAR_LWIN;
325 else
326 winkey = SCANCODE_CHAR_RWIN;
327
328 if (pressed)
329 {
330 if (g_use_rdp5)
331 {
332 rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
333 }
334 else
335 {
336 /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
337 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
338 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
339 }
340 }
341 else
342 {
343 /* key released */
344 if (g_use_rdp5)
345 {
346 rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
347 }
348 else
349 {
350 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
351 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
352 }
353 }
354 }
355
356 static void
357 reset_winkey(uint32 ev_time)
358 {
359 if (g_use_rdp5)
360 {
361 /* For some reason, it seems to suffice to release
362 *either* the left or right winkey. */
363 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
364 }
365 }
366
367 /* Handles, for example, multi-scancode keypresses (which is not
368 possible via keymap-files) */
369 BOOL
370 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
371 {
372 switch (keysym)
373 {
374 case XK_Return:
375 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
376 && (get_key_state(state, XK_Control_L)
377 || get_key_state(state, XK_Control_R)))
378 {
379 /* Ctrl-Alt-Enter: toggle full screen */
380 if (pressed)
381 xwin_toggle_fullscreen();
382 return True;
383 }
384 break;
385
386 case XK_Break:
387 /* Send Break sequence E0 46 E0 C6 */
388 if (pressed)
389 {
390 rdp_send_scancode(ev_time, RDP_KEYPRESS,
391 (SCANCODE_EXTENDED | 0x46));
392 rdp_send_scancode(ev_time, RDP_KEYPRESS,
393 (SCANCODE_EXTENDED | 0xc6));
394 }
395 /* No release sequence */
396 return True;
397 break;
398
399 case XK_Pause:
400 /* According to MS Keyboard Scan Code
401 Specification, pressing Pause should result
402 in E1 1D 45 E1 9D C5. I'm not exactly sure
403 of how this is supposed to be sent via
404 RDP. The code below seems to work, but with
405 the side effect that Left Ctrl stays
406 down. Therefore, we release it when Pause
407 is released. */
408 if (pressed)
409 {
410 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
411 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
412 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
413 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
414 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
415 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
416 }
417 else
418 {
419 /* Release Left Ctrl */
420 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
421 0x1d, 0);
422 }
423 return True;
424 break;
425
426 case XK_Meta_L: /* Windows keys */
427 case XK_Super_L:
428 case XK_Hyper_L:
429 send_winkey(ev_time, pressed, True);
430 return True;
431 break;
432
433 case XK_Meta_R:
434 case XK_Super_R:
435 case XK_Hyper_R:
436 send_winkey(ev_time, pressed, False);
437 return True;
438 break;
439
440 case XK_space:
441 /* Prevent access to the Windows system menu in single app mode */
442 if (g_win_button_size
443 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
444 return True;
445 break;
446
447 case XK_Num_Lock:
448 /* Synchronize on key release */
449 if (g_numlock_sync && !pressed)
450 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
451 ui_get_numlock_state(read_keyboard_state()), 0);
452
453 /* Inhibit */
454 return True;
455 break;
456
457 }
458 return False;
459 }
460
461
462 key_translation
463 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
464 {
465 key_translation tr = { 0, 0, 0, 0 };
466 key_translation *ptr;
467
468 ptr = keymap[keysym & KEYMAP_MASK];
469 if (ptr)
470 {
471 tr = *ptr;
472 if (tr.seq_keysym == 0) /* Normal scancode translation */
473 {
474 if (tr.modifiers & MapInhibitMask)
475 {
476 DEBUG_KBD(("Inhibiting key\n"));
477 tr.scancode = 0;
478 return tr;
479 }
480
481 if (tr.modifiers & MapLocalStateMask)
482 {
483 /* The modifiers to send for this key should be obtained
484 from the local state. Currently, only shift is implemented. */
485 if (state & ShiftMask)
486 {
487 tr.modifiers = MapLeftShiftMask;
488 }
489 }
490
491 if ((tr.modifiers & MapLeftShiftMask)
492 && ((remote_modifier_state & MapLeftCtrlMask)
493 || (remote_modifier_state & MapRightCtrlMask))
494 && get_key_state(state, XK_Caps_Lock))
495 {
496 DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
497 tr.modifiers ^= MapLeftShiftMask;
498 }
499
500 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
501 tr.scancode, tr.modifiers));
502 }
503 }
504 else
505 {
506 if (keymap_loaded)
507 warning("No translation for (keysym 0x%lx, %s)\n", keysym,
508 get_ksname(keysym));
509
510 /* not in keymap, try to interpret the raw scancode */
511 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
512 {
513 tr.scancode = keycode - min_keycode;
514
515 /* The modifiers to send for this key should be
516 obtained from the local state. Currently, only
517 shift is implemented. */
518 if (state & ShiftMask)
519 {
520 tr.modifiers = MapLeftShiftMask;
521 }
522
523 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
524 }
525 else
526 {
527 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
528 }
529 }
530
531 return tr;
532 }
533
534 void
535 xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
536 BOOL pressed)
537 {
538 key_translation tr, *ptr;
539 tr = xkeymap_translate_key(keysym, keycode, state);
540
541 if (tr.seq_keysym == 0)
542 {
543 /* Scancode translation */
544 if (tr.scancode == 0)
545 return;
546
547 if (pressed)
548 {
549 save_remote_modifiers(tr.scancode);
550 ensure_remote_modifiers(ev_time, tr);
551 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
552 restore_remote_modifiers(ev_time, tr.scancode);
553 }
554 else
555 {
556 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
557 }
558 return;
559 }
560
561 /* Sequence, only on key down */
562 if (pressed)
563 {
564 ptr = &tr;
565 do
566 {
567 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
568 (unsigned int) ptr->seq_keysym));
569 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
570 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
571 ptr = ptr->next;
572 }
573 while (ptr);
574 }
575 }
576
577 uint16
578 xkeymap_translate_button(unsigned int button)
579 {
580 switch (button)
581 {
582 case Button1: /* left */
583 return MOUSE_FLAG_BUTTON1;
584 case Button2: /* middle */
585 return MOUSE_FLAG_BUTTON3;
586 case Button3: /* right */
587 return MOUSE_FLAG_BUTTON2;
588 case Button4: /* wheel up */
589 return MOUSE_FLAG_BUTTON4;
590 case Button5: /* wheel down */
591 return MOUSE_FLAG_BUTTON5;
592 }
593
594 return 0;
595 }
596
597 char *
598 get_ksname(uint32 keysym)
599 {
600 char *ksname = NULL;
601
602 if (keysym == NoSymbol)
603 ksname = "NoSymbol";
604 else if (!(ksname = XKeysymToString(keysym)))
605 ksname = "(no name)";
606
607 return ksname;
608 }
609
610 static BOOL
611 is_modifier(uint8 scancode)
612 {
613 switch (scancode)
614 {
615 case SCANCODE_CHAR_LSHIFT:
616 case SCANCODE_CHAR_RSHIFT:
617 case SCANCODE_CHAR_LCTRL:
618 case SCANCODE_CHAR_RCTRL:
619 case SCANCODE_CHAR_LALT:
620 case SCANCODE_CHAR_RALT:
621 case SCANCODE_CHAR_LWIN:
622 case SCANCODE_CHAR_RWIN:
623 case SCANCODE_CHAR_NUMLOCK:
624 return True;
625 default:
626 break;
627 }
628 return False;
629 }
630
631 void
632 save_remote_modifiers(uint8 scancode)
633 {
634 if (is_modifier(scancode))
635 return;
636
637 saved_remote_modifier_state = remote_modifier_state;
638 }
639
640 void
641 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
642 {
643 key_translation dummy;
644
645 if (is_modifier(scancode))
646 return;
647
648 dummy.scancode = 0;
649 dummy.modifiers = saved_remote_modifier_state;
650 ensure_remote_modifiers(ev_time, dummy);
651 }
652
653 void
654 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
655 {
656 /* If this key is a modifier, do nothing */
657 if (is_modifier(tr.scancode))
658 return;
659
660 if (!g_numlock_sync)
661 {
662 /* NumLock */
663 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
664 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
665 {
666 /* The remote modifier state is not correct */
667 uint16 new_remote_state;
668
669 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
670 {
671 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
672 new_remote_state = KBD_FLAG_NUMLOCK;
673 remote_modifier_state = MapNumLockMask;
674 }
675 else
676 {
677 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
678 new_remote_state = 0;
679 remote_modifier_state = 0;
680 }
681
682 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
683 }
684 }
685
686
687 /* Shift. Left shift and right shift are treated as equal; either is fine. */
688 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
689 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
690 {
691 /* The remote modifier state is not correct */
692 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
693 {
694 /* Needs left shift. Send down. */
695 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
696 }
697 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
698 {
699 /* Needs right shift. Send down. */
700 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
701 }
702 else
703 {
704 /* Should not use this modifier. Send up for shift currently pressed. */
705 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
706 /* Left shift is down */
707 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
708 else
709 /* Right shift is down */
710 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
711 }
712 }
713
714 /* AltGr */
715 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
716 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
717 {
718 /* The remote modifier state is not correct */
719 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
720 {
721 /* Needs this modifier. Send down. */
722 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
723 }
724 else
725 {
726 /* Should not use this modifier. Send up. */
727 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
728 }
729 }
730
731
732 }
733
734
735 unsigned int
736 read_keyboard_state()
737 {
738 #ifdef RDP2VNC
739 return 0;
740 #else
741 unsigned int state;
742 Window wdummy;
743 int dummy;
744
745 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
746 return state;
747 #endif
748 }
749
750
751 uint16
752 ui_get_numlock_state(unsigned int state)
753 {
754 uint16 numlock_state = 0;
755
756 if (get_key_state(state, XK_Num_Lock))
757 numlock_state = KBD_FLAG_NUMLOCK;
758
759 return numlock_state;
760 }
761
762
763 void
764 reset_modifier_keys()
765 {
766 unsigned int state = read_keyboard_state();
767
768 /* reset keys */
769 uint32 ev_time;
770 ev_time = time(NULL);
771
772 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
773 && !get_key_state(state, XK_Shift_L))
774 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
775
776 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
777 && !get_key_state(state, XK_Shift_R))
778 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
779
780 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
781 && !get_key_state(state, XK_Control_L))
782 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
783
784 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
785 && !get_key_state(state, XK_Control_R))
786 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
787
788 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
789 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
790
791 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
792 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
793 && !get_key_state(state, XK_ISO_Level3_Shift))
794 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
795
796 reset_winkey(ev_time);
797
798 if (g_numlock_sync)
799 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
800 }
801
802
803 static void
804 update_modifier_state(uint8 scancode, BOOL pressed)
805 {
806 #ifdef WITH_DEBUG_KBD
807 uint16 old_modifier_state;
808
809 old_modifier_state = remote_modifier_state;
810 #endif
811
812 switch (scancode)
813 {
814 case SCANCODE_CHAR_LSHIFT:
815 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
816 break;
817 case SCANCODE_CHAR_RSHIFT:
818 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
819 break;
820 case SCANCODE_CHAR_LCTRL:
821 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
822 break;
823 case SCANCODE_CHAR_RCTRL:
824 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
825 break;
826 case SCANCODE_CHAR_LALT:
827 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
828 break;
829 case SCANCODE_CHAR_RALT:
830 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
831 break;
832 case SCANCODE_CHAR_LWIN:
833 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
834 break;
835 case SCANCODE_CHAR_RWIN:
836 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
837 break;
838 case SCANCODE_CHAR_NUMLOCK:
839 /* KeyReleases for NumLocks are sent immediately. Toggle the
840 modifier state only on Keypress */
841 if (pressed && !g_numlock_sync)
842 {
843 BOOL newNumLockState;
844 newNumLockState =
845 (MASK_HAS_BITS
846 (remote_modifier_state, MapNumLockMask) == False);
847 MASK_CHANGE_BIT(remote_modifier_state,
848 MapNumLockMask, newNumLockState);
849 }
850 }
851
852 #ifdef WITH_DEBUG_KBD
853 if (old_modifier_state != remote_modifier_state)
854 {
855 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
856 old_modifier_state, pressed));
857 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
858 }
859 #endif
860
861 }
862
863 /* Send keyboard input */
864 void
865 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
866 {
867 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
868
869 if (scancode & SCANCODE_EXTENDED)
870 {
871 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
872 scancode & ~SCANCODE_EXTENDED, flags));
873 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
874 scancode & ~SCANCODE_EXTENDED, 0);
875 }
876 else
877 {
878 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
879 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
880 }
881 }

  ViewVC Help
Powered by ViewVC 1.1.26