/[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 1010 - (show annotations)
Wed Aug 31 13:00:57 2005 UTC (18 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 23468 byte(s)
Using new utility function str_startswith, to get rid of many sizeof:s and hardcoded constants.

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

  ViewVC Help
Powered by ViewVC 1.1.26