/[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

Annotation of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 207 - (hide annotations)
Thu Sep 26 14:26:46 2002 UTC (21 years, 7 months ago) by matthewc
File MIME type: text/plain
File size: 14560 byte(s)
Update copyright dates on all files that have changed.
Bump version to 1.2-cvs.

1 matthewc 38 /*
2     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X keyboard mapping
4 matthewc 207 Copyright (C) Matthew Chapman 1999-2002
5 matthewc 38
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 matthewc 190 #define XK_MISCELLANY
23     #include <X11/keysymdef.h>
24 astrand 66 #include <ctype.h>
25 matthewc 39 #include <limits.h>
26 matthewc 190 #include <time.h>
27 matthewc 38 #include "rdesktop.h"
28 astrand 66 #include "scancodes.h"
29 matthewc 38
30     #define KEYMAP_SIZE 4096
31     #define KEYMAP_MASK (KEYMAP_SIZE - 1)
32 astrand 66 #define KEYMAP_MAX_LINE_LENGTH 80
33 matthewc 38
34 matthewc 50 extern Display *display;
35 matthewc 38 extern char keymapname[16];
36     extern int keylayout;
37 astrand 70 extern BOOL enable_compose;
38 matthewc 38
39 matthewc 205 static BOOL keymap_loaded;
40 astrand 66 static key_translation keymap[KEYMAP_SIZE];
41 astrand 73 static int min_keycode;
42 astrand 66 static uint16 remote_modifier_state = 0;
43 matthewc 38
44 matthewc 203 static void update_modifier_state(uint8 scancode, BOOL pressed);
45 astrand 115
46 astrand 66 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 astrand 84 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
59     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
60 astrand 66
61     keymap[keysym & KEYMAP_MASK].scancode = scancode;
62     keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
63    
64     return;
65     }
66    
67    
68 astrand 64 static BOOL
69     xkeymap_read(char *mapname)
70 matthewc 38 {
71     FILE *fp;
72 astrand 66 char line[KEYMAP_MAX_LINE_LENGTH], path[PATH_MAX];
73     unsigned int line_num = 0;
74     unsigned int line_length = 0;
75 matthewc 38 char *keyname, *p;
76 astrand 66 char *line_rest;
77     uint8 scancode;
78     uint16 modifiers;
79 matthewc 38
80 astrand 66
81 matthewc 38 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 astrand 66 /* FIXME: More tolerant on white space */
92 matthewc 38 while (fgets(line, sizeof(line), fp) != NULL)
93     {
94 astrand 66 line_num++;
95    
96     /* Replace the \n with \0 */
97 matthewc 38 p = strchr(line, '\n');
98     if (p != NULL)
99     *p = 0;
100    
101 astrand 66 line_length = strlen(line);
102    
103     /* Completely empty line */
104     if (strspn(line, " \t\n\r\f\v") == line_length)
105 matthewc 38 {
106 astrand 66 continue;
107     }
108 matthewc 38
109 astrand 66 /* Include */
110     if (strncmp(line, "include ", 8) == 0)
111 matthewc 38 {
112 astrand 64 if (!xkeymap_read(line + 8))
113 matthewc 38 return False;
114 astrand 66 continue;
115 matthewc 38 }
116 astrand 66
117     /* map */
118     if (strncmp(line, "map ", 4) == 0)
119 matthewc 38 {
120 astrand 64 keylayout = strtol(line + 4, NULL, 16);
121 astrand 84 DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
122 astrand 66 continue;
123 matthewc 38 }
124 astrand 66
125 astrand 70 /* compose */
126     if (strncmp(line, "enable_compose", 15) == 0)
127     {
128 astrand 84 DEBUG_KBD(("Enabling compose handling\n"));
129 astrand 70 enable_compose = True;
130     continue;
131     }
132    
133 astrand 66 /* Comment */
134     if (line[0] == '#')
135 matthewc 38 {
136 astrand 66 continue;
137 matthewc 38 }
138 astrand 66
139     /* Normal line */
140     keyname = line;
141     p = strchr(line, ' ');
142     if (p == NULL)
143     {
144 astrand 82 error("Bad line %d in keymap %s\n", line_num, mapname);
145 astrand 66 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 astrand 69 if (strstr(line_rest, "localstate"))
176     {
177     MASK_ADD_BITS(modifiers, MapLocalStateMask);
178     }
179    
180 astrand 116 if (strstr(line_rest, "inhibit"))
181     {
182     MASK_ADD_BITS(modifiers, MapInhibitMask);
183     }
184    
185 astrand 66 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 matthewc 38 }
197    
198     fclose(fp);
199     return True;
200     }
201    
202 astrand 66
203     /* Before connecting and creating UI */
204 astrand 64 void
205 matthewc 121 xkeymap_init(void)
206 matthewc 38 {
207 matthewc 121 unsigned int max_keycode;
208 matthewc 38
209     if (strcmp(keymapname, "none"))
210 matthewc 205 {
211     if (xkeymap_read(keymapname))
212     keymap_loaded = True;
213     }
214 astrand 66
215 astrand 77 XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);
216 astrand 66 }
217 matthewc 38
218 astrand 118 /* Handles, for example, multi-scancode keypresses (which is not
219     possible via keymap-files) */
220     BOOL
221 matthewc 203 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
222 astrand 118 {
223     switch (keysym)
224     {
225 astrand 199 case XK_Break:
226 matthewc 203 if (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
227 astrand 118 {
228 astrand 199 /* toggle full screen */
229 matthewc 193 if (pressed)
230     xwin_toggle_fullscreen();
231 astrand 199
232 astrand 118 }
233 astrand 199 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 astrand 118 break;
248 astrand 66
249 astrand 197 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 matthewc 206 /* Release Left Ctrl */
270 astrand 197 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d,
271     0);
272     }
273    
274     return True;
275     break;
276    
277 astrand 118 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 astrand 66 key_translation
301 matthewc 190 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
302 astrand 66 {
303     key_translation tr = { 0, 0 };
304    
305     tr = keymap[keysym & KEYMAP_MASK];
306    
307 astrand 116 if (tr.modifiers & MapInhibitMask)
308     {
309     DEBUG_KBD(("Inhibiting key\n"));
310     tr.scancode = 0;
311     return tr;
312     }
313    
314 astrand 69 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 astrand 66 if (tr.scancode != 0)
325 matthewc 50 {
326 matthewc 190 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
327 astrand 197 tr.scancode, tr.modifiers));
328 astrand 66 return tr;
329 matthewc 50 }
330    
331 matthewc 205 if (keymap_loaded)
332     error("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
333 astrand 66
334 matthewc 38 /* not in keymap, try to interpret the raw scancode */
335     if ((keycode >= min_keycode) && (keycode <= 0x60))
336     {
337 astrand 66 tr.scancode = keycode - min_keycode;
338 astrand 165
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 matthewc 190 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
348 matthewc 38 }
349 astrand 66 else
350     {
351 matthewc 190 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
352 astrand 66 }
353 matthewc 38
354 astrand 66 return tr;
355 matthewc 38 }
356    
357 astrand 64 uint16
358     xkeymap_translate_button(unsigned int button)
359 matthewc 38 {
360     switch (button)
361     {
362 astrand 64 case Button1: /* left */
363 matthewc 38 return MOUSE_FLAG_BUTTON1;
364 astrand 64 case Button2: /* middle */
365 matthewc 38 return MOUSE_FLAG_BUTTON3;
366 astrand 64 case Button3: /* right */
367 matthewc 38 return MOUSE_FLAG_BUTTON2;
368 jsorg71 67 case Button4: /* wheel up */
369     return MOUSE_FLAG_BUTTON4;
370     case Button5: /* wheel down */
371     return MOUSE_FLAG_BUTTON5;
372 matthewc 38 }
373    
374     return 0;
375     }
376 astrand 66
377     char *
378 matthewc 190 get_ksname(uint32 keysym)
379 astrand 66 {
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 astrand 183 /* Shift. Left shift and right shift are treated as equal; either is fine. */
412 astrand 66 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 astrand 183 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
417 astrand 66 {
418 astrand 183 /* Needs left shift. Send down. */
419 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
420 astrand 66 }
421 astrand 183 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 astrand 66 else
427     {
428 astrand 183 /* 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 astrand 66 }
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 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
447 astrand 66 }
448     else
449     {
450     /* Should not use this modifier. Send up. */
451 astrand 82 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
452 astrand 66 }
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 astrand 115 uint16 new_remote_state = 0;
461    
462 astrand 66 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
463     {
464 astrand 115 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
465     new_remote_state |= KBD_FLAG_NUMLOCK;
466 astrand 66 }
467     else
468     {
469 astrand 115 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
470 astrand 66 }
471 astrand 115
472     rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
473     update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);
474 astrand 66 }
475     }
476    
477    
478 astrand 170 void
479 matthewc 203 reset_modifier_keys(unsigned int state)
480 astrand 170 {
481     /* reset keys */
482     uint32 ev_time;
483     ev_time = time(NULL);
484    
485 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask) && !get_key_state(state, XK_Shift_L))
486 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
487    
488 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask) && !get_key_state(state, XK_Shift_R))
489 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
490    
491 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask) && !get_key_state(state, XK_Control_L))
492 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
493    
494 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask) && !get_key_state(state, XK_Control_R))
495 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
496    
497 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
498 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
499    
500     if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
501 matthewc 203 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
502 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
503     }
504    
505    
506 astrand 66 static void
507 matthewc 203 update_modifier_state(uint8 scancode, BOOL pressed)
508 astrand 66 {
509 astrand 113 #ifdef WITH_DEBUG_KBD
510     uint16 old_modifier_state;
511 astrand 66
512 astrand 113 old_modifier_state = remote_modifier_state;
513     #endif
514    
515 matthewc 203 switch (scancode)
516 astrand 66 {
517     case SCANCODE_CHAR_LSHIFT:
518 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
519 astrand 66 break;
520     case SCANCODE_CHAR_RSHIFT:
521 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
522 astrand 66 break;
523     case SCANCODE_CHAR_LCTRL:
524 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
525 astrand 66 break;
526     case SCANCODE_CHAR_RCTRL:
527 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
528 astrand 66 break;
529     case SCANCODE_CHAR_LALT:
530 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
531 astrand 66 break;
532     case SCANCODE_CHAR_RALT:
533 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
534 astrand 66 break;
535     case SCANCODE_CHAR_LWIN:
536 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
537 astrand 66 break;
538     case SCANCODE_CHAR_RWIN:
539 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
540 astrand 66 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 astrand 82 (remote_modifier_state, MapNumLockMask) == False);
550 astrand 66 MASK_CHANGE_BIT(remote_modifier_state,
551 astrand 82 MapNumLockMask, newNumLockState);
552 astrand 66 }
553     break;
554     }
555    
556 astrand 113 #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 astrand 66 }
566    
567     /* Send keyboard input */
568     void
569 matthewc 203 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
570 astrand 66 {
571     update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
572    
573     if (scancode & SCANCODE_EXTENDED)
574     {
575 astrand 84 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
576     scancode & ~SCANCODE_EXTENDED, flags));
577 astrand 66 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
578     scancode & ~SCANCODE_EXTENDED, 0);
579     }
580     else
581     {
582 astrand 85 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
583     rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
584 astrand 66 }
585     }

  ViewVC Help
Powered by ViewVC 1.1.26