/[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 327 - (show annotations)
Tue Feb 18 13:02:58 2003 UTC (21 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 15167 byte(s)
Indent fix.

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 0xffff+1
31 #define KEYMAP_MASK 0xffff
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 DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\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((int) *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 {
223 *mapname_ptr = tolower((int) *mapname_ptr);
224 mapname_ptr++;
225 }
226
227 if (strcmp(keymapname, "none"))
228 {
229 if (xkeymap_read(keymapname))
230 keymap_loaded = True;
231 }
232
233 XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);
234 }
235
236 /* Handles, for example, multi-scancode keypresses (which is not
237 possible via keymap-files) */
238 BOOL
239 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
240 {
241 switch (keysym)
242 {
243 case XK_Return:
244 if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
245 && (get_key_state(state, XK_Control_L)
246 || get_key_state(state, XK_Control_R)))
247 {
248 /* Ctrl-Alt-Enter: toggle full screen */
249 if (pressed)
250 xwin_toggle_fullscreen();
251 return True;
252 }
253 break;
254
255 case XK_Break:
256 /* Send Break sequence E0 46 E0 C6 */
257 if (pressed)
258 {
259 rdp_send_scancode(ev_time, RDP_KEYPRESS,
260 (SCANCODE_EXTENDED | 0x46));
261 rdp_send_scancode(ev_time, RDP_KEYPRESS,
262 (SCANCODE_EXTENDED | 0xc6));
263 }
264 /* No release sequence */
265 return True;
266
267 case XK_Pause:
268 /* According to MS Keyboard Scan Code
269 Specification, pressing Pause should result
270 in E1 1D 45 E1 9D C5. I'm not exactly sure
271 of how this is supposed to be sent via
272 RDP. The code below seems to work, but with
273 the side effect that Left Ctrl stays
274 down. Therefore, we release it when Pause
275 is released. */
276 if (pressed)
277 {
278 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
279 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
280 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
281 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
282 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
283 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
284 }
285 else
286 {
287 /* Release Left Ctrl */
288 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
289 0x1d, 0);
290 }
291 return True;
292
293 case XK_Meta_L: /* Windows keys */
294 case XK_Super_L:
295 case XK_Hyper_L:
296 case XK_Meta_R:
297 case XK_Super_R:
298 case XK_Hyper_R:
299 if (pressed)
300 {
301 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
302 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
303 }
304 else
305 {
306 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
307 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
308 }
309 return True;
310 }
311 return False;
312 }
313
314
315 key_translation
316 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
317 {
318 key_translation tr = { 0, 0 };
319
320 tr = keymap[keysym & KEYMAP_MASK];
321
322 if (tr.modifiers & MapInhibitMask)
323 {
324 DEBUG_KBD(("Inhibiting key\n"));
325 tr.scancode = 0;
326 return tr;
327 }
328
329 if (tr.modifiers & MapLocalStateMask)
330 {
331 /* The modifiers to send for this key should be obtained
332 from the local state. Currently, only shift is implemented. */
333 if (state & ShiftMask)
334 {
335 tr.modifiers = MapLeftShiftMask;
336 }
337 }
338
339 if (tr.scancode != 0)
340 {
341 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
342 tr.scancode, tr.modifiers));
343 return tr;
344 }
345
346 if (keymap_loaded)
347 warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
348
349 /* not in keymap, try to interpret the raw scancode */
350 if ((keycode >= min_keycode) && (keycode <= 0x60))
351 {
352 tr.scancode = keycode - min_keycode;
353
354 /* The modifiers to send for this key should be
355 obtained from the local state. Currently, only
356 shift is implemented. */
357 if (state & ShiftMask)
358 {
359 tr.modifiers = MapLeftShiftMask;
360 }
361
362 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
363 }
364 else
365 {
366 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
367 }
368
369 return tr;
370 }
371
372 uint16
373 xkeymap_translate_button(unsigned int button)
374 {
375 switch (button)
376 {
377 case Button1: /* left */
378 return MOUSE_FLAG_BUTTON1;
379 case Button2: /* middle */
380 return MOUSE_FLAG_BUTTON3;
381 case Button3: /* right */
382 return MOUSE_FLAG_BUTTON2;
383 case Button4: /* wheel up */
384 return MOUSE_FLAG_BUTTON4;
385 case Button5: /* wheel down */
386 return MOUSE_FLAG_BUTTON5;
387 }
388
389 return 0;
390 }
391
392 char *
393 get_ksname(uint32 keysym)
394 {
395 char *ksname = NULL;
396
397 if (keysym == NoSymbol)
398 ksname = "NoSymbol";
399 else if (!(ksname = XKeysymToString(keysym)))
400 ksname = "(no name)";
401
402 return ksname;
403 }
404
405
406 void
407 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
408 {
409 /* If this key is a modifier, do nothing */
410 switch (tr.scancode)
411 {
412 case SCANCODE_CHAR_LSHIFT:
413 case SCANCODE_CHAR_RSHIFT:
414 case SCANCODE_CHAR_LCTRL:
415 case SCANCODE_CHAR_RCTRL:
416 case SCANCODE_CHAR_LALT:
417 case SCANCODE_CHAR_RALT:
418 case SCANCODE_CHAR_LWIN:
419 case SCANCODE_CHAR_RWIN:
420 case SCANCODE_CHAR_NUMLOCK:
421 return;
422 default:
423 break;
424 }
425
426 /* NumLock */
427 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
428 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
429 {
430 /* The remote modifier state is not correct */
431 uint16 new_remote_state;
432
433 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
434 {
435 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
436 new_remote_state = KBD_FLAG_NUMLOCK;
437 remote_modifier_state = MapNumLockMask;
438 }
439 else
440 {
441 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
442 new_remote_state = 0;
443 remote_modifier_state = 0;
444 }
445
446 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
447 }
448
449 /* Shift. Left shift and right shift are treated as equal; either is fine. */
450 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
451 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
452 {
453 /* The remote modifier state is not correct */
454 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
455 {
456 /* Needs left shift. Send down. */
457 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
458 }
459 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
460 {
461 /* Needs right shift. Send down. */
462 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
463 }
464 else
465 {
466 /* Should not use this modifier. Send up for shift currently pressed. */
467 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
468 /* Left shift is down */
469 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
470 else
471 /* Right shift is down */
472 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
473 }
474 }
475
476 /* AltGr */
477 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
478 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
479 {
480 /* The remote modifier state is not correct */
481 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
482 {
483 /* Needs this modifier. Send down. */
484 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
485 }
486 else
487 {
488 /* Should not use this modifier. Send up. */
489 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
490 }
491 }
492
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