/[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 961 - (show annotations)
Wed Aug 3 09:32:22 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 21661 byte(s)
The keymap names are now case sensitive, since the -k argument now specifies a file name.

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

  ViewVC Help
Powered by ViewVC 1.1.26