VirtualBox

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

Last change on this file since 14833 was 11982, checked in by vboxsync, 16 years ago

All: license header changes for 2.0 (OSE headers, add Sun GPL/LGPL disclaimer)

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