/[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 333 - (show annotations)
Thu Feb 20 12:14:13 2003 UTC (21 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 15432 byte(s)
Added rdp2vnc support

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

  ViewVC Help
Powered by ViewVC 1.1.26