/[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 1507 - (show annotations)
Mon Jul 20 16:45:11 2009 UTC (14 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 23916 byte(s)
branch for integration of Daniel Jarboe <daniel.jarboe(at)gmail.com>
patches for jpeg
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-2008
6 Copyright (C) Peter Astrand <astrand@cendio.se> 2003-2008
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 RD_BOOL g_enable_compose;
50 extern RD_BOOL g_use_rdp5;
51 extern RD_BOOL g_numlock_sync;
52
53 static RD_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, RD_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 RD_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 RD_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, RD_BOOL pressed, RD_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 RD_BOOL
508 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_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 static RD_BOOL
683 is_modifier(uint8 scancode)
684 {
685 switch (scancode)
686 {
687 case SCANCODE_CHAR_LSHIFT:
688 case SCANCODE_CHAR_RSHIFT:
689 case SCANCODE_CHAR_LCTRL:
690 case SCANCODE_CHAR_RCTRL:
691 case SCANCODE_CHAR_LALT:
692 case SCANCODE_CHAR_RALT:
693 case SCANCODE_CHAR_LWIN:
694 case SCANCODE_CHAR_RWIN:
695 case SCANCODE_CHAR_NUMLOCK:
696 return True;
697 default:
698 break;
699 }
700 return False;
701 }
702
703
704 void
705 xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
706 RD_BOOL pressed, uint8 nesting)
707 {
708 key_translation tr, *ptr;
709 tr = xkeymap_translate_key(keysym, keycode, state);
710
711 if (tr.seq_keysym == 0)
712 {
713 /* Scancode translation */
714 if (tr.scancode == 0)
715 return;
716
717 save_remote_modifiers(tr.scancode);
718 ensure_remote_modifiers(ev_time, tr);
719 rdp_send_scancode(ev_time, pressed ? RDP_KEYPRESS : RDP_KEYRELEASE, tr.scancode);
720 restore_remote_modifiers(ev_time, tr.scancode);
721 return;
722 }
723
724 /* Sequence, only on key down */
725 if (pressed)
726 {
727 ptr = &tr;
728 do
729 {
730 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
731 (unsigned int) ptr->seq_keysym));
732
733 if (nesting++ > 32)
734 {
735 error("Sequence nesting too deep\n");
736 return;
737 }
738
739 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
740 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
741 ptr = ptr->next;
742 }
743 while (ptr);
744 }
745 }
746
747 uint16
748 xkeymap_translate_button(unsigned int button)
749 {
750 switch (button)
751 {
752 case Button1: /* left */
753 return MOUSE_FLAG_BUTTON1;
754 case Button2: /* middle */
755 return MOUSE_FLAG_BUTTON3;
756 case Button3: /* right */
757 return MOUSE_FLAG_BUTTON2;
758 case Button4: /* wheel up */
759 return MOUSE_FLAG_BUTTON4;
760 case Button5: /* wheel down */
761 return MOUSE_FLAG_BUTTON5;
762 }
763
764 return 0;
765 }
766
767 char *
768 get_ksname(uint32 keysym)
769 {
770 char *ksname = NULL;
771
772 if (keysym == NoSymbol)
773 ksname = "NoSymbol";
774 else if (!(ksname = XKeysymToString(keysym)))
775 ksname = "(no name)";
776
777 return ksname;
778 }
779
780 void
781 save_remote_modifiers(uint8 scancode)
782 {
783 if (is_modifier(scancode))
784 return;
785
786 saved_remote_modifier_state = remote_modifier_state;
787 }
788
789 void
790 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
791 {
792 key_translation dummy;
793
794 if (is_modifier(scancode))
795 return;
796
797 dummy.scancode = 0;
798 dummy.modifiers = saved_remote_modifier_state;
799 ensure_remote_modifiers(ev_time, dummy);
800 }
801
802 void
803 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
804 {
805 /* If this key is a modifier, do nothing */
806 if (is_modifier(tr.scancode))
807 return;
808
809 if (!g_numlock_sync)
810 {
811 /* NumLock */
812 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
813 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
814 {
815 /* The remote modifier state is not correct */
816 uint16 new_remote_state;
817
818 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
819 {
820 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
821 new_remote_state = KBD_FLAG_NUMLOCK;
822 remote_modifier_state = MapNumLockMask;
823 }
824 else
825 {
826 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
827 new_remote_state = 0;
828 remote_modifier_state = 0;
829 }
830
831 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
832 }
833 }
834
835
836 /* Shift. Left shift and right shift are treated as equal; either is fine. */
837 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
838 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
839 {
840 /* The remote modifier state is not correct */
841 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
842 {
843 /* Needs left shift. Send down. */
844 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
845 }
846 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
847 {
848 /* Needs right shift. Send down. */
849 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
850 }
851 else
852 {
853 /* Should not use this modifier. Send up for shift currently pressed. */
854 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
855 /* Left shift is down */
856 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
857 else
858 /* Right shift is down */
859 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
860 }
861 }
862
863 /* AltGr */
864 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
865 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
866 {
867 /* The remote modifier state is not correct */
868 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
869 {
870 /* Needs this modifier. Send down. */
871 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
872 }
873 else
874 {
875 /* Should not use this modifier. Send up. */
876 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
877 }
878 }
879
880
881 }
882
883
884 unsigned int
885 read_keyboard_state()
886 {
887 #ifdef RDP2VNC
888 return 0;
889 #else
890 unsigned int state;
891 Window wdummy;
892 int dummy;
893
894 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
895 return state;
896 #endif
897 }
898
899
900 uint16
901 ui_get_numlock_state(unsigned int state)
902 {
903 uint16 numlock_state = 0;
904
905 if (get_key_state(state, XK_Num_Lock))
906 numlock_state = KBD_FLAG_NUMLOCK;
907
908 return numlock_state;
909 }
910
911
912 void
913 reset_modifier_keys()
914 {
915 unsigned int state = read_keyboard_state();
916
917 /* reset keys */
918 uint32 ev_time;
919 ev_time = time(NULL);
920
921 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
922 && !get_key_state(state, XK_Shift_L))
923 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
924
925 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
926 && !get_key_state(state, XK_Shift_R))
927 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
928
929 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
930 && !get_key_state(state, XK_Control_L))
931 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
932
933 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
934 && !get_key_state(state, XK_Control_R))
935 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
936
937 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
938 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
939
940 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
941 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
942 && !get_key_state(state, XK_ISO_Level3_Shift))
943 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
944
945 reset_winkey(ev_time);
946
947 if (g_numlock_sync)
948 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
949 }
950
951
952 static void
953 update_modifier_state(uint8 scancode, RD_BOOL pressed)
954 {
955 #ifdef WITH_DEBUG_KBD
956 uint16 old_modifier_state;
957
958 old_modifier_state = remote_modifier_state;
959 #endif
960
961 switch (scancode)
962 {
963 case SCANCODE_CHAR_LSHIFT:
964 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
965 break;
966 case SCANCODE_CHAR_RSHIFT:
967 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
968 break;
969 case SCANCODE_CHAR_LCTRL:
970 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
971 break;
972 case SCANCODE_CHAR_RCTRL:
973 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
974 break;
975 case SCANCODE_CHAR_LALT:
976 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
977 break;
978 case SCANCODE_CHAR_RALT:
979 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
980 break;
981 case SCANCODE_CHAR_LWIN:
982 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
983 break;
984 case SCANCODE_CHAR_RWIN:
985 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
986 break;
987 case SCANCODE_CHAR_NUMLOCK:
988 /* KeyReleases for NumLocks are sent immediately. Toggle the
989 modifier state only on Keypress */
990 if (pressed && !g_numlock_sync)
991 {
992 RD_BOOL newNumLockState;
993 newNumLockState =
994 (MASK_HAS_BITS
995 (remote_modifier_state, MapNumLockMask) == False);
996 MASK_CHANGE_BIT(remote_modifier_state,
997 MapNumLockMask, newNumLockState);
998 }
999 }
1000
1001 #ifdef WITH_DEBUG_KBD
1002 if (old_modifier_state != remote_modifier_state)
1003 {
1004 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1005 old_modifier_state, pressed));
1006 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1007 }
1008 #endif
1009
1010 }
1011
1012 /* Send keyboard input */
1013 void
1014 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1015 {
1016 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1017
1018 if (scancode & SCANCODE_EXTENDED)
1019 {
1020 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1021 scancode & ~SCANCODE_EXTENDED, flags));
1022 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1023 scancode & ~SCANCODE_EXTENDED, 0);
1024 }
1025 else
1026 {
1027 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1028 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1029 }
1030 }

  ViewVC Help
Powered by ViewVC 1.1.26