/[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 227 - (show annotations)
Fri Oct 11 09:38:49 2002 UTC (21 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 15219 byte(s)
Eliminating GCC warning message.

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

  ViewVC Help
Powered by ViewVC 1.1.26