/[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 1219 - (show annotations)
Fri Apr 7 22:20:43 2006 UTC (18 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 23917 byte(s)
Using MASK_ macros in a few more places.

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 (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
616 {
617 DEBUG_KBD(("Inhibiting key\n"));
618 tr.scancode = 0;
619 return tr;
620 }
621
622 if (MASK_HAS_BITS(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 (MASK_HAS_BITS(state, ShiftMask))
627 {
628 tr.modifiers = MapLeftShiftMask;
629 }
630 }
631
632 /* Windows interprets CapsLock+Ctrl+key
633 differently from Shift+Ctrl+key. Since we
634 are simulating CapsLock with Shifts, things
635 like Ctrl+f with CapsLock on breaks. To
636 solve this, we are releasing Shift if Ctrl
637 is on, but only if Shift isn't physically pressed. */
638 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
639 && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
640 && !MASK_HAS_BITS(state, ShiftMask))
641 {
642 DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
643 MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
644 }
645
646 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
647 tr.scancode, tr.modifiers));
648 }
649 }
650 else
651 {
652 if (keymap_loaded)
653 warning("No translation for (keysym 0x%lx, %s)\n", keysym,
654 get_ksname(keysym));
655
656 /* not in keymap, try to interpret the raw scancode */
657 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
658 {
659 tr.scancode = keycode - min_keycode;
660
661 /* The modifiers to send for this key should be
662 obtained from the local state. Currently, only
663 shift is implemented. */
664 if (MASK_HAS_BITS(state, ShiftMask))
665 {
666 tr.modifiers = MapLeftShiftMask;
667 }
668
669 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
670 }
671 else
672 {
673 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
674 }
675 }
676
677 return tr;
678 }
679
680 void
681 xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
682 BOOL pressed, uint8 nesting)
683 {
684 key_translation tr, *ptr;
685 tr = xkeymap_translate_key(keysym, keycode, state);
686
687 if (tr.seq_keysym == 0)
688 {
689 /* Scancode translation */
690 if (tr.scancode == 0)
691 return;
692
693 if (pressed)
694 {
695 save_remote_modifiers(tr.scancode);
696 ensure_remote_modifiers(ev_time, tr);
697 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
698 restore_remote_modifiers(ev_time, tr.scancode);
699 }
700 else
701 {
702 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
703 }
704 return;
705 }
706
707 /* Sequence, only on key down */
708 if (pressed)
709 {
710 ptr = &tr;
711 do
712 {
713 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
714 (unsigned int) ptr->seq_keysym));
715
716 if (nesting++ > 32)
717 {
718 error("Sequence nesting too deep\n");
719 return;
720 }
721
722 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
723 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
724 ptr = ptr->next;
725 }
726 while (ptr);
727 }
728 }
729
730 uint16
731 xkeymap_translate_button(unsigned int button)
732 {
733 switch (button)
734 {
735 case Button1: /* left */
736 return MOUSE_FLAG_BUTTON1;
737 case Button2: /* middle */
738 return MOUSE_FLAG_BUTTON3;
739 case Button3: /* right */
740 return MOUSE_FLAG_BUTTON2;
741 case Button4: /* wheel up */
742 return MOUSE_FLAG_BUTTON4;
743 case Button5: /* wheel down */
744 return MOUSE_FLAG_BUTTON5;
745 }
746
747 return 0;
748 }
749
750 char *
751 get_ksname(uint32 keysym)
752 {
753 char *ksname = NULL;
754
755 if (keysym == NoSymbol)
756 ksname = "NoSymbol";
757 else if (!(ksname = XKeysymToString(keysym)))
758 ksname = "(no name)";
759
760 return ksname;
761 }
762
763 static BOOL
764 is_modifier(uint8 scancode)
765 {
766 switch (scancode)
767 {
768 case SCANCODE_CHAR_LSHIFT:
769 case SCANCODE_CHAR_RSHIFT:
770 case SCANCODE_CHAR_LCTRL:
771 case SCANCODE_CHAR_RCTRL:
772 case SCANCODE_CHAR_LALT:
773 case SCANCODE_CHAR_RALT:
774 case SCANCODE_CHAR_LWIN:
775 case SCANCODE_CHAR_RWIN:
776 case SCANCODE_CHAR_NUMLOCK:
777 return True;
778 default:
779 break;
780 }
781 return False;
782 }
783
784 void
785 save_remote_modifiers(uint8 scancode)
786 {
787 if (is_modifier(scancode))
788 return;
789
790 saved_remote_modifier_state = remote_modifier_state;
791 }
792
793 void
794 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
795 {
796 key_translation dummy;
797
798 if (is_modifier(scancode))
799 return;
800
801 dummy.scancode = 0;
802 dummy.modifiers = saved_remote_modifier_state;
803 ensure_remote_modifiers(ev_time, dummy);
804 }
805
806 void
807 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
808 {
809 /* If this key is a modifier, do nothing */
810 if (is_modifier(tr.scancode))
811 return;
812
813 if (!g_numlock_sync)
814 {
815 /* NumLock */
816 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
817 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
818 {
819 /* The remote modifier state is not correct */
820 uint16 new_remote_state;
821
822 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
823 {
824 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
825 new_remote_state = KBD_FLAG_NUMLOCK;
826 remote_modifier_state = MapNumLockMask;
827 }
828 else
829 {
830 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
831 new_remote_state = 0;
832 remote_modifier_state = 0;
833 }
834
835 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
836 }
837 }
838
839
840 /* Shift. Left shift and right shift are treated as equal; either is fine. */
841 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
842 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
843 {
844 /* The remote modifier state is not correct */
845 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
846 {
847 /* Needs left shift. Send down. */
848 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
849 }
850 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
851 {
852 /* Needs right shift. Send down. */
853 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
854 }
855 else
856 {
857 /* Should not use this modifier. Send up for shift currently pressed. */
858 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
859 /* Left shift is down */
860 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
861 else
862 /* Right shift is down */
863 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
864 }
865 }
866
867 /* AltGr */
868 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
869 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
870 {
871 /* The remote modifier state is not correct */
872 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
873 {
874 /* Needs this modifier. Send down. */
875 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
876 }
877 else
878 {
879 /* Should not use this modifier. Send up. */
880 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
881 }
882 }
883
884
885 }
886
887
888 unsigned int
889 read_keyboard_state()
890 {
891 #ifdef RDP2VNC
892 return 0;
893 #else
894 unsigned int state;
895 Window wdummy;
896 int dummy;
897
898 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
899 return state;
900 #endif
901 }
902
903
904 uint16
905 ui_get_numlock_state(unsigned int state)
906 {
907 uint16 numlock_state = 0;
908
909 if (get_key_state(state, XK_Num_Lock))
910 numlock_state = KBD_FLAG_NUMLOCK;
911
912 return numlock_state;
913 }
914
915
916 void
917 reset_modifier_keys()
918 {
919 unsigned int state = read_keyboard_state();
920
921 /* reset keys */
922 uint32 ev_time;
923 ev_time = time(NULL);
924
925 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
926 && !get_key_state(state, XK_Shift_L))
927 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
928
929 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
930 && !get_key_state(state, XK_Shift_R))
931 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
932
933 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
934 && !get_key_state(state, XK_Control_L))
935 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
936
937 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
938 && !get_key_state(state, XK_Control_R))
939 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
940
941 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
942 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
943
944 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
945 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
946 && !get_key_state(state, XK_ISO_Level3_Shift))
947 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
948
949 reset_winkey(ev_time);
950
951 if (g_numlock_sync)
952 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
953 }
954
955
956 static void
957 update_modifier_state(uint8 scancode, BOOL pressed)
958 {
959 #ifdef WITH_DEBUG_KBD
960 uint16 old_modifier_state;
961
962 old_modifier_state = remote_modifier_state;
963 #endif
964
965 switch (scancode)
966 {
967 case SCANCODE_CHAR_LSHIFT:
968 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
969 break;
970 case SCANCODE_CHAR_RSHIFT:
971 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
972 break;
973 case SCANCODE_CHAR_LCTRL:
974 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
975 break;
976 case SCANCODE_CHAR_RCTRL:
977 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
978 break;
979 case SCANCODE_CHAR_LALT:
980 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
981 break;
982 case SCANCODE_CHAR_RALT:
983 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
984 break;
985 case SCANCODE_CHAR_LWIN:
986 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
987 break;
988 case SCANCODE_CHAR_RWIN:
989 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
990 break;
991 case SCANCODE_CHAR_NUMLOCK:
992 /* KeyReleases for NumLocks are sent immediately. Toggle the
993 modifier state only on Keypress */
994 if (pressed && !g_numlock_sync)
995 {
996 BOOL newNumLockState;
997 newNumLockState =
998 (MASK_HAS_BITS
999 (remote_modifier_state, MapNumLockMask) == False);
1000 MASK_CHANGE_BIT(remote_modifier_state,
1001 MapNumLockMask, newNumLockState);
1002 }
1003 }
1004
1005 #ifdef WITH_DEBUG_KBD
1006 if (old_modifier_state != remote_modifier_state)
1007 {
1008 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1009 old_modifier_state, pressed));
1010 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1011 }
1012 #endif
1013
1014 }
1015
1016 /* Send keyboard input */
1017 void
1018 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1019 {
1020 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1021
1022 if (scancode & SCANCODE_EXTENDED)
1023 {
1024 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1025 scancode & ~SCANCODE_EXTENDED, flags));
1026 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1027 scancode & ~SCANCODE_EXTENDED, 0);
1028 }
1029 else
1030 {
1031 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1032 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1033 }
1034 }

  ViewVC Help
Powered by ViewVC 1.1.26