/[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 960 - (show annotations)
Wed Aug 3 08:41:02 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 21793 byte(s)
~/.rdesktop/keymaps is now tried before KEYMAP_PATH

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

  ViewVC Help
Powered by ViewVC 1.1.26