/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 548 - (show annotations)
Tue Nov 11 14:01:31 2003 UTC (20 years, 6 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xkeymap.c
File MIME type: text/plain
File size: 16234 byte(s)
Resetting Windows key state in reset_modifiers

1 /*
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X keyboard mapping
4
5 Copyright (C) Matthew Chapman 1999-2002
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 "rdesktop.h"
34 #include "scancodes.h"
35
36 #define KEYMAP_SIZE 0xffff+1
37 #define KEYMAP_MASK 0xffff
38 #define KEYMAP_MAX_LINE_LENGTH 80
39
40 extern Display *g_display;
41 extern Window g_wnd;
42 extern char keymapname[16];
43 extern int keylayout;
44 extern int g_win_button_size;
45 extern BOOL g_enable_compose;
46 extern BOOL g_use_rdp5;
47
48 static BOOL keymap_loaded;
49 static key_translation keymap[KEYMAP_SIZE];
50 static int min_keycode;
51 static uint16 remote_modifier_state = 0;
52 static uint16 saved_remote_modifier_state = 0;
53
54 static void update_modifier_state(uint8 scancode, BOOL pressed);
55
56 static void
57 add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
58 {
59 KeySym keysym;
60
61 keysym = XStringToKeysym(keyname);
62 if (keysym == NoSymbol)
63 {
64 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
65 return;
66 }
67
68 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
69 "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
70
71 keymap[keysym & KEYMAP_MASK].scancode = scancode;
72 keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
73
74 return;
75 }
76
77
78 static BOOL
79 xkeymap_read(char *mapname)
80 {
81 FILE *fp;
82 char line[KEYMAP_MAX_LINE_LENGTH];
83 char path[PATH_MAX], inplace_path[PATH_MAX];
84 unsigned int line_num = 0;
85 unsigned int line_length = 0;
86 char *keyname, *p;
87 char *line_rest;
88 uint8 scancode;
89 uint16 modifiers;
90
91
92 strcpy(path, KEYMAP_PATH);
93 strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
94
95 fp = fopen(path, "r");
96 if (fp == NULL)
97 {
98 /* in case we are running from the source tree */
99 strcpy(inplace_path, "keymaps/");
100 strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));
101
102 fp = fopen(inplace_path, "r");
103 if (fp == NULL)
104 {
105 error("Failed to open keymap %s\n", path);
106 return False;
107 }
108 }
109
110 /* FIXME: More tolerant on white space */
111 while (fgets(line, sizeof(line), fp) != NULL)
112 {
113 line_num++;
114
115 /* Replace the \n with \0 */
116 p = strchr(line, '\n');
117 if (p != NULL)
118 *p = 0;
119
120 line_length = strlen(line);
121
122 /* Completely empty line */
123 if (strspn(line, " \t\n\r\f\v") == line_length)
124 {
125 continue;
126 }
127
128 /* Include */
129 if (strncmp(line, "include ", 8) == 0)
130 {
131 if (!xkeymap_read(line + 8))
132 return False;
133 continue;
134 }
135
136 /* map */
137 if (strncmp(line, "map ", 4) == 0)
138 {
139 keylayout = strtol(line + 4, NULL, 16);
140 DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
141 continue;
142 }
143
144 /* compose */
145 if (strncmp(line, "enable_compose", 15) == 0)
146 {
147 DEBUG_KBD(("Enabling compose handling\n"));
148 g_enable_compose = True;
149 continue;
150 }
151
152 /* Comment */
153 if (line[0] == '#')
154 {
155 continue;
156 }
157
158 /* Normal line */
159 keyname = line;
160 p = strchr(line, ' ');
161 if (p == NULL)
162 {
163 error("Bad line %d in keymap %s\n", line_num, mapname);
164 continue;
165 }
166 else
167 {
168 *p = 0;
169 }
170
171 /* scancode */
172 p++;
173 scancode = strtol(p, &line_rest, 16);
174
175 /* flags */
176 /* FIXME: Should allow case-insensitive flag names.
177 Fix by using lex+yacc... */
178 modifiers = 0;
179 if (strstr(line_rest, "altgr"))
180 {
181 MASK_ADD_BITS(modifiers, MapAltGrMask);
182 }
183
184 if (strstr(line_rest, "shift"))
185 {
186 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
187 }
188
189 if (strstr(line_rest, "localstate"))
190 {
191 MASK_ADD_BITS(modifiers, MapLocalStateMask);
192 }
193
194 if (strstr(line_rest, "inhibit"))
195 {
196 MASK_ADD_BITS(modifiers, MapInhibitMask);
197 }
198
199 add_to_keymap(keyname, scancode, modifiers, mapname);
200
201 if (strstr(line_rest, "addupper"))
202 {
203 /* Automatically add uppercase key, with same modifiers
204 plus shift */
205 for (p = keyname; *p; p++)
206 *p = toupper((int) *p);
207 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
208 add_to_keymap(keyname, scancode, modifiers, mapname);
209 }
210 }
211
212 fclose(fp);
213 return True;
214 }
215
216
217 /* Before connecting and creating UI */
218 void
219 xkeymap_init(void)
220 {
221 unsigned int max_keycode;
222 char *mapname_ptr;
223
224 /* Make keymapname lowercase */
225 mapname_ptr = keymapname;
226 while (*mapname_ptr)
227 {
228 *mapname_ptr = tolower((int) *mapname_ptr);
229 mapname_ptr++;
230 }
231
232 if (strcmp(keymapname, "none"))
233 {
234 if (xkeymap_read(keymapname))
235 keymap_loaded = True;
236 }
237
238 XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
239 }
240
241 static void
242 send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
243 {
244 uint8 winkey;
245
246 if (leftkey)
247 winkey = SCANCODE_CHAR_LWIN;
248 else
249 winkey = SCANCODE_CHAR_RWIN;
250
251 if (pressed)
252 {
253 if (g_use_rdp5)
254 {
255 rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
256 }
257 else
258 {
259 /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
260 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
261 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
262 }
263 }
264 else
265 {
266 /* key released */
267 if (g_use_rdp5)
268 {
269 rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
270 }
271 else
272 {
273 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
274 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
275 }
276 }
277 }
278
279 static void
280 reset_winkey(uint32 ev_time)
281 {
282 if (g_use_rdp5)
283 {
284 /* For some reason, it seems to suffice to release
285 *either* the left or right winkey. */
286 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
287 }
288 }
289
290 /* Handles, for example, multi-scancode keypresses (which is not
291 possible via keymap-files) */
292 BOOL
293 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
294 {
295 switch (keysym)
296 {
297 case XK_Return:
298 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
299 && (get_key_state(state, XK_Control_L)
300 || get_key_state(state, XK_Control_R)))
301 {
302 /* Ctrl-Alt-Enter: toggle full screen */
303 if (pressed)
304 xwin_toggle_fullscreen();
305 return True;
306 }
307 break;
308
309 case XK_Break:
310 /* Send Break sequence E0 46 E0 C6 */
311 if (pressed)
312 {
313 rdp_send_scancode(ev_time, RDP_KEYPRESS,
314 (SCANCODE_EXTENDED | 0x46));
315 rdp_send_scancode(ev_time, RDP_KEYPRESS,
316 (SCANCODE_EXTENDED | 0xc6));
317 }
318 /* No release sequence */
319 return True;
320
321 case XK_Pause:
322 /* According to MS Keyboard Scan Code
323 Specification, pressing Pause should result
324 in E1 1D 45 E1 9D C5. I'm not exactly sure
325 of how this is supposed to be sent via
326 RDP. The code below seems to work, but with
327 the side effect that Left Ctrl stays
328 down. Therefore, we release it when Pause
329 is released. */
330 if (pressed)
331 {
332 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
333 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
334 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
335 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
336 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
337 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
338 }
339 else
340 {
341 /* Release Left Ctrl */
342 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
343 0x1d, 0);
344 }
345 return True;
346
347 case XK_Meta_L: /* Windows keys */
348 case XK_Super_L:
349 case XK_Hyper_L:
350 send_winkey(ev_time, pressed, True);
351 return True;
352
353 case XK_Meta_R:
354 case XK_Super_R:
355 case XK_Hyper_R:
356 send_winkey(ev_time, pressed, False);
357 return True;
358
359 case XK_space:
360 /* Prevent access to the Windows system menu in single app mode */
361 if (g_win_button_size
362 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
363 return True;
364
365 }
366 return False;
367 }
368
369
370 key_translation
371 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
372 {
373 key_translation tr = { 0, 0 };
374
375 tr = keymap[keysym & KEYMAP_MASK];
376
377 if (tr.modifiers & MapInhibitMask)
378 {
379 DEBUG_KBD(("Inhibiting key\n"));
380 tr.scancode = 0;
381 return tr;
382 }
383
384 if (tr.modifiers & MapLocalStateMask)
385 {
386 /* The modifiers to send for this key should be obtained
387 from the local state. Currently, only shift is implemented. */
388 if (state & ShiftMask)
389 {
390 tr.modifiers = MapLeftShiftMask;
391 }
392 }
393
394 if (tr.scancode != 0)
395 {
396 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
397 tr.scancode, tr.modifiers));
398 return tr;
399 }
400
401 if (keymap_loaded)
402 warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
403
404 /* not in keymap, try to interpret the raw scancode */
405 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
406 {
407 tr.scancode = keycode - min_keycode;
408
409 /* The modifiers to send for this key should be
410 obtained from the local state. Currently, only
411 shift is implemented. */
412 if (state & ShiftMask)
413 {
414 tr.modifiers = MapLeftShiftMask;
415 }
416
417 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
418 }
419 else
420 {
421 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
422 }
423
424 return tr;
425 }
426
427 uint16
428 xkeymap_translate_button(unsigned int button)
429 {
430 switch (button)
431 {
432 case Button1: /* left */
433 return MOUSE_FLAG_BUTTON1;
434 case Button2: /* middle */
435 return MOUSE_FLAG_BUTTON3;
436 case Button3: /* right */
437 return MOUSE_FLAG_BUTTON2;
438 case Button4: /* wheel up */
439 return MOUSE_FLAG_BUTTON4;
440 case Button5: /* wheel down */
441 return MOUSE_FLAG_BUTTON5;
442 }
443
444 return 0;
445 }
446
447 char *
448 get_ksname(uint32 keysym)
449 {
450 char *ksname = NULL;
451
452 if (keysym == NoSymbol)
453 ksname = "NoSymbol";
454 else if (!(ksname = XKeysymToString(keysym)))
455 ksname = "(no name)";
456
457 return ksname;
458 }
459
460 static BOOL
461 is_modifier(uint8 scancode)
462 {
463 switch (scancode)
464 {
465 case SCANCODE_CHAR_LSHIFT:
466 case SCANCODE_CHAR_RSHIFT:
467 case SCANCODE_CHAR_LCTRL:
468 case SCANCODE_CHAR_RCTRL:
469 case SCANCODE_CHAR_LALT:
470 case SCANCODE_CHAR_RALT:
471 case SCANCODE_CHAR_LWIN:
472 case SCANCODE_CHAR_RWIN:
473 case SCANCODE_CHAR_NUMLOCK:
474 return True;
475 default:
476 break;
477 }
478 return False;
479 }
480
481 void
482 save_remote_modifiers(uint8 scancode)
483 {
484 if (is_modifier(scancode))
485 return;
486
487 saved_remote_modifier_state = remote_modifier_state;
488 }
489
490 void
491 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
492 {
493 key_translation dummy;
494
495 if (is_modifier(scancode))
496 return;
497
498 dummy.scancode = 0;
499 dummy.modifiers = saved_remote_modifier_state;
500 ensure_remote_modifiers(ev_time, dummy);
501 }
502
503 void
504 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
505 {
506 /* If this key is a modifier, do nothing */
507 if (is_modifier(tr.scancode))
508 return;
509
510 /* Shift. Left shift and right shift are treated as equal; either is fine. */
511 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
512 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
513 {
514 /* The remote modifier state is not correct */
515 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
516 {
517 /* Needs left shift. Send down. */
518 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
519 }
520 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
521 {
522 /* Needs right shift. Send down. */
523 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
524 }
525 else
526 {
527 /* Should not use this modifier. Send up for shift currently pressed. */
528 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
529 /* Left shift is down */
530 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
531 else
532 /* Right shift is down */
533 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
534 }
535 }
536
537 /* AltGr */
538 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
539 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
540 {
541 /* The remote modifier state is not correct */
542 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
543 {
544 /* Needs this modifier. Send down. */
545 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
546 }
547 else
548 {
549 /* Should not use this modifier. Send up. */
550 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
551 }
552 }
553
554
555 }
556
557
558 unsigned int
559 read_keyboard_state()
560 {
561 unsigned int state;
562 Window wdummy;
563 int dummy;
564
565 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
566 return state;
567 }
568
569
570 uint16
571 ui_get_numlock_state(unsigned int state)
572 {
573 uint16 numlock_state = 0;
574
575 if (get_key_state(state, XK_Num_Lock))
576 numlock_state = KBD_FLAG_NUMLOCK;
577
578 return numlock_state;
579 }
580
581
582 void
583 reset_modifier_keys()
584 {
585 unsigned int state = read_keyboard_state();
586
587 /* reset keys */
588 uint32 ev_time;
589 ev_time = time(NULL);
590
591 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
592 && !get_key_state(state, XK_Shift_L))
593 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
594
595 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
596 && !get_key_state(state, XK_Shift_R))
597 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
598
599 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
600 && !get_key_state(state, XK_Control_L))
601 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
602
603 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
604 && !get_key_state(state, XK_Control_R))
605 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
606
607 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
608 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
609
610 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
611 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
612 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
613
614 reset_winkey(ev_time);
615
616 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
617 }
618
619
620 static void
621 update_modifier_state(uint8 scancode, BOOL pressed)
622 {
623 #ifdef WITH_DEBUG_KBD
624 uint16 old_modifier_state;
625
626 old_modifier_state = remote_modifier_state;
627 #endif
628
629 switch (scancode)
630 {
631 case SCANCODE_CHAR_LSHIFT:
632 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
633 break;
634 case SCANCODE_CHAR_RSHIFT:
635 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
636 break;
637 case SCANCODE_CHAR_LCTRL:
638 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
639 break;
640 case SCANCODE_CHAR_RCTRL:
641 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
642 break;
643 case SCANCODE_CHAR_LALT:
644 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
645 break;
646 case SCANCODE_CHAR_RALT:
647 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
648 break;
649 case SCANCODE_CHAR_LWIN:
650 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
651 break;
652 case SCANCODE_CHAR_RWIN:
653 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
654 break;
655 }
656
657 #ifdef WITH_DEBUG_KBD
658 if (old_modifier_state != remote_modifier_state)
659 {
660 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
661 old_modifier_state, pressed));
662 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
663 }
664 #endif
665
666 }
667
668 /* Send keyboard input */
669 void
670 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
671 {
672 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
673
674 if (scancode & SCANCODE_EXTENDED)
675 {
676 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
677 scancode & ~SCANCODE_EXTENDED, flags));
678 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
679 scancode & ~SCANCODE_EXTENDED, 0);
680 }
681 else
682 {
683 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
684 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
685 }
686 }

  ViewVC Help
Powered by ViewVC 1.1.26