/[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 1294 - (show annotations)
Wed Oct 11 17:59:18 2006 UTC (17 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 23944 byte(s)
Undo incorrect commit

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

  ViewVC Help
Powered by ViewVC 1.1.26