/[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 470 - (show annotations)
Mon Sep 15 08:03:30 2003 UTC (20 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 16580 byte(s)
Kbd fix: Shift was always reset after press

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

  ViewVC Help
Powered by ViewVC 1.1.26