/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 963 - (show annotations)
Wed Aug 3 10:56:16 2005 UTC (18 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 22533 byte(s)
Added missing c-basic-offset:s and license headers

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

  ViewVC Help
Powered by ViewVC 1.1.26