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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1199 - (show annotations)
Mon Mar 27 08:17:34 2006 UTC (18 years, 1 month ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 23585 byte(s)
Added SeamlessRDP support: Merged seamlessrdp-branch

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

  ViewVC Help
Powered by ViewVC 1.1.26