/[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 452 - (show annotations)
Sun Aug 31 19:45:56 2003 UTC (20 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 16314 byte(s)
Support for (real) Windows keys, if running RDP5.

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

  ViewVC Help
Powered by ViewVC 1.1.26