/[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 543 - (show annotations)
Mon Nov 3 13:33:35 2003 UTC (20 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 15980 byte(s)
Re-worked numlock handling: Keeping remote numlock state in sync with local state

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 /* Handles, for example, multi-scancode keypresses (which is not
280 possible via keymap-files) */
281 BOOL
282 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
283 {
284 switch (keysym)
285 {
286 case XK_Return:
287 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
288 && (get_key_state(state, XK_Control_L)
289 || get_key_state(state, XK_Control_R)))
290 {
291 /* Ctrl-Alt-Enter: toggle full screen */
292 if (pressed)
293 xwin_toggle_fullscreen();
294 return True;
295 }
296 break;
297
298 case XK_Break:
299 /* Send Break sequence E0 46 E0 C6 */
300 if (pressed)
301 {
302 rdp_send_scancode(ev_time, RDP_KEYPRESS,
303 (SCANCODE_EXTENDED | 0x46));
304 rdp_send_scancode(ev_time, RDP_KEYPRESS,
305 (SCANCODE_EXTENDED | 0xc6));
306 }
307 /* No release sequence */
308 return True;
309
310 case XK_Pause:
311 /* According to MS Keyboard Scan Code
312 Specification, pressing Pause should result
313 in E1 1D 45 E1 9D C5. I'm not exactly sure
314 of how this is supposed to be sent via
315 RDP. The code below seems to work, but with
316 the side effect that Left Ctrl stays
317 down. Therefore, we release it when Pause
318 is released. */
319 if (pressed)
320 {
321 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
322 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
323 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
324 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
325 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
326 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
327 }
328 else
329 {
330 /* Release Left Ctrl */
331 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
332 0x1d, 0);
333 }
334 return True;
335
336 case XK_Meta_L: /* Windows keys */
337 case XK_Super_L:
338 case XK_Hyper_L:
339 send_winkey(ev_time, pressed, True);
340 return True;
341
342 case XK_Meta_R:
343 case XK_Super_R:
344 case XK_Hyper_R:
345 send_winkey(ev_time, pressed, False);
346 return True;
347
348 case XK_space:
349 /* Prevent access to the Windows system menu in single app mode */
350 if (g_win_button_size
351 && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
352 return True;
353
354 }
355 return False;
356 }
357
358
359 key_translation
360 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
361 {
362 key_translation tr = { 0, 0 };
363
364 tr = keymap[keysym & KEYMAP_MASK];
365
366 if (tr.modifiers & MapInhibitMask)
367 {
368 DEBUG_KBD(("Inhibiting key\n"));
369 tr.scancode = 0;
370 return tr;
371 }
372
373 if (tr.modifiers & MapLocalStateMask)
374 {
375 /* The modifiers to send for this key should be obtained
376 from the local state. Currently, only shift is implemented. */
377 if (state & ShiftMask)
378 {
379 tr.modifiers = MapLeftShiftMask;
380 }
381 }
382
383 if (tr.scancode != 0)
384 {
385 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
386 tr.scancode, tr.modifiers));
387 return tr;
388 }
389
390 if (keymap_loaded)
391 warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
392
393 /* not in keymap, try to interpret the raw scancode */
394 if (((int) keycode >= min_keycode) && (keycode <= 0x60))
395 {
396 tr.scancode = keycode - min_keycode;
397
398 /* The modifiers to send for this key should be
399 obtained from the local state. Currently, only
400 shift is implemented. */
401 if (state & ShiftMask)
402 {
403 tr.modifiers = MapLeftShiftMask;
404 }
405
406 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
407 }
408 else
409 {
410 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
411 }
412
413 return tr;
414 }
415
416 uint16
417 xkeymap_translate_button(unsigned int button)
418 {
419 switch (button)
420 {
421 case Button1: /* left */
422 return MOUSE_FLAG_BUTTON1;
423 case Button2: /* middle */
424 return MOUSE_FLAG_BUTTON3;
425 case Button3: /* right */
426 return MOUSE_FLAG_BUTTON2;
427 case Button4: /* wheel up */
428 return MOUSE_FLAG_BUTTON4;
429 case Button5: /* wheel down */
430 return MOUSE_FLAG_BUTTON5;
431 }
432
433 return 0;
434 }
435
436 char *
437 get_ksname(uint32 keysym)
438 {
439 char *ksname = NULL;
440
441 if (keysym == NoSymbol)
442 ksname = "NoSymbol";
443 else if (!(ksname = XKeysymToString(keysym)))
444 ksname = "(no name)";
445
446 return ksname;
447 }
448
449 static BOOL
450 is_modifier(uint8 scancode)
451 {
452 switch (scancode)
453 {
454 case SCANCODE_CHAR_LSHIFT:
455 case SCANCODE_CHAR_RSHIFT:
456 case SCANCODE_CHAR_LCTRL:
457 case SCANCODE_CHAR_RCTRL:
458 case SCANCODE_CHAR_LALT:
459 case SCANCODE_CHAR_RALT:
460 case SCANCODE_CHAR_LWIN:
461 case SCANCODE_CHAR_RWIN:
462 case SCANCODE_CHAR_NUMLOCK:
463 return True;
464 default:
465 break;
466 }
467 return False;
468 }
469
470 void
471 save_remote_modifiers(uint8 scancode)
472 {
473 if (is_modifier(scancode))
474 return;
475
476 saved_remote_modifier_state = remote_modifier_state;
477 }
478
479 void
480 restore_remote_modifiers(uint32 ev_time, uint8 scancode)
481 {
482 key_translation dummy;
483
484 if (is_modifier(scancode))
485 return;
486
487 dummy.scancode = 0;
488 dummy.modifiers = saved_remote_modifier_state;
489 ensure_remote_modifiers(ev_time, dummy);
490 }
491
492 void
493 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
494 {
495 /* If this key is a modifier, do nothing */
496 if (is_modifier(tr.scancode))
497 return;
498
499 /* Shift. Left shift and right shift are treated as equal; either is fine. */
500 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
501 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
502 {
503 /* The remote modifier state is not correct */
504 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
505 {
506 /* Needs left shift. Send down. */
507 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
508 }
509 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
510 {
511 /* Needs right shift. Send down. */
512 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
513 }
514 else
515 {
516 /* Should not use this modifier. Send up for shift currently pressed. */
517 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
518 /* Left shift is down */
519 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
520 else
521 /* Right shift is down */
522 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
523 }
524 }
525
526 /* AltGr */
527 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
528 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
529 {
530 /* The remote modifier state is not correct */
531 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
532 {
533 /* Needs this modifier. Send down. */
534 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
535 }
536 else
537 {
538 /* Should not use this modifier. Send up. */
539 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
540 }
541 }
542
543
544 }
545
546
547 unsigned int
548 read_keyboard_state()
549 {
550 unsigned int state;
551 Window wdummy;
552 int dummy;
553
554 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
555 return state;
556 }
557
558
559 uint16
560 ui_get_numlock_state(unsigned int state)
561 {
562 uint16 numlock_state = 0;
563
564 if (get_key_state(state, XK_Num_Lock))
565 numlock_state = KBD_FLAG_NUMLOCK;
566
567 return numlock_state;
568 }
569
570
571 void
572 reset_modifier_keys()
573 {
574 unsigned int state = read_keyboard_state();
575
576 /* reset keys */
577 uint32 ev_time;
578 ev_time = time(NULL);
579
580 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
581 && !get_key_state(state, XK_Shift_L))
582 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
583
584 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
585 && !get_key_state(state, XK_Shift_R))
586 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
587
588 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
589 && !get_key_state(state, XK_Control_L))
590 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
591
592 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
593 && !get_key_state(state, XK_Control_R))
594 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
595
596 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
597 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
598
599 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
600 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
601 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
602
603 rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
604 }
605
606
607 static void
608 update_modifier_state(uint8 scancode, BOOL pressed)
609 {
610 #ifdef WITH_DEBUG_KBD
611 uint16 old_modifier_state;
612
613 old_modifier_state = remote_modifier_state;
614 #endif
615
616 switch (scancode)
617 {
618 case SCANCODE_CHAR_LSHIFT:
619 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
620 break;
621 case SCANCODE_CHAR_RSHIFT:
622 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
623 break;
624 case SCANCODE_CHAR_LCTRL:
625 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
626 break;
627 case SCANCODE_CHAR_RCTRL:
628 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
629 break;
630 case SCANCODE_CHAR_LALT:
631 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
632 break;
633 case SCANCODE_CHAR_RALT:
634 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
635 break;
636 case SCANCODE_CHAR_LWIN:
637 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
638 break;
639 case SCANCODE_CHAR_RWIN:
640 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
641 break;
642 }
643
644 #ifdef WITH_DEBUG_KBD
645 if (old_modifier_state != remote_modifier_state)
646 {
647 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
648 old_modifier_state, pressed));
649 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
650 }
651 #endif
652
653 }
654
655 /* Send keyboard input */
656 void
657 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
658 {
659 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
660
661 if (scancode & SCANCODE_EXTENDED)
662 {
663 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
664 scancode & ~SCANCODE_EXTENDED, flags));
665 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
666 scancode & ~SCANCODE_EXTENDED, 0);
667 }
668 else
669 {
670 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
671 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
672 }
673 }

  ViewVC Help
Powered by ViewVC 1.1.26