/[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 225 - (show annotations)
Fri Oct 11 08:54:08 2002 UTC (21 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 15097 byte(s)
Case-insensitive keymap names.

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

  ViewVC Help
Powered by ViewVC 1.1.26