VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/xkeymap.c@ 72372

Last change on this file since 72372 was 55123, checked in by vboxsync, 10 years ago

rdesktop 1.8.3 modified for VBox

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.0 KB
Line 
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 <matthewc.unsw.edu.au> 1999-2008
6 Copyright 2003-2008 Peter Astrand <[email protected]> for Cendio AB
7 Copyright 2014 Henrik Andersson <[email protected]> for Cendio AB
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23/*
24 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
25 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
26 * the General Public License version 2 (GPLv2) at this time for any software where
27 * a choice of GPL license versions is made available with the language indicating
28 * that GPLv2 or any later version may be used, or where a choice of which version
29 * of the GPL is applied is otherwise unspecified.
30 */
31
32#ifdef RDP2VNC
33#include "vnc/x11stubs.h"
34#else
35#include <X11/Xlib.h>
36#include <X11/keysym.h>
37#endif
38
39#include <ctype.h>
40#include <limits.h>
41#include <time.h>
42#include <string.h>
43#include <assert.h>
44#include "rdesktop.h"
45#include "scancodes.h"
46
47#define KEYMAP_SIZE 0x7f+1
48#define KEYMAP_MASK 0x7f
49#define KEYMAP_MAX_LINE_LENGTH 80
50
51extern Display *g_display;
52extern Window g_wnd;
53extern char g_keymapname[16];
54extern unsigned int g_keylayout;
55extern int g_keyboard_type;
56extern int g_keyboard_subtype;
57extern int g_keyboard_functionkeys;
58extern int g_win_button_size;
59extern RD_BOOL g_enable_compose;
60extern RDP_VERSION g_rdp_version;
61extern RD_BOOL g_numlock_sync;
62
63static RD_BOOL keymap_loaded;
64static key_translation_entry *keymap[KEYMAP_SIZE];
65static KeySym keypress_keysyms[256];
66static int min_keycode;
67static uint16 remote_modifier_state = 0;
68static uint16 saved_remote_modifier_state = 0;
69
70static void update_modifier_state(uint8 scancode, RD_BOOL pressed);
71
72/* Free key_translation structure, including linked list */
73static void
74free_key_translation(key_translation * ptr)
75{
76 key_translation *next;
77
78 while (ptr)
79 {
80 next = ptr->next;
81 xfree(ptr);
82 ptr = next;
83 }
84}
85
86/* Free the key_translation_entry for a given keysym and remove from the table */
87static void
88delete_key_translation_entry(KeySym keysym)
89{
90 uint32 hash;
91 key_translation_entry *ptr;
92 key_translation_entry *next;
93 key_translation_entry *prev;
94 key_translation_entry tmp;
95
96 /* Faking a prev node allows us to keep the algorithm simple */
97 hash = keysym & KEYMAP_MASK;
98 ptr = keymap[hash];
99 tmp.next = ptr;
100 prev = &tmp;
101
102 while (ptr)
103 {
104 next = ptr->next;
105 if (ptr->keysym == keysym)
106 {
107 free_key_translation(ptr->tr);
108 prev->next = next;
109 xfree(ptr);
110 }
111 else
112 {
113 prev = ptr;
114 }
115
116 ptr = next;
117 }
118
119 /* Copy pointer back from our fake node */
120 keymap[hash] = tmp.next;
121}
122
123/* Allocate and return a new entry in the translation table */
124static key_translation_entry *
125new_key_translation_entry(KeySym keysym)
126{
127 uint32 hash;
128 key_translation_entry *entry;
129
130 /* Clear out any existing entry */
131 delete_key_translation_entry(keysym);
132
133 /* Allocate the new one */
134 entry = (key_translation_entry *) xmalloc(sizeof(key_translation_entry));
135 memset(entry, 0, sizeof(key_translation_entry));
136 entry->keysym = keysym;
137
138 /* And insert it at head of list */
139 hash = keysym & KEYMAP_MASK;
140 entry->next = keymap[hash];
141 keymap[hash] = entry;
142
143 return entry;
144}
145
146/* Retrieve the key_translation_entry for a given keysym */
147static key_translation_entry *
148get_key_translation_entry(uint32 keysym)
149{
150 key_translation_entry *ptr;
151 key_translation_entry *next;
152
153 ptr = keymap[keysym & KEYMAP_MASK];
154
155 while (ptr)
156 {
157 next = ptr->next;
158 if (ptr->keysym == keysym)
159 return ptr;
160
161 ptr = next;
162 }
163
164 /* Not found */
165 return NULL;
166}
167
168static void
169add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
170{
171 KeySym keysym;
172 key_translation_entry *entry;
173
174 keysym = XStringToKeysym(keyname);
175 if (keysym == NoSymbol)
176 {
177 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
178 return;
179 }
180
181 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
182 "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
183
184 /* Make a new entry in the table */
185 entry = new_key_translation_entry(keysym);
186
187 /* And add the new translation to it */
188 entry->tr = (key_translation *) xmalloc(sizeof(key_translation));
189 memset(entry->tr, 0, sizeof(key_translation));
190 entry->tr->scancode = scancode;
191 entry->tr->modifiers = modifiers;
192
193 return;
194}
195
196static void
197add_sequence(char *rest, char *mapname)
198{
199 KeySym keysym;
200 KeySym seq_keysym;
201 key_translation_entry *entry;
202 key_translation *tr, **prev_next;
203 size_t chars;
204 char keyname[KEYMAP_MAX_LINE_LENGTH];
205
206 /* Skip over whitespace after the sequence keyword */
207 chars = strspn(rest, " \t");
208 rest += chars;
209
210 /* Fetch the keysym name */
211 chars = strcspn(rest, " \t\0");
212 STRNCPY(keyname, rest, chars + 1);
213 rest += chars;
214
215 keysym = XStringToKeysym(keyname);
216 if (keysym == NoSymbol)
217 {
218 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname));
219 return;
220 }
221
222 DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
223
224 entry = new_key_translation_entry(keysym);
225 prev_next = &(entry->tr);
226
227 while (*rest)
228 {
229 /* Skip whitespace */
230 chars = strspn(rest, " \t");
231 rest += chars;
232
233 /* Fetch the keysym name */
234 chars = strcspn(rest, " \t\0");
235 STRNCPY(keyname, rest, chars + 1);
236 rest += chars;
237
238 /* Handle trailing whitespace */
239 if (*keyname == 0)
240 break;
241
242 seq_keysym = XStringToKeysym(keyname);
243 if (seq_keysym == NoSymbol)
244 {
245 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
246 mapname));
247 delete_key_translation_entry(keysym);
248 return;
249 }
250
251 /* Allocate space for key_translation structure */
252 tr = (key_translation *) xmalloc(sizeof(key_translation));
253 memset(tr, 0, sizeof(key_translation));
254
255 /* Do this straight away so the key_translation won't get orphaned on error */
256 if (!entry->tr)
257 entry->tr = tr;
258
259 *prev_next = tr;
260 prev_next = &tr->next;
261 tr->seq_keysym = seq_keysym;
262
263 DEBUG_KBD(("0x%x, ", (unsigned int) seq_keysym));
264 }
265 DEBUG_KBD(("\n"));
266}
267
268RD_BOOL
269xkeymap_from_locale(const char *locale)
270{
271 char *str, *ptr;
272 FILE *fp;
273
274 /* Create a working copy */
275 str = xstrdup(locale);
276
277 /* Truncate at dot and at */
278 ptr = strrchr(str, '.');
279 if (ptr)
280 *ptr = '\0';
281 ptr = strrchr(str, '@');
282 if (ptr)
283 *ptr = '\0';
284
285 /* Replace _ with - */
286 ptr = strrchr(str, '_');
287 if (ptr)
288 *ptr = '-';
289
290 /* Convert to lowercase */
291 ptr = str;
292 while (*ptr)
293 {
294 *ptr = tolower((int) *ptr);
295 ptr++;
296 }
297
298 /* Try to open this keymap (da-dk) */
299 fp = xkeymap_open(str);
300 if (fp == NULL)
301 {
302 /* Truncate at dash */
303 ptr = strrchr(str, '-');
304 if (ptr)
305 *ptr = '\0';
306
307 /* Try the short name (da) */
308 fp = xkeymap_open(str);
309 }
310
311 if (fp)
312 {
313 fclose(fp);
314 STRNCPY(g_keymapname, str, sizeof(g_keymapname));
315 xfree(str);
316 return True;
317 }
318
319 xfree(str);
320 return False;
321}
322
323
324/* Joins two path components. The result should be freed with
325 xfree(). */
326static char *
327pathjoin(const char *a, const char *b)
328{
329 char *result;
330 result = xmalloc(PATH_MAX * 2 + 1);
331
332 if (b[0] == '/')
333 {
334 strncpy(result, b, PATH_MAX);
335 }
336 else
337 {
338 strncpy(result, a, PATH_MAX);
339 strcat(result, "/");
340 strncat(result, b, PATH_MAX);
341 }
342 return result;
343}
344
345/* Try to open a keymap with fopen() */
346FILE *
347xkeymap_open(const char *filename)
348{
349 char *path1, *path2;
350 char *home;
351 FILE *fp;
352
353 /* Try ~/.rdesktop/keymaps */
354 home = getenv("HOME");
355 if (home)
356 {
357 path1 = pathjoin(home, ".rdesktop/keymaps");
358 path2 = pathjoin(path1, filename);
359 xfree(path1);
360 fp = fopen(path2, "r");
361 xfree(path2);
362 if (fp)
363 return fp;
364 }
365
366 /* Try KEYMAP_PATH */
367 path1 = pathjoin(KEYMAP_PATH, filename);
368 fp = fopen(path1, "r");
369 xfree(path1);
370 if (fp)
371 return fp;
372
373 /* Try current directory, in case we are running from the source
374 tree */
375 path1 = pathjoin("keymaps", filename);
376 fp = fopen(path1, "r");
377 xfree(path1);
378 if (fp)
379 return fp;
380
381 return NULL;
382}
383
384static RD_BOOL
385xkeymap_read(char *mapname)
386{
387 FILE *fp;
388 char line[KEYMAP_MAX_LINE_LENGTH];
389 unsigned int line_num = 0;
390 unsigned int line_length = 0;
391 char *keyname, *p;
392 char *line_rest;
393 uint8 scancode;
394 uint16 modifiers;
395
396 fp = xkeymap_open(mapname);
397 if (fp == NULL)
398 {
399 error("Failed to open keymap %s\n", mapname);
400 return False;
401 }
402
403 /* FIXME: More tolerant on white space */
404 while (fgets(line, sizeof(line), fp) != NULL)
405 {
406 line_num++;
407
408 /* Replace the \n with \0 */
409 p = strchr(line, '\n');
410 if (p != NULL)
411 *p = 0;
412
413 line_length = strlen(line);
414
415 /* Completely empty line */
416 if (strspn(line, " \t\n\r\f\v") == line_length)
417 {
418 continue;
419 }
420
421 /* Include */
422 if (str_startswith(line, "include "))
423 {
424 if (!xkeymap_read(line + sizeof("include ") - 1))
425 return False;
426 continue;
427 }
428
429 /* map */
430 if (str_startswith(line, "map "))
431 {
432 g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16);
433 DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
434 continue;
435 }
436
437 /* compose */
438 if (str_startswith(line, "enable_compose"))
439 {
440 DEBUG_KBD(("Enabling compose handling\n"));
441 g_enable_compose = True;
442 continue;
443 }
444
445 /* sequence */
446 if (str_startswith(line, "sequence"))
447 {
448 add_sequence(line + sizeof("sequence") - 1, mapname);
449 continue;
450 }
451
452 /* keyboard_type */
453 if (str_startswith(line, "keyboard_type "))
454 {
455 g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16);
456 DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
457 continue;
458 }
459
460 /* keyboard_subtype */
461 if (str_startswith(line, "keyboard_subtype "))
462 {
463 g_keyboard_subtype =
464 strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16);
465 DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
466 continue;
467 }
468
469 /* keyboard_functionkeys */
470 if (str_startswith(line, "keyboard_functionkeys "))
471 {
472 g_keyboard_functionkeys =
473 strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16);
474 DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys));
475 continue;
476 }
477
478 /* Comment */
479 if (line[0] == '#')
480 {
481 continue;
482 }
483
484 /* Normal line */
485 keyname = line;
486 p = strchr(line, ' ');
487 if (p == NULL)
488 {
489 error("Bad line %d in keymap %s\n", line_num, mapname);
490 continue;
491 }
492 else
493 {
494 *p = 0;
495 }
496
497 /* scancode */
498 p++;
499 scancode = strtol(p, &line_rest, 16);
500
501 /* flags */
502 /* FIXME: Should allow case-insensitive flag names.
503 Fix by using lex+yacc... */
504 modifiers = 0;
505 if (strstr(line_rest, "altgr"))
506 {
507 MASK_ADD_BITS(modifiers, MapAltGrMask);
508 }
509
510 if (strstr(line_rest, "shift"))
511 {
512 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
513 }
514
515 if (strstr(line_rest, "numlock"))
516 {
517 MASK_ADD_BITS(modifiers, MapNumLockMask);
518 }
519
520 if (strstr(line_rest, "localstate"))
521 {
522 MASK_ADD_BITS(modifiers, MapLocalStateMask);
523 }
524
525 if (strstr(line_rest, "inhibit"))
526 {
527 MASK_ADD_BITS(modifiers, MapInhibitMask);
528 }
529
530 add_to_keymap(keyname, scancode, modifiers, mapname);
531
532 if (strstr(line_rest, "addupper"))
533 {
534 /* Automatically add uppercase key, with same modifiers
535 plus shift */
536 for (p = keyname; *p; p++)
537 *p = toupper((int) *p);
538 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
539 add_to_keymap(keyname, scancode, modifiers, mapname);
540 }
541 }
542
543 fclose(fp);
544 return True;
545}
546
547
548/* Before connecting and creating UI */
549void
550xkeymap_init(void)
551{
552 unsigned int max_keycode;
553
554 if (strcmp(g_keymapname, "none"))
555 {
556 if (xkeymap_read(g_keymapname))
557 keymap_loaded = True;
558 }
559
560 XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
561}
562
563static void
564send_winkey(uint32 ev_time, RD_BOOL pressed, RD_BOOL leftkey)
565{
566 uint8 winkey;
567
568 if (leftkey)
569 winkey = SCANCODE_CHAR_LWIN;
570 else
571 winkey = SCANCODE_CHAR_RWIN;
572
573 if (pressed)
574 {
575 if (g_rdp_version >= RDP_V5)
576 {
577 rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
578 }
579 else
580 {
581 /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
582 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
583 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
584 }
585 }
586 else
587 {
588 /* key released */
589 if (g_rdp_version >= RDP_V5)
590 {
591 rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
592 }
593 else
594 {
595 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
596 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
597 }
598 }
599}
600
601static void
602reset_winkey(uint32 ev_time)
603{
604 if (g_rdp_version >= RDP_V5)
605 {
606 /* For some reason, it seems to suffice to release
607 *either* the left or right winkey. */
608 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
609 }
610}
611
612
613void
614set_keypress_keysym(unsigned int keycode, KeySym keysym)
615{
616 if (keycode < 8 || keycode > 255)
617 return;
618 keypress_keysyms[keycode] = keysym;
619}
620
621
622KeySym
623reset_keypress_keysym(unsigned int keycode, KeySym keysym)
624{
625 KeySym ks;
626 if (keycode < 8 || keycode > 255)
627 return keysym;
628 ks = keypress_keysyms[keycode];
629 if (ks != 0)
630 {
631 keypress_keysyms[keycode] = 0;
632 }
633 else
634 {
635 ks = keysym;
636 }
637
638 return ks;
639}
640
641
642/* Handle special key combinations */
643RD_BOOL
644handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed)
645{
646 switch (keysym)
647 {
648 case XK_Return:
649 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
650 && (get_key_state(state, XK_Control_L)
651 || get_key_state(state, XK_Control_R)))
652 {
653 /* Ctrl-Alt-Enter: toggle full screen */
654 if (pressed)
655 xwin_toggle_fullscreen();
656 return True;
657 }
658 break;
659
660 case XK_Break:
661#ifdef RDESKTOP_KBD_CODE
662 /* Send Break sequence E0 46 E0 C6 */
663 if (pressed)
664 {
665 rdp_send_scancode(ev_time, RDP_KEYPRESS,
666 (SCANCODE_EXTENDED | 0x46));
667 rdp_send_scancode(ev_time, RDP_KEYPRESS,
668 (SCANCODE_EXTENDED | 0xc6));
669 }
670 /* No release sequence */
671 return True;
672#else
673 /* Send Break sequence E0 46 E0 C6 */
674 if (pressed)
675 {
676 /* VirtualBox code begin */
677 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_EXT, 0x46, 0);
678 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_EXT | KBD_FLAG_UP, 0x46, 0);
679 /* VirtualBox code end */
680 }
681 /* No release sequence */
682 return True;
683#endif /* RDESKTOP_KBD_CODE */
684 break;
685
686 case XK_Pause:
687#ifdef RDESKTOP_KBD_CODE
688 /* According to MS Keyboard Scan Code
689 Specification, pressing Pause should result
690 in E1 1D 45 E1 9D C5. I'm not exactly sure
691 of how this is supposed to be sent via
692 RDP. The code below seems to work, but with
693 the side effect that Left Ctrl stays
694 down. Therefore, we release it when Pause
695 is released. */
696 if (pressed)
697 {
698 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
699 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
700 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
701 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
702 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
703 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
704 }
705 else
706 {
707 /* Release Left Ctrl */
708 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
709 0x1d, 0);
710 }
711 return True;
712#else
713 /* Send Break sequence E1 1D 45 E1 9D C5 */
714 if (pressed)
715 {
716 /* VirtualBox code begin */
717 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_EXT2, 0x1d, 0);
718 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
719 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_EXT2 | KBD_FLAG_UP, 0x1d, 0);
720 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x45, 0);
721 /* VirtualBox code end */
722 }
723 /* No release sequence */
724 return True;
725#endif /* RDESKTOP_KBD_CODE */
726 break;
727
728 case XK_Meta_L: /* Windows keys */
729 case XK_Super_L:
730 case XK_Hyper_L:
731 send_winkey(ev_time, pressed, True);
732 return True;
733 break;
734
735 case XK_Meta_R:
736 case XK_Super_R:
737 case XK_Hyper_R:
738 send_winkey(ev_time, pressed, False);
739 return True;
740 break;
741
742 case XK_space:
743 /* Prevent access to the Windows system menu in single app mode */
744 if (g_win_button_size
745 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
746 return True;
747 break;
748
749 case XK_Num_Lock:
750 /* Synchronize on key release */
751 if (g_numlock_sync && !pressed)
752 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
753 ui_get_numlock_state(read_keyboard_state()), 0);
754
755 /* Inhibit */
756 return True;
757 break;
758 case XK_Overlay1_Enable:
759 /* Toggle SeamlessRDP */
760 if (pressed)
761 ui_seamless_toggle();
762 break;
763#ifdef WITH_BIRD_VD_HACKS
764 case XK_Left:
765 case XK_Right:
766 {
767 /* Check for typical virtual desktop switching hotkeys:
768 Ctrl-Alt-Left and Ctrl-Alt-Right.
769 Needs to be pressed twice to have any effect... */
770 extern RD_BOOL g_keep_virtual_desktop_shortcuts;
771 extern RD_BOOL g_fullscreen;
772 if ( g_keep_virtual_desktop_shortcuts
773 && ( ( get_key_state(state, XK_Alt_L)
774 || get_key_state(state, XK_Alt_R))
775 && ( get_key_state(state, XK_Control_L)
776 || get_key_state(state, XK_Control_R))
777 )
778 )
779 {
780 if (g_fullscreen)
781 xwin_toggle_fullscreen();
782 XUngrabKeyboard(g_display, CurrentTime);
783 return True;
784 }
785 break;
786 }
787#endif
788 }
789 return False;
790}
791
792
793key_translation
794xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
795{
796 key_translation tr = { 0, 0, 0, 0 };
797 key_translation *ptr;
798 key_translation_entry *entry;
799
800 entry = get_key_translation_entry(keysym);
801 ptr = entry ? entry->tr : NULL;
802
803 if (ptr)
804 {
805 tr = *ptr;
806 if (tr.seq_keysym == 0) /* Normal scancode translation */
807 {
808 if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask))
809 {
810 DEBUG_KBD(("Inhibiting key\n"));
811 tr.scancode = 0;
812 return tr;
813 }
814
815 if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask))
816 {
817 /* The modifiers to send for this key should be obtained
818 from the local state. Currently, only shift is implemented. */
819 if (MASK_HAS_BITS(state, ShiftMask))
820 {
821 tr.modifiers = MapLeftShiftMask;
822 }
823 }
824
825 /* Windows interprets CapsLock+Ctrl+key
826 differently from Shift+Ctrl+key. Since we
827 are simulating CapsLock with Shifts, things
828 like Ctrl+f with CapsLock on breaks. To
829 solve this, we are releasing Shift if Ctrl
830 is on, but only if Shift isn't physically pressed. */
831 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
832 && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask)
833 && !MASK_HAS_BITS(state, ShiftMask))
834 {
835 DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n"));
836 MASK_REMOVE_BITS(tr.modifiers, MapShiftMask);
837 }
838
839 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
840 tr.scancode, tr.modifiers));
841 }
842 }
843 else
844 {
845 if (keymap_loaded)
846 warning("No translation for (keysym 0x%lx, %s)\n", keysym,
847 get_ksname(keysym));
848
849 /* not in keymap, try to interpret the raw scancode */
850 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
851 {
852 tr.scancode = keycode - min_keycode;
853
854 /* The modifiers to send for this key should be
855 obtained from the local state. Currently, only
856 shift is implemented. */
857 if (MASK_HAS_BITS(state, ShiftMask))
858 {
859 tr.modifiers = MapLeftShiftMask;
860 }
861
862 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
863 }
864 else
865 {
866 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
867 }
868 }
869
870 return tr;
871}
872
873static RD_BOOL
874is_modifier(uint8 scancode)
875{
876 switch (scancode)
877 {
878 case SCANCODE_CHAR_LSHIFT:
879 case SCANCODE_CHAR_RSHIFT:
880 case SCANCODE_CHAR_LCTRL:
881 case SCANCODE_CHAR_RCTRL:
882 case SCANCODE_CHAR_LALT:
883 case SCANCODE_CHAR_RALT:
884 case SCANCODE_CHAR_LWIN:
885 case SCANCODE_CHAR_RWIN:
886 case SCANCODE_CHAR_NUMLOCK:
887 return True;
888 default:
889 break;
890 }
891 return False;
892}
893
894
895void
896xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
897 RD_BOOL pressed, uint8 nesting)
898{
899 key_translation tr, *ptr;
900 tr = xkeymap_translate_key(keysym, keycode, state);
901
902 if (tr.seq_keysym == 0)
903 {
904 /* Scancode translation */
905 if (tr.scancode == 0)
906 return;
907
908 save_remote_modifiers(tr.scancode);
909 ensure_remote_modifiers(ev_time, tr);
910 rdp_send_scancode(ev_time, pressed ? RDP_KEYPRESS : RDP_KEYRELEASE, tr.scancode);
911 restore_remote_modifiers(ev_time, tr.scancode);
912 return;
913 }
914
915 /* Sequence, only on key down */
916 if (pressed)
917 {
918 ptr = &tr;
919 do
920 {
921 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
922 (unsigned int) ptr->seq_keysym));
923
924 if (nesting++ > 32)
925 {
926 error("Sequence nesting too deep\n");
927 return;
928 }
929
930 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting);
931 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting);
932 ptr = ptr->next;
933 }
934 while (ptr);
935 }
936}
937
938uint16
939xkeymap_translate_button(unsigned int button)
940{
941 switch (button)
942 {
943 case Button1: /* left */
944 return MOUSE_FLAG_BUTTON1;
945 case Button2: /* middle */
946 return MOUSE_FLAG_BUTTON3;
947 case Button3: /* right */
948 return MOUSE_FLAG_BUTTON2;
949 case Button4: /* wheel up */
950 return MOUSE_FLAG_BUTTON4;
951 case Button5: /* wheel down */
952 return MOUSE_FLAG_BUTTON5;
953 }
954
955 return 0;
956}
957
958char *
959get_ksname(uint32 keysym)
960{
961 char *ksname = NULL;
962
963 if (keysym == NoSymbol)
964 ksname = "NoSymbol";
965 else if (!(ksname = XKeysymToString(keysym)))
966 ksname = "(no name)";
967
968 return ksname;
969}
970
971void
972save_remote_modifiers(uint8 scancode)
973{
974 if (is_modifier(scancode))
975 return;
976
977 saved_remote_modifier_state = remote_modifier_state;
978}
979
980void
981restore_remote_modifiers(uint32 ev_time, uint8 scancode)
982{
983 key_translation dummy = { };
984
985 if (is_modifier(scancode))
986 return;
987
988 dummy.scancode = 0;
989 dummy.modifiers = saved_remote_modifier_state;
990 ensure_remote_modifiers(ev_time, dummy);
991}
992
993void
994ensure_remote_modifiers(uint32 ev_time, key_translation tr)
995{
996 /* If this key is a modifier, do nothing */
997 if (is_modifier(tr.scancode))
998 return;
999
1000 if (!g_numlock_sync)
1001 {
1002 /* NumLock */
1003 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
1004 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
1005 {
1006 /* The remote modifier state is not correct */
1007 uint16 new_remote_state;
1008
1009 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
1010 {
1011 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
1012 new_remote_state = KBD_FLAG_NUMLOCK;
1013 remote_modifier_state = MapNumLockMask;
1014 }
1015 else
1016 {
1017 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
1018 new_remote_state = 0;
1019 remote_modifier_state = 0;
1020 }
1021
1022 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
1023 }
1024 }
1025
1026
1027 /* Shift. Left shift and right shift are treated as equal; either is fine. */
1028 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
1029 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
1030 {
1031 /* The remote modifier state is not correct */
1032 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
1033 {
1034 /* Needs left shift. Send down. */
1035 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
1036 }
1037 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
1038 {
1039 /* Needs right shift. Send down. */
1040 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
1041 }
1042 else
1043 {
1044 /* Should not use this modifier. Send up for shift currently pressed. */
1045 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
1046 /* Left shift is down */
1047 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
1048 else
1049 /* Right shift is down */
1050 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
1051 }
1052 }
1053
1054 /* AltGr */
1055 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
1056 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
1057 {
1058 /* The remote modifier state is not correct */
1059 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
1060 {
1061 /* Needs this modifier. Send down. */
1062 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
1063 }
1064 else
1065 {
1066 /* Should not use this modifier. Send up. */
1067 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
1068 }
1069 }
1070
1071
1072}
1073
1074
1075unsigned int
1076read_keyboard_state()
1077{
1078#ifdef RDP2VNC
1079 return 0;
1080#else
1081 unsigned int state;
1082 Window wdummy;
1083 int dummy;
1084
1085 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
1086 return state;
1087#endif
1088}
1089
1090
1091uint16
1092ui_get_numlock_state(unsigned int state)
1093{
1094 uint16 numlock_state = 0;
1095
1096 if (get_key_state(state, XK_Num_Lock))
1097 numlock_state = KBD_FLAG_NUMLOCK;
1098
1099 return numlock_state;
1100}
1101
1102
1103void
1104reset_modifier_keys()
1105{
1106 unsigned int state = read_keyboard_state();
1107
1108 /* reset keys */
1109 uint32 ev_time;
1110 ev_time = time(NULL);
1111
1112 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
1113 && !get_key_state(state, XK_Shift_L))
1114 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
1115
1116 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
1117 && !get_key_state(state, XK_Shift_R))
1118 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
1119
1120 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
1121 && !get_key_state(state, XK_Control_L))
1122 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
1123
1124 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
1125 && !get_key_state(state, XK_Control_R))
1126 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
1127
1128 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
1129 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
1130
1131 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
1132 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
1133 && !get_key_state(state, XK_ISO_Level3_Shift))
1134 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
1135
1136 reset_winkey(ev_time);
1137
1138 if (g_numlock_sync)
1139 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
1140}
1141
1142
1143static void
1144update_modifier_state(uint8 scancode, RD_BOOL pressed)
1145{
1146#ifdef WITH_DEBUG_KBD
1147 uint16 old_modifier_state;
1148
1149 old_modifier_state = remote_modifier_state;
1150#endif
1151
1152 switch (scancode)
1153 {
1154 case SCANCODE_CHAR_LSHIFT:
1155 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
1156 break;
1157 case SCANCODE_CHAR_RSHIFT:
1158 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
1159 break;
1160 case SCANCODE_CHAR_LCTRL:
1161 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
1162 break;
1163 case SCANCODE_CHAR_RCTRL:
1164 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
1165 break;
1166 case SCANCODE_CHAR_LALT:
1167 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
1168 break;
1169 case SCANCODE_CHAR_RALT:
1170 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
1171 break;
1172 case SCANCODE_CHAR_LWIN:
1173 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
1174 break;
1175 case SCANCODE_CHAR_RWIN:
1176 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
1177 break;
1178 case SCANCODE_CHAR_NUMLOCK:
1179 /* KeyReleases for NumLocks are sent immediately. Toggle the
1180 modifier state only on Keypress */
1181 if (pressed && !g_numlock_sync)
1182 {
1183 RD_BOOL newNumLockState;
1184 newNumLockState =
1185 (MASK_HAS_BITS
1186 (remote_modifier_state, MapNumLockMask) == False);
1187 MASK_CHANGE_BIT(remote_modifier_state,
1188 MapNumLockMask, newNumLockState);
1189 }
1190 }
1191
1192#ifdef WITH_DEBUG_KBD
1193 if (old_modifier_state != remote_modifier_state)
1194 {
1195 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
1196 old_modifier_state, pressed));
1197 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
1198 }
1199#endif
1200
1201}
1202
1203/* Send keyboard input */
1204void
1205rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1206{
1207 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1208
1209 if (scancode & SCANCODE_EXTENDED)
1210 {
1211 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1212 scancode & ~SCANCODE_EXTENDED, flags));
1213 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1214 scancode & ~SCANCODE_EXTENDED, 0);
1215 }
1216 else
1217 {
1218 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1219 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1220 }
1221}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette