VirtualBox

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

Last change on this file since 9176 was 8170, checked in by vboxsync, 17 years ago

Rebranding: replacing more innotek strings.

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