/[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 205 - (show annotations)
Thu Sep 26 14:11:59 2002 UTC (21 years, 7 months ago) by matthewc
File MIME type: text/plain
File size: 14557 byte(s)
Suppress missing translation warnings if the keymap was "none" or doesn't
exist (in the latter case the user already receives an error).

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

  ViewVC Help
Powered by ViewVC 1.1.26