/[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 1293 - (show annotations)
Wed Oct 11 17:56:05 2006 UTC (17 years, 8 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 24135 byte(s)
Changed the Copyright: tag to License: in accordance with RPM 4

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 printf("reset_winkey\n");
499 if (g_use_rdp5)
500 {
501 /* For some reason, it seems to suffice to release
502 *either* the left or right winkey. */
503 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
504 }
505 }
506
507 /* Handle special key combinations */
508 BOOL
509 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
510 {
511 switch (keysym)
512 {
513 case XK_Return:
514 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
515 && (get_key_state(state, XK_Control_L)
516 || get_key_state(state, XK_Control_R)))
517 {
518 /* Ctrl-Alt-Enter: toggle full screen */
519 if (pressed)
520 xwin_toggle_fullscreen();
521 return True;
522 }
523 break;
524
525 case XK_Break:
526 /* Send Break sequence E0 46 E0 C6 */
527 if (pressed)
528 {
529 rdp_send_scancode(ev_time, RDP_KEYPRESS,
530 (SCANCODE_EXTENDED | 0x46));
531 rdp_send_scancode(ev_time, RDP_KEYPRESS,
532 (SCANCODE_EXTENDED | 0xc6));
533 }
534 /* No release sequence */
535 return True;
536 break;
537
538 case XK_Pause:
539 /* According to MS Keyboard Scan Code
540 Specification, pressing Pause should result
541 in E1 1D 45 E1 9D C5. I'm not exactly sure
542 of how this is supposed to be sent via
543 RDP. The code below seems to work, but with
544 the side effect that Left Ctrl stays
545 down. Therefore, we release it when Pause
546 is released. */
547 if (pressed)
548 {
549 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
550 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
551 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
552 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
553 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
554 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
555 }
556 else
557 {
558 /* Release Left Ctrl */
559 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
560 0x1d, 0);
561 }
562 return True;
563 break;
564
565 case XK_Meta_L: /* Windows keys */
566 case XK_Super_L:
567 case XK_Hyper_L:
568 send_winkey(ev_time, pressed, True);
569 return True;
570 break;
571
572 case XK_Meta_R:
573 case XK_Super_R:
574 case XK_Hyper_R:
575 send_winkey(ev_time, pressed, False);
576 return True;
577 break;
578
579 case XK_space:
580 /* Prevent access to the Windows system menu in single app mode */
581 if (g_win_button_size
582 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
583 return True;
584 break;
585
586 case XK_Num_Lock:
587 /* Synchronize on key release */
588 if (g_numlock_sync && !pressed)
589 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
590 ui_get_numlock_state(read_keyboard_state()), 0);
591
592 /* Inhibit */
593 return True;
594 break;
595 case XK_Overlay1_Enable:
596 /* Toggle SeamlessRDP */
597 if (pressed)
598 ui_seamless_toggle();
599 break;
600
601 }
602 return False;
603 }
604
605
606 key_translation
607 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
608 {
609 key_translation tr = { 0, 0, 0, 0 };
610 key_translation *ptr;
611
612 ptr = keymap[keysym & KEYMAP_MASK];
613 if (ptr)
614 {
615 tr = *ptr;
616 if (tr.seq_keysym == 0) /* Normal scancode translation */
617 {
618 if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
619 {
620 DEBUG_KBD(("Inhibiting key\n"));
621 tr.scancode = 0;
622 return tr;
623 }
624
625 if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask))
626 {
627 /* The modifiers to send for this key should be obtained
628 from the local state. Currently, only shift is implemented. */
629 if (MASK_HAS_BITS(state, ShiftMask))
630 {
631 tr.modifiers = MapLeftShiftMask;
632 }
633 }
634
635 /* Windows interprets CapsLock+Ctrl+key
636 differently from Shift+Ctrl+key. Since we
637 are simulating CapsLock with Shifts, things
638 like Ctrl+f with CapsLock on breaks. To
639 solve this, we are releasing Shift if Ctrl
640 is on, but only if Shift isn't physically pressed. */
641 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
642 && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
643 && !MASK_HAS_BITS(state, ShiftMask))
644 {
645 DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
646 MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
647 }
648
649 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
650 tr.scancode, tr.modifiers));
651 }
652 }
653 else
654 {
655 if (keymap_loaded)
656 warning("No translation for (keysym 0x%lx, %s)\n", keysym,
657 get_ksname(keysym));
658
659 /* not in keymap, try to interpret the raw scancode */
660 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
661 {
662 tr.scancode = keycode - min_keycode;
663
664 /* The modifiers to send for this key should be
665 obtained from the local state. Currently, only
666 shift is implemented. */
667 if (MASK_HAS_BITS(state, ShiftMask))
668 {
669 tr.modifiers = MapLeftShiftMask;
670 }
671
672 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
673 }
674 else
675 {
676 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
677 }
678 }
679
680 return tr;
681 }
682
683 void
684 xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
685 BOOL pressed, uint8 nesting)
686 {
687 key_translation tr, *ptr;
688 tr = xkeymap_translate_key(keysym, keycode, state);
689
690 if (tr.seq_keysym == 0)
691 {
692 /* Scancode translation */
693 if (tr.scancode == 0)
694 return;
695
696 if (pressed)
697 {
698 save_remote_modifiers(tr.scancode);
699 ensure_remote_modifiers(ev_time, tr);
700 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
701 restore_remote_modifiers(ev_time, tr.scancode);
702 }
703 else
704 {
705 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
706 }
707 return;
708 }
709
710 /* Sequence, only on key down */
711 if (pressed)
712 {
713 ptr = &tr;
714 do
715 {
716 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
717 (unsigned int) ptr->seq_keysym));
718
719 if (nesting++ > 32)
720 {
721 error("Sequence nesting too deep\n");
722 return;
723 }
724
725 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
726 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
727 ptr = ptr->next;
728 }
729 while (ptr);
730 }
731 }
732
733 uint16
734 xkeymap_translate_button(unsigned int button)
735 {
736 switch (button)
737 {
738 case Button1: /* left */
739 return MOUSE_FLAG_BUTTON1;
740 case Button2: /* middle */
741 return MOUSE_FLAG_BUTTON3;
742 case Button3: /* right */
743 return MOUSE_FLAG_BUTTON2;
744 case Button4: /* wheel up */
745 return MOUSE_FLAG_BUTTON4;
746 case Button5: /* wheel down */
747 return MOUSE_FLAG_BUTTON5;
748 }
749
750 return 0;
751 }
752
753 char *
754 get_ksname(uint32 keysym)
755 {
756 char *ksname = NULL;
757
758 if (keysym == NoSymbol)
759 ksname = "NoSymbol";
760 else if (!(ksname = XKeysymToString(keysym)))
761 ksname = "(no name)";
762
763 return ksname;
764 }
765
766 static BOOL
767 is_modifier(uint8 scancode)
768 {
769 switch (scancode)
770 {
771 case SCANCODE_CHAR_LSHIFT:
772 case SCANCODE_CHAR_RSHIFT:
773 case SCANCODE_CHAR_LCTRL:
774 case SCANCODE_CHAR_RCTRL:
775 case SCANCODE_CHAR_LALT:
776 case SCANCODE_CHAR_RALT:
777 case SCANCODE_CHAR_LWIN:
778 case SCANCODE_CHAR_RWIN:
779 case SCANCODE_CHAR_NUMLOCK:
780 return True;
781 default:
782 break;
783 }
784 return False;
785 }
786
787 void
788 save_remote_modifiers(uint8 scancode)
789 {
790 if (is_modifier(scancode))
791 return;
792
793 saved_remote_modifier_state = remote_modifier_state;
794 }
795
796 void
797 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
798 {
799 key_translation dummy;
800
801 if (is_modifier(scancode))
802 return;
803
804 dummy.scancode = 0;
805 dummy.modifiers = saved_remote_modifier_state;
806 ensure_remote_modifiers(ev_time, dummy);
807 }
808
809 void
810 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
811 {
812 /* If this key is a modifier, do nothing */
813 if (is_modifier(tr.scancode))
814 return;
815
816 if (!g_numlock_sync)
817 {
818 /* NumLock */
819 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
820 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
821 {
822 /* The remote modifier state is not correct */
823 uint16 new_remote_state;
824
825 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
826 {
827 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
828 new_remote_state = KBD_FLAG_NUMLOCK;
829 remote_modifier_state = MapNumLockMask;
830 }
831 else
832 {
833 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
834 new_remote_state = 0;
835 remote_modifier_state = 0;
836 }
837
838 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
839 }
840 }
841
842
843 /* Shift. Left shift and right shift are treated as equal; either is fine. */
844 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
845 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
846 {
847 /* The remote modifier state is not correct */
848 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
849 {
850 /* Needs left shift. Send down. */
851 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
852 }
853 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
854 {
855 /* Needs right shift. Send down. */
856 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
857 }
858 else
859 {
860 /* Should not use this modifier. Send up for shift currently pressed. */
861 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
862 /* Left shift is down */
863 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
864 else
865 /* Right shift is down */
866 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
867 }
868 }
869
870 /* AltGr */
871 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
872 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
873 {
874 /* The remote modifier state is not correct */
875 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
876 {
877 /* Needs this modifier. Send down. */
878 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
879 }
880 else
881 {
882 /* Should not use this modifier. Send up. */
883 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
884 }
885 }
886
887
888 }
889
890
891 unsigned int
892 read_keyboard_state()
893 {
894 #ifdef RDP2VNC
895 return 0;
896 #else
897 unsigned int state;
898 Window wdummy;
899 int dummy;
900
901 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
902 return state;
903 #endif
904 }
905
906
907 uint16
908 ui_get_numlock_state(unsigned int state)
909 {
910 uint16 numlock_state = 0;
911
912 if (get_key_state(state, XK_Num_Lock))
913 numlock_state = KBD_FLAG_NUMLOCK;
914
915 return numlock_state;
916 }
917
918
919 void
920 reset_modifier_keys()
921 {
922 unsigned int state = read_keyboard_state();
923
924 /* reset keys */
925 uint32 ev_time;
926 ev_time = time(NULL);
927
928 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
929 && !get_key_state(state, XK_Shift_L))
930 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
931
932 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
933 && !get_key_state(state, XK_Shift_R))
934 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
935
936 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
937 && !get_key_state(state, XK_Control_L))
938 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
939
940 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
941 && !get_key_state(state, XK_Control_R))
942 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
943
944 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
945 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
946
947 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
948 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
949 && !get_key_state(state, XK_ISO_Level3_Shift))
950 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
951
952 reset_winkey(ev_time);
953
954 if (g_numlock_sync)
955 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
956
957 //sleep(4);
958 //rdp_send_input(time(NULL), RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9c, 0);
959 //rdp_send_input(time(NULL), RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x9c, 0);
960 }
961
962
963 static void
964 update_modifier_state(uint8 scancode, BOOL pressed)
965 {
966 #ifdef WITH_DEBUG_KBD
967 uint16 old_modifier_state;
968
969 old_modifier_state = remote_modifier_state;
970 #endif
971
972 switch (scancode)
973 {
974 case SCANCODE_CHAR_LSHIFT:
975 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
976 break;
977 case SCANCODE_CHAR_RSHIFT:
978 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
979 break;
980 case SCANCODE_CHAR_LCTRL:
981 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
982 break;
983 case SCANCODE_CHAR_RCTRL:
984 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
985 break;
986 case SCANCODE_CHAR_LALT:
987 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
988 break;
989 case SCANCODE_CHAR_RALT:
990 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
991 break;
992 case SCANCODE_CHAR_LWIN:
993 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
994 break;
995 case SCANCODE_CHAR_RWIN:
996 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
997 break;
998 case SCANCODE_CHAR_NUMLOCK:
999 /* KeyReleases for NumLocks are sent immediately. Toggle the
1000 modifier state only on Keypress */
1001 if (pressed && !g_numlock_sync)
1002 {
1003 BOOL newNumLockState;
1004 newNumLockState =
1005 (MASK_HAS_BITS
1006 (remote_modifier_state, MapNumLockMask) == False);
1007 MASK_CHANGE_BIT(remote_modifier_state,
1008 MapNumLockMask, newNumLockState);
1009 }
1010 }
1011
1012 #ifdef WITH_DEBUG_KBD
1013 if (old_modifier_state != remote_modifier_state)
1014 {
1015 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1016 old_modifier_state, pressed));
1017 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1018 }
1019 #endif
1020
1021 }
1022
1023 /* Send keyboard input */
1024 void
1025 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1026 {
1027 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1028
1029 if (scancode & SCANCODE_EXTENDED)
1030 {
1031 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1032 scancode & ~SCANCODE_EXTENDED, flags));
1033 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1034 scancode & ~SCANCODE_EXTENDED, 0);
1035 }
1036 else
1037 {
1038 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1039 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1040 }
1041 }

  ViewVC Help
Powered by ViewVC 1.1.26