/[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 976 - (show annotations)
Thu Aug 4 13:39:57 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23659 byte(s)
Protection against recursive sequences

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

  ViewVC Help
Powered by ViewVC 1.1.26