/[rdesktop]/jpeg/rdesktop/trunk/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /jpeg/rdesktop/trunk/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 965 - (show annotations)
Wed Aug 3 11:47:20 2005 UTC (18 years, 9 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 23616 byte(s)
Replaced magic numbers for string lenghts with sizeof. Corrected sizeof statements for keyboard_*; we shouldn't count the trailing zero.

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

  ViewVC Help
Powered by ViewVC 1.1.26