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

  ViewVC Help
Powered by ViewVC 1.1.26