/[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 226 - (show annotations)
Fri Oct 11 09:37:48 2002 UTC (21 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 15198 byte(s)
Indent fixes.

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)
244 || get_key_state(state, XK_Control_R)))
245 {
246 /* Ctrl-Alt-Break: toggle full screen */
247 if (pressed)
248 xwin_toggle_fullscreen();
249
250 }
251 else if (keysym == XK_Break)
252 {
253 /* Send Break sequence E0 46 E0 C6 */
254 if (pressed)
255 {
256 rdp_send_scancode(ev_time, RDP_KEYPRESS,
257 (SCANCODE_EXTENDED | 0x46));
258 rdp_send_scancode(ev_time, RDP_KEYPRESS,
259 (SCANCODE_EXTENDED | 0xc6));
260 }
261 /* No break sequence */
262 }
263 else /* XK_Pause */
264 {
265 /* According to MS Keyboard Scan Code
266 Specification, pressing Pause should result
267 in E1 1D 45 E1 9D C5. I'm not exactly sure
268 of how this is supposed to be sent via
269 RDP. The code below seems to work, but with
270 the side effect that Left Ctrl stays
271 down. Therefore, we release it when Pause
272 is released. */
273 if (pressed)
274 {
275 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
276 0xe1, 0);
277 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
278 0x1d, 0);
279 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
280 0x45, 0);
281 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
282 0xe1, 0);
283 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
284 0x9d, 0);
285 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS,
286 0xc5, 0);
287 }
288 else
289 {
290 /* Release Left Ctrl */
291 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
292 0x1d, 0);
293 }
294 }
295 return True;
296
297 case XK_Meta_L: /* Windows keys */
298 case XK_Super_L:
299 case XK_Hyper_L:
300 case XK_Meta_R:
301 case XK_Super_R:
302 case XK_Hyper_R:
303 if (pressed)
304 {
305 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
306 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
307 }
308 else
309 {
310 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
311 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
312 }
313 return True;
314 }
315 return False;
316 }
317
318
319 key_translation
320 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
321 {
322 key_translation tr = { 0, 0 };
323
324 tr = keymap[keysym & KEYMAP_MASK];
325
326 if (tr.modifiers & MapInhibitMask)
327 {
328 DEBUG_KBD(("Inhibiting key\n"));
329 tr.scancode = 0;
330 return tr;
331 }
332
333 if (tr.modifiers & MapLocalStateMask)
334 {
335 /* The modifiers to send for this key should be obtained
336 from the local state. Currently, only shift is implemented. */
337 if (state & ShiftMask)
338 {
339 tr.modifiers = MapLeftShiftMask;
340 }
341 }
342
343 if (tr.scancode != 0)
344 {
345 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
346 tr.scancode, tr.modifiers));
347 return tr;
348 }
349
350 if (keymap_loaded)
351 error("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
352
353 /* not in keymap, try to interpret the raw scancode */
354 if ((keycode >= min_keycode) && (keycode <= 0x60))
355 {
356 tr.scancode = keycode - min_keycode;
357
358 /* The modifiers to send for this key should be
359 obtained from the local state. Currently, only
360 shift is implemented. */
361 if (state & ShiftMask)
362 {
363 tr.modifiers = MapLeftShiftMask;
364 }
365
366 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
367 }
368 else
369 {
370 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
371 }
372
373 return tr;
374 }
375
376 uint16
377 xkeymap_translate_button(unsigned int button)
378 {
379 switch (button)
380 {
381 case Button1: /* left */
382 return MOUSE_FLAG_BUTTON1;
383 case Button2: /* middle */
384 return MOUSE_FLAG_BUTTON3;
385 case Button3: /* right */
386 return MOUSE_FLAG_BUTTON2;
387 case Button4: /* wheel up */
388 return MOUSE_FLAG_BUTTON4;
389 case Button5: /* wheel down */
390 return MOUSE_FLAG_BUTTON5;
391 }
392
393 return 0;
394 }
395
396 char *
397 get_ksname(uint32 keysym)
398 {
399 char *ksname = NULL;
400
401 if (keysym == NoSymbol)
402 ksname = "NoSymbol";
403 else if (!(ksname = XKeysymToString(keysym)))
404 ksname = "(no name)";
405
406 return ksname;
407 }
408
409
410 void
411 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
412 {
413 /* If this key is a modifier, do nothing */
414 switch (tr.scancode)
415 {
416 case SCANCODE_CHAR_LSHIFT:
417 case SCANCODE_CHAR_RSHIFT:
418 case SCANCODE_CHAR_LCTRL:
419 case SCANCODE_CHAR_RCTRL:
420 case SCANCODE_CHAR_LALT:
421 case SCANCODE_CHAR_RALT:
422 case SCANCODE_CHAR_LWIN:
423 case SCANCODE_CHAR_RWIN:
424 case SCANCODE_CHAR_NUMLOCK:
425 return;
426 default:
427 break;
428 }
429
430 /* Shift. Left shift and right shift are treated as equal; either is fine. */
431 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
432 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
433 {
434 /* The remote modifier state is not correct */
435 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
436 {
437 /* Needs left shift. Send down. */
438 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
439 }
440 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
441 {
442 /* Needs right shift. Send down. */
443 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
444 }
445 else
446 {
447 /* Should not use this modifier. Send up for shift currently pressed. */
448 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
449 /* Left shift is down */
450 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
451 else
452 /* Right shift is down */
453 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
454 }
455 }
456
457 /* AltGr */
458 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
459 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
460 {
461 /* The remote modifier state is not correct */
462 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
463 {
464 /* Needs this modifier. Send down. */
465 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
466 }
467 else
468 {
469 /* Should not use this modifier. Send up. */
470 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
471 }
472 }
473
474 /* NumLock */
475 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
476 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
477 {
478 /* The remote modifier state is not correct */
479 uint16 new_remote_state = 0;
480
481 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
482 {
483 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
484 new_remote_state |= KBD_FLAG_NUMLOCK;
485 }
486 else
487 {
488 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
489 }
490
491 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
492 update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);
493 }
494 }
495
496
497 void
498 reset_modifier_keys(unsigned int state)
499 {
500 /* reset keys */
501 uint32 ev_time;
502 ev_time = time(NULL);
503
504 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
505 && !get_key_state(state, XK_Shift_L))
506 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
507
508 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
509 && !get_key_state(state, XK_Shift_R))
510 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
511
512 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
513 && !get_key_state(state, XK_Control_L))
514 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
515
516 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
517 && !get_key_state(state, XK_Control_R))
518 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
519
520 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
521 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
522
523 if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
524 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
525 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
526 }
527
528
529 static void
530 update_modifier_state(uint8 scancode, BOOL pressed)
531 {
532 #ifdef WITH_DEBUG_KBD
533 uint16 old_modifier_state;
534
535 old_modifier_state = remote_modifier_state;
536 #endif
537
538 switch (scancode)
539 {
540 case SCANCODE_CHAR_LSHIFT:
541 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
542 break;
543 case SCANCODE_CHAR_RSHIFT:
544 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
545 break;
546 case SCANCODE_CHAR_LCTRL:
547 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
548 break;
549 case SCANCODE_CHAR_RCTRL:
550 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
551 break;
552 case SCANCODE_CHAR_LALT:
553 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
554 break;
555 case SCANCODE_CHAR_RALT:
556 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
557 break;
558 case SCANCODE_CHAR_LWIN:
559 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
560 break;
561 case SCANCODE_CHAR_RWIN:
562 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
563 break;
564 case SCANCODE_CHAR_NUMLOCK:
565 /* KeyReleases for NumLocks are sent immediately. Toggle the
566 modifier state only on Keypress */
567 if (pressed)
568 {
569 BOOL newNumLockState;
570 newNumLockState =
571 (MASK_HAS_BITS
572 (remote_modifier_state, MapNumLockMask) == False);
573 MASK_CHANGE_BIT(remote_modifier_state,
574 MapNumLockMask, newNumLockState);
575 }
576 break;
577 }
578
579 #ifdef WITH_DEBUG_KBD
580 if (old_modifier_state != remote_modifier_state)
581 {
582 DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
583 old_modifier_state, pressed));
584 DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
585 }
586 #endif
587
588 }
589
590 /* Send keyboard input */
591 void
592 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
593 {
594 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
595
596 if (scancode & SCANCODE_EXTENDED)
597 {
598 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
599 scancode & ~SCANCODE_EXTENDED, flags));
600 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
601 scancode & ~SCANCODE_EXTENDED, 0);
602 }
603 else
604 {
605 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
606 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
607 }
608 }

  ViewVC Help
Powered by ViewVC 1.1.26