/[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 199 - (hide annotations)
Wed Sep 25 11:17:59 2002 UTC (21 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 14389 byte(s)
Support for Break key.

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

  ViewVC Help
Powered by ViewVC 1.1.26