/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 974 - (show annotations)
Thu Aug 4 12:50:15 2005 UTC (18 years, 10 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 23527 byte(s)
Created a common xstrdup function.

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

  ViewVC Help
Powered by ViewVC 1.1.26