VirtualBox

source: vbox/trunk/src/VBox/RDP/client/xkeymap.c@ 37224

Last change on this file since 37224 was 37224, checked in by vboxsync, 13 years ago

RDP/client: fix OSE

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