/[rdesktop]/sourceforge.net/trunk/rdesktop/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 964 - (show annotations)
Wed Aug 3 11:30:53 2005 UTC (18 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 23438 byte(s)
It is now possible to specify keyboard type, subtype and number of functionskeys. From patch #974509, by Dekaino.

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 <peter@cendio.se> 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
41 extern Display *g_display;
42 extern Window g_wnd;
43 extern char keymapname[16];
44 extern int g_keylayout;
45 extern int g_keyboard_type;
46 extern int g_keyboard_subtype;
47 extern int g_keyboard_functionkeys;
48 extern int g_win_button_size;
49 extern BOOL g_enable_compose;
50 extern BOOL g_use_rdp5;
51 extern BOOL g_numlock_sync;
52
53 static BOOL keymap_loaded;
54 static key_translation *keymap[KEYMAP_SIZE];
55 static int min_keycode;
56 static uint16 remote_modifier_state = 0;
57 static uint16 saved_remote_modifier_state = 0;
58
59 static void update_modifier_state(uint8 scancode, BOOL pressed);
60
61 /* Free key_translation structure, including linked list */
62 static void
63 free_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
75 static void
76 add_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
101 static void
102 add_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
162 void
163 xkeymap_from_locale(const char *locale)
164 {
165 char *str, *ptr;
166 FILE *fp;
167
168 /* Create a working copy */
169 str = strdup(locale);
170 if (str == NULL)
171 {
172 perror("strdup");
173 exit(1);
174 }
175
176 /* Truncate at dot and at */
177 ptr = strrchr(str, '.');
178 if (ptr)
179 *ptr = '\0';
180 ptr = strrchr(str, '@');
181 if (ptr)
182 *ptr = '\0';
183
184 /* Replace _ with - */
185 ptr = strrchr(str, '_');
186 if (ptr)
187 *ptr = '-';
188
189 /* Convert to lowercase */
190 ptr = str;
191 while (*ptr)
192 {
193 *ptr = tolower((int) *ptr);
194 ptr++;
195 }
196
197 /* Try to open this keymap (da-dk) */
198 fp = xkeymap_open(str);
199 if (fp == NULL)
200 {
201 /* Truncate at dash */
202 ptr = strrchr(str, '-');
203 if (ptr)
204 *ptr = '\0';
205
206 /* Try the short name (da) */
207 fp = xkeymap_open(str);
208 }
209
210 if (fp)
211 {
212 fclose(fp);
213 STRNCPY(keymapname, str, sizeof(keymapname));
214 fprintf(stderr, "Autoselected keyboard map %s.\n", keymapname);
215 }
216 }
217
218
219 /* Joins two path components. The result should be freed with
220 xfree(). */
221 static char *
222 pathjoin(const char *a, const char *b)
223 {
224 char *result;
225 result = xmalloc(PATH_MAX * 2 + 1);
226
227 if (b[0] == '/')
228 {
229 strncpy(result, b, PATH_MAX);
230 }
231 else
232 {
233 strncpy(result, a, PATH_MAX);
234 strcat(result, "/");
235 strncat(result, b, PATH_MAX);
236 }
237 return result;
238 }
239
240 /* Try to open a keymap with fopen() */
241 FILE *
242 xkeymap_open(const char *filename)
243 {
244 char *path1, *path2;
245 char *home;
246 FILE *fp;
247
248 /* Try ~/.rdesktop/keymaps */
249 home = getenv("HOME");
250 if (home)
251 {
252 path1 = pathjoin(home, ".rdesktop/keymaps");
253 path2 = pathjoin(path1, filename);
254 xfree(path1);
255 fp = fopen(path2, "r");
256 xfree(path2);
257 if (fp)
258 return fp;
259 }
260
261 /* Try KEYMAP_PATH */
262 path1 = pathjoin(KEYMAP_PATH, filename);
263 fp = fopen(path1, "r");
264 xfree(path1);
265 if (fp)
266 return fp;
267
268 /* Try current directory, in case we are running from the source
269 tree */
270 path1 = pathjoin("keymaps", filename);
271 fp = fopen(path1, "r");
272 xfree(path1);
273 if (fp)
274 return fp;
275
276 return NULL;
277 }
278
279 static BOOL
280 xkeymap_read(char *mapname)
281 {
282 FILE *fp;
283 char line[KEYMAP_MAX_LINE_LENGTH];
284 unsigned int line_num = 0;
285 unsigned int line_length = 0;
286 char *keyname, *p;
287 char *line_rest;
288 uint8 scancode;
289 uint16 modifiers;
290
291 fp = xkeymap_open(mapname);
292 if (fp == NULL)
293 {
294 error("Failed to open keymap %s\n", mapname);
295 return False;
296 }
297
298 /* FIXME: More tolerant on white space */
299 while (fgets(line, sizeof(line), fp) != NULL)
300 {
301 line_num++;
302
303 /* Replace the \n with \0 */
304 p = strchr(line, '\n');
305 if (p != NULL)
306 *p = 0;
307
308 line_length = strlen(line);
309
310 /* Completely empty line */
311 if (strspn(line, " \t\n\r\f\v") == line_length)
312 {
313 continue;
314 }
315
316 /* Include */
317 if (strncmp(line, "include ", 8) == 0)
318 {
319 if (!xkeymap_read(line + 8))
320 return False;
321 continue;
322 }
323
324 /* map */
325 if (strncmp(line, "map ", 4) == 0)
326 {
327 g_keylayout = strtol(line + 4, NULL, 16);
328 DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout));
329 continue;
330 }
331
332 /* compose */
333 if (strncmp(line, "enable_compose", 15) == 0)
334 {
335 DEBUG_KBD(("Enabling compose handling\n"));
336 g_enable_compose = True;
337 continue;
338 }
339
340 /* sequence */
341 if (strncmp(line, "sequence", 8) == 0)
342 {
343 add_sequence(line + 8, mapname);
344 continue;
345 }
346
347 /* keyboard_type */
348 if (strncmp(line, "keyboard_type ", sizeof("keyboard_type ")) == 0)
349 {
350 g_keyboard_type = strtol(line + sizeof("keyboard_type "), NULL, 16);
351 DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type));
352 continue;
353 }
354
355 /* keyboard_subtype */
356 if (strncmp(line, "keyboard_subtype ", sizeof("keyboard_subtype ")) == 0)
357 {
358 g_keyboard_subtype = strtol(line + sizeof("keyboard_subtype "), NULL, 16);
359 DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype));
360 continue;
361 }
362
363 /* keyboard_functionkeys */
364 if (strncmp(line, "keyboard_functionkeys ", sizeof("keyboard_functionkeys ")) == 0)
365 {
366 g_keyboard_functionkeys =
367 strtol(line + sizeof("keyboard_functionkeys "), 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 */
443 void
444 xkeymap_init(void)
445 {
446 unsigned int max_keycode;
447
448 if (strcmp(keymapname, "none"))
449 {
450 if (xkeymap_read(keymapname))
451 keymap_loaded = True;
452 }
453
454 XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
455 }
456
457 static void
458 send_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
495 static void
496 reset_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 */
507 BOOL
508 handle_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 /* Send Break sequence E0 46 E0 C6 */
526 if (pressed)
527 {
528 rdp_send_scancode(ev_time, RDP_KEYPRESS,
529 (SCANCODE_EXTENDED | 0x46));
530 rdp_send_scancode(ev_time, RDP_KEYPRESS,
531 (SCANCODE_EXTENDED | 0xc6));
532 }
533 /* No release sequence */
534 return True;
535 break;
536
537 case XK_Pause:
538 /* According to MS Keyboard Scan Code
539 Specification, pressing Pause should result
540 in E1 1D 45 E1 9D C5. I'm not exactly sure
541 of how this is supposed to be sent via
542 RDP. The code below seems to work, but with
543 the side effect that Left Ctrl stays
544 down. Therefore, we release it when Pause
545 is released. */
546 if (pressed)
547 {
548 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
549 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
550 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
551 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
552 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
553 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
554 }
555 else
556 {
557 /* Release Left Ctrl */
558 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
559 0x1d, 0);
560 }
561 return True;
562 break;
563
564 case XK_Meta_L: /* Windows keys */
565 case XK_Super_L:
566 case XK_Hyper_L:
567 send_winkey(ev_time, pressed, True);
568 return True;
569 break;
570
571 case XK_Meta_R:
572 case XK_Super_R:
573 case XK_Hyper_R:
574 send_winkey(ev_time, pressed, False);
575 return True;
576 break;
577
578 case XK_space:
579 /* Prevent access to the Windows system menu in single app mode */
580 if (g_win_button_size
581 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
582 return True;
583 break;
584
585 case XK_Num_Lock:
586 /* Synchronize on key release */
587 if (g_numlock_sync && !pressed)
588 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
589 ui_get_numlock_state(read_keyboard_state()), 0);
590
591 /* Inhibit */
592 return True;
593 break;
594
595 }
596 return False;
597 }
598
599
600 key_translation
601 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
602 {
603 key_translation tr = { 0, 0, 0, 0 };
604 key_translation *ptr;
605
606 ptr = keymap[keysym & KEYMAP_MASK];
607 if (ptr)
608 {
609 tr = *ptr;
610 if (tr.seq_keysym == 0) /* Normal scancode translation */
611 {
612 if (tr.modifiers & MapInhibitMask)
613 {
614 DEBUG_KBD(("Inhibiting key\n"));
615 tr.scancode = 0;
616 return tr;
617 }
618
619 if (tr.modifiers & MapLocalStateMask)
620 {
621 /* The modifiers to send for this key should be obtained
622 from the local state. Currently, only shift is implemented. */
623 if (state & ShiftMask)
624 {
625 tr.modifiers = MapLeftShiftMask;
626 }
627 }
628
629 if ((tr.modifiers & MapLeftShiftMask)
630 && ((remote_modifier_state & MapLeftCtrlMask)
631 || (remote_modifier_state & MapRightCtrlMask))
632 && get_key_state(state, XK_Caps_Lock))
633 {
634 DEBUG_KBD(("CapsLock + Ctrl pressed, releasing LeftShift\n"));
635 tr.modifiers ^= MapLeftShiftMask;
636 }
637
638 DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n",
639 tr.scancode, tr.modifiers));
640 }
641 }
642 else
643 {
644 if (keymap_loaded)
645 warning("No translation for (keysym 0x%lx, %s)\n", keysym,
646 get_ksname(keysym));
647
648 /* not in keymap, try to interpret the raw scancode */
649 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
650 {
651 tr.scancode = keycode - min_keycode;
652
653 /* The modifiers to send for this key should be
654 obtained from the local state. Currently, only
655 shift is implemented. */
656 if (state & ShiftMask)
657 {
658 tr.modifiers = MapLeftShiftMask;
659 }
660
661 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
662 }
663 else
664 {
665 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
666 }
667 }
668
669 return tr;
670 }
671
672 void
673 xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
674 BOOL pressed)
675 {
676 key_translation tr, *ptr;
677 tr = xkeymap_translate_key(keysym, keycode, state);
678
679 if (tr.seq_keysym == 0)
680 {
681 /* Scancode translation */
682 if (tr.scancode == 0)
683 return;
684
685 if (pressed)
686 {
687 save_remote_modifiers(tr.scancode);
688 ensure_remote_modifiers(ev_time, tr);
689 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
690 restore_remote_modifiers(ev_time, tr.scancode);
691 }
692 else
693 {
694 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
695 }
696 return;
697 }
698
699 /* Sequence, only on key down */
700 if (pressed)
701 {
702 ptr = &tr;
703 do
704 {
705 DEBUG_KBD(("Handling sequence element, keysym=0x%x\n",
706 (unsigned int) ptr->seq_keysym));
707 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True);
708 xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False);
709 ptr = ptr->next;
710 }
711 while (ptr);
712 }
713 }
714
715 uint16
716 xkeymap_translate_button(unsigned int button)
717 {
718 switch (button)
719 {
720 case Button1: /* left */
721 return MOUSE_FLAG_BUTTON1;
722 case Button2: /* middle */
723 return MOUSE_FLAG_BUTTON3;
724 case Button3: /* right */
725 return MOUSE_FLAG_BUTTON2;
726 case Button4: /* wheel up */
727 return MOUSE_FLAG_BUTTON4;
728 case Button5: /* wheel down */
729 return MOUSE_FLAG_BUTTON5;
730 }
731
732 return 0;
733 }
734
735 char *
736 get_ksname(uint32 keysym)
737 {
738 char *ksname = NULL;
739
740 if (keysym == NoSymbol)
741 ksname = "NoSymbol";
742 else if (!(ksname = XKeysymToString(keysym)))
743 ksname = "(no name)";
744
745 return ksname;
746 }
747
748 static BOOL
749 is_modifier(uint8 scancode)
750 {
751 switch (scancode)
752 {
753 case SCANCODE_CHAR_LSHIFT:
754 case SCANCODE_CHAR_RSHIFT:
755 case SCANCODE_CHAR_LCTRL:
756 case SCANCODE_CHAR_RCTRL:
757 case SCANCODE_CHAR_LALT:
758 case SCANCODE_CHAR_RALT:
759 case SCANCODE_CHAR_LWIN:
760 case SCANCODE_CHAR_RWIN:
761 case SCANCODE_CHAR_NUMLOCK:
762 return True;
763 default:
764 break;
765 }
766 return False;
767 }
768
769 void
770 save_remote_modifiers(uint8 scancode)
771 {
772 if (is_modifier(scancode))
773 return;
774
775 saved_remote_modifier_state = remote_modifier_state;
776 }
777
778 void
779 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
780 {
781 key_translation dummy;
782
783 if (is_modifier(scancode))
784 return;
785
786 dummy.scancode = 0;
787 dummy.modifiers = saved_remote_modifier_state;
788 ensure_remote_modifiers(ev_time, dummy);
789 }
790
791 void
792 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
793 {
794 /* If this key is a modifier, do nothing */
795 if (is_modifier(tr.scancode))
796 return;
797
798 if (!g_numlock_sync)
799 {
800 /* NumLock */
801 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
802 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
803 {
804 /* The remote modifier state is not correct */
805 uint16 new_remote_state;
806
807 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
808 {
809 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
810 new_remote_state = KBD_FLAG_NUMLOCK;
811 remote_modifier_state = MapNumLockMask;
812 }
813 else
814 {
815 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
816 new_remote_state = 0;
817 remote_modifier_state = 0;
818 }
819
820 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
821 }
822 }
823
824
825 /* Shift. Left shift and right shift are treated as equal; either is fine. */
826 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
827 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
828 {
829 /* The remote modifier state is not correct */
830 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
831 {
832 /* Needs left shift. Send down. */
833 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
834 }
835 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
836 {
837 /* Needs right shift. Send down. */
838 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
839 }
840 else
841 {
842 /* Should not use this modifier. Send up for shift currently pressed. */
843 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
844 /* Left shift is down */
845 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
846 else
847 /* Right shift is down */
848 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
849 }
850 }
851
852 /* AltGr */
853 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
854 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
855 {
856 /* The remote modifier state is not correct */
857 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
858 {
859 /* Needs this modifier. Send down. */
860 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
861 }
862 else
863 {
864 /* Should not use this modifier. Send up. */
865 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
866 }
867 }
868
869
870 }
871
872
873 unsigned int
874 read_keyboard_state()
875 {
876 #ifdef RDP2VNC
877 return 0;
878 #else
879 unsigned int state;
880 Window wdummy;
881 int dummy;
882
883 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
884 return state;
885 #endif
886 }
887
888
889 uint16
890 ui_get_numlock_state(unsigned int state)
891 {
892 uint16 numlock_state = 0;
893
894 if (get_key_state(state, XK_Num_Lock))
895 numlock_state = KBD_FLAG_NUMLOCK;
896
897 return numlock_state;
898 }
899
900
901 void
902 reset_modifier_keys()
903 {
904 unsigned int state = read_keyboard_state();
905
906 /* reset keys */
907 uint32 ev_time;
908 ev_time = time(NULL);
909
910 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
911 && !get_key_state(state, XK_Shift_L))
912 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
913
914 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
915 && !get_key_state(state, XK_Shift_R))
916 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
917
918 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
919 && !get_key_state(state, XK_Control_L))
920 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
921
922 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
923 && !get_key_state(state, XK_Control_R))
924 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
925
926 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
927 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
928
929 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
930 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch)
931 && !get_key_state(state, XK_ISO_Level3_Shift))
932 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
933
934 reset_winkey(ev_time);
935
936 if (g_numlock_sync)
937 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
938 }
939
940
941 static void
942 update_modifier_state(uint8 scancode, BOOL pressed)
943 {
944 #ifdef WITH_DEBUG_KBD
945 uint16 old_modifier_state;
946
947 old_modifier_state = remote_modifier_state;
948 #endif
949
950 switch (scancode)
951 {
952 case SCANCODE_CHAR_LSHIFT:
953 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
954 break;
955 case SCANCODE_CHAR_RSHIFT:
956 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
957 break;
958 case SCANCODE_CHAR_LCTRL:
959 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
960 break;
961 case SCANCODE_CHAR_RCTRL:
962 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
963 break;
964 case SCANCODE_CHAR_LALT:
965 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
966 break;
967 case SCANCODE_CHAR_RALT:
968 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
969 break;
970 case SCANCODE_CHAR_LWIN:
971 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
972 break;
973 case SCANCODE_CHAR_RWIN:
974 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
975 break;
976 case SCANCODE_CHAR_NUMLOCK:
977 /* KeyReleases for NumLocks are sent immediately. Toggle the
978 modifier state only on Keypress */
979 if (pressed && !g_numlock_sync)
980 {
981 BOOL newNumLockState;
982 newNumLockState =
983 (MASK_HAS_BITS
984 (remote_modifier_state, MapNumLockMask) == False);
985 MASK_CHANGE_BIT(remote_modifier_state,
986 MapNumLockMask, newNumLockState);
987 }
988 }
989
990 #ifdef WITH_DEBUG_KBD
991 if (old_modifier_state != remote_modifier_state)
992 {
993 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
994 old_modifier_state, pressed));
995 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
996 }
997 #endif
998
999 }
1000
1001 /* Send keyboard input */
1002 void
1003 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
1004 {
1005 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
1006
1007 if (scancode & SCANCODE_EXTENDED)
1008 {
1009 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
1010 scancode & ~SCANCODE_EXTENDED, flags));
1011 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
1012 scancode & ~SCANCODE_EXTENDED, 0);
1013 }
1014 else
1015 {
1016 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
1017 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
1018 }
1019 }

  ViewVC Help
Powered by ViewVC 1.1.26