/[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 973 - (show annotations)
Thu Aug 4 12:44:10 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23581 byte(s)
Reorganized the automatic selection of keymap: The message about autoselection is not printed if -k is not given.

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

  ViewVC Help
Powered by ViewVC 1.1.26