/[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 449 - (show annotations)
Wed Aug 27 09:42:55 2003 UTC (20 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 15760 byte(s)
kbd: Restoring changed remote modifiers after keypress. Fixes problem with shift & altgr 'stuck' down after typing, for example, A

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

  ViewVC Help
Powered by ViewVC 1.1.26