VirtualBox

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

Last change on this file since 10809 was 9902, checked in by vboxsync, 17 years ago

Added rdesktop 1.6.0.

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